diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 73746e9..bb9cba9 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -13,6 +13,12 @@ versioni `0.y.z` erano pre-release. ## [Non rilasciato] +### Rimosso + +- **Promemoria evento a 24 e 3 ore** — non partono più per nessun evento (allenamenti, partite, extra-campo): + niente notifica, push né email. Migration `m28_niente_promemoria_evento` (tolti i due job `pg_cron`; + funzione, tipi e notifiche già generate restano). Applicata in produzione il 01/10/2026 (DD-043). + ### Modificato - **Turno palloni: un solo avviso, 3 ore prima** — a chi deve portare i palloni e a chi li deve diff --git a/docs/DATABASE.md b/docs/DATABASE.md index ccace6b..0aa1b87 100644 --- a/docs/DATABASE.md +++ b/docs/DATABASE.md @@ -153,7 +153,7 @@ riservate alla service role (anon e utenti autenticati non possono chiamarle). T | Funzione (migration) | Cosa fa | Job `pg_cron` | | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | -| `genera_promemoria_eventi(tipo, finestra)` (M17, M23, M26) | Promemoria a 24 e 3 ore, con «oggi/domani», data, ora e luogo. | `promemoria-eventi-24h` (ogni ora), `-3h` (15 min) | +| `genera_promemoria_eventi(tipo, finestra)` (M17, M23, M26) | Promemoria a 24 e 3 ore, con «oggi/domani», data, ora e luogo. **Non pianificata dalla M28** (DD-043): resta come funzione, nessun job la chiama. | `promemoria-eventi-24h` (ogni ora), `-3h` (15 min) | | `genera_avvisi_palloni()` (M26, M27), con `genera_avvisi_palloni_fascia()` | Avviso del turno palloni a 3 ore (M27; in M26 erano 12, 6 e 3) per gli eventi con un incaricato confermato; poi chiama `genera_revoche_palloni()`. | `avvisi-palloni-automatici` (15 min) | | `genera_revoche_palloni()` (M26) | Una revoca per chi aveva un avviso automatico e non è più destinatario, per eventi non ancora iniziati; guarda il registro. | (dentro `genera_avvisi_palloni()`) | | `genera_solleciti_presenze()` (M26), con `..._fascia()` | Solleciti a 24, 12 e 6 ore ai destinatari dell'evento senza risposta o con «forse». | `solleciti-presenze-automatici` (15 min) | diff --git a/docs/EFFICIENZA_CLOUD.md b/docs/EFFICIENZA_CLOUD.md index d782dc6..3a93f4b 100644 --- a/docs/EFFICIENZA_CLOUD.md +++ b/docs/EFFICIENZA_CLOUD.md @@ -19,7 +19,7 @@ Query, traffico e invocazioni vanno tenuti al minimo **per costruzione**, non ot si ricalcolano a ogni apertura di pagina. I badge restano calcolati a runtime dai dati già in cache, senza query aggiuntive (DD-007): `src/lib/rosa.ts` aggrega ciò che è già stato letto. -6. **Push solo per eventi importanti**: convocazioni, promemoria allenamento/partita, turno +6. **Push solo per eventi importanti**: convocazioni, turno palloni, esito finale. 7. **Niente funzionalità pesanti**: foto, video, chat. 8. **Indici** sui campi usati per filtri e relazioni in ogni nuova migration. diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 1f89772..1afcd3e 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -44,8 +44,8 @@ Tutto quello che è rilasciato, fino alla versione 1.0.0 (vedi `CHANGELOG.md`). - [x] Notifiche email — ogni notifica in-app inviata anche per email agli account registrati, da un worker Docker sull'host di casa via Gmail, con interruttore «Email» in Profilo ([specifica](modules/notifiche-email.md), DD-036) -- [x] Notifiche automatiche — promemoria con «oggi/domani», turno palloni 3 ore prima, sollecito - presenze a 24, 12 e 6 ore (i pulsanti «Avvisa chi è di turno» e «Sollecita» restano) ([specifica](modules/notifiche.md#testi-delle-notifiche), DD-040) +- [x] Notifiche automatiche — turno palloni 3 ore prima, sollecito + presenze a 24, 12 e 6 ore (i pulsanti «Avvisa chi è di turno» e «Sollecita» restano; il promemoria a 24 e 3 ore è stato tolto, DD-043) ([specifica](modules/notifiche.md#testi-delle-notifiche), DD-040) ## Prossimo diff --git a/docs/WORKER_EMAIL.md b/docs/WORKER_EMAIL.md index f24fc90..17adc4d 100644 --- a/docs/WORKER_EMAIL.md +++ b/docs/WORKER_EMAIL.md @@ -1,7 +1,7 @@ # Worker email: installazione e gestione Come si mette in funzione, si controlla e si diagnostica il worker (`mailer/`) che invia le notifiche -per email e le push delle notifiche che nascono nel database: promemoria a 24 e 3 ore, turno palloni a 3 ore con revoca, solleciti presenze a 24, 12 e 6 ore (DD-040). Cosa fa il canale email sta in +per email e le push delle notifiche che nascono nel database: turno palloni a 3 ore con revoca, solleciti presenze a 24, 12 e 6 ore (DD-040). Cosa fa il canale email sta in [modules/notifiche-email.md](modules/notifiche-email.md), la push dei promemoria in [modules/notifiche.md](modules/notifiche.md#push-dei-promemoria-m24); perché è fatto così in [DD-036](decisions/DD-036.md) diff --git a/docs/decisions/DD-043.md b/docs/decisions/DD-043.md new file mode 100644 index 0000000..026c21d --- /dev/null +++ b/docs/decisions/DD-043.md @@ -0,0 +1,35 @@ +# DD-043 — Niente promemoria automatico a 24 e 3 ore prima degli eventi + +**Data:** 1 ottobre 2026 +**Stato:** Accettata (migration `m28`, applicata in produzione il 1 ottobre 2026; sostituisce il promemoria di +[DD-030](DD-030.md), [DD-037](DD-037.md) e [DD-040](DD-040.md)) + +**Contesto** +Il promemoria a 24 e 3 ore prima di ogni evento non serve: la squadra ha già il calendario, il +sollecito presenze (per chi non ha risposto) e l'avviso del turno palloni a 3 ore. + +**Decisione** + +1. Il database **non genera più** `evento_promemoria_24h` ed `evento_promemoria_3h`, per nessun tipo di + evento (allenamento, partita, extra-campo). +2. La migration `m28` toglie solo i due job `pg_cron` (`promemoria-eventi-24h` e `-3h`). + `genera_promemoria_eventi()`, i tipi nei `CHECK`, il registro `promemoria_eventi_generati` e la coda + push restano: le notifiche già create continuano a esistere e rimettere il promemoria richiede solo + un `cron.schedule`. +3. Non cambiano: sollecito presenze, turno palloni (DD-042), messaggio dello staff, sondaggio. + +**Alternative scartate** + +- Togliere il promemoria solo per gli allenamenti → scartata su indicazione esplicita: via per tutti. +- Cancellare funzione, tipi e registro → scartata: vanno tenute le notifiche già generate e il lavoro per + rimetterlo sarebbe molto più grande di un `cron.schedule`. + +**Conseguenze** + +- Meno notifiche per la squadra. Chi voleva il promemoria di una partita non lo riceve più. +- Funzione, test e registro restano come codice non pianificato: sono ancora coperti da + `promemoria-eventi.test.ts` e dagli altri test sulla funzione. + +**Riesame** +Se la squadra sente la mancanza del promemoria (per esempio solo per le partite), rimettere i job o +reintrodurlo per tipo di evento. diff --git a/docs/decisions/README.md b/docs/decisions/README.md index dcf0aae..09bb665 100644 --- a/docs/decisions/README.md +++ b/docs/decisions/README.md @@ -86,6 +86,7 @@ Una decisione sostituita non si cancella: si cambia il suo **Stato** e si rimand | [DD-038](DD-038.md) | Tre canali per ogni notifica | | [DD-039](DD-039.md) | Niente promemoria all'allenatore | | [DD-040](DD-040.md) | Palloni e solleciti automatici | +| [DD-043](DD-043.md) | Niente promemoria evento a 24 e 3 ore | | [DD-042](DD-042.md) | Turno palloni: un solo avviso a 3 ore | | [DD-041](DD-041.md) | Avviso certificati: giocatore a 30 giorni | diff --git a/docs/modules/allenatore.md b/docs/modules/allenatore.md index 6f40313..91ea452 100644 --- a/docs/modules/allenatore.md +++ b/docs/modules/allenatore.md @@ -125,14 +125,14 @@ risposte presenze altrui, gestione dei ruoli. Cosa riceve l'allenatore, notifica per notifica (il catalogo completo, con i canali di tutti, sta in [notifiche.md](notifiche.md#catalogo-delle-notifiche)): -| Notifica | L'allenatore la riceve? | Note | -| ------------------------------------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Promemoria a 24 e 3 ore prima di un evento | **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. | -| 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. | +| 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. | +| 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 diff --git a/docs/modules/notifiche-email.md b/docs/modules/notifiche-email.md index dedd0d8..a2b2662 100644 --- a/docs/modules/notifiche-email.md +++ b/docs/modules/notifiche-email.md @@ -49,8 +49,7 @@ App su Vercel ──scrive──▶ notifiche_utente ──trigger──▶ noti ## Quali notifiche e a chi -**Ogni riga nuova di `notifiche_utente` genera una mail**: messaggio admin, promemoria a 24 ore e a -3 ore, sollecito presenze, sondaggio pre-partita. **Fa eccezione il turno palloni** (DD-040, dalla +**Ogni riga nuova di `notifiche_utente` genera una mail**: messaggio admin, sollecito presenze, sondaggio pre-partita. **Fa eccezione il turno palloni** (DD-040, dalla `m26`): per i tipi `turno_palloni`, `turno_palloni_12h`, `_6h`, `_3h` e `turno_palloni_revocato` il trigger non accoda nulla, restano push e centro notifiche. Un tipo nuovo che in futuro finisse in quella tabella viaggerebbe per email senza altro lavoro. Le notifiche già presenti quando si applica la migration diff --git a/docs/modules/notifiche.md b/docs/modules/notifiche.md index 1b24638..83139c8 100644 --- a/docs/modules/notifiche.md +++ b/docs/modules/notifiche.md @@ -36,8 +36,8 @@ quelle del turno palloni**, che restano solo push e in-app: DD-040). | # | Notifica | Cosa la fa partire | Destinatari | Push | In-app | Email | | --- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | ------ | --------------- | -| 1 | **Promemoria a 24 ore** — «Promemoria evento di _domani_ (o _oggi_): _titolo_», con data, ora e luogo | Job `pg_cron` `promemoria-eventi-24h`, ogni ora, per gli eventi che iniziano entro le prossime 24 ore. Tipo `evento_promemoria_24h`. La push la manda il worker (M24). | I convocati dell'evento, o tutta la rosa attiva se `convocati` è vuoto; mai gli allenatori (DD-039). | sì (worker) | sì | sì | -| 2 | **Promemoria a 3 ore** — stesso testo | Job `pg_cron` `promemoria-eventi-3h`, ogni 15 minuti, per gli eventi che iniziano entro le prossime 3 ore. Tipo `evento_promemoria_3h`. La push la manda il worker (M24). | Come il promemoria a 24 ore. | sì (worker) | sì | sì | +| 1 | ~~Promemoria a 24 ore~~ — **rimosso** | Non parte più: i job `pg_cron` sono stati tolti dalla migration `m28` (DD-043). Restano le notifiche già generate (tipo `evento_promemoria_24h`). | — | — | — | — | +| 2 | ~~Promemoria a 3 ore~~ — **rimosso** | Come la riga 1 (tipo `evento_promemoria_3h`). | — | — | — | — | | 3 | **Messaggio dello staff** — titolo fisso «Messaggio dallo staff», corpo il testo scritto (max 300 caratteri) | Un admin, dalla tab «Notifiche» della dashboard: «Invia messaggio a tutti» o il pulsante della riga di un giocatore. Route `notifica-personalizzata`, tipo `admin`. | Push: tutti i dispositivi iscritti, o quelli del giocatore scelto. In-app ed email: tutta la rosa attiva (allenatori compresi, anche senza dispositivi iscritti), o il giocatore scelto. | sì | sì | sì | | 4 | **Turno palloni** — «Turno palloni: incarico assegnato» / «Turno palloni: riconsegna» | **Automatica**, **una sola volta, 3 ore prima** dell'evento (DD-040, DD-042): job `pg_cron` ogni 15 minuti, solo per allenamenti e partite con un incaricato confermato; tipo `turno_palloni_3h` (`_12h` e `_6h` esistono solo nelle notifiche generate prima di `m27`), push dal worker. Se l'incaricato cambia, chi aveva già ricevuto un avviso riceve una volta «Turno palloni: incarico revocato» (tipo `turno_palloni_revocato`). **Manuale**, in più: un admin, con il pulsante nella pagina dell'evento; route `promemoria-palloni`, tipo `turno_palloni`, push dalla route. | L'incaricato del turno di quell'evento e, se è un'altra persona, chi aveva i palloni all'evento precedente. Se per l'evento non c'è un incaricato non parte nulla. | sì | sì | **no** (DD-040) | | 5 | **Sollecito presenze** — «Conferma di partecipazione richiesta: _titolo_» | **Automatica**, in tre tempi (DD-040): **24, 12 e 6 ore** prima dell'evento, dallo stesso job; tipi `sollecita_presenze_24h`, `_12h`, `_6h`, push dal worker. **Manuale**, in più: un admin o un allenatore con il pulsante nella pagina dell'evento; route `sollecita-presenze`, tipo `sollecita_presenze`, push dalla route. | Automatica e manuale: i destinatari dell'evento (convocati, o tutta la rosa attiva se `convocati` è vuoto; mai gli allenatori) che in quel momento non hanno risposto o hanno risposto «forse». | sì | sì | sì | @@ -46,7 +46,7 @@ quelle del turno palloni**, che restano solo push e in-app: DD-040). Le notifiche generate dal server (righe 1-6) hanno tutti e tre i canali (DD-038), tranne il turno palloni (riga 4), che non manda email (DD-040). La differenza sta in come parte la push: quelle dei pulsanti (3 e 6) la mandano le route dell'app, quelle -automatiche (1, 2, 4 e 5) nascono nel database e la manda il worker `mailer/` (vedi «Push dei +automatiche (4 e 5; la 1 e la 2 non esistono più) nascono nel database e la manda il worker `mailer/` (vedi «Push dei promemoria»). Il sondaggio riscrive la notifica esistente se l'admin preme di nuovo il pulsante per lo stesso evento (vedi «Centro notifiche in-app»). @@ -63,17 +63,17 @@ volta sola. Nell'email il titolo diventa l'oggetto e il corpo segue il formato d [notifiche-email.md](notifiche-email.md#contenuto-delle-mail) (link «Apri CrAPP» e avviso di disattivazione). Tra `<…>` i valori che cambiano a ogni invio; le date sono `GG/MM/AAAA`. -| # | Notifica | Titolo | Corpo | -| --- | ----------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 1-2 | Promemoria 24 e 3 ore | `Promemoria evento di domani: `, oppure `…di oggi: ` | `Data: domani, `
`Ora: `
`Luogo: ` — «domani» se la data dell'evento è quella di domani, «oggi» altrimenti (fuso `Europe/Rome`, vale per entrambi i promemoria) | -| 3 | Messaggio dello staff | `Messaggio dallo staff` | Il testo scritto dall'admin, max 300 caratteri. | -| 4a | Turno palloni, all'incaricato | `Turno palloni: incarico assegnato` | `Evento: `
`Data: , ore `
`Incarico: custodia dei palloni al termine dell'evento`
`Riconsegna: ` — senza evento successivo la riga «Riconsegna» manca | -| 4b | Turno palloni, a chi li aveva | `Turno palloni: riconsegna` | `Evento: `
`Data: , ore `
`Incarico: riconsegna dei palloni in custodia dal turno precedente` | -| 4c | Turno palloni, revoca | `Turno palloni: incarico revocato` | `Evento: `
`Data: , ore `
`Incarico: non più a tuo carico per questo evento` — a chi aveva ricevuto un avviso (4a o 4b) e non è più destinatario; una sola volta | -| 5 | Sollecito presenze | `Conferma di partecipazione richiesta: ` | `Data: `
`Ora: `
`Luogo: `
`Richiesta di: ` (solo nel sollecito manuale, e solo se il nome c'è)
`Risposta attuale: nessuna` (oppure `forse`)
`Azione: indicare presente, assente o in ritardo` — stesso testo a 24, 12 e 6 ore | -| 6 | Sondaggio pre-partita | `💩 Sondaggio pre-partita aperto` | ` · ore . Quante cacche hai fatto? Rispondi prima del fischio d'inizio.` | +| # | Notifica | Titolo | Corpo | +| --- | --------------------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 1-2 | Promemoria 24 e 3 ore (rimosso, DD-043) | `Promemoria evento di domani: `, oppure `…di oggi: ` | `Data: domani, `
`Ora: `
`Luogo: ` — «domani» se la data dell'evento è quella di domani, «oggi» altrimenti (fuso `Europe/Rome`, vale per entrambi i promemoria) | +| 3 | Messaggio dello staff | `Messaggio dallo staff` | Il testo scritto dall'admin, max 300 caratteri. | +| 4a | Turno palloni, all'incaricato | `Turno palloni: incarico assegnato` | `Evento: `
`Data: , ore `
`Incarico: custodia dei palloni al termine dell'evento`
`Riconsegna: ` — senza evento successivo la riga «Riconsegna» manca | +| 4b | Turno palloni, a chi li aveva | `Turno palloni: riconsegna` | `Evento: `
`Data: , ore `
`Incarico: riconsegna dei palloni in custodia dal turno precedente` | +| 4c | Turno palloni, revoca | `Turno palloni: incarico revocato` | `Evento: `
`Data: , ore `
`Incarico: non più a tuo carico per questo evento` — a chi aveva ricevuto un avviso (4a o 4b) e non è più destinatario; una sola volta | +| 5 | Sollecito presenze | `Conferma di partecipazione richiesta: ` | `Data: `
`Ora: `
`Luogo: `
`Richiesta di: ` (solo nel sollecito manuale, e solo se il nome c'è)
`Risposta attuale: nessuna` (oppure `forse`)
`Azione: indicare presente, assente o in ritardo` — stesso testo a 24, 12 e 6 ore | +| 6 | Sondaggio pre-partita | `💩 Sondaggio pre-partita aperto` | ` · ore . Quante cacche hai fatto? Rispondi prima del fischio d'inizio.` | -Le righe 1-2, 4a-4c e 5 nascono nelle funzioni SQL della migration `m26` +Le righe 4a-4c e 5 (e le 1-2, finché esistevano) nascono nelle funzioni SQL della migration `m26` (`genera_promemoria_eventi`, `genera_avvisi_palloni_fascia`, `genera_revoche_palloni`, `genera_solleciti_presenze_fascia`); i pulsanti usano gli stessi testi da `palloni-core.ts` (`avvisiPalloniEvento`) e `presenze.ts` (`testoSollecito`), e `notifiche-automatiche.test.ts` verifica che siano @@ -96,8 +96,8 @@ dall'emoji. Non entrano nel centro notifiche e non generano email. ### Cosa non genera nessuna notifica -- Creare, spostare, modificare o cancellare un evento: contano solo i promemoria prima - dell'inizio (DD-030). +- Creare, spostare, modificare o cancellare un evento. Dalla `m28` (DD-043) non parte nemmeno più un + promemoria prima dell'inizio: restano solo il turno palloni e il sollecito presenze. - L'arrivo di un risultato, di una pagella o di un voto MVP. - Un giocatore che risponde a un evento: nessun avviso a chi gestisce gli eventi. - Assenze e infortuni. @@ -106,7 +106,9 @@ dall'emoji. Non entrano nel centro notifiche e non generano email. ### Comportamenti da conoscere -Sono l'effetto attuale della logica, non scelte documentate altrove: +Sono l'effetto attuale della logica, non scelte documentate altrove. I punti sui **promemoria 1 e 2** +descrivono come funzionavano fino alla `m28`: la funzione esiste ancora ma nessun job la chiama +(DD-043); valgono solo se i job vengono ripianificati. - **I promemoria (1 e 2) non distinguono il tipo di evento:** scattano per allenamenti, partite ed eventi extra-campo (per esempio una cena). Il turno palloni (4), invece, esiste solo per @@ -146,16 +148,16 @@ Sono l'effetto attuale della logica, non scelte documentate altrove: ### Test che verificano il catalogo -| Cosa | Test | -| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Promemoria 24 e 3 ore: destinatari (convocati, tutti i giocatori attivi se `convocati` è vuoto, mai l'allenatore), deduplica, eliminazione, coda push ed email | `test/integration/destinatari-notifiche.test.ts`, `promemoria-eventi.test.ts`, `push-promemoria.test.ts`, `notifiche-email.test.ts` | -| Messaggio dello staff: push a tutti i dispositivi (allenatore compreso) o a uno solo, in-app a tutta la rosa attiva, riservato agli admin | `destinatari-notifiche.test.ts`, `notifiche-utente.test.ts` | -| Turno palloni: incaricato e chi li aveva prima, solo allenamenti e partite, riservato agli admin | `destinatari-notifiche.test.ts`, `unit/palloni-core.test.ts` | -| Sollecito presenze: chi non ha risposto o ha detto «forse», mai l'allenatore; permesso ad allenatore e admin, non ai giocatori | `destinatari-notifiche.test.ts`, `unit/presenze.test.ts` | -| Sondaggio pre-partita: push senza allenatori, avviso in-app ed email ai giocatori attivi, `upsert`, riservato agli admin | `destinatari-notifiche.test.ts`, `sondaggio-notifiche.test.ts`, `unit/cacche.test.ts` | -| Promemoria con «oggi/domani», turno palloni a 3 ore e revoca, solleciti a 24·12·6 ore (manuale compreso): finestre, destinatari, una sola volta, registro (DD-040, `m26`; palloni a 3 ore: DD-042, `m27`) | `integration/notifiche-automatiche.test.ts`, `promemoria-eventi.test.ts` (testo oggi/domani), `destinatari-notifiche.test.ts` (pulsanti), `unit/palloni-core.test.ts`, `unit/presenze.test.ts` | -| Worker: esiti, backoff, tetto giornaliero, iscrizioni scadute | `unit/mailer-core.test.ts` | -| L'allenatore è fuori dalla rosa di gioco | `unit/giocatori-squadra.test.ts` (`inRosa`) | +| Cosa | Test | +| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Promemoria 24 e 3 ore (funzione ancora presente ma non pianificata, M28): destinatari (convocati, tutti i giocatori attivi se `convocati` è vuoto, mai l'allenatore), deduplica, eliminazione, coda push ed email | `test/integration/destinatari-notifiche.test.ts`, `promemoria-eventi.test.ts`, `push-promemoria.test.ts`, `notifiche-email.test.ts`; niente job pianificati: `notifiche-automatiche.test.ts` (M28) | +| Messaggio dello staff: push a tutti i dispositivi (allenatore compreso) o a uno solo, in-app a tutta la rosa attiva, riservato agli admin | `destinatari-notifiche.test.ts`, `notifiche-utente.test.ts` | +| Turno palloni: incaricato e chi li aveva prima, solo allenamenti e partite, riservato agli admin | `destinatari-notifiche.test.ts`, `unit/palloni-core.test.ts` | +| Sollecito presenze: chi non ha risposto o ha detto «forse», mai l'allenatore; permesso ad allenatore e admin, non ai giocatori | `destinatari-notifiche.test.ts`, `unit/presenze.test.ts` | +| Sondaggio pre-partita: push senza allenatori, avviso in-app ed email ai giocatori attivi, `upsert`, riservato agli admin | `destinatari-notifiche.test.ts`, `sondaggio-notifiche.test.ts`, `unit/cacche.test.ts` | +| Promemoria con «oggi/domani», turno palloni a 3 ore e revoca, solleciti a 24·12·6 ore (manuale compreso): finestre, destinatari, una sola volta, registro (DD-040, `m26`; palloni a 3 ore: DD-042, `m27`) | `integration/notifiche-automatiche.test.ts`, `promemoria-eventi.test.ts` (testo oggi/domani), `destinatari-notifiche.test.ts` (pulsanti), `unit/palloni-core.test.ts`, `unit/presenze.test.ts` | +| Worker: esiti, backoff, tetto giornaliero, iscrizioni scadute | `unit/mailer-core.test.ts` | +| L'allenatore è fuori dalla rosa di gioco | `unit/giocatori-squadra.test.ts` (`inRosa`) | Le push dei test vanno a un servizio push finto in locale: si verifica **a chi** arrivano, non la consegna su un telefono. Non ha un test l'esclusione dell'allenatore dalle **notifiche smart**: la @@ -287,7 +289,7 @@ job `pg_cron` come la 2, che scrive `turno_palloni_3h`/`_revocato` (`_12h`/`_6h` 1. **Messaggio admin** — `notifica-personalizzata.ts` inserisce una riga per destinatario in parallelo all'invio push esistente (a tutta la rosa attiva se `giocatoreId` è omesso). -2. **Promemoria evento** — due job `pg_cron` (ogni ora per la finestra delle 24h, ogni 15 +2. **Promemoria evento (rimosso dalla `m28`, DD-043: i job non esistono più)** — due job `pg_cron` (ogni ora per la finestra delle 24h, ogni 15 minuti per quella delle 3h) generano una notifica per evento imminente, per i convocati (o tutta la rosa attiva se l'evento non ne specifica), deduplicata dal registro `promemoria_eventi_generati` (M23, DD-037; il vincolo `UNIQUE (giocatore_id, evento_id, tipo)` @@ -325,7 +327,7 @@ ritrova per sempre nell'elenco, solo segnata come letta. ## Push dei promemoria (M24) -I promemoria a 24 e 3 ore nascono nel database (job `pg_cron`), che non può firmare né cifrare una +I promemoria a 24 e 3 ore (rimossi con la `m28`, DD-043; la coda resta valida per i tipi già esistenti) nascevano nel database (job `pg_cron`), che non può firmare né cifrare una push Web: la manda il worker `mailer/`, lo stesso che invia le email ([WORKER_EMAIL.md](../WORKER_EMAIL.md), DD-038). diff --git a/src/lib/notifiche-utente.ts b/src/lib/notifiche-utente.ts index 626cf36..8310b0f 100644 --- a/src/lib/notifiche-utente.ts +++ b/src/lib/notifiche-utente.ts @@ -5,7 +5,7 @@ import { useGiocatoreId } from "./user-store"; /** * Centro notifiche in-app (M17): pallino sull'avatar del profilo, con il numero delle non * lette. Cinque sorgenti riempiono `notifiche_utente` (lato database, mai dal client): un - * messaggio libero dell'admin, un promemoria automatico prima di un evento (24h e 3h), il + * messaggio libero dell'admin, un promemoria automatico prima di un evento (24h e 3h, non più generato dalla M28), il * turno palloni e il sollecito presenze (questi due avviati a mano da un admin, in * parallelo alla push esistente). Qui si legge e si segna come letto, con * `supabaseNuoveTabelle` perché `types.ts` non include ancora questa tabella (vedi diff --git a/src/routes/calendario.tsx b/src/routes/calendario.tsx index 400b663..3a35251 100644 --- a/src/routes/calendario.tsx +++ b/src/routes/calendario.tsx @@ -31,7 +31,7 @@ export const Route = createFileRoute("/calendario")({ { property: "og:title", content: "Calendario squadra — CrAPP" }, { property: "og:description", - content: "Vista mensile e prossimi eventi con promemoria per la squadra.", + content: "Vista mensile e prossimi eventi per la squadra.", }, ], }), diff --git a/supabase/migrations/20261001150000_m28_niente_promemoria_evento.sql b/supabase/migrations/20261001150000_m28_niente_promemoria_evento.sql new file mode 100644 index 0000000..5c64c9f --- /dev/null +++ b/supabase/migrations/20261001150000_m28_niente_promemoria_evento.sql @@ -0,0 +1,14 @@ +-- M28 — Niente più promemoria automatico a 24 e 3 ore prima degli eventi (DD-043) +-- +-- Si tolgono solo i due job `pg_cron` di M17: da ora il database non genera più notifiche +-- `evento_promemoria_24h` e `evento_promemoria_3h`. La funzione `genera_promemoria_eventi()`, i tipi +-- ammessi dai CHECK e il registro `promemoria_eventi_generati` restano: servono per le notifiche +-- già generate e, volendo, per rimettere in funzione il promemoria con un solo `cron.schedule`. + +DO $$ +BEGIN + PERFORM cron.unschedule(jobname) + FROM cron.job + WHERE jobname IN ('promemoria-eventi-24h', 'promemoria-eventi-3h'); +END; +$$; diff --git a/test/integration/notifiche-automatiche.test.ts b/test/integration/notifiche-automatiche.test.ts index 68e2ab3..30f0251 100644 --- a/test/integration/notifiche-automatiche.test.ts +++ b/test/integration/notifiche-automatiche.test.ts @@ -5,6 +5,7 @@ * Esegue i job veri del database (`genera_avvisi_palloni`, `genera_solleciti_presenze`) su eventi * creati con orari relativi a «adesso» e verifica: * + * - che il promemoria a 24 e 3 ore non sia più pianificato (M28, DD-043); * - le finestre (palloni: un solo avviso nelle 3 ore prima; solleciti 24·12·6 ore, contigue e senza * sovrapposizione); * - i destinatari (incaricato e turno precedente; convocati senza risposta o con «forse»; mai @@ -795,6 +796,33 @@ if (!locale) { ); }); + await prova("il promemoria a 24 e 3 ore non è più pianificato (M28, DD-043)", async () => { + const contenitore = spawnSync( + "docker", + ["ps", "--filter", "name=supabase_db", "--format", "{{.Names}}"], + { encoding: "utf8" }, + ) + .stdout.trim() + .split("\n")[0]; + assert.ok(contenitore, "container del database locale non trovato"); + const esito = spawnSync( + "docker", + [ + "exec", + contenitore, + "psql", + "-U", + "postgres", + "-At", + "-c", + "select count(*) from cron.job where jobname like 'promemoria-eventi-%'", + ], + { encoding: "utf8" }, + ); + assert.equal(esito.status, 0, esito.stderr); + assert.equal(esito.stdout.trim(), "0", "nessun job di promemoria evento"); + }); + await prova("cancellare l'evento toglie registro e notifiche collegate", async () => { assert.ok((await registro(MAIN)).length > 0); await scrivi(`eventi_app?id=eq.${MAIN}`, "DELETE");