fix: wire handler layer in main.go and fix migration issues
cmd/server/main.go: replace stub router with full wiring — UserRepo, SessionRepo, AuthService, AuthMiddleware, AuthHandler, NewRouter; use postgres.NewPool instead of pgxpool.New directly. migrations/001_init_schemas.sql: wrap uuid_v7 and uuid_extract_timestamp function bodies with goose StatementBegin/End so semicolons inside dollar-quoted strings are not treated as statement separators. migrations/007_seed_data.sql: add seed admin user (admin/admin, bcrypt cost 10, is_admin=true, can_create=true) for manual testing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
caeff6786e
commit
6c9b1bf1cd
@ -3,15 +3,15 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"github.com/jackc/pgx/v5/pgxpool"
|
|
||||||
"github.com/jackc/pgx/v5/stdlib"
|
"github.com/jackc/pgx/v5/stdlib"
|
||||||
"github.com/pressly/goose/v3"
|
"github.com/pressly/goose/v3"
|
||||||
|
|
||||||
"tanabata/backend/internal/config"
|
"tanabata/backend/internal/config"
|
||||||
|
"tanabata/backend/internal/db/postgres"
|
||||||
|
"tanabata/backend/internal/handler"
|
||||||
|
"tanabata/backend/internal/service"
|
||||||
"tanabata/backend/migrations"
|
"tanabata/backend/migrations"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -22,22 +22,14 @@ func main() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pool, err := pgxpool.New(context.Background(), cfg.DatabaseURL)
|
pool, err := postgres.NewPool(context.Background(), cfg.DatabaseURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("failed to connect to database", "err", err)
|
slog.Error("failed to connect to database", "err", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
defer pool.Close()
|
defer pool.Close()
|
||||||
|
|
||||||
if err := pool.Ping(context.Background()); err != nil {
|
|
||||||
slog.Error("database ping failed", "err", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
slog.Info("database connected")
|
slog.Info("database connected")
|
||||||
|
|
||||||
// Run migrations using the embedded FS.
|
|
||||||
// stdlib.OpenDBFromPool wraps the pool in a *sql.DB without closing
|
|
||||||
// the pool when the sql.DB is closed.
|
|
||||||
migDB := stdlib.OpenDBFromPool(pool)
|
migDB := stdlib.OpenDBFromPool(pool)
|
||||||
goose.SetBaseFS(migrations.FS)
|
goose.SetBaseFS(migrations.FS)
|
||||||
if err := goose.SetDialect("postgres"); err != nil {
|
if err := goose.SetDialect("postgres"); err != nil {
|
||||||
@ -51,12 +43,24 @@ func main() {
|
|||||||
migDB.Close()
|
migDB.Close()
|
||||||
slog.Info("migrations applied")
|
slog.Info("migrations applied")
|
||||||
|
|
||||||
r := gin.New()
|
// Repositories
|
||||||
r.Use(gin.Recovery())
|
userRepo := postgres.NewUserRepo(pool)
|
||||||
|
sessionRepo := postgres.NewSessionRepo(pool)
|
||||||
|
|
||||||
r.GET("/health", func(c *gin.Context) {
|
// Services
|
||||||
c.Status(http.StatusOK)
|
authSvc := service.NewAuthService(
|
||||||
})
|
userRepo,
|
||||||
|
sessionRepo,
|
||||||
|
cfg.JWTSecret,
|
||||||
|
cfg.JWTAccessTTL,
|
||||||
|
cfg.JWTRefreshTTL,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Handlers
|
||||||
|
authMiddleware := handler.NewAuthMiddleware(authSvc)
|
||||||
|
authHandler := handler.NewAuthHandler(authSvc)
|
||||||
|
|
||||||
|
r := handler.NewRouter(authMiddleware, authHandler)
|
||||||
|
|
||||||
slog.Info("starting server", "addr", cfg.ListenAddr)
|
slog.Info("starting server", "addr", cfg.ListenAddr)
|
||||||
if err := r.Run(cfg.ListenAddr); err != nil {
|
if err := r.Run(cfg.ListenAddr); err != nil {
|
||||||
|
|||||||
@ -9,6 +9,7 @@ CREATE SCHEMA IF NOT EXISTS acl;
|
|||||||
CREATE SCHEMA IF NOT EXISTS activity;
|
CREATE SCHEMA IF NOT EXISTS activity;
|
||||||
|
|
||||||
-- UUID v7 generator
|
-- UUID v7 generator
|
||||||
|
-- +goose StatementBegin
|
||||||
CREATE OR REPLACE FUNCTION public.uuid_v7(cts timestamptz DEFAULT clock_timestamp())
|
CREATE OR REPLACE FUNCTION public.uuid_v7(cts timestamptz DEFAULT clock_timestamp())
|
||||||
RETURNS uuid LANGUAGE plpgsql AS $$
|
RETURNS uuid LANGUAGE plpgsql AS $$
|
||||||
DECLARE
|
DECLARE
|
||||||
@ -38,14 +39,17 @@ BEGIN
|
|||||||
substring(entropy from 1 for 12))::uuid;
|
substring(entropy from 1 for 12))::uuid;
|
||||||
END;
|
END;
|
||||||
$$;
|
$$;
|
||||||
|
-- +goose StatementEnd
|
||||||
|
|
||||||
-- Extract timestamp from UUID v7
|
-- Extract timestamp from UUID v7
|
||||||
|
-- +goose StatementBegin
|
||||||
CREATE OR REPLACE FUNCTION public.uuid_extract_timestamp(uuid_val uuid)
|
CREATE OR REPLACE FUNCTION public.uuid_extract_timestamp(uuid_val uuid)
|
||||||
RETURNS timestamptz LANGUAGE sql IMMUTABLE PARALLEL SAFE AS $$
|
RETURNS timestamptz LANGUAGE sql IMMUTABLE PARALLEL SAFE AS $$
|
||||||
SELECT to_timestamp(
|
SELECT to_timestamp(
|
||||||
('x' || left(replace(uuid_val::text, '-', ''), 12))::bit(48)::bigint / 1000.0
|
('x' || left(replace(uuid_val::text, '-', ''), 12))::bit(48)::bigint / 1000.0
|
||||||
);
|
);
|
||||||
$$;
|
$$;
|
||||||
|
-- +goose StatementEnd
|
||||||
|
|
||||||
-- +goose Down
|
-- +goose Down
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,11 @@ INSERT INTO activity.action_types (name) VALUES
|
|||||||
-- Sessions
|
-- Sessions
|
||||||
('session_terminate');
|
('session_terminate');
|
||||||
|
|
||||||
|
INSERT INTO core.users (name, password, is_admin, can_create) VALUES
|
||||||
|
('admin', '$2a$10$zk.VTFjRRxbkTE7cKfc7KOWeZfByk1VEkbkgZMJggI1fFf.yDEHZy', true, true);
|
||||||
|
|
||||||
-- +goose Down
|
-- +goose Down
|
||||||
|
|
||||||
|
DELETE FROM core.users WHERE name = 'admin';
|
||||||
DELETE FROM activity.action_types;
|
DELETE FROM activity.action_types;
|
||||||
DELETE FROM core.object_types;
|
DELETE FROM core.object_types;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user