Commit Graph
6 Commits
Author SHA1 Message Date
davideandClaude Sonnet 5 242941740b Cappa le vittorie di "10 vittorie in campionato" e completa la copertura test
o5 non aveva il Math.min(vittorie, 10) dei fratelli o3/o4: il progresso
mostrato non cambiava (già cappato al 100%), ma il valore grezzo sì, mostrato
senza cap in squadra.tsx/index.tsx (es. "15/10 vittorie" invece di "10/10").

Nessuno dei tre obiettivi aveva test. Le vittorie non toccano Supabase -
arrivano dal portale CSI via /api/public/csi - quindi l'integration test
estende test/integration/api.test.ts (che già chiama quella route dal vivo)
invece di test/integration/obiettivi.test.ts, verificando o3/o4/o5 sui dati
CSI reali del giorno.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 12:01:43 +02:00
davideandClaude Opus 5 fb6bde279e Toglie la notifica di prova dalle Opzioni.
Era impalcatura per diagnosticare "le push non arrivano": ha fatto il suo
lavoro, la causa e' documentata nei limiti noti. Lasciare il pulsante avrebbe
tenuto in piedi anche la route push-prova e notificaDiProva, senza piu' nessuno
che le usa.

Via il pulsante, la funzione client, la route e i test che la coprivano. Resta
in git se dovesse servire di nuovo.

inviaPush continua a tornare { stato, corpo } e a loggare i rifiuti: serve alle
tre route che mandano notifiche, non solo alla prova.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 15:16:41 +02:00
davideandClaude Opus 5 d8f334007b 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>
2026-09-06 14:24:07 +02:00
davideandClaude Opus 5 ee9f3f1b8c Il promemoria palloni lo manda un admin dalla pagina evento (DD-025).
La route era disegnata per un cron quotidiano: calcolava chi è di turno oggi e
gli mandava una push. Ma nel repository nessun cron esiste, e palloni.md lo
annotava già come "da verificare lato hosting": nei fatti quel promemoria non è
mai partito. Il segreto condiviso introdotto ieri proteggeva una porta che
nessuno apriva, al prezzo di una variabile d'ambiente da configurare ovunque.

Ora la fa partire un amministratore dal pulsante "Avvisa chi è di turno", dentro
il riquadro palloni dell'evento. La route accetta un eventoId e avvisa i
destinatari di quell'evento invece della giornata corrente: chi deve prendere i
palloni e chi deve riportarli, con un testo diverso per ciascuno. Stesso
precedente di apri-sondaggio, manuale fin dalla v1.0.6.

Il testo va in coda su promemoria_push prima dell'invio. Serve: la push parte
vuota e il service worker chiede a push-messaggio cosa mostrare, ma quella route
sa raccontare solo la giornata corrente, quindi un avviso mandato il martedì per
il sabato arriverebbe con il testo generico.

avvisiPalloniEvento() è la nuova funzione pura, con i suoi test: due destinatari
con testi diversi, un avviso solo quando sono la stessa persona, niente avvisi
per un evento inesistente o senza turni. Un'asserzione verifica che il testo non
dica mai "oggi", perché può arrivare giorni prima.

richiediSegreto e CRON_SEGRETO spariscono: tutte e tre le route di notifica
usano ora richiediAdmin, e non resta nessuna variabile da configurare.
destinatariPromemoriaPalloni() resta in palloni-core.ts con i suoi test perché
push-messaggio continua a usarla per il testo calcolato al volo.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 12:15:39 +02:00
davideandClaude Opus 5 847972b582 Chiede le credenziali alle route che avvisano tutta la squadra (DD-024).
Le route in src/routes/api/public/ girano con la service role e saltano la RLS,
quindi DD-023 non le copre. Nessuna faceva un controllo di accesso: cercando
"authorization" in quella cartella l'unico header era lo User-Agent con cui
csi.ts chiama il portale CSI. Chiunque conoscesse l'URL poteva far suonare i
telefoni della squadra, e promemoria-palloni accetta perfino una POST con il
corpo vuoto.

La difesa apparente delle altre due — serve un id evento valido — non è una
difesa: l'id è "e" più il timestamp in base 36, compare negli URL che la squadra
si scambia ed è elencabile da qualsiasi utente loggato.

auth-route.server.ts porta i due controlli, diversi perché i chiamanti sono
diversi. apri-sondaggio e sollecita-presenze usano richiediAdmin: token della
sessione verificato con auth.getUser, poi ruolo admin da user_roles, la stessa
fonte di ruoli.ts. Il controllo precede la validazione dell'input, così la
risposta non rivela nemmeno se un evento esiste. promemoria-palloni usa
richiediSegreto, perché la chiama un cron che una sessione non ce l'ha: se
CRON_SEGRETO non è configurata la route resta chiusa con 503, perché una porta
che si riapre da sola quando manca una variabile non se ne accorge nessuno.

csi, push-config, push-subscribe e push-messaggio restano aperte: le chiamano il
browser prima del login e il service worker, dove qualsiasi segreto finirebbe
nel bundle.

Lato client i due pulsanti admin mandano il token con intestazioniAutenticate(),
letto al momento della chiamata e non da uno stato React.

permessi-route.test.ts copre il giro intero — nessun token, giocatore, admin —
avviando il server di sviluppo puntato al database locale, perché servono utenti
veri. Il controllo positivo è il 404: l'admin supera l'accesso e arriva alla
validazione. In api.test.ts restano i rifiuti che non richiedono un utente e
sparisce la verifica della validazione di sollecita-presenze, che ora sta dietro
all'accesso.

I limiti noti di palloni.md sono aggiornati: il secret che il piano originale
prevedeva ora c'è. Resta vero che nessun cron chiama la route, quindi il
promemoria quotidiano non parte da solo.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 12:05:39 +02:00
davideandClaude Opus 5 af563603f9 Add a test suite for the domain logic and the server routes.
The project had no automated verification at all, so the "Test" step in
the AGENTS.md workflow rested entirely on clicking through the app.

The suite runs on bun with node:assert and adds no dependency: every file
is a script that exits non-zero when a check fails, and test/run.ts runs
each one in its own process. Unit tests cover the rules that decide what
players see (badges, streaks, ball duty rotation, ratings, MVP ties,
scouting totals, goals, notifications, CSI parsing); integration and
end-to-end tests drive the real dev server. Nothing writes to the
database, so both can be pointed at a live environment.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 13:07:41 +02:00