"""FastAPI application entry point.""" from contextlib import asynccontextmanager from typing import AsyncGenerator from fastapi import FastAPI from fastapi.openapi.utils import get_openapi from app.api.v1 import auth, health, incidents, org from app.config import settings from app.db import db, redis_client @asynccontextmanager async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: """Manage application lifecycle - connect/disconnect resources.""" # Startup await db.connect(settings.database_url) await redis_client.connect(settings.redis_url) yield # Shutdown await redis_client.disconnect() await db.disconnect() app = FastAPI( title="IncidentOps", description="Incident management API with multi-tenant org support", version="0.1.0", docs_url="/docs", redoc_url="/redoc", openapi_url="/openapi.json", lifespan=lifespan, ) app.openapi_tags = [ {"name": "auth", "description": "Registration, login, token lifecycle"}, {"name": "org", "description": "Organization membership, services, and notifications"}, {"name": "incidents", "description": "Incident lifecycle and timelines"}, {"name": "health", "description": "Service health probes"}, ] def custom_openapi() -> dict: """Add JWT bearer security scheme to the generated OpenAPI schema.""" if app.openapi_schema: return app.openapi_schema openapi_schema = get_openapi( title=app.title, version=app.version, description=app.description, routes=app.routes, ) security_schemes = openapi_schema.setdefault("components", {}).setdefault("securitySchemes", {}) security_schemes["BearerToken"] = { "type": "http", "scheme": "bearer", "bearerFormat": "JWT", "description": "Paste the JWT access token returned by /auth endpoints", } openapi_schema["security"] = [{"BearerToken": []}] app.openapi_schema = openapi_schema return app.openapi_schema app.openapi = custom_openapi # type: ignore[assignment] # Include routers app.include_router(auth.router, prefix=settings.api_v1_prefix) app.include_router(incidents.router, prefix=settings.api_v1_prefix) app.include_router(org.router, prefix=settings.api_v1_prefix) app.include_router(health.router, prefix=settings.api_v1_prefix, tags=["health"])