Files
CRAPP/docs/modules/collegamento-csi.md
T
davideandClaude Opus 5 822180bffc Riscrive AGENTS.md e riallinea la documentazione allo stato reale.
I riferimenti ai documenti in AGENTS.md erano rotti: una venticinquina di link
nella forma docs/[README.md](http://README.md), che spezzavano il nome del file
a meta e puntavano a domini inesistenti. Ora sono percorsi relativi verificati,
con CHANGELOG.md e DESIGN_DECISIONS.md sotto docs/ e PROJECT_STATE.md in root.

Tolte da AGENTS.md le sezioni Architettura, Documentazione e Struttura della
documentazione: duplicavano ARCHITECTURE.md e docs/README.md con uno stack ormai
parziale, contro la regola "ogni informazione ha una sola casa" che docs/README.md
stesso impone. Aggiunti invece i comandi, bun e la guardia minimumReleaseAge:
Codex e Cursor leggono solo AGENTS.md e non avevano modo di sapere come si
verifica una modifica. Scritta la checklist "Fine lavoro" che CLAUDE.md citava
senza che esistesse.

Nuova regola: chi aggiunge o modifica una funzione scrive o aggiorna il test nello
stesso lavoro, i test devono essere verdi e la doc del modulo va aggiornata se il
comportamento cambia (DD-020). Serve perche con main come branch di lavoro non
c'e piu un ambiente di prova tra il codice e i giocatori.

Il flusso git documentato non descriveva piu la realta: main e arrivato a 43
commit di vantaggio su develop, rimasto fermo. DD-003 e ora sostituita da DD-019:
il branch dei commit lo decide l'utente, l'assistente al massimo consiglia un
branch dedicato e non committa, non pusha e non apre PR di propria iniziativa.

Allineati di conseguenza ARCHITECTURE.md (sezione branch), README.md (flusso,
install con bun, comandi di test e lint), ROADMAP.md e TODO.md (le voci spuntate
sono in produzione, non su develop) e PROJECT_STATE.md (auth e profilo giocatore
in produzione, 20 migration fino a M9, passaggi 1-3 e 5 fatti).

Corretti poi sei disallineamenti tra documentazione e codice, ognuno verificato
sul sorgente:

- badge.md e obiettivi-squadra.md dicevano che le serie sono inerti e che
  serieAllenamenti e sempre 0, quindi badge e obiettivo "Continuita di squadra"
  non sbloccabili. Falso da 7237e8f: presenze.ts:48 le calcola e rosa.ts:64-67 le
  attacca al Giocatore. Il limite che resta e un altro, ora scritto: risposto_il
  non e ricostruibile prima di m9, quindi sulle risposte vecchie serieConferme e
  un'approssimazione.
- TODO.md e PROJECT_STATE.md davano il tracciamento tesseramento CSI come da
  fare, mentre ROADMAP, CHANGELOG e DATABASE lo davano per fatto. Lo e:
  admin.tsx:264-278 registra numero e data, :472 mostra Tesserato/Da tesserare,
  :676 il contatore.
- collegamento-csi.md indicava il check di parsing in src/lib/csi-core.test.ts;
  sta in test/unit/csi-core.test.ts, in src/lib non esiste nessun .test.ts.
- profilo-giocatore.md annunciava cinque aree del profilo e ne elencava sette.
- "Segnala un bug" e "Suggerisci una nuova funzionalita" (profilo.tsx:259-276,
  commit 72a9864) non erano documentati da nessuna parte, contro DD-002: ora
  stanno in profilo-giocatore.md e nel CHANGELOG.

npm run test: 28/28 file ok. npm run lint: 12 problemi, identici a prima di
questa modifica e tutti in src/, non toccato qui.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 23:24:22 +02:00

101 lines
4.9 KiB
Markdown

# 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.
- **`test/unit/csi-core.test.ts`** — check del parsing: `bun test/unit/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, l'endpoint `/api/public/csi` restituisce l'ultimo
dato buono in cache; se non ne ha ancora uno, la classifica resta vuota e i risultati
ricadono sulle partite dello Scout Live locale (`useScoutMatches()`).
- **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: `/classifica` non si rompe, ma mostra "Classifica non
ancora disponibile" (o l'ultimo dato buono in cache, se ce n'è uno) e i risultati ricadono
sulle partite dello Scout Live locale, non su dati demo — non esistono più in `crapp-data.ts`.
Il check con `CSI_LIVE=1` serve a scoprire il problema di parsing.
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.