- Created main application entry point in `main.go`. - Added configuration management in `config/config.go` and tests in `config/config_test.go`. - Implemented handlers for book and stationery uploads in `handlers/book.go` and `handlers/stationery.go`, including validation logic. - Established database connection and services in `services/database.go` and `services/book_service.go`. - Defined models for books and stationery in `models/book.go` and `models/stationery.go`. - Set up Firebase integration for image uploads in `services/firebase.go`. - Created migration scripts for database schema in `migrations/001_create_tables.sql` and subsequent updates. - Added CORS and error handling middleware. - Included comprehensive tests for handlers, services, and utilities. - Documented API endpoints and usage in `README.md` and migration instructions in `migrations/README.md`. - Introduced `.gitignore` to exclude unnecessary files and directories. - Added Go module support with `go.mod` and `go.sum` files. - Implemented utility functions for slug generation and validation in `utils/slug.go` and `utils/validation.go`.
108 lines
2.7 KiB
Go
108 lines
2.7 KiB
Go
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
|
|
}
|