Per ogni convocato un − o un + su battuta, ricezione, attacco e muro, separato per set e
fuori dal punteggio (DD-053, migration m39: colonna scout_partite.valutazioni). Lo stato in
corso le salva in scout_live.stato; il CSV admin ha la tabella per set.
Nella pagina dello scout tolti il blocco avversario/campo, i tasti delle azioni e il
tabellone del punteggio; il titolo della sezione mostra cognome e numero del giocatore.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Integrazione (permessi, permessi-allenatore, mvp-badge, s-tiebreak-badge), unit (mvp-voti) e helper
delle date di Roma. Con le parità l'MVP vale per tutti i pari merito.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Sezione 1.4.0 del CHANGELOG, versione in package.json e package-lock.json,
PROJECT_STATE aggiornato. Il test di presenza-modificata copre ora i confini
delle 6 ore, ogni stato, allenatore inattivo, admin senza slot, doppio ruolo e
ora dell'evento non valida. Documentazione delle notifiche allineata (riga 9,
copertura test, email, DATABASE). Nessuna nuova migration: la m32 e la m33 sono
applicate in produzione (09/10/2026).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Fine della fase di prova: la funzione avvisa admin e allenatori attivi. Test
aggiornato (l'allenatore ora è tra i destinatari), DD-050, notifiche, allenatore,
DATABASE, CHANGELOG, ROADMAP e PROJECT_STATE allineati. m33 non ancora applicata
in produzione.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Migration m32: tipo presenza_modificata, funzione e trigger su risposte_presenze
che avvisano gli admin attivi se una risposta cambia a 0-6 ore da una partita o
un allenamento (push, email e centro notifiche). Gli allenatori non la ricevono
finché dura la prova. Applicata in produzione il 09/10/2026.
Test di integrazione e unitario; DD-050, notifiche, DATABASE, CHANGELOG,
ROADMAP e PROJECT_STATE aggiornati (slot g18 ora giocatore).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Toglie la serie dal profilo, dalla Home e dalle notifiche di traguardo, insieme
ai badge «Risposta lampo» e «Mai un forfait» e al calcolo di serieConferme.
La colonna risposto_il e il suo trigger restano nel database, inutilizzati.
Test e documentazione allineati.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Ogni obiettivo di squadra apre un drawer che spiega come si calcola, cosa conta,
cosa è una presenza persa, cosa resta fuori, periodo, fonte dei dati ed esempio.
«90% di presenze del mese» usa ora i convocati dell'evento come posti (tutta la
rosa se non ce ne sono), come le presenze collettive: chi non è convocato non
abbassa più la percentuale. Test unit, card e integrazione; docs aggiornate.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Sostituisce «250 presenze complessive». Il valore è la percentuale di presenze
(presente o ritardo) su tutti gli allenamenti e le partite in calendario, passati
e futuri, con i convocati come posti (tutta la rosa se non ce ne sono). Stagione
intera, nessun reset mensile.
Test unitari ampliati (arrotondamento, convocati, ora legale, cambio mese) e test
di integrazione di o6 riallineato alla regola dell'ora dell'evento. Documentazione
e CHANGELOG aggiornati.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Ogni giorno, dalle 8:00 (Europe/Rome), un job pg_cron orario manda a chi compie
gli anni «Buon compleanno, <Nome>! 🎂» e a tutti gli altri membri attivi,
allenatori compresi, «Oggi è il compleanno di <Nome>» (con più compleanni lo
stesso giorno un solo messaggio a testa, nomi in ordine alfabetico). Solo
titolo, senza corpo né età. Canali: push, centro notifiche ed email.
- migration m31: tipi `compleanno` e `compleanno_auguri`, registro
`compleanni_notificati` (una sola volta per destinatario e giorno, anche se la
notifica viene eliminata), funzione `genera_avvisi_compleanno()` e job
`avvisi-compleanno`, trigger push esteso ai nuovi tipi. Non ancora applicata
in produzione.
- 29 febbraio non gestito: chi è nato quel giorno è avvisato solo negli anni
bisestili (limite noto, documentato).
- test: integrazione `notifiche-compleanno` (ora e ora legale, destinatari,
più compleanni, registro, coda push/email, 29 febbraio, job pianificato);
unit sui nuovi tipi e sul corpo vuoto del service worker.
- documentazione: DD-047, catalogo e testi delle notifiche, DATABASE, CHANGELOG,
ROADMAP, PROJECT_STATE.
Chiude la issue #11.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
La migration m30 riduce il job automatico alla sola fascia delle 24 ore:
il sollecito arriva una volta a chi non ha risposto o ha risposto «forse»,
anche per un evento creato a meno di 24 ore dall'inizio. Il pulsante
manuale «Sollecita» non cambia. I tipi sollecita_presenze_12h e _6h restano
ammessi per le notifiche già generate. Migration applicata in produzione.
Test di integrazione aggiornati; documentati DD-045, moduli notifiche,
presenze e allenatore, DATABASE, ROADMAP e changelog.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Il Profilo non chiede più la foto tessera e la scheda admin non la mostra.
Il completamento diventa dati personali 34%, documento 33%, certificato 33%.
La migration m29 elimina la colonna profili_giocatore.foto_path; le 4 foto
già caricate sono state cancellate dal bucket profili-giocatore. Migration
applicata in produzione.
Test: pesi e sezioni di profili-core, rendering di CampiProfilo, colonna
rimossa sul database locale. Documentati DD-044, modulo profilo-giocatore,
DATABASE, ROADMAP e changelog.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
La migration m28 toglie i due job pg_cron che generavano il promemoria
prima di ogni evento. Funzione, tipi, registro e notifiche già generate
restano. Migration applicata in produzione.
Nuovo test sui job non più pianificati; documentati DD-043, modulo
notifiche, DATABASE, ROADMAP, WORKER_EMAIL e changelog.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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>
- Spezza il registro delle decisioni in docs/decisions/DD-XXX.md, con indice
- Ripulisce DATABASE.md dalla storia delle migration e aggiunge la sezione Lettura
- Riduce PROJECT_STATE.md a una pagina; la procedura di allestimento passa in OPERATIONS.md
- Aggiunge OPERATIONS.md, GLOSSARIO.md, trappole note e checklist in ARCHITECTURE.md
- Sintetizza la copertura test di badge.md e documenta docs/archive
- Allinea AGENTS.md, README.md e la regola Cursor (tolto l'obbligo di develop, in contrasto con DD-019)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
I pulsanti «Avvisa chi è di turno» e «Sollecita» usano gli stessi testi dei job
del database. Il sollecito manuale segue i convocati e dice la risposta attuale
e chi lo ha chiesto. L'ordine degli eventi dei palloni diventa data, ora, id.
Le righe del corpo di una notifica vanno a capo nel centro notifiche.
Test unitari dei testi, dei destinatari e delle date; il test delle route
verifica testi, convocati e assenza di email per i palloni.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Promemoria con «oggi/domani», data, ora e luogo. Turno palloni a 12, 6 e 3 ore
per gli eventi con un incaricato confermato, con revoca una tantum se
l'incaricato cambia. Sollecito presenze a 24, 12 e 6 ore ai destinatari
dell'evento senza risposta o con «forse». Due job pg_cron ogni 15 minuti; push
dei tipi automatici dalla coda; nessuna email per il turno palloni.
Nuovo test di integrazione sui job veri del database; aggiornati i test di
promemoria, code push ed email.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
m25: giocatori_destinatari_evento() include solo i giocatori attivi, quindi
l'allenatore non riceve più i promemoria a 24 e 3 ore, per nessun tipo di
evento (fino alla m24 li riceveva sempre, DD-034). Riceve ancora i messaggi
dello staff.
Test: nuovo destinatari-notifiche.test.ts (14 controlli sulle route vere con un
servizio push finto: promemoria, messaggio dello staff, sondaggio, sollecito,
turno palloni, permessi di allenatore e giocatore) e aggiornato
permessi-allenatore. Documentazione: DD-039, tabella delle notifiche
dell'allenatore, catalogo e tabella dei test che lo verificano.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
m23: un registro (promemoria_eventi_generati) ricorda i promemoria a 24 e 3 ore
già generati, così eliminare la notifica non li fa rigenerare dal cron né
riaccodare la mail a ogni giro.
m24: la push dei promemoria, che nascono nel database, la manda il worker
mailer/ con lo stesso modulo dell'app (coda notifiche_push_coda, esiti, backoff,
iscrizioni scadute eliminate, push scartate oltre 3 ore). Il sondaggio
pre-partita scrive anche notifiche_utente (tipo sondaggio_cacche): compare
in-app e arriva per email. L'immagine del worker si costruisce dalla radice
del repository per includere src/lib/webpush.server.ts.
Test: 9 di integrazione per m23, 17 per la coda push, 6 per la route del
sondaggio, nuovi casi unitari sul worker; prova end-to-end con un servizio
push finto. Documentazione e catalogo delle notifiche aggiornati.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Migration m22: coda notifiche_email_coda, preferenze_utente, trigger che
accoda ogni notifica di notifiche_utente e tre funzioni RPC riservate
alla service role. Worker in mailer/ (bun + nodemailer, solo polling in
uscita) con backoff, tetto giornaliero e healthcheck. Interruttore
«Email» in Profilo → Opzioni, acceso di default. Test unit e di
integrazione; documentazione aggiornata (DD-036 accettata).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- Modello: tipo sugli slot, inRosa() al posto del filtro su attivo in tutte le
letture della rosa di gioco (presenze, convocati, voti, palloni, classifiche,
badge, sollecito); gli allenatori restano solo nei compleanni e in Squadra.
- Permessi: user_roles letto una volta per tutti i ruoli; usePuoGestireEventi()
apre /eventi e il sollecito presenze anche all'allenatore, lato server con
richiediGestoreEventi(). Palloni, sondaggio e messaggi restano all'admin.
- Identità: useGiocatoreInCampo() è null per l'allenatore, così non risponde alle
presenze e non vota; useSonoAllenatore() decide cosa si vede.
- Profilo: per l'allenatore solo Docs (nome, cognome, nascita, telefono, email) e
Opzioni; card avatar e tab Opzioni estratte per riusarle.
- Home, Squadra e partita: niente statistiche personali, badge, cacche e
obiettivi per l'allenatore; in Rosa compare con la dicitura «Allenatore».
- Admin: tipo in «Aggiungi», allenatori a parte in Profili, fuori da conteggi ed
export CSI.
Test unit su rosa di gioco e completamento, route test sull'allenatore.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
L'allenatore è uno slot di giocatori_squadra con tipo = 'allenatore' (DD-034):
- M20 aggiunge il valore allenatore ad app_role, da solo perché Postgres non lascia
usare un valore di enum nella transazione che lo crea;
- M21 aggiunge la colonna tipo, rende numero nullabile solo per gli allenatori,
blocca tipo nel trigger sugli slot e lascia all'allenatore nome e cognome del
proprio slot; un trigger tiene allineato il ruolo in user_roles al collegamento;
- eventi_app scrivibile da admin e allenatori; presenze, cacche e voti chiusi
all'allenatore; i promemoria evento lo includono sempre.
Compatibile con la 0.9.2: senza allenatori registrati non cambia nulla. Già
applicata in produzione con supabase db push; g18 «Beta Tester» è allenatore.
Il test permessi-allenatore verifica le regole contro il database locale.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- schema-profili: il test pretendeva che lo slot g1 fosse libero, ma in
produzione è collegato a un giocatore vero; ora verifica che il
tentativo anonimo non cambi il valore.
- rosa: il default dei voti MVP era fuori da useMemo e faceva ricalcolare
la rosa a ogni render finché i voti non erano caricati.
- test dei badge, profili-core, push-sw, scout-stato: tipi allineati al
codice (MappaPresenze, nascita da M18, renotify, narrowing di deepEqual).
- vite.config: tipizzato come UserConfig e rimosso esbuild.keepNames,
ignorato da Vite 8 che non usa più esbuild.
- formattazione Prettier in BarraSottosezioni e classifica.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
M19 era stato applicato in produzione senza copertura automatica, solo
verificato a mano. Il test simula un profilo compilato prima di M18 ed
esegue lo stesso SQL del backfill via psql, perché PostgREST non espone
un update multi-tabella come RPC.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Prima veniva mostrata solo per i 17 giocatori del seed storico: chi la
inseriva da sé restava con "Invalid Date" in Squadra, perché il dato
finiva solo in profili_giocatore (privato). Un trigger ora lo sincronizza
in giocatori_squadra.nascita, colonna pubblica a tutta la rosa.
Include il backfill dei profili già compilati prima di M18 (M19),
mancante nel push iniziale.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Icona a campana con badge delle non lette, indipendente dal canale push:
copre messaggio libero admin, promemoria evento (24h/3h prima), turno
palloni e sollecito presenze. Ogni notifica si rimuove con uno swipe o
la ×, non c'è pulizia automatica delle vecchie (DD-030).
Migration m17_notifiche_utente non ancora applicata in produzione.
Co-Authored-By: Claude Mythos <noreply@anthropic.com>
Nella tab Notifiche della dashboard admin è ora possibile mostrare anche i
giocatori senza notifiche attive e inviare un messaggio libero a tutta la
squadra o a un singolo giocatore, tramite un nuovo endpoint
/api/public/notifica-personalizzata che riusa lo stesso pattern di invio
delle altre route push admin.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Estrae la deduplica degli id giocatore in idsConNotificheAttive
(src/lib/notifiche-attive.server.ts), testata a livello unit. Aggiunge
un test di integrazione sui permessi della route (401/403/200), sullo
stesso schema di permessi-route.test.ts. Documenta il nuovo endpoint
in notifiche.md e la dashboard admin a tab in profilo-giocatore.md.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
In Campionato > Storico partite ogni gara diventa cliccabile: verso /partita/$id
se collegata a un evento CrAPP, verso la nuova /partita-csi/$id altrimenti (nessuna
creazione automatica di eventi dal calendario CSI, quindi molte gare ne sono prive).
Il dettaglio aggiunge formazioni (titolari/panchina/staff), storico scontri diretti
e probabilità di vittoria calcolata dal CSI, letti on-demand da tre nuovi endpoint
per-partita (match-main/players/stats.php) dietro /api/public/csi-partita/$id, con
cache server per-partita separata da quella di /api/public/csi — è un dato aperto a
richiesta, non precaricato per tutti come classifica e partite.
Include anche logo squadra e metadati leggeri (girone, n° gara, arbitro, link al
referto ufficiale) già presenti nel JSON esistente, a costo zero.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
parseClassifica() legge project-sheets.php?project_id=848 con lo stesso
parsing del girone di campionato (stessa struttura di tabella), quindi
nessun parser dedicato. La Coppa resta limitata alla fase a gironi: la
finale secca vive in un project_id figlio non tracciato dal codice.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Il test copriva solo 3 delle 9 istruzioni DELETE dentro
bonifica_dati_evento_orfani() (risposte_presenze, mvp_voti,
pagelle_voti), lasciando cacche_partita, turni_palloni,
scout_sessioni, scout_live, scout_partite e badge_social_voti senza
verifica automatica. Ora inserisce una riga orfana in tutte e sei le
tabelle evento_id e una riga orfana più due storiche (Scout, CSI) in
tutte e tre le tabelle match_id, verificando la stessa distinzione
delicata su ciascuna, non solo su un sottoinsieme.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
M15 ha ripulito una tantum le righe orfane con un blocco di DELETE
verificato solo a mano, senza lasciare nessuna rete di sicurezza
automatica per il futuro. Questa migration rende lo stesso corpo la
funzione bonifica_dati_evento_orfani(), riservata al service role, così
resta richiamabile se il trigger di M14 smettesse mai di funzionare.
Aggiunge test/integration/bonifica-evento.test.ts: inserisce una riga
orfana e una storica su id Scout/CSI, richiama la funzione via RPC e
verifica che tocchi solo la prima. Documenta l'aggiornamento in
DESIGN_DECISIONS.md (DD-029), DATABASE.md, test/README.md e CHANGELOG.md.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Un audit del modulo Obiettivi ha verificato che gli obiettivi non hanno
bisogno di pulizia: sono ricalcolati a runtime sull'elenco eventi
corrente. Il problema reale era un livello sotto: cancellare un evento
lasciava orfane le righe collegate in 8 tabelle (risposte_presenze,
cacche_partita, mvp_voti, pagelle_voti, badge_social_voti,
turni_palloni, scout_sessioni, scout_live, scout_partite), nessuna con
una foreign key verso eventi_app.
Aggiunge un trigger AFTER DELETE su eventi_app (migration
m14_pulizia_dati_evento_cancellato) invece di una FK con CASCADE, non
applicabile per dati storici disallineati (match_id che a volte punta
a id Scout/CSI). Verificato con un nuovo test di integrazione contro
il database locale; documentato in DESIGN_DECISIONS.md, DATABASE.md,
obiettivi-squadra.md, test/README.md e CHANGELOG.md.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Rimuove l'hint statico "+2 questo mese" dalla StatTile Presenze. La StatTile
Media voto usa ora la stessa soglia minima di voti del badge Pagellone
(VOTI_MINIMI_PAGELLA), tramite la nuova funzione pura testabile
mediaVotoColpoDOcchio(). L'MVP di partita richiede un quorum minimo di 2
voti totali (VOTI_MINIMI_MVP) oltre al margine netto già richiesto: un
solo voto non assegna più la vittoria, con effetto anche sui conteggi
già mostrati. Aggiorna test unitari e di integrazione, e documenta la
decisione in DESIGN_DECISIONS.md, pagelle.md, mvp.md e CHANGELOG.md.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Audit dedicato su tutti i 16 badge: s-tiebreak non applicava la soglia minima di
voti pagella di Pagellone sullo stesso campo mediaVoto (corretto), s-cacche
prometteva "partite di campionato" senza che il codice lo verificasse mai
(corretta la descrizione, comportamento invariato). Aggiunti test unit e
integration end-to-end mancanti su badge segreti e social, con dati scritti a
database anche per i cinque segreti che prima ne erano privi.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Analisi della logica di serieConferme() senza bug trovati; aggiunte le soglie
esplicite 3/8/15 e i rami mancanti (convocati ristretti, tipo misto, bordo
esatto delle 24h, evento futuro), più un integration test end-to-end che
verifica la mappatura creato_il/risposto_il con dati reali.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Il portale CSI (livescore.csibologna.it) è momentaneamente in manutenzione lato
loro (risponde con un errore SQL in chiaro al posto del JSON su
getEventsByTeamId.php). I 5 test che dipendono dal CSI reale ora sondano una
volta sola /api/public/csi: se non è raggiungibile vengono saltati con salta()
invece di fallire, senza toccare la loro logica né cancellarli — tornano a girare
non appena il portale è di nuovo su.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
rosa.ts calcolava Giocatore.palloni su completaTurni() (turni salvati + proposte
automatiche di rotazione non ancora confermate da nessuno): un giocatore poteva
avanzare nel badge senza aver mai confermato un turno, solo perché l'algoritmo lo
proponeva per un evento passato. Ora passa a conteggioTurni() solo turniSalvati
(i turni davvero confermati in turni_palloni); completaTurni() resta in uso solo
per la UI di rotazione (TurnoPalloni.tsx, PromemoriaPalloni.tsx). Corregge anche
la StatTile "quante volte hai portato i palloni" nel profilo, che leggeva lo
stesso valore.
Aggiornato palloni-badge.test.ts per verificare il nuovo comportamento (un evento
non confermato non conta più per nessuno) invece del vecchio. docs/modules/
badge.md e palloni.md aggiornati di conseguenza, spostando la voce da "Limiti
noti" a "risolto".
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Nessun bug trovato: serieConsecutiva() gestisce correttamente buco (azzera) vs
infortunio (congela senza azzerare), lo stesso filtro sui convocati della funzione
pura protegge anche questo badge senza bisogno dell'estensione RLS di M13.
Confermato che il limite noto "risposto_il non ricostruibile prima di m9" riguarda
solo serie-conferme e il segreto s-mai-forfait, non questo badge: serieConsecutiva()
guarda solo lo stato della risposta, non il suo istante.
Aggiunti test unit sulle soglie (badges.test.ts) e un nuovo end-to-end
(serie-allenamenti-badge.test.ts) che scrive allenamenti e risposte reali sul
database locale e verifica l'intera pipeline fetchPresenze()/daRiga() ->
serieConsecutiva() -> statoBadge() attraverso le tre soglie, incluso il caso "un
buco azzera" e, separatamente, "un infortunio congela invece di azzerare".
docs/modules/badge.md aggiornato con la pipeline, la copertura test e la
descrizione corretta (l'infortunio non spezza la serie).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Nessun bug trovato: contaPresenzeGiocatore() filtra correttamente per convocati,
tipo evento e stato (presente/ritardo contano, assente/forse no), gli eventi
futuri restano esclusi. Confermato che, a differenza di MVP/pagelle/badge social,
questo badge non ha bisogno dell'estensione RLS di M13: il filtro sui convocati è
già nella funzione pura, non solo in UI.
Aggiunti test unit sulle soglie (badges.test.ts) e un nuovo end-to-end
(presenze-badge.test.ts) che scrive eventi e risposte reali sul database locale e
verifica l'intera pipeline fetchPresenze()/daRiga() -> contaPresenzeGiocatore() ->
statoBadge() attraverso le tre soglie, incluso il caso "non convocato, la riga
esiste ma non conta". docs/modules/badge.md aggiornato con la pipeline, la
copertura test e la correzione della dicitura "in stagione" (il conteggio è
sull'intero storico, coerente con gli altri badge).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Nessun bug nella logica di calcolo: soglie 3/6/10 corrette, gradoRaggiunto()/
statoBadge() si comportano come per gli altri badge da contatore. Trovato però un
comportamento reale ma non ovvio (già accennato in palloni.md, mai dimostrato con
dati veri): il conteggio del badge include anche le proposte automatiche di
completaTurni() non ancora confermate da nessuno, non solo i turni salvati in
turni_palloni.
Aggiunti test unit sulle soglie (badges.test.ts) e un nuovo end-to-end
(palloni-badge.test.ts) che scrive eventi/turni parzialmente confermati sul
database locale e verifica l'intera pipeline fetchTurni() -> completaTurni() ->
conteggioTurni() -> statoBadge(), incluso il caso "evento futuro non conta".
docs/modules/badge.md aggiornato con la pipeline, la copertura test e il limite
noto.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
npx eslint --fix su test/unit/obiettivi.test.ts, test/integration/obiettivi.test.ts,
BarraSottosezioni.tsx, EventoCard.tsx e calendario.tsx — solo formattazione,
nessuna modifica di comportamento. Verificato con la suite unit (32/32 verde).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Il badge Pagellone si sblocca ora solo con almeno 5 pagelle ricevute
(VOTI_MINIMI_PAGELLA): un voto solo poteva sbloccarlo o farlo sparire senza
significatività statistica. Aggiunto Giocatore.votiPagella per farlo funzionare.
La migration m13 (DD-027) estende le policy RLS di M11 su pagelle_voti, mvp_voti e
badge_social_voti: votante e votato devono essere convocati all'evento (prima solo
un filtro applicativo), e per le pagelle anche pagelle_chiuse=false. Le policy
admin restano permissive di proposito. Applicata anche al progetto cloud.
Copertura test completa: unit sulla soglia minima, integration sulle nuove policy
RLS (permessi.test.ts) e un end-to-end reale (pagella-badge.test.ts) sul modello
di mvp-badge.test.ts.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Aggiunge il caso positivo RLS mancante per mvp_voti in permessi.test.ts e un nuovo
test end-to-end (mvp-badge.test.ts) che verifica l'intera pipeline voti reali ->
mvpVintiPerGiocatore() -> statoBadge(). docs/modules/badge.md ora elenca tutti e 16
i badge con come funzionano, la copertura test badge per badge e i due problemi
minori trovati in audit (badgeSbloccati() morta, categoria senza vincolo DB).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
Il target 12 non è un valore arbitrario da scalare con la rosa come gli altri
target fissi: è il minimo di giocatori per schierare due sestetti (6vs6) in
allenamento, confermato intenzionale. Documentato in
docs/modules/obiettivi-squadra.md.
Non aveva alcun test. Aggiunti unit test (rosa vuota, confine >= 3, target
fisso) e un integration test end-to-end che scrive tre allenamenti e presenze
reali sul database locale, calcola serieConsecutiva() (la stessa funzione pura
usata da useRosa() in produzione) sui dati riletti, e verifica il conteggio.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
C'era una sola asserzione (2 pagelle -> 2), nessun caso vuoto esplicito e
nessun integration test. Aggiunti il caso vuoto, il conteggio aggregato su
più match_id, e l'assert su o13 nell'integration test già scritto per la
media pagelle (stessi voti reali scritti su pagelle_voti, zero setup extra).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
o1 e o2 avevano solo test con un evento singolo per volta: mancavano rosa vuota
(divisione per zero), verifica che le partite contino come gli allenamenti con
eventi sociali/compleanni esclusi, e l'aggregazione su più eventi dello stesso
mese. Aggiunti unit e integration test per entrambi.
"Media pagelle da 7.5" aveva solo il caso vuoto e un caso che faceva già media
esatta: aggiunti test sull'arrotondamento a una cifra decimale e
sull'aggregazione di voti da più partite, più un integration test che scrive
voti veri su pagelle_voti rispettando i vincoli reali della tabella.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
C'era solo un confronto circolare (la stessa formula ricalcolata sugli stessi
dati reali) più il caso rosa vuota. Aggiunto un unit test con roster piccolo e
valori noti (5 + 10 + 15 = 30), e un integration test end-to-end che scrive
eventi/risposte veri sul database locale, calcola contaPresenzeGiocatore() (la
stessa funzione pura usata da useRosa() in produzione) sui dati riletti, e
verifica che obiettiviSquadra() sommi correttamente il risultato.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
La scadenza era una data fissa (2026-09-30), stesso problema già risolto per
"presenze del mese" e "evento di squadra al mese": ora segue l'ultimo giorno
del mese corrente. Aggiunti unit test e integration test end-to-end contro il
database locale (isolando gli eventi di test, perché questo obiettivo aggrega
su tutti gli eventi indipendentemente dal mese).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
"Presenze del mese" e "evento di squadra al mese" erano ancorati a una costante
MESE = "2026-08": passato agosto restavano congelati sul mese scorso invece di
azzerarsi a ogni cambio mese. Ora il mese di riferimento (e per il primo anche
titolo e scadenza) segue la data corrente, con un parametro `oggi` iniettabile
per test deterministici. Aggiunti unit test e un integration test end-to-end
contro il database locale.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>