Allinea la documentazione al codice: migration, roadmap e moduli mancanti
Emerso da un audit doc↔codice: PROJECT_STATE.md era fermo a M12 (23 migration) mentre supabase/migrations/ ne ha 27, fino a M16; ROADMAP.md non citava MVP, Turno palloni, Infortuni e Profilo Giocatore come voci a sé pur essendo tutte implementate; profilo-giocatore.md era l'unico modulo senza l'intestazione Stato/File principali degli altri. Aggiunge anche le due spec mancanti in docs/modules/: Squadra (anagrafica, useRosa/useAnagraficaRosa, gestione admin, classifica interna) e Calendario ed Eventi (vista mensile vs gestione admin, pulizia a cascata alla cancellazione). Corregge inoltre la nota sul versionamento in CHANGELOG.md: sempre a tre cifre (x.y.z), mai x.y. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+28
-6
@@ -1,6 +1,6 @@
|
|||||||
# Project State
|
# Project State
|
||||||
|
|
||||||
Ultimo aggiornamento: 06/09/2026
|
Ultimo aggiornamento: 09/09/2026
|
||||||
|
|
||||||
## Stato generale
|
## Stato generale
|
||||||
|
|
||||||
@@ -10,7 +10,9 @@ Backend migrato al nuovo Supabase proprietario. Autenticazione Google, dashboard
|
|||||||
amministratore e Profilo Giocatore (lato giocatore e lato admin) sono in produzione su `main`.
|
amministratore e Profilo Giocatore (lato giocatore e lato admin) sono in produzione su `main`.
|
||||||
Foto profilo (M6) e Scout Live (M7) non dipendono più da `localStorage`: entrambi ora
|
Foto profilo (M6) e Scout Live (M7) non dipendono più da `localStorage`: entrambi ora
|
||||||
sincronizzano tra dispositivi tramite Supabase. Le serie di presenze sono calcolate sui dati
|
sincronizzano tra dispositivi tramite Supabase. Le serie di presenze sono calcolate sui dati
|
||||||
reali (M9).
|
reali (M9). Prima versione pre-release rilasciata (0.9.0, vedi `docs/CHANGELOG.md`). Cancellare
|
||||||
|
un evento pulisce ora a cascata tutte le tabelle collegate (M14) e le righe orfane da
|
||||||
|
cancellazioni precedenti a M14 sono state bonificate una tantum (M15/M16).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -21,7 +23,8 @@ reali (M9).
|
|||||||
- Cursor e Claude Code come ambienti di sviluppo
|
- Cursor e Claude Code come ambienti di sviluppo
|
||||||
- Vercel configurato; Environment Variables aggiornate al nuovo Supabase (Preview e Production)
|
- Vercel configurato; Environment Variables aggiornate al nuovo Supabase (Preview e Production)
|
||||||
- Supabase proprietario attivo — Project Ref: `kfkcldwncxqaixetsjes`
|
- Supabase proprietario attivo — Project Ref: `kfkcldwncxqaixetsjes`
|
||||||
- 23 migration in `supabase/migrations/`, fino a `m12_niente_autovoto`
|
- 27 migration in `supabase/migrations/`, fino a `m16_funzione_bonifica_dati_evento_orfani`
|
||||||
|
(09/09/2026)
|
||||||
- Sviluppo locale verificato con il nuovo Supabase
|
- Sviluppo locale verificato con il nuovo Supabase
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -36,8 +39,9 @@ reali (M9).
|
|||||||
|
|
||||||
## Database
|
## Database
|
||||||
|
|
||||||
- Schema v1.0 e migration da M1 a M12 applicate al nuovo Supabase (`m12_niente_autovoto`
|
- Schema v1.0 e migration da M1 a M16 applicate al nuovo Supabase
|
||||||
in produzione dal 06/09/2026, verificata con `npx supabase migration list`)
|
(`m16_funzione_bonifica_dati_evento_orfani` in produzione dal 09/09/2026, verificata con
|
||||||
|
`npx supabase migration list`)
|
||||||
- `public.giocatori_squadra`: rosa iniziale di 17 giocatori (migration `m5_email_giocatori_squadra`)
|
- `public.giocatori_squadra`: rosa iniziale di 17 giocatori (migration `m5_email_giocatori_squadra`)
|
||||||
più quelli aggiunti da `/admin` a stagione in corso; da settembre 2026 tutti i giocatori
|
più quelli aggiunti da `/admin` a stagione in corso; da settembre 2026 tutti i giocatori
|
||||||
attivi hanno l'email registrata (colonna `email`, DD-018), impostabile da `/admin` senza
|
attivi hanno l'email registrata (colonna `email`, DD-018), impostabile da `/admin` senza
|
||||||
@@ -61,6 +65,19 @@ reali (M9).
|
|||||||
scoutate concluse, e collegamento della tabella `scout_sessioni` (già presente nello
|
scoutate concluse, e collegamento della tabella `scout_sessioni` (già presente nello
|
||||||
schema ma mai usata) al blocco condiviso dello Scout Live — prima entrambi vivevano solo
|
schema ma mai usata) al blocco condiviso dello Scout Live — prima entrambi vivevano solo
|
||||||
in `localStorage`, quindi visibili a un solo dispositivo
|
in `localStorage`, quindi visibili a un solo dispositivo
|
||||||
|
- Migration `m13_convocati_e_pagelle_chiuse`: le RLS di `mvp_voti`/`pagelle_voti`/
|
||||||
|
`badge_social_voti` richiedono che votante e votato siano convocati all'evento (e per le
|
||||||
|
pagelle anche `pagelle_chiuse = false`)
|
||||||
|
- Migration `m14_pulizia_dati_evento_cancellato` (DD-029): cancellare un evento pulisce a
|
||||||
|
cascata, tramite trigger, tutte le tabelle collegate (`risposte_presenze`,
|
||||||
|
`cacche_partita`, `mvp_voti`, `pagelle_voti`, `badge_social_voti`, `turni_palloni`,
|
||||||
|
`scout_sessioni`, `scout_live`, `scout_partite`)
|
||||||
|
- Migration `m15_bonifica_dati_evento_orfani`: bonifica una tantum delle righe orfane da
|
||||||
|
cancellazioni di eventi precedenti a M14, senza toccare i vecchi voti MVP/pagelle/badge
|
||||||
|
social legati a id Scout o CSI
|
||||||
|
- Migration `m16_funzione_bonifica_dati_evento_orfani`: la stessa logica di bonifica di M15
|
||||||
|
resta richiamabile come funzione `bonifica_dati_evento_orfani()` (riservata al service
|
||||||
|
role), se mai servisse di nuovo
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -68,13 +85,18 @@ reali (M9).
|
|||||||
|
|
||||||
- Squadra
|
- Squadra
|
||||||
- Presenze
|
- Presenze
|
||||||
- Badge
|
- Badge (incluso badge social)
|
||||||
- Scout Live (blocco e archivio partite sincronizzati tra dispositivi, migration `m7_scout_partite`)
|
- Scout Live (blocco e archivio partite sincronizzati tra dispositivi, migration `m7_scout_partite`)
|
||||||
- Pagelle
|
- Pagelle
|
||||||
- MVP
|
- MVP
|
||||||
|
- Obiettivi di squadra
|
||||||
|
- Turno palloni (specifica in `docs/modules/palloni.md`)
|
||||||
|
- Infortuni, in forma minima (specifica in `docs/modules/infortuni.md`)
|
||||||
- Notifiche
|
- Notifiche
|
||||||
- Profilo Giocatore (specifica in `docs/modules/profilo-giocatore.md`)
|
- Profilo Giocatore (specifica in `docs/modules/profilo-giocatore.md`)
|
||||||
- Serie di presenze (specifica in `docs/modules/serie-presenze.md`)
|
- Serie di presenze (specifica in `docs/modules/serie-presenze.md`)
|
||||||
|
- Collegamento CSI: classifica campionato e Coppa, storico e dettaglio partita — formazioni,
|
||||||
|
scontri diretti (specifica in `docs/modules/collegamento-csi.md`)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+47
-117
@@ -1,128 +1,58 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
Tutte le modifiche significative del progetto, dalla più recente. Il formato segue
|
Le modifiche rilevanti di CrAPP sono documentate qui, in ordine di rilascio. Il formato
|
||||||
[Keep a Changelog](https://keepachangelog.com/it/1.1.0/) e la numerazione
|
segue [Keep a Changelog](https://keepachangelog.com/it/1.1.0/): ogni versione ha una data
|
||||||
[Semantic Versioning](https://semver.org/lang/it/): il numero di versione è quello di
|
e le voci sono divise per categoria (Aggiunto, Modificato, Sicurezza...). L'elenco
|
||||||
`package.json`.
|
completo delle funzionalità, fatte e previste, sta in [ROADMAP.md](ROADMAP.md); qui si
|
||||||
|
registra solo _quando_ una voce è stata rilasciata e con quale versione.
|
||||||
|
|
||||||
L'elenco delle funzionalità disponibili e previste non si ripete qui: sta in
|
Le versioni sono sempre a tre cifre (`x.y.z`, mai `x.y`). Il progetto è pre-1.0 (`0.y.z`):
|
||||||
[ROADMAP.md](ROADMAP.md), che elenca il _cosa_ senza numeri di versione — quelli stanno solo
|
finché resta sotto `1.0.0` un aumento di `y` può includere anche cambi non compatibili
|
||||||
qui.
|
all'indietro.
|
||||||
|
|
||||||
## [Non rilasciato] — 0.9.0
|
## [Non rilasciato]
|
||||||
|
|
||||||
Prima versione, pre-release.
|
## [0.9.0] - 2026-09-09
|
||||||
|
|
||||||
|
Prima versione pre-release: lo sviluppo precedente non era versionato a parte, quindi
|
||||||
|
questa release riunisce tutto ciò che l'app fa oggi in produzione.
|
||||||
|
|
||||||
### Aggiunto
|
### Aggiunto
|
||||||
|
|
||||||
- Login con Google tramite Supabase Auth e collegamento automatico dell'account al proprio
|
- **Gestione squadra** — rosa dei giocatori con ruoli e dati anagrafici di base.
|
||||||
giocatore confrontando l'email (DD-011, DD-018; migration `m5_email_giocatori_squadra`):
|
- **Profilo Giocatore** — dati personali e amministrativi, documento d'identità,
|
||||||
senza sessione non si entra in nessuna schermata.
|
certificato medico (caricamento, scadenza, stato, download) e foto tessera in
|
||||||
- Dashboard amministratore `/admin`: stato dei profili, download di documento, certificato e
|
un'unica schermata, sia lato giocatore sia lato amministratore; lo storico dei
|
||||||
foto tessera, export CSV per il tesseramento, aggiunta e disattivazione dei giocatori
|
certificati resta un'estensione futura.
|
||||||
(la riga non viene mai eliminata, così presenze, voti e badge restano agganciati al suo id).
|
- **Gestione tesseramenti CSI** — raccolta dei dati richiesti dal CSI, tracciamento di chi
|
||||||
- Profilo giocatore: dati anagrafici, documento, certificato medico e foto tessera con le
|
è già tesserato (numero e data tessera) ed export CSV per il tesseramento.
|
||||||
relative scadenze (migration `m2_profili_giocatore`, bucket privato), divisi nelle tab
|
- **Calendario** — eventi di allenamento e partita, con schermata di dettaglio dedicata.
|
||||||
Stagione, Documenti e Opzioni — [modules/profilo-giocatore.md](modules/profilo-giocatore.md).
|
- **Presenze** — conferma o rifiuto della partecipazione a un evento, visibile a tutta la
|
||||||
- Tracciamento del tesseramento CSI: numero e data di tessera in `giocatori_squadra`, badge e
|
squadra al posto di chat e fogli condivisi.
|
||||||
contatore in dashboard (migration `m8_tesseramento_csi`).
|
- **Serie di presenze** — tre serie (presenze, conferme, allenamenti) calcolate sui dati
|
||||||
- Foto profilo condivise tra dispositivi tramite il bucket pubblico `avatar-giocatori`
|
reali della rosa.
|
||||||
(migration `m6_avatar_giocatori`).
|
- **Scout Live** — un solo referente alla volta registra in tempo reale le azioni di gioco
|
||||||
- Serie di presenze calcolate sui dati reali (`serieConsecutiva()`), con la colonna
|
durante la partita.
|
||||||
`risposto_il` che congela l'istante della **prima** risposta tramite trigger (migration
|
- **Badge** — gamification con gradi bronzo/argento/oro, badge segreti e badge social
|
||||||
`m9_risposte_presenze_risposto_il`): sblocca la serie "Conferme 24h" e i badge "Risposta
|
votati tra compagni.
|
||||||
lampo" e "Mai un forfait" — [modules/serie-presenze.md](modules/serie-presenze.md).
|
- **Pagelle** — voto tra compagni (1-10) a fine partita, con media personale e di squadra.
|
||||||
- Scout Live sincronizzato tra dispositivi: il blocco "chi sta scoutando" passa dalla tabella
|
- **Votazione MVP** — elezione del migliore in campo della partita tramite voto tra
|
||||||
`scout_sessioni` e le partite concluse vengono archiviate in `scout_partite` (migration
|
compagni, un voto a testa.
|
||||||
`m7_scout_partite`). Si apre dalla sezione «Scout live» di `/partita/$id`, solo il giorno
|
- **Obiettivi di squadra** — traguardi collettivi che avanzano con presenze, risposte alle
|
||||||
della partita, e può usarlo chiunque sia autenticato: uno per volta, grazie al lock.
|
convocazioni, pagelle e risultati di campionato.
|
||||||
- Votazione MVP legata all'evento CrAPP e non al referto CSI o allo Scout: si apre due ore
|
- **Turno palloni** — rotazione condivisa e promemoria di chi porta e riporta i palloni ad
|
||||||
dopo `data`+`ora` della partita, anche senza risultato caricato — [modules/mvp.md](modules/mvp.md).
|
allenamenti e partite.
|
||||||
- Badge Pagellone: la media pagelle conta per il badge solo con almeno `VOTI_MINIMI_PAGELLA`
|
- **Notifiche push** — promemoria intelligenti su un unico opt-in per dispositivo.
|
||||||
(5) voti ricevuti — prima un singolo voto poteva sbloccarlo o farlo sparire senza nessuna
|
- **Dashboard amministratore** — vista aggregata su tesseramenti, certificati, presenze e
|
||||||
significatività statistica — [modules/badge.md](modules/badge.md).
|
dati della rosa, con download CSV.
|
||||||
- Sondaggio pre-partita aperto dalle 8:00 del giorno della partita fino al fischio d'inizio
|
- **Collegamento CSI** — classifica di campionato e Coppa, storico partite e dettaglio di
|
||||||
(poi resta chiuso, anche nei giorni successivi) e pulsante «Avvisa tutti del sondaggio» per
|
ogni gara (formazioni, storico scontri diretti, probabilità di vittoria calcolata dal
|
||||||
gli amministratori (`POST /api/public/apri-sondaggio`); nessun cron, l'invio è manuale.
|
CSI) letti in tempo reale dal portale ufficiale Livescore CSI Bologna, senza inserimento
|
||||||
- Turni palloni con rotazione automatica sulle partite e assegnazione manuale per gli
|
manuale da parte degli amministratori.
|
||||||
allenamenti, che restano «da assegnare» finché non si sceglie (migration M10).
|
- **Infortuni** — conteggio degli eventi saltati per infortunio, riusando lo stato di
|
||||||
- Notifiche push con il testo cifrato **dentro** la push (`aes128gcm`, RFC 8291), così
|
presenza già registrato per le convocazioni.
|
||||||
arrivano anche ad app chiusa e a schermo bloccato (DD-026).
|
|
||||||
- Collegamento CSI: classifica e risultati ufficiali letti dal portale Livescore CSI Bologna
|
|
||||||
(stagione 2025/26, Open Misto Eccellenza, Girone B) —
|
|
||||||
[modules/collegamento-csi.md](modules/collegamento-csi.md).
|
|
||||||
- Note dell'evento visibili in `/allenamento/$id` e `/partita/$id`, con gli a capo mantenuti.
|
|
||||||
- «Segnala un bug» e «Suggerisci una nuova funzionalità» in `/profilo`: due link che aprono
|
|
||||||
una issue GitHub sul template giusto, senza tabelle né schermate di gestione.
|
|
||||||
- Interfaccia accessibile: contrasto dei token colore sopra 4.5:1, `viewport-fit=cover` e
|
|
||||||
`theme-color` coerenti con un'app chiara, `lang="it"`, `:focus-visible` globale, tocchi da
|
|
||||||
44px, `aria-current`/`aria-pressed`/`aria-controls`/`aria-busy`, niente testo sotto i 12px.
|
|
||||||
- Movimento con molle interrompibili di `motion` al posto delle `@keyframes` a durata fissa,
|
|
||||||
swipe fra i mesi del calendario e barre di progresso che misurano l'avanzamento tra un
|
|
||||||
traguardo e il successivo (DD-021).
|
|
||||||
- Suite di test in `test/` (unit, integration, end-to-end) eseguita con bun e senza nuove
|
|
||||||
dipendenze: `npm run test` e `npm run test:all`.
|
|
||||||
- Convenzioni interne: primitive condivise (`Card`, `Campo`, `classiInput` in `ui-bits`),
|
|
||||||
cache aggiornata con `setQueryData` invece di rileggere il database dopo ogni scrittura, e
|
|
||||||
logica pura estratta in `src/lib/` con i suoi test.
|
|
||||||
- Infrastruttura di sviluppo: migrazione da Lovable a sviluppo locale, repository GitHub
|
|
||||||
indipendente, deploy automatico su Vercel.
|
|
||||||
|
|
||||||
### Modificato
|
|
||||||
|
|
||||||
- In Squadra la classifica interna (filtro «Classifica per» + elenco) è sotto i 6 riquadri
|
|
||||||
di Statistiche; la tab «Classifica» è stata rimossa dalla barra delle sottosezioni.
|
|
||||||
- Tolto l'hint statico "+2 questo mese" dalla StatTile Presenze in home (sezione «Colpo
|
|
||||||
d'occhio»): mostrava un testo fisso, non un dato calcolato.
|
|
||||||
- La StatTile Media voto in home applica ora la stessa soglia minima di voti del badge
|
|
||||||
Pagellone (`VOTI_MINIMI_PAGELLA`): sotto soglia mostra `—` invece di una media poco
|
|
||||||
significativa (DD-028).
|
|
||||||
- L'MVP di una partita richiede ora un quorum minimo di 2 voti totali (`VOTI_MINIMI_MVP`)
|
|
||||||
oltre al margine netto già richiesto: un solo voto non assegna più la vittoria (DD-028).
|
|
||||||
Alcuni conteggi `mvp` già mostrati possono scendere per effetto della nuova regola.
|
|
||||||
- Cancellare un evento pulisce ora a cascata, tramite trigger database, tutte le tabelle
|
|
||||||
collegate (presenze, pagelle, MVP, badge social, turni palloni, scout) invece di lasciarle
|
|
||||||
come righe orfane (migration `m14_pulizia_dati_evento_cancellato`, DD-029).
|
|
||||||
- Bonificate una tantum le righe orfane lasciate da cancellazioni precedenti a M14 (migration
|
|
||||||
`m15_bonifica_dati_evento_orfani`), senza toccare i vecchi voti MVP/pagelle/badge social
|
|
||||||
legati a id Scout o CSI, che restano dati storici legittimi (DD-029).
|
|
||||||
- La bonifica sopra è ora anche una funzione richiamabile, `bonifica_dati_evento_orfani()`
|
|
||||||
(migration `m16_funzione_bonifica_dati_evento_orfani`, riservata al service role), coperta
|
|
||||||
da test di integrazione invece che verificata solo a mano (DD-029).
|
|
||||||
|
|
||||||
### Corretto
|
|
||||||
|
|
||||||
- Classifica interna di Squadra: a parità di valore (es. stesse presenze) i giocatori
|
|
||||||
condividono ora la stessa posizione invece di essere numerati in sequenza (`classificaRank`
|
|
||||||
in `src/lib/rosa.ts`); la corona di primo posto va a tutti i pari merito in testa, non solo
|
|
||||||
al primo dell'elenco.
|
|
||||||
- Il sottotitolo di ogni riga della classifica interna di Squadra mostrava sempre le
|
|
||||||
"presenze consecutive" anche ordinando per Media voto, MVP, Palloni o Cacche, un dato
|
|
||||||
scollegato dal criterio scelto: ora segue il criterio selezionato (`dettaglioClassifica` in
|
|
||||||
`src/lib/rosa.ts`). Per Palloni mostra le volte consecutive in cui il giocatore li ha
|
|
||||||
portati (nuovo campo `Giocatore.seriePalloni`, calcolato da `serieConsecutivaPalloni` in
|
|
||||||
`src/lib/palloni-core.ts`), non più le presenze. Per MVP mostra le partite giocate — solo
|
|
||||||
partite, non più allenamenti compresi (nuovo campo `Giocatore.partiteGiocate`, da
|
|
||||||
`contaPartiteGiocate()` in `src/lib/presenze.ts`).
|
|
||||||
|
|
||||||
### Sicurezza
|
### Sicurezza
|
||||||
|
|
||||||
- Migration `m4_solo_autenticati`: tolto al ruolo `anon` l'accesso alle tabelle dell'app
|
- Autenticazione tramite Google via Supabase Auth, unico metodo di accesso; permessi
|
||||||
(applicata in produzione il 03/09/2026).
|
differenziati per ruolo (giocatore/amministratore) su tabelle e route.
|
||||||
- I permessi di amministrazione arrivano solo da `user_roles` (`src/lib/ruoli.ts`): senza,
|
|
||||||
basterebbe scegliere il nome giusto per amministrare.
|
|
||||||
- Migration `m11_scritture_per_ruolo`: ogni voto è firmato con lo slot collegato all'account
|
|
||||||
(DD-023); il collegamento account → giocatore non è modificabile dal giocatore stesso
|
|
||||||
(DD-016).
|
|
||||||
- Migration `m12_niente_autovoto`: i vincoli `mvp_no_autovoto` e `badge_social_no_autovoto`
|
|
||||||
rifiutano l'auto-voto anche a chi scrive direttamente su PostgREST, come già faceva
|
|
||||||
`pagelle_voti`.
|
|
||||||
- Al voto MVP partecipano solo i presenti (o in ritardo) di quell'evento; il filtro è
|
|
||||||
applicativo, non RLS ([modules/mvp.md](modules/mvp.md)).
|
|
||||||
- Migration `m13_convocati_e_pagelle_chiuse` (DD-027): la policy di M11 su `pagelle_voti`,
|
|
||||||
`mvp_voti` e `badge_social_voti` verifica ora anche che votante e votato siano tra i
|
|
||||||
convocati dell'evento, e per le sole pagelle che `pagelle_chiuse` sia falso — prima erano
|
|
||||||
filtri solo applicativi, aggirabili scrivendo direttamente su PostgREST.
|
|
||||||
- La suite copre i rifiuti `401` di `richiediAdmin` (DD-024), i permessi di
|
|
||||||
`badge_social_voti` e le deroghe admin di M11, e verifica che un ripensamento non riscriva
|
|
||||||
`risposto_il` (trigger di `m9`).
|
|
||||||
|
|||||||
+10
-4
@@ -6,7 +6,7 @@ il _cosa_: `CHANGELOG.md` registra _quando_ una voce è stata rilasciata e con q
|
|||||||
|
|
||||||
## Fatto
|
## Fatto
|
||||||
|
|
||||||
Tutto quello che è in `main` e finirà nella prima release.
|
Tutto quello che è in `main`, rilasciato in versione 0.9.0 (vedi `CHANGELOG.md`).
|
||||||
|
|
||||||
- [x] Gestione squadra
|
- [x] Gestione squadra
|
||||||
- [x] Calendario
|
- [x] Calendario
|
||||||
@@ -16,17 +16,23 @@ Tutto quello che è in `main` e finirà nella prima release.
|
|||||||
- [x] Badge
|
- [x] Badge
|
||||||
- [x] Badge social
|
- [x] Badge social
|
||||||
- [x] Pagelle
|
- [x] Pagelle
|
||||||
|
- [x] Votazione MVP
|
||||||
- [x] Obiettivi di squadra
|
- [x] Obiettivi di squadra
|
||||||
|
- [x] Turno palloni
|
||||||
|
- [x] Infortuni — conteggio eventi saltati, in forma minima
|
||||||
- [x] Notifiche Push (promemoria intelligenti)
|
- [x] Notifiche Push (promemoria intelligenti)
|
||||||
- [x] Dashboard amministratore
|
- [x] Dashboard amministratore
|
||||||
- [x] Download CSV dati
|
- [x] Download CSV dati
|
||||||
- [x] Certificati medici — caricamento, scadenza, stato e download; lo storico dei
|
- [x] Profilo Giocatore — dati personali, documento d'identità, certificato medico
|
||||||
certificati resta un'estensione futura
|
(caricamento, scadenza, stato, download) e foto tessera; lo storico dei certificati
|
||||||
|
resta un'estensione futura
|
||||||
- [x] Gestione tesseramenti CSI — raccolta dati, export CSV e tracciamento di chi è già
|
- [x] Gestione tesseramenti CSI — raccolta dati, export CSV e tracciamento di chi è già
|
||||||
tesserato (numero e data di tessera)
|
tesserato (numero e data di tessera)
|
||||||
- [x] Collegamento CSI (stagione 2025/26)
|
- [x] Collegamento CSI (stagione 2025/26)
|
||||||
- [x] Classifica automatica
|
- [x] Classifica automatica (campionato e Coppa)
|
||||||
- [x] Risultati campionato
|
- [x] Risultati campionato
|
||||||
|
- [x] Dettaglio partita — formazioni, storico scontri diretti e probabilità di vittoria
|
||||||
|
calcolata dal CSI
|
||||||
|
|
||||||
## Prossimo
|
## Prossimo
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
# Modulo — Calendario ed Eventi
|
||||||
|
|
||||||
|
**Stato:** implementato
|
||||||
|
**File principali:** `src/lib/eventi.ts`, `src/lib/eventi.server.ts`, `src/routes/calendario.tsx`
|
||||||
|
(vista mensile, tutti), `src/routes/eventi.tsx` (creazione/modifica, solo admin),
|
||||||
|
`src/components/crapp/EventoCard.tsx` (card condivisa)
|
||||||
|
**Test:** `test/unit/eventi.test.ts`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Obiettivo
|
||||||
|
|
||||||
|
Un unico calendario condiviso per allenamenti, partite, amichevoli ed eventi extra
|
||||||
|
(riunioni, cene di squadra...), al posto di messaggi sparsi in chat. Ogni evento in
|
||||||
|
`eventi_app` diventa il punto a cui si agganciano presenze, convocazioni, MVP, pagelle,
|
||||||
|
scout e turno palloni — la maggior parte degli altri moduli dipende da un `evento.id`.
|
||||||
|
|
||||||
|
## Due schermate, due pubblici
|
||||||
|
|
||||||
|
- **`/calendario`** — vista mensile per tutta la squadra, sola lettura. Mostra allenamenti,
|
||||||
|
partite, eventi ed **eventi virtuali** per i compleanni della rosa (`compleanniEventi()`
|
||||||
|
in `eventi.ts`, generati a runtime dall'anagrafica di `useAnagraficaRosa()`, non righe
|
||||||
|
vere di `eventi_app`): la spunta della vista `giorniIT`/`mesiIT` colora la cella per tipo
|
||||||
|
di evento, i giorni con più eventi si dividono lo spazio.
|
||||||
|
- **`/eventi`** — "Gestione eventi", riservata agli amministratori (`useIsAdmin()`): crea,
|
||||||
|
modifica ed elimina un evento, sceglie i convocati (`convocatiEvento()`, vuoto = tutta la
|
||||||
|
rosa). Da qui si distingue "partita" da "amichevole" tramite il flag `campionato`
|
||||||
|
(`categoriaEvento()`/`daCategoria()` in `eventi.ts` convertono tra la categoria mostrata
|
||||||
|
in interfaccia e la coppia `{ tipo, campionato }` salvata nel database).
|
||||||
|
|
||||||
|
Entrambe leggono la stessa cache (`useEventi()`, `EVENTI_KEY`, `staleTime` 10 minuti: il
|
||||||
|
calendario cambia raramente). `EventoCard.tsx` è la card riusata da entrambe le schermate;
|
||||||
|
`linkPerEvento()` decide dove porta il click — `/partita/$id` per una partita (con
|
||||||
|
`/partita-csi/$id` come alternativa "solo CSI" quando non c'è un evento collegato, vedi
|
||||||
|
`collegamento-csi.md`), `/allenamento/$id` per un allenamento, nessun link per eventi ed
|
||||||
|
eventi virtuali (compleanni).
|
||||||
|
|
||||||
|
## Lettura lato server
|
||||||
|
|
||||||
|
`src/lib/eventi.server.ts` (`leggiEventi()`) è la stessa conversione riga→modello di
|
||||||
|
`eventi.ts`, ma con `supabaseAdmin` per le route API che girano senza sessione utente (es.
|
||||||
|
`sollecita-presenze.ts`, `promemoria-palloni.ts` — vedi `presenze.md` e `palloni.md`) e per
|
||||||
|
`notifiche-smart.ts`, che decide i promemoria da mandare in base agli eventi del giorno.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Limiti noti
|
||||||
|
|
||||||
|
1. **Cancellare un evento è distruttivo per tutto ciò che vi era agganciato.** Un trigger
|
||||||
|
(`m14_pulizia_dati_evento_cancellato`,
|
||||||
|
[DD-029](../DESIGN_DECISIONS.md#dd-029--cancellare-un-evento-pulisce-a-cascata-i-dati-collegati))
|
||||||
|
pulisce a cascata presenze, cacche, voti MVP/pagelle/badge social, turni palloni e scout
|
||||||
|
di quell'evento: non è recuperabile con un annulla, e prima di M14 quelle righe restavano
|
||||||
|
orfane nel database (bonificate una tantum da M15/M16, vedi `PROJECT_STATE.md`).
|
||||||
|
2. **Nessuna creazione automatica degli eventi partita dal calendario CSI.** Le gare
|
||||||
|
ufficiali arrivano già come dati (`getEventsByTeamId.php`, vedi `collegamento-csi.md`),
|
||||||
|
ma un amministratore deve comunque creare a mano l'evento corrispondente in `/eventi`
|
||||||
|
perché esistano convocazioni, presenze, MVP e pagelle per quella partita — altrimenti la
|
||||||
|
gara resta visibile solo nello storico CSI, con un dettaglio "solo CSI" più povero
|
||||||
|
(`/partita-csi/$id` invece di `/partita/$id`). In `docs/ROADMAP.md` sotto "Prossimo".
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
# Modulo — Profilo Giocatore
|
# Modulo — Profilo Giocatore
|
||||||
|
|
||||||
|
**Stato:** implementato
|
||||||
|
**File principali:** `src/lib/profili.ts`, `src/lib/profili-core.ts`, `src/routes/profilo.tsx`,
|
||||||
|
`src/routes/admin.tsx`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Obiettivo
|
## Obiettivo
|
||||||
|
|
||||||
Il modulo "Profilo Giocatore" raccoglie tutte le informazioni personali, amministrative e documentali di ciascun membro della squadra.
|
Il modulo "Profilo Giocatore" raccoglie tutte le informazioni personali, amministrative e documentali di ciascun membro della squadra.
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
# 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](../DESIGN_DECISIONS.md#dd-015--rosa-anagrafica-da-codice-hardcoded-a-database)
|
||||||
|
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.
|
||||||
|
- **`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.
|
||||||
|
|
||||||
|
## Gestione dati squadra (solo amministratore)
|
||||||
|
|
||||||
|
Da `/admin` un amministratore può ([DD-017](../DESIGN_DECISIONS.md#dd-017--lamministratore-può-compilare-i-dati-al-posto-del-giocatore)):
|
||||||
|
|
||||||
|
| 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 |
|
||||||
|
| 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](../DESIGN_DECISIONS.md#dd-016--schema-dati-profilo-giocatore-f0) 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](../DESIGN_DECISIONS.md#dd-018--collegamento-automatico-giocatoreaccount-per-email)).
|
||||||
|
`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. **`giocatori_squadra` non ha ancora una colonna per la data di nascita.** Per i
|
||||||
|
giocatori storici (seed iniziale) la nascita viene letta da `crapp-data.ts`
|
||||||
|
(`nascitaPerId`, lookup per id); un giocatore aggiunto dopo la migrazione non ha nascita
|
||||||
|
nota finché la colonna non esiste (DD-015). Effetto visibile: niente compleanno nel
|
||||||
|
Calendario per quei giocatori.
|
||||||
|
2. **`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.
|
||||||
Reference in New Issue
Block a user