Ogni testo sotto i 16 px sale di un passo in tutte le pagine (12→13, 13→14, 14→15, 15→16); restano invariate le barre a pillola dei menu (navigazione in basso e sottosezioni) e i badge da 10-11 px. Nella scheda giocatore di Squadra l'etichetta «Cacche/partita» diventa «Cacche» (il valore resta la media). Documentazione: DD-049, CHANGELOG, ARCHITECTURE, PROJECT_STATE, moduli squadra e allenatore. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
18 KiB
Modulo — Ruolo Allenatore
Stato: implementato
Decisione: DD-034
Migration: m20_ruolo_allenatore_enum, m21_ruolo_allenatore
File principali: src/lib/giocatori-squadra.ts (tipo, inRosa, isAllenatore,
ruoloVisibile), src/lib/ruoli.ts, src/lib/user-store.ts (useSonoAllenatore,
useGiocatoreInCampo), src/lib/auth-route.server.ts, src/routes/profilo.tsx,
src/routes/admin.tsx, src/routes/squadra.tsx, src/routes/index.tsx
Test: test/unit/giocatori-squadra.test.ts, test/unit/profili-core.test.ts,
test/unit/presenze.test.ts, test/integration/permessi-allenatore.test.ts,
test/integration/permessi-route.test.ts
Obiettivo
Dare accesso all'app all'allenatore, con permessi diversi da quelli di un giocatore: gestisce gli eventi (allenamenti, partite, amichevoli) e sollecita le presenze, ma non gioca: compare in Squadra come membro con la dicitura «Allenatore», però non è convocabile, non vota, non riceve voti e non ha statistiche, badge o stagione.
Registrazione
Stesso flusso dei giocatori (DD-018), senza passaggi in più:
- L'admin, da
/admin→ Aggiungi, sceglie il tipo Allenatore invece di Giocatore e inserisce nome, cognome ed email Gmail. Numero di maglia e ruolo in campo non si chiedono. - L'allenatore accede con Google; l'email corrisponde allo slot e il collegamento è automatico. Se l'email non corrisponde, stesso messaggio di errore dei giocatori.
- Entra in Home.
Il permesso nasce dalla registrazione fatta dall'admin: l'allenatore non può auto-promuoversi, perché il tipo dello slot lo scrive solo un admin (come oggi numero e ruolo).
Profilo
Il profilo dell'allenatore ha solo due tab (quelle del giocatore sono quattro):
| Tab | Giocatore | Allenatore |
|---|---|---|
| Stagione | sì | no |
| Badge | sì | no |
| Documenti | sì | sì, ridotta (vedi sotto); tab iniziale |
| Impostazioni | sì | sì, identica (logout, notifiche, segnalazioni) |
Un link diretto a /profilo?tab=stagione o ?tab=badge apre Documenti.
Dati modificabili dall'allenatore
| Campo | Dove sta oggi | Nota |
|---|---|---|
| Nome, cognome | giocatori_squadra |
per un giocatore li scrive solo l'admin; per l'allenatore anche lui sul proprio slot |
| Email (contatto) | profili_giocatore.email |
non è l'email di login, che resta quella registrata dall'admin |
| Data di nascita | profili_giocatore.data_nascita |
sincronizzata in giocatori_squadra.nascita come per tutti (DD-031): compleanno in Calendario |
| Luogo di nascita | profili_giocatore.luogo_nascita |
|
| Telefono | profili_giocatore.telefono |
|
| Foto profilo | bucket avatar-giocatori |
stesso cerchio avatar e stesso upload dei giocatori |
Non si mostrano: indirizzo di residenza, documento d'identità, certificato medico, tesseramento CSI.
Completamento profilo
Per l'allenatore il completamento conta solo data e luogo di nascita, telefono ed email, 25%
ciascuno (completamentoAllenatore()). Il widget in Home segue la stessa regola: sparisce
quando quei campi sono compilati.
Home
La Home dell'allenatore tiene ciò che riguarda la squadra e toglie ciò che riguarda il giocatore: restano classifica e bilancio, prossimo impegno e ultima partita; spariscono lo streak personale, il promemoria palloni, «Da confermare», l'obiettivo di squadra e il «Colpo d'occhio» con le statistiche personali. Non compare nemmeno l'avviso certificati: lo vedono solo gli admin e il giocatore interessato (DD-035).
Squadra
L'allenatore compare nella tab Rosa insieme ai giocatori, con foto, nome e cognome. Dove
per un giocatore c'è il ruolo in campo (palleggiatore, schiacciatore…) per lui c'è scritto
Allenatore, ricavato da tipo e non dal campo ruolo. Non ha numero di maglia né
statistiche, e non compare nella tab Stats né nelle classifiche.
Da allenatore, in /squadra vede solo Rosa e Stats: le tab Obiettivi e Badge
non compaiono.
| Tab | Giocatore | Allenatore |
|---|---|---|
| Rosa | sì | sì |
| Stats | sì | sì |
| Obiettivi | sì | no |
| Badge | sì | no |
Badge e cacche nascosti
L'allenatore non vede nessun badge e nessuna classifica o dato sulle cacche, in nessuna schermata:
| Dove | Cosa si nasconde all'allenatore |
|---|---|
/squadra → Stats |
il criterio di ordinamento «Cacche» (cacchePartita) |
/squadra → Rosa, scheda giocatore |
la riga «Cacche 💩» |
/partita/$id |
la sezione «Badge votati dai compagni» e il sondaggio cacche (SondaggioCacche) |
| push «Sondaggio pre-partita aperto» | non parte verso i dispositivi degli allenatori (apri-sondaggio.ts) |
/profilo, /squadra |
le tab Badge (già escluse sopra) |
Presenze, media voto, MVP e palloni restano visibili.
Gestione eventi
L'allenatore ha su /eventi gli stessi poteri dell'admin: crea, modifica, sposta ed elimina
eventi e sceglie i convocati (l'elenco dei convocati contiene solo giocatori). Nel database
la policy di scrittura su eventi_app è "admin o allenatore" (M21); la cancellazione a
cascata (DD-029) resta invariata. Il bottone «Gestisci eventi» del Calendario compare anche
a lui (usePuoGestireEventi()).
Può anche sollecitare le presenze di un evento, come l'admin: la route
sollecita-presenze.ts accetta admin o allenatore (richiediGestoreEventi()), e il
sollecito arriva solo ai giocatori che non hanno risposto, mai all'allenatore stesso. Con DD-040 si aggiungono un sollecito automatico 24 ore prima dell'evento, ma il pulsante resta.
Restano solo admin: dashboard /admin, dati e documenti dei giocatori, export CSI,
notifica personalizzata, promemoria palloni, apertura sondaggio cacche, correzione delle
risposte presenze altrui, gestione dei ruoli.
Notifiche
Cosa riceve l'allenatore, notifica per notifica (il catalogo completo, con i canali di tutti, sta in notifiche.md):
| Notifica | L'allenatore la riceve? | Note |
|---|---|---|
| Promemoria a 24 e 3 ore prima di un evento (rimosso, DD-043) | no | Dal 29/09/2026 (m25, DD-039) giocatori_destinatari_evento() include solo i giocatori attivi: l'allenatore non può rispondere alle presenze né essere convocato, quindi il promemoria non gli chiederebbe nulla che possa fare (per esempio una cena di squadra). Prima gli arrivava sempre, convocato o no (m21). |
| Messaggio dello staff | sì | In-app ed email vanno a tutta la rosa attiva, allenatori compresi; la push ai suoi dispositivi iscritti, o solo a lui se il messaggio è per lui. |
| Sollecito presenze | no | L'allenatore non risponde alle presenze (DD-034). Può invece far partire il sollecito . |
| Turno palloni | no | I turni riguardano solo i giocatori. |
| Sondaggio pre-partita | no | Né la push né l'avviso in-app e per email (DD-038): il sondaggio non lo riguarda. |
| Compleanno (DD-047) | sì | Riceve l'avviso «Oggi è il compleanno di …» come tutta la squadra, e gli auguri nel giorno del proprio compleanno (la nascita è pubblica, DD-031). In-app, email e push come per i giocatori. |
| Notifiche smart (badge, serie, obiettivi, social) | no | Le mostra CelebrazioneBadge per il giocatore selezionato, letto da useIo(), che cerca l'id in useRosa(), da cui l'allenatore è escluso: per lui useIo() è null e useNotificheSmart() non fa nulla. Non ha statistiche da cui calcolarle. |
Le email arrivano solo se il suo slot ha un account collegato e un'email registrata e se non ha spento l'interruttore «Email»; la push solo sui dispositivi su cui ha attivato «Notifiche» dal proprio Profilo (l'interruttore è identico a quello dei giocatori). Il centro notifiche in-app funziona come per i giocatori, con i soli messaggi dello staff.
Esclusione dalla rosa
L'allenatore ha uno slot in giocatori_squadra (DD-034), quindi ogni lettura della "rosa di
gioco" lo esclude con inRosa() (attivo e tipo = giocatore) al posto del vecchio filtro
su attivo. Fanno eccezione la tab Rosa di Squadra, i compleanni del Calendario
(useAnagraficaRosa({ conAllenatori: true })) e i destinatari dei messaggi admin, che lo
includono.
| Livello | Dove si esclude l'allenatore |
|---|---|
| client | useRosa(), useAnagraficaRosa(), useTurniPalloni(), usePresenzeUltimoMeseTutti(), form convocati di /eventi, EventoCard, TurnoPalloni, VotazioneMvp, VotoSocial, useIo() e useGiocatoreCorrente() (quindi le notifiche smart) |
| identità | useGiocatoreInCampo() è null per l'allenatore: niente risposta presenze, voti, pagelle, cacche, promemoria palloni |
| server | destinatariSollecito(), promemoria-palloni.ts, apri-sondaggio.ts |
| database | policy presenze e cacche «la propria riga» solo per tipo = giocatore; evento_permette_voto() rifiuta votante o votato allenatore |
| admin | tab Squadra (conteggi, export CSI) e Profili (allenatori in un gruppo a parte, senza documenti né tesseramento) |
Il compleanno dell'allenatore resta visibile in Calendario (è un membro della squadra, non un giocatore).
Permessi (riepilogo)
| Azione | Giocatore | Allenatore | Admin |
|---|---|---|---|
| Modificare nome e cognome | no | sì, i propri | tutti |
| Dati personali e foto profilo | i propri | i propri (ridotti) | tutti (non i file) |
| Documento, certificato | i propri | — | lettura/download |
| Avviso certificati in Home | il proprio | no | tutta la rosa |
| Creare/modificare/eliminare eventi, convocati | no | sì | sì |
| Sollecitare le presenze | no | sì | sì |
| Promemoria palloni, notifica personalizzata | no | no | sì |
| Ricevere i promemoria automatici degli eventi (in-app, email, push) | sì | no (DD-039) | secondo il proprio slot |
| Ricevere i messaggi dello staff | sì | sì | secondo il proprio slot |
| Ricevere sollecito presenze, turno palloni, sondaggio cacche | sì | no | solo con uno slot giocatore in rosa |
| Ricevere le notifiche smart (badge, serie, obiettivi) | sì | no | solo con uno slot giocatore in rosa |
| Rispondere alle presenze, votare, essere votato | sì | no | sì (se giocatore) |
| Tab Stagione e Badge del profilo | sì | no | sì |
| Tab Obiettivi e Badge di Squadra | sì | no | sì |
| Badge e classifiche/dati sulle cacche | sì | no | sì |
Dashboard /admin |
no | no | sì |
Le notifiche sono legate allo slot (giocatori_squadra), non al ruolo di admin: chi è admin le riceve
secondo il proprio slot, come giocatore o come allenatore, e non ne riceve se non ha uno slot.
Implementazione
- Migration M20 aggiunge
allenatoreall'enumapp_role: sta da sola perché Postgres non lascia usare un valore di enum nella transazione che lo crea. - Migration M21: colonna
giocatori_squadra.tipo;numeronullabile solo per gli allenatori (vincologiocatori_squadra_numero_giocatori); triggerenforce_giocatori_squadra_updatecontipobloccato e nome/cognome liberi solo sullo slot del proprio allenatore; policy «L'allenatore aggiorna il proprio slot»; triggersincronizza_ruolo_allenatoreche aggiunge o toglie la rigaallenatoreinuser_rolesal collegamento, scollegamento, disattivazione o cambio di tipo; policyeventi_appadmin o allenatore; presenze, cacche e voti chiusi all'allenatore. - Client: nell'app
numeroresta unnumber(0 per l'allenatore, NULL a database). I permessi (eventi, sollecito) leggonouser_rolesconusePuoGestireEventi(); cosa si vede dipende dal tipo del proprio slot (useSonoAllenatore()), che è immediato. - Admin: «Aggiungi giocatore o allenatore» con il campo Tipo; per l'allenatore il form non chiede numero e ruolo. Il tipo si sceglie solo alla creazione.
Scelte confermate
- Non riceve i promemoria degli eventi (DD-039; fino alla m24 li riceveva sempre, DD-034). Riceve i messaggi dello staff.
- Sollecita le presenze: sì. Promemoria palloni: no.
- Badge e cacche: mai visibili all'allenatore, né classifiche né sondaggio.
- In Squadra: nessuna sezione Staff; compare in Rosa come gli altri, con «Allenatore» al posto del ruolo.
- Vede le risposte presenze e le pagelle dei giocatori: sì, la lettura è già aperta a tutti gli autenticati.