kirche-einfach/backend/app/settings.py

63 lines
2.5 KiB
Python

from pathlib import Path
from pydantic import computed_field
from pydantic_settings import BaseSettings, SettingsConfigDict
# Repo-root .env (shared with the compose stack). Real environment variables
# always take precedence over .env values.
REPO_ROOT = Path(__file__).resolve().parent.parent.parent
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=REPO_ROOT / ".env", extra="ignore")
version: str = "0.1.0"
debug: bool = False
# App database (SQLite file). Override via DATABASE_URL for other engines.
# Must be a URL (not a bare path): db.py and Alembic hand it to
# create_engine, which rejects bare paths.
database_url: str = f"sqlite:///{REPO_ROOT / 'backend' / 'data' / 'kirche.db'}"
# Canonical flow definitions (source of truth): one Langflow export per file.
flows_dir: str = str(REPO_ROOT / "backend" / "flows")
# Auto-reconcile backend/flows into the DB + LFX while the API is running.
flows_watch_enabled: bool = True
langflow_url: str = "http://localhost:7860"
langflow_api_key: str = ""
lfx_url: str = "http://localhost:6004"
lfx_api_key: str = ""
llm_api_key: str = ""
# Base URL flows use for callbacks into this API. Must be reachable
# FROM the LFX process (compose: http://api:8000).
callback_base_url: str = "http://localhost:8000"
# Shared secret that authenticates flow callbacks (POST /api/approvals).
# The runner injects it into every run envelope; LFX-served flows send
# it back as X-Callback-Token. Empty disables callbacks (503) — set a
# long random value in prod (.env CALLBACK_TOKEN).
callback_token: str = ""
# Edge hardening (see app/middleware.py).
max_body_bytes: int = 2 * 1024 * 1024
run_throttle_per_minute: int = 60
# --- access management (magic-link auth, see app/auth) ---
# Public frontend URL (magic links point at /login?token= there).
frontend_url: str = "http://localhost:3000"
# Comma-separated emails that become admins (role assignment + bootstrap).
admin_emails: str = ""
# Reply-To on outgoing mail; also receives access-request notifications.
contact_to: str = ""
mail_from: str = ""
smtp_host: str = ""
smtp_port: int = 587
smtp_username: str = ""
smtp_password: str = ""
@computed_field # type: ignore[misc]
@property
def admin_email_list(self) -> list[str]:
return [e.strip().lower() for e in self.admin_emails.split(",") if e.strip()]
settings = Settings()