import logging from contextlib import asynccontextmanager from fastapi import FastAPI, Request from fastapi.responses import JSONResponse from app.db import check_db, run_migrations from app.routers import filaments, pricing, print_jobs, printers, todos from app.routers import ui logging.basicConfig( level=logging.INFO, format="%(asctime)s %(levelname)-8s %(name)s: %(message)s", ) logger = logging.getLogger("pops") @asynccontextmanager async def lifespan(app: FastAPI): ok, msg = check_db() if ok: logger.info("Database connection OK") try: run_migrations() except Exception: logger.exception("Migration failed — schema may be out of date") else: logger.warning("Database unreachable: %s", msg) yield app = FastAPI(title="POPS", lifespan=lifespan) @app.exception_handler(Exception) async def unhandled_exception(request: Request, exc: Exception): logger.exception("Unhandled error on %s %s", request.method, request.url) return JSONResponse(status_code=500, content={"detail": str(exc)}) # JSON API app.include_router(printers.router, prefix="/api") app.include_router(filaments.router, prefix="/api") app.include_router(print_jobs.router, prefix="/api") app.include_router(todos.router, prefix="/api") app.include_router(pricing.router, prefix="/api") # Web UI app.include_router(ui.router) @app.get("/health") def health(): ok, msg = check_db() return { "status": "ok" if ok else "degraded", "db": "connected" if ok else "unreachable", "detail": msg, }