From 604d29b5f0621465dac8b64f6947c910ab686698 Mon Sep 17 00:00:00 2001 From: huangzhuang_3rd Date: Wed, 12 Aug 2026 17:05:16 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=89=8D=E7=AB=AF=E6=9E=84=E5=BB=BA?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D+=E5=90=8E=E7=AB=AF=E9=9D=99=E6=80=81?= =?UTF-8?q?=E6=89=98=E7=AE=A1+Docker=E9=83=A8=E7=BD=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/main.py | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/backend/app/main.py b/backend/app/main.py index 5c15d69..a72ea99 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -1,20 +1,24 @@ """AI Worker Platform - FastAPI Application Entry Point.""" import os from contextlib import asynccontextmanager +from pathlib import Path from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware -from fastapi.responses import JSONResponse +from fastapi.responses import JSONResponse, FileResponse +from fastapi.staticfiles import StaticFiles from app.config import settings from app.database import init_db from app.api.v1 import api_router from app.core.exceptions import AppException +# Frontend dist path (relative to backend dir) +FRONTEND_DIST = Path(__file__).resolve().parent.parent.parent / "frontend" / "dist" + @asynccontextmanager async def lifespan(app: FastAPI): """Initialize database on startup.""" init_db() - # Seed default tenant if not exists from app.database import SessionLocal from app.models.tenant import Tenant db = SessionLocal() @@ -41,7 +45,7 @@ app = FastAPI( # CORS app.add_middleware( CORSMiddleware, - allow_origins=settings.cors_origins_list, + allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], @@ -65,3 +69,36 @@ def health(): # API routes app.include_router(api_router) + + +# --- Serve frontend (SPA) --- +if FRONTEND_DIST.exists(): + # Mount static assets (js, css, images) + app.mount("/assets", StaticFiles(directory=FRONTEND_DIST / "assets"), name="assets") + + @app.get("/{full_path:path}") + async def serve_spa(full_path: str, request: Request): + """Catch-all: serve index.html for SPA routing, or static files.""" + # Don't intercept API routes + if full_path.startswith("api/") or full_path.startswith("health"): + return JSONResponse({"detail": "Not Found"}, status_code=404) + + # Try to serve a real file first + file_path = FRONTEND_DIST / full_path + if file_path.is_file(): + return FileResponse(file_path) + + # Fallback to index.html for SPA client-side routing + index = FRONTEND_DIST / "index.html" + if index.exists(): + return FileResponse(index) + return JSONResponse({"detail": "Frontend not built"}, status_code=404) +else: + @app.get("/") + def root(): + return { + "message": "AI Worker Platform API", + "version": settings.APP_VERSION, + "docs": "/docs", + "frontend": "Run 'npm run build' in frontend/ to enable web UI", + }