# Mappa funzionalità — roadmap → release v4 (archivio condiviso sul server)

Fino alla v3 l'app girava **interamente nel browser**: nessun server, dati nel `localStorage`
del singolo dispositivo, due tablet che non si parlavano. La v4 ha un servizio Node e un
archivio condiviso, e con quello diventano possibili tre cose che prima erano sbarrate: il
portale cliente, la firma del contratto da tablet e la conservazione dei documenti.

La tabella dice cosa è stato preso, cosa è stato preso **in una forma diversa** e cosa resta
**scartato con motivo**, invece di fingere di averlo.

## Fatto, e funzionante

| Modulo roadmap | Come è realizzato qui |
|---|---|
| Calendario, corsi, prenotazioni (GYM-015/016) | Settimana, filtri istruttore, durata fascia configurabile (45–120 min), corsi e sala che non si sovrappongono, **corsi e sala distinti per colore e per etichetta** con legenda, dettaglio fascia con l'elenco nominativo dei prenotati |
| Prenota / cancella (GYM-016) | `addBooking` unica porta d'ingresso — vale per il form, per l'approvazione, per la lista d'attesa **e per il portale cliente** |
| Lista d'attesa e auto-promozione (GYM-016) | Le richieste oltre soglia sono la lista d'attesa; quando un posto si libera sotto la soglia standard la più vecchia entra da sola, con notifica |
| No-show (GYM-016) | Segno per prenotazione, contatore nella scheda cliente e nella pagella |
| Capienza e override (GYM-006/011) | 10 standard / 12 massimo, configurabili; il tetto è verificato a ogni approvazione **e a ogni richiesta dal portale** |
| Clienti (GYM-007) | Anagrafica estesa (nascita, codice fiscale, indirizzo, contatto d'emergenza, **altezza**), ricerca che **restringe** l'elenco, archiviazione, eliminazione solo se non lascia orfani contabili. **Una sola scheda**: si apre cliccando la riga, la matita in alto a destra la mette in modifica e diventa ✗ / ✓ |
| **Documenti e certificati (GYM-008)** | Upload su server (PDF e immagini fino a 10 MB), **trascinamento diretto dall'allegato della mail** o tasto per sceglierli, anteprima dentro il gestionale, **scaricamento** con il nome originale, eliminazione solo con la scheda in modifica, scadenze allineate allo scadenziario. Tipi: certificato medico, **scheda di esercizi**, documento, contratto, foto |
| Privacy (GYM-009) | Consenso registrato per cliente; dal tablet è **obbligatorio** per procedere e viene archiviato col testo dell'informativa che il cliente ha visto |
| Abbonamenti (GYM-010/011) | Catalogo piani, pacchetto cliente, ingressi scalati alla prenotazione e restituiti alla disdetta |
| Pagamenti (GYM-012) | Registrazione, collegamento automatico al cash flow |
| **Scadenze (GYM-013)** | Certificato, documento, iscrizione annuale e abbonamento **derivati dai dati**, non scritti a mano: allerta da 10 giorni prima, ripetuta ogni giorno, fino a "Ricevuto" |
| Dashboard (GYM-014) | KPI, prossime fasce cliccabili, **pannello scadenze dedicato** con azione diretta |
| Presenze ed export (GYM-018) | Check-in dal dettaglio fascia o dal modulo Presenze, uscita, export CSV della giornata, **mini calendario per capire se il cliente segue il percorso** |
| HR (GYM-019) | Tre istruttori, ruoli, carico giornaliero, calendario personale |
| Finanza, inventario, manutenzioni (GYM-020/022/023) | Movimenti, beni, ticket |
| **Schede allenamento (GYM-024)** | **Creazione scheda** con serie/ripetizioni/recupero/note, invio al cliente, **storico riutilizzabile** e modelli da cui ripartire. Dal cliente, **Gestione schede**: assegnate a sinistra (un terzo) e libreria cercabile a destra (due terzi), assegnazione per copia, anteprima che diventa editor, **fasi** che fanno proseguire lo stesso percorso |
| **Web app cliente (GYM-026)** | **Portale**: prenota, disdice, sposta, chiede un posto se la fascia è piena, vede la sua scheda e il suo percorso |
| Loyalty e referral (GYM-027/028) | Punti, classifica, premi, codice |
| Messaggi (GYM-029) | Conversazioni locali, centro notifiche, **avvisi diretti al cliente nel portale** |
| Backup e restore (GYM-031) | Export/import JSON con validazione e copia di sicurezza; il server tiene la versione precedente e non sovrascrive mai un archivio illeggibile |
| **Auth, sessioni, ruoli (GYM-002/003)** | Password scrypt, sessioni firmate HMAC, cambio obbligatorio al primo accesso, rate limiting, ruolo responsabile/istruttore |
| **Audit (GYM-032)** | Registro delle operazioni sensibili, con il nome di **chi era collegato** (non più un operatore scelto da una tendina) |
| **Architettura (GYM-001/005)** | Servizio Node con regole di dominio condivise fra client e server; archivio unico con lucchetto ottimistico, **piu' un archivio storico per anno** che tiene il documento condiviso di dimensione costante |

## Preso in forma diversa, perché qui ha senso così

- **PostgreSQL (GYM-001)** → un documento JSON scritto in modo atomico (tmp + rename) con
  revisione. Sul Pi ci sono 415 MB di RAM e Node 20 non ha `node:sqlite` (verificato: il
  modulo non esiste su questa versione): un file scritto bene è più onesto di un database
  mezzo installato. La soglia che avevamo scritto — "se i dati crescono oltre qualche
  megabyte, è qui che si cambia" — è stata affrontata in v5 **partizionando nel tempo**
  invece di cambiare motore: il documento vivo tiene una finestra e lo storico sta in file
  per anno. Se un giorno servissero query vere (cerca fra tutte le presenze di tre anni),
  allora sì che servirebbe un database.
- **Licenza (GYM-004/030)** → sostituita da una scheda "Questa installazione" che dice la
  verità: chi è collegato, quale revisione, quando e da chi è stato fatto l'ultimo salvataggio.
  Un pulsante "Licenza" che non verifica niente sarebbe peggio di nessun pulsante.
- **Firma su tablet per la privacy (GYM-009)** → ora si fa, ma nella **postazione iscrizioni**:
  la firma è un PNG su disco, non base64 nel `localStorage`. Era proprio il limite che nella v3
  aveva fatto scartare la firma.
- **Notifiche push (GYM-029)** → avvisi dentro il portale del cliente, che li vede al prossimo
  accesso. Senza servizio push non si promette una notifica che non arriverebbe.

## Scartato, e perché

| Roadmap | Perché non si fa |
|---|---|
| Fatture passive / fatturazione elettronica (GYM-021) | Richiede SDI e conservazione a norma: non è un problema di interfaccia |
| Guided workout con video (GYM-025) | I contenuti video vanno su un CDN, non su una SD card da 58 GB condivisa col centralino |
| Campagne marketing via email/SMS (GYM-028) | Serve un servizio di invio e la gestione delle revoche: è un progetto a sé |
| Multi-struttura e multi-sala | La palestra è una: la regola "un corso occupa la palestra" nasce proprio da lì |
| Penetration test (GYM-032) | Non è una funzione da sviluppare: è un'attività da commissionare, e ora che c'è una superficie di rete **serve davvero** |

## Limiti noti di questa forma

- **Il gestionale rispedisce lo stato intero** a ogni operazione. Con due o tre postazioni va
  bene; con dieci utenti che scrivono nello stesso secondo i conflitti diventerebbero fastidiosi.
  Quello che **non** e' piu' un problema e' la dimensione: dalla v5 fasce e presenze oltre i
  120 giorni escono dal documento condiviso, che quindi non cresce piu' con gli anni. Misurato
  su tre anni di dati: 1,11 MB → 132 KB, e un salvataggio da ~160 ms a 2,9 ms.
- **Senza rete non si scrive.** L'agenda si può guardare (ultima copia scaricata), ma le
  modifiche non partono e l'avviso in testa lo dice. Meglio di un dato che sembra salvato e non lo è.
- **L'archivio contiene dati sanitari e foto.** Il backup va cifrato e portato fuori dal Pi;
  senza backup esterno, un guasto della SD card è una perdita definitiva.
- **Un solo Pi.** Se si spegne, si fermano gestionale, portale e iscrizioni.

## Aggiunte della v5

| Cosa | Come |
|---|---|
| **Scheda cliente unica** | Lettura e modifica nella stessa modale; la matita diventa ✗ e ✓. I campi si salvano con ✓; i file, che passano direttamente dall'API, no — e la scheda lo dichiara invece di lasciarlo scoprire |
| **Peso e altezza a mano** | Non sono documenti: si scrivono. Il peso e' una rilevazione datata, non un campo sovrascritto, perche' il grafico e il PDF vivono sullo storico |
| **Gestione schede** | Un terzo assegnate / due terzi libreria, con ricerca anche dentro gli esercizi; "nuova fase" riparte dall'ultima fase dello stesso percorso |
| **PDF delle statistiche** | Peso nel tempo, corsi, presenze e allenamenti in sala, con le tabelle dei numeri. Scritto a mano senza librerie: niente CDN da raggiungere, e resta vettoriale |
| **Istruttori rinominati** | Luca e Marco sono diventati **Andrea** e **Pietro**, anche nei dati gia' scritti (fasce in agenda, pagamenti, registro) e negli account |
| **Contrasto dei pulsanti** | Ogni pulsante ha un bordo pieno ad almeno 3:1 con lo sfondo su cui poggia (WCAG 1.4.11), misurato su tutte le viste e sia su desktop sia su telefono |
| **Archivio storico** | Fasce e presenze oltre 120 giorni escono dal documento condiviso e vanno in file per anno; si rileggono da `GET /api/archivio` per statistiche, pagella e agenda sfogliata indietro |
| **Compressione** | nginx comprime JS, CSS e JSON della palestra: app.js -70%, risposta dell'API -94% |

## Layout
- Desktop: dashboard nel viewport, pannelli con scroll interno.
- Tablet: due colonne; postazione iscrizioni con testi grandi e bersagli larghi.
- Telefono: bottom navigation, striscia dei giorni, **modali a tutta altezza** con la × e i
  pulsanti sempre raggiungibili, tabelle che diventano schede, campi a 16px (iOS non zooma).
