2026-08-30 16:26:14 +02:00
# Modulo — Profilo Giocatore
2026-08-07 15:36:02 +02:00
2026-09-09 13:31:39 +02:00
**Stato:** implementato
**File principali:** `src/lib/profili.ts` , `src/lib/profili-core.ts` , `src/routes/profilo.tsx` ,
`src/routes/admin.tsx`
---
2026-08-07 15:36:02 +02:00
## Obiettivo
Il modulo "Profilo Giocatore" raccoglie tutte le informazioni personali, amministrative e documentali di ciascun membro della squadra.
L'obiettivo è centralizzare in un'unica schermata tutti i dati necessari sia al giocatore sia agli amministratori, eliminando la gestione tramite chat, documenti cartacei e fogli Excel.
2026-08-30 16:26:14 +02:00
## Utenti
2026-08-07 15:36:02 +02:00
2026-09-24 14:54:35 +02:00
L'allenatore ha un profilo ridotto (solo Docs con i dati personali essenziali e Opzioni):
la specifica sta in [allenatore.md ](allenatore.md ).
2026-08-30 16:26:14 +02:00
### Giocatore
2026-08-07 15:36:02 +02:00
Può:
- visualizzare il proprio profilo
- modificare i propri dati personali
- aggiornare il certificato medico
- aggiornare i documenti
- caricare le immagini richieste
2026-08-30 16:26:14 +02:00
### Amministratore
2026-08-07 15:36:02 +02:00
Può:
- visualizzare il profilo di tutti i giocatori
- scaricare documenti e certificati
- esportare i dati necessari al tesseramento CSI
- verificare lo stato di completamento dei profili
2026-09-01 11:29:41 +02:00
- modificare i dati squadra di qualsiasi giocatore (nome, cognome, numero, ruolo, email)
2026-08-30 18:15:16 +02:00
- compilare e correggere i dati personali e del documento al posto di un giocatore (DD-017)
- scollegare un account da un profilo, liberando lo slot
2026-09-24 14:54:35 +02:00
- aggiungere un nuovo giocatore alla rosa (id, nome, cognome, numero, ruolo, email opzionale),
oppure un allenatore (tipo «Allenatore»: niente numero né ruolo, DD-034)
2026-09-01 11:29:41 +02:00
- disattivare un giocatore che ha lasciato la squadra, e riattivarlo in caso di errore: la
riga non viene eliminata, così presenze, voti, pagelle e badge della stagione restano
agganciati al suo id
2026-08-30 18:15:16 +02:00
Non può caricare o sostituire i file altrui: documento, certificato e foto restano
responsabilità del giocatore che li fornisce.
2026-08-07 15:36:02 +02:00
2026-08-30 16:26:14 +02:00
## Flusso utente
2026-08-07 15:36:02 +02:00
2026-08-30 16:26:14 +02:00
### Primo accesso
2026-08-07 15:36:02 +02:00
2026-09-01 13:38:56 +02:00
1. Login tramite Google oppure Email. _Implementato con il solo Google: la squadra ha tutti
2026-08-30 17:58:24 +02:00
un account Google, e un secondo metodo è additivo (un bottone in più sulla stessa
2026-09-01 13:38:56 +02:00
schermata) il giorno che serve._
2026-09-01 10:46:38 +02:00
2. Collegamento automatico al proprio giocatore, confrontando l'email dell'account Google
con l'email registrata in `giocatori_squadra` (DD-018). Nessuna scelta manuale: se
l'email non corrisponde a nessun profilo, l'accesso si ferma con un messaggio che invita
a contattare un amministratore.
2026-08-07 15:36:02 +02:00
3. Accesso alla Home.
Se il profilo non è completo compare automaticamente un widget di completamento.
2026-08-30 16:26:14 +02:00
## Home
2026-08-07 15:36:02 +02:00
2026-09-24 15:43:26 +02:00
Il giocatore visualizza un widget dedicato e, quando serve, l'avviso sul certificato medico.
2026-08-07 15:36:02 +02:00
2026-08-30 16:26:14 +02:00
### Completa il tuo profilo
2026-08-07 15:36:02 +02:00
2026-09-01 13:38:56 +02:00
Viene mostrata una barra di avanzamento (esempio: _Profilo completato — 85%_ ), composta dalle seguenti sezioni.
2026-08-07 15:36:02 +02:00
- Dati personali
- Documento di identità
- Certificato medico
- Foto tessera
Quando tutte le sezioni sono complete il widget scompare automaticamente.
2026-09-05 23:37:41 +02:00
Il tap apre Profilo sulla sottosezione **Documenti** (`/profilo?tab=documenti` ), non
2026-09-05 22:38:48 +02:00
sulla tab Stagione.
2026-09-24 15:43:26 +02:00
### Avviso certificati
2026-10-01 14:21:25 +02:00
**Stato:** implementato (DD-035, soglia del giocatore DD-041).
2026-09-24 15:43:26 +02:00
Un avviso in Home segnala i certificati medici in scadenza o scaduti, così nessuno se ne
accorge quando il giocatore è già fuori regola. Si calcola al volo dalla data di scadenza
già salvata: niente tabella, niente migration, niente push.
#### Chi lo vede
2026-10-01 14:21:25 +02:00
| Utente | Cosa vede | Al tocco |
| --------------------------- | ------------------------------------------------------------------------------ | ---------------------------------------- |
| Admin | l'avviso **dello staff** : i nomi di tutti i giocatori coinvolti | niente, non è cliccabile |
| Giocatore interessato | l'avviso **personale** : solo il proprio certificato | apre `/profilo?tab=documenti` |
| Admin che è anche giocatore | **entrambi** : lo staff (senza il suo nome) e il proprio personale, a 30 giorni | personale: apre `/profilo?tab=documenti` |
| Altri giocatori | niente | — |
| Allenatore | niente: non vede i certificati altrui e non ne ha uno (DD-034) | — |
2026-09-24 15:43:26 +02:00
L'avviso dello staff non è cliccabile, come quello dei palloni: l'admin non può caricare il
certificato al posto del giocatore (DD-017), quindi può solo sollecitarlo, e il giocatore
riceve già il proprio avviso. Quello personale porta invece dove si carica il certificato
nuovo, come il widget «Completa il tuo profilo».
I certificati sono dati sanitari: fuori da `/admin` li legge solo il titolare (DD-016).
Nessuna policy cambia, perché `useProfili()` restituisce già tutti i profili a un admin e il
solo proprio a un giocatore.
#### Quando compare
2026-10-01 14:21:25 +02:00
`giorni` è la differenza in giorni di calendario tra la scadenza e oggi (ora locale). La
soglia del giallo dipende da chi guarda (DD-041): il giocatore è avvisato un mese prima dello
staff.
2026-09-24 15:43:26 +02:00
2026-10-01 14:21:25 +02:00
| Chi guarda | Soglia |
| ---------- | ------------------------------------------ |
| Giocatore | `GIORNI_AVVISO_CERTIFICATO_GIOCATORE = 30` |
| Admin | `GIORNI_AVVISO_CERTIFICATO = 7` |
| Condizione | Stato | Avviso |
| --------------------- | ----------- | ------------------ |
| `giorni > soglia` | valido | nessuno |
| `0 ≤ giorni ≤ soglia` | in scadenza | giallo (`warning` ) |
| `giorni < 0` | scaduto | nero (`primary` ) |
| data o file mancanti | mancante | nessuno |
Esempio: scadenza il 5 ottobre 2026. Dal 5 settembre l'avviso giallo compare solo al
giocatore; dal 28 settembre anche agli admin; dal 6 ottobre è nero per entrambi.
2026-09-24 15:43:26 +02:00
- Il giorno della scadenza il certificato vale ancora, coerente con `statoScadenza()` : il
giocatore compare nel giallo con «scade oggi» e passa al nero dal giorno dopo.
- L'avviso nero resta finché il giocatore non aggiorna la data: non c'è un limite di tempo.
- Il certificato **mancante** non genera avviso: è un problema diverso, già visibile nella
tab Profili di `/admin` e nel widget di completamento del giocatore.
- Sono esclusi i giocatori disattivati e gli allenatori: conta solo la rosa (`inRosa()` ,
cioè `attivo` e `tipo = 'giocatore'` ).
#### Testi
| Avviso | Titolo (staff / personale) | Riga |
| ----------------- | -------------------------- | ------------------------------------------------------------------------ |
| Giallo, staff | «Certificati in scadenza» | «Mario Rossi — scade tra 5 giorni», «… — scade domani», «… — scade oggi» |
| Nero, staff | «Certificati scaduti» | «Mario Rossi — scaduto il 12/09/2026» |
| Giallo, personale | «Certificato in scadenza» | «Il tuo certificato medico scade tra 5 giorni» / «domani» / «oggi» |
| Nero, personale | «Certificato scaduto» | «Il tuo certificato medico è scaduto il 12/09/2026: caricane uno nuovo» |
2026-10-01 14:21:25 +02:00
Il numero di giorni scende da solo ogni giorno (30… 7, 6, 5… domani, oggi): l'avviso non
2026-09-24 15:43:26 +02:00
conserva niente, rilegge la data a ogni apertura della Home.
#### Più giocatori
- Più giocatori nello stesso stato stanno in un **unico avviso** , una riga ciascuno, e
compaiono **tutti** : nessun limite al numero di nomi, anche a inizio stagione quando ne
scadono molti insieme.
- Se ci sono sia certificati in scadenza sia scaduti compaiono **due avvisi** : prima quello
nero, poi quello giallo.
- Ordine delle righe: dalla scadenza più vicina nel giallo, dal certificato scaduto da più
tempo nel nero; a parità di data, alfabetico per cognome e poi per nome. L'ordine è
stabile, quindi l'elenco non si rimescola tra un'apertura e l'altra.
#### Aspetto e posizione
- Stessa forma del banner palloni (`PromemoriaPalloni` ): card arrotondata a tutta larghezza
con icona e titolo in `font-display` maiuscolo, righe in testo piccolo sotto.
- Giallo: sfondo `bg-warning` , testo `text-warning-foreground` . Nero: sfondo `bg-primary` ,
testo `text-primary-foreground` . L'app è solo chiara (DD-022), quindi il nero non rischia
di confondersi con lo sfondo.
- In Home sta subito **sotto il banner palloni** e sopra «Completa il tuo profilo»: prima
ciò che scade oggi, poi ciò che manca.
#### Rinnovo
Il giocatore rinnova dal proprio profilo, sottosezione Documenti: carica il file nuovo e
aggiorna la data. Il salvataggio aggiorna la cache dei profili (`setQueryData` ), quindi il
suo avviso personale sparisce subito. Nell'avviso dello staff il nome sparisce alla lettura
successiva dei profili da parte dell'admin (cache di 30 minuti, `useProfili()` ), senza
nessuna azione da parte sua. Quando non resta nessuno, l'avviso non compare più.
Basta aggiornare la data: l'avviso guarda solo quella (e la presenza di un file). Che il
file caricato sia davvero quello nuovo resta un controllo dell'admin, come oggi. Anche l'admin
può correggere la data dalla scheda del giocatore (DD-017, non il file): l'avviso segue la
data, chiunque l'abbia scritta.
#### Caricamento
Finché ruoli e profili non sono arrivati, l'avviso non compare: così un admin che è anche
giocatore non vede per un attimo l'avviso personale prima di quello dello staff. Se la
lettura dei profili fallisce l'avviso semplicemente non compare, senza messaggio d'errore:
la Home non deve rompersi per un dato accessorio.
#### Implementazione
2026-10-01 14:21:25 +02:00
| Pezzo | Ruolo |
| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GIORNI_AVVISO_CERTIFICATO` (`profili-core.ts` ) | la soglia dello staff, 7 |
| `GIORNI_AVVISO_CERTIFICATO_GIOCATORE` | la soglia del giocatore, 30 (DD-041) |
| `giorniAllaScadenza(scadenza, oggi)` | differenza in giorni di calendario tra due date `AAAA-MM-GG` , negativa se scaduto |
| `avvisiCertificati(rosa, profili, oggi, soglia)` | funzione pura (`soglia` di default 7): restituisce `{ scaduti, inScadenza }` , ognuno una lista ordinata di `{ giocatoreId, nome, cognome, scadenza, giorni }` |
| `avvisiCertificatiUtente(rosa, profili, oggi, utente)` | funzione pura: `{ personale, staff }` per chi guarda; l'admin giocatore ha entrambi, senza il suo nome nello staff (DD-041) |
| `testoScadenza(giorni)` | «scade oggi» / «scade domani» / «scade tra N giorni» |
| `src/components/crapp/AvvisoCertificati.tsx` | legge `useGiocatoriSquadra()` , `useProfili()` , `useIsAdmin()` e l'utente corrente; sceglie avviso dello staff o personale e disegna le card |
| `src/routes/index.tsx` | monta `<AvvisoCertificati />` subito dopo `<PromemoriaPalloni />` |
2026-09-24 15:43:26 +02:00
- "Oggi" viene da `oggiISO()` (`palloni-core.ts` ), in ora locale. Non da
`new Date().toISOString()` , che è in UTC e tra mezzanotte e le 2 darebbe il giorno prima.
- Nessuna query nuova: `useProfili()` ha la stessa chiave di cache usata da Profilo e
`/admin` , quindi al massimo una lettura di `profili_giocatore` per sessione (vedi
[EFFICIENZA_CLOUD.md ](../EFFICIENZA_CLOUD.md )). Per l'allenatore il componente non legge
i profili.
2026-10-01 14:21:25 +02:00
- Test in `test/unit/profili-core.test.ts` : avvisi per utente (admin giocatore, admin puro, giocatore semplice), soglia dello staff (8 giorni no, 7 sì, 0 sì, − 1 scaduto) e del giocatore (31 no, 30 sì),
2026-09-24 15:43:26 +02:00
certificato senza file o senza data escluso, giocatore disattivato e allenatore esclusi,
ordinamento (per data, poi alfabetico), testi al singolare e al plurale, cambio di mese e
di anno nel calcolo dei giorni.
2026-08-30 16:26:14 +02:00
## Profilo
2026-08-07 15:36:02 +02:00
2026-09-04 23:14:55 +02:00
Il profilo viene suddiviso in sette aree.
2026-08-07 15:36:02 +02:00
2026-08-30 16:26:14 +02:00
### Dati Giocatore
2026-08-07 15:36:02 +02:00
2026-08-30 16:26:14 +02:00
**Dati squadra** — solo lettura, gestiti esclusivamente dagli amministratori.
2026-08-07 15:36:02 +02:00
- Nome
- Cognome
- Numero di maglia
- Ruolo
2026-08-30 16:26:14 +02:00
**Dati personali** — modificabili dal giocatore.
2026-08-07 15:36:02 +02:00
2026-09-15 12:18:01 +02:00
- Data di nascita — oltre a `profili_giocatore.data_nascita` , un trigger la sincronizza in
`giocatori_squadra.nascita` (DD-031): a differenza degli altri campi di questa sezione,
visibile a **tutta la squadra** , non solo al giocatore stesso o all'admin (alimenta
Squadra e i compleanni nel Calendario, vedi `squadra.md` ). Cancellare il profilo azzera
anche quel valore pubblico.
2026-08-07 15:36:02 +02:00
- Luogo di nascita
- Indirizzo di residenza
- Telefono
- Email
2026-08-30 16:26:14 +02:00
### Documento di identità
2026-08-07 15:36:02 +02:00
Campi.
- Tipo documento
- Numero documento
- Rilasciato da
- Data emissione
- Data scadenza
Upload.
- Foto fronte
- Foto retro
2026-08-30 16:26:14 +02:00
### Certificato medico
2026-08-07 15:36:02 +02:00
Campi.
- Data di scadenza
Upload.
- Certificato medico
Il giocatore può aggiornare liberamente sia la data sia il file.
2026-10-01 14:21:25 +02:00
Quando mancano 30 giorni o meno alla scadenza, o il certificato è scaduto, il giocatore
riceve un avviso nella propria Home; compare in quello degli admin da 7 giorni prima (vedi
2026-09-24 15:43:26 +02:00
[Avviso certificati ](#avviso-certificati )).
2026-08-07 15:36:02 +02:00
Lo storico non viene mantenuto nella prima versione.
2026-08-30 16:26:14 +02:00
### Foto tessera
2026-08-07 15:36:02 +02:00
Upload di una fotografia formato tessera.
Utilizzata dagli amministratori per il tesseramento CSI.
2026-08-30 16:26:14 +02:00
### Statistiche
2026-08-07 15:36:02 +02:00
2026-08-30 16:26:14 +02:00
Sezione già presente. Contiene.
2026-08-07 15:36:02 +02:00
- Presenze
- Voto medio
- MVP
- Serie
- Altre statistiche disponibili
2026-08-30 16:26:14 +02:00
### Badge
2026-08-07 15:36:02 +02:00
Sezione già presente.
Contiene tutti i badge ottenuti e quelli ancora da sbloccare.
2026-09-05 23:37:41 +02:00
### Opzioni
2026-08-07 15:36:02 +02:00
Contiene.
- Logout
2026-09-05 22:31:56 +02:00
- Preferenze notifiche: un solo interruttore che iscrive il dispositivo a **tutte** le push
(turno palloni, solleciti presenze) e abilita le notifiche smart in app — non è limitato
ai soli palloni (vedi [Notifiche ](notifiche.md ))
2026-08-07 15:36:02 +02:00
- Impostazioni applicazione
2026-09-04 23:14:55 +02:00
- Segnala un bug e Suggerisci una nuova funzionalità: due link che aprono una issue GitHub
già impostata sul template giusto (`.github/ISSUE_TEMPLATE/bug_report.yml` e
`feature_request.yml` ). Nessun dato passa dall'app — la segnalazione vive interamente su
GitHub, così non servono né una tabella né una schermata di gestione.
2026-08-07 15:36:02 +02:00
2026-08-30 16:26:14 +02:00
## Dashboard amministratore
2026-08-07 15:36:02 +02:00
2026-08-30 17:58:24 +02:00
Gli amministratori dispongono di una schermata dedicata (`/admin` , raggiungibile da
2026-09-10 14:32:11 +02:00
Profilo → Opzioni), organizzata in tab scorrevoli a pillole (`BarraSottosezioni` , stesso
componente di [Squadra ](squadra.md ) e Campionato): Squadra, Profili, Disattivati (solo se
c'è almeno un giocatore disattivato) e Notifiche.
2026-08-07 15:36:02 +02:00
2026-09-10 14:32:11 +02:00
La tab **Notifiche** mostra quanti giocatori attivi hanno almeno un dispositivo iscritto
alle notifiche push e i loro nomi, leggendo `GET /api/public/notifiche-attive` (vedi
[Notifiche ](notifiche.md )). È solo consultiva: l'attivazione resta un gesto che ogni
giocatore deve fare dal proprio dispositivo (Profilo), l'admin non può attivarla per conto
di altri.
2026-09-24 14:54:35 +02:00
Gli allenatori stanno nella stessa tab in un gruppo «Allenatori» a parte, senza documenti né
tesseramento, e non entrano nei conteggi della tab Squadra né nell'export CSI (DD-034).
2026-09-10 14:32:11 +02:00
Per ogni giocatore, nella tab Profili, vengono mostrati.
2026-08-07 15:36:02 +02:00
- Stato del profilo
- Certificato medico
- Documento di identità
- Foto tessera
2026-09-02 15:27:12 +02:00
- Stato tesseramento CSI (tesserato / da tesserare)
2026-08-07 15:36:02 +02:00
Azioni disponibili.
2026-08-30 17:58:24 +02:00
- Visualizza profilo (la scheda si apre in linea nell'elenco: nessuna schermata separata)
2026-08-07 15:36:02 +02:00
- Scarica certificato
- Scarica documento
- Scarica foto tessera
2026-08-30 18:15:16 +02:00
- Modifica dati squadra e dati personali del giocatore (DD-017)
2026-09-02 15:27:12 +02:00
- Registra numero e data della tessera CSI, una volta arrivata dal comitato
2026-08-30 18:15:16 +02:00
- Scollega account, per liberare uno slot assegnato per errore
2026-09-01 11:29:41 +02:00
- Aggiungi giocatore, per inserire un nuovo membro della squadra
- Disattiva/Riattiva giocatore, per chi lascia la squadra (o rientra)
2026-08-07 15:36:02 +02:00
2026-08-30 16:26:14 +02:00
## Esportazione CSI
2026-08-07 15:36:02 +02:00
Gli amministratori possono esportare un file CSV contenente esclusivamente i dati richiesti per il tesseramento.
Campi esportati.
- Nome
- Cognome
- Data di nascita
- Luogo di nascita
- Indirizzo
- Telefono
- Email
- Tipo documento
- Numero documento
- Rilasciato da
- Data emissione
- Data scadenza
2026-09-02 15:27:12 +02:00
## Tracciamento tesseramento
Numero e data della tessera CSI non sono dati che il giocatore conosce in anticipo: arrivano
dal comitato dopo l'iscrizione effettiva. Per questo, a differenza dei dati personali del
profilo, li scrive solo un amministratore — come nome, cognome, numero di maglia e ruolo
(DD-017), il trigger sulla tabella li rende non modificabili dal giocatore stesso. La
dashboard mostra un badge "Tesserato"/"Da tesserare" su ogni scheda e il conteggio
complessivo della squadra.
2026-08-30 16:26:14 +02:00
## Completamento profilo
2026-08-07 15:36:02 +02:00
Ogni sezione contribuisce alla percentuale di completamento.
2026-09-01 13:38:56 +02:00
| Sezione | Peso |
| --------------------- | ---- |
| Dati personali | 30% |
| Documento di identità | 30% |
| Certificato medico | 30% |
| Foto tessera | 10% |
2026-08-07 15:36:02 +02:00
Quando tutte le sezioni risultano complete il profilo raggiunge il 100%.
2026-08-30 16:26:14 +02:00
## Permessi
2026-08-07 15:36:02 +02:00
2026-08-30 16:26:14 +02:00
**Giocatore** — può modificare esclusivamente il proprio profilo.
2026-08-07 15:36:02 +02:00
2026-08-30 18:15:16 +02:00
**Amministratore** — può visualizzare tutti i profili, scaricare tutti i documenti, esportare i
dati, modificare dati squadra e dati personali di chiunque e scollegare un account (DD-017).
Non carica file al posto di altri.
2026-08-07 15:36:02 +02:00
2026-09-24 15:43:26 +02:00
**Avviso certificati** — il giocatore vede solo il proprio, l'admin i nomi di tutta la rosa,
nessun altro ne vede (vedi [Avviso certificati ](#avviso-certificati )).
2026-08-30 16:26:14 +02:00
## Versione 1
2026-08-07 15:36:02 +02:00
- Profilo giocatore
- Completamento profilo
- Gestione dati personali
- Documento di identità
- Certificato medico
- Foto tessera
- Dashboard amministratore
- Esportazione CSV CSI
2026-08-30 16:26:14 +02:00
## Versioni future
2026-08-07 15:36:02 +02:00
- Storico certificati medici
2026-09-24 15:43:26 +02:00
- Avviso certificati anche via push, o con una soglia regolabile dall'admin (DD-035, Riesame)
2026-08-07 15:36:02 +02:00
- Gestione documenti aggiuntivi
- Consensi privacy
- Firma digitale
2026-08-30 16:26:14 +02:00
- Verifica automatica documenti