package config import ( "fmt" "log/slog" "os" "strconv" "strings" ) type Config struct { AppEnv string LogLevel slog.Level BackendAddr string ConsoleProxyAddr string WorkerConcurrency int DatabaseURL string DatabaseDirectURL string SupabaseURL string SupabaseJWKSURL string SupabaseIssuer string SupabaseJWTSecret string RedisAddr string AppSiteURL string } func Load() (Config, error) { logLevel, err := parseLogLevel(getenv("LOG_LEVEL", "info")) if err != nil { return Config{}, err } workerConcurrency, err := intFromEnv("WORKER_CONCURRENCY", 5) if err != nil { return Config{}, err } if workerConcurrency < 1 { return Config{}, fmt.Errorf("WORKER_CONCURRENCY must be greater than 0") } return Config{ AppEnv: getenv("APP_ENV", "development"), LogLevel: logLevel, BackendAddr: getenv("BACKEND_ADDR", ":8080"), ConsoleProxyAddr: getenv("CONSOLE_PROXY_ADDR", ":8081"), WorkerConcurrency: workerConcurrency, DatabaseURL: os.Getenv("DATABASE_URL"), DatabaseDirectURL: os.Getenv("DATABASE_DIRECT_URL"), SupabaseURL: os.Getenv("SUPABASE_URL"), SupabaseJWKSURL: os.Getenv("SUPABASE_JWKS_URL"), SupabaseIssuer: os.Getenv("SUPABASE_ISSUER"), SupabaseJWTSecret: os.Getenv("SUPABASE_JWT_SECRET"), RedisAddr: getenv("REDIS_ADDR", "localhost:6379"), AppSiteURL: getenv("APP_SITE_URL", "http://localhost:5173"), }, nil } func getenv(key, fallback string) string { if value := strings.TrimSpace(os.Getenv(key)); value != "" { return value } return fallback } func intFromEnv(key string, fallback int) (int, error) { raw := strings.TrimSpace(os.Getenv(key)) if raw == "" { return fallback, nil } value, err := strconv.Atoi(raw) if err != nil { return 0, fmt.Errorf("%s must be an integer: %w", key, err) } return value, nil } func parseLogLevel(raw string) (slog.Level, error) { switch strings.ToLower(strings.TrimSpace(raw)) { case "debug": return slog.LevelDebug, nil case "info": return slog.LevelInfo, nil case "warn", "warning": return slog.LevelWarn, nil case "error": return slog.LevelError, nil default: return slog.LevelInfo, fmt.Errorf("LOG_LEVEL must be one of debug, info, warn, error") } }