- Spezza il registro delle decisioni in docs/decisions/DD-XXX.md, con indice - Ripulisce DATABASE.md dalla storia delle migration e aggiunge la sezione Lettura - Riduce PROJECT_STATE.md a una pagina; la procedura di allestimento passa in OPERATIONS.md - Aggiunge OPERATIONS.md, GLOSSARIO.md, trappole note e checklist in ARCHITECTURE.md - Sintetizza la copertura test di badge.md e documenta docs/archive - Allinea AGENTS.md, README.md e la regola Cursor (tolto l'obbligo di develop, in contrasto con DD-019) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
99 lines
6.3 KiB
Markdown
99 lines
6.3 KiB
Markdown
# Modulo — Squadra
|
|
|
|
**Stato:** implementato
|
|
**File principali:** `src/lib/giocatori-squadra.ts`, `src/lib/giocatori-squadra.server.ts`,
|
|
`src/lib/rosa.ts`, `src/routes/squadra.tsx`, `src/routes/admin.tsx` (sezione rosa)
|
|
**Test:** `test/unit/giocatori-squadra.test.ts`, `test/unit/rosa.test.ts`
|
|
|
|
---
|
|
|
|
## Obiettivo
|
|
|
|
Tenere l'anagrafica della rosa (nome, numero di maglia, ruolo, chi è collegato a quale
|
|
account) in un unico posto — `giocatori_squadra` — e farla usare a tutte le schermate che
|
|
hanno bisogno di sapere "chi c'è in squadra", invece di ciascuna avere la propria copia.
|
|
Prima di [DD-015](../decisions/DD-015.md)
|
|
la lista viveva hardcoded in `src/lib/crapp-data.ts`: aggiungere o disattivare un
|
|
giocatore dalla dashboard admin non aveva alcun effetto sul resto dell'app.
|
|
|
|
---
|
|
|
|
## Due letture diverse, per non pagare due volte lo stesso costo
|
|
|
|
- **`useAnagraficaRosa()`** (`rosa.ts`) — solo id, nome, ruolo, numero, data di nascita dei
|
|
giocatori `attivo`. Serve dove basta sapere chi c'è, es. i compleanni nel Calendario o le
|
|
liste presenze: non monta gli hook di MVP/pagelle/palloni/infortuni. La data di nascita
|
|
viene da `giocatori_squadra.nascita` (migration `m18_nascita_pubblica_giocatori_squadra`,
|
|
DD-031): pubblica a tutta la rosa, sincronizzata automaticamente da un trigger quando il
|
|
giocatore (o un admin per lui) la salva dal Profilo — vedi `profilo-giocatore.md`. `null`
|
|
finché non è stata inserita da nessuno.
|
|
- **`useRosa()`** (`rosa.ts`) — la stessa anagrafica arricchita con tutte le statistiche
|
|
personali calcolate a runtime: presenze, partite giocate, serie (presenze, allenamenti,
|
|
partite, conferme, palloni), MVP vinti, media voto pagelle, palloni, cacche, infortuni,
|
|
ritardi. Non fa query aggiuntive: combina in un `useMemo` le cache già in memoria di
|
|
`mvp-voti.ts`, `pagelle.ts`, `cacche.ts`, `palloni.ts`, `infortuni.ts`, `presenze.ts`,
|
|
`eventi.ts` — la spec di ciascuna di queste statistiche sta nel modulo relativo
|
|
(`mvp.md`, `pagelle.md`, `palloni.md`, `infortuni.md`, `presenze.md`). `useRosa()` è anche
|
|
la base di `useIo()` (il giocatore sul dispositivo corrente) e `useObiettivi()`
|
|
(`obiettivi-squadra.md`).
|
|
|
|
Entrambe filtrano solo i giocatori `attivo`: chi ha lasciato la squadra resta nel database
|
|
(presenze, voti, pagelle e badge della stagione restano agganciati al suo id) ma sparisce
|
|
dagli elenchi correnti. Il filtro è `inRosa()` (`giocatori-squadra.ts`), che esclude anche
|
|
gli allenatori (`tipo = 'allenatore'`, DD-034): hanno uno slot ma non giocano.
|
|
`useAnagraficaRosa({ conAllenatori: true })` li include, per i compleanni.
|
|
|
|
## Allenatori in Squadra
|
|
|
|
Nella tab Rosa gli allenatori attivi compaiono in cima, con foto, nome e la dicitura
|
|
«Allenatore» dove i giocatori hanno il ruolo in campo (`ruoloVisibile()`); niente numero,
|
|
statistiche né badge, e niente posto nella tab Stats. Chi usa l'app da allenatore vede solo
|
|
Rosa e Stats, senza badge e senza cacche (criterio «Cacche» e riga «Cacche/partita»). La
|
|
specifica completa sta in [allenatore.md](allenatore.md).
|
|
|
|
## Gestione dati squadra (solo amministratore)
|
|
|
|
Da `/admin` un amministratore può ([DD-017](../decisions/DD-017.md)):
|
|
|
|
| Azione | Hook | Effetto |
|
|
| ------------------------------ | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| Modificare dati squadra | `useSalvaDatiSquadra()` | Nome, cognome, numero, ruolo, email (usata per il collegamento automatico, non il dato personale del profilo) |
|
|
| Aggiungere un giocatore | `useAggiungiGiocatore()` | Nuova riga con id progressivo `g<N>` (`prossimoIdGiocatore()`), non generato dal database; con tipo «Allenatore» senza numero né ruolo (DD-034) |
|
|
| Attivare/disattivare | `useImpostaAttivo()` | Non elimina la riga: la storia della stagione resta intatta |
|
|
| Scollegare un account | `useScollegaAccount()` | Libera uno slot collegato per errore ([DD-016](../decisions/DD-016.md) regola 2); il giocatore si ricollega al primo accesso successivo |
|
|
| Registrare il tesseramento CSI | `useSalvaTesseramento()` | Numero e data tessera, note solo dopo il tesseramento effettivo (vedi `profilo-giocatore.md`) |
|
|
|
|
Il collegamento giocatore↔account, invece, non è manuale: avviene in automatico al primo
|
|
accesso con Google, per corrispondenza email
|
|
([DD-018](../decisions/DD-018.md)).
|
|
`useCollegaGiocatore()` esiste per completare quel flusso, non per una scelta libera
|
|
dell'admin.
|
|
|
|
Le regole di validazione (`validaDatiSquadra()`, `numeroGiaUsato()`) rispecchiano i vincoli
|
|
della tabella (numero maglia univoco tra gli attivi, campi obbligatori): l'obiettivo è
|
|
mostrare un messaggio leggibile invece di far arrivare un errore Postgres grezzo
|
|
all'amministratore.
|
|
|
|
## Classifica interna di Squadra
|
|
|
|
La tab "Stats" di `/squadra` mostra una classifica interna ordinabile per 5 criteri
|
|
(`CriterioClassifica` in `rosa.ts`): presenze, media voto, MVP, palloni, cacche/partita.
|
|
`classificaRank()` calcola un "dense rank" (a parità di valore stessa posizione, il
|
|
successivo non salta — 1, 1, 2, non 1, 1, 3); `dettaglioClassifica()` sceglie quale
|
|
sottostatistica mostrare sotto il nome, coerente col criterio selezionato (es. "voti
|
|
pagella" per il criterio media voto, non sempre "presenze consecutive").
|
|
|
|
Le altre tab di `/squadra` (Rosa, Obiettivi, Badge) sono viste diverse sugli stessi dati di
|
|
`useRosa()`/`useObiettivi()`/`badges.ts`: non introducono altra logica di dominio, solo
|
|
presentazione — le rispettive specifiche stanno in `badge.md` e `obiettivi-squadra.md`.
|
|
|
|
---
|
|
|
|
## Limiti noti
|
|
|
|
1. **`src/lib/crapp-data.ts` resta come fallback**, non più come fonte viva: se il database
|
|
non risponde o non è ancora popolato, `rosaFallback()` genera una rosa di riserva dai
|
|
dati statici storici. Un ambiente nuovo senza dati in `giocatori_squadra` mostra quindi
|
|
comunque una squadra, non una schermata vuota — ma è la rosa 2025/26 hardcoded, non
|
|
quella reale.
|