R7+ orchestrator + CC3 logo home: combined patches

Orchestrator-side:
- routers/img_proxy_router.py: 4xx/5xx → 1x1 transparent PNG (eliminates cascade <img onerror>)
- static/sport2.html: removed standalone three.min.js (3d-force-graph bundles), bumped to 1.73.4

CC3 (before limit hit):
- Logo home link applied to ALL HTML pages (admin.html, admin_users.html, audit.html, crm.html, erp.html, kpi.html, login.html)
- Backups in _backups/*.cc3_pre_logo.$ts

CC4 R3 (before plan mode):
- _backups/r3_cc4/ocr.py.pre_S2.$ts

Audit screenshots (80 pages) committed to _audit/audit_20260505_023639/shots/
This commit is contained in:
2026-05-05 08:20:07 +02:00
parent 662f448590
commit 4fc8327789
106 changed files with 12789 additions and 11 deletions
+65
View File
@@ -231,6 +231,71 @@ def dashboard():
WHERE godina = 2025 ORDER BY iznos DESC LIMIT 10""")
return {**d, "top_savezi": top, "proracun_trend": proracun_trend, "nositelji_2025": nositelji}
@app.get("/api/kpi")
def api_kpi():
"""CC6 analitika — single-payload KPI for /kpi page.
Returns top-level counts (savezi, klubovi, sportasi, members),
proracun current/trend, top10 sufinanciranje, sport distribution,
drill-down hooks, and a heartbeat so the page can refresh.
"""
counts_row = fetch("""SELECT
(SELECT COUNT(*) FROM pgz_sport.savezi) AS savezi,
(SELECT COUNT(*) FROM pgz_sport.klubovi WHERE aktivan) AS klubovi,
(SELECT COUNT(*) FROM pgz_sport.clanovi WHERE aktivan) AS sportasi,
(SELECT COUNT(*) FROM pgz_sport.clanovi WHERE aktivan AND reprezentativac) AS reprezentativci,
(SELECT COUNT(*) FROM pgz_sport.sportski_objekti WHERE aktivan) AS objekti,
(SELECT COUNT(*) FROM pgz_sport.manifestacije) AS manifestacije
""")
counts = counts_row[0] if counts_row else {}
proracun_trend = fetch("SELECT godina, ukupno FROM pgz_sport.proracun ORDER BY godina")
proracun_2026 = next((r['ukupno'] for r in proracun_trend if r.get('godina') == 2026), None)
top_sufin = fetch("""SELECT naziv_kluba, godina, iznos
FROM pgz_sport.potpore_nositelji
WHERE godina = 2025
ORDER BY iznos DESC NULLS LAST
LIMIT 10""")
by_sport = fetch("""SELECT sport, COUNT(*)::int AS broj
FROM pgz_sport.klubovi
WHERE aktivan AND sport IS NOT NULL
GROUP BY sport
ORDER BY COUNT(*) DESC
LIMIT 15""")
by_region = fetch("""SELECT COALESCE(region, 'N/A') AS region, COUNT(*)::int AS broj
FROM pgz_sport.klubovi
WHERE aktivan
GROUP BY region
ORDER BY COUNT(*) DESC""")
# Liječnički expiring (next 30d) — ops widget
lijec_expiring = fetch("""SELECT COUNT(*)::int AS n
FROM pgz_sport.lijecnicki_pregledi
WHERE vrijedi_do BETWEEN CURRENT_DATE
AND CURRENT_DATE + INTERVAL '30 days'""")
lijec_expiring_n = lijec_expiring[0]['n'] if lijec_expiring else 0
return {
"as_of": datetime.now().isoformat(timespec='seconds'),
"counts": counts,
"proracun_2026": proracun_2026,
"proracun_trend": proracun_trend,
"top_sufinanciranje_2025": top_sufin,
"klubovi_by_sport": by_sport,
"klubovi_by_region": by_region,
"lijecnicki_expiring_30d": lijec_expiring_n,
"drill_down": {
"savezi": "/api/v2/savezi",
"klubovi": "/api/klubovi",
"sportasi": "/api/clanovi-full",
"objekti": "/api/sportski-objekti",
},
}
@app.get("/api/dashboard/ekosustav")
def dashboard_ekosustav():
"""Sport ekosustav PGŽ — coverage stats za enrichment iz FINA registra."""