docs: add rev04 migration master roadmap and phase1 plan

Aggiunge il master plan di migrazione V1.0.7 -> V1.1.0 (rev04-2026)
con le sette fasi organizzate in milestone M1 (demo cliente) e M2
(produzione), piu il piano TDD dettagliato della Fase 1 (Stazioni e
identita per-tablet) con 17 task eseguibili.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-17 21:13:01 +02:00
parent 767bd7f947
commit f71bbf398e
2 changed files with 2572 additions and 0 deletions
@@ -0,0 +1,377 @@
# TieMeasureFlow V1.0.7 → V1.1.0 (rev04-2026) — Master Roadmap
> **Tipo documento:** Master plan / roadmap. Non contiene task eseguibili TDD — rimanda ai sotto-piani per-fase.
> **Spec sorgente:** `Schema sviluppo SW TieFlow_rev04-2026.docx` + `PIANO_IMPLEMENTAZIONE.md` v1.0.
> **Target deployment:** Scenario B — container `tmflow-client` distribuito a ogni tablet/PC industriale, un `tmflow-server` centralizzato su VPS.
**Goal:** Portare TieMeasureFlow da V1.0.7 (funzionalità base: ricette, misure, SPC) a V1.1.0 allineata alla rev04: integrazione GAIA, stazioni per-tablet, ruolo capoturno, editor ricetta a blocchi, workflow operatore stretto (retry/timer/cicalino/avvio produzione), deploy docker per-tablet con registry privato.
## Strategia di Rilascio (revisione 2026-04-17)
Priorità aggiornata dal committente: **consegnare al cliente un sistema funzionante di test il prima possibile**. Il deploy Scenario B (registry + Watchtower + immagini pubblicate) è esplicitamente **rimandato alla fine dello sviluppo**.
Il programma si articola quindi in due milestone:
| Milestone | Contenuto | Obiettivo |
|---|---|---|
| **M1 — Demo cliente** | Fasi 1-5 del piano (modello dati, capoturno, editor blocchi, workflow operatore, GAIA **import-only con dati reali**) + deploy "demo" semplice (single docker-compose su VPS demo, senza registry) | Sistema testabile end-to-end dal cliente con i suoi dati, per raccogliere feedback sul workflow operatore prima di integrare GAIA live e andare in produzione. |
| **M2 — Produzione** | Fase 6 (Deploy B industriale) + Fase 7 (hardening, E2E, rollout pilota) + eventuali aggiustamenti post-feedback M1 | Rollout su tablet/PC reali del cliente. |
Conseguenze operative:
- **Dati reali, non mock:** M1 parte con contenuti veri del cliente (articoli, ricette, stazioni). Niente `MockGaiaClient`: in Fase 5 per M1 sviluppiamo solo il canale di **import one-shot** (endpoint admin che accetta un export GAIA in CSV/JSON, più UI Maker per editing manuale). L'integrazione GAIA live (polling, comandi produzione real-time) slitta a M2. Il cliente ci fornirà una snapshot dati all'inizio di M1.
- L'interfaccia astratta `GaiaClient` viene comunque disegnata in M1 (per non accumulare debito) ma in M1 resta implementata da un `ImportOnlyGaiaClient` che legge da file/DB senza contattare GAIA. I comandi produzione (`start/pause/resume/end`) in M1 scrivono su `production_events` locali — a M2 aggiungiamo l'implementazione che li invia a GAIA.
- Il deploy M1 usa un singolo `docker-compose.yml` su VPS di test con porte esposte a dominio di demo (HTTPS con Let's Encrypt tramite Traefik già presente in V1.0.7). Nessun registry privato, nessun Watchtower, build locale + push con `docker compose up --build`.
- Durante M1 il cliente testa da browser direttamente contro la VPS demo; i "tablet" in quella fase sono semplicemente browser puntati all'URL demo.
- Il feedback M1 può rimodulare le fasi di M2 (es. scoprire che serve un ruolo in più, che il cicalino va cambiato, che il protocollo GAIA va rivisto).
**Architecture:**
- Server FastAPI centralizzato su VPS — unico nodo che parla a GAIA, detiene DB MySQL, genera report, calcola SPC.
- Client Flask impacchettato come `tmflow-client:<version>` pubblicato su registry privato della VPS; ogni tablet/PC industriale pulla la propria copia e si identifica via `STATION_ID` nel `.env`.
- Capoturno come ruolo separato con flusso di override a token a scadenza breve.
- Ricetta estesa a blocchi tipizzati: preparazione documentale + misura vincolata a tolleranze.
- Parametri volatili di ricetta (timer, max_retries) isolati dalla versione immutabile.
**Tech Stack (invariato rispetto a V1.0.7):**
- Server: FastAPI, SQLAlchemy 2.0 async, MySQL 8, Alembic, Pydantic v2, WeasyPrint, Plotly+Kaleido, APScheduler (nuovo, per sync GAIA).
- Client: Flask, Jinja2, Alpine.js, TailwindCSS, Fabric.js, Plotly.js, html5-qrcode, Web Serial, Flask-Babel.
- Nuove integrazioni: adapter GAIA (protocollo TBD col cliente).
- Deploy: Docker registry privato (`registry:2`) sulla VPS + Watchtower sui tablet per auto-update.
---
## 0. Precondizioni e Decisioni Aperte (RISOLVERE PRIMA DI INIZIARE)
Queste scelte sono **prerequisiti**: iniziare senza risolverle produce rework sicuro.
| # | Decisione | Opzioni | Chi decide | Stato |
|---|---|---|---|---|
| D-0.1 | Protocollo integrazione GAIA | REST, DB shared, OPC-UA, file scambio | Cliente + noi | **Aperta** |
| D-0.2 | Credenziali e rete GAIA | VPN, firewall, whitelist IP | IT cliente | **Aperta** |
| D-0.3 | Target hardware "tablet" | Tablet Windows consumer, PC touch industriale Linux, tablet Android | Cliente | **Aperta** (critica per B) |
| D-0.4 | Cicalino/luce avviso | Audio browser HTML5, hardware USB locale, entrambi | Cliente | **Rimandato a M2** (non bloccante M1) |
| D-0.5 | Parametri runtime modificabili vs versione immutabile | A: ogni modifica crea versione; B: separare volatili da strutturali | Noi (raccomandato B) | **Aperta** |
| D-0.6 | Autenticazione capoturno durante override | Login sovrapposto modale, PIN rapido, badge RFID | Cliente | **Aperta** |
| D-0.7 | Timeout auto-logout | Valore default + configurabilità | Cliente | **Risolta:** configurabile via `system_settings` (chiave `auto_logout_minutes`, default 15), con override opzionale per-utente in colonna `users.auto_logout_minutes` (NULL = usa globale). |
| D-0.8 | Naming ruolo capoturno | `Supervisor`, `ShiftLeader`, `Capoturno` | Noi | Proposta: `Supervisor` (già inglese come gli altri) |
| D-0.9 | Tag versione immagine docker | `latest`, SemVer, git sha | Noi | Proposta: SemVer + `latest` |
| D-0.10 | Registry esposto su Internet o solo VPN | Internet+auth, solo VPN | Cliente + noi | Proposta: solo VPN cliente |
**Azione richiesta:** aprire una riunione di allineamento col cliente su D-0.1, D-0.2, D-0.3, D-0.4, D-0.6 prima di Fase 1.
---
## Fasi (ordine consigliato)
Capoturno (Fase 2) è precondizione del workflow operatore (Fase 4). GAIA (Fase 5) può partire in parallelo a Fase 2-3 dopo Fase 1. Fase 6 (deploy industriale B) parte **solo dopo il feedback cliente su M1**.
```
┌─────────────────────────── M1 — Demo per cliente ────────────────────────────┐
│ │
│ ┌───────────────────────────────────────────────────┐ │
│ │ Fase 1 — Stazioni + identità per-tablet │ 1.5-2 settimane │
│ └───────────────┬──────────────────────────────────┘ │
│ │ │
│ ┌───────────┼─────────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ Fase 2 Fase 3 Fase 5 (import-only) │
│ Capoturno Editor a blocchi ImportOnlyGaiaClient + UI import │
│ │ │ │ (paralleli, ~2-3 sett.) │
│ └─────┬─────┘ │ │
│ ▼ │ │
│ Fase 4 — Workflow operatore │ 2-3 settimane │
│ (retry/timer/autologout/avvio) │ │
│ │ │ │
│ └──────────┬───────────────┘ │
│ ▼ │
│ Demo deploy su VPS test ~2 giorni │
│ (docker-compose single-file, │
│ Traefik+LE, no registry, │
│ dati reali cliente importati) │
│ │ │
└────────────────────────┼─────────────────────────────────────────────────────┘
═══ CHECKPOINT: feedback cliente su M1 ═══
┌─────────────────────── M2 — Produzione ─────────────────────────────────────┐
│ │ │
│ ▼ │
│ Adjustments post-feedback variabile │
│ (modifiche workflow, UX, GAIA reale) │
│ │ │
│ ▼ │
│ Fase 5 reale — GAIA integrazione 1-2 settimane │
│ (protocollo definitivo, credenziali, │
│ rete cliente, feature flag) │
│ ▼ │
│ Fase 6 — Deploy B industriale 1 settimana │
│ (registry + watchtower + compose │
│ split server/client, STATION_ID, │
│ CI release) │
│ ▼ │
│ Fase 7 — Hardening & rollout 1-2 settimane │
│ (security review, e2e sito pilota, │
│ docs aggiornati, i18n delta) │
│ │
└──────────────────────────────────────────────────────────────────────────────┘
```
**Stima a M1 (sistema demo testabile):** ~6-7 settimane full-time; ~4-5 settimane con 2 fasi in parallelo.
**Stima totale fino a M2:** ~9-11 settimane full-time (include feedback cycle stimato 1-2 settimane).
---
## Fase 1 — Stazioni e Identità per-tablet
**Obiettivo:** modellare il concetto di "stazione di controllo", associare ricette a stazioni, far sì che ogni client carichi solo le ricette della propria stazione identificata da `STATION_ID`.
**Sotto-piano:** `docs/superpowers/plans/2026-04-17-rev04-phase1-stations.md`
**Deliverable:**
- Tabelle `stations`, `station_recipe_assignments` + migration Alembic.
- Endpoint `GET /api/stations`, `POST /api/stations`, `PUT /api/stations/{id}`, `GET /api/stations/{id}/recipes`.
- Schema auth: API key del client associata a una stazione → ogni request porta identità di stazione implicita.
- Variabile d'ambiente `STATION_ID` nel client Flask, letta a startup, usata per filtrare `/api/recipes` in `select_recipe`.
- UI admin per gestire stazioni + assegnazioni.
- Test: un client con STATION_ID=A vede solo le ricette assegnate ad A.
**File impattati principali:**
- Nuovi: `server/models/station.py`, `server/routers/stations.py`, `server/schemas/station.py`, `server/services/station_service.py`, `client/templates/admin/stations.html`, `server/migrations/versions/<hash>_add_stations.py`.
- Modificati: `server/main.py` (registra router), `server/models/__init__.py`, `server/routers/recipes.py` (filtro by station), `client/config.py` (`STATION_ID`), `client/blueprints/measure.py` (passa STATION_ID alle query), `client/blueprints/admin.py` (CRUD stazioni), `client/blueprints/auth.py` (usa API key specifica di stazione).
**Rischi:** rotture retrocompatibilità API se cambiamo signature endpoint esistenti → mitigare con parametro opzionale `station_id` e default None = backward compat.
---
## Fase 2 — Ruolo Capoturno (Supervisor) e Override
**Obiettivo:** introdurre ruolo `Supervisor`, endpoint di override a token breve, UI login-sovrapposto per autorizzazioni puntuali.
**Sotto-piano:** `docs/superpowers/plans/2026-04-17-rev04-phase2-supervisor.md`
**Deliverable:**
- Estensione enum ruoli con `Supervisor` + dependency `require_supervisor`.
- Tabella `supervisor_overrides` (id, requested_by, authorized_by, override_type, target_ref, created_at, consumed_at, reason).
- Endpoint `POST /api/supervisor/override` che valida credenziali supervisor e ritorna `override_token` JWT-like (firmato, TTL 60s).
- Endpoint `POST /api/supervisor/override/verify` usato da altri router prima di eseguire azioni protette.
- Componente Alpine.js `supervisor-modal` riusabile: apertura modale, login, callback con token.
- Audit trail: ogni override consumato logga `consumed_at` + contesto.
**Tipi di override previsti:**
- `FORCE_OUT_OF_TOLERANCE` — operatore vuole confermare misura fuori tolleranza.
- `RESET_RETRY_COUNTER` — sbloccare dopo N tentativi falliti.
- `PAUSE_PRODUCTION` — fermo linea (invierà comando GAIA in Fase 5).
- `END_PRODUCTION` — fine produzione (chiude timer GAIA in Fase 5).
- `EDIT_RUNTIME_PARAMS` — modificare timer/max_retries della ricetta in corsa.
**File impattati principali:**
- Nuovi: `server/models/supervisor_override.py`, `server/routers/supervisor.py`, `server/services/supervisor_service.py`, `server/schemas/supervisor.py`, `client/templates/components/supervisor_modal.html`, `client/static/js/supervisor-modal.js`.
- Modificati: `server/models/user.py` (commento ruoli), `server/middleware/api_key.py` (nuova dep `require_supervisor`), `client/blueprints/measure.py` (consuma token).
---
## Fase 3 — Editor Ricetta a Blocchi (Preparazione + Misura)
**Obiettivo:** estendere il concetto di `RecipeTask` a blocchi tipizzati: `preparation` (documentale: materiali, imballo, temperatura) e `measurement` (con subtask + tolleranze + timer intervallo).
**Sotto-piano:** `docs/superpowers/plans/2026-04-17-rev04-phase3-block-editor.md`
**Deliverable:**
- Migration: aggiunge `block_type ENUM('preparation', 'measurement')` e `measurement_interval_seconds INT NULL`, `max_retries INT NOT NULL DEFAULT 3`, `preparation_content LONGTEXT NULL` a `recipe_tasks`.
- Backfill: tutti i task esistenti → `block_type='measurement'`.
- Editor UI: toggle tipo blocco nel task editor; blocchi preparazione usano rich-text editor (TipTap light o textarea con markdown + preview) e accettano upload PDF/immagine opzionale.
- MeasurementTec UI: blocchi preparazione visualizzati come "scheda documentale" con pulsante "Ho letto, procedi"; blocchi misura invariati.
- Parametri volatili: nuove colonne `measurement_interval_seconds` e `max_retries` sono modificabili senza creare nuova versione (Decisione D-0.5 opzione B).
**File impattati principali:**
- Migration Alembic.
- Modificati: `server/models/task.py`, `server/schemas/task.py`, `server/services/recipe_service.py` (copy-on-write copia anche nuovi campi), `client/templates/maker/task_editor.html`, `client/static/js/annotation-editor.js` (skip per blocchi prep), `client/templates/measure/task_execute.html` (branch per tipo blocco), nuovo `client/templates/measure/preparation_view.html`.
---
## Fase 4 — Workflow Operatore: Retry, Timer, Autologout, Avvio Produzione
> Nota: feedback sonoro (cicalino avvio misura + luce continua) **rimandato a M2**. M1 usa solo notifiche visive.
**Obiettivo:** implementare le regole stringenti della rev04 sul flusso operatore.
**Sotto-piano:** `docs/superpowers/plans/2026-04-17-rev04-phase4-workflow.md`
**Deliverable:**
| Feature | Implementazione |
|---|---|
| N tentativi max poi Supervisor | Contatore in session Flask per `(measurement_session_id, subtask_id)`. Al superamento: modale Supervisor (Fase 2) per reset. |
| Auto-avanzamento solo se pass | Logica JS: se `pass_fail != 'pass'`, bottone "Avanti" disabilitato finché operatore non richiede conferma Supervisor (override FORCE_OUT_OF_TOLERANCE). |
| Log-out bloccato durante attività | Flag `measurement_session.is_active`. Link "Logout" in navbar nascosto/disabilitato se attiva. Endpoint `POST /api/auth/logout` respinge con 409 se sessione attiva senza override. |
| Auto-logout inattività | Alpine store `idle-timer` con event listeners `pointermove/keydown`. Alla scadenza (default 15m, config per-utente o globale) → redirect a `/logout`. |
| ~~Cicalino avvio misura~~ | **Rimandato a M2.** In M1 nessun feedback sonoro: al tick 0 del timer si mostra solo notifica visiva (toast + highlight subtask). |
| ~~Luce/cicalino continuo~~ | **Rimandato a M2.** |
| Timer intervallo tra misure | Countdown JS che legge `measurement_interval_seconds`. Al tick 0: notifica visiva + mostra subtask + sblocca input calibro. |
| "Avvio produzione" post-prima-misura | Bottone UI visibile solo dopo prima misura confermata. Chiamata `POST /api/gaia/production/start` (Fase 5). |
| "Fermo linea" / "Fine produzione" | Due bottoni protetti da Supervisor override. Chiamate GAIA (Fase 5). |
**File impattati principali:**
- Modificati: `client/blueprints/measure.py`, `client/templates/measure/task_execute.html`, `client/static/js/numpad.js` (estende con retry counter), nuovo `client/static/js/idle-timer.js`, nuovo `client/static/js/production-timer.js`, `client/static/js/caliper.js` (hook conferma esplicita).
- Server: aggiunge `measurement_sessions` table (id, user_id, recipe_version_id, station_id, started_at, ended_at, is_active), endpoint start/end.
**Dipendenza:** Fase 2 (Supervisor) e Fase 3 (blocchi con timer) devono essere completate.
---
## Fase 5 — Adapter GAIA
**Obiettivo:** integrare il MES GAIA per sync ricette-stazioni e comandi produzione.
**Sotto-piano:** `docs/superpowers/plans/2026-04-17-rev04-phase5-gaia.md`
**Scope per milestone:**
- **M1 (dati reali, no live GAIA):**
- Interfaccia astratta `GaiaClient` disegnata per intero (tutti i metodi previsti).
- Implementazione `ImportOnlyGaiaClient`: `fetch_station_articles` legge da DB popolato via import one-shot; i comandi `start/pause/resume/end` scrivono in una nuova tabella `production_events` locale (sorgente di verità per la demo, poi verrà replicata a GAIA in M2).
- Endpoint admin `POST /api/admin/gaia-import` che accetta un file (CSV o JSON) esportato dal cliente e popola `station_recipe_assignments` + articoli. Parser tollerante con report errori riga per riga.
- UI admin `/admin/gaia-import` per uploadare il file, previeware i dati, confermare l'import.
- Export retro-compatibile: `GET /api/admin/production-events/export` restituisce il JSON/CSV dei `production_events` accumulati (il cliente può caricarlo manualmente in GAIA in M1 se gli serve).
- Nessuna rete verso GAIA, nessuna credenziale GAIA richiesta per M1.
- **M2:** implementazione concreta `LiveGaiaClient` del protocollo definitivo (REST/DB/altro) in base a D-0.1, credenziali, rete cliente, circuit breaker, monitoring. I `production_events` accumulati da M1 diventano la coda che `LiveGaiaClient` drena verso GAIA al primo avvio.
**Contratto comune (disegnato in M1, usato da entrambe le implementazioni):**
```python
# server/services/gaia_client.py
class GaiaClient(Protocol):
async def fetch_station_articles(self, station_code: str) -> list[StationArticle]: ...
async def start_production(self, article_code: str, station_code: str, operator_id: str) -> None: ...
async def pause_production(self, article_code: str, station_code: str, reason: str) -> None: ...
async def resume_production(self, article_code: str, station_code: str) -> None: ...
async def end_production(self, article_code: str, station_code: str, stats: ProductionStats) -> None: ...
```
**Deliverable M1 — `ImportOnlyGaiaClient`:**
- Lettura articoli/ricette dal DB interno popolato via import one-shot.
- Comandi produzione persistiti in tabella `production_events` (no rete esterna).
- Endpoint `POST /api/admin/gaia-import` (upload CSV/JSON export GAIA) + UI `/admin/gaia-import` con preview e conferma.
- Endpoint `GET /api/admin/production-events/export` per esportare gli eventi accumulati (JSON/CSV) da caricare manualmente su GAIA se serve.
- Endpoint `POST /api/gaia/production/{start,pause,resume,end}` usati dal client Flask.
- Config `.env`: `GAIA_MODE=import_only` (default in M1).
**Deliverable M2 — `LiveGaiaClient`:**
- Implementazione concreta del protocollo definitivo (REST/DB/altro) in base a D-0.1.
- Job APScheduler ogni 60s: per ogni stazione attiva, chiama `fetch_station_articles`, aggiorna `station_recipe_assignments`.
- Drain iniziale dei `production_events` accumulati verso GAIA.
- Config `.env`: `GAIA_MODE=live`, `GAIA_BASE_URL`, `GAIA_AUTH_TOKEN`, `GAIA_POLL_INTERVAL_SECONDS`.
- Circuit breaker: se GAIA giù, non bloccare operazioni interne; accoda su `production_events` e degrada a warning in UI.
**File impattati principali:**
- Nuovi in M1: `server/services/gaia_client.py` (Protocol + `ImportOnlyGaiaClient`), `server/services/gaia_import.py`, `server/routers/gaia.py` (production events), `server/routers/admin_gaia.py` (import), `server/schemas/gaia.py`, `server/models/production_event.py`, `client/blueprints/admin.py` (aggiunge route import), `client/templates/admin/gaia_import.html`, `server/tests/test_gaia_import_only.py`.
- Aggiunti in M2: `server/services/gaia_live_client.py`, `server/services/gaia_sync.py` (scheduler), `server/tests/test_gaia_live.py`.
- Modificati: `server/main.py` (lifespan avvia APScheduler solo in modalità live), `server/config.py` (nuove variabili).
---
## Fase M1-Demo — Deploy Demo per Cliente (tra Fase 4 e checkpoint feedback)
**Obiettivo:** dopo Fasi 1-4 e Fase 5 import-only, mettere online una demo accessibile al cliente via HTTPS su dominio di test, **con i dati reali del cliente** (articoli, ricette, stazioni).
**Deliverable:**
- `docker-compose.demo.yml`: estensione del `docker-compose.yml` prod esistente con Traefik + Let's Encrypt puntato a dominio `demo.tielogic.<tld>` (o sottodominio dedicato), MySQL vuoto pronto per l'import, server e client buildati localmente (no registry).
- Seed minimo: solo utenti di esempio per ogni ruolo (MeasurementTec, Maker, Metrologist, Supervisor, Admin) + una stazione "default". Articoli e ricette non vengono seedati: vengono importati dal cliente (o da noi a suo nome) via `/admin/gaia-import` con il file export GAIA reale.
- Pagina `/admin/demo-reset` (protetta da SETUP_PASSWORD) che ripulisce misure + production events lasciando utenti, articoli e ricette (così il cliente ri-testa più volte senza perdere i dati importati).
- Script `scripts/deploy-demo.sh` che fa build, push via SSH alla VPS demo, restart con `docker compose up -d --build`.
- Credenziali demo consegnate al cliente insieme alla guida di test (scenari guidati: "prova come operatore", "prova come capoturno", "prova come maker", ecc.).
**Non incluso (rimandato a M2/Fase 6):** registry privato, Watchtower, compose split server/client, CI release automation, deploy su hardware cliente, `LiveGaiaClient` in tempo reale.
---
## Fase 6 — Deploy Scenario B (Docker per-tablet + Registry + Watchtower) [M2]
**Obiettivo:** package del client come immagine pubblicata su registry privato della VPS; ogni tablet pulla + auto-update via Watchtower. **Parte solo dopo checkpoint feedback M1.**
**Sotto-piano:** `docs/superpowers/plans/2026-04-17-rev04-phase6-deploy-b.md`
**Deliverable:**
- `docker-compose.server.yml` (VPS): `mysql` + `server` + `traefik` + `registry` + `watchtower-server`.
- `docker-compose.client.yml` (per-tablet): `client` + `watchtower-client`, `image: vps.tielogic.local:5000/tielogic/tmflow-client:latest`.
- `.env.client.example` con solo variabili necessarie al client: `STATION_ID`, `STATION_API_KEY`, `API_SERVER_URL`, `CLIENT_SECRET_KEY`, `LANG_DEFAULT`, ecc.
- `Dockerfile.client` ottimizzato: multi-stage, Tailwind build + Babel compile + gunicorn.
- GitHub Actions `.github/workflows/release.yml`: su tag `v*.*.*` builda e pusha `tmflow-server` e `tmflow-client` al registry.
- Script di provisioning `scripts/provision-tablet.sh`: installa docker, crea `.env`, genera STATION_ID, pulla e avvia.
- Documento `docs/DEPLOYMENT_B.md` con procedura manuale operatore IT cliente.
**Scelte tecniche:**
- Registry self-hosted su VPS con auth basic (htpasswd) su `registry:2`, esposto solo via VPN cliente (D-0.10).
- Watchtower `WATCHTOWER_POLL_INTERVAL=300`, `WATCHTOWER_ROLLING_RESTART=true`, label-filtered (`com.centurylinklabs.watchtower.enable=true`) per evitare update indesiderati.
- Tag strategia: ogni release push `tmflow-client:1.1.0` + `tmflow-client:latest`. Tablet seguono `latest`; rollback = retag del latest a versione precedente.
**Caveat D-0.3:** se i tablet target sono Windows consumer, B è fragile (docker desktop + licenze). Documentare come prerequisito mini-PC Linux industriale oppure scivolare a C (che è comunque B+LAN). Questo blocco deve essere chiarito prima.
---
## Fase 7 — Hardening, E2E, Rollout [M2]
**Obiettivo:** fare il sistema robusto per produzione e rilasciarlo su un sito pilota prima del rollout generale.
**Sotto-piano:** `docs/superpowers/plans/2026-04-17-rev04-phase7-hardening.md`
**Deliverable:**
- Security review completa (`oh-my-claudecode:security-reviewer`): nuovi endpoint GAIA, override Supervisor, registry esposto.
- Test E2E manuali + script Playwright/Selenium su: flusso completo operatore + capoturno override + sync GAIA + avvio/fine produzione.
- Rollback plan: procedura di ritorno a V1.0.7 se necessario (backup DB pre-migration, tag immagine precedente).
- Aggiornamento stringhe i18n IT/EN per tutti i nuovi messaggi (capoturno, cicalino, timer, GAIA errori).
- Aggiornamento `CLAUDE.md` + `README.md` + `API.md` + `USER_GUIDE.md`.
- Sito pilota: una singola postazione per una settimana prima del rollout sugli altri.
- Monitoring: log centralizzato + alert su errori GAIA persistenti, override Supervisor eccessivi per stazione, misure fuori tolleranza per ricetta.
---
## Vincoli Trasversali (applicare in ogni fase)
1. **Retrocompatibilità dati:** ogni migration deve avere `downgrade` testato. Mai DROP di colonne con dati senza passo di deprecazione.
2. **Feature flags:** nuove integrazioni (GAIA, Supervisor) dietro flag config (`GAIA_ENABLED`, `SUPERVISOR_ENABLED`) → rollout graduale e rollback veloce.
3. **Test prima:** seguire TDD sui sotto-piani. Ogni endpoint ha almeno un happy path + un negative path + un permission test.
4. **Envelope response:** iniziare ad allineare nuovi endpoint allo standard `{success, data, error}` della spec 2026-04-01, anche se V1.0.7 non lo usa. Minimizza rework futuro.
5. **Audit log:** ogni operazione critica (override, GAIA command, station assign) scrive su `access_logs`.
6. **i18n:** ogni nuova stringa passa da `{{ _('...') }}` o equivalente client-side. Niente testo hardcoded in italiano nei template.
7. **Commit granulari:** un commit per task TDD (test rosso → verde → commit). Usa il git-master agent per il formato commit.
---
## Scelte Architetturali Confermate / Deviate dalla Spec 2026-04-01
| Scelta | Spec 2026-04-01 | V1.1.0 | Motivazione |
|---|---|---|---|
| Struttura cartelle | `src/backend/` + `src/frontend/` | `server/` + `client/` | V1.0.7 ha già cementato questa struttura. Rework > costo beneficio. |
| Package manager | `uv` | `requirements.txt` | Migrazione a uv rimandata a V1.2.0 (task dedicato). |
| Frontend | Gradio o React | Flask server-side | Vincolo cliente: tablet kiosk, i18n server-side, no SPA. Deviazione documentata. |
| Messaging | NATS obbligatorio | Nessuno | Monolite a 2 processi, NATS rimandato a v2.x (quando compariranno moduli camera/ML). |
| API Envelope `{success,data,error}` | Obbligatorio | Adozione incrementale sui nuovi endpoint rev04 | Evita rework totale ma allinea il nuovo codice. |
| Auth header `X-Api-Key` | Obbligatorio | ✓ Già presente (`X-API-Key`) | Allineato (case-insensitive per HTTP). |
| Registry privato + Watchtower | Raccomandato | ✓ Adottato in Fase 6 | Necessario per scenario B. |
---
## Rischi e Mitigazioni
| Rischio | Probabilità | Impatto | Mitigazione |
|---|---|---|---|
| Protocollo GAIA live non decidibile prima di M2 | Media | Medio | M1 non dipende dal protocollo live: usa `ImportOnlyGaiaClient` con dati reali importati. Il protocollo definitivo si chiude durante M1, pronto per Fase 5-live in M2. |
| Export GAIA fornito dal cliente in formato non documentato | Media | Medio | Parser `gaia_import.py` tollerante + anteprima UI + possibilità di caricare più volte; prevedere 1-2 giorni di fitting iniziale del parser sullo specifico formato fornito. |
| Tablet Windows consumer rendono B non praticabile | Media | Alto | Documentare prerequisito hardware, prevedere fallback a C (edge NUC per sito). |
| Cliente cambia idea sul ruolo capoturno | Bassa | Medio | Astrazione override generica: il ruolo può essere rinominato o scomposto senza toccare il flusso. |
| Prestazioni Watchtower con N tablet | Bassa | Basso | `poll_interval=300s`, update scaglionati (`rolling_restart`), banda registry limitata ma accettabile. |
| i18n delta si accumula e va in produzione non tradotto | Media | Medio | Lint in CI che fallisce se ci sono stringhe `_('...')` non in `messages.po`. |
| Migration Alembic rompe DB produzione | Bassa | Critico | Backup pre-deploy obbligatorio, staging con dump produzione, downgrade testato. |
---
## Prossimi passi (focus M1)
1. **Decisioni chiuse:** D-0.4 (cicalino → M2), D-0.7 (autologout configurabile), scelta (b) "dati reali senza live GAIA" in M1.
2. **Decisioni ancora aperte per M1:** D-0.5 (parametri volatili separati dalla versione — raccomandato B) e D-0.6 (UX capoturno: default modale login sovrapposto). Da confermare al volo col cliente o decise da noi di default.
3. **Decisioni rinviabili a M2:** D-0.1 (protocollo GAIA live), D-0.2 (rete/credenziali GAIA), D-0.3 (target hardware tablet), D-0.10 (registry esposto o solo VPN). Da chiudere durante M1, non bloccano la demo.
4. **Richiesta al cliente per sbloccare Fase 5 import-only:** farci avere un **export GAIA d'esempio** (CSV/JSON) degli articoli + ricette per una o due stazioni, così adattiamo il parser.
5. Dettagliare il sotto-piano `phase1-stations` in TDD eseguibile (prima fase sbloccante per tutte le altre di M1).
6. Eseguire le fasi di M1 (1 → 2/3/5-import in parallelo → 4 → Demo deploy) via `superpowers:subagent-driven-development` oppure `superpowers:executing-plans`, con review + verifier tra una fase e l'altra.
7. Consegnare demo al cliente → raccogliere feedback → aprire M2.
8. In M2: chiudere decisioni residue, sviluppare `LiveGaiaClient` + cicalino + Fase 6 (Deploy B) + Fase 7 (hardening/rollout).
File diff suppressed because it is too large Load Diff