Files
CRAPP/docs/modules/collegamento-csi.md
T
davideandClaude Opus 5 fee3d0b55a Read the official standings and results from the CSI portal.
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>
2026-08-30 12:23:12 +02:00

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 (503 solo 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. Con CSI_LIVE=1 verifica 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, /classifica mostra i dati esistenti come prima.
  • Portabilità (DD-013): endpoint HTTP standard, nessun servizio esclusivo.

Limiti noti

  1. 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=1 serve a scoprirlo.
  2. project_id è legato alla stagione. Per il 2026/27 servirà un nuovo id, ricavabile da team_details.php?team_id=3359, che elenca i campionati della squadra. Oggi va aggiornato a mano in csi-core.ts.
  3. 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).
  4. 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.