2026-09-03 15:10:18 +02:00
# Modulo — Scout Live
2026-09-09 09:32:19 +02:00
**Stato:** implementato (fix M7 per la persistenza condivisa)
2026-09-03 15:10:18 +02:00
**File principali:** `src/lib/scout-live.ts` , `src/lib/scout-stato.ts` , `src/lib/scout-store.ts` ,
`src/lib/scout-export.ts` , `src/lib/cacche.ts` , `src/components/crapp/ScoutEntry.tsx` ,
`src/components/crapp/SondaggioCacche.tsx` , `src/routes/scout.tsx` , `src/routes/partita.$id.tsx`
---
## Obiettivo
Permettere a un solo referente per volta di registrare in tempo reale, durante la partita,
2026-11-02 08:17:06 +01:00
un giudizio − / + sui fondamentali (battuta, ricezione, attacco, muro) di ciascun convocato,
per set, con salvataggio condiviso su Supabase (non più solo `localStorage` , fix M7) così che tutta la squadra veda lo stato
2026-09-03 15:10:18 +02:00
aggiornato da qualunque dispositivo.
---
## Dati
- `scout_sessioni` — chi ha il controllo dello Scout Live per una partita (una riga per
`evento_id` , quindi un solo detentore).
- `scout_live` — stato in corso (azioni non ancora concluse) di una sessione.
2026-11-02 08:16:39 +01:00
- `scout_partite` — archivio delle partite scoutate concluse (risultato, parziali, azioni,
valutazioni − / +),
2026-09-03 15:10:18 +02:00
mai più modificato una volta salvato (solo eliminabile per intero).
- `cacche_partita` — sondaggio goliardico pre-partita, un voto per giocatore/evento
(`UNIQUE evento_id, giocatore_id` ).
---
## Chi può usarlo
2026-09-06 00:24:39 +02:00
Chiunque sia autenticato: non è più riservato agli admin. A tenere l'ordine basta il lock di
sessione — scoutizza uno per volta, gli altri vedono "In uso da …". Questo allinea l'interfaccia
alle policy RLS di `scout_sessioni` /`scout_live` /`scout_partite` , che sono sempre state aperte a
qualunque utente autenticato (la migration M4 toglie l'accesso solo al ruolo `anon` ).
---
## Da dove ci si arriva
`ScoutEntry.tsx` è l'unico accesso a `/scout` : sta nella pagina della partita
(`partita.$id.tsx` , sezione «Scout live»), visibile a tutta la squadra. Si accende solo se
**quella** partita è quella di oggi — la prop `eventoId` confronta l'evento aperto con
`partitaDiOggi()` — e se nessun altro ha il lock; negli altri casi resta una card grigia non
cliccabile («Si attiva il giorno della partita» / «In uso da …»). Dalla home è stato tolto
perché occupava spazio 6 giorni su 7.
2026-09-03 15:10:18 +02:00
---
## Meccanismo di lock condiviso
- `useApriSessioneScout()` (`scout-live.ts` ) prende il controllo con un upsert su
`scout_sessioni` (chiave `evento_id` ), rifiutando se un altro giocatore ha già una sessione
non scaduta.
- Una sessione scade dopo 5 minuti di inattività; `useHeartbeatScout()` la rinnova ogni 60
secondi finché lo scout resta aperto.
- Il rilascio (`useChiudiSessioneScout()` ) avviene al bottone "Rilascia", a fine partita, e
sull'evento `pagehide` della finestra (per liberare il lock se il browser viene chiuso senza
uscire esplicitamente).
- Nessun realtime: la sessione si rilegge solo all'apertura/focus pagina o al bottone
"Aggiorna" (`staleTime` 30s).
---
## Cosa registra
2026-11-02 08:24:43 +01:00
La schermata `/scout` ha due passi: **Selezione giocatore** (griglia dei convocati, ordinata per cognome o per numero con il selettore a destra del titolo, default cognome; in ogni riquadro, sotto il nome, i ** +** del giocatore nel set in corso, ricezione esclusa; filtrati sulle
2026-11-02 08:17:06 +01:00
risposte "presente"/"ritardo", con fallback a tutta la rosa se nessuno ha risposto) e **2. Valuta**
(vedi sotto), seguiti da «Ultime azioni», «Chiudi set» e «Fine partita». Salvataggio automatico su
`scout_live` con debounce di 800ms a ogni cambiamento.
**Punteggio e azioni.** L'interfaccia non registra più il punteggio: sono stati tolti i tasti delle
azioni (punto attacco, ace, muro, errore nostro, punto e errore avversario), il tabellone con punti
e set e il blocco avversario / in casa / trasferta. Avversario e campo restano quelli ricavati dal
titolo della partita (o dallo stato già salvato) e non si modificano. I tipi di azione
(`AzioneTipo` , `scout-store.ts` : `attacco` , `ace` , `muro` , `errore` , `punto_avv` , `errore_avv` ),
i totali `totaliPerGiocatore()` e il campo `scout_partite.azioni` restano nel codice e nei dati:
leggono le partite scoutate prima di questa modifica, ma oggi nessuna schermata crea nuove azioni.
2026-09-03 15:10:18 +02:00
---
2026-11-02 08:16:39 +01:00
## Valutazioni dei fondamentali (− / +)
Per ogni convocato lo scout può segnare un ** − ** o un ** +** su battuta, ricezione, attacco e muro
([DD-053 ](../decisions/DD-053.md )). Non sono punti: restano fuori dal punteggio, dai parziali e dai
2026-11-02 08:24:43 +01:00
totali P/A/M/E. Si seleziona il giocatore (primo passo) e si tocca − o + sul fondamentale (passo 2, il cui titolo mostra
2026-11-02 08:17:06 +01:00
cognome e numero del giocatore e il set in corso);
2026-11-02 08:16:39 +01:00
accanto a ogni tasto compare il conteggio di quel giocatore **nel set in corso** . «Annulla» nella
2026-11-02 08:17:06 +01:00
sezione toglie l'ultima valutazione del set in corso (l'«Annulla» in alto agisce solo sulle azioni, quindi oggi è sempre spento).
2026-11-02 08:16:39 +01:00
Ogni tocco è una riga `Valutazione` (`giocatoreId` , `fondamentale` , `segno` , `set` , `ts` ) in una
lista separata da `azioni` ; i conteggi per set si calcolano con `contaValutazioni()`
(`scout-store.ts` ). Lo stato in corso le salva in `scout_live.stato.valutazioni` (assente negli
stati salvati prima: vale lista vuota); a fine partita finiscono in `scout_partite.valutazioni` .
---
2026-09-03 15:10:18 +02:00
## Fine partita
2026-11-02 08:17:06 +01:00
**Limite attuale:** `chiudiSet()` e `finePartita()` si basano sui punti, che non si registrano più. «Chiudi
set» risponde «Set senza azioni» (quindi il set resta sempre il 1) e «Fine partita» «Nessun set da
salvare»: le valutazioni restano nello stato in corso e non arrivano in `scout_partite` .
2026-09-03 15:10:18 +02:00
`finePartita()` (`scout.tsx` ) compone i parziali finali, inserisce la partita in
`scout_partite` (INSERT, non upsert), poi cancella la riga da `scout_live` (stato consumato)
e rilascia la sessione.
---
## Export CSV
`scout-export.ts` genera un CSV (separatore `;` , BOM UTF-8) con parziali, riepilogo per
2026-11-02 08:16:39 +01:00
giocatore e log cronologico delle azioni. Se ci sono valutazioni, aggiunge una tabella per set e giocatore con i
- e i − di ogni fondamentale (solo per chi ne ha). Scaricabile dagli admin dalla pagina partita,
sezione "Report tecnico".
2026-09-03 15:10:18 +02:00
---
## Sondaggio cacche
`SondaggioCacche.tsx` chiede "quante cacche hai fatto prima di questa partita" (0-5+), sempre
2026-09-06 00:08:58 +02:00
modificabile. `sondaggioAperto()` (`cacche.ts` ) lo apre alle **8:00 del giorno della partita**
(ora locale del dispositivo) e da lì lo lascia aperto per sempre; prima la card mostra solo
l'avviso di apertura. Quando è aperto, gli **amministratori** vedono nella card il pulsante
«Avvisa tutti del sondaggio»: chiama `POST /api/public/apri-sondaggio` e manda la push a tutti
i dispositivi iscritti, come il sollecito presenze (vedi [Notifiche ](notifiche.md )). Nessun
invio automatico: parte solo quando un admin lo preme.
`statisticheCacche()` (`cacche.ts` ) calcola media, record e `giornateTop`
2026-09-03 15:10:18 +02:00
(giornate con ≥3), soglia usata per un [badge ](badge.md ) segreto — coerente con DD-007 (badge
calcolati a runtime).
---
## Regole rispettate
- **DD-008 (gamification equa)**: i dati tecnici (punti/ace/muri) restano confinati allo Scout
Live come statistica di squadra e non entrano nel tipo `Giocatore` usato per badge o
classifiche individuali.
---
## Limiti noti
2026-11-02 08:17:06 +01:00
- Senza punteggio, set e partita non si chiudono (vedi «Fine partita»): da risolvere, per esempio
chiudendo il set anche senza punti e salvando la partita con le sole valutazioni.
2026-09-06 00:24:39 +02:00
- Scout aperto a tutta la squadra: nessun filtro su chi può registrare le azioni, l'unica
garanzia è il lock di sessione (vedi sopra).
2026-09-03 15:10:18 +02:00
- Possibile, per quanto improbabile, doppio "successo" applicativo nel prendere il lock:
lettura e upsert non sono atomici.
2026-11-02 08:17:06 +01:00
- Avversario e campo non si correggono dallo scout.
2026-09-03 15:10:18 +02:00
- `scout_partite` si inserisce ma non si corregge dall'interfaccia: solo eliminazione totale.
- Abbinamento partita↔scout fatto anche per uguaglianza di data come fallback: ambiguo se due
partite cadono lo stesso giorno.
---
## Evoluzioni possibili
2026-11-02 08:16:39 +01:00
- Mostrare le valutazioni anche nella pagina della partita (oggi solo nel CSV admin).
2026-09-03 15:10:18 +02:00
- Realtime (Supabase Realtime) per aggiornare la sessione condivisa senza refresh manuale.