The Campionato page showed hardcoded demo data. It now reads the real 2025/26 season (Campionato Open Misto Eccellenza, project 767, team 3359, Girone B) from the Livescore CSI Bologna portal. The portal has no documented API: we call the same endpoints its own pages call over ajax, so parsing must degrade gracefully. A single server route fetches them, caches for 6 hours and serves the last good payload on failure; the page falls back to the previous data when nothing is available. No browser ever contacts the portal, keeping the request count independent of how many players open the app. Also fixes the header, which claimed "Girone C - CSI Milano". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
4.0 KiB
Modulo — Collegamento CSI
Stato: implementato (stagione 2025/26)
Route interessata: /classifica
Obiettivo
Mostrare nell'app la classifica e i risultati ufficiali del campionato CSI, al posto
dei dati dimostrativi hardcoded in crapp-data.ts. Nessun inserimento manuale da parte
degli amministratori: è esattamente il tipo di lavoro amministrativo che CrAPP deve togliere.
Sorgente dati
Portale Livescore CSI Bologna (https://livescore.csibologna.it).
Il portale non espone un'API pubblica documentata. Vengono usati gli stessi endpoint che il sito chiama internamente via ajax: sono raggiungibili senza autenticazione e senza API key, ma non offrono alcuna garanzia di stabilità.
| Endpoint | Formato | Uso |
|---|---|---|
components/project-sheets.php?project_id=767 |
HTML | Classifica completa dei due gironi |
assets/json/getEventsByTeamId.php?team_id=3359 |
JSON | Tutte le gare della squadra: data, ora, avversario, campo, risultato, parziali |
Altri endpoint disponibili ma non usati: getEventsByProjectIdHierarchical.php (tutte le
gare del campionato), project-chart-rankings.php (solo punti), project-next_matches.php,
project-last_results.php, team-roster.php, team-results.php.
Identificativi (stagione 2025/26)
| Cosa | Valore |
|---|---|
| Campionato | PVM - Campionato Open Misto Eccellenza |
project_id |
767 |
| Squadra sul portale | C.R.A.P. Volley (con i punti) |
team_id |
3359 |
| Girone | B |
Gli identificativi sono costanti in src/lib/csi-core.ts.
Implementazione
CSI (portale)
↓ fetch server-side, cache 6 ore
/api/public/csi → src/routes/api/public/csi.ts
↓ JSON { classifica, partite, girone, aggiornato }
useCsi() → src/lib/csi.ts (React Query, staleTime 6h)
↓
/classifica → src/routes/classifica.tsx
src/lib/csi-core.ts— costanti, tipi e funzioni pure:parseClassifica()(HTML → righe),partiteDaEventi()(JSON → partite),isNostraSquadra(),partiteGiocate().src/routes/api/public/csi.ts— unica route che contatta il CSI. Cache in memoria di 6 ore; in caso di errore restituisce l'ultimo dato buono (503solo se non ne esiste uno).src/lib/csi.ts— hook client, una lettura per sessione.src/lib/csi-core.test.ts— check del parsing:bun src/lib/csi-core.test.ts. ConCSI_LIVE=1verifica anche gli endpoint reali.
Regole rispettate
- Nessuna chiamata dal browser: il portale viene contattato solo lato server, al massimo 4 volte al giorno, indipendentemente da quanti giocatori aprono l'app (regola anti-consumo).
- Nessuna dipendenza nuova: parsing con espressioni regolari sulla struttura della tabella.
- Fallback: se il CSI non risponde,
/classificamostra i dati esistenti come prima. - Portabilità (DD-013): endpoint HTTP standard, nessun servizio esclusivo.
Limiti noti
- La classifica si legge da HTML. Se il portale cambia la struttura della tabella il
parsing restituisce un array vuoto e l'app ricade sui dati demo — non si rompe, ma i dati
sono vecchi. Il check con
CSI_LIVE=1serve a scoprirlo. project_idè legato alla stagione. Per il 2026/27 servirà un nuovo id, ricavabile dateam_details.php?team_id=3359, che elenca i campionati della squadra. Oggi va aggiornato a mano incsi-core.ts.- La cache vive nel processo del server. Si perde a ogni cold start e non è condivisa tra
istanze. Sufficiente per una squadra; se serve di più, spostare i dati in una tabella
Supabase riempita da un job cron (stesso pattern di
promemoria-palloni). - I risultati includono anche la Coppa, non solo il girone di campionato.
Evoluzioni possibili
- Prossima partita ufficiale nella home e nel calendario (i dati sono già disponibili).
- Creazione automatica degli eventi partita da calendario CSI.
- Confronto tra i parziali ufficiali e quelli dello Scout Live.