Initial commit: Project foundation
- Backend: Go API server with Gin framework - Frontend: React setup (placeholder) - ML Service: Python FastAPI skeleton - Docker Compose: Full stack configuration - Database: PostgreSQL schema with migrations - Documentation: Implementation plan and README Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
106
backend/internal/config/config.go
Normal file
106
backend/internal/config/config.go
Normal file
@@ -0,0 +1,106 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Server ServerConfig `yaml:"server"`
|
||||
Database DatabaseConfig `yaml:"database"`
|
||||
VictoriaLogs VictoriaLogsConfig `yaml:"victorialogs"`
|
||||
VMAlert VMAlertConfig `yaml:"vmalert"`
|
||||
MLService MLServiceConfig `yaml:"ml_service"`
|
||||
Auth AuthConfig `yaml:"auth"`
|
||||
RateLimiting RateLimitingConfig `yaml:"rate_limiting"`
|
||||
}
|
||||
|
||||
type ServerConfig struct {
|
||||
Port int `yaml:"port"`
|
||||
ReadTimeout time.Duration `yaml:"read_timeout"`
|
||||
WriteTimeout time.Duration `yaml:"write_timeout"`
|
||||
}
|
||||
|
||||
type DatabaseConfig struct {
|
||||
Host string `yaml:"host"`
|
||||
Port int `yaml:"port"`
|
||||
Name string `yaml:"name"`
|
||||
User string `yaml:"user"`
|
||||
Password string `yaml:"password"`
|
||||
MaxConnections int `yaml:"max_connections"`
|
||||
}
|
||||
|
||||
type VictoriaLogsConfig struct {
|
||||
URL string `yaml:"url"`
|
||||
Timeout time.Duration `yaml:"timeout"`
|
||||
MaxQuerySize int `yaml:"max_query_size"`
|
||||
}
|
||||
|
||||
type VMAlertConfig struct {
|
||||
URL string `yaml:"url"`
|
||||
RulesDir string `yaml:"rules_dir"`
|
||||
ReloadEndpoint string `yaml:"reload_endpoint"`
|
||||
}
|
||||
|
||||
type MLServiceConfig struct {
|
||||
URL string `yaml:"url"`
|
||||
Timeout time.Duration `yaml:"timeout"`
|
||||
}
|
||||
|
||||
type AuthConfig struct {
|
||||
JWTSecret string `yaml:"jwt_secret"`
|
||||
AccessTokenDuration time.Duration `yaml:"access_token_duration"`
|
||||
RefreshTokenDuration time.Duration `yaml:"refresh_token_duration"`
|
||||
}
|
||||
|
||||
type RateLimitingConfig struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
RequestsPerMinute map[string]int `yaml:"requests_per_minute"`
|
||||
}
|
||||
|
||||
// Load loads configuration from YAML file and environment variables
|
||||
func Load(configPath string) (*Config, error) {
|
||||
data, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read config file: %w", err)
|
||||
}
|
||||
|
||||
// Expand environment variables in config
|
||||
expandedData := []byte(os.ExpandEnv(string(data)))
|
||||
|
||||
var cfg Config
|
||||
if err := yaml.Unmarshal(expandedData, &cfg); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse config: %w", err)
|
||||
}
|
||||
|
||||
// Validate required fields
|
||||
if err := cfg.validate(); err != nil {
|
||||
return nil, fmt.Errorf("config validation failed: %w", err)
|
||||
}
|
||||
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
func (c *Config) validate() error {
|
||||
if c.Database.Password == "" {
|
||||
return fmt.Errorf("database password is required")
|
||||
}
|
||||
if c.Auth.JWTSecret == "" {
|
||||
return fmt.Errorf("JWT secret is required")
|
||||
}
|
||||
if len(c.Auth.JWTSecret) < 32 {
|
||||
return fmt.Errorf("JWT secret must be at least 32 characters")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDSN returns the PostgreSQL connection string
|
||||
func (c *DatabaseConfig) GetDSN() string {
|
||||
return fmt.Sprintf(
|
||||
"host=%s port=%d user=%s password=%s dbname=%s sslmode=disable",
|
||||
c.Host, c.Port, c.User, c.Password, c.Name,
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user