"""Application settings using Pydantic Settings.""" from pydantic import Field, SecretStr from pydantic_settings import BaseSettings, SettingsConfigDict class Settings(BaseSettings): """Runtime application configuration.""" model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="allow") project_name: str = "Test Task CRM" version: str = "0.1.0" api_v1_prefix: str = "/api/v1" db_host: str = Field(default="localhost", description="Database hostname") db_port: int = Field(default=5432, description="Database port") db_name: str = Field(default="test_task_crm", description="Database name") db_user: str = Field(default="postgres", description="Database user") db_password: SecretStr = Field( default=SecretStr("postgres"), description="Database user password" ) database_url_override: str | None = Field( default=None, alias="DATABASE_URL", description="Optional full SQLAlchemy URL override", ) sqlalchemy_echo: bool = False jwt_secret_key: SecretStr = Field(default=SecretStr("change-me")) jwt_algorithm: str = "HS256" access_token_expire_minutes: int = 30 refresh_token_expire_days: int = 7 redis_enabled: bool = Field(default=False, description="Toggle Redis-backed cache usage") redis_url: str = Field(default="redis://localhost:6379/0", description="Redis connection URL") analytics_cache_ttl_seconds: int = Field( default=120, ge=1, description="TTL for cached analytics responses" ) analytics_cache_backoff_ms: int = Field( default=200, ge=0, description="Maximum backoff (ms) for retrying cache writes/invalidation", ) @property def database_url(self) -> str: if self.database_url_override: return self.database_url_override password = self.db_password.get_secret_value() return ( f"postgresql+asyncpg://{self.db_user}:{password}@" f"{self.db_host}:{self.db_port}/{self.db_name}" ) settings = Settings()