import logging from contextlib import asynccontextmanager from pathlib import Path from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from app.routers import backups, restore, services, status, system logging.basicConfig( level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s: %(message)s", ) logger = logging.getLogger(__name__) _STATIC_DIR = Path(__file__).parent.parent / "static" @asynccontextmanager async def lifespan(app: FastAPI): logger.info("Ops WebUI server is running") yield app = FastAPI( title="Ops WebUI API", description="Backend API for the ops web dashboard", version="1.0.0", lifespan=lifespan, ) # --------------------------------------------------------------------------- # CORS – open for development; restrict in production via env/reverse proxy # --------------------------------------------------------------------------- app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # --------------------------------------------------------------------------- # API routers # --------------------------------------------------------------------------- app.include_router(status.router, prefix="/api/status", tags=["status"]) app.include_router(backups.router, prefix="/api/backups", tags=["backups"]) app.include_router(restore.router, prefix="/api/restore", tags=["restore"]) app.include_router(services.router, prefix="/api/services", tags=["services"]) app.include_router(system.router, prefix="/api/system", tags=["system"]) # --------------------------------------------------------------------------- # Static files – serve the frontend SPA at / # Mount last so API routes take precedence # --------------------------------------------------------------------------- if _STATIC_DIR.exists(): app.mount("/", StaticFiles(directory=str(_STATIC_DIR), html=True), name="static") else: logger.warning("Static directory not found at %s – frontend will not be served", _STATIC_DIR)