import logging import os from datetime import datetime, timezone from typing import Optional def utcnow() -> datetime: """Return the current UTC time as a timezone-naive datetime. SQLite (and SQLAlchemy's default column handling) stores datetimes without timezone info. Using this helper keeps all DB timestamps and comparisons consistent and avoids TypeError on offset-naive vs offset-aware comparisons. """ return datetime.now(timezone.utc).replace(tzinfo=None) # ── Paths ───────────────────────────────────────────────────────────────────── _HERE = os.path.dirname(os.path.abspath(__file__)) # src/core/ _SRC_DIR = os.path.dirname(_HERE) # src/ _PROJECT_ROOT = os.path.dirname(_SRC_DIR) # project root DATA_DIR: str = os.path.join(_PROJECT_ROOT, "data") # ── Logging ─────────────────────────────────────────────────────────────────── # LOG_LEVEL: one of DEBUG, INFO, WARNING, ERROR, CRITICAL (default: INFO) LOG_LEVEL: int = getattr(logging, os.environ.get("LOG_LEVEL", "INFO").upper(), logging.INFO) # LOG_FILE: set to empty string to disable file logging LOG_FILE: str = os.environ.get("LOG_FILE", "") # ── Security ────────────────────────────────────────────────────────────────── SECRET_KEY: str = os.environ.get("SECRET_KEY") or "" if not SECRET_KEY: raise RuntimeError("SECRET_KEY environment variable must be set") # ── Database ────────────────────────────────────────────────────────────────── DATABASE_URL: str = os.environ.get( "DATABASE_URL", f"sqlite:///{os.path.join(DATA_DIR, 'gates.db')}", ) # ── CORS ────────────────────────────────────────────────────────────────────── # Comma-separated list of allowed origins, e.g. "https://example.com,https://app.example.com" # Default to empty list (no cross-origin requests allowed) when not set. _cors_env = os.environ.get("CORS_ORIGINS", "") CORS_ORIGINS: list[str] = [o.strip() for o in _cors_env.split(",") if o.strip()] # ── Proxy ───────────────────────────────────────────────────────────────────── # Comma-separated list of trusted reverse-proxy IPs for X-Forwarded-For propagation. # e.g. "127.0.0.1,10.0.0.1" _proxy_env = os.environ.get("TRUSTED_PROXY_IPS", "127.0.0.1") TRUSTED_PROXY_IPS: list[str] = [ip.strip() for ip in _proxy_env.split(",") if ip.strip()] # ── Admin seed ──────────────────────────────────────────────────────────────── ADMIN_USERNAME: str = os.environ.get("ADMIN_USERNAME", "admin") ADMIN_PASSWORD: Optional[str] = os.environ.get("ADMIN_PASSWORD") or None # ── Server ──────────────────────────────────────────────────────────────────── APP_PORT: int = int(os.environ.get("APP_PORT", 8000)) # ── Map / home location ─────────────────────────────────────────────────────── # Optional WGS-84 coordinates for the "home" marker shown on the frontend map. HOME_LAT: Optional[float] = float(os.environ["HOME_LAT"]) if os.environ.get("HOME_LAT") else None HOME_LON: Optional[float] = float(os.environ["HOME_LON"]) if os.environ.get("HOME_LON") else None HOME_NAME: str = os.environ.get("HOME_NAME", "Home")