# Configuration Management ## Configuration Architecture The system implements a hierarchical, environment-driven configuration system designed for flexibility, type safety, and testability. Configuration is managed through the `internal/serviceconfig` package with domain-specific sub-packages. ## Configuration Hierarchy ### Environment Variable Priority (First Wins) 1. **devbox.json "env"** section - Highest priority for development 2. **devbox.json "init_hook"** exports - Build-time configuration 3. **.env file** variables - Local overrides 4. **System environment** - Runtime environment variables ### Configuration Loading Process ```go // 1. Load .env file if present (development) godotenv.Load() // 2. Parse environment variables into struct env.Parse(&config) // 3. Validate required fields config.Validate() // 4. Initialize dependent services config.Initialize(ctx) ``` ## Base Configuration Structure ### Core Configuration (`serviceconfig/common.go`) ```go type BaseConfig struct { // Application LogLevel string `env:"LOG_LEVEL" envDefault:"INFO"` // Server Port int `env:"PORT" envDefault:"8080"` HTTPHost string `env:"HTTP_HOST" envDefault:"0.0.0.0"` // Feature Flags DisableAuth bool `env:"DISABLE_AUTH" envDefault:"false"` EnableOTEL bool `env:"ENABLE_OTEL" envDefault:"false"` // Observability MetricsPath string `env:"METRICS_PATH" envDefault:"/metrics"` } ``` ### Configuration Providers Pattern ```go // Interface composition for service dependencies type ConfigProvider interface { GetLogLevel() string GetPort() int GetHTTPHost() string IsAuthDisabled() bool } // Service-specific configuration embeds base type ServiceConfig struct { BaseConfig DatabaseConfig database.Config AWSConfig aws.Config QueueConfig queue.Config } ``` ## Domain-Specific Configuration ### Database Configuration (`serviceconfig/database/`) ```go type Config struct { // Connection Host string `env:"PGHOST" envDefault:"localhost"` Port int `env:"PGPORT" envDefault:"5432"` Database string `env:"PGDATABASE"` Username string `env:"PGUSER"` Password string `env:"PGPASSWORD"` // Connection Pool MaxOpenConns int `env:"DB_MAX_OPEN_CONNS" envDefault:"25"` MaxIdleConns int `env:"DB_MAX_IDLE_CONNS" envDefault:"25"` ConnMaxLifetime int `env:"DB_CONN_MAX_LIFETIME" envDefault:"300"` // Security SSLMode string `env:"DB_SSL_MODE" envDefault:"require"` NoSSL bool `env:"DB_NOSSL" envDefault:"false"` } // Provider interface type ConfigProvider interface { GetDatabaseConfig() Config } // Connection pool management func (c Config) CreatePool(ctx context.Context) (*pgxpool.Pool, error) { dsn := c.buildConnectionString() return pgxpool.New(ctx, dsn) } ``` ### AWS Configuration (`serviceconfig/aws/`) ```go type Config struct { // Credentials Region string `env:"AWS_REGION" envDefault:"us-east-1"` AccessKeyID string `env:"AWS_ACCESS_KEY_ID"` SecretAccessKey string `env:"AWS_SECRET_ACCESS_KEY"` SessionToken string `env:"AWS_SESSION_TOKEN"` Profile string `env:"AWS_PROFILE"` // Endpoints (for LocalStack/testing) EndpointURL string `env:"AWS_ENDPOINT_URL"` S3UsePathStyle bool `env:"AWS_S3_USE_PATH_STYLE" envDefault:"false"` // Service-specific S3Bucket string `env:"S3_BUCKET"` TextractRoleARN string `env:"TEXTRACT_ROLE_ARN"` } // SDK integration func (c Config) LoadAWSConfig(ctx context.Context) (aws.Config, error) { var opts []func(*config.LoadOptions) error if c.Region != "" { opts = append(opts, config.WithRegion(c.Region)) } if c.EndpointURL != "" { opts = append(opts, config.WithEndpointResolverWithOptions( aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) { return aws.Endpoint{URL: c.EndpointURL}, nil }), )) } return config.LoadDefaultConfig(ctx, opts...) } ``` ### Queue Configuration (`serviceconfig/queue/`) ```go // Base queue configuration type Config struct { // Connection QueueURL string `env:"QUEUE_URL"` MaxMessages int32 `env:"QUEUE_MAX_MESSAGES" envDefault:"10"` WaitTimeSeconds int32 `env:"QUEUE_WAIT_TIME" envDefault:"20"` VisibilityTimeout int32 `env:"QUEUE_VISIBILITY_TIMEOUT" envDefault:"30"` // Processing WorkerCount int `env:"QUEUE_WORKER_COUNT" envDefault:"5"` MaxRetries int `env:"QUEUE_MAX_RETRIES" envDefault:"3"` RetryDelay int `env:"QUEUE_RETRY_DELAY" envDefault:"5"` } // Service-specific queue configs type DocumentInitConfig struct { Config DocumentSyncURL string `env:"DOCUMENT_SYNC_URL"` } type QueryConfig struct { Config QuerySyncURL string `env:"QUERY_SYNC_URL"` } ``` ### Authentication Configuration (`serviceconfig/auth/`) ```go type Config struct { // Cognito Configuration UserPoolID string `env:"COGNITO_USER_POOL_ID"` ClientID string `env:"COGNITO_CLIENT_ID"` ClientSecret string `env:"COGNITO_CLIENT_SECRET" envSecret:"true"` Domain string `env:"COGNITO_DOMAIN"` // URLs RedirectURL string `env:"COGNITO_REDIRECT_URL"` LogoutURL string `env:"COGNITO_LOGOUT_URL"` // JWT Configuration JWKSCacheExpiry time.Duration `env:"JWKS_CACHE_EXPIRY" envDefault:"1h"` TokenExpiry time.Duration `env:"TOKEN_EXPIRY" envDefault:"24h"` // Feature Flags DisableAuth bool `env:"DISABLE_AUTH" envDefault:"false"` } // Dynamic URL generation func (c Config) GetAuthorizationURL() string { return fmt.Sprintf("https://%s.auth.%s.amazoncognito.com/oauth2/authorize", c.Domain, extractRegion(c.UserPoolID)) } func (c Config) GetTokenURL() string { return fmt.Sprintf("https://%s.auth.%s.amazoncognito.com/oauth2/token", c.Domain, extractRegion(c.UserPoolID)) } ``` ## Environment Variables Reference ### Core Application Variables ```bash # Logging and Debugging LOG_LEVEL=DEBUG|INFO|WARN|ERROR # Default: INFO ENABLE_OTEL=true|false # Default: false # Server Configuration PORT=8080 # Default: 8080 HTTP_HOST=0.0.0.0 # Default: 0.0.0.0 METRICS_PATH=/metrics # Default: /metrics # Feature Flags DISABLE_AUTH=true|false # Default: false (enable for local dev) ``` ### Database Variables ```bash # Connection PGHOST=localhost # Database host PGPORT=5432 # Database port PGDATABASE=queryorchestration # Database name PGUSER=postgres # Database user PGPASSWORD=password # Database password # Connection Pool DB_MAX_OPEN_CONNS=25 # Default: 25 DB_MAX_IDLE_CONNS=25 # Default: 25 DB_CONN_MAX_LIFETIME=300 # Seconds, Default: 300 # Security DB_SSL_MODE=require|disable # Default: require DB_NOSSL=true|false # Default: false (for local dev) ``` ### AWS Configuration Variables ```bash # Credentials AWS_REGION=us-east-1 # AWS region AWS_ACCESS_KEY_ID=your-access-key # AWS access key AWS_SECRET_ACCESS_KEY=your-secret # AWS secret key AWS_SESSION_TOKEN=session-token # Optional session token AWS_PROFILE=default # Optional AWS profile # LocalStack/Testing AWS_ENDPOINT_URL=http://localstack:4566 # Override AWS endpoints AWS_S3_USE_PATH_STYLE=true|false # S3 path style (LocalStack) # Service Configuration S3_BUCKET=documents-bucket # S3 bucket for documents TEXTRACT_ROLE_ARN=arn:aws:iam::... # Textract service role ``` ### Queue Configuration Variables ```bash # Queue URLs (SQS) STORE_EVENT_URL=https://sqs.region.amazonaws.com/account/store-events DOCUMENT_INIT_URL=https://sqs.region.amazonaws.com/account/doc-init DOCUMENT_SYNC_URL=https://sqs.region.amazonaws.com/account/doc-sync DOCUMENT_CLEAN_URL=https://sqs.region.amazonaws.com/account/doc-clean DOCUMENT_TEXT_URL=https://sqs.region.amazonaws.com/account/doc-text QUERY_SYNC_URL=https://sqs.region.amazonaws.com/account/query-sync QUERY_URL=https://sqs.region.amazonaws.com/account/query CLIENT_SYNC_URL=https://sqs.region.amazonaws.com/account/client-sync QUERY_VERSION_SYNC_URL=https://sqs.region.amazonaws.com/account/query-version-sync # Queue Processing QUEUE_MAX_MESSAGES=10 # Messages per batch QUEUE_WAIT_TIME=20 # Long polling seconds QUEUE_VISIBILITY_TIMEOUT=30 # Message visibility QUEUE_WORKER_COUNT=5 # Concurrent workers QUEUE_MAX_RETRIES=3 # Retry attempts QUEUE_RETRY_DELAY=5 # Retry delay seconds ``` ### Authentication Variables ```bash # AWS Cognito COGNITO_USER_POOL_ID=us-east-1_xxxxxxx # Cognito User Pool ID COGNITO_CLIENT_ID=client-id # Cognito App Client ID COGNITO_CLIENT_SECRET=client-secret # Cognito App Client Secret COGNITO_DOMAIN=your-domain # Cognito domain name # URLs COGNITO_REDIRECT_URL=http://localhost:8080/login-callback COGNITO_LOGOUT_URL=http://localhost:8080/logout # JWT Settings JWKS_CACHE_EXPIRY=1h # JWKS cache duration TOKEN_EXPIRY=24h # JWT token expiry ``` ## Configuration Validation ### Required Field Validation ```go type Config struct { DatabaseURL string `env:"DATABASE_URL,required"` S3Bucket string `env:"S3_BUCKET,required"` QueueURL string `env:"QUEUE_URL,required"` } // Validation on startup func (c *Config) Validate() error { var errors []string if c.DatabaseURL == "" { errors = append(errors, "DATABASE_URL is required") } if c.S3Bucket == "" { errors = append(errors, "S3_BUCKET is required") } if len(errors) > 0 { return fmt.Errorf("configuration validation failed: %s", strings.Join(errors, ", ")) } return nil } ``` ### Secret Masking ```go // Automatic masking of sensitive values in logs type Config struct { DatabasePassword string `env:"PGPASSWORD" envSecret:"true"` AWSSecretKey string `env:"AWS_SECRET_ACCESS_KEY" envSecret:"true"` JWTSecret string `env:"JWT_SECRET" envSecret:"true"` } // String() method automatically masks secrets func (c Config) String() string { return env.String(c) // Automatically masks fields tagged with envSecret } ``` ## Development vs Production Configuration ### Development Environment (.env) ```bash # Local development overrides LOG_LEVEL=DEBUG DISABLE_AUTH=true DB_NOSSL=true AWS_ENDPOINT_URL=http://localstack:4566 AWS_S3_USE_PATH_STYLE=true # Local service URLs PGHOST=localhost PGPORT=5432 ``` ### Production Environment ```bash # Production settings LOG_LEVEL=INFO DISABLE_AUTH=false DB_SSL_MODE=require # Production AWS AWS_REGION=us-east-1 # Credentials from IAM roles or environment # Production database PGHOST=production-db.region.rds.amazonaws.com PGPORT=5432 DB_SSL_MODE=require ``` ### Testing Environment ```bash # Test-specific overrides LOG_LEVEL=WARN DISABLE_AUTH=true DB_NOSSL=true # Test containers PGHOST=test-container AWS_ENDPOINT_URL=http://test-localstack:4566 ``` ## Configuration Best Practices ### Security - **Never commit secrets**: Use environment variables or secret management - **Mask sensitive logs**: Use `envSecret` tag for automatic masking - **Validate inputs**: Check configuration values at startup - **Use least privilege**: Configure minimal required permissions ### Maintainability - **Default values**: Provide sensible defaults for optional configuration - **Documentation**: Document all environment variables and their purpose - **Type safety**: Use strong typing and validation - **Composition**: Build configuration from smaller, focused interfaces ### Testing - **Override-friendly**: Allow easy configuration overrides for tests - **Isolation**: Each test should have independent configuration - **Realistic defaults**: Test configuration should mirror production patterns - **Environment separation**: Clear separation between dev/test/prod configs