package config import ( "context" "fmt" "os" "strconv" ) type Config struct { ServerPort string BaseURL string JWTSecret string UploadPath string DatabaseHost string DatabasePort string DatabaseUser string DatabasePassword string DatabaseName string TestMode bool RateLimitEnabled bool RequestsPerMinute int } func LoadConfig() *Config { port := getEnv("SERVER_PORT", "8765") return &Config{ ServerPort: port, BaseURL: getEnv("BASE_URL", "http://localhost:"+port), DatabaseHost: getEnv("DATABASE_HOST", "localhost"), DatabasePort: getEnv("DATABASE_PORT", "5432"), DatabaseUser: getEnv("DATABASE_USER", "postgres"), DatabasePassword: getEnv("DATABASE_PASSWORD", "password"), DatabaseName: getEnv("DATABASE_NAME", "bookhoard"), JWTSecret: getEnv("JWT_SECRET", "your-secret-key"), UploadPath: getEnv("UPLOAD_PATH", "./uploads"), TestMode: getEnvBool("TEST_MODE", false), RateLimitEnabled: getEnvBool("RATE_LIMIT_ENABLED", true), RequestsPerMinute: getEnvInt("REQUESTS_PER_MINUTE", 10), } } func (c *Config) DatabaseURL() string { return fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable", c.DatabaseUser, c.DatabasePassword, c.DatabaseHost, c.DatabasePort, c.DatabaseName) } // SystemConfigGetter returns the value for a system config key, or an error. type SystemConfigGetter func(ctx context.Context, key string) (string, error) // GetBaseURL returns the base URL from system configuration database, or empty // string if not set. The getter abstraction avoids importing the database package. func GetBaseURL(ctx context.Context, getter SystemConfigGetter) string { val, err := getter(ctx, "base_url") if err == nil && val != "" { return val } return "" } func getEnv(key, defaultValue string) string { if value := os.Getenv(key); value != "" { return value } return defaultValue } func getEnvBool(key string, defaultValue bool) bool { if value := os.Getenv(key); value != "" { boolVal, err := strconv.ParseBool(value) if err == nil { return boolVal } } return defaultValue } func getEnvInt(key string, defaultValue int) int { if value := os.Getenv(key); value != "" { intVal, err := strconv.Atoi(value) if err == nil { return intVal } } return defaultValue }