import logging import os from pathlib import Path from pydantic_settings import BaseSettings, SettingsConfigDict logger = logging.getLogger(__name__) def _resolve_db_url(url: str) -> str: """Convert relative sqlite path to absolute path for Docker or local dev.""" if url.startswith("sqlite+aiosqlite:///./"): # Convert relative path to absolute (works in both local and Docker) rel_path = url.replace("sqlite+aiosqlite:///./", "") # Use working directory as base base_dir = Path.cwd() abs_path = base_dir / rel_path return f"sqlite+aiosqlite:///{abs_path.resolve()}" return url class Settings(BaseSettings): model_config = SettingsConfigDict(env_file=".env", extra="ignore") DATABASE_URL: str = "sqlite+aiosqlite:///./data/claudia_docs.db" JWT_SECRET_KEY: str JWT_ALGORITHM: str = "HS256" JWT_ACCESS_TOKEN_EXPIRE_MINUTES: int = 15 JWT_REFRESH_TOKEN_EXPIRE_DAYS: int = 7 CORS_ORIGINS: str = "http://localhost:5173,http://localhost:80" HOST: str = "0.0.0.0" PORT: int = 8000 LOG_LEVEL: str = "INFO" INITIAL_ADMIN_USERNAME: str # Required: admin user to auto-create INITIAL_ADMIN_PASSWORD: str # Required: password for auto-created admin DISABLE_REGISTRATION: bool = False @property def resolved_database_url(self) -> str: return _resolve_db_url(self.DATABASE_URL) @property def cors_origins_list(self) -> list[str]: return [o.strip() for o in self.CORS_ORIGINS.split(",") if o.strip()] settings = Settings() # Validate required secrets at startup _missing = [] if not settings.JWT_SECRET_KEY or settings.JWT_SECRET_KEY == "change-me-super-secret-key-min32chars!!": _missing.append("JWT_SECRET_KEY") if not settings.INITIAL_ADMIN_USERNAME: _missing.append("INITIAL_ADMIN_USERNAME") if not settings.INITIAL_ADMIN_PASSWORD: _missing.append("INITIAL_ADMIN_PASSWORD") if _missing: raise ValueError(f"Required environment variables not set: {', '.join(_missing)}") # Log initial admin credentials (password masked) logger.info(f"Initial admin username: {settings.INITIAL_ADMIN_USERNAME}") logger.info(f"Initial admin password: {'*' * len(settings.INITIAL_ADMIN_PASSWORD)}")