diff --git a/app/main.py b/app/main.py index a6f9fa0..0e32981 100644 --- a/app/main.py +++ b/app/main.py @@ -4,6 +4,7 @@ from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles +from fastapi.responses import FileResponse from app.api.auth_routes import router as auth_router from app.api.routes import router as api_router from app.config import get_settings @@ -30,15 +31,24 @@ # статики нет (локальный запуск api без фронта) — просто пропускаем. spa = settings.spa_dist_dir if (spa / "index.html").exists(): - app.mount("/", StaticFiles(directory=spa, html=True), name="spa") - - @app.get("/") - def root() -> dict: - return { - "service": settings.app_name, - "docs": "/api/docs", - "health": "/api/healthz", - } + # Не mount(StaticFiles, html=True): он отдаёт 404 на произвольных путях, + # а vue-router'у (например /oauth/callback) нужен fallback на index.html. + @app.get("/{spa_path:path}", include_in_schema=False) + def spa_fallback(spa_path: str) -> FileResponse: + candidate = (spa / spa_path).resolve() + # Только файлы внутри каталога SPA (без ../ побегов); роутеры + # /api/* и /auth/* зарегистрированы раньше и матчатся первыми. + if spa_path and candidate.is_file() and candidate.is_relative_to(spa.resolve()): + return FileResponse(candidate) + return FileResponse(spa / "index.html") + else: + @app.get("/") + def root() -> dict: + return { + "service": settings.app_name, + "docs": "/api/docs", + "health": "/api/healthz", + } return app