docs: allinea README, CLAUDE.md e guida test al nuovo flusso time out
La documentazione descriveva ancora il vecchio toggleTimeout (video in loop/sequenza); aggiornata a startTimeout/stopTimeout con scelta squadra/video, countdown e auto-chiusura server-side a 30s.
This commit is contained in:
@@ -48,7 +48,7 @@ Punteggio, set e servizio si ricavano sempre dalla `striscia`: al primo punto di
|
|||||||
|
|
||||||
`src/persist.js` carica/salva lo stato su `.segnapunti/state.json`. `src/server-utils.js` ricava gli IP di rete (`getNetworkIPs`, con sorgente iniettabile) e stampa gli URL all'avvio. `src/spot-utils.js` espone `listSpotVideos(spotDir)`, che elenca i `.mp4` (ordinati) della cartella `spot/`; ritorna `[]` se la cartella manca.
|
`src/persist.js` carica/salva lo stato su `.segnapunti/state.json`. `src/server-utils.js` ricava gli IP di rete (`getNetworkIPs`, con sorgente iniettabile) e stampa gli URL all'avvio. `src/spot-utils.js` espone `listSpotVideos(spotDir)`, che elenca i `.mp4` (ordinati) della cartella `spot/`; ritorna `[]` se la cartella manca.
|
||||||
|
|
||||||
**Time out / spot video** — l'action `toggleTimeout` commuta il flag booleano `state.timeout`. Quando attivo, il display mostra a tutto schermo i video `.mp4` della cartella `spot/` nella root (non versionata): uno solo va in loop, più video girano in sequenza ripartendo dal primo; se la cartella è vuota mostra un overlay "TIME OUT". La lista è esposta dall'endpoint HTTP `/spot/list` (JSON) e i file sono serviti staticamente da `/spot/<file>.mp4`, sia in produzione (`server.js`) sia in sviluppo (`vite-plugin-websocket.js`). I video partono con audio; se il browser blocca l'autoplay con suono si ripiega automaticamente su muto — per avere l'audio reale il browser del display (schermo senza input) va avviato in kiosk con autoplay consentito (es. Chrome `--autoplay-policy=no-user-gesture-required`).
|
**Time out / spot video** — le action `startTimeout` (richiede `team`, `video` opzionale) e `stopTimeout` impostano/azzerano `state.timeout`, `timeoutTeam`, `timeoutVideo` e `timeoutStartedAt`. Il timestamp `startedAt` lo aggiunge `websocket-handler.js` (non il client), così `gameState.js` resta puro e deterministico; lo stesso handler arma un timer server-side di 30 secondi che invia automaticamente `stopTimeout` (sopravvive a refresh o disconnessione del controller). Sul controller il pulsante Time Out apre una modal per scegliere la squadra e uno dei video `.mp4` della cartella `spot/` nella root (non versionata), oppure nessun video; durante il time out il pulsante mostra il countdown e ripremerlo chiude in anticipo. Il display copre il tabellone con un overlay a tutto schermo con countdown: riproduce il video scelto (riallineandosi al punto giusto in caso di riconnessione a metà time out) e ripiega sulla scritta "TIME OUT <squadra>" se non c'è video o se il video finisce prima dei 30 secondi, con dissolvenza nell'ultimo secondo. La lista è esposta dall'endpoint HTTP `/spot/list` (JSON) e i file sono serviti staticamente da `/spot/<file>.mp4`, sia in produzione (`server.js`) sia in sviluppo (`vite-plugin-websocket.js`). I video partono con audio; se il browser blocca l'autoplay con suono si ripiega automaticamente su muto — per avere l'audio reale il browser del display (schermo senza input) va avviato in kiosk con autoplay consentito (es. Chrome `--autoplay-policy=no-user-gesture-required`).
|
||||||
|
|
||||||
`server.js` (Express) espone `createApp(distDir)` (solo routing, testabile) e `startServer(port)` (HTTP + WebSocket); serve entrambe le interfacce sulla porta 3000: `/display` → `dist/index.html`, `/controller` → `dist/controller.html`. Singolo endpoint WebSocket su `/ws`. L'avvio automatico parte solo se il file è eseguito come entrypoint.
|
`server.js` (Express) espone `createApp(distDir)` (solo routing, testabile) e `startServer(port)` (HTTP + WebSocket); serve entrambe le interfacce sulla porta 3000: `/display` → `dist/index.html`, `/controller` → `dist/controller.html`. Singolo endpoint WebSocket su `/ws`. L'avvio automatico parte solo se il file è eseguito come entrypoint.
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ Pagina di sola visualizzazione, pensata per uno schermo grande o un proiettore.
|
|||||||
- **Striscia storica dei punti** del set in corso: una sequenza scorrevole che ricostruisce l'andamento punto su punto.
|
- **Striscia storica dei punti** del set in corso: una sequenza scorrevole che ricostruisce l'andamento punto su punto.
|
||||||
- **Modalità formazioni**: in alternativa al punteggio, mostra le posizioni dei 6 giocatori in campo (numeri di maglia disposti come a referto).
|
- **Modalità formazioni**: in alternativa al punteggio, mostra le posizioni dei 6 giocatori in campo (numeri di maglia disposti come a referto).
|
||||||
- **Ordine di visualizzazione invertibile**: le due squadre possono essere scambiate di lato per rispecchiare l'orientamento reale del campo.
|
- **Ordine di visualizzazione invertibile**: le due squadre possono essere scambiate di lato per rispecchiare l'orientamento reale del campo.
|
||||||
- **Overlay time out / spot**: durante un time out copre il tabellone con i video della cartella `spot/` (vedi sotto).
|
- **Overlay time out / spot**: durante un time out copre il tabellone con un countdown e il video scelto dall'operatore, o con la scritta *TIME OUT* (vedi sotto).
|
||||||
- **Annuncio vocale del punteggio** (sintesi vocale del browser), comandato dal controller.
|
- **Annuncio vocale del punteggio** (sintesi vocale del browser), comandato dal controller.
|
||||||
- **Indicatore di connessione**: scompare quando tutto è connesso, diventa un punto rosso lampeggiante con scritta *Disconnesso* in caso di problemi.
|
- **Indicatore di connessione**: scompare quando tutto è connesso, diventa un punto rosso lampeggiante con scritta *Disconnesso* in caso di problemi.
|
||||||
- **Fullscreen automatico** all'apertura sui dispositivi mobili.
|
- **Fullscreen automatico** all'apertura sui dispositivi mobili.
|
||||||
@@ -137,13 +137,13 @@ Il pulsante **Cambi** apre, dopo aver scelto la squadra, un dialog con righe `IN
|
|||||||
|
|
||||||
#### Time Out e spot pubblicitari
|
#### Time Out e spot pubblicitari
|
||||||
|
|
||||||
Il pulsante **Time Out** attiva/disattiva la proiezione degli spot sul display. Quando la modalità è attiva il controller resta **pienamente operativo** ma è chiaramente evidenziato: compare un banner *MODALITÀ TIME OUT ATTIVA* e il pulsante diventa arancione e pulsante. Ripremendolo si esce e il display torna al punteggio.
|
Il pulsante **Time Out** apre una finestra in cui l'operatore sceglie **quale squadra** ha chiamato il time out (obbligatorio) e **quale video** proiettare sul display, scegliendo tra i file della cartella `spot/` oppure *nessun video* (overlay con la scritta *TIME OUT*). Alla conferma:
|
||||||
|
|
||||||
I video da proiettare vanno messi in una cartella **`spot/`** nella root del progetto (non versionata). Comportamento:
|
- il **display** copre il tabellone con un overlay a tutto schermo: countdown in sovraimpressione e video scelto; se non c'è video, o se il video finisce prima del tempo, compare la scritta *TIME OUT* con il nome della squadra. Nell'ultimo secondo il video sfuma in dissolvenza.
|
||||||
|
- il **controller** resta pienamente operativo: compare un banner *TIME OUT <squadra>* con il conto alla rovescia e il pulsante Time Out mostra i secondi rimanenti. Ripremendolo si chiude il time out in anticipo.
|
||||||
|
- il **server** chiude automaticamente il time out dopo **30 secondi**, anche se il controller si disconnette o va in standby.
|
||||||
|
|
||||||
- **un solo** video `.mp4` → riprodotto in loop continuo;
|
I video da proiettare vanno messi in una cartella **`spot/`** nella root del progetto (non versionata): vengono elencati nella finestra di scelta in ordine alfabetico (solo file `.mp4`). Se un display si riconnette a metà time out, il video riparte dal punto corretto.
|
||||||
- **più** video `.mp4` → riprodotti in sequenza in ordine alfabetico, poi si riparte dal primo;
|
|
||||||
- **cartella vuota o assente** → il display mostra un overlay nero con la scritta *TIME OUT*.
|
|
||||||
|
|
||||||
> **Audio:** i video partono con audio, ma il display è in genere uno schermo senza tastiera/mouse e i browser bloccano l'autoplay con suono senza un'interazione dell'utente. In assenza di configurazione il video parte automaticamente **muto** (il video si vede comunque). Per avere l'audio, avvia il browser del display in modalità kiosk consentendo l'autoplay con suono (es. Chrome con `--autoplay-policy=no-user-gesture-required`, oppure impostando un'eccezione del sito per audio/video).
|
> **Audio:** i video partono con audio, ma il display è in genere uno schermo senza tastiera/mouse e i browser bloccano l'autoplay con suono senza un'interazione dell'utente. In assenza di configurazione il video parte automaticamente **muto** (il video si vede comunque). Per avere l'audio, avvia il browser del display in modalità kiosk consentendo l'autoplay con suono (es. Chrome con `--autoplay-policy=no-user-gesture-required`, oppure impostando un'eccezione del sito per audio/video).
|
||||||
|
|
||||||
@@ -174,7 +174,9 @@ La **partita** è vinta da chi raggiunge 3 set su 5 (modalità `3/5`) o 2 set su
|
|||||||
docker compose up -d
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
Lo stato viene salvato nel volume Docker `segnapunti-state` e sopravvive ai riavvii del container.
|
Lo stato viene salvato nella cartella `./.segnapunti` montata come volume nel container e sopravvive ai riavvii.
|
||||||
|
|
||||||
|
> **Video spot in Docker:** la cartella `spot/` non è inclusa nell'immagine. Per usare i video del time out aggiungi un volume in `docker-compose.yml`: `./spot:/app/spot`.
|
||||||
|
|
||||||
### Aggiornamento a nuova versione
|
### Aggiornamento a nuova versione
|
||||||
|
|
||||||
|
|||||||
+8
-2
@@ -91,9 +91,11 @@ Esempi reali nel progetto:
|
|||||||
- vittoria set con regola dei 2 punti di scarto
|
- vittoria set con regola dei 2 punti di scarto
|
||||||
- reset stato
|
- reset stato
|
||||||
- `formInizio` (snapshot formazione di partenza del set)
|
- `formInizio` (snapshot formazione di partenza del set)
|
||||||
|
- time out (`startTimeout`/`stopTimeout`: squadra, video, timestamp)
|
||||||
- generazione del referto (`buildRefertoHtml`)
|
- generazione del referto (`buildRefertoHtml`)
|
||||||
- persistenza stato su disco (`persist.js`, con `fs` mockato)
|
- persistenza stato su disco (`persist.js`, con `fs` mockato)
|
||||||
- utility di rete (`server-utils.js`)
|
- utility di rete (`server-utils.js`)
|
||||||
|
- elenco video spot (`spot-utils.js`, su cartella temporanea reale)
|
||||||
|
|
||||||
Quando falliscono:
|
Quando falliscono:
|
||||||
- quasi sempre c'e un problema nella logica core
|
- quasi sempre c'e un problema nella logica core
|
||||||
@@ -115,7 +117,8 @@ Esempi reali nel progetto:
|
|||||||
- broadcast stato ai client
|
- broadcast stato ai client
|
||||||
- validazione input malformati
|
- validazione input malformati
|
||||||
- autorizzazioni (solo controller puo inviare certe azioni)
|
- autorizzazioni (solo controller puo inviare certe azioni)
|
||||||
- routing del server Express (`createApp`: rotte display/controller/asset)
|
- timer server-side del time out (auto-`stopTimeout` dopo 30s, `startedAt` impostato dal server)
|
||||||
|
- routing del server Express (`createApp`: rotte display/controller/asset, `/spot/list` e file statici `/spot/`)
|
||||||
|
|
||||||
Quando falliscono:
|
Quando falliscono:
|
||||||
- spesso c'e problema nel protocollo messaggi o nei controlli di ruolo
|
- spesso c'e problema nel protocollo messaggi o nei controlli di ruolo
|
||||||
@@ -133,8 +136,10 @@ Esempi reali nel progetto:
|
|||||||
- stato connessione
|
- stato connessione
|
||||||
- click bottoni controller
|
- click bottoni controller
|
||||||
- dialog reset/config/cambi
|
- dialog reset/config/cambi
|
||||||
|
- modal time out del controller (scelta squadra/video, banner, countdown)
|
||||||
|
- overlay time out del display (video, placeholder, countdown, dissolvenza)
|
||||||
- bottone REFERTO nel dialog PARTITA FINITA
|
- bottone REFERTO nel dialog PARTITA FINITA
|
||||||
- client WebSocket (`wsMixin`: connessione, riconnessione, `sendWs`)
|
- client WebSocket (`wsMixin`: connessione, riconnessione, `sendWs`, errori)
|
||||||
|
|
||||||
Quando falliscono:
|
Quando falliscono:
|
||||||
- spesso hai rotto template, computed, metodi o binding
|
- spesso hai rotto template, computed, metodi o binding
|
||||||
@@ -168,6 +173,7 @@ File principali:
|
|||||||
- `game-operations.spec.cjs`: reset, config, toggle, cambi
|
- `game-operations.spec.cjs`: reset, config, toggle, cambi
|
||||||
- `game-simulation.spec.cjs`: simulazione partita
|
- `game-simulation.spec.cjs`: simulazione partita
|
||||||
- `full-match.spec.cjs`: scenari partita completi
|
- `full-match.spec.cjs`: scenari partita completi
|
||||||
|
- `timeout.spec.cjs`: time out end-to-end (modal, overlay sul display, chiusura anticipata)
|
||||||
- `referto.spec.cjs`: generazione referto a PARTITA FINITA
|
- `referto.spec.cjs`: generazione referto a PARTITA FINITA
|
||||||
- `accessibility.spec.cjs`: controlli accessibilita con axe
|
- `accessibility.spec.cjs`: controlli accessibilita con axe
|
||||||
- `visual-regression.spec.cjs`: confronto screenshot con baseline
|
- `visual-regression.spec.cjs`: confronto screenshot con baseline
|
||||||
|
|||||||
Reference in New Issue
Block a user