package config import ( "fmt" "os" "time" "gopkg.in/yaml.v3" ) type Config struct { Server ServerConfig `yaml:"server"` Site SiteConfig `yaml:"site"` Wedding WeddingConfig `yaml:"wedding"` Storage StorageConfig `yaml:"storage"` Email EmailConfig `yaml:"email"` Upload UploadConfig `yaml:"upload"` } type ServerConfig struct { Port int `yaml:"port"` } type SiteConfig struct { URL string `yaml:"url"` } type WeddingConfig struct { Date time.Time `yaml:"date"` CeremonyTime string `yaml:"ceremony_time"` RSVPBy time.Time `yaml:"rsvp_by"` VenueName string `yaml:"venue_name"` VenueAddress string `yaml:"venue_address"` RSVPPhone string `yaml:"rsvp_phone"` } type StorageConfig struct { DataDir string `yaml:"data_dir"` } type EmailConfig struct { SMTPHost string `yaml:"smtp_host"` SMTPPort int `yaml:"smtp_port"` SMTPUser string `yaml:"smtp_user"` SMTPPass string `yaml:"smtp_pass"` From string `yaml:"from"` To string `yaml:"to"` } type UploadConfig struct { MaxSizeMB int `yaml:"max_size_mb"` MaxFiles int `yaml:"max_files"` } // Path resolves the config file location: $CONFIG_PATH, or ./config.yaml. func Path() string { if p := os.Getenv("CONFIG_PATH"); p != "" { return p } return "config.yaml" } func Load(path string) (*Config, error) { data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("reading config %s: %w", path, err) } var cfg Config if err := yaml.Unmarshal(data, &cfg); err != nil { return nil, fmt.Errorf("parsing config %s: %w", path, err) } if cfg.Server.Port == 0 { cfg.Server.Port = 8080 } if cfg.Storage.DataDir == "" { cfg.Storage.DataDir = "./data" } if cfg.Upload.MaxSizeMB == 0 { cfg.Upload.MaxSizeMB = 15 } if cfg.Upload.MaxFiles == 0 { cfg.Upload.MaxFiles = 10 } if cfg.Wedding.Date.IsZero() { return nil, fmt.Errorf("wedding.date is required in %s", path) } if cfg.Wedding.RSVPBy.IsZero() { return nil, fmt.Errorf("wedding.rsvp_by is required in %s", path) } return &cfg, nil }