Files
segnapunti/README.md
T
davide f65f87722c docs: documenta la modalità time out e dettaglia tutte le funzioni
- README: sezione Funzionalità riscritta per spiegare in modo completo
  display e controller (layout, punteggio/set, config, cambi, servizio,
  voce, time out/spot, reset/referto, regole partita e amichevole).
- CLAUDE.md: descrizione di toggleTimeout, flag `timeout`, cartella `spot/`,
  endpoint `/spot/list` e nota sull'autoplay con audio in kiosk.
2026-06-21 18:35:34 +02:00

256 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Segnapunti
![Version](https://img.shields.io/badge/versione-2.0.0-blue)
![Node](https://img.shields.io/badge/node-%3E%3D18-green)
![Docker](https://img.shields.io/badge/docker-ready-2496ED?logo=docker&logoColor=white)
![License](https://img.shields.io/badge/licenza-privata-lightgrey)
Segnapunti digitale in tempo reale per partite di pallavolo. Un server centrale gestisce lo stato della partita; un **display** mostra il tabellone pubblico e un **controller** (smartphone o tablet) permette all'operatore di gestire punti, formazioni e cambi.
---
## Indice
- [Architettura](#architettura)
- [Guida utente](#guida-utente)
- [Funzionalità](#funzionalità)
- [Deploy con Docker](#deploy-con-docker)
- [Sviluppo](#sviluppo)
- [Test](#test)
---
## Architettura
```
Controller (smartphone) ──WebSocket──┐
├── Server Node.js ── gameState.js
Display (schermo) ──WebSocket──┘ │
└── .segnapunti/state.json
```
Il server è l'unica fonte di verità. Ogni azione del controller viene elaborata e trasmessa in broadcast a tutti i client connessi. Lo stato viene salvato su disco ad ogni azione e ricaricato all'avvio, sopravvivendo ai riavvii del server.
| Percorso | Ruolo |
|---|---|
| `http://<host>:3000/display` | Tabellone pubblico — sola lettura |
| `http://<host>:3000/controller` | Pannello operatore — gestione partita |
| `ws://<host>:3000/ws` | WebSocket endpoint |
---
## Guida utente
### Scenario tipico: schermo fisso + smartphone operatore
#### 1. Avvia il server
```bash
docker compose up -d
```
All'avvio il terminale mostra gli URL locali e di rete.
#### 2. Apri il display
Collega il PC/server allo schermo via HDMI e apri il browser a schermo intero:
```
http://localhost:3000/display
```
Se il display è su un dispositivo separato nella stessa rete:
```
http://<IP-del-server>:3000/display
```
> **Trovare l'IP:** il server lo stampa all'avvio. In alternativa usa `ip a` su Linux.
#### 3. Apri il controller sullo smartphone
Connetti il telefono alla stessa rete Wi-Fi e apri:
```
http://<IP-del-server>:3000/controller
```
> **Installazione come app:** nel browser tocca *"Aggiungi a schermata Home"* per avere il controller come icona dedicata.
---
## Funzionalità
Il sistema è composto da due interfacce complementari: il **display** è in sola lettura e mostra al pubblico lo stato della partita; il **controller** è il pannello operatore da cui parte ogni azione. Tutto ciò che l'operatore tocca sul controller si riflette istantaneamente sul display via WebSocket.
### Display (tabellone pubblico)
Pagina di sola visualizzazione, pensata per uno schermo grande o un proiettore. Mostra:
- **Nomi squadre** con **indicatore di servizio** (l'icona della palla compare accanto alla squadra che sta servendo).
- **Punteggio del set corrente** in caratteri molto grandi, leggibili da lontano.
- **Contatore dei set vinti** per ciascuna squadra.
- **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).
- **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).
- **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.
- **Fullscreen automatico** all'apertura sui dispositivi mobili.
### Controller (pannello operatore)
Il controller adatta automaticamente il proprio layout all'orientamento del dispositivo:
- **Verticale (smartphone)** — layout compatto: anteprima punteggio toccabile in alto e griglia di pulsanti sotto.
- **Orizzontale (tablet)** — layout esteso "da regia": due grandi pannelli squadra affiancati con punteggio, campo e tasto set, più una barra di azioni in basso.
#### Gestione del punteggio
- **Punto** — tocca il punteggio/la card di una squadra per assegnarle `+1`. Il sistema gestisce automaticamente il **cambio palla** e la **rotazione** della squadra che riconquista il servizio.
- **Annulla punto** — rimuove l'ultimo punto assegnato, ripristinando anche eventuale rotazione e servizio.
- **Tasti SET** — incrementano manualmente il contatore dei set vinti di una squadra (utile per correzioni); il contatore cicla da 0.
- **Dialog automatico SET VINTO / PARTITA FINITA** — compare da solo al raggiungimento delle condizioni di vittoria (25 punti, o 15 nel set decisivo, con 2 di scarto). Da qui puoi:
- **VAI AL SET SUCCESSIVO** — chiude il set, lo registra come vinto e prepara il set successivo aprendo la configurazione delle formazioni;
- **INDIETRO** — annulla l'ultimo punto se il dialog è comparso per errore;
- a partita conclusa, **REFERTO** per generare il referto e **CHIUDI** per tornare al tabellone.
#### Configurazione partita
Dal pulsante **Config** si apre una finestra che permette di impostare:
- **Nomi delle squadre** (Home e Guest);
- **Modalità partita**: `2/3` (al meglio dei 3 set), `3/5` (al meglio dei 5 set) o `Amichevole` (senza vittoria automatica della partita);
- **Formazioni iniziali**: i numeri di maglia dei 6 giocatori in campo per ciascuna squadra, disposti per zona.
#### Cambi giocatore
Il pulsante **Cambi** apre, dopo aver scelto la squadra, un dialog con righe `IN → OUT`. Le sostituzioni vengono **validate** prima di essere applicate: i numeri devono essere cifre, il giocatore entrante non può essere già in campo, quello uscente deve essere effettivamente in formazione, e nessuno può sostituire sé stesso. Eventuali errori sono segnalati in chiaro.
#### Servizio e visualizzazione
- **Cambio Palla** — assegna manualmente il servizio; disponibile **solo a 0-0** (a inizio set).
- **Inverti** — scambia il lato delle due squadre sul display.
- **Formazioni / Punteggio** — alterna sul display la vista formazioni in campo e la vista punteggio.
- **Striscia ON/OFF** — mostra o nasconde lo storico punti del set sul display.
- **Voce** — fa annunciare al display il punteggio corrente con la sintesi vocale (es. *"15 a 12"*, *"15 pari"*, *"zero a zero"*).
#### 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.
I video da proiettare vanno messi in una cartella **`spot/`** nella root del progetto (non versionata). Comportamento:
- **un solo** video `.mp4` → riprodotto in loop continuo;
- **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).
#### Reset e referto
- **Reset** — azzera la partita (punteggi, set e formazioni) previa conferma, e riapre subito la configurazione per impostare la partita successiva.
- **Referto** — a fine partita, dal dialog *PARTITA FINITA*, genera un referto di gara stampabile/PDF con i punteggi per set, le formazioni di partenza e l'andamento punto-punto. *Funzione prototipale.*
### Regole pallavolo integrate
Le condizioni di vittoria del set sono applicate automaticamente dal server (è quello che fa comparire il dialog *SET VINTO*):
| Set | Condizione di vittoria |
|---|---|
| Set 14 (modalità 3/5) o 12 (modalità 2/3) | Primo a **25** con almeno 2 punti di scarto |
| Set decisivo (tie-break) | Primo a **15** con almeno 2 punti di scarto |
La **partita** è vinta da chi raggiunge 3 set su 5 (modalità `3/5`) o 2 set su 3 (modalità `2/3`). In modalità **Amichevole** non c'è vittoria automatica della partita: si continua a giocare set senza che compaia *PARTITA FINITA*.
---
## Deploy con Docker
### Prima installazione
```bash
docker compose up -d
```
Lo stato viene salvato nel volume Docker `segnapunti-state` e sopravvive ai riavvii del container.
### Aggiornamento a nuova versione
```bash
docker compose pull && docker compose up -d
```
### Build e pubblicazione immagine
```bash
docker build \
-t santantonio.sytes.net/attilio/segnapunti:2.0.0 \
-t santantonio.sytes.net/attilio/segnapunti:latest .
docker push santantonio.sytes.net/attilio/segnapunti:2.0.0
docker push santantonio.sytes.net/attilio/segnapunti:latest
```
---
## Sviluppo
### Requisiti
| Strumento | Versione minima |
|---|---|
| Node.js | >= 18 |
| npm | >= 9 |
### Avvio
```bash
npm install
npm run dev
```
| URL | Interfaccia |
|---|---|
| `http://localhost:5173/display` | Display |
| `http://localhost:5173/controller` | Controller |
Lo stato viene salvato in `.segnapunti/state.json` anche in modalità dev.
### Comandi disponibili
| Comando | Descrizione |
|---|---|
| `npm run dev` | Dev server con hot reload |
| `npm run build` | Build di produzione in `dist/` |
| `npm run serve` | Build + avvio server produzione |
---
## Test
| Comando | Descrizione |
|---|---|
| `npm run test:unit` | Unit + integration (Vitest) |
| `npm run test:component` | Componenti Vue (Happy-DOM) |
| `npm run test:stress` | Load test WebSocket (50+ client) |
| `npm run test:all` | Tutti i test tranne E2E |
| `npm run test:ui` | Vitest con interfaccia grafica |
| `npm run test:e2e` | Playwright — Chromium, Firefox, Mobile Chrome |
Le suite Vitest coprono la logica di gioco (`gameState`, inclusa `formInizio`),
il protocollo e il routing del server, la persistenza, il client WebSocket
(`wsMixin`), i componenti Vue e la generazione del referto.
> I test E2E richiedono il server in esecuzione (`npm run serve`) e i browser Playwright installati:
> ```bash
> npx playwright install chromium firefox
> ```
---
## Changelog
Vedere [CHANGELOG.md](CHANGELOG.md) per la storia delle versioni.