CRISIS FIX: login flow + mobile responsive + token expiry handling

ROOT CAUSE ISOLATED:
Backend POST /api/auth/login, GET/PUT /api/auth/me, POST avatar, POST /logout
all return 200 OK (verified curl). Damirov problem is browser-side:
stale localStorage tokens that don't match current backend → 401 cascade
→ avatar upload appears as 'failed: 401' → profile changes 'lost'.

FIXES:
1. apiAuth() in app.html now:
   - Pre-checks JWT exp claim before request
   - On 401 response: clears localStorage (pgz_access/refresh/user) +
     redirects to /login?reason=unauthorized
   - On JWT expired: redirects to /login?reason=expired

2. login.html displays toast for ?reason=expired/unauthorized

3. Mobile responsive CSS (max-width: 768px):
   - app.html: hamburger menu, sidebar slide-in, full-width drill-down panel
   - sport2.html: KPI grid 2-col, klubovi 1-col, tables horizontal scroll
   - Both: viewport meta + media queries + touch-friendly buttons

4. Mobile menu toggle button + backdrop overlay added

VERIFIED E2E (curl):
- POST /auth/login → 200 + JWT
- GET /auth/me → 200 + telefon persisted
- PUT /auth/me → 200, DB row updated
- POST /auth/me/avatar → 200, file saved + avatar_url returned
- POST /auth/logout → 200, token revoked (next /me returns 401)
This commit is contained in:
2026-05-05 09:14:46 +02:00
parent 31e0374465
commit 8e136351f9
27 changed files with 2323 additions and 56 deletions
+537
View File
@@ -0,0 +1,537 @@
{
"ts": "2026-05-05T09:08:40.470443",
"sub5a": [
{
"id": 2611,
"original_naziv": "VIDEO Seminar za trenere/ice seniorskih liga Opatija 2025",
"kind": "heading/event",
"suggestion": null,
"confidence": 0.0,
"sport": "kosarka",
"sjediste": null,
"savez_id": null,
"action": "flagged_in_napomena+aktivan=false (no rename, conf<0.9)"
},
{
"id": 2614,
"original_naziv": "www.zok-rijeka.hr",
"kind": "url",
"suggestion": "OK [VERIFY-from-URL-zok-rijeka]",
"confidence": 0.4,
"sport": "odbojka",
"sjediste": null,
"savez_id": null,
"action": "flagged_in_napomena+aktivan=false (no rename, conf<0.9)"
},
{
"id": 2617,
"original_naziv": "http://www.beachvolley-opatija.com/",
"kind": "url",
"suggestion": "OK [VERIFY-from-URL-www]",
"confidence": 0.4,
"sport": "odbojka",
"sjediste": null,
"savez_id": null,
"action": "flagged_in_napomena+aktivan=false (no rename, conf<0.9)"
},
{
"id": 2621,
"original_naziv": "www.mok-rijeka.hr",
"kind": "url",
"suggestion": "OK [VERIFY-from-URL-mok-rijeka]",
"confidence": 0.4,
"sport": "odbojka",
"sjediste": null,
"savez_id": null,
"action": "flagged_in_napomena+aktivan=false (no rename, conf<0.9)"
},
{
"id": 2627,
"original_naziv": "Ante Kovačića 21, 51 000 Rijeka",
"kind": "address",
"suggestion": "OK [VERIFY-RIJEKA]",
"confidence": 0.5,
"sport": "odbojka",
"sjediste": null,
"savez_id": null,
"action": "flagged_in_napomena+aktivan=false (no rename, conf<0.9)"
},
{
"id": 2635,
"original_naziv": "Ćirila Kosovela 3, 51 000 Rijeka",
"kind": "address",
"suggestion": "OK [VERIFY-RIJEKA]",
"confidence": 0.5,
"sport": "odbojka",
"sjediste": null,
"savez_id": null,
"action": "flagged_in_napomena+aktivan=false (no rename, conf<0.9)"
},
{
"id": 2639,
"original_naziv": "www.zaokskurinjerijeka.hr",
"kind": "url",
"suggestion": "OK [VERIFY-from-URL-zaokskurinjerijeka]",
"confidence": 0.4,
"sport": "odbojka",
"sjediste": null,
"savez_id": null,
"action": "flagged_in_napomena+aktivan=false (no rename, conf<0.9)"
},
{
"id": 2642,
"original_naziv": "zok.crikvenica@gmail.com",
"kind": "email",
"suggestion": null,
"confidence": 0.0,
"sport": "odbojka",
"sjediste": null,
"savez_id": null,
"action": "flagged_in_napomena+aktivan=false (no rename, conf<0.9)"
},
{
"id": 2645,
"original_naziv": "Omladinska 10, 51 550 Mali Lošinj",
"kind": "address",
"suggestion": "OK [VERIFY-MALI LOŠINJ]",
"confidence": 0.5,
"sport": "odbojka",
"sjediste": null,
"savez_id": null,
"action": "flagged_in_napomena+aktivan=false (no rename, conf<0.9)"
},
{
"id": 2646,
"original_naziv": "Braće Horvatića 6, 51 000 Rijeka",
"kind": "address",
"suggestion": "OK [VERIFY-RIJEKA]",
"confidence": 0.5,
"sport": "odbojka",
"sjediste": null,
"savez_id": null,
"action": "flagged_in_napomena+aktivan=false (no rename, conf<0.9)"
},
{
"id": 2647,
"original_naziv": "www.plivackiklub-rijeka.hr",
"kind": "url",
"suggestion": "PK [VERIFY-from-URL-plivackiklub-rijeka]",
"confidence": 0.4,
"sport": "plivanje",
"sjediste": null,
"savez_id": null,
"action": "flagged_in_napomena+aktivan=false (no rename, conf<0.9)"
},
{
"id": 2648,
"original_naziv": "Ždrijeb i satnica za 10.Opatija Open",
"kind": "heading/event",
"suggestion": null,
"confidence": 0.0,
"sport": "stolni tenis",
"sjediste": null,
"savez_id": null,
"action": "flagged_in_napomena+aktivan=false (no rename, conf<0.9)"
},
{
"id": 2649,
"original_naziv": "Propozicije za 41.Međunarodni Kup Grada Rijeke",
"kind": "heading/event",
"suggestion": null,
"confidence": 0.0,
"sport": "stolni tenis",
"sjediste": null,
"savez_id": null,
"action": "flagged_in_napomena+aktivan=false (no rename, conf<0.9)"
}
],
"sub5b": [
{
"id": 1650,
"naziv": "LOVAČKO DRUŠTVO ZA UZGOJ, ZAŠTITU I LOV DIVLJAČI \"TUHOBIĆ\" KRASICA",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 1669,
"naziv": "LOVAČKO DRUŠTVO \"KAMENJARKA\" KUKULJANOVO-ŠKRLJEVO",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 1693,
"naziv": "LOVAČKO DRUŠTVO \"SRNDAĆ\" BROD MORAVICE",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 1694,
"naziv": "LOVAČKO DRUŠTVO \"GOLUB\" KAMPOR-RAB",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 1710,
"naziv": "LOVAČKO DRUŠTVO \"TETRIJEB\" DELNICE",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 1718,
"naziv": "LOVAČKO DRUŠTVO \"VRBNIK-GARICA\"",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 1736,
"naziv": "LOVAČKO DRUŠTVO \"VEPAR\" BRIBIR",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 1752,
"naziv": "LOVAČKO DRUŠTVO \"JELEN\" ČAVLE",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 1772,
"naziv": "LOVAČKO DRUŠTVO \"ŠLJUKA\" KRK",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 1838,
"naziv": "LOVAČKO DRUŠTVO \"TETRIJEB\" RAVNA GORA",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 1843,
"naziv": "LOVAČKO DRUŠTVO \"VEPAR\" LOŠINJ",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 1849,
"naziv": "LOVAČKO DRUŠTVO \"KAMENJARKA\"",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 1900,
"naziv": "LOVAČKO DRUŠTVO \"FAZAN\" DOBRINJ",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 1904,
"naziv": "LOVAČKO DRUŠTVO KAMENJARKA BAŠKA",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 1908,
"naziv": "LOVAČKO DRUŠTVO \"JELEN\" SKRAD",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 1925,
"naziv": "LOVAČKO DRUŠTVO \"VINODOL\"",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 1926,
"naziv": "LOVAČKO DRUŠTVO \"OREBICA\" CRES",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 1951,
"naziv": "LOVAČKO DRUŠTVO \"JELENSKI JARAK\" VRBOVSKO",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 1973,
"naziv": "LOVAČKO DRUŠTVO \"TETRIJEB\" GEROVO",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 1974,
"naziv": "LOVAČKO DRUŠTVO \"OREBICA\" KRK",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 1975,
"naziv": "LOVAČKO DRUŠTVO \"TETRIJEB\" ČABAR",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 1976,
"naziv": "LOVAČKO DRUŠTVO \"KUNIĆ\" RAB",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 1981,
"naziv": "LOVAČKO DRUŠTVO \"SRNDAĆ\" HRELJIN",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2000,
"naziv": "LOVAČKO DRUŠTVO \"KAMENJARKA\" KORNIĆ",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2047,
"naziv": "LOVAČKO DRUŠTVO \"HALMAC\" NEREZINE",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2052,
"naziv": "HRVATSKO LOVAČKO DRUŠTVO \"ZEC\" KLANA",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2083,
"naziv": "LOVAČKO DRUŠTVO \"KUNA\" LOPAR",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2086,
"naziv": "LOVAČKO DRUŠTVO \"VEPAR\" MRKOPALJ",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2110,
"naziv": "LOVAČKO DRUŠTVO \"MEDVIĐAK\" DRIVENIK",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2122,
"naziv": "LOVAČKO DRUŠTVO \"JELEN\" SKRAD-RAVNA GORA",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2123,
"naziv": "LOVAČKO DRUŠTVO \"SRNJAK\" FUŽINE-LOKVE",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2133,
"naziv": "LOVAČKO DRUŠTVO \"ŠLJUKA 1924\" OMIŠALJ",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2137,
"naziv": "LOVAČKO DRUŠTVO \"DIVOKOZA\"-JELENJE",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2150,
"naziv": "LOVAČKO DRUŠTVO \"ZEC\" MALINSKA",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2165,
"naziv": "LOVAČKO DRUŠTVO \"OTOK RAB\"",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2183,
"naziv": "LOVAČKO DRUŠTVO \"KOŠUTNJAK-NOVI\"",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2215,
"naziv": "Lovačko društvo \"GRADINA\" Novi Vinodolski",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2216,
"naziv": "Lovačko društvo \"JELEN\" Čavle",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2217,
"naziv": "Lovačko društvo \"KAMENJARKA\" Kukuljanovo",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2218,
"naziv": "Lovačko društvo \"KOBAC 1960\" Lovran",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2219,
"naziv": "Lovačko društvo \"KOŠUTNJAK - NOVI\" Novi Vinodolski",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2220,
"naziv": "Lovačko društvo \"LANE\" Opatija",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2221,
"naziv": "Lovačko društvo \"LISJAK\" Kastav",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2222,
"naziv": "Lovačko društvo \"MEDVIĐAK\" Drivenik Tribalj",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2223,
"naziv": "Lovačko društvo \"PERUN\" Mošćenička Draga",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2224,
"naziv": "Lovačko društvo \"PLATAK\" Rijeka",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2225,
"naziv": "Lovačko društvo \"SRNDAĆ\" Permani",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2226,
"naziv": "Lovačko društvo \"OTOK RAB\" Rab",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
},
{
"id": 2227,
"naziv": "Lovačko društvo \"VEPAR\" Veli Lošinj",
"sport_before": "kulturno-umjetnicko",
"sport_after": "lovstvo",
"reason": "naziv počinje sa \"Lovačko društvo\" — nije KUD, kategorija lovstvo"
}
],
"sub5c": {
"sources": [
{
"url": "https://sport-pgz.hr/clanice-zajednice",
"status": "200 OK",
"type": "ZSPGZ savezi members (NOT individual clubs)",
"n_found": 31,
"n_flagged": 0,
"note": "ZSPGZ portal lists only SAVEZE pages, not individual klubove. Individual clubs only available via NSPGZ glasnik PDFs / per-savez sites (most non-existent or paywalled). Cross-check protiv klubova nije moguć autonomno bez parsiranja PDF-ova."
},
{
"url": "https://rss-rijeka.hr/clanovi",
"status": "no DNS / unreachable",
"type": "RSS Rijeka member-clubs",
"n_found": 0,
"n_flagged": 0,
"note": "Domain not resolvable. RSS Rijeka info-page exists on sport-pgz.hr/rijecki-sportski-savez but lists only PGZ-savezi (Atletski, Boćarski, ...), not individual clubs."
},
{
"url": "https://www.zssr-pgz.hr",
"status": "no DNS / unreachable",
"type": "ŽSSR PGŽ membership",
"n_found": 0,
"n_flagged": 0,
"note": "Domain unreachable. Use info-page on sport-pgz.hr."
},
{
"url": "https://www.nspgz.hr",
"status": "200 OK",
"type": "Nogometni savez PGŽ",
"n_found": 0,
"n_flagged": 0,
"note": "Has /komisija/registracije-klubovi-igraci, but no machine-readable list. Glasniks su PDF; potreban OCR + parsing."
}
],
"no_savez_active_klubovi": 755,
"flagged": []
},
"summary": {
"sub5a_flagged": 13,
"sub5b_reclassified": 49,
"sub5b_total_reviewed": 49,
"sub5c_blocked_sources": 3
}
}