"""Application configuration via Pydantic Settings.""" from __future__ import annotations from functools import lru_cache from typing import Literal from pydantic_settings import BaseSettings, SettingsConfigDict class Settings(BaseSettings): """Application settings loaded from environment variables.""" model_config = SettingsConfigDict( env_file=".env", env_file_encoding="utf-8", case_sensitive=False, extra="ignore", ) # Environment environment: Literal["development", "production", "testing"] = "development" log_level: str = "INFO" # Database database_url: str = "postgresql+asyncpg://leocrm:leocrm@localhost:5432/leocrm_test" db_pool_size: int = 10 db_max_overflow: int = 20 db_echo: bool = False # Redis redis_url: str = "redis://localhost:6379/0" session_ttl_seconds: int = 28800 # 8 hours # Auth bcrypt_rounds: int = 12 session_cookie_name: str = "leocrm_session" session_cookie_secure: bool = False # True in production behind HTTPS session_cookie_samesite: str = "strict" session_cookie_httponly: bool = True password_reset_expiry_hours: int = 1 # Storage storage_path: str = "/tmp" # SMTP smtp_host: str = "localhost" smtp_port: int = 587 smtp_username: str | None = None smtp_password: str | None = None smtp_from_email: str = "noreply@leocrm.local" smtp_use_tls: bool = True # Secret Key (for signing, sessions, etc.) secret_key: str = "change-me-in-production-use-a-secure-random-string" # CORS cors_origins: str = "http://localhost:5173,http://localhost:3000" # Rate Limiting rate_limit_login_max: int = 5 rate_limit_login_window: int = 900 # 15 min rate_limit_reset_max: int = 3 rate_limit_reset_window: int = 3600 # 1 hour rate_limit_reset_confirm_max: int = 5 rate_limit_reset_confirm_window: int = 3600 # 1 hour rate_limit_general_max: int = 60 rate_limit_general_window: int = 60 # 1 min @property def cors_origin_list(self) -> list[str]: """Parse comma-separated CORS origins into a list.""" return [o.strip() for o in self.cors_origins.split(",") if o.strip()] @lru_cache def get_settings() -> Settings: """Get cached settings instance.""" return Settings() # Module-level singleton for backward-compatible imports settings = get_settings()