diff --git a/docs/DESIGN_DECISIONS.md b/docs/DESIGN_DECISIONS.md index a0579a1..57b89f2 100644 --- a/docs/DESIGN_DECISIONS.md +++ b/docs/DESIGN_DECISIONS.md @@ -16,45 +16,46 @@ Serve a rispondere a domande del tipo: **Accettate** -| ID | Titolo | -| --------------------------------------------------------------------------------- | ------------------------------------- | -| [DD-001](#dd-001--crapp-deve-restare-indipendente-da-lovable) | Indipendenza da Lovable | -| [DD-002](#dd-002--sviluppo-document-first) | Sviluppo document-first | -| [DD-004](#dd-004--ogni-versione-aggiunge-non-riscrive) | Ogni versione aggiunge, non riscrive | -| [DD-005](#dd-005--mobile-first-pochi-click-pochi-schermi) | Mobile-first | -| [DD-006](#dd-006--intelligenza-artificiale-solo-se-porta-beneficio-reale) | AI solo se utile | -| [DD-007](#dd-007--badge-calcolati-dallapp-non-salvati-nel-database) | Badge calcolati, non in DB | -| [DD-008](#dd-008--gamification-equa-tra-ruoli) | Gamification equa tra ruoli | -| [DD-009](#dd-009--tesseramento-csi-manuale-integrazione-api-in-una-fase-successiva) | CSI manuale, poi integrazione API | -| [DD-010](#dd-010--profilo-giocatore-niente-storico-certificati) | Niente storico certificati | -| [DD-011](#dd-011--autenticazione-reale-prima-del-profilo-amministrativo-completo) | Auth reale prima del profilo | -| [DD-012](#dd-012--rimandare-la-migrazione-degli-id-giocatore) | Rimandare la migrazione ID | -| [DD-013](#dd-013--portabilità-lapp-non-deve-dipendere-da-servizi-esclusivi) | Portabilità dello stack | -| [DD-015](#dd-015--rosa-anagrafica-da-codice-hardcoded-a-database) | Rosa da hardcoded a DB | -| [DD-016](#dd-016--schema-dati-profilo-giocatore-f0) | Schema dati Profilo Giocatore | -| [DD-017](#dd-017--lamministratore-può-compilare-i-dati-al-posto-del-giocatore) | L'admin scrive al posto del giocatore | -| [DD-018](#dd-018--collegamento-automatico-giocatoreaccount-per-email) | Collegamento automatico per email | -| [DD-019](#dd-019--il-branch-dei-commit-lo-decide-lutente) | Il branch lo decide l'utente | -| [DD-020](#dd-020--una-funzione-modificata-senza-test-non-è-finita) | Test obbligatori e verdi | -| [DD-021](#dd-021--molle-interrompibili-al-posto-delle-animazioni-a-durata-fissa) | Molle interrompibili con motion | -| [DD-022](#dd-022--lapp-è-solo-chiara) | App solo chiara | -| [DD-023](#dd-023--ogni-scrittura-è-limitata-a-chi-la-fa) | Scritture limitate per ruolo | -| [DD-024](#dd-024--le-route-che-avvisano-la-squadra-chiedono-le-credenziali) | Route di notifica autenticate | -| [DD-025](#dd-025--il-promemoria-palloni-lo-manda-ladmin-per-un-evento) | Promemoria palloni manuale | -| [DD-026](#dd-026--il-testo-della-notifica-viaggia-dentro-la-push) | Payload push cifrato | -| [DD-027](#dd-027--chi-vota-deve-essere-convocato-non-solo-autenticato-come-sé-stesso) | Voto limitato ai convocati | -| [DD-028](#dd-028--soglia-minima-di-campione-per-media-voto-e-mvp-in-home) | Soglia minima Media voto e MVP | -| [DD-029](#dd-029--cancellare-un-evento-pulisce-a-cascata-i-dati-collegati) | Pulizia a cascata evento cancellato | -| [DD-030](#dd-030--centro-notifiche-in-app-storico-separato-dalla-push-letto-solo-con-rls) | Centro notifiche in-app | +| ID | Titolo | +| ------------------------------------------------------------------------------------------------ | ------------------------------------- | +| [DD-001](#dd-001--crapp-deve-restare-indipendente-da-lovable) | Indipendenza da Lovable | +| [DD-002](#dd-002--sviluppo-document-first) | Sviluppo document-first | +| [DD-004](#dd-004--ogni-versione-aggiunge-non-riscrive) | Ogni versione aggiunge, non riscrive | +| [DD-005](#dd-005--mobile-first-pochi-click-pochi-schermi) | Mobile-first | +| [DD-006](#dd-006--intelligenza-artificiale-solo-se-porta-beneficio-reale) | AI solo se utile | +| [DD-007](#dd-007--badge-calcolati-dallapp-non-salvati-nel-database) | Badge calcolati, non in DB | +| [DD-008](#dd-008--gamification-equa-tra-ruoli) | Gamification equa tra ruoli | +| [DD-009](#dd-009--tesseramento-csi-manuale-integrazione-api-in-una-fase-successiva) | CSI manuale, poi integrazione API | +| [DD-010](#dd-010--profilo-giocatore-niente-storico-certificati) | Niente storico certificati | +| [DD-011](#dd-011--autenticazione-reale-prima-del-profilo-amministrativo-completo) | Auth reale prima del profilo | +| [DD-012](#dd-012--rimandare-la-migrazione-degli-id-giocatore) | Rimandare la migrazione ID | +| [DD-013](#dd-013--portabilità-lapp-non-deve-dipendere-da-servizi-esclusivi) | Portabilità dello stack | +| [DD-015](#dd-015--rosa-anagrafica-da-codice-hardcoded-a-database) | Rosa da hardcoded a DB | +| [DD-016](#dd-016--schema-dati-profilo-giocatore-f0) | Schema dati Profilo Giocatore | +| [DD-017](#dd-017--lamministratore-può-compilare-i-dati-al-posto-del-giocatore) | L'admin scrive al posto del giocatore | +| [DD-018](#dd-018--collegamento-automatico-giocatoreaccount-per-email) | Collegamento automatico per email | +| [DD-019](#dd-019--il-branch-dei-commit-lo-decide-lutente) | Il branch lo decide l'utente | +| [DD-020](#dd-020--una-funzione-modificata-senza-test-non-è-finita) | Test obbligatori e verdi | +| [DD-021](#dd-021--molle-interrompibili-al-posto-delle-animazioni-a-durata-fissa) | Molle interrompibili con motion | +| [DD-022](#dd-022--lapp-è-solo-chiara) | App solo chiara | +| [DD-023](#dd-023--ogni-scrittura-è-limitata-a-chi-la-fa) | Scritture limitate per ruolo | +| [DD-024](#dd-024--le-route-che-avvisano-la-squadra-chiedono-le-credenziali) | Route di notifica autenticate | +| [DD-025](#dd-025--il-promemoria-palloni-lo-manda-ladmin-per-un-evento) | Promemoria palloni manuale | +| [DD-026](#dd-026--il-testo-della-notifica-viaggia-dentro-la-push) | Payload push cifrato | +| [DD-027](#dd-027--chi-vota-deve-essere-convocato-non-solo-autenticato-come-sé-stesso) | Voto limitato ai convocati | +| [DD-028](#dd-028--soglia-minima-di-campione-per-media-voto-e-mvp-in-home) | Soglia minima Media voto e MVP | +| [DD-029](#dd-029--cancellare-un-evento-pulisce-a-cascata-i-dati-collegati) | Pulizia a cascata evento cancellato | +| [DD-030](#dd-030--centro-notifiche-in-app-storico-separato-dalla-push-letto-solo-con-rls) | Centro notifiche in-app | | [DD-031](#dd-031--data-di-nascita-pubblica-una-colonna-sincronizzata-non-una-seconda-rls-aperta) | Nascita pubblica sincronizzata | -| [DD-032](#dd-032--la-stagione-csi-si-ricava-dalle-date-delle-gare) | Stagione CSI dalle date delle gare | -| [DD-033](#dd-033--gestione-eventi-solo-calendario-giorno-fissato-dal-tocco) | Gestione eventi solo da calendario | +| [DD-032](#dd-032--la-stagione-csi-si-ricava-dalle-date-delle-gare) | Stagione CSI dalle date delle gare | +| [DD-033](#dd-033--gestione-eventi-solo-calendario-giorno-fissato-dal-tocco) | Gestione eventi solo da calendario | **In valutazione** -| ID | Titolo | -| ---------------------------------------------------------------- | --------------------- | -| [DD-014](#dd-014--convergenza-schema-database-eventi-e-presenze) | Convergenza schema DB | +| ID | Titolo | +| ----------------------------------------------------------------------------------------- | --------------------- | +| [DD-014](#dd-014--convergenza-schema-database-eventi-e-presenze) | Convergenza schema DB | +| [DD-034](#dd-034--lallenatore-è-uno-slot-della-squadra-con-tipo-diverso-non-un-giocatore) | Ruolo allenatore | **Sostituite** @@ -1200,7 +1201,7 @@ modo per un giocatore di toglierle di torno per sempre. - Notificare anche sulla sola creazione di un evento, non solo sull'avvicinarsi della data → scartata su richiesta esplicita: conta quando l'evento sta per succedere, non il momento in cui è stato messo in calendario. La prima versione aveva un trigger `AFTER INSERT ON - eventi_app` per questo, rimosso prima del rilascio. +eventi_app` per questo, rimosso prima del rilascio. - Una route API dedicata per leggere/segnare come lette (come le route push esistenti) → scartata: qui non serve la service role (niente da nascondere al giocatore stesso), quindi la RLS basta ed evita di duplicare la logica di lettura già scritta lato client per gli @@ -1242,7 +1243,7 @@ In "Squadra" la data di nascita mostrava **"Invalid Date"** per chi l'aveva inse solo dal proprio Profilo. Causa: due fonti mai collegate. I 17 giocatori del seed storico hanno la nascita in `nascitaPerId`, una mappa statica pubblica bundlata nel client (`src/lib/crapp-data.ts`) — il commento sulla riga la descriveva esplicitamente come -stopgap: *"`giocatori_squadra` non ha ancora questa colonna (DD-015 follow-up)"*. Un +stopgap: _"`giocatori_squadra` non ha ancora questa colonna (DD-015 follow-up)"_. Un giocatore aggiunto dopo la migrazione DD-015 inserisce invece la nascita dal form Profilo, che scrive su `profili_giocatore.data_nascita` — tabella con RLS "solo il proprio profilo o admin" (M2), mai letta da `useRosa()`/`useAnagraficaRosa()` (`src/lib/rosa.ts`), e comunque @@ -1309,7 +1310,7 @@ per questa colonna. **Aggiornamento (15 settembre 2026, stesso giorno)** — dopo aver applicato M18 in produzione (`supabase db push`), la nascita in Squadra compariva solo per i 17 giocatori storici, non per chi aveva già compilato il proprio profilo prima della migration: il trigger di sync -copre solo le scritture *future* su `profili_giocatore`, non retroattivamente, e M18 +copre solo le scritture _future_ su `profili_giocatore`, non retroattivamente, e M18 backfillava a mano solo il seed storico. Migration `m19_backfill_nascita_da_profili_esistenti` allinea una tantum `giocatori_squadra.nascita` a `profili_giocatore.data_nascita` per tutti i profili già esistenti, con la stessa disattivazione temporanea del trigger di sicurezza usata @@ -1399,3 +1400,49 @@ toccando «Cambia», per spostare un evento in un altro giorno. **Riesame** Se gli eventi crescono tanto da rendere scomodo lo scorrere dei mesi, valutare una ricerca per titolo invece di reintrodurre la lista completa. + +### DD-034 — L'allenatore è uno slot della squadra con tipo diverso, non un giocatore + +**Data:** 24 settembre 2026 +**Stato:** In valutazione + +**Contesto** +Serve un account per l'allenatore: deve gestire gli eventi (oggi solo admin, `m11`) ma non è +un giocatore. Non ha statistiche, badge né stagione, non vota e non viene votato. L'admin +vuole registrarlo come i giocatori, inserendo la sua email Gmail. Specifica completa in +[modules/allenatore.md](modules/allenatore.md). + +**Decisione** +L'allenatore è una riga di `giocatori_squadra` con una nuova colonna `tipo = 'allenatore'` +(default `'giocatore'`). Così riusa senza cambiarli il collegamento per email (DD-018), +`profili_giocatore` per i dati personali, il bucket avatar e il compleanno sincronizzato +(DD-031). Il permesso di gestire gli eventi arriva da un nuovo valore `allenatore` di +`app_role` in `user_roles` (DD-011), scritto da una funzione `SECURITY DEFINER` quando si +collega uno slot di tipo allenatore: è quindi l'admin a concederlo, registrando lo slot. +"Rosa" diventa `attivo e tipo = 'giocatore'` ovunque. + +**Alternative scartate** + +- Una tabella `staff` separata → isola l'allenatore da voti e rosa senza toccare i filtri, ma + duplica collegamento per email, profilo, avatar e form admin. Resta l'alternativa se i + filtri sulla rosa si rivelano troppi o fragili. +- Registrare l'allenatore come admin → gli darebbe dati personali e documenti di tutta la + squadra (DD-017), molto più del necessario. +- Distinguere l'allenatore dal campo `ruolo` (ruolo in campo) → mescola due concetti e il + campo è testo libero. + +**Conseguenze** + +- Ogni lettura della rosa (client, server, SQL di voto e promemoria) va filtrata per `tipo`: + un punto dimenticato rende l'allenatore votabile o lo conta tra i convocati. L'elenco sta + nella specifica e va coperto dai test di `permessi.test.ts`. +- Il trigger sugli slot cambia: `tipo` lo scrive solo l'admin; nome e cognome li scrive anche + l'allenatore sul proprio slot. +- L'allenatore non vede le tab Stagione e Badge del Profilo, né Obiettivi e Badge di Squadra. +- In Squadra compare nella tab Rosa con «Allenatore» al posto del ruolo, ricavato da `tipo`; + riceve i promemoria degli eventi e può sollecitare le presenze, non il turno palloni. +- Non vede badge né classifiche o sondaggi sulle cacche, in nessuna schermata. + +**Riesame** +Se arriva un secondo tipo di staff (dirigente, segreteria) o se i filtri sulla rosa diventano +fonte di bug, passare alla tabella `staff` separata. diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index bb70edf..0463ad4 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -44,6 +44,8 @@ Tutto quello che è in `main`, rilasciato in versione 0.9.0 (vedi `CHANGELOG.md` - [ ] Database esercizi - [ ] AI Allenamenti - [ ] Archivio allenamenti +- [ ] Ruolo allenatore — gestisce gli eventi, profilo ridotto senza stagione e badge + ([specifica](modules/allenatore.md), DD-034) ## Idee future diff --git a/docs/modules/allenatore.md b/docs/modules/allenatore.md new file mode 100644 index 0000000..1b0f536 --- /dev/null +++ b/docs/modules/allenatore.md @@ -0,0 +1,191 @@ +# Modulo — Ruolo Allenatore + +**Stato:** da implementare (specifica) +**Decisione:** [DD-034](../DESIGN_DECISIONS.md#dd-034--lallenatore-è-uno-slot-della-squadra-con-tipo-diverso-non-un-giocatore) +**File coinvolti (previsti):** `src/lib/ruoli.ts`, `src/lib/auth-route.server.ts`, +`src/routes/profilo.tsx`, `src/routes/eventi.tsx`, `src/routes/admin.tsx`, +`src/lib/profili-core.ts`, i punti che leggono la rosa (vedi [Esclusione dalla rosa](#esclusione-dalla-rosa)) + +## 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ù: + +1. 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. +2. 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. +3. 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 (in `TAB_PROFILO` oggi 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, foto +tessera, tesseramento CSI. + +### Completamento profilo + +Per l'allenatore il completamento conta solo i dati personali della tabella sopra (100%). +Il widget in Home segue la stessa regola: sparisce quando quei campi sono compilati. + +## 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, e un link diretto a una delle due apre Rosa. + +| 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 💩» | +| `/partita/$id` | la sezione «Badge votati dai compagni» e il sondaggio cacche (`SondaggioCacche`) | +| `/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. Nel database la policy di scrittura su `eventi_app` passa da +"solo admin" a "admin o allenatore" (oggi `m11_scritture_per_ruolo`); la cancellazione a +cascata (DD-029) resta invariata. + +Il link a `/eventi` compare dove oggi compare per l'admin. + +Può anche **sollecitare le presenze** di un evento, come l'admin: la route +`sollecita-presenze.ts` accetta admin o allenatore (oggi `richiediAdmin()`), e il sollecito +arriva solo ai giocatori che non hanno risposto, mai all'allenatore stesso. + +**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 + +L'allenatore riceve i promemoria degli eventi (24h e 3h prima, push e centro notifiche +in-app) come i giocatori, anche se non è convocato, e può attivare le push dal proprio +Profilo. Non riceve il sollecito presenze né il turno palloni, che riguardano chi gioca. + +## Esclusione dalla rosa + +L'allenatore ha uno slot in `giocatori_squadra` (DD-034), quindi ogni lettura della "rosa di +gioco" deve escluderlo: oggi il filtro è `attivo`, diventa `attivo e tipo = giocatore`. Fanno +eccezione la tab Rosa di Squadra, i compleanni del Calendario e i destinatari dei promemoria +evento, che lo includono. Punti da coprire, da verificare uno per uno in implementazione: + +- client: `useRosa()`, `useGiocatoriSquadra()` (dove usata come rosa), `useAnagraficaRosa()` + — Squadra (Stats, Obiettivi, Badge), Presenze, Palloni, Pagelle, MVP, Badge, Classifica, + Scout, form convocati di `/eventi`; +- server e condivisi: `leggiGiocatoriSquadra()`, `convocatiEvento()` (`eventi.ts`, riceve la + rosa già filtrata), route API che notificano "tutta la rosa"; +- database: `evento_permette_voto()` (M13), che con `convocati` vuoto intende "tutta la rosa + attiva"; i cron dei promemoria evento (M17) invece aggiungono sempre l'allenatore ai + destinatari, convocato o no; +- admin: tab Profili (conteggi di completamento e tesseramento), export CSI. + +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, foto tessera | i propri | — | lettura/download | +| Creare/modificare/eliminare eventi, convocati | no | sì | sì | +| Sollecitare le presenze | no | sì | sì | +| Promemoria palloni, notifica personalizzata | no | no | sì | +| 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ì | + +## Cosa implementare + +1. **Migration** (nuova, non si riscrivono le esistenti): + - `giocatori_squadra.tipo` (`giocatore` | `allenatore`, default `giocatore`, non nullo); + - valore `allenatore` nell'enum `app_role`, assegnato in `user_roles` da una funzione + `SECURITY DEFINER` al momento del collegamento di uno slot con `tipo = allenatore` + (i permessi restano letti da `user_roles`, DD-011); + - trigger `enforce_giocatori_squadra_update`: `tipo` scrivibile solo dall'admin; `nome` e + `cognome` scrivibili dall'allenatore sul proprio slot; + - policy di scrittura `eventi_app`: admin o allenatore; + - `evento_permette_voto()`: escludere `tipo = allenatore`; + - cron promemoria evento: includere sempre gli allenatori attivi tra i destinatari. +2. **`src/lib/ruoli.ts`**: `useIsAllenatore()` e `usePuoGestireEventi()` (admin o allenatore), + stessa lettura di `user_roles` e stessa cache. +3. **`/eventi`**: gate `usePuoGestireEventi()` al posto di `useIsAdmin()`, anche per il link di accesso. + Il bottone del sollecito presenze usa lo stesso gate; lato server `sollecita-presenze.ts` + passa da `richiediAdmin()` a un controllo "admin o allenatore" in `auth-route.server.ts`. +4. **`/profilo`**: tab e campi in base al tipo; nome e cognome modificabili per l'allenatore. +5. **`/squadra`**: l'allenatore compare in Rosa con la dicitura «Allenatore», senza numero né + statistiche; da allenatore non si vedono le tab Obiettivi e Badge, né il criterio e la riga + delle cacche. + **`/partita/$id`**: niente sezione badge né sondaggio cacche per l'allenatore. +6. **`profili-core.ts`**: completamento dedicato all'allenatore (solo dati personali). +7. **`/admin`**: scelta del tipo in "Aggiungi"; allenatori mostrati a parte, fuori dai conteggi + di completamento e tesseramento; nessun export CSI per loro. +8. **Filtro rosa** in tutti i punti elencati sopra. +9. **Test**: unit sul completamento e sul filtro rosa; integration in + `test/integration/permessi.test.ts` (l'allenatore scrive `eventi_app`, non vota, non cambia + il proprio `tipo`, non scrive slot altrui). +10. **Documentazione** alla consegna: `DATABASE.md` (colonna, enum, tabella permessi), + `profilo-giocatore.md`, `squadra.md`, `calendario.md`, `CHANGELOG.md`, `ROADMAP.md`, DD-034 → Accettata. + +## Scelte confermate + +- Riceve i promemoria degli eventi: sì. +- 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.