adeshboudh16
bug fix for dynamic routing logic
c2de869
import asyncio
import logging
import sys
from dotenv import load_dotenv
load_dotenv()
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(name)s] %(levelname)s: %(message)s")
log = logging.getLogger("app")
# psycopg (used by LangGraph checkpointer) requires SelectorEventLoop on Windows
if sys.platform == "win32":
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
from contextlib import asynccontextmanager
from fastapi import FastAPI
from backend.checkpointer import init_checkpointer
from backend.db.connection import init_db_pool
from backend.graph.graph import build_graph
from backend.routers import auth, batches, instructor, interview, sessions, student, topics, upload
@asynccontextmanager
async def lifespan(app: FastAPI):
log.info("Starting up β€” connecting to DB...")
await init_db_pool()
log.info("DB pool ready")
checkpointer = await init_checkpointer()
log.info("LangGraph checkpointer ready")
app.state.graph = build_graph(checkpointer)
log.info("Interview graph compiled")
yield
log.info("Shutting down")
app = FastAPI(lifespan=lifespan)
app.include_router(auth.router, prefix="/api/auth")
app.include_router(batches.router, prefix="/api/batches")
app.include_router(topics.router, prefix="/api/topics")
app.include_router(upload.router, prefix="/api/upload")
app.include_router(student.router, prefix="/api/student")
app.include_router(sessions.router, prefix="/api/sessions")
app.include_router(instructor.router, prefix="/api/instructor")
app.include_router(interview.router, prefix="/interview")
# React static build β€” MUST be last (serves the SPA for all non-API routes)
from pathlib import Path
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
_dist = Path(__file__).resolve().parent.parent / "frontend" / "dist"
if _dist.is_dir():
# Catch-all for React Router β€” serve index.html for any path that isn't a real file
@app.get("/{full_path:path}", include_in_schema=False)
async def spa_fallback(full_path: str):
file = _dist / full_path
if file.is_file():
return FileResponse(str(file))
return FileResponse(str(_dist / "index.html"))
app.mount("/", StaticFiles(directory=str(_dist)), name="static")
log.info("Static files mounted from %s", _dist)
else:
log.warning("frontend/dist not found at %s β€” SPA will not be served", _dist)