"""Environment-driven configuration for the scopa application. Mirrors kaya's own pattern: read ``os.environ`` directly into a plain dataclass. No pydantic-settings, no settings module. """ from __future__ import annotations import os from dataclasses import dataclass from typing import Optional def _env(name: str, default: Optional[str] = None) -> str: value = os.environ.get(name) if value is None or value == "": if default is None: raise RuntimeError(f"Missing required environment variable: {name}") return default return value @dataclass(frozen=True) class Settings: database_url: str oidc_issuer: str oidc_client_id: str oidc_client_secret: Optional[str] oidc_redirect_uri: str # Where the browser is sent after login/logout. In production the SPA is # served by this app ("/"); in development point these at the trunk dev # server (e.g. "http://localhost:8000/"). oidc_post_login_redirect: str oidc_post_logout_redirect: str app_host: str app_port: int redis_url: Optional[str] # How long a live game (and its join-code index) survives in Redis # without activity, in seconds. Defaults to 24h. game_ttl_seconds: int # Directory holding the compiled frontend (trunk's dist output), # served for every path that is not under /api or /auth. static_dir: str @staticmethod def from_env() -> "Settings": return Settings( database_url=_env("DATABASE_URL", "postgres://scopa:scopa@localhost:5432/scopa"), oidc_issuer=_env("OIDC_ISSUER", "http://localhost:8180/scopa"), oidc_client_id=_env("OIDC_CLIENT_ID", "scopa"), oidc_client_secret=os.environ.get("OIDC_CLIENT_SECRET"), oidc_redirect_uri=_env("OIDC_REDIRECT_URI", "http://localhost:8080/auth/callback"), oidc_post_login_redirect=_env("OIDC_POST_LOGIN_REDIRECT", "/"), oidc_post_logout_redirect=_env("OIDC_POST_LOGOUT_REDIRECT", "/"), app_host=_env("APP_HOST", "0.0.0.0"), app_port=int(_env("APP_PORT", "8080")), # When unset, sessions and live games fall back to in-memory # stores (tests, ephemeral dev). Set to e.g. # redis://localhost:6379/0 to persist both in Redis. redis_url=os.environ.get("REDIS_URL"), game_ttl_seconds=int(_env("GAME_TTL_SECONDS", "86400")), static_dir=_env("STATIC_DIR", "web/dist"), ) settings: Settings = Settings.from_env()