Files
bxh/app/main.py

60 lines
1.5 KiB
Python

"""City Knowledge Graph Admin — FastAPI entry point."""
from __future__ import annotations
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from starlette.exceptions import HTTPException as StarletteHTTPException
from app.api import api_router
from app.db import init_pool, close_pool
class SPAStaticFiles(StaticFiles):
"""Serve the admin SPA with client-side-routing fallback.
Any unknown path under /admin (e.g. /admin/login-v2, /admin/plaza/graph)
falls back to index.html so React Router can handle it on a hard
navigation or page refresh — instead of returning a 404.
"""
async def get_response(self, path: str, scope):
try:
return await super().get_response(path, scope)
except StarletteHTTPException as exc:
if exc.status_code == 404:
return await super().get_response("index.html", scope)
raise
@asynccontextmanager
async def lifespan(_app: FastAPI):
await init_pool()
yield
await close_pool()
app = FastAPI(
title="ZN-KG Admin",
version="0.1.0",
lifespan=lifespan,
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(api_router)
# Serve built admin-web SPA (when available)
try:
app.mount("/admin", SPAStaticFiles(directory="app/static/admin", html=True), name="admin-web")
except Exception:
pass