Bonifica una tantum le righe orfane da eventi cancellati prima di M14

M14 (DD-029) pulisce a cascata i dati collegati solo per le cancellazioni
future; questa migration ripulisce lo storico. Per risposte_presenze,
cacche_partita, turni_palloni, scout_sessioni, scout_live e scout_partite
elimina ogni riga il cui evento_id non esiste più in eventi_app.

Per mvp_voti, pagelle_voti e badge_social_voti serve più cautela: prima
del passaggio all'id evento CrAPP, match_id conteneva id Scout
(prefisso "s") o CSI (numerico o data-based), voti storici legittimi
mai collegati a un evento CrAPP. Il filtro si applica solo ai match_id
nel formato di nuovoIdEvento() ("e" + timestamp base36), così i vecchi
voti Scout/CSI restano intatti. Verificato manualmente sul database
locale prima dell'applicazione.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-09 10:24:43 +02:00
co-authored by Claude Sonnet 5
parent c7cd527045
commit 57463f993b
4 changed files with 74 additions and 6 deletions
+4 -2
View File
@@ -82,8 +82,10 @@ Prima versione, pre-release.
Alcuni conteggi `mvp` già mostrati possono scendere per effetto della nuova regola.
- Cancellare un evento pulisce ora a cascata, tramite trigger database, tutte le tabelle
collegate (presenze, pagelle, MVP, badge social, turni palloni, scout) invece di lasciarle
come righe orfane (migration `m14_pulizia_dati_evento_cancellato`, DD-029). Le righe orfane
generate da cancellazioni precedenti a questa migration non vengono bonificate.
come righe orfane (migration `m14_pulizia_dati_evento_cancellato`, DD-029).
- Bonificate una tantum le righe orfane lasciate da cancellazioni precedenti a M14 (migration
`m15_bonifica_dati_evento_orfani`), senza toccare i vecchi voti MVP/pagelle/badge social
legati a id Scout o CSI, che restano dati storici legittimi (DD-029).
### Sicurezza
+1 -1
View File
@@ -46,7 +46,7 @@ La tabella è verificata da `test/integration/permessi.test.ts` contro il databa
| Tabella | Scopo | Note |
| ------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `eventi_app` | Eventi gestionali utilizzati dall'app. | Modello in uso dal codice attuale. Cancellare un evento pulisce a cascata, tramite trigger, tutte le tabelle collegate elencate in questa pagina (`risposte_presenze`, `cacche_partita`, `mvp_voti`, `pagelle_voti`, `badge_social_voti`, `turni_palloni`, `scout_sessioni`, `scout_live`, `scout_partite`) — migration `m14_pulizia_dati_evento_cancellato`, DD-029. |
| `eventi_app` | Eventi gestionali utilizzati dall'app. | Modello in uso dal codice attuale. Cancellare un evento pulisce a cascata, tramite trigger, tutte le tabelle collegate elencate in questa pagina (`risposte_presenze`, `cacche_partita`, `mvp_voti`, `pagelle_voti`, `badge_social_voti`, `turni_palloni`, `scout_sessioni`, `scout_live`, `scout_partite`) — migration `m14_pulizia_dati_evento_cancellato`, DD-029. Le righe orfane da cancellazioni precedenti sono state bonificate una tantum da `m15_bonifica_dati_evento_orfani`, senza toccare i vecchi voti MVP/pagelle/badge social legati a id Scout o CSI. |
| `risposte_presenze` | Risposte dei giocatori agli eventi. | Modello in uso dal codice attuale. `risposto_il` è l'istante della **prima** risposta (migration `m9_risposte_presenze_risposto_il`): confrontato con `eventi_app.creato_il` dà la serie "Conferme 24h". Un trigger lo rende immutabile, così un ripensamento non fa risultare rapida una risposta lenta — `aggiornato_il` resta l'ultima modifica. |
| `eventi` | Calendario generale: allenamenti, partite, eventi della squadra. | Modello "nuovo" con autenticazione e vincoli, non ancora adottato (DD-014). |
| `presenze` | Presenze agli eventi. | Come sopra (DD-014). |
+14 -3
View File
@@ -1130,7 +1130,18 @@ PostgREST, non solo chi passa dal bottone dell'app.
scrive una riga in ciascuna delle otto tabelle, cancella l'evento e verifica che spariscano
tutte.
**Aggiornamento (9 settembre 2026, stesso giorno)** — la bonifica dello storico prevista sopra
come "riesame" è stata fatta subito dopo, migration `m15_bonifica_dati_evento_orfani`: righe
orfane in `risposte_presenze`, `cacche_partita`, `turni_palloni`, `scout_sessioni`,
`scout_live`, `scout_partite` identificate confrontando `evento_id` con `eventi_app`. Per
`mvp_voti`/`pagelle_voti`/`badge_social_voti` il confronto si applica **solo** ai `match_id`
nel formato id evento CrAPP (`^e[0-9a-z]+$`, quello di `nuovoIdEvento()`): i vecchi voti su id
Scout (prefisso `s` + timestamp decimale) o CSI (numerico o `data-squadra-squadra`) non sono
orfani, sono dati storici legittimi mai collegati a un evento CrAPP (vedi contesto sopra), e la
migration non li tocca. Verificato manualmente sul database locale prima di applicarla: un voto
di test su id Scout è sopravvissuto alla bonifica, un voto di test su id evento CrAPP orfano è
stato rimosso.
**Riesame**
Se in futuro si vuole bonificare anche lo storico di righe orfane già esistenti, o se una
nuova tabella collegata a un evento non viene aggiunta al trigger quando creata (va aggiornata
a mano, non c'è un meccanismo che lo forzi).
Se una nuova tabella collegata a un evento non viene aggiunta al trigger quando creata (va
aggiornata a mano, non c'è un meccanismo che lo forzi).
@@ -0,0 +1,55 @@
-- M15 — Bonifica delle righe orfane lasciate da eventi cancellati prima di M14
--
-- M14 ha aggiunto un trigger che pulisce a cascata i dati collegati quando un evento viene
-- cancellato (DD-029), ma agisce solo sulle cancellazioni da quel momento in avanti. Questa
-- migration ripulisce una tantum le righe orfane lasciate da cancellazioni PRECEDENTI a M14.
--
-- Per `risposte_presenze`, `cacche_partita`, `turni_palloni`, `scout_sessioni`, `scout_live` e
-- `scout_partite`, `evento_id` ha sempre e solo indicato un id evento CrAPP (mai un altro
-- schema): qualsiasi riga il cui `evento_id` non esiste più in `eventi_app` è, senza ambiguità,
-- un orfano da una cancellazione passata (per `scout_partite`, `evento_id` può anche essere
-- legittimamente NULL — una partita scoutata mai collegata a un evento — e quelle righe non
-- vengono toccate).
--
-- `mvp_voti`, `pagelle_voti` e `badge_social_voti` sono diverse: PRIMA che `match_id`
-- diventasse l'id evento CrAPP, contenevano l'id di una sessione Scout (formato `s` + timestamp
-- in base 10, es. "s1717426810123") o la chiave di un referto CSI (id numerico del portale, o
-- fallback "data-squadra-squadra"). Quei voti sono dati storici legittimi, mai stati collegati
-- a un evento CrAPP: docs/modules/mvp.md li descrive come "non più letti da nessuna schermata",
-- non come dati da eliminare. Cancellarli qui sarebbe un bug, non una bonifica.
--
-- Il filtro `match_id ~ '^e[0-9a-z]+$'` isola solo i match_id nel formato di
-- `nuovoIdEvento()` (`"e" + Date.now().toString(36)`, src/lib/eventi.ts): nessun id Scout (che
-- inizia per "s") o CSI (numerico o con trattini) può rientrarci, quindi solo i veri orfani da
-- evento CrAPP cancellato vengono rimossi, mai un voto storico su id scout/CSI.
DELETE FROM public.risposte_presenze
WHERE evento_id NOT IN (SELECT id FROM public.eventi_app);
DELETE FROM public.cacche_partita
WHERE evento_id NOT IN (SELECT id FROM public.eventi_app);
DELETE FROM public.turni_palloni
WHERE evento_id NOT IN (SELECT id FROM public.eventi_app);
DELETE FROM public.scout_sessioni
WHERE evento_id NOT IN (SELECT id FROM public.eventi_app);
DELETE FROM public.scout_live
WHERE evento_id NOT IN (SELECT id FROM public.eventi_app);
DELETE FROM public.scout_partite
WHERE evento_id IS NOT NULL
AND evento_id NOT IN (SELECT id FROM public.eventi_app);
DELETE FROM public.mvp_voti
WHERE match_id ~ '^e[0-9a-z]+$'
AND match_id NOT IN (SELECT id FROM public.eventi_app);
DELETE FROM public.pagelle_voti
WHERE match_id ~ '^e[0-9a-z]+$'
AND match_id NOT IN (SELECT id FROM public.eventi_app);
DELETE FROM public.badge_social_voti
WHERE match_id ~ '^e[0-9a-z]+$'
AND match_id NOT IN (SELECT id FROM public.eventi_app);