import logging import os from pathlib import Path import uvicorn from dotenv import load_dotenv from fastapi import FastAPI from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse from starlette.middleware.cors import CORSMiddleware from mta_sign_server.router import router as default_router from mta_sign_server.mta.router import router as mta_router from mta_sign_server.config.router import router as config_router load_dotenv() app = FastAPI() app.add_middleware( CORSMiddleware, allow_origins=['*'] ) app.include_router(default_router) app.include_router(mta_router) app.include_router(config_router) logger = logging.getLogger("main") # Serve static files from the Next.js build output # In production, the 'static' directory contains the built frontend # Set FRONTEND_ENABLE=false to disable serving static files frontend_enabled = os.getenv("FRONTEND_ENABLE", "true").lower() not in ("false", "0", "no") static_dir = Path(__file__).parent / "static" if frontend_enabled and static_dir.exists(): # Serve Next.js static assets (_next directory) next_static = static_dir / "_next" if next_static.exists(): app.mount("/_next", StaticFiles(directory=str(next_static)), name="next-static") # Serve other static files (images, etc.) app.mount("/static", StaticFiles(directory=str(static_dir)), name="static") @app.get("/") async def serve_index(): """Serve the main index.html for the SPA""" return FileResponse(static_dir / "index.html") @app.get("/{path:path}") async def serve_spa(path: str): """Serve static files or fall back to index.html for SPA routing""" file_path = static_dir / path if file_path.exists() and file_path.is_file(): return FileResponse(file_path) # Fall back to index.html for client-side routing return FileResponse(static_dir / "index.html") if __name__ == "__main__": uvicorn.run("main:app", host="0.0.0.0", port=8000, log_level="info", reload=True)