""" Configuration management for HCFS API. Handles environment-based configuration with validation and defaults. """ import os from typing import List, Optional, Dict, Any from pydantic import BaseSettings, Field, validator from pathlib import Path class DatabaseConfig(BaseSettings): """Database configuration settings.""" # SQLite settings db_path: str = Field(default="hcfs_production.db", description="Path to SQLite database") vector_db_path: str = Field(default="hcfs_vectors_production.db", description="Path to vector database") # Connection settings pool_size: int = Field(default=10, description="Database connection pool size") max_overflow: int = Field(default=20, description="Maximum connection overflow") pool_timeout: int = Field(default=30, description="Connection pool timeout in seconds") # Performance settings cache_size: int = Field(default=1000, description="Database cache size") enable_wal_mode: bool = Field(default=True, description="Enable SQLite WAL mode") synchronous_mode: str = Field(default="NORMAL", description="SQLite synchronous mode") class Config: env_prefix = "HCFS_DB_" class EmbeddingConfig(BaseSettings): """Embedding system configuration.""" # Model settings model_name: str = Field(default="mini", description="Embedding model to use") cache_size: int = Field(default=2000, description="Embedding cache size") batch_size: int = Field(default=32, description="Batch processing size") # Performance settings max_workers: int = Field(default=4, description="Maximum worker threads") timeout_seconds: int = Field(default=300, description="Operation timeout") # Vector database settings vector_dimension: int = Field(default=384, description="Vector dimension") similarity_threshold: float = Field(default=0.0, description="Default similarity threshold") class Config: env_prefix = "HCFS_EMBEDDING_" class APIConfig(BaseSettings): """API server configuration.""" # Server settings host: str = Field(default="0.0.0.0", description="Server host") port: int = Field(default=8000, description="Server port") workers: int = Field(default=1, description="Number of worker processes") # Security settings secret_key: str = Field(default="dev-secret-key-change-in-production", description="JWT secret key") algorithm: str = Field(default="HS256", description="JWT algorithm") token_expire_minutes: int = Field(default=30, description="JWT token expiration time") # CORS settings cors_origins: List[str] = Field( default=["http://localhost:3000", "http://localhost:8080"], description="Allowed CORS origins" ) cors_credentials: bool = Field(default=True, description="Allow credentials in CORS") # Rate limiting rate_limit_requests: int = Field(default=100, description="Requests per minute") rate_limit_burst: int = Field(default=20, description="Burst requests allowed") # Feature flags enable_auth: bool = Field(default=True, description="Enable authentication") enable_websocket: bool = Field(default=True, description="Enable WebSocket support") enable_metrics: bool = Field(default=True, description="Enable Prometheus metrics") enable_docs: bool = Field(default=True, description="Enable API documentation") class Config: env_prefix = "HCFS_API_" class MonitoringConfig(BaseSettings): """Monitoring and observability configuration.""" # Logging settings log_level: str = Field(default="INFO", description="Logging level") log_format: str = Field(default="json", description="Log format (json/text)") log_file: Optional[str] = Field(default=None, description="Log file path") # Metrics settings metrics_enabled: bool = Field(default=True, description="Enable metrics collection") metrics_port: int = Field(default=9090, description="Metrics server port") # Health check settings health_check_interval: int = Field(default=30, description="Health check interval in seconds") health_check_timeout: int = Field(default=5, description="Health check timeout") # Tracing settings tracing_enabled: bool = Field(default=False, description="Enable distributed tracing") tracing_sample_rate: float = Field(default=0.1, description="Tracing sample rate") jaeger_endpoint: Optional[str] = Field(default=None, description="Jaeger endpoint") class Config: env_prefix = "HCFS_MONITORING_" class RedisConfig(BaseSettings): """Redis configuration for caching and rate limiting.""" # Connection settings host: str = Field(default="localhost", description="Redis host") port: int = Field(default=6379, description="Redis port") db: int = Field(default=0, description="Redis database number") password: Optional[str] = Field(default=None, description="Redis password") # Pool settings max_connections: int = Field(default=20, description="Maximum Redis connections") socket_timeout: int = Field(default=5, description="Socket timeout in seconds") # Cache settings default_ttl: int = Field(default=3600, description="Default cache TTL in seconds") key_prefix: str = Field(default="hcfs:", description="Redis key prefix") class Config: env_prefix = "HCFS_REDIS_" class SecurityConfig(BaseSettings): """Security configuration.""" # Authentication require_auth: bool = Field(default=True, description="Require authentication") api_key_header: str = Field(default="X-API-Key", description="API key header name") # Rate limiting rate_limit_enabled: bool = Field(default=True, description="Enable rate limiting") rate_limit_storage: str = Field(default="memory", description="Rate limit storage (memory/redis)") # HTTPS settings force_https: bool = Field(default=False, description="Force HTTPS in production") hsts_max_age: int = Field(default=31536000, description="HSTS max age") # Request validation max_request_size: int = Field(default=10 * 1024 * 1024, description="Maximum request size in bytes") max_query_params: int = Field(default=100, description="Maximum query parameters") # Content security allowed_content_types: List[str] = Field( default=["application/json", "application/x-www-form-urlencoded", "multipart/form-data"], description="Allowed content types" ) class Config: env_prefix = "HCFS_SECURITY_" class HCFSConfig(BaseSettings): """Main HCFS configuration combining all subsystem configs.""" # Environment environment: str = Field(default="development", description="Environment (development/staging/production)") debug: bool = Field(default=False, description="Enable debug mode") # Application info app_name: str = Field(default="HCFS API", description="Application name") app_version: str = Field(default="2.0.0", description="Application version") app_description: str = Field(default="Context-Aware Hierarchical Context File System API", description="App description") # Configuration file path config_file: Optional[str] = Field(default=None, description="Path to configuration file") # Subsystem configurations database: DatabaseConfig = Field(default_factory=DatabaseConfig) embedding: EmbeddingConfig = Field(default_factory=EmbeddingConfig) api: APIConfig = Field(default_factory=APIConfig) monitoring: MonitoringConfig = Field(default_factory=MonitoringConfig) redis: RedisConfig = Field(default_factory=RedisConfig) security: SecurityConfig = Field(default_factory=SecurityConfig) class Config: env_prefix = "HCFS_" env_file = ".env" env_file_encoding = "utf-8" @validator('environment') def validate_environment(cls, v): """Validate environment value.""" allowed = ['development', 'staging', 'production'] if v not in allowed: raise ValueError(f'Environment must be one of: {allowed}') return v @validator('debug') def validate_debug_in_production(cls, v, values): """Ensure debug is disabled in production.""" if values.get('environment') == 'production' and v: raise ValueError('Debug mode cannot be enabled in production') return v def is_production(self) -> bool: """Check if running in production environment.""" return self.environment == 'production' def is_development(self) -> bool: """Check if running in development environment.""" return self.environment == 'development' def get_database_url(self) -> str: """Get database URL.""" return f"sqlite:///{self.database.db_path}" def get_redis_url(self) -> str: """Get Redis URL.""" if self.redis.password: return f"redis://:{self.redis.password}@{self.redis.host}:{self.redis.port}/{self.redis.db}" return f"redis://{self.redis.host}:{self.redis.port}/{self.redis.db}" def load_from_file(self, config_path: str) -> None: """Load configuration from YAML file.""" import yaml config_file = Path(config_path) if not config_file.exists(): raise FileNotFoundError(f"Configuration file not found: {config_path}") with open(config_file, 'r') as f: config_data = yaml.safe_load(f) # Update configuration for key, value in config_data.items(): if hasattr(self, key): setattr(self, key, value) def to_dict(self) -> Dict[str, Any]: """Convert configuration to dictionary.""" return self.dict() def save_to_file(self, config_path: str) -> None: """Save configuration to YAML file.""" import yaml config_data = self.to_dict() with open(config_path, 'w') as f: yaml.dump(config_data, f, default_flow_style=False, indent=2) # Global configuration instance config = HCFSConfig() def get_config() -> HCFSConfig: """Get the global configuration instance.""" return config def load_config(config_path: Optional[str] = None, **overrides) -> HCFSConfig: """Load configuration with optional file and overrides.""" global config # Load from file if provided if config_path: config.load_from_file(config_path) # Apply overrides for key, value in overrides.items(): if hasattr(config, key): setattr(config, key, value) return config def create_config_template(output_path: str = "hcfs_config.yaml") -> None: """Create a configuration template file.""" template_config = HCFSConfig() template_config.save_to_file(output_path) print(f"Configuration template created: {output_path}") if __name__ == "__main__": # Create configuration template create_config_template()