from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse from app.models import init_db from app.routers import auth, etl, match, dashboard, report, lab from app.config import STATIC_DIR, DEBUG, CORS_ORIGINS, APP_HOST, APP_PORT # 初始化資料庫 init_db() app = FastAPI( title="SalesPipeline API", description="銷售管線管理系統 API", version="1.0.0", docs_url="/api/docs" if DEBUG else None, redoc_url="/api/redoc" if DEBUG else None, ) # CORS 設定 (開發模式需要) if DEBUG and CORS_ORIGINS: app.add_middleware( CORSMiddleware, allow_origins=CORS_ORIGINS, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # 註冊 API 路由 app.include_router(auth.router, prefix="/api") app.include_router(etl.router, prefix="/api") app.include_router(match.router, prefix="/api") app.include_router(dashboard.router, prefix="/api") app.include_router(report.router, prefix="/api") app.include_router(lab.router, prefix="/api") @app.get("/api/health") def health_check(): return {"status": "healthy", "version": "1.0.0"} # 靜態檔案服務 (前端 build 後的檔案) static_path = STATIC_DIR if static_path.exists(): assets_dir = static_path / "assets" if assets_dir.exists(): app.mount("/assets", StaticFiles(directory=assets_dir), name="assets") # SPA 路由處理 - 所有非 API 路由都返回 index.html @app.get("/{full_path:path}") async def serve_spa(request: Request, full_path: str): if full_path.startswith("api/"): return {"error": "Not Found"}, 404 static_file = static_path / full_path if static_file.exists() and static_file.is_file(): return FileResponse(static_file) index_file = static_path / "index.html" if index_file.exists(): return FileResponse(index_file) return { "message": "SalesPipeline API is running", "docs": "/api/docs" if DEBUG else "Disabled in production", "health": "/api/health" } if __name__ == "__main__": import uvicorn uvicorn.run(app, host=APP_HOST, port=APP_PORT)