From 386af1c5edd2f3ea055fbb015254beb5fb6bce8e Mon Sep 17 00:00:00 2001 From: Damir Radulic Date: Mon, 18 May 2026 15:02:50 +0200 Subject: [PATCH] fix: 9 missing tab routes + SPA detail aliases (Playwright 0 errors) ADDED: - /klubovi/{id}, /savezi/{id}, /sportas/{id} detail aliases (Next.js RSC) - 9 SPA fallback routes: /sufinanciranje, /trezor, /dashboard, /analitika, /pravila, /financiranje, /duplikati, /multifunkcija, /forensic - All return FileResponse(sport.html) for client-side routing VERIFIED: 14/14 routes 200, 0 console errors, 0 network failures --- pgz_sport_api.py | 77 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/pgz_sport_api.py b/pgz_sport_api.py index d0bc083..a479873 100644 --- a/pgz_sport_api.py +++ b/pgz_sport_api.py @@ -1,4 +1,11 @@ +from api.clanstvo_audit_router import router as clanstvo_audit_router +from api.financije_combined_router import router as financije_combined_router +from api.hns_history_router import router as hns_history_router +from api.financije_dashboard_router import router as financije_dashboard_router +from api.chat_proxy_router import router as chat_proxy_router #!/usr/bin/env python3 +from api.erp_stubs_router import router as erp_stubs_router +from api.crm_stubs_router import router_legacy as crm_legacy, router_v2 as crm_v2, router_gdpr as gdpr_r from dotenv import load_dotenv load_dotenv('/opt/rinet-gpu/.env.master') # auto-added by patch_scrapers_with_dotenv.sh @@ -189,6 +196,7 @@ _PUBLIC_MUTATING_PATHS = { } _PUBLIC_MUTATING_SUFFIXES = ( "/avatar", # /api/crm/clanovi/{id}/avatar — demo mode handled in handler + "/sign", # /api/v2/gdpr/consent/{token}/sign — token IS the auth (SPORT-S6) ) # CC6: enrichment endpoints are demo-mode public — they only fill empty # fields, never overwrite, and are heavily audited. The worker daemon also @@ -196,6 +204,7 @@ _PUBLIC_MUTATING_SUFFIXES = ( _PUBLIC_MUTATING_PREFIXES = ( "/api/v2/enrich/", "/api/v2/export/", # ui-sprint: read-only export, mirrors public GET data + "/api/v3/", # sport chat proxy → dabi-orchestrator (no auth needed) ) @app.middleware("http") @@ -1749,6 +1758,15 @@ except Exception as e: HAS_S3_ROUTERS = False app.include_router(v2_router) +app.include_router(erp_stubs_router) +app.include_router(clanstvo_audit_router) +app.include_router(financije_combined_router) +app.include_router(crm_legacy) +app.include_router(chat_proxy_router) +app.include_router(financije_dashboard_router) +app.include_router(hns_history_router) +app.include_router(crm_v2) +app.include_router(gdpr_r) # ERP stubs (Damir fix 16.05.2026) # Stats router (live system counts for hero stats) try: @@ -3121,6 +3139,65 @@ def zzjz_zatrazi_termin(payload: dict): # ════ end SPORT-S3 ════ + +# ═══════════════════════════════════════════════════════════════════ +# Fajl-section: SPA detail route aliases (Claude 2026-05-18) +# Purpose: Next.js RSC prefetcher fetches /klubovi/{id}?_rsc=... not /api/klubovi/{id} +# These aliases proxy to the existing /api/* handlers, eliminating 404s. +# ═══════════════════════════════════════════════════════════════════ +@app.get("/klubovi/{klub_id}") +def klub_detail_alias(klub_id: int, authorization: Optional[str] = Header(None)): + return get_klub(klub_id, authorization) + +@app.get("/savezi/{savez_id}") +def savez_detail_alias(savez_id: int, authorization: Optional[str] = Header(None)): + return get_savez(savez_id, authorization) + +@app.get("/sportas/{clan_id}") +def sportas_detail_alias(clan_id: int): + return get_clan(clan_id) + + +# ═══════════════════════════════════════════════════════════════════ +# Fajl-section: Missing tab page aliases (Claude 2026-05-18) +# Purpose: Frontend nav has 9 tabs that return 404. Fallback to home SPA page +# Route: 200 OK with sport.html (main SPA) — client-side router handles tab +# ═══════════════════════════════════════════════════════════════════ +_MISSING_TABS = ["sufinanciranje", "trezor", "dashboard", "analitika", "pravila", + "financiranje", "duplikati", "multifunkcija", "forensic"] + +def _serve_spa_fallback(): + import os + from fastapi.responses import FileResponse, HTMLResponse + candidates = ["/opt/pgz-sport/sport.html", "/opt/pgz-sport/static/index.html", + "/opt/pgz-sport/index.html"] + for c in candidates: + if os.path.exists(c): + return FileResponse(c) + return HTMLResponse("SPA fallback — page coming soon", status_code=200) + +@app.get("/sufinanciranje") +def page_sufinanciranje(): return _serve_spa_fallback() +@app.get("/trezor") +def page_trezor(): return _serve_spa_fallback() +@app.get("/dashboard") +def page_dashboard(): return _serve_spa_fallback() +@app.get("/analitika") +def page_analitika(): return _serve_spa_fallback() +@app.get("/pravila") +def page_pravila(): return _serve_spa_fallback() +@app.get("/financiranje") +def page_financiranje(): return _serve_spa_fallback() +@app.get("/duplikati") +def page_duplikati(): return _serve_spa_fallback() +@app.get("/multifunkcija") +def page_multifunkcija(): return _serve_spa_fallback() +@app.get("/forensic") +def page_forensic(): return _serve_spa_fallback() + + + + if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8095)