130 lines
4.4 KiB
Python
130 lines
4.4 KiB
Python
"""WealthWise application configuration management.
|
|
|
|
This module provides centralized configuration management using Pydantic Settings v2.
|
|
Configuration values are loaded from environment variables and .env files.
|
|
"""
|
|
|
|
from functools import lru_cache
|
|
from typing import Any, Optional, Union
|
|
|
|
from pydantic import Field, field_validator
|
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
|
|
|
|
class Settings(BaseSettings):
|
|
"""Application settings management.
|
|
|
|
All configuration values are loaded from environment variables.
|
|
The .env file is automatically loaded when present.
|
|
System environment variables override values in .env.
|
|
|
|
Attributes:
|
|
PROJECT_NAME: Application name for documentation and logging
|
|
API_V1_STR: Base path for API v1 endpoints
|
|
VERSION: Application version string
|
|
DATABASE_URL: PostgreSQL connection string (Supabase Transaction Pooler format)
|
|
SUPABASE_JWT_SECRET: JWT secret for Supabase authentication
|
|
DEBUG: Enable debug mode (default: False)
|
|
CORS_ORIGINS: Comma-separated list of allowed CORS origins
|
|
"""
|
|
|
|
model_config = SettingsConfigDict(
|
|
env_file=".env",
|
|
env_file_encoding="utf-8",
|
|
extra="ignore", # Allow extra env vars without raising errors
|
|
case_sensitive=True,
|
|
)
|
|
|
|
# Application Info
|
|
PROJECT_NAME: str = Field(default="WealthWise", description="Application name")
|
|
API_V1_STR: str = Field(default="/api/v1", description="API v1 base path")
|
|
VERSION: str = Field(default="1.0.0", description="Application version")
|
|
|
|
# Security
|
|
SECRET_KEY: str = Field(
|
|
default="dev-secret-key-change-in-production",
|
|
description="Secret key for JWT signing",
|
|
)
|
|
ALGORITHM: str = Field(
|
|
default="HS256",
|
|
description="JWT signing algorithm",
|
|
)
|
|
ACCESS_TOKEN_EXPIRE_MINUTES: int = Field(
|
|
default=30,
|
|
description="JWT token expiration in minutes",
|
|
)
|
|
|
|
# Database - Local PostgreSQL (Docker)
|
|
DATABASE_URL: str = Field(
|
|
default="postgresql+asyncpg://postgres:postgres@localhost:5432/wealthwise",
|
|
description="PostgreSQL async connection string",
|
|
)
|
|
|
|
# Database Pool Configuration
|
|
DB_POOL_SIZE: int = Field(default=20, ge=1, le=100, description="Connection pool size")
|
|
DB_MAX_OVERFLOW: int = Field(default=10, ge=0, le=50, description="Max overflow connections")
|
|
DB_POOL_PRE_PING: bool = Field(
|
|
default=True,
|
|
description="Verify connections before using from pool",
|
|
)
|
|
DB_ECHO: bool = Field(default=False, description="Echo SQL queries to stdout")
|
|
|
|
# API Configuration
|
|
DEBUG: bool = Field(default=False, description="Debug mode")
|
|
CORS_ORIGINS: str = Field(
|
|
default="http://localhost:5173,http://localhost:3000",
|
|
description="Comma-separated list of allowed CORS origins",
|
|
)
|
|
|
|
# Logging
|
|
LOG_LEVEL: str = Field(default="INFO", pattern="^(DEBUG|INFO|WARNING|ERROR|CRITICAL)$")
|
|
|
|
@property
|
|
def cors_origins_list(self) -> list[str]:
|
|
"""Parse CORS_ORIGINS string into a list.
|
|
|
|
Returns:
|
|
List of origin strings
|
|
"""
|
|
return [origin.strip() for origin in self.CORS_ORIGINS.split(",") if origin.strip()]
|
|
|
|
@field_validator("DATABASE_URL")
|
|
@classmethod
|
|
def validate_database_url(cls, v: Optional[str]) -> Any:
|
|
"""Validate and ensure proper asyncpg driver in DATABASE_URL.
|
|
|
|
Args:
|
|
v: Database URL string
|
|
|
|
Returns:
|
|
Validated database URL with asyncpg driver
|
|
|
|
Raises:
|
|
ValueError: If URL format is invalid
|
|
"""
|
|
if not v:
|
|
raise ValueError("DATABASE_URL cannot be empty")
|
|
|
|
# Ensure asyncpg driver is used
|
|
if v.startswith("postgresql://"):
|
|
v = v.replace("postgresql://", "postgresql+asyncpg://", 1)
|
|
elif not v.startswith("postgresql+asyncpg://"):
|
|
raise ValueError(
|
|
"DATABASE_URL must use postgresql+asyncpg:// driver for async support"
|
|
)
|
|
|
|
return v
|
|
|
|
|
|
@lru_cache()
|
|
def get_settings() -> Settings:
|
|
"""Get cached settings instance.
|
|
|
|
This function uses LRU caching to avoid re-reading configuration
|
|
on every call. Settings are loaded once at application startup.
|
|
|
|
Returns:
|
|
Settings instance with all configuration values
|
|
"""
|
|
return Settings()
|