Add initial project structure with core functionality for book and stationery uploads
- 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`.
This commit is contained in:
107
config/config.go
Normal file
107
config/config.go
Normal file
@@ -0,0 +1,107 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user