package config import ( "fmt" "os" "github.com/joho/godotenv" ) // Config holds all application configuration type Config struct { // Server Port string FrontendURL string // Database DBHost string DBPort string DBUser string DBPassword string DBName string // Firebase FirebaseProjectID string FirebaseStorageBucket string FirebaseCredentialsFile string } // LoadConfig loads configuration from environment variables // Loading order (later files override earlier ones): // 1. .env (base/default values) // 2. .env.local (local development overrides - takes precedence) // Note: OS environment variables take highest precedence (godotenv won't override them) func LoadConfig() (*Config, error) { // Load .env file if it exists (optional, won't error if missing) _ = godotenv.Load(".env") // Load .env.local if it exists (overrides .env values) // This allows local development overrides without modifying .env _ = godotenv.Load(".env.local") cfg := &Config{ // Server Port: getEnv("PORT", "8080"), FrontendURL: getEnv("FRONTEND_URL", "http://localhost:5173"), // Database DBHost: getEnv("DB_HOST", "localhost"), DBPort: getEnv("DB_PORT", "5432"), DBUser: getEnv("DB_USER", ""), DBPassword: getEnv("DB_PASSWORD", ""), DBName: getEnv("DB_NAME", ""), // Firebase FirebaseProjectID: getEnv("FIREBASE_PROJECT_ID", ""), FirebaseStorageBucket: getEnv("FIREBASE_STORAGE_BUCKET", ""), FirebaseCredentialsFile: getEnv("FIREBASE_CREDENTIALS_FILE", ""), } // Validate required fields if err := cfg.Validate(); err != nil { return nil, fmt.Errorf("config validation failed: %w", err) } return cfg, nil } // Validate checks that all required configuration values are set func (c *Config) Validate() error { var missing []string if c.DBUser == "" { missing = append(missing, "DB_USER") } if c.DBPassword == "" { missing = append(missing, "DB_PASSWORD") } if c.DBName == "" { missing = append(missing, "DB_NAME") } if c.FirebaseProjectID == "" { missing = append(missing, "FIREBASE_PROJECT_ID") } if c.FirebaseStorageBucket == "" { missing = append(missing, "FIREBASE_STORAGE_BUCKET") } if c.FirebaseCredentialsFile == "" { // Check if GOOGLE_APPLICATION_CREDENTIALS is set as fallback if os.Getenv("GOOGLE_APPLICATION_CREDENTIALS") == "" { missing = append(missing, "FIREBASE_CREDENTIALS_FILE (or GOOGLE_APPLICATION_CREDENTIALS)") } } if len(missing) > 0 { return fmt.Errorf("missing required environment variables: %v", missing) } return nil } // getEnv gets an environment variable or returns a default value func getEnv(key, defaultValue string) string { if value := os.Getenv(key); value != "" { return value } return defaultValue }