La migration m27 riduce il job automatico alla sola fascia delle 3 ore: l'avviso arriva una volta a chi deve portare i palloni e a chi li deve prendere. I tipi turno_palloni_12h e _6h restano ammessi per le notifiche già generate e per la revoca. Migration applicata in produzione. Test di integrazione aggiornati (nessun avviso a 4,5 e 9 ore); documentati DD-042, moduli, DATABASE, ROADMAP, glossario e changelog. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
95 lines
7.4 KiB
Markdown
95 lines
7.4 KiB
Markdown
# DD-040 — Promemoria con «oggi» o «domani», turno palloni e solleciti automatici
|
|
|
|
**Data:** 30 settembre 2026
|
|
**Stato:** Accettata (implementata: migration `m26`, applicata in produzione il 30 settembre 2026, job, route e test). Il turno palloni è poi passato a un solo avviso a 3 ore da [DD-042](DD-042.md).
|
|
|
|
**Contesto**
|
|
Quattro notifiche su sei partivano da un pulsante premuto da un admin (DD-025 per i palloni): se nessuno
|
|
lo premeva, nessuno veniva avvisato. I testi erano inoltre brevi e informali, e i promemoria non dicevano
|
|
quando e dove. Si vuole che turno palloni e sollecito presenze partano anche da soli, a orari fissi prima
|
|
dell'evento, e che i testi siano più formali e completi. I testi nuovi sono nel
|
|
[catalogo](../modules/notifiche.md#testi-delle-notifiche).
|
|
|
|
**Decisione**
|
|
|
|
1. **Promemoria a 24 e 3 ore:** nuovo testo con data, ora e luogo. La parola nel titolo e nella riga
|
|
«Data» è **«domani»** se la data dell'evento è quella di domani (fuso `Europe/Rome`), **«oggi»**
|
|
altrimenti. Vale per entrambi i promemoria, quindi anche quello a 3 ore di un evento dopo la
|
|
mezzanotte dice «domani». La parola la calcola la funzione SQL quando genera la notifica.
|
|
2. **Turno palloni automatico.** Un job `pg_cron` ogni 15 minuti avvisa per gli eventi di tipo allenamento
|
|
o partita, in tre tempi con finestre che non si sovrappongono: **12 ore** (tra 12 e 6 ore prima
|
|
dell'inizio), **6 ore** (tra 6 e 3) e **3 ore** (meno di 3). Parte **solo se per l'evento c'è un
|
|
incaricato confermato** in `turni_palloni`: le proposte automatiche di `completaTurni()` non salvate non
|
|
contano. Gli avvisi sono due, con lo stesso testo nei tre tempi: «incarico assegnato» all'incaricato e
|
|
«riconsegna» a chi aveva i palloni all'evento precedente, se è un'altra persona.
|
|
- **Pulsante manuale.** «Avvisa chi è di turno» e la route `promemoria-palloni` **restano**: tipo
|
|
`turno_palloni`, testo nuovo, push mandata dalla route e non dalla coda. È una notifica in più;
|
|
riceverne due (automatica e manuale) va bene.
|
|
- **Incaricato cambiato dopo un avviso.** Il nuovo incaricato riceve il suo avviso al giro successivo,
|
|
con il tipo della finestra in cui cade. Chi aveva già ricevuto un avviso e non è più destinatario
|
|
riceve **una sola volta** «Turno palloni: incarico revocato» (`turno_palloni_revocato`), se
|
|
l'evento non è iniziato. Il job lo scopre confrontando i destinatari attuali con il **registro** degli
|
|
avvisi automatici già generati (non con le notifiche, che il giocatore può aver eliminato), senza
|
|
trigger su `turni_palloni`. Gli avvisi del pulsante non contano: possono riguardare una proposta non
|
|
confermata.
|
|
- **Niente email.** Gli avvisi palloni (automatici, revoca e pulsante) arrivano come push e nel centro
|
|
notifiche, **non per email**: il trigger `notifiche_utente_accoda_email` salta i tipi
|
|
`turno_palloni`, `turno_palloni_12h`, `_6h`, `_3h` e `turno_palloni_revocato`. È un'eccezione a
|
|
DD-038 («ogni notifica ha tre canali») solo per questi tipi; l'interruttore «Email» non cambia.
|
|
3. **Sollecito presenze automatico in tre tempi.** Lo stesso job manda il sollecito **24 ore** (tra 24 e
|
|
12 ore prima), **12 ore** (tra 12 e 6) e **6 ore** (meno di 6) prima, al massimo una notifica per
|
|
giocatore e per tipo. Lo riceve solo chi in quel momento non ha risposto o ha risposto «forse» ed è
|
|
destinatario dell'evento: i convocati, o tutta la rosa attiva se `convocati` è vuoto, mai l'allenatore.
|
|
Chi risponde presente, assente o in ritardo smette di riceverli; chi resta su «forse» li riceve tutti e
|
|
tre. Un evento creato a meno di 12 ore dall'inizio riceve solo il sollecito della sua finestra.
|
|
- **Pulsante manuale.** «Sollecita» e la route `sollecita-presenze` **restano**, anche per l'allenatore:
|
|
tipo `sollecita_presenze`, push mandata dalla route, testo nuovo con in più la riga «Richiesta di:
|
|
_Nome_». I destinatari sono **gli stessi dell'automatico** (convocati senza risposta o con «forse»);
|
|
oggi la route guarda invece tutti i giocatori attivi.
|
|
4. **Stessa infrastruttura dei promemoria** (DD-037, DD-038): le notifiche automatiche nascono nel
|
|
database, il registro `promemoria_eventi_generati` impedisce i doppioni anche se il giocatore le
|
|
elimina, la push la manda il worker dalla coda `notifiche_push_coda`, l'email (quando c'è) nasce dal
|
|
trigger su `notifiche_utente`. Tipi nuovi: `sollecita_presenze_24h`, `_12h`, `_6h`;
|
|
`turno_palloni_12h`, `_6h`, `_3h` e `turno_palloni_revocato`. Il `turno_palloni` del pulsante resta.
|
|
5. **Migration `m26`:** estende i `CHECK` sui tipi di `notifiche_utente` e del registro, il trigger della
|
|
coda push, il trigger della coda email (che salta i tipi dei palloni) e ridefinisce la funzione dei
|
|
promemoria. Le funzioni nuove riusano `giocatori_destinatari_evento()`.
|
|
|
|
**Alternative scartate**
|
|
|
|
- Togliere i pulsanti manuali (turno palloni e sollecito) una volta arrivati gli automatici → scartata su
|
|
indicazione esplicita: servono all'admin per rimandare un avviso o sollecitare fuori dagli orari fissi.
|
|
- Mandare tutti i solleciti (o gli avvisi palloni) a un evento creato tardi → scartata: più messaggi nel
|
|
giro di pochi minuti sono rumore.
|
|
- «Domani» e «oggi» fissi nei due testi → scartata: il job delle 24 ore scatta anche per eventi che
|
|
iniziano oggi, e quello delle 3 ore attraversa la mezzanotte.
|
|
- Calcolare il testo nell'app invece che nel database → scartata: le notifiche nascono nei job `pg_cron`,
|
|
che non chiamano l'app (DD-038).
|
|
- Spostare nel worker il calcolo di evento precedente e successivo dei palloni → scartata: un secondo
|
|
punto che scrive in `notifiche_utente`, per un vantaggio piccolo.
|
|
- Ritirare l'avviso già consegnato al vecchio incaricato → scartata: per la push non si può, e in-app
|
|
confonde. Si manda la revoca.
|
|
|
|
**Conseguenze**
|
|
|
|
- Cambia la regola «quattro notifiche su sei dipendono da un gesto manuale»: restano solo manuali il
|
|
messaggio dello staff e il sondaggio pre-partita; per turno palloni e sollecito gli automatici si
|
|
aggiungono ai pulsanti, e un giocatore può ricevere lo stesso avviso due volte.
|
|
- **Logica duplicata:** «evento precedente» e «evento successivo» per i palloni, in `palloni-core.ts`
|
|
(usato dal pulsante e dalla schermata), sono riscritti in SQL per i job (`genera_avvisi_palloni_fascia`).
|
|
Ordine comune: data, ora, id. Se si cambia una regola in una sola delle due versioni, pulsante e job danno
|
|
risposte diverse: `notifiche-automatiche.test.ts` confronta testi e destinatari sugli stessi dati, anche a
|
|
parità di data e ora.
|
|
- `destinatariSollecito()` riceve anche i convocati e serve al sollecito manuale; un giocatore non
|
|
convocato non è più sollecitato. `avvisiPalloniEvento()` resta come riferimento per i test finché il SQL
|
|
non la sostituisce del tutto.
|
|
- Se un incaricato revocato viene poi riassegnato non riceve un secondo avviso, perché il registro lo ha
|
|
già generato per quella finestra: la revoca resta l'ultima notifica che ha letto.
|
|
- Le mail automatiche per evento e giocatore sono al massimo **cinque** (due promemoria, tre solleciti),
|
|
più quelle dei pulsanti (sollecito, sondaggio). Il turno palloni non ne manda.
|
|
- Il testo dei promemoria già generati non cambia (il registro impedisce di rigenerarli).
|
|
|
|
**Riesame**
|
|
Dopo la prima stagione di uso: se i solleciti o gli avvisi palloni risultano troppi, ridurre le
|
|
finestre o escludere chi ha risposto «forse» più di una volta.
|