// Package config handles configuration loading. package config import ( "fmt" "os" "gopkg.in/yaml.v3" ) // Config holds all application configuration. type Config struct { Server ServerConfig `yaml:"server"` Database DatabaseConfig `yaml:"database"` Storage StorageConfig `yaml:"storage"` Schemas SchemasConfig `yaml:"schemas"` FreeCAD FreeCADConfig `yaml:"freecad"` Odoo OdooConfig `yaml:"odoo"` } // ServerConfig holds HTTP server settings. type ServerConfig struct { Host string `yaml:"host"` Port int `yaml:"port"` BaseURL string `yaml:"base_url"` } // DatabaseConfig holds PostgreSQL connection settings. type DatabaseConfig struct { Host string `yaml:"host"` Port int `yaml:"port"` Name string `yaml:"name"` User string `yaml:"user"` Password string `yaml:"password"` SSLMode string `yaml:"sslmode"` MaxConnections int `yaml:"max_connections"` } // StorageConfig holds MinIO connection settings. type StorageConfig struct { Endpoint string `yaml:"endpoint"` AccessKey string `yaml:"access_key"` SecretKey string `yaml:"secret_key"` Bucket string `yaml:"bucket"` UseSSL bool `yaml:"use_ssl"` Region string `yaml:"region"` } // SchemasConfig holds schema loading settings. type SchemasConfig struct { Directory string `yaml:"directory"` Default string `yaml:"default"` } // FreeCADConfig holds FreeCAD integration settings. type FreeCADConfig struct { URIScheme string `yaml:"uri_scheme"` Executable string `yaml:"executable"` } // OdooConfig holds Odoo ERP integration settings. type OdooConfig struct { Enabled bool `yaml:"enabled"` URL string `yaml:"url"` Database string `yaml:"database"` Username string `yaml:"username"` APIKey string `yaml:"api_key"` } // Load reads configuration from a YAML file. func Load(path string) (*Config, error) { data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("reading config file: %w", err) } // Expand environment variables data = []byte(os.ExpandEnv(string(data))) var cfg Config if err := yaml.Unmarshal(data, &cfg); err != nil { return nil, fmt.Errorf("parsing config YAML: %w", err) } // Apply defaults if cfg.Server.Port == 0 { cfg.Server.Port = 8080 } if cfg.Database.Port == 0 { cfg.Database.Port = 5432 } if cfg.Database.SSLMode == "" { cfg.Database.SSLMode = "require" } if cfg.Database.MaxConnections == 0 { cfg.Database.MaxConnections = 10 } if cfg.Storage.Region == "" { cfg.Storage.Region = "us-east-1" } if cfg.Schemas.Directory == "" { cfg.Schemas.Directory = "/etc/silo/schemas" } if cfg.FreeCAD.URIScheme == "" { cfg.FreeCAD.URIScheme = "silo" } // Override with environment variables if v := os.Getenv("SILO_DB_HOST"); v != "" { cfg.Database.Host = v } if v := os.Getenv("SILO_DB_NAME"); v != "" { cfg.Database.Name = v } if v := os.Getenv("SILO_DB_USER"); v != "" { cfg.Database.User = v } if v := os.Getenv("SILO_DB_PASSWORD"); v != "" { cfg.Database.Password = v } if v := os.Getenv("SILO_MINIO_ENDPOINT"); v != "" { cfg.Storage.Endpoint = v } if v := os.Getenv("SILO_MINIO_ACCESS_KEY"); v != "" { cfg.Storage.AccessKey = v } if v := os.Getenv("SILO_MINIO_SECRET_KEY"); v != "" { cfg.Storage.SecretKey = v } return &cfg, nil }