Hwandji commited on
Commit
582752d
·
1 Parent(s): 6a6737e

fix(backend): Correct SPA static files mounting order

Browse files

- Move SPAStaticFiles mount to end of main.py (after all API routes)
- Fix 404 errors for API endpoints
- Static catchall now properly preserves /api routes

Files changed (2) hide show
  1. backend/main.py +17 -17
  2. backend/spa_static_files.py +3 -6
backend/main.py CHANGED
@@ -223,23 +223,6 @@ def get_websocket_manager() -> WebSocketManager:
223
  """Get WebSocket manager instance"""
224
  return saap_app.websocket_manager
225
 
226
- # =====================================================
227
- # STATIC FILES - Serve Vue.js Frontend (SPA Mode)
228
- # =====================================================
229
-
230
- # Import custom SPA Static Files handler
231
- from spa_static_files import SPAStaticFiles
232
-
233
- # Mount static files for frontend (must be AFTER all API routes)
234
- # SPAStaticFiles preserves API routes while serving Vue.js SPA
235
- import os
236
- frontend_dist = "/app/frontend/dist"
237
- if os.path.exists(frontend_dist):
238
- app.mount("/", SPAStaticFiles(directory=frontend_dist, html=True), name="static")
239
- logger.info(f"✅ SPA Static files mounted: {frontend_dist}")
240
- else:
241
- logger.warning(f"⚠️ Frontend dist directory not found: {frontend_dist}")
242
-
243
  # =====================================================
244
  # ENHANCED ROOT ENDPOINT WITH HYBRID INFO (API)
245
  # =====================================================
@@ -1639,3 +1622,20 @@ async def startup_message():
1639
  # NOTE: No if __name__ == "__main__" block needed
1640
  # Supervisor/Uvicorn will start the app directly
1641
  # ==========================================
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
  """Get WebSocket manager instance"""
224
  return saap_app.websocket_manager
225
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
  # =====================================================
227
  # ENHANCED ROOT ENDPOINT WITH HYBRID INFO (API)
228
  # =====================================================
 
1622
  # NOTE: No if __name__ == "__main__" block needed
1623
  # Supervisor/Uvicorn will start the app directly
1624
  # ==========================================
1625
+
1626
+ # =====================================================
1627
+ # STATIC FILES - Serve Vue.js Frontend (SPA Mode)
1628
+ # ⚠️ CRITICAL: Must be AFTER all API routes!
1629
+ # =====================================================
1630
+
1631
+ # Import custom SPA Static Files handler
1632
+ from spa_static_files import SPAStaticFiles
1633
+
1634
+ # Mount static files for frontend (must be AFTER all API routes)
1635
+ # SPAStaticFiles preserves API routes while serving Vue.js SPA
1636
+ frontend_dist = "/app/frontend/dist"
1637
+ if os.path.exists(frontend_dist):
1638
+ app.mount("/", SPAStaticFiles(directory=frontend_dist, html=True), name="static")
1639
+ logger.info(f"✅ SPA Static files mounted: {frontend_dist}")
1640
+ else:
1641
+ logger.warning(f"⚠️ Frontend dist directory not found: {frontend_dist}")
backend/spa_static_files.py CHANGED
@@ -17,15 +17,12 @@ class SPAStaticFiles(StaticFiles):
17
  async def get_response(self, path: str, scope: Scope):
18
  """
19
  Handle requests:
20
- - API routes (/api/*) → 404 (let FastAPI handle)
21
  - Static files (exist) → serve file
22
  - Everything else → index.html (SPA routing)
23
- """
24
- # Let API routes pass through to FastAPI
25
- if path.startswith("api/") or path.startswith("docs") or path.startswith("redoc") or path.startswith("openapi.json"):
26
- # Return 404 to let FastAPI handle it
27
- raise RuntimeError("Not found")
28
 
 
 
 
29
  try:
30
  # Try to serve the file
31
  return await super().get_response(path, scope)
 
17
  async def get_response(self, path: str, scope: Scope):
18
  """
19
  Handle requests:
 
20
  - Static files (exist) → serve file
21
  - Everything else → index.html (SPA routing)
 
 
 
 
 
22
 
23
+ NOTE: This should be mounted AFTER API routes in main.py
24
+ so API routes are handled first
25
+ """
26
  try:
27
  # Try to serve the file
28
  return await super().get_response(path, scope)