package config import ( "fmt" "os" "strings" "time" "gopkg.in/yaml.v3" ) type Config struct { Server ServerConfig `yaml:"server"` Database DatabaseConfig `yaml:"database"` Admin AdminConfig `yaml:"admin"` Cache CacheConfig `yaml:"cache"` HealthCheck HealthCheckConfig `yaml:"health_check"` Security SecurityConfig `yaml:"security"` Gateway GatewayConfig `yaml:"gateway"` } type GatewayConfig struct { MaxRetries int `yaml:"max_retries"` RetryBackoffMs int `yaml:"retry_backoff_ms"` } type ServerConfig struct { Addr string `yaml:"addr"` } type DatabaseConfig struct { Path string `yaml:"path"` } type AdminConfig struct { Username string `yaml:"username"` Password string `yaml:"password"` } type CacheConfig struct { UsageFlushInterval time.Duration `yaml:"usage_flush_interval"` } type HealthCheckConfig struct { Interval time.Duration `yaml:"interval"` } type SecurityConfig struct { EncryptionKey string `yaml:"encryption_key"` SessionTTL time.Duration `yaml:"session_ttl"` IPAllowlist []string `yaml:"ip_allowlist"` TrustedProxies []string `yaml:"trusted_proxies"` LoginMaxAttempts int `yaml:"login_max_attempts"` LoginLockout time.Duration `yaml:"login_lockout"` } func Load(path string) (*Config, error) { data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("read config: %w", err) } cfg := Default() if err := yaml.Unmarshal(data, cfg); err != nil { return nil, fmt.Errorf("parse config: %w", err) } resolveEnv(cfg) return cfg, nil } func Default() *Config { return &Config{ Server: ServerConfig{Addr: ":8080"}, Database: DatabaseConfig{ Path: "./data/luminary.db", }, Admin: AdminConfig{ Username: "admin", Password: "admin123", }, Cache: CacheConfig{ UsageFlushInterval: 5 * time.Second, }, HealthCheck: HealthCheckConfig{ Interval: 30 * time.Second, }, Security: SecurityConfig{ EncryptionKey: "change-me-in-production-32bytes!!", SessionTTL: 24 * time.Hour, LoginMaxAttempts: 5, LoginLockout: 15 * time.Minute, }, Gateway: GatewayConfig{ MaxRetries: 3, RetryBackoffMs: 200, }, } } func resolveEnv(cfg *Config) { cfg.Admin.Username = resolveEnvValue(cfg.Admin.Username) cfg.Admin.Password = resolveEnvValue(cfg.Admin.Password) cfg.Security.EncryptionKey = resolveEnvValue(cfg.Security.EncryptionKey) } func resolveEnvValue(v string) string { if strings.HasPrefix(v, "env.") { key := strings.TrimPrefix(v, "env.") if val := os.Getenv(key); val != "" { return val } } return v }