"""FastAPI application entry point.""" from __future__ import annotations import os from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.responses import FileResponse, JSONResponse from fastapi.staticfiles import StaticFiles from . import VERSION from .auth import ensure_bootstrap_admin from .config import get_settings from .db import SessionLocal, init_db from .routers import (actions_router, alerts_router, auth_router, cases_router, linkage_router, settings_router) settings = get_settings() @asynccontextmanager async def lifespan(app: FastAPI): init_db() db = SessionLocal() try: message = ensure_bootstrap_admin(db) if message: print(f"[auth] {message}") finally: db.close() print(f"[startup] {settings.app_name} {VERSION}") print(f"[startup] prometheus: {settings.prometheus_base}") print(f"[startup] sso: {'on' if settings.oidc_enabled else 'off'} | " f"zendesk: {'ready' if settings.zendesk_ready else 'off'} | " f"jira: {'ready' if settings.jira_ready else 'off'} | " f"sending: {'ENABLED' if settings.feature_send_enabled else 'disabled'}") alerts_router.engine.warm() yield app = FastAPI(title=settings.app_name, version=VERSION, lifespan=lifespan) for module in (auth_router, alerts_router, cases_router, settings_router, linkage_router, actions_router): app.include_router(module.router) @app.get("/api/health") def health(): return {"status": "ok", "version": VERSION, "config": settings.public_flags()} # The built React bundle is copied into the image; in development Vite serves it # instead and proxies /api here, so a missing directory is not an error. if os.path.isdir(settings.static_dir): app.mount("/assets", StaticFiles(directory=os.path.join(settings.static_dir, "assets")), name="assets") @app.get("/{full_path:path}") def spa(full_path: str): if full_path.startswith("api/"): return JSONResponse({"detail": "Not found"}, status_code=404) index = os.path.join(settings.static_dir, "index.html") if os.path.isfile(index): return FileResponse(index) return JSONResponse({"detail": "Frontend not built"}, status_code=404)