from contextlib import asynccontextmanager from pathlib import Path from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import RedirectResponse from fastapi.staticfiles import StaticFiles from app.api.router import api_router from app.core.config import settings from app.core.database import init_db from app.deps import NotAuthenticated from app.web.admin import router as admin_router from app.web.pages import router as pages_router STATIC_DIR = Path(__file__).resolve().parent / "static" @asynccontextmanager async def lifespan(app: FastAPI): # Dev/SQLite convenience. Use Alembic migrations in production. if settings.auto_create_tables: await init_db() yield def create_app() -> FastAPI: app = FastAPI(title=settings.app_name, debug=settings.debug, lifespan=lifespan) app.add_middleware( CORSMiddleware, allow_origins=settings.cors_origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static") app.include_router(api_router, prefix="/api") app.include_router(pages_router) app.include_router(admin_router) @app.exception_handler(NotAuthenticated) async def _redirect_to_login(request: Request, exc: NotAuthenticated): return RedirectResponse(url="/login", status_code=302) @app.get("/healthz", tags=["health"]) async def healthz(): return {"status": "ok"} return app app = create_app()