from fastapi import FastAPI from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse from contextlib import asynccontextmanager import os from .config import get_settings from .database import init_db from .routes import router settings = get_settings() @asynccontextmanager async def lifespan(app: FastAPI): # Startup: initialize database init_db() yield # Shutdown: cleanup if needed app = FastAPI( title="Orchard", description="Content-Addressable Storage System", version="1.0.0", lifespan=lifespan, ) # Include API routes app.include_router(router) # Serve static files (React build) if the directory exists static_dir = os.path.join(os.path.dirname(__file__), "..", "..", "frontend", "dist") if os.path.exists(static_dir): app.mount("/assets", StaticFiles(directory=os.path.join(static_dir, "assets")), name="assets") @app.get("/") async def serve_spa(): return FileResponse(os.path.join(static_dir, "index.html")) # Catch-all for SPA routing (must be last) @app.get("/{full_path:path}") async def serve_spa_routes(full_path: str): # Don't catch API routes if full_path.startswith("api/") or full_path.startswith("health") or full_path.startswith("project/"): from fastapi import HTTPException raise HTTPException(status_code=404, detail="Not found") index_path = os.path.join(static_dir, "index.html") if os.path.exists(index_path): return FileResponse(index_path) from fastapi import HTTPException raise HTTPException(status_code=404, detail="Not found")