from pydantic_settings import BaseSettings from functools import lru_cache import os import yaml class Settings(BaseSettings): APP_NAME: str = "TianpuEMS" DEBUG: bool = True API_V1_PREFIX: str = "/api/v1" # Customer configuration CUSTOMER: str = "tianpu" # tianpu, zpark, etc. CUSTOMER_DISPLAY_NAME: str = "" # Loaded from customer config # Database: set DATABASE_URL in .env to override. # Default: SQLite for local dev. Docker sets PostgreSQL via env var. # Examples: # SQLite: sqlite+aiosqlite:///./tianpu_ems.db # PostgreSQL: postgresql+asyncpg://tianpu:tianpu2026@localhost:5432/tianpu_ems DATABASE_URL: str = "sqlite+aiosqlite:///./tianpu_ems.db" REDIS_URL: str = "redis://localhost:6379/0" SECRET_KEY: str = "tianpu-ems-secret-key-change-in-production-2026" ALGORITHM: str = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES: int = 480 CELERY_ENABLED: bool = False # Set True when Celery worker is running USE_SIMULATOR: bool = True # True=simulator mode, False=real IoT collectors # Infrastructure flags TIMESCALE_ENABLED: bool = False REDIS_ENABLED: bool = True INGESTION_QUEUE_ENABLED: bool = False AGGREGATION_ENABLED: bool = True # SMTP Email settings SMTP_HOST: str = "" SMTP_PORT: int = 587 SMTP_USER: str = "" SMTP_PASSWORD: str = "" SMTP_FROM: str = "noreply@tianpu-ems.com" SMTP_ENABLED: bool = False # Platform URL for links in emails PLATFORM_URL: str = "http://localhost:3000" @property def DATABASE_URL_SYNC(self) -> str: """Derive synchronous URL from async DATABASE_URL for Alembic.""" url = self.DATABASE_URL return url.replace("+aiosqlite", "").replace("+asyncpg", "+psycopg2") @property def is_sqlite(self) -> bool: return "sqlite" in self.DATABASE_URL @property def customer_config_path(self) -> str: return os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "..", "customers", self.CUSTOMER) def load_customer_config(self) -> dict: """Load customer-specific config from customers/{CUSTOMER}/config.yaml""" config_file = os.path.join(self.customer_config_path, "config.yaml") if os.path.exists(config_file): with open(config_file, 'r', encoding='utf-8') as f: return yaml.safe_load(f) or {} return {} class Config: env_file = ".env" extra = "ignore" @lru_cache def get_settings() -> Settings: return Settings()