""" Main FastAPI application for Core Code API """ from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse from contextlib import asynccontextmanager from src.shared.config import get_settings from src.shared.logging import setup_logging, get_logger from src.shared.database import get_database from src.shared.security import initialize_oidc # Import domain controllers from src.domains.health import health_controller from src.domains.auth import auth_controller from src.domains.tools import tools_controller from src.domains.infrastructure import infrastructure_controller from src.domains.housekeeping import housekeeping_controller from src.domains.static import static_controller from src.domains.dashboard import dashboard_controller # Initialize settings settings = get_settings() # Setup logging setup_logging(settings.log_level) logger = get_logger(__name__) @asynccontextmanager async def lifespan(app: FastAPI): """ Application lifespan manager for startup/shutdown events Args: app: FastAPI application instance """ # Startup logger.info("=" * 60) logger.info(f"Starting {settings.app_name} v{settings.app_version}") logger.info(f"Debug mode: {settings.debug}") logger.info(f"Log level: {settings.log_level}") logger.info("=" * 60) # Check database connectivity database = get_database() db_healthy = await database.health_check() if db_healthy: logger.info("Database connection successful") else: logger.warning("Database connection failed - auth features may not work") # Initialize security (OIDC authentication) initialize_oidc(settings) yield # Shutdown logger.info("Shutting down application") await database.close() # Create FastAPI application app = FastAPI( title=settings.app_name, version=settings.app_version, description=""" Core Code API - Infrastructure management and home automation API. ## Features - **Infrastructure Management** - Container and stack management via Portainer - **Home Automation** - Device control via Home Assistant - **Dashboard** - Quick links and widget management - **Tools** - DNS lookup and utilities See `/docs` for the full API reference. """, docs_url="/docs", redoc_url=None, openapi_url="/openapi.json", lifespan=lifespan, debug=settings.debug, swagger_ui_init_oauth={ "clientId": settings.oidc_audiences[0] if settings.oidc_audiences else "core-api", "usePkceWithAuthorizationCodeGrant": True, } if settings.oidc_enabled else None ) # Add CORS middleware app.add_middleware( CORSMiddleware, allow_origins=settings.cors_origins, allow_credentials=settings.cors_credentials, allow_methods=settings.cors_methods, allow_headers=settings.cors_headers, ) # Include domain routers app.include_router(health_controller.router) # / and /health app.include_router(auth_controller.router) # /auth/* app.include_router(tools_controller.router) # /tools/* app.include_router(infrastructure_controller.router) # /infrastructure/* app.include_router(housekeeping_controller.router) # /housekeeping/* app.include_router(static_controller.router) # /static/* app.include_router(dashboard_controller.router) # /dashboard/* # Global exception handler @app.exception_handler(Exception) async def global_exception_handler(request, exc): """ Catch-all exception handler for unhandled errors Args: request: The request that caused the exception exc: The exception instance Returns: JSON error response """ logger.error(f"Unhandled exception: {str(exc)}", exc_info=True) return JSONResponse( status_code=500, content={ "detail": "Internal server error", "type": type(exc).__name__ } )