«Tesseramento» nominava lo scopo invece del contenuto (dati personali, documento, certificato medico, foto tessera); cambia anche la rotta in /profilo?tab=documenti. «Impostazioni» diventa «Opzioni» così le quattro etichette stanno in uno schermo da telefono: le voci della barra si dividono la riga in parti uguali (grow basis-0) e tornano a scorrere solo se non ci stanno, quindi vale anche per Squadra e Classifica. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
4.3 KiB
Modulo — Notifiche
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,
public/push-sw.js
Obiettivo
Tenere aggiornati i giocatori senza che debbano aprire l'app, con due meccanismi indipendenti:
- Push VAPID — arrivano anche ad app chiusa (turno palloni, sollecito presenze).
- Notifiche smart — notifiche locali mostrate solo ad app aperta, generate da badge, serie e obiettivi appena raggiunti; non è un canale push separato.
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).
Iscrizione alle notifiche push
In Profilo → Opzioni c’è un solo interruttore («Notifiche»). Non esistono preferenze separate per tipo di messaggio: l’iscrizione registra il dispositivo e lo rende destinatario di tutte le push (promemoria palloni, solleciti presenze) e abilita anche le notifiche smart in app, che usano lo stesso service worker.
- Il giocatore attiva «Notifiche» in
/profilo→ richiesta permesso browser. GET /api/public/push-configrestituisce solo la chiave pubblica VAPID.- Registrazione del service worker
public/push-sw.jsepushManager.subscribe(). POST /api/public/push-subscriberegistra endpoint e chiavi inpush_subscriptions(upsert).
Ruolo delle tre route pubbliche
push-config— espone la sola chiave pubblica VAPID.push-subscribe— registra o rimuove l'iscrizione di un dispositivo.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 supromemoria_push(scritto dasollecita-presenze, vedi Presenze), altrimenti il messaggio calcolato al volo sul turno palloni (vedi Palloni).
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.
Notifiche smart
calcolaNotifiche() (notifiche-smart.ts) genera un evento solo quando "c'è qualcosa di
reale": badge appena sbloccato, "sei a un passo" da un traguardo, serie che raggiunge un
traguardo esatto, obiettivo di squadra tra il 90 e il 100%, badge social vinto. Ogni notifica
ha un id deterministico; quelli già mostrati sono salvati in localStorage per non
ripetersi — deduplica puramente locale al dispositivo, non sincronizzata.
Limiti noti
- 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.- Nessuna verifica di autenticazione su
push-messaggio(chiunque conosca un endpoint push valido può leggerne il messaggio) né supromemoria-palloni. - 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.
- Le notifiche smart dipendono da un service worker già registrato: se il giocatore non ha
mai attivato le push,
notificaSistema()non ha unrega 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.
Evoluzioni possibili
- Preferenze per canale (palloni, solleciti, smart), se servono davvero alla squadra.
- Aggiungere autenticazione alle route pubbliche coinvolte.
- Gestire esplicitamente il caso iOS (messaggio se l'app non è installata da Home).