import logging from typing import Awaitable, Callable from fastapi import FastAPI, Request, Response from fastapi.staticfiles import StaticFiles from config.database import Base, engine from config.settings import get_settings from middleware.auth_session import AuthSessionMiddleware from middleware.validation import validate_json from models import ( FinancialInput, Project, Scenario, SimulationParameter, ) from routes.auth import router as auth_router from routes.dashboard import router as dashboard_router from routes.imports import router as imports_router from routes.exports import router as exports_router from routes.projects import router as projects_router from routes.scenarios import router as scenarios_router from monitoring import router as monitoring_router from services.bootstrap import bootstrap_admin # Initialize database schema (imports above ensure models are registered) Base.metadata.create_all(bind=engine) app = FastAPI() app.add_middleware(AuthSessionMiddleware) logger = logging.getLogger(__name__) @app.middleware("http") async def json_validation( request: Request, call_next: Callable[[Request], Awaitable[Response]] ) -> Response: return await validate_json(request, call_next) @app.get("/health", summary="Container health probe") async def health() -> dict[str, str]: return {"status": "ok"} @app.on_event("startup") async def ensure_admin_bootstrap() -> None: settings = get_settings().admin_bootstrap_settings() try: role_result, admin_result = bootstrap_admin(settings=settings) logger.info( "Admin bootstrap completed: roles=%s created=%s updated=%s rotated=%s assigned=%s", role_result.ensured, admin_result.created_user, admin_result.updated_user, admin_result.password_rotated, admin_result.roles_granted, ) except Exception: # pragma: no cover - defensive logging logger.exception("Failed to bootstrap administrator account") app.include_router(dashboard_router) app.include_router(auth_router) app.include_router(imports_router) app.include_router(exports_router) app.include_router(projects_router) app.include_router(scenarios_router) app.include_router(monitoring_router) app.mount("/static", StaticFiles(directory="static"), name="static")