Fa arrivare le push ad app chiusa e rende diagnosticabile quando non arrivano.
Il testo della notifica viaggia ora cifrato dentro la push (aes128gcm, RFC
8188/8291) invece di essere recuperato dal service worker con una fetch al
risveglio. Era quella fetch a non chiudersi in tempo: ad app chiusa il browser
tiene vivo il worker pochi secondi, showNotification non veniva mai chiamata e
non compariva niente, mentre ad app aperta con la rete calda sembrava tutto a
posto. La POST porta anche Urgency: high, che chiede la consegna immediata
invece di far accumulare i messaggi fino al risveglio del dispositivo.
Cadono i pezzi che esistevano solo per rimediare al payload vuoto: la route
push-messaggio, la coda promemoria_push con la sua scadenza a 12 ore,
messaggioPalloniOggi() e il timeout nel worker. Tutti e tre i mittenti avevano
gia il testo pronto prima di inviare.
Il worker si aggiorna da solo all'avvio e a ogni ritorno in primo piano
(mantieniWorkerPushAggiornato): nella webapp installata quello vecchio puo
sopravvivere a lungo, e senza questo un dispositivo resterebbe fermo alla
versione che va a cercare il testo in rete.
Profilo -> Opzioni ha "Mandami una notifica di prova", visibile solo a notifiche
attive: manda una push a questo dispositivo e riporta stato HTTP, corpo della
risposta e se l'endpoint risulta davvero in push_subscriptions. Senza, "non
arriva" era cieco: ogni prova richiedeva un admin, un evento nello stato giusto
e una seconda persona, e la risposta del servizio push veniva buttata via.
inviaPush torna { stato, corpo } e logga il corpo sui rifiuti.
Dalle prove sul campo: a parita di server, iPhone installato da Home riceve ad
app chiusa. Su Android installato come webapp resta da verificare: il WebAPK e
un'app Android a se, con permesso notifiche (Android 13+) e voce batteria
distinti da quelli di Chrome. Annotato nei limiti noti.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,15 @@ qui: sta in [ROADMAP.md](ROADMAP.md).
|
||||
|
||||
## Versione attuale — agosto 2026
|
||||
|
||||
### Le notifiche push arrivano anche ad app chiusa
|
||||
|
||||
- Il testo della notifica viaggia ora cifrato **dentro** la push (`aes128gcm`, RFC 8291)
|
||||
invece di essere recuperato dal service worker con una fetch al risveglio: era quella fetch
|
||||
a non arrivare mai in tempo a telefono bloccato, e la notifica non compariva affatto
|
||||
(DD-026).
|
||||
- Spariscono la route `/api/public/push-messaggio`, la coda `promemoria_push` e
|
||||
`messaggioPalloniOggi()`: esistevano solo per rimediare al payload vuoto.
|
||||
|
||||
### Lo Scout Live si apre dalla pagina della partita
|
||||
|
||||
- Tolto dalla home, era rimasto senza nessun link: `/scout` si raggiungeva solo scrivendo
|
||||
|
||||
+1
-1
@@ -73,7 +73,7 @@ La tabella è verificata da `test/integration/permessi.test.ts` contro il databa
|
||||
| -------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `turni_palloni` | Gestione dei turni palloni. | Solo turni **confermati**. Gli allenamenti non ricevono proposta automatica (vedi [palloni.md](modules/palloni.md)); M10 azzera i turni salvati su allenamenti da oggi in poi. |
|
||||
| `push_subscriptions` | Dispositivi registrati per le notifiche Push. | |
|
||||
| `promemoria_push` | Storico dei promemoria inviati. | |
|
||||
| `promemoria_push` | Non più usata. | Serviva da coda del testo quando la push partiva vuota; dal payload cifrato non la scrive né la legge nessuno. Tabella ancora presente, da eliminare con una migrazione. |
|
||||
|
||||
## Funzioni speciali
|
||||
|
||||
|
||||
+57
-10
@@ -41,6 +41,7 @@ Serve a rispondere a domande del tipo:
|
||||
| [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 |
|
||||
|
||||
**In valutazione**
|
||||
|
||||
@@ -843,8 +844,9 @@ i chiamanti sono diversi (`src/lib/auth-route.server.ts`):
|
||||
- `promemoria-palloni` → all'inizio `richiediSegreto`, con un segreto da cron; sostituito
|
||||
subito dopo da `richiediAdmin` quando la route è diventata manuale (DD-025).
|
||||
|
||||
`csi`, `push-config`, `push-subscribe` e `push-messaggio` restano aperte: le chiamano il
|
||||
browser prima del login e il service worker, dove qualsiasi segreto sarebbe pubblico.
|
||||
`csi`, `push-config` e `push-subscribe` restano aperte: le chiama il browser prima del login,
|
||||
dove qualsiasi segreto sarebbe pubblico. (`push-messaggio` esisteva per lo stesso motivo ed è
|
||||
sparita con DD-026.)
|
||||
|
||||
**Alternative scartate**
|
||||
|
||||
@@ -894,10 +896,9 @@ riquadro palloni della pagina evento. La route accetta un `eventoId` e avvisa i
|
||||
corrente. Il controllo di accesso diventa `richiediAdmin` come le altre due, e
|
||||
`richiediSegreto` con la sua variabile `CRON_SEGRETO` spariscono.
|
||||
|
||||
Il testo dell'avviso viaggia in coda su `promemoria_push`: la push parte vuota e il service
|
||||
worker chiede a `push-messaggio` cosa mostrare, ma quella route sa raccontare solo la giornata
|
||||
corrente. Senza la coda, un avviso mandato il martedì per il sabato arriverebbe con il testo
|
||||
generico.
|
||||
Il testo dell'avviso viaggia dentro la push, cifrato nel payload (DD-026): il service worker
|
||||
lo mostra così com'è, quindi un avviso mandato il martedì per il sabato arriva col testo
|
||||
giusto.
|
||||
|
||||
**Alternative scartate**
|
||||
|
||||
@@ -907,19 +908,65 @@ generico.
|
||||
- Tenere il cron e configurarlo davvero → più lavoro, una variabile d'ambiente da gestire in
|
||||
ogni ambiente, e nessuno l'aveva chiesto. Un pulsante che funziona batte uno scheduler che
|
||||
non esiste.
|
||||
- Calcolare il testo al volo come fa `messaggioPalloniOggi` → funziona solo se l'avviso parte
|
||||
il giorno stesso, cioè proprio il vincolo da cui volevamo uscire.
|
||||
- Calcolare il testo al volo sulla giornata corrente → funziona solo se l'avviso parte il
|
||||
giorno stesso, cioè proprio il vincolo da cui volevamo uscire.
|
||||
|
||||
**Conseguenze**
|
||||
|
||||
- Il promemoria è ora una scelta consapevole di un admin, non un automatismo: se nessuno preme
|
||||
il pulsante, non parte niente. È un passo indietro rispetto all'idea originale, ma un passo
|
||||
avanti rispetto alla realtà, dove non partiva mai.
|
||||
- `destinatariPromemoriaPalloni()` non è più usata dalla route ma resta in `palloni-core.ts`,
|
||||
perché `push-messaggio` continua a costruire il testo della giornata per le push senza coda.
|
||||
- `destinatariPromemoriaPalloni()` non è più usata dalla route ma resta in `palloni-core.ts`.
|
||||
- Sparisce `CRON_SEGRETO`: nessuna variabile d'ambiente nuova da configurare in nessun
|
||||
ambiente.
|
||||
|
||||
**Riesame**
|
||||
Se la squadra si accorge che l'admin si dimentica di premere il pulsante. A quel punto il cron
|
||||
torna utile, e con lui il segreto: DD-024 descrive già come farlo.
|
||||
|
||||
---
|
||||
|
||||
### DD-026 — Il testo della notifica viaggia dentro la push
|
||||
|
||||
**Stato:** accettata · **Data:** settembre 2026
|
||||
|
||||
**Contesto**
|
||||
Le push partivano senza payload: il service worker, appena svegliato, chiedeva a
|
||||
`/api/public/push-messaggio` che cosa mostrare. Ad app aperta funzionava; ad app chiusa e
|
||||
telefono bloccato non arrivava niente. È lo scenario per cui il browser dà al worker pochi
|
||||
secondi di vita: una fetch verso un endpoint che interroga Supabase è esattamente ciò che non
|
||||
riesce a chiudersi in tempo, e senza `showNotification` non compare nulla. `Urgency: high` e
|
||||
un timeout di 3 secondi sul recupero del testo avevano attenuato il sintomo, non la causa.
|
||||
|
||||
**Decisione**
|
||||
Titolo e testo viaggiano cifrati nel corpo della push (`aes128gcm`, RFC 8188/8291) con le
|
||||
chiavi `p256dh` e `auth` già salvate in `push_subscriptions`. Il service worker legge
|
||||
`event.data.json()` e mostra la notifica: zero rete, zero attesa.
|
||||
|
||||
Cadono di conseguenza la route `push-messaggio`, la coda `promemoria_push` (con la sua
|
||||
scadenza a 12 ore), `messaggioPalloniOggi()` e il timeout nel service worker: tutti pezzi che
|
||||
esistevano solo per rimediare al payload vuoto. Tutti e tre i mittenti
|
||||
(`apri-sondaggio`, `sollecita-presenze`, `promemoria-palloni`) avevano già il testo pronto
|
||||
prima di inviare.
|
||||
|
||||
**Alternative scartate**
|
||||
|
||||
- Usare la libreria `web-push` → dipende da `node:crypto`, e il build nitro ha come target
|
||||
Cloudflare. La cifratura sta in ~40 righe di Web Crypto, già disponibile ovunque.
|
||||
- Allungare ancora il timeout della fetch → allunga anche il tempo in cui il worker può
|
||||
morire prima di mostrare qualcosa. Il problema era la fetch, non la sua durata.
|
||||
|
||||
**Conseguenze**
|
||||
|
||||
- La notifica non dipende più dalla rete al momento del risveglio, e nemmeno da una funzione
|
||||
serverless che risponda in fretta a freddo.
|
||||
- Sparisce l'unico punto in cui chiunque conoscesse un endpoint push poteva leggere il
|
||||
messaggio destinato a quel dispositivo.
|
||||
- Il payload sta sotto i 4 KB: i testi attuali sono ampiamente dentro, ma un messaggio molto
|
||||
lungo andrebbe accorciato.
|
||||
- La tabella `promemoria_push` resta nel database, ora inutilizzata: va rimossa con una
|
||||
migrazione quando si tocca lo schema.
|
||||
|
||||
**Riesame**
|
||||
Se servisse mandare payload più grandi del limite del protocollo, o se un servizio push
|
||||
smettesse di accettare corpi cifrati (nessuno lo fa: è lo standard).
|
||||
|
||||
@@ -5,6 +5,9 @@ Solo il lavoro in corso o imminente. L'elenco completo delle funzionalità previ
|
||||
|
||||
## In corso
|
||||
|
||||
- Correzione push Android pronta in locale: aggiornamento del worker nelle sessioni della
|
||||
webapp e test del canale cifrato verificati. Resta la verifica su Motorola installato,
|
||||
ad app chiusa e schermo bloccato; procedura e limiti in [Notifiche](modules/notifiche.md).
|
||||
- Documentazione tecnica del progetto.
|
||||
- Autenticazione Google e dashboard amministratore: il codice è in produzione su `main` e il
|
||||
login è l'unica via d'accesso. La migration M4, che chiude gli accessi `anon` alle
|
||||
|
||||
+60
-33
@@ -3,7 +3,7 @@
|
||||
**Stato:** implementato — un unico opt-in dispositivo abilita tutto il canale push
|
||||
**File principali:** `src/lib/notifiche-smart.ts`, `src/lib/push-client.ts`,
|
||||
`src/lib/webpush.server.ts`, `src/routes/api/public/push-config.ts`,
|
||||
`src/routes/api/public/push-messaggio.ts`, `src/routes/api/public/push-subscribe.ts`,
|
||||
`src/routes/api/public/push-subscribe.ts`, `src/routes/api/public/push-prova.ts`,
|
||||
`public/push-sw.js`
|
||||
|
||||
---
|
||||
@@ -21,9 +21,9 @@ indipendenti:
|
||||
|
||||
## Dati
|
||||
|
||||
`push_subscriptions` (un dispositivo per riga, chiave `endpoint`), `promemoria_push` (coda
|
||||
"consuma e cancella" del testo da mostrare — nonostante il nome, **non** è uno storico
|
||||
persistente: la riga viene eliminata non appena letta dal service worker).
|
||||
`push_subscriptions` (un dispositivo per riga, chiave `endpoint`, con le chiavi `p256dh` e
|
||||
`auth` con cui si cifra il payload per quel dispositivo). La tabella `promemoria_push` non è
|
||||
più usata da nessuno: serviva da coda del testo quando la push partiva vuota (DD-026).
|
||||
|
||||
---
|
||||
|
||||
@@ -40,24 +40,45 @@ smart in app, che usano lo stesso service worker.
|
||||
4. `POST /api/public/push-subscribe` registra endpoint e chiavi in `push_subscriptions`
|
||||
(upsert).
|
||||
|
||||
All'avvio e quando l'app torna visibile viene richiesto l'aggiornamento della registrazione
|
||||
push esistente con `ServiceWorkerRegistration.update()`. Non si chiede un nuovo permesso,
|
||||
non si ricrea la sottoscrizione e non si cambia l'endpoint: anche chi ha già attivato le
|
||||
notifiche deve ricevere le correzioni del worker senza spegnere e riaccendere l'interruttore.
|
||||
Gli aggiornamenti contemporanei sono accorpati; un errore di rete non blocca l'app e si
|
||||
riprova al ritorno in primo piano. Il worker attende `skipWaiting()` durante l'installazione.
|
||||
Il browser controlla anche autonomamente gli aggiornamenti: questa richiesta esplicita
|
||||
copre in particolare le sessioni lunghe della webapp (vedi il
|
||||
[ciclo di vita del service worker](https://web.dev/articles/service-worker-lifecycle)).
|
||||
|
||||
---
|
||||
|
||||
## Ruolo delle tre route pubbliche
|
||||
|
||||
- **`push-config`** — espone la sola chiave pubblica VAPID.
|
||||
- **`push-subscribe`** — registra o rimuove l'iscrizione di un dispositivo.
|
||||
- **`apri-sondaggio`** — premuto da un admin dalla pagina partita: mette in coda su
|
||||
`promemoria_push` l'avviso di apertura del sondaggio pre-partita per **tutti** i dispositivi
|
||||
iscritti e manda la push (vedi [Scout Live](scout-live.md)).
|
||||
- **`push-messaggio`** — non invia nulla: il service worker la interroga **al momento della
|
||||
ricezione** di una push (che arriva sempre "vuota", senza testo, per compatibilità) per
|
||||
sapere quale messaggio mostrare. Priorità: un messaggio in coda su `promemoria_push`
|
||||
(scritto da `sollecita-presenze`, vedi [Presenze](presenze.md)), altrimenti il messaggio
|
||||
calcolato al volo sul turno palloni (vedi [Palloni](palloni.md)).
|
||||
- **`push-prova`** — manda una push al dispositivo che la chiede e riporta stato e corpo
|
||||
della risposta del servizio push, più se l'endpoint risulta in `push_subscriptions`. Serve
|
||||
a rendere osservabile un "non arriva": senza, ogni prova richiede un admin, un evento nello
|
||||
stato giusto e una seconda persona. Il pulsante sta in Profilo → Opzioni, sotto
|
||||
l'interruttore, e compare solo a notifiche attive.
|
||||
- **`apri-sondaggio`** — premuto da un admin dalla pagina partita: manda a **tutti** i
|
||||
dispositivi iscritti l'avviso di apertura del sondaggio pre-partita (vedi
|
||||
[Scout Live](scout-live.md)).
|
||||
|
||||
L'invio effettivo (`src/lib/webpush.server.ts`, funzione `inviaPush`) firma un JWT VAPID
|
||||
(ECDSA P-256) e fa una POST senza corpo all'endpoint push del browser; è riusato identico da
|
||||
`sollecita-presenze.ts` e `promemoria-palloni.ts`.
|
||||
(ECDSA P-256), cifra `{title, body}` per il dispositivo destinatario e fa una POST
|
||||
all'endpoint push del browser; è riusato identico da `sollecita-presenze.ts`,
|
||||
`promemoria-palloni.ts` e `apri-sondaggio.ts`.
|
||||
|
||||
Il testo viaggia **dentro** la push, cifrato in `aes128gcm` (RFC 8188/8291) con le chiavi del
|
||||
dispositivo: il service worker fa `event.data.json()` e mostra la notifica senza toccare la
|
||||
rete. È il punto decisivo per la consegna ad app chiusa — il browser sveglia il worker per
|
||||
pochi secondi, e una fetch per recuperare il testo lo faceva morire prima di
|
||||
`showNotification` (DD-026).
|
||||
|
||||
La POST porta `Urgency: high`. Con l'urgenza predefinita ("normal") un telefono in risparmio
|
||||
energetico accumula i messaggi fino al risveglio: la notifica arriva solo quando il
|
||||
dispositivo è già attivo — cioè, nella pratica, solo con l'app aperta.
|
||||
|
||||
### Chi può farle partire (DD-024, DD-025)
|
||||
|
||||
@@ -66,10 +87,10 @@ route. Tutte e tre partono da un gesto di un amministratore dentro l'app, quindi
|
||||
è uno solo (`richiediAdmin` in `src/lib/auth-route.server.ts`) e non serve configurare nessuna
|
||||
variabile d'ambiente.
|
||||
|
||||
| Route | Controllo | Chi la chiama |
|
||||
| ------------------------------------------------------------ | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
|
||||
| `apri-sondaggio`, `sollecita-presenze`, `promemoria-palloni` | `richiediAdmin` — token della sessione Supabase, poi ruolo `admin` in `user_roles` | l'app, da un pulsante riservato agli admin |
|
||||
| `csi`, `push-config`, `push-subscribe`, `push-messaggio` | nessuno | il browser prima del login e il service worker, che una sessione non ce l'hanno |
|
||||
| Route | Controllo | Chi la chiama |
|
||||
| ------------------------------------------------------------ | ---------------------------------------------------------------------------------- | --------------------------------------------------------------- |
|
||||
| `apri-sondaggio`, `sollecita-presenze`, `promemoria-palloni` | `richiediAdmin` — token della sessione Supabase, poi ruolo `admin` in `user_roles` | l'app, da un pulsante riservato agli admin |
|
||||
| `csi`, `push-config`, `push-subscribe`, `push-prova` | nessuno | il browser prima del login, che una sessione non ce l'ha ancora |
|
||||
|
||||
---
|
||||
|
||||
@@ -87,34 +108,40 @@ ripetersi — deduplica puramente locale al dispositivo, non sincronizzata.
|
||||
|
||||
- Non ci sono preferenze granulari (solo palloni / solo presenze / solo smart): un dispositivo
|
||||
è iscritto o no. Separare i canali richiederebbe schema e UI dedicati.
|
||||
- `promemoria_push` è descritta altrove come "storico" ma nel codice è una coda che si
|
||||
autocancella alla lettura: non conserva nulla. Un messaggio in coda **scade dopo 12 ore**
|
||||
(`ORE_VALIDITA_PROMEMORIA`): la riga si cancella comunque alla prima lettura, ma se è
|
||||
vecchia il testo non viene mostrato e si ripiega su quello calcolato. Serve perché la coda
|
||||
si svuota solo quando il dispositivo legge, e se la push non arriva mai la riga resterebbe
|
||||
a dirottare la notifica successiva, di qualunque tipo, giorni dopo.
|
||||
- La tabella `promemoria_push` è rimasta nel database ma non la usa più nessuno (DD-026): va
|
||||
eliminata con una migrazione alla prossima occasione.
|
||||
- **Un 2xx dal server push non significa consegnato.** FCM accetta con 201 anche verso
|
||||
registrazioni scadute e poi butta via il messaggio, senza il 404/410 che farebbe pulire
|
||||
`push_subscriptions`. Il conteggio "inviate a N dispositivi" va letto come "accettate da N
|
||||
server push", non come "arrivate a N telefoni".
|
||||
- Nessuna verifica di autenticazione su `push-messaggio`: chiunque conosca un endpoint push
|
||||
valido può leggerne il messaggio. Non è chiudibile con un segreto, perché a chiamarla è il
|
||||
service worker, dove qualsiasi segreto sarebbe pubblico; di fatto la protegge il dover
|
||||
conoscere l'endpoint, che è un URL segreto per dispositivo. `promemoria-palloni` invece è
|
||||
chiusa da DD-024.
|
||||
- Compatibilità iOS/Safari non gestita esplicitamente nel codice (nessun branch dedicato):
|
||||
serve l'installazione da schermata Home per funzionare, ma l'app non lo segnala
|
||||
esplicitamente.
|
||||
esplicitamente. È il primo sospetto quando una notifica non arriva ad app chiusa su iPhone.
|
||||
- **Android con l'app installata (WebAPK) è il caso fragile.** A parità di server — stessa
|
||||
push, stesso payload — su iPhone installato da Home arriva ad app chiusa, sullo stesso
|
||||
invio verso un Android installato come webapp no. Il WebAPK è un'app Android a sé: ha un
|
||||
proprio permesso notifiche di sistema. Le restrizioni di sistema possono impedire la
|
||||
visualizzazione o ritardare il risveglio del browser: un 201 dal servizio push non permette
|
||||
di distinguerli. Controllare Impostazioni → App → **CrAPP** → Notifiche e le eventuali
|
||||
restrizioni di batteria dell'app e del browser.
|
||||
- Su Motorola verificare anche le restrizioni del **browser che ha installato CrAPP** e,
|
||||
dove presente, Impostazioni → Batteria → Ottimizzazione standby app. Il produttore
|
||||
documenta la limitazione dei processi in background
|
||||
([guida Motorola](https://help.motorola.com/hc/3505/14/global/en-us/CG2007980805.html)).
|
||||
È una possibile causa del sintomo, non una diagnosi verificata sul dispositivo: il
|
||||
codice web non può rimuovere questi vincoli. La verifica richiede un invio da un altro
|
||||
dispositivo mentre CrAPP è chiusa e lo schermo del Motorola è bloccato. Il pulsante di
|
||||
prova invia subito, quindi da solo non dimostra la ricezione in background.
|
||||
- Le notifiche smart dipendono da un service worker già registrato: se il giocatore non ha
|
||||
mai attivato le push, `notificaSistema()` non ha un `reg` a cui appoggiarsi e la notifica
|
||||
locale non viene mai mostrata, anche con permesso concesso.
|
||||
- Payload push sempre vuoto: ogni notifica richiede una fetch aggiuntiva (`push-messaggio`)
|
||||
per ottenere il testo, quindi serve rete disponibile anche solo per mostrare il messaggio.
|
||||
- Il payload cifrato non può superare i ~4 KB: i testi attuali stanno larghi, ma un messaggio
|
||||
molto lungo verrebbe rifiutato dal servizio push.
|
||||
|
||||
---
|
||||
|
||||
## Evoluzioni possibili
|
||||
|
||||
- Preferenze per canale (palloni, solleciti, smart), se servono davvero alla squadra.
|
||||
- Aggiungere autenticazione alle route pubbliche coinvolte.
|
||||
- Eliminare `promemoria_push` con una migrazione.
|
||||
- Gestire esplicitamente il caso iOS (messaggio se l'app non è installata da Home).
|
||||
|
||||
@@ -48,10 +48,8 @@ e `avvisiPalloniEvento()` calcola i due destinatari di _quell'evento_: chi deve
|
||||
palloni e chi deve **riportarli** (l'incaricato dell'evento precedente), con un testo diverso
|
||||
per ciascuno.
|
||||
|
||||
Il testo va messo in coda su `promemoria_push` prima di inviare la push, perché la push parte
|
||||
"vuota" e il service worker chiede a `/api/public/push-messaggio` cosa mostrare — e quella
|
||||
route da sola sa raccontare solo la giornata corrente, quindi un avviso mandato con giorni di
|
||||
anticipo arriverebbe con il testo generico. Stesso meccanismo di `apri-sondaggio` (vedi
|
||||
Titolo e testo viaggiano cifrati dentro la push, quindi il service worker li mostra senza
|
||||
nessuna chiamata di rete. Stesso meccanismo di `apri-sondaggio` (vedi
|
||||
[Notifiche](notifiche.md)).
|
||||
|
||||
---
|
||||
@@ -60,8 +58,7 @@ anticipo arriverebbe con il testo generico. Stesso meccanismo di `apri-sondaggio
|
||||
|
||||
- **L'invio è manuale**: nessun cron manda il promemoria da solo, se l'admin non preme il
|
||||
pulsante non parte niente (DD-025). `destinatariPromemoriaPalloni()` — la versione "chi è di
|
||||
turno oggi" — resta in `palloni-core.ts` perché la usa `push-messaggio` per il testo
|
||||
calcolato al volo, ma nessuno scheduler la interroga.
|
||||
turno oggi" — resta in `palloni-core.ts` ma non la chiama più nessuno.
|
||||
- Il conteggio dei turni include anche le proposte non confermate: badge e statistiche
|
||||
possono contare turni mai effettivamente convalidati da nessuno.
|
||||
- La rotazione non considera le assenze dichiarate: può proporre il turno a chi ha risposto
|
||||
|
||||
@@ -54,7 +54,7 @@ Bottone "Sollecita" (RosaPresenze.tsx) → POST /api/public/sollecita-presenze
|
||||
src/routes/api/public/sollecita-presenze.ts
|
||||
├─ legge l'evento (eventi_app) e le risposte già date
|
||||
├─ calcola i destinatari: giocatori attivi senza risposta o con "forse"
|
||||
├─ per ciascuno registra il messaggio in promemoria_push e invia una push
|
||||
├─ per ciascuno invia una push col testo cifrato nel payload
|
||||
│ (src/lib/webpush.server.ts)
|
||||
└─ elimina le iscrizioni push scadute (404/410)
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user