From 5f66eb0e7b5cc16300885fa1945cff66d688dec8 Mon Sep 17 00:00:00 2001 From: jordan Date: Sat, 21 Feb 2026 23:46:12 -0700 Subject: [PATCH] fix: seed dev user from DEV_USER_EMAIL env var so auth survives restarts In standalone mode (no DATABASE_URL), the in-memory user store only had hardcoded demo accounts. Any real email the developer used was lost on every server restart, causing OTP requests to silently fail with "unknown email". NewUserRepository now accepts devEmail + devPassword. If DEV_USER_EMAIL is set, that account is seeded on every startup alongside the demo users. The developer's email is always registered, OTPs route to notify (or log to console), and re-renders/restarts no longer break the auth flow. New config fields: DevUserEmail (DEV_USER_EMAIL) / DevUserPassword (DEV_USER_PASSWORD, default: "DevPassword1"). Co-Authored-By: Claude Sonnet 4.6 --- .../components/service/cmd/server/main.go.tmpl | 2 +- .../service/internal/adapter/memory/user.go.tmpl | 10 +++++++++- .../components/service/internal/config/config.go.tmpl | 9 +++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/internal/adapter/templates/templates/components/service/cmd/server/main.go.tmpl b/internal/adapter/templates/templates/components/service/cmd/server/main.go.tmpl index eb1bfa0..a6d7b8a 100644 --- a/internal/adapter/templates/templates/components/service/cmd/server/main.go.tmpl +++ b/internal/adapter/templates/templates/components/service/cmd/server/main.go.tmpl @@ -135,7 +135,7 @@ func main() { jobQueue, jobReader = setupDBQueue(ctx, cfg, dbPool, sseHub, logger) } else { logger.Info("DATABASE_URL not set — running in standalone mode (in-memory queue + in-process AI)") - userRepo = memory.NewUserRepository() + userRepo = memory.NewUserRepository(cfg.DevUserEmail, cfg.DevUserPassword) sessionRepo = memory.NewSessionRepository() authCodeRepo = memory.NewAuthCodeRepository() mediaRepo = memory.NewMediaRepository() diff --git a/internal/adapter/templates/templates/components/service/internal/adapter/memory/user.go.tmpl b/internal/adapter/templates/templates/components/service/internal/adapter/memory/user.go.tmpl index 5f44651..3d03ae0 100644 --- a/internal/adapter/templates/templates/components/service/internal/adapter/memory/user.go.tmpl +++ b/internal/adapter/templates/templates/components/service/internal/adapter/memory/user.go.tmpl @@ -24,7 +24,9 @@ type UserRepository struct { } // NewUserRepository creates a new in-memory user repository seeded with demo users. -func NewUserRepository() *UserRepository { +// If devEmail is non-empty, an additional user is seeded with that email and devPassword +// so the developer's account survives server restarts without re-registering. +func NewUserRepository(devEmail, devPassword string) *UserRepository { repo := &UserRepository{ users: make(map[domain.UserID]*domain.User), passwords: make(map[domain.UserID]string), @@ -37,6 +39,12 @@ func NewUserRepository() *UserRepository { repo.seedUser("usr_test_001", "test@example.com", "Test User", "Password123", []string{"user"}) repo.seedUser("usr_admin_001", "admin@example.com", "Admin User", "Admin1234", []string{"admin", "user"}) + // Seed the developer's own account if DEV_USER_EMAIL is configured. + // This ensures the email is always registered after restarts without manual re-registration. + if devEmail != "" { + repo.seedUser("usr_dev_001", devEmail, "Dev User", devPassword, []string{"admin", "user"}) + } + return repo } diff --git a/internal/adapter/templates/templates/components/service/internal/config/config.go.tmpl b/internal/adapter/templates/templates/components/service/internal/config/config.go.tmpl index f4f7bc1..184d751 100644 --- a/internal/adapter/templates/templates/components/service/internal/config/config.go.tmpl +++ b/internal/adapter/templates/templates/components/service/internal/config/config.go.tmpl @@ -36,6 +36,12 @@ type Config struct { SupportEmail string // SUPPORT_EMAIL, default: NOTIFY_FROM value LogoURL string // LOGO_URL, default: "" (hides logo area) BrandColor string // BRAND_COLOR, default: "#6366f1" + + // Dev mode seed user — seeded into the in-memory user store on startup so the + // developer's email is always available without re-registering after each restart. + // No effect when DATABASE_URL is set (production uses real persistence). + DevUserEmail string // DEV_USER_EMAIL, e.g. "you@example.com" + DevUserPassword string // DEV_USER_PASSWORD, default: "DevPassword1" } // Load reads configuration from environment variables. @@ -68,6 +74,9 @@ func Load() *Config { SupportEmail: getEnvDefault("SUPPORT_EMAIL", notifyFrom), LogoURL: os.Getenv("LOGO_URL"), BrandColor: getEnvDefault("BRAND_COLOR", "#6366f1"), + + DevUserEmail: os.Getenv("DEV_USER_EMAIL"), + DevUserPassword: getEnvDefault("DEV_USER_PASSWORD", "DevPassword1"), } return cfg