"""FastAPI application factory. Run with uvicorn's factory mode (no import-time DB side effects): uvicorn ams.api.app:create_app --factory --reload """ from __future__ import annotations from pathlib import Path from fastapi import FastAPI from fastapi.responses import RedirectResponse from fastapi.staticfiles import StaticFiles from .. import __version__ from .db import configure, init_db from .routes import diff, games, snapshots _STATIC = Path(__file__).parent / "static" def create_app(database_url: str | None = None) -> FastAPI: configure(database_url) init_db() app = FastAPI(title="ams — engine surface catalog", version=__version__) app.include_router(games.router) app.include_router(snapshots.router) app.include_router(diff.router) @app.get("/health", tags=["meta"]) def health() -> dict[str, str]: return {"status": "ok", "version": __version__} @app.get("/", include_in_schema=False) def root() -> RedirectResponse: return RedirectResponse("/ui/") # The command-center UI (static HTML/CSS/JS, no build step) is served last so API # routes take precedence. app.mount("/ui", StaticFiles(directory=str(_STATIC), html=True), name="ui") return app