Files
CRAPP/docs/decisions/DD-027.md
T
davideandClaude Sonnet 5.5 8f25143aa5 Riorganizza la documentazione per l'uso con assistenti AI
- 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>
2026-10-01 08:53:38 +02:00

3.1 KiB

DD-027 — Chi vota deve essere convocato, non solo autenticato come sé stesso

Stato: accettata · Data: 8 settembre 2026

Contesto
Un audit del modulo Badge (docs/modules/badge.md) ha trovato due filtri rimasti solo applicativi dopo DD-023: la policy di M11 garantisce che votante_id sia lo slot collegato all'account di chi scrive, ma non controlla che votante e votato fossero convocati all'evento — un utente che scrive direttamente su PostgREST (bypassando l'interfaccia) poteva votare o essere votato in una partita a cui non aveva partecipato, gonfiando mediaVoto, mvp o un badge social a piacere. Allo stesso modo, eventi_app.pagelle_chiuse nascondeva solo i bottoni in UI: un voto pagella "fuori tempo" restava tecnicamente possibile.

Decisione
La policy "Ognuno gestisce i propri voti ..." di pagelle_voti, mvp_voti e badge_social_voti (M11) guadagna un controllo aggiuntivo tramite la funzione evento_permette_voto() (migration m13_convocati_e_pagelle_chiuse): verifica che sia votante_id sia votato_id compaiano in eventi_app.convocati per quel match_id (convocati vuoto = tutta la rosa, la stessa convenzione di convocatiEvento() in eventi.ts), e — solo per le pagelle — che pagelle_chiuse sia falso. Le policy admin restano invariate e permissive: un amministratore deve poter correggere un voto anche fuori convocazione o dopo la chiusura.

Il controllo si ferma alla convocazione, non alla presenza reale: per l'MVP, ad esempio, l'interfaccia limita già il voto ai soli presenti/in ritardo (usePresenzeEvento), un filtro più stretto che resta solo applicativo — un convocato ma assente passa ancora a livello database. Stringere fino a quel punto avrebbe richiesto leggere risposte_presenze dentro la policy, un salto di complessità non giustificato dall'audit che ha originato questa decisione.

Alternative scartate

  • Un trigger BEFORE INSERT/UPDATE invece di RLS → si applicherebbe anche alla service key e agli admin, bloccando correzioni legittime fuori convocazione; la RLS, applicata solo alla policy non-admin, li esclude naturalmente.
  • Controllare anche la presenza reale (risposte_presenze), non solo la convocazione → scope maggiore del gap trovato in audit, e specifico dell'MVP (pagelle e badge social non hanno un concetto di "presente" distinto da "convocato" nell'interfaccia attuale).

Conseguenze

  • Un evento senza convocati esplicito (lista vuota, il caso più comune oggi) non cambia comportamento: tutta la rosa resta votabile, come prima.
  • I test di test/integration/permessi.test.ts sono la definizione eseguibile anche di questa parte della tabella dei permessi (voti non convocati rifiutati, pagelle_chiuse rifiutata a database, controlli positivi che provano che un voto legittimo passa ancora).
  • Resta un gap conosciuto e documentato (non quello risolto qui): che il votante fosse davvero presente, non solo convocato, per MVP/pagelle/badge social.

Riesame
Se un giorno servisse bloccare anche il voto di un convocato-ma-assente a livello database, non solo in UI.