Le tabelle della v1.0 sono nate con policy USING (true) per anon e authenticated. M4 ha tolto il GRANT ad anon e la cosa è passata per "ora è chiuso", ma per gli autenticati non era rimasto nessun limite. Verificato sul database locale con un utente appena creato, senza ruolo e senza slot nella rosa: POST su eventi_app risponde 201, DELETE risponde 200. Qualsiasi giocatore loggato poteva svuotare il calendario o riscrivere il voto di un altro parlando direttamente con PostgREST, saltando l'interfaccia che quei pulsanti glieli nasconde. Il permesso viveva solo nei componenti, cioè nel posto che un attaccante non usa. M11 fa dire alle policy quello che l'interfaccia già fa: eventi_app agli admin, risposte_presenze e cacche_partita alla propria riga, i tre voti al proprio votante_id. L'admin resta incluso ovunque, perché DD-017 gli riconosce già il diritto di agire al posto del giocatore. turni_palloni e le tabelle scout restano aperte di proposito: nell'interfaccia non hanno nessun gate, quindi stringerle sarebbe una funzionalità nuova e non una messa in sicurezza. Un test lo fissa, così se il gate arriva qualcuno se ne accorge. L'identità è lo slot di giocatori_squadra collegato all'account, con lo stesso EXISTS delle policy dei profili: mio_giocatore_id() di M2 era già stata rimossa dalla migration di correzione e non va reintrodotta. I cinque test nuovi in permessi.test.ts hanno ognuno il proprio controllo positivo — l'admin crea l'evento, il giocatore salva la propria presenza — perché un database che rifiuta tutto passerebbe qualsiasi test di sola negazione. Provata con db reset da zero; non applicata in produzione. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
88 lines
17 KiB
Markdown
88 lines
17 KiB
Markdown
# Database CrAPP
|
|
|
|
Struttura del database Supabase (PostgreSQL) e ruolo di ogni tabella. Lo schema autoritativo
|
|
sono le migration in `supabase/migrations/`: **una tabella nuova va documentata qui nella
|
|
stessa modifica che la crea**. Le funzionalità future stanno in [ROADMAP.md](ROADMAP.md),
|
|
non in questo file.
|
|
|
|
## Permessi di scrittura
|
|
|
|
Chi può scrivere cosa, dopo la migration `m11_scritture_per_ruolo` (DD-023). La **lettura**
|
|
resta aperta a tutti gli autenticati su ogni tabella di questo elenco; `anon` non arriva a
|
|
nessuna di esse da M4 (DD-011).
|
|
|
|
| Tabella | Chi può scrivere |
|
|
| ---------------------------------------------------------------- | ------------------------------------------------------------------- |
|
|
| `eventi_app` | solo admin (nell'app li gestisce la rotta `/eventi`, già riservata) |
|
|
| `risposte_presenze`, `cacche_partita` | il giocatore sulla propria riga (`giocatore_id`), più gli admin |
|
|
| `pagelle_voti`, `mvp_voti`, `badge_social_voti` | il votante sui propri voti (`votante_id`), più gli admin |
|
|
| `turni_palloni`, `scout_sessioni`, `scout_live`, `scout_partite` | qualsiasi autenticato: nell'interfaccia non hanno gate |
|
|
| `profili_giocatore` | il giocatore sul proprio profilo, admin su tutti (DD-016, DD-017) |
|
|
| `giocatori_squadra` | admin; il giocatore può solo reclamare uno slot libero (DD-016) |
|
|
| `user_roles` | solo admin |
|
|
|
|
L'identità del giocatore è lo slot di `giocatori_squadra` con `auth_user_id = auth.uid()`.
|
|
La tabella è verificata da `test/integration/permessi.test.ts` contro il database locale.
|
|
|
|
## Anagrafica e utenti
|
|
|
|
| Tabella | Scopo | Note |
|
|
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| `giocatori_squadra` | Anagrafica operativa della squadra, con ID testuali (`g1`…`gN`), dati gestiti dagli admin (nome, cognome, numero, ruolo), collegamento all'account (`auth_user_id`) ed email registrata (`email`). | Introdotta dalla migration `m1_giocatori_squadra`, source of truth della rosa (DD-015): `useRosa()` e gli altri punti che elencano i giocatori la leggono tramite `useGiocatoriSquadra()` (client) o `leggiGiocatoriSquadra()` (server), filtrando `attivo`. `src/lib/crapp-data.ts` resta solo come seed storico e fallback (`rosaFallback()`) quando il database non risponde, e come sorgente della data di nascita (non ancora una colonna di questa tabella). Vedi DD-015 e DD-016. La colonna `email` (migration `m5_email_giocatori_squadra`, impostabile anche da `/admin`) è la chiave del collegamento automatico account↔giocatore al primo accesso (DD-018): NULL finché non nota, oggi impostata per tutta la rosa attiva. Le colonne `numero_tessera`/`data_tessera` (migration `m8_tesseramento_csi`) tracciano chi è già tesserato al CSI; come `numero`/`ruolo` le scrive solo un admin, il trigger di M1/M5 le include tra i campi bloccati per chi reclama il proprio slot. |
|
|
| `giocatori` | Anagrafica giocatori con UUID. | Presente ma **non usata** dal codice attuale: la convergenza è rinviata (DD-012, DD-014). |
|
|
| `profili_giocatore` | Dati personali, metadati del documento d'identità, certificato medico e path dei file, in relazione 1:1 con `giocatori_squadra`. | Creata dalla migration `m2_profili_giocatore` (DD-016). Letta da `src/lib/profili.ts`; le policy mostrano al giocatore solo il proprio profilo e all'admin tutti. I file non stanno qui: la tabella conserva i path nel bucket. |
|
|
| `user_roles` | Ruoli applicativi (es. amministratore, giocatore). | Fonte dei permessi di amministrazione, letta da `src/lib/ruoli.ts` (DD-011). Il primo admin va inserito a mano; vedi [PROJECT_STATE.md](../PROJECT_STATE.md). |
|
|
|
|
`giocatori_squadra` / `giocatori` sono usate da: Squadra, Profili, Presenze, Scout, Badge, Pagelle.
|
|
|
|
## Storage
|
|
|
|
| Bucket | Scopo | Note |
|
|
| ------------------- | ---------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| `profili-giocatore` | Documento d'identità, certificato medico e foto tessera, in cartelle per giocatore (`<giocatore_id>/<sezione>.<est>`). | **Privato** e destinato a restare tale: contiene documenti e dati sanitari, che non devono mai avere URL pubblici (DD-016 regola 4). Il giocatore gestisce solo la propria cartella, l'admin può scaricare tutto tramite signed URL a scadenza breve. Creato dalla migration `m2_profili_giocatore`. |
|
|
| `avatar-giocatori` | Foto profilo mostrate nel cerchio avatar (Squadra, Profilo), un file per giocatore (`<giocatore_id>/avatar.jpg`). | **Pubblico**: foto informali, non documenti sensibili. Qualsiasi autenticato può caricare/sostituire/eliminare un file (nessun controllo per-proprietario, la maggior parte dei giocatori non ha ancora `auth_user_id` collegato, DD-018). Letto da `src/lib/avatar-store.ts`. Creato dalla migration `m6_avatar_giocatori`. |
|
|
|
|
## Eventi e presenze
|
|
|
|
| Tabella | Scopo | Note |
|
|
| ------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| `eventi_app` | Eventi gestionali utilizzati dall'app. | Modello in uso dal codice attuale. |
|
|
| `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). |
|
|
|
|
## Scout
|
|
|
|
| Tabella | Scopo | Note |
|
|
| ---------------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| `scout_sessioni` | Chi ha il controllo dello Scout Live per una partita (blocco condiviso), una riga per evento. | Letta/scritta da `src/lib/scout-live.ts`. Prima viveva solo in `localStorage`: "Scout occupato da X" non funzionava mai tra dispositivi diversi (fix M7). |
|
|
| `scout_live` | Stato in corso (azioni non ancora concluse) di una sessione di Scout Live. | Serve esclusivamente per statistiche di squadra, mai per classifiche individuali (DD-008). Letta/scritta da `src/lib/scout-stato.ts`. |
|
|
| `scout_partite` | Archivio delle partite scoutate concluse (risultato, parziali, azioni). | Letta/scritta da `src/lib/scout-store.ts`. Prima il risultato finale finiva solo in `localStorage`: invisibile a chiunque non fosse il dispositivo di chi aveva chiuso la partita (fix M7). |
|
|
|
|
## Votazioni
|
|
|
|
| Tabella | Scopo | Note |
|
|
| ------------------- | ------------------------------------ | ------------------------ |
|
|
| `mvp_voti` | Voti MVP assegnati a fine partita. | |
|
|
| `pagelle_voti` | Voti anonimi assegnati ai giocatori. | Usati per il voto medio. |
|
|
| `badge_social_voti` | Voti social per i badge. | |
|
|
|
|
## Turni e notifiche
|
|
|
|
| Tabella | Scopo | Note |
|
|
| -------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
| `turni_palloni` | Gestione dei turni palloni. | Solo turni **confermati**. Gli allenamenti non ricevono proposta automatica (vedi [palloni.md](modules/palloni.md)); M10 azzera i turni salvati su allenamenti da oggi in poi. |
|
|
| `push_subscriptions` | Dispositivi registrati per le notifiche Push. | |
|
|
| `promemoria_push` | Storico dei promemoria inviati. | |
|
|
|
|
## Funzioni speciali
|
|
|
|
| Tabella | Scopo | Note |
|
|
| ---------------- | --------------------- | -------------------------------------- |
|
|
| `cacche_partita` | Sondaggio prepartita. | Usato per statistiche e badge segreti. |
|
|
|
|
## Badge
|
|
|
|
Non esiste una tabella dedicata: i badge vengono **calcolati a runtime** dall'applicazione a
|
|
partire dai dati esistenti (DD-007).
|