# TieMeasureFlow - Piano di Implementazione Completo > **TieMeasureFlow** by Tielogic > Sistema di gestione task per misurazioni con calibro manuale > Data: 2026-02-06 | Versione Piano: 1.0 --- ## Indice 0. [Brand Identity](#0-brand-identity) 1. [Analisi Concorrenza](#1-analisi-concorrenza) 2. [Architettura Generale](#2-architettura-generale) 3. [Stack Tecnologico e Motivazioni](#3-stack-tecnologico-e-motivazioni) 4. [Struttura Monorepo](#4-struttura-monorepo) 5. [Modello Dati MySQL](#5-modello-dati-mysql) 6. [API REST Endpoints](#6-api-rest-endpoints) 7. [Ruoli e Autorizzazioni](#7-ruoli-e-autorizzazioni) 8. [UX Design e Wireframe](#8-ux-design-e-wireframe) 9. [Fasi di Sviluppo](#9-fasi-di-sviluppo) 10. [Dettaglio Task e Agenti](#10-dettaglio-task-e-agenti) 11. [Versioning Ricette](#11-versioning-ricette) 12. [Gestione File Server](#12-gestione-file-server) 13. [Tastierino Touch](#13-tastierino-touch) 14. [Internazionalizzazione e Temi](#14-internazionalizzazione-e-temi) 15. [Sicurezza e Rete](#15-sicurezza-e-rete) 16. [Evoluzioni Future](#16-evoluzioni-future) 17. [Decisioni Architetturali](#17-decisioni-architetturali) --- ## 0. Brand Identity | Elemento | Valore | |----------|--------| | **Nome prodotto** | TieMeasureFlow | | **Nome breve** | TMFlow | | **Azienda** | Tielogic | | **Claim** | "Tie" (da Tielogic) + "Measure" + "Flow" = collega le misure in un flusso guidato | | **Concept logo** | Calibro stilizzato + freccia fluida curva | | **Colore primario** | Blu industriale `#2563EB` | | **Colore secondario** | Grigio acciaio `#64748B` | | **Colore accent** | Blu scuro `#1E40AF` | | **Tema light** | Sfondo `#F8FAFC`, testo `#0F172A` | | **Tema dark** | Sfondo `#0F172A`, testo `#F1F5F9` | | **Feedback misura OK** | Verde `#059669` | | **Feedback misura WARNING** | Giallo `#D97706` | | **Feedback misura FAIL** | Rosso `#DC2626` | | **Font UI** | Inter | | **Font numeri/misure** | JetBrains Mono (monospace, ottimo per valori decimali) | | **Logo varianti** | Completo (icona+testo), icona sola, monocromo bianco, monocromo scuro | ### Concept Logo ``` ┌──────────────────────────────────────────────┐ │ │ │ ╔══╗ │ │ ║ ║──────┐ │ │ ║ ║ │ ~~~> (freccia fluida curva) │ │ ║ ║──────┘ │ │ ╚══╝ │ │ Calibro stilizzato Flow │ │ │ │ TieMeasureFlow │ │ by Tielogic │ │ │ └──────────────────────────────────────────────┘ Varianti necessarie: - Logo completo (icona + testo) per navbar e login - Icona sola (favicon 32x32, 16x16) per tab browser - Monocromo bianco (su sfondo scuro / dark theme) - Monocromo scuro (su sfondo chiaro / light theme) - Formato SVG (vettoriale) + PNG (raster) ``` ### Branding Configurabile Il logo e il nome azienda sono **configurabili dal server**: - Ogni installazione del sistema puo caricare il proprio logo - Il nome azienda e visibile nella navbar e nei report PDF - Configurazione via `system_settings` nel database - Il branding "Powered by TieMeasureFlow - Tielogic" resta nel footer --- ## 1. Analisi Concorrenza ### Mitutoyo MeasurLink Real-Time Standard (v10) **Prezzo**: $1.680/licenza | **Tipo**: Desktop Windows #### Analisi Screenshot Concorrente **Vista Classica (std1.jpg)**: - Grafici a barre per ogni caratteristica (Diametro Interno, Esterno, Lunghezza) - Zone colorate: rosso (fuori tolleranza), giallo (warning), verde (in specifica) - Foto del pezzo fisico + foto calibro che misura il pezzo - Prompt guidato in basso: "Next: Coupling 256-78 Inside Diameter" - Stato DAQ: "USB Input Tool" per acquisizione diretta **Carta di Controllo SPC (std2.jpg)**: - Grafico con limiti UTL/UWL/Target/LWL/LTL a zone colorate - Istogramma con indici Cp, Cpk, Pp, Ppk - Tabella dati: osservazione, sottogruppo, valore, timestamp - Tab per ogni caratteristica misurata **Vista Multi-caratteristica (std3.jpg)**: - 5 "Position Offset" affiancati, ciascuno con carta di controllo + istogramma - Indici di capability per ogni posizione - Confronto visivo immediato tra posizioni #### Confronto Competitivo | Aspetto | MeasurLink | TieMeasureFlow (nostro) | Vantaggio | |---------|------------|------------------------|-----------| | **Piattaforma** | Desktop Windows | Web app (qualsiasi dispositivo) | Nostro | | **Prezzo** | $1.680/licenza | Da definire (piu accessibile) | Nostro | | **Guida visuale** | Foto generica pezzo | **Immagine/PDF annotata con marker numerati** | Nostro | | **Dove misurare** | Lista piatta caratteristiche | **Frecce e indicatori posizionati sul disegno tecnico** | Nostro | | **Workflow** | Semi-guidato | **Task strutturati con subtask per marker** | Nostro | | **Selezione ricetta** | Manuale da lista | **Barcode + URL parametrico + manuale** | Nostro | | **Multilingua** | Solo inglese | **IT/EN configurabile per utente** | Nostro | | **Tema** | Un solo tema | **Dark/Light per utente** | Nostro | | **SPC** | Completo, maturo | Completo (da implementare) | MeasurLink | | **Integrazione HW** | Vasta gamma calibri | Web Serial API (Chrome/Edge) | MeasurLink | | **Storicita** | Prodotto consolidato | Nuovo prodotto | MeasurLink | | **Editor ricette** | Assente (setup tecnico) | **Editor drag-and-drop con Fabric.js** | Nostro | #### Feature Adottate da MeasurLink | Feature | Come la implementiamo | |---------|----------------------| | Zone colorate rosso/giallo/verde | Feedback in tempo reale su ogni misura inserita | | Prompt "Next" guidato | Indicatore "Prossima misura: Marker #N - Descrizione" | | Stato connessione DAQ | Icona stato calibro USB nella status bar | | Tolleranze UTL/UWL/Target/LWL/LTL | Configurabili per ogni subtask nella ricetta | | Timestamp automatico | Ogni misura registrata con data/ora precisa | | Istogrammi e Cp/Cpk | Dashboard Metrologist con Plotly.js | --- ## 2. Architettura Generale ``` ┌──────────────────────────────────────────────────────────────┐ │ TABLET WINDOWS (Edge/Chrome) │ │ │ │ ┌──────────────── FLASK CLIENT ──────────────────────────┐ │ │ │ │ │ │ │ [Logo Azienda] TieMeasureFlow [IT/EN] [Dark] [User] │ │ │ │ ───────────────────────────────────────────────────── │ │ │ │ │ │ │ │ ┌─────────────┐ ┌──────────────┐ ┌─────────────────┐ │ │ │ │ │ /maker │ │ /measure │ │ /statistics │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ Fabric.js │ │ PDF.js │ │ Plotly.js │ │ │ │ │ │ Editor │ │ Canvas │ │ Carte controllo │ │ │ │ │ │ Ricette │ │ Web Serial │ │ Istogrammi │ │ │ │ │ │ Upload file │ │ Numpad touch │ │ Trend/Cp/Cpk │ │ │ │ │ │ Task/Sub │ │ Barcode scan │ │ Report PDF │ │ │ │ │ │ Versioning │ │ CSV export │ │ Filtri avanzati │ │ │ │ │ └──────┬──────┘ └──────┬───────┘ └───────┬─────────┘ │ │ │ │ └───────────────┼─────────────────┘ │ │ │ └─────────────────────────┼───────────────────────────────┘ │ │ │ │ └─────────────────────────────┼──────────────────────────────────┘ │ HTTPS + API Key │ ZeroTier Network ┌─────────────────────────────┼──────────────────────────────────┐ │ FastAPI SERVER │ │ │ │ │ ┌──────────────────────────┼────────────────────────────────┐ │ │ │ /api/auth - Login, logout, profilo utente │ │ │ │ /api/users - CRUD utenti + ruoli + API keys │ │ │ │ /api/recipes - CRUD ricette + versioning immutabile │ │ │ │ /api/tasks - Task + subtask per versione ricetta │ │ │ │ /api/measurements - Salvataggio + query misure │ │ │ │ /api/statistics - Aggregazioni SPC, indici capability │ │ │ │ /api/files - Upload/download immagini/PDF │ │ │ │ /api/reports - Generazione PDF (WeasyPrint + Kaleido) │ │ │ │ /api/settings - Config sistema (logo, nome azienda) │ │ │ └──────────────────────────┬────────────────────────────────┘ │ │ │ │ │ ┌────────────────┐ ┌──────┴───────────────┐ │ │ │ /uploads │ │ MySQL 8.0+ │ │ │ │ ├── images/ │ │ │ │ │ │ ├── pdfs/ │ │ users │ │ │ │ ├── logos/ │ │ recipes │ │ │ │ └── reports/ │ │ recipe_versions │ │ │ │ │ │ recipe_tasks │ │ │ │ (disco locale) │ │ recipe_subtasks │ │ │ │ │ │ measurements │ │ │ └────────────────┘ │ access_logs │ │ │ │ system_settings │ │ │ │ recipe_version_audit │ │ │ └────────────────────────┘ │ └───────────────────────────────────────────────────────────────────┘ ``` --- ## 3. Stack Tecnologico e Motivazioni ### Backend | Tecnologia | Versione | Motivazione | |-----------|----------|-------------| | **FastAPI** | 0.110+ | Async nativo, auto-docs OpenAPI, performance per tablet multipli | | **Uvicorn** | 0.30+ | ASGI server, supporto HTTPS | | **SQLAlchemy 2.0** | 2.0+ | ORM async first-class, type-safe, moderne best practice | | **asyncmy** | 0.2+ | Driver MySQL async (non-blocking I/O) | | **MySQL** | 8.0+ | Richiesto dal cliente, JSON support, buon ecosistema | | **Alembic** | 1.13+ | Migration database versionato | | **Pydantic** | 2.0+ | Validazione dati, serializzazione automatica | | **passlib + bcrypt** | - | Hash password sicuro | | **Pillow** | 10+ | Generazione miniature immagini | | **Plotly Python** | 5.x | Generazione grafici SPC server-side per report | | **Kaleido** | 0.2+ | Export grafici Plotly in SVG/PNG ad alta qualita | | **WeasyPrint** | 62+ | HTML → PDF professionale, supporta CSS3 moderno | ### Frontend Client | Tecnologia | Versione | Motivazione | |-----------|----------|-------------| | **Flask** | 3.0+ | Lightweight, Jinja2 integrato, blueprint routing | | **Jinja2** | 3.x | Template engine server-side, i18n nativo | | **htmx** | 2.0 | HTML-over-the-wire, aggiornamenti parziali senza SPA | | **Alpine.js** | 3.x | Reattivita client-side leggera, stato locale | | **TailwindCSS** | 3.x | Utility-first, personalizzazione tema, dark mode nativa | | **PDF.js** | 4.x | Rendering PDF in canvas, worker-based, HiDPI | | **Fabric.js** | 6.x | Editor annotazioni: frecce, cerchi, rettangoli, drag-and-drop | | **Plotly.js** | 5.x | Grafici SPC interattivi (zoom, hover, filtri) | | **html5-qrcode** | 2.x | Barcode scanner via camera, cross-browser | | **Web Serial API** | Browser | Lettura calibri USB, nativo Chrome/Edge | | **Flask-Babel** | 4.x | i18n server-side (estrazione stringhe, .po/.mo) | | **alpinejs-i18n** | 2.x | i18n client-side (switch lingua dinamico) | | **Inter font** | - | UI professionale, leggibilita ottimale | | **JetBrains Mono** | - | Monospace per valori numerici/misure | ### Perche Queste Scelte | Scelta | Alternative scartate | Motivazione | |--------|---------------------|-------------| | FastAPI vs Django | Django REST troppo pesante per API pura | FastAPI e 3-5x piu veloce, async nativo | | Flask vs React | React = SPA complessa, overhead JS | Flask + htmx = semplicita, SEO, meno bundle JS | | TailwindCSS vs Bootstrap | Bootstrap meno personalizzabile | Tailwind: dark mode nativa, CSS variables, look moderno | | Plotly vs Chart.js | Chart.js meno potente per SPC | Plotly: export SVG, piu tipi di grafici, hover ricchi | | WeasyPrint vs wkhtmltopdf | wkhtmltopdf non supporta CSS3 | WeasyPrint: flexbox, grid, CSS moderno | | Fabric.js vs marker.js | marker.js licenza commerciale | Fabric.js: MIT, oggetti ricchi, export JSON | | MySQL vs PostgreSQL | Richiesto MySQL dal cliente | MySQL 8.0+ ha JSON, async, sufficiente | --- ## 4. Struttura Monorepo ``` TieMeasureFlow/ ├── PIANO_IMPLEMENTAZIONE.md # Questo file ├── CLAUDE.md # Istruzioni progetto per Claude ├── docker-compose.yml # MySQL + servizi (opzionale) ├── .env.example # Template variabili ambiente ├── .gitignore │ ├── server/ # FastAPI Backend │ ├── main.py # Entry point FastAPI │ ├── requirements.txt │ ├── config.py # Configurazione (DB, paths, API keys) │ ├── database.py # Engine SQLAlchemy async │ │ │ ├── models/ # SQLAlchemy Models │ │ ├── __init__.py │ │ ├── user.py # User + roles (JSON) │ │ ├── recipe.py # Recipe + RecipeVersion (immutabile) │ │ ├── task.py # RecipeTask + RecipeSubtask │ │ ├── measurement.py # Measurement records │ │ ├── access_log.py # Login/action logs │ │ └── setting.py # SystemSetting (logo, nome, config) │ │ │ ├── schemas/ # Pydantic Schemas (validazione I/O) │ │ ├── __init__.py │ │ ├── user.py │ │ ├── recipe.py # Include version schemas │ │ ├── task.py # Include subtask schemas │ │ ├── measurement.py │ │ └── statistics.py # SPC response schemas │ │ │ ├── routers/ # API Routers (endpoint grouping) │ │ ├── __init__.py │ │ ├── auth.py # POST login, logout, GET/PUT me │ │ ├── users.py # CRUD utenti (admin only) │ │ ├── recipes.py # CRUD ricette + versioning │ │ ├── tasks.py # CRUD task + subtask │ │ ├── measurements.py # POST misure, GET query │ │ ├── statistics.py # GET SPC data endpoints │ │ ├── files.py # POST upload, GET download │ │ ├── reports.py # GET genera PDF report │ │ └── settings.py # GET/PUT config sistema │ │ │ ├── services/ # Business Logic (separata dai router) │ │ ├── __init__.py │ │ ├── auth_service.py # Login, password hash, API key validation │ │ ├── recipe_service.py # Versioning copy-on-write logic │ │ ├── measurement_service.py # Salvataggio, pass/fail calc, deviation │ │ ├── spc_service.py # Calcoli Cp, Cpk, Pp, Ppk, X-bar, R │ │ └── report_service.py # WeasyPrint + Plotly/Kaleido generation │ │ │ ├── middleware/ # Middleware FastAPI │ │ ├── __init__.py │ │ ├── api_key.py # Verifica API Key su ogni request │ │ └── logging.py # Access logging automatico │ │ │ ├── templates/ # Jinja2 template per report PDF server-side │ │ └── reports/ │ │ ├── base_report.html # Layout base report con logo │ │ ├── spc_report.html # Report SPC con grafici │ │ └── measurement_report.html # Report misure tabulare │ │ │ ├── uploads/ # File uploadati (GITIGNORED) │ │ ├── images/ # {recipe_id}/{version_id}/ │ │ ├── pdfs/ # {recipe_id}/{version_id}/ │ │ ├── logos/ # Logo azienda configurabile │ │ └── reports/ # Report PDF temporanei (auto-pulizia 24h) │ │ │ ├── migrations/ # Alembic DB migrations │ │ ├── env.py │ │ ├── alembic.ini │ │ └── versions/ │ │ │ └── tests/ │ ├── conftest.py # Fixtures condivise (test DB, client) │ ├── test_auth.py │ ├── test_recipes.py # Include test versioning │ ├── test_measurements.py │ └── test_spc.py # Test calcoli statistici │ ├── client/ # Flask Frontend (Tablet UI) │ ├── app.py # Entry point Flask │ ├── requirements.txt │ ├── config.py # URL server API, API key, settings │ │ │ ├── blueprints/ # Flask Blueprints (routing per ruolo) │ │ ├── __init__.py │ │ ├── auth.py # Login/logout/profile pages │ │ ├── measure.py # Pagine MeasurementTec │ │ ├── maker.py # Pagine Maker (editor ricette) │ │ └── statistics.py # Pagine Metrologist (SPC) │ │ │ ├── services/ # API client helpers │ │ ├── __init__.py │ │ └── api_client.py # Wrapper requests verso FastAPI server │ │ │ ├── templates/ # Jinja2 Templates │ │ ├── base.html # Layout: navbar, footer, tema, lingua, logo │ │ │ │ │ ├── components/ # Componenti riutilizzabili │ │ │ ├── navbar.html # Navbar dinamica per ruoli + logo + lingua + tema │ │ │ ├── numpad.html # Tastierino touch per misure manuali │ │ │ ├── caliper_status.html # Indicatore stato connessione calibro USB │ │ │ ├── barcode_scanner.html # Modal scanner barcode │ │ │ ├── measurement_feedback.html # Feedback colore verde/giallo/rosso │ │ │ └── next_measurement.html # Indicatore "Prossima misura" │ │ │ │ │ ├── auth/ │ │ │ ├── login.html # Login con logo azienda │ │ │ └── profile.html # Modifica: nome display, lingua, tema │ │ │ │ │ ├── measure/ # Pagine ruolo MeasurementTec │ │ │ ├── select_recipe.html # Selezione ricetta (barcode/manual/URL param) │ │ │ ├── task_list.html # Lista task con miniature + progress │ │ │ ├── task_execute.html # Esecuzione: immagine annotata + numpad + misure │ │ │ └── task_complete.html # Riepilogo: pass/fail + export CSV │ │ │ │ │ ├── maker/ # Pagine ruolo Maker │ │ │ ├── recipe_list.html # Lista ricette con filtri + stato versione │ │ │ ├── recipe_editor.html # Editor: form + upload + Fabric.js canvas │ │ │ ├── task_editor.html # Editor task/subtask con tolleranze │ │ │ ├── recipe_preview.html # Anteprima come vista MeasurementTec │ │ │ └── version_history.html # Storico versioni con diff │ │ │ │ │ └── statistics/ # Pagine ruolo Metrologist │ │ ├── dashboard.html # Dashboard SPC: overview + alert │ │ ├── control_chart.html # Carta X-bar / R interattiva │ │ ├── histogram.html # Istogramma + curva normale + distribuzione │ │ ├── capability.html # Gauge Cp/Cpk/Pp/Ppk con indicatori │ │ ├── trend.html # Trend temporali + confronto periodi │ │ └── filters.html # Componente filtri: date, ricetta, operatore, lotto, seriale │ │ │ ├── static/ │ │ ├── css/ │ │ │ ├── tailwind.css # TailwindCSS compilato │ │ │ ├── themes.css # CSS Variables per dark/light + brand colors │ │ │ └── numpad.css # Stili tastierino touch (bottoni grandi) │ │ │ │ │ ├── js/ │ │ │ ├── alpine-init.js # Alpine.js config + i18n + tema toggle │ │ │ ├── caliper.js # Web Serial API: connect, read, parse dati calibro │ │ │ ├── barcode.js # html5-qrcode: init camera, decode, callback │ │ │ ├── numpad.js # Logica numpad: cifre, punto, +/-, backspace, invio │ │ │ ├── annotation-viewer.js # Canvas overlay display-only (MeasurementTec) │ │ │ ├── annotation-editor.js # Fabric.js editor completo (Maker) │ │ │ ├── csv-export.js # Export misure in CSV (Blob API) │ │ │ └── spc-charts.js # Plotly.js: configurazioni grafici SPC │ │ │ │ │ ├── img/ │ │ │ ├── tmflow-logo.svg # Logo TieMeasureFlow (vettoriale) │ │ │ ├── tmflow-icon.svg # Icona sola (favicon source) │ │ │ ├── favicon.ico # Favicon 32x32 │ │ │ └── default-company-logo.png # Logo placeholder se non configurato │ │ │ │ │ └── vendor/ # Librerie JS locali (fallback CDN) │ │ ├── pdf.js/ │ │ ├── fabric.js/ │ │ ├── plotly.js/ │ │ ├── htmx.min.js │ │ ├── alpine.min.js │ │ └── html5-qrcode/ │ │ │ ├── translations/ # Flask-Babel i18n │ │ ├── babel.cfg # Config estrazione stringhe │ │ ├── messages.pot # Template stringhe estratte │ │ ├── it/LC_MESSAGES/ │ │ │ ├── messages.po # Traduzioni italiano │ │ │ └── messages.mo # Compilato │ │ └── en/LC_MESSAGES/ │ │ ├── messages.po # Traduzioni inglese │ │ └── messages.mo # Compilato │ │ │ └── tests/ │ ├── test_auth_pages.py │ ├── test_measure_flow.py │ └── test_maker_flow.py │ └── docs/ # Documentazione ├── API.md # Documentazione API REST completa ├── DEPLOYMENT.md # Guida deployment (server + client + MySQL) ├── USER_GUIDE.md # Guida utente per tutti i ruoli └── COMPETITOR_ANALYSIS.md # Analisi dettagliata concorrenza ``` --- ## 5. Modello Dati MySQL ### Diagramma ER ``` ┌──────────────┐ ┌────────────────┐ ┌──────────────────┐ │ users │ │ recipes │ │ system_settings │ │──────────────│ │────────────────│ │──────────────────│ │ id (PK) │ │ id (PK) │ │ key (PK) │ │ username │ │ code (UNIQUE) │ │ value │ │ password_hash│ │ name │ │ type │ │ email │ │ description │ │ description │ │ display_name │ │ created_by (FK)─┼───┐ │ updated_at │ │ roles (JSON) │ ┌───┤ created_at │ │ │ updated_by (FK) │ │ language_pref│ │ │ active │ │ └──────────────────┘ │ theme_pref │ │ └───────┬────────┘ │ │ is_admin │ │ │ 1:N │ │ active │ │ ┌───────┴────────┐ │ │ api_key │ │ │recipe_versions │ │ │ created_at │ │ │────────────────│ │ │ last_login │ │ │ id (PK) │ │ └──────┬───────┘ │ │ recipe_id (FK) │ │ │ │ │ version_number │ │ │ │ │ is_current │ │ │ └───┤ created_by (FK) │ │ │ │ created_at │ │ │ │ change_notes │ │ │ └───────┬────────┘ │ │ │ 1:N │ │ ┌───────┴────────┐ │ │ │ recipe_tasks │ │ │ │────────────────│ │ │ │ id (PK) │ │ │ │ version_id (FK) │ │ │ │ order_index │ │ │ │ title │ │ │ │ directive │ │ │ │ description │ │ │ │ file_path │ │ │ │ file_type │ │ │ │ annotations_json│ │ │ └───────┬────────┘ │ │ │ 1:N │ │ ┌───────┴────────┐ │ │ │recipe_subtasks │ │ │ │────────────────│ │ │ │ id (PK) │ │ │ │ task_id (FK) │ │ │ │ marker_number │ │ │ │ description │ │ │ │ measurement_type│ │ │ │ nominal │ │ │ │ utl, uwl │ │ │ │ lwl, ltl │ │ │ │ unit │ │ │ └───────┬────────┘ │ │ │ 1:N │ │ ┌───────┴──────────┐ │ └───────────────┤ measurements │ │ │──────────────────│ │ │ id (PK BIGINT) │ │ │ subtask_id (FK) │ │ │ version_id (FK) │ │ │ measured_by (FK)──┘ │ │ value │ │ pass_fail │ │ deviation │ │ lot_number │ │ serial_number │ │ input_method │ │ measured_at │ │ synced_to_csv │ └───────────────────┘ ┌──────────────────────┐ ┌──────────────────────────┐ │ access_logs │ │ recipe_version_audit │ │──────────────────────│ │──────────────────────────│ │ id (PK BIGINT) │ │ id (PK BIGINT) │ │ user_id (FK) │ │ recipe_id (FK) │ │ action │ │ old_version_id (FK NULL) │ │ details (JSON) │ │ new_version_id (FK) │ │ ip_address │ │ changed_by (FK) │ │ user_agent │ │ change_type │ │ created_at │ │ change_reason │ └──────────────────────┘ │ created_at │ └──────────────────────────┘ ``` ### Schema SQL Dettagliato ```sql -- ============================================= -- UTENTI -- ============================================= CREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(100) NOT NULL UNIQUE, password_hash VARCHAR(255) NOT NULL, email VARCHAR(255), display_name VARCHAR(255) NOT NULL, -- Ruoli: combinazione di "Maker", "MeasurementTec", "Metrologist" roles JSON NOT NULL DEFAULT '[]', -- Flag admin separato (almeno 1 utente deve essere admin) is_admin BOOLEAN NOT NULL DEFAULT FALSE, -- Preferenze personali configurabili dall'utente language_pref ENUM('it', 'en') NOT NULL DEFAULT 'it', theme_pref ENUM('light', 'dark') NOT NULL DEFAULT 'light', -- Stato active BOOLEAN NOT NULL DEFAULT TRUE, api_key VARCHAR(64) UNIQUE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_login TIMESTAMP NULL, INDEX idx_username (username), INDEX idx_api_key (api_key) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- ============================================= -- RICETTE (Master - metadati condivisi tra versioni) -- ============================================= CREATE TABLE recipes ( id INT PRIMARY KEY AUTO_INCREMENT, code VARCHAR(100) NOT NULL UNIQUE, -- Codice ricetta (per barcode) name VARCHAR(255) NOT NULL, description TEXT, created_by INT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, active BOOLEAN NOT NULL DEFAULT TRUE, FOREIGN KEY (created_by) REFERENCES users(id), INDEX idx_code (code), INDEX idx_active (active) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- ============================================= -- VERSIONI RICETTA (Immutabili - copy-on-write) -- Ogni modifica crea una nuova versione. -- Le misure restano legate alla versione originale. -- ============================================= CREATE TABLE recipe_versions ( id INT PRIMARY KEY AUTO_INCREMENT, recipe_id INT NOT NULL, version_number INT NOT NULL, -- Auto-incrementale per ricetta is_current BOOLEAN NOT NULL DEFAULT FALSE, -- Audit created_by INT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, change_notes TEXT, -- Motivo modifica FOREIGN KEY (recipe_id) REFERENCES recipes(id), FOREIGN KEY (created_by) REFERENCES users(id), UNIQUE KEY uk_recipe_version (recipe_id, version_number), INDEX idx_current (recipe_id, is_current) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- ============================================= -- TASK (legati a una versione specifica della ricetta) -- ============================================= CREATE TABLE recipe_tasks ( id INT PRIMARY KEY AUTO_INCREMENT, version_id INT NOT NULL, order_index INT NOT NULL DEFAULT 0, -- Ordine visualizzazione title VARCHAR(255) NOT NULL, directive TEXT, -- Direttiva breve (es: "Misurare diametro interno") description TEXT, -- Descrizione estesa file_path VARCHAR(500), -- Path relativo file immagine/PDF file_type ENUM('image', 'pdf') NULL, annotations_json JSON, -- Fabric.js canvas export (frecce, marker, aree) FOREIGN KEY (version_id) REFERENCES recipe_versions(id), INDEX idx_version_order (version_id, order_index) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- ============================================= -- SUBTASK (indicatori numerici posizionati su immagine) -- Ogni marker numerico corrisponde a un punto di misura -- ============================================= CREATE TABLE recipe_subtasks ( id INT PRIMARY KEY AUTO_INCREMENT, task_id INT NOT NULL, marker_number INT NOT NULL, -- Numero indicatore su immagine (1, 2, 3...) description VARCHAR(500) NOT NULL, -- Es: "Diametro interno foro A" measurement_type VARCHAR(100), -- Es: "diametro", "lunghezza", "profondita", "angolo" nominal DECIMAL(12,6), -- Valore nominale target utl DECIMAL(12,6), -- Upper Tolerance Limit (limite superiore) uwl DECIMAL(12,6), -- Upper Warning Limit (warning superiore) lwl DECIMAL(12,6), -- Lower Warning Limit (warning inferiore) ltl DECIMAL(12,6), -- Lower Tolerance Limit (limite inferiore) unit VARCHAR(20) NOT NULL DEFAULT 'mm', -- Unita: mm, inch, deg, etc. FOREIGN KEY (task_id) REFERENCES recipe_tasks(id) ON DELETE CASCADE, UNIQUE KEY uk_task_marker (task_id, marker_number), INDEX idx_task (task_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- ============================================= -- MISURAZIONI -- Ogni record = una singola misura effettuata -- ============================================= CREATE TABLE measurements ( id BIGINT PRIMARY KEY AUTO_INCREMENT, subtask_id INT NOT NULL, -- Quale subtask e stato misurato version_id INT NOT NULL, -- Link DIRETTO alla versione ricetta (immutabile) measured_by INT NOT NULL, -- Chi ha misurato (MeasurementTec) -- Dati misura value DECIMAL(12,6) NOT NULL, pass_fail ENUM('pass', 'warning', 'fail') NOT NULL, deviation DECIMAL(12,6), -- value - nominal -- Tracciabilita lot_number VARCHAR(100), -- Numero lotto produzione serial_number VARCHAR(100), -- Numero seriale pezzo -- Metodo input input_method ENUM('usb_caliper', 'manual') NOT NULL DEFAULT 'manual', -- Timestamp measured_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- Sync flag per CSV synced_to_csv BOOLEAN DEFAULT FALSE, FOREIGN KEY (subtask_id) REFERENCES recipe_subtasks(id), FOREIGN KEY (version_id) REFERENCES recipe_versions(id), FOREIGN KEY (measured_by) REFERENCES users(id), INDEX idx_version (version_id), INDEX idx_subtask (subtask_id), INDEX idx_measured_at (measured_at), INDEX idx_lot (lot_number), INDEX idx_serial (serial_number), INDEX idx_operator (measured_by) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- ============================================= -- LOG ACCESSI -- ============================================= CREATE TABLE access_logs ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id INT, action VARCHAR(100) NOT NULL, -- login, logout, recipe_create, recipe_update, etc. details JSON, -- Dettagli aggiuntivi (es: recipe_id, version_id) ip_address VARCHAR(45), -- IPv4 o IPv6 user_agent VARCHAR(500), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id), INDEX idx_user_time (user_id, created_at), INDEX idx_action (action) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- ============================================= -- IMPOSTAZIONI SISTEMA (key-value configurabile) -- ============================================= CREATE TABLE system_settings ( setting_key VARCHAR(100) PRIMARY KEY, setting_value TEXT NOT NULL, setting_type ENUM('string', 'number', 'boolean', 'json') DEFAULT 'string', description VARCHAR(500), updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, updated_by INT, FOREIGN KEY (updated_by) REFERENCES users(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- Dati iniziali settings INSERT INTO system_settings (setting_key, setting_value, setting_type, description) VALUES ('company_name', 'TieMeasureFlow', 'string', 'Nome azienda visualizzato in navbar e report'), ('company_logo_path', '', 'string', 'Path logo azienda (relativo a uploads/logos/)'), ('max_upload_size_mb', '50', 'number', 'Dimensione massima upload file in MB'), ('csv_export_delimiter', ';', 'string', 'Delimitatore CSV per export'), ('csv_export_decimal', ',', 'string', 'Separatore decimale CSV per export'), ('default_language', 'it', 'string', 'Lingua default per nuovi utenti'), ('default_theme', 'light', 'string', 'Tema default per nuovi utenti'); -- ============================================= -- AUDIT VERSIONI RICETTA -- Traccia ogni modifica alle ricette -- ============================================= CREATE TABLE recipe_version_audit ( id BIGINT PRIMARY KEY AUTO_INCREMENT, recipe_id INT NOT NULL, old_version_id INT, -- NULL se prima creazione new_version_id INT NOT NULL, changed_by INT NOT NULL, change_type ENUM('CREATE', 'UPDATE', 'ACTIVATE', 'RETIRE') NOT NULL, change_reason TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (recipe_id) REFERENCES recipes(id), FOREIGN KEY (changed_by) REFERENCES users(id), INDEX idx_recipe_time (recipe_id, created_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ``` --- ## 6. API REST Endpoints ### Autenticazione & Utenti | Metodo | Endpoint | Descrizione | Ruolo | |--------|----------|-------------|-------| | POST | `/api/auth/login` | Login utente (username + password) | Tutti | | POST | `/api/auth/logout` | Logout (invalida sessione) | Tutti | | GET | `/api/auth/me` | Profilo corrente con ruoli | Tutti | | PUT | `/api/auth/me` | Aggiorna profilo (display_name, lingua, tema) | Tutti | | GET | `/api/users` | Lista utenti con ruoli | Admin | | POST | `/api/users` | Crea utente con ruoli | Admin | | PUT | `/api/users/{id}` | Modifica utente (ruoli, stato, admin) | Admin | | DELETE | `/api/users/{id}` | Disattiva utente (soft delete) | Admin | | POST | `/api/users/{id}/regenerate-key` | Rigenera API key utente | Admin | ### Ricette | Metodo | Endpoint | Descrizione | Ruolo | |--------|----------|-------------|-------| | GET | `/api/recipes` | Lista ricette attive (paginata) | Tutti | | GET | `/api/recipes/{id}` | Dettaglio ricetta con versione corrente + task | Tutti | | GET | `/api/recipes/code/{code}` | Ricetta per codice barcode | MeasurementTec | | POST | `/api/recipes` | Crea nuova ricetta (versione 1) | Maker | | PUT | `/api/recipes/{id}` | Aggiorna ricetta (crea nuova versione) | Maker | | DELETE | `/api/recipes/{id}` | Disattiva ricetta | Maker | | GET | `/api/recipes/{id}/versions` | Lista tutte le versioni | Maker, Metrologist | | GET | `/api/recipes/{id}/versions/{v}` | Dettaglio versione specifica | Maker, Metrologist | | GET | `/api/recipes/{id}/versions/{v}/measurement-count` | Conteggio misure per versione | Maker | ### Task & Subtask | Metodo | Endpoint | Descrizione | Ruolo | |--------|----------|-------------|-------| | GET | `/api/recipes/{id}/tasks` | Lista task versione corrente (ordinati) | Tutti | | POST | `/api/recipes/{id}/tasks` | Aggiungi task (crea nuova versione) | Maker | | PUT | `/api/tasks/{id}` | Modifica task | Maker | | DELETE | `/api/tasks/{id}` | Elimina task | Maker | | PUT | `/api/tasks/reorder` | Riordina task (drag-and-drop) | Maker | | POST | `/api/tasks/{id}/subtasks` | Aggiungi subtask con tolleranze | Maker | | PUT | `/api/subtasks/{id}` | Modifica subtask | Maker | | DELETE | `/api/subtasks/{id}` | Elimina subtask | Maker | ### Misurazioni | Metodo | Endpoint | Descrizione | Ruolo | |--------|----------|-------------|-------| | POST | `/api/measurements` | Salva singola misura | MeasurementTec | | POST | `/api/measurements/batch` | Salva batch di misure | MeasurementTec | | GET | `/api/measurements` | Query misure (con filtri paginati) | Metrologist | | GET | `/api/measurements/export/csv` | Export CSV server-side | MeasurementTec, Metrologist | ### Statistiche SPC | Metodo | Endpoint | Descrizione | Ruolo | |--------|----------|-------------|-------| | GET | `/api/statistics/control-chart` | Dati carta di controllo X-bar/R | Metrologist | | GET | `/api/statistics/histogram` | Dati istogramma + distribuzione | Metrologist | | GET | `/api/statistics/capability` | Indici Cp/Cpk/Pp/Ppk | Metrologist | | GET | `/api/statistics/trend` | Trend temporali indici | Metrologist | | GET | `/api/statistics/summary` | Riepilogo pass/fail/warning count | Metrologist | | GET | `/api/statistics/compare-versions` | Confronto SPC tra versioni ricetta | Metrologist | | GET | `/api/statistics/alerts` | Western Electric rules violations | Metrologist | **Filtri comuni per tutti gli endpoint statistics** (query params): - `recipe_id` - Ricetta specifica - `version_id` - Versione specifica (opzionale, default=tutte) - `subtask_id` - Subtask specifico - `date_from`, `date_to` - Intervallo date - `operator_id` - MeasurementTec specifico - `lot_number` - Numero lotto - `serial_number` - Numero seriale ### File & Report | Metodo | Endpoint | Descrizione | Ruolo | |--------|----------|-------------|-------| | POST | `/api/files/upload` | Upload immagine/PDF per task | Maker | | GET | `/api/files/{path}` | Download/serve file | Tutti | | DELETE | `/api/files/{path}` | Elimina file | Maker | | GET | `/api/reports/spc` | Genera PDF report SPC (filtri come statistics) | Metrologist | | GET | `/api/reports/measurements` | Genera PDF report misure tabulare | Metrologist | ### Settings | Metodo | Endpoint | Descrizione | Ruolo | |--------|----------|-------------|-------| | GET | `/api/settings` | Leggi tutte le impostazioni | Tutti | | PUT | `/api/settings` | Aggiorna impostazioni (batch) | Admin | | POST | `/api/settings/logo` | Upload logo azienda | Admin | --- ## 7. Ruoli e Autorizzazioni ### Matrice Ruoli | Funzionalita | MeasurementTec | Maker | Metrologist | Admin | |--------------|:-:|:-:|:-:|:-:| | Login / Logout / Profilo personale | X | X | X | X | | Modificare: nome display, lingua, tema | X | X | X | X | | Seleziona ricetta (barcode/manual/URL) | X | | | | | Visualizza task con immagine annotata | X | | | | | Inserisce misure (numpad / calibro USB) | X | | | | | Vede feedback colore (pass/warning/fail) | X | | | | | Export CSV misure | X | | | | | Crea nuove ricette | | X | | | | Modifica ricette (crea nuova versione) | | X | | | | Upload immagini / PDF | | X | | | | Editor annotazioni Fabric.js | | X | | | | Gestione task e subtask con tolleranze | | X | | | | Anteprima ricetta come MeasurementTec | | X | | | | Storico versioni ricetta | | X | X | | | Dashboard SPC overview | | | X | | | Carte di controllo X-bar / R | | | X | | | Istogrammi e distribuzione | | | X | | | Indici capability Cp/Cpk/Pp/Ppk | | | X | | | Trend temporali e confronto periodi | | | X | | | Alert Western Electric rules | | | X | | | Download report PDF | | | X | | | Confronto SPC tra versioni ricetta | | | X | | | Gestione utenti (CRUD) | | | | X | | Impostazioni sistema (logo, nome, config) | | | | X | ### Regole Combinazione Ruoli - Un utente puo avere **1, 2 o 3 ruoli** contemporaneamente (JSON array) - `is_admin` e un **flag separato** (non un ruolo), combinabile con qualsiasi ruolo - La navbar mostra **solo le voci** accessibili ai ruoli dell'utente corrente - Esempio: utente con `roles: ["Maker", "Metrologist"], is_admin: true` vede tutto - **Almeno 1 utente** deve essere admin (vincolo applicativo) - Un utente **senza ruoli** puo solo fare login e modificare il proprio profilo --- ## 8. UX Design e Wireframe ### Pagina Login ``` ┌──────────────────────────────────────────────┐ │ │ │ [Logo Azienda Configurabile] │ │ ────────────────────────── │ │ TieMeasureFlow │ │ by Tielogic │ │ │ │ ┌──────────────────────────────┐ │ │ │ Username │ │ │ └──────────────────────────────┘ │ │ ┌──────────────────────────────┐ │ │ │ Password │ │ │ └──────────────────────────────┘ │ │ │ │ ┌──────────────────────────────┐ │ │ │ ACCEDI │ │ │ └──────────────────────────────┘ │ │ │ │ [IT] [EN] [Dark] │ └──────────────────────────────────────────────┘ ``` ### Navbar (dinamica per ruoli) ``` ┌──────────────────────────────────────────────────────────────┐ │ [Logo] TieMeasureFlow | Misure | Ricette | Statistiche | │ │ └──MeT──┘ └─Maker─┘ └─Metrolog──┘ │ │ [IT/EN] [☀/🌙] [👤]│ └──────────────────────────────────────────────────────────────┘ Voci visibili in base ai ruoli dell'utente loggato ``` ### MeasurementTec - Esecuzione Task ``` ┌──────────────────────────────────────────────────────────────┐ │ [Navbar] [Calibro: ●] │ ├──────────────────────────────────────────────────────────────┤ │ │ │ Task 2 di 5: Controllo Diametri Foro │ │ Direttiva: Misurare i diametri indicati nel disegno │ │ │ │ ┌──────────────────────────────┐ ┌──────────────────────┐ │ │ │ │ │ │ │ │ │ [Immagine/PDF con │ │ Marker #2 │ │ │ │ annotazioni overlay] │ │ Diametro Int. (mm) │ │ │ │ │ │ Nom: 12.500 │ │ │ │ ①──→ │ │ Tol: ±0.050 │ │ │ │ ②──→ │ │ │ │ │ │ ③──→ │ │ ┌────────────────┐ │ │ │ │ │ │ │ 12.487 │ │ │ │ │ [Rettangolo area] │ │ └────────────────┘ │ │ │ │ │ │ ██████████████░░░░ │ │ │ │ │ │ (barra verde OK) │ │ │ └──────────────────────────────┘ │ │ │ │ │ ┌───┬───┬───┬───┐ │ │ │ │ │ 7 │ 8 │ 9 │ ⌫ │ │ │ │ │ ├───┼───┼───┼───┤ │ │ │ │ │ 4 │ 5 │ 6 │ C │ │ │ │ │ ├───┼───┼───┼───┤ │ │ │ │ │ 1 │ 2 │ 3 │+/-│ │ │ │ │ ├───┼───┼───┼───┤ │ │ │ │ │ 0 │ . │ │ ✓ │ │ │ │ │ └───┴───┴───┴───┘ │ │ │ │ │ │ │ │ → Prossima: #3 Lung.│ │ │ └──────────────────────┘ │ │ │ │ [← Task precedente] [Task successivo →] │ └──────────────────────────────────────────────────────────────┘ ``` ### Maker - Editor Annotazioni ``` ┌──────────────────────────────────────────────────────────────┐ │ [Navbar] │ ├──────────────────────────────────────────────────────────────┤ │ │ │ Ricetta: COUPLING-256 (v3) [Salva] [Anteprima] [Annulla] │ │ │ │ ┌── Toolbar Fabric.js ──────────────────────────────────┐ │ │ │ [Freccia] [Marker#] [Rettangolo] [Testo] [Elimina] │ │ │ └───────────────────────────────────────────────────────┘ │ │ │ │ ┌──────────────────────────────┐ ┌──────────────────────┐ │ │ │ │ │ Task 2: Diametri │ │ │ │ [Canvas Fabric.js] │ │ │ │ │ │ Immagine/PDF con │ │ Subtask (per marker):│ │ │ │ annotazioni editabili │ │ │ │ │ │ │ │ #1 Diam. Esterno │ │ │ │ Drag frecce, marker, │ │ Nom: 25.000 mm │ │ │ │ rettangoli area │ │ Tol: ±0.100 │ │ │ │ │ │ [Modifica] [X] │ │ │ │ │ │ │ │ │ │ │ │ #2 Diam. Interno │ │ │ │ │ │ Nom: 12.500 mm │ │ │ │ │ │ Tol: ±0.050 │ │ │ │ │ │ [Modifica] [X] │ │ │ │ │ │ │ │ │ └──────────────────────────────┘ │ [+ Aggiungi Subtask] │ │ │ └──────────────────────┘ │ │ │ │ [Upload nuova immagine/PDF] │ └──────────────────────────────────────────────────────────────┘ ``` ### Metrologist - Dashboard SPC ``` ┌──────────────────────────────────────────────────────────────┐ │ [Navbar] │ ├──────────────────────────────────────────────────────────────┤ │ │ │ ┌── Filtri ───────────────────────────────────────────────┐ │ │ │ Ricetta: [COUPLING-256 ▼] Versione: [Tutte ▼] │ │ │ │ Dal: [2026-01-01] Al: [2026-02-06] │ │ │ │ Operatore: [Tutti ▼] Lotto: [________] Seriale: [__] │ │ │ │ [Applica filtri] │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────┐ ┌──────────────────────────────┐ │ │ │ Riepilogo │ │ Capability │ │ │ │ Misure: 1.247 │ │ │ │ │ │ Pass: 1.198 (96.1%) │ │ Cp: 1.45 Cpk: 1.32 │ │ │ │ Warn: 31 (2.5%) │ │ Pp: 1.41 Ppk: 1.28 │ │ │ │ Fail: 18 (1.4%) │ │ │ │ │ └─────────────────────┘ │ [Gauge indicator ████████░░] │ │ │ └──────────────────────────────┘ │ │ │ │ ┌───────────────────────────────────────────────────────┐ │ │ │ Carta di Controllo X-bar / R [Plotly.js] │ │ │ │ ═══════════════════ UTL ═════════════════ │ │ │ │ ─ ─ ─ ─ ─ ─ ─ ─ ─ UWL ─ ─ ─ ─ ─ ─ ─ ─ │ │ │ │ · · · · · · · · · Target │ │ │ │ ─ ─ ─ ─ ─ ─ ─ ─ ─ LWL ─ ─ ─ ─ ─ ─ ─ ─ │ │ │ │ ═══════════════════ LTL ═════════════════ │ │ │ └───────────────────────────────────────────────────────┘ │ │ │ │ ┌────────────────────┐ ┌────────────────────────────────┐ │ │ │ Istogramma │ │ Trend Cpk ultimi 30 giorni │ │ │ │ [Plotly.js] │ │ [Plotly.js] │ │ │ │ ▄ │ │ · · · │ │ │ │ ▄█▄ │ │ · · · · │ │ │ │ ▄███▄ │ │ · · · │ │ │ │▄█████▄ │ │ │ │ │ └────────────────────┘ └────────────────────────────────┘ │ │ │ │ [Scarica Report PDF] [Confronta Versioni] │ └──────────────────────────────────────────────────────────────┘ ``` --- ## 9. Fasi di Sviluppo | Fase | Descrizione | Dipendenze | |------|-------------|------------| | **FASE 0** | Setup Progetto: repo, dipendenze, config, DB | Nessuna | | **FASE 1** | Backend Core: modelli, auth, API ricette/utenti/files | Fase 0 | | **FASE 2** | Client Base: layout, login, navbar ruoli, tema, lingua | Fase 0 (parallelo a Fase 1) | | **FASE 3** | Flusso MeasurementTec: ricette, task, misure, numpad, CSV | Fase 1 + 2 | | **FASE 4** | Editor Maker: Fabric.js, upload, task/subtask, versioning | Fase 1 + 2 | | **FASE 5** | Calibro USB + Barcode: Web Serial, html5-qrcode | Fase 3 | | **FASE 6** | Dashboard Metrologist: SPC, grafici Plotly, report PDF | Fase 1 + 2 | | **FASE 7** | Polish & Testing: i18n, test E2E, security, docs | Tutte | **Note**: Fase 3, 4 e 6 possono essere sviluppate in **parallelo** dopo che Fase 1 e 2 sono complete. --- ## 10. Dettaglio Task e Agenti > **Legenda Agenti** (prefisso `oh-my-claudecode:` quando usati via Task tool): > > | Agente | Modello | Specializzazione | > |--------|---------|-----------------| > | `executor-low` | Haiku | Task semplici, file singolo | > | `executor` | Sonnet | Implementazione standard | > | `executor-high` | Opus | Logica complessa, multi-file | > | `designer` | Sonnet | UI/UX, template HTML, CSS | > | `designer-high` | Opus | Design system complesso | > | `architect` | Opus | Analisi, verifica architettura | > | `researcher` | Sonnet | Ricerca documentazione, API docs | > | `tdd-guide` | Sonnet | Test-driven development | > | `build-fixer` | Sonnet | Fix errori build/type | > | `writer` | Haiku | Documentazione, traduzioni | > | `code-reviewer` | Opus | Review qualita codice | > | `security-reviewer` | Opus | Review sicurezza | --- ### FASE 0 - Setup Progetto | # | Task | Subtask | Agente | Parallelo | |---|------|---------|--------|-----------| | 0.1 | **Init repository** | | | | | | | 0.1.1 - Creare .gitignore (Python, Node, uploads) | `executor-low` | | | | | 0.1.2 - Creare .env.example (DB, API keys, paths) | `executor-low` | Con 0.1.1 | | | | 0.1.3 - Creare CLAUDE.md progetto | `writer` | Con 0.1.1 | | 0.2 | **Setup server** | | | | | | | 0.2.1 - Creare requirements.txt server | `executor-low` | | | | | 0.2.2 - Creare main.py FastAPI base con CORS | `executor` | Dopo 0.2.1 | | | | 0.2.3 - Creare config.py (settings da .env) | `executor` | Con 0.2.2 | | | | 0.2.4 - Creare database.py (async engine + session) | `executor` | Dopo 0.2.2 | | 0.3 | **Setup client** | | | **Parallelo con 0.2** | | | | 0.3.1 - Creare requirements.txt client | `executor-low` | | | | | 0.3.2 - Creare app.py Flask base con blueprints | `executor` | Dopo 0.3.1 | | | | 0.3.3 - Setup TailwindCSS (config + build) | `executor` | Con 0.3.2 | | | | 0.3.4 - Creare struttura static/ + vendor/ | `executor-low` | Con 0.3.2 | | 0.4 | **Database** | | | | | | | 0.4.1 - Setup Alembic migrations | `executor` | Dopo 0.2.4 | | | | 0.4.2 - docker-compose.yml con MySQL 8.0 | `executor-low` | Con 0.4.1 | --- ### FASE 1 - Backend Core | # | Task | Subtask | Agente | Parallelo | |---|------|---------|--------|-----------| | 1.1 | **Modelli SQLAlchemy** | | | | | | | 1.1.1 - models/user.py (User + roles JSON + is_admin) | `executor` | | | | | 1.1.2 - models/recipe.py (Recipe + RecipeVersion) | `executor` | Con 1.1.1 | | | | 1.1.3 - models/task.py (RecipeTask + RecipeSubtask) | `executor` | Con 1.1.1 | | | | 1.1.4 - models/measurement.py (Measurement) | `executor` | Con 1.1.1 | | | | 1.1.5 - models/access_log.py + setting.py | `executor-low` | Con 1.1.1 | | 1.2 | **Schemas Pydantic** | | | **Parallelo con 1.1** | | | | 1.2.1 - schemas/user.py (Create, Update, Response) | `executor` | | | | | 1.2.2 - schemas/recipe.py (+ version schemas) | `executor` | Con 1.2.1 | | | | 1.2.3 - schemas/task.py (+ subtask schemas) | `executor` | Con 1.2.1 | | | | 1.2.4 - schemas/measurement.py (Create, Query, Response) | `executor` | Con 1.2.1 | | | | 1.2.5 - schemas/statistics.py (SPC response schemas) | `executor` | Con 1.2.1 | | 1.3 | **Middleware** | | | **Parallelo con 1.1** | | | | 1.3.1 - middleware/api_key.py (verifica header) | `executor` | | | | | 1.3.2 - middleware/logging.py (access log automatico) | `executor-low` | Con 1.3.1 | | 1.4 | **Router Auth** | | | Dopo 1.1, 1.2 | | | | 1.4.1 - routers/auth.py (login, logout, me) | `executor` | | | | | 1.4.2 - services/auth_service.py (hash, verify, API key) | `executor` | Con 1.4.1 | | 1.5 | **Router Users** | | | Con 1.4 | | | | 1.5.1 - routers/users.py (CRUD + admin check) | `executor` | | | 1.6 | **Router Recipes** | | | Dopo 1.4 | | | | 1.6.1 - routers/recipes.py (CRUD + versioning endpoints) | `executor-high` | | | | | 1.6.2 - services/recipe_service.py (copy-on-write logic) | `executor-high` | Con 1.6.1 | | 1.7 | **Router Tasks** | | | Con 1.6 | | | | 1.7.1 - routers/tasks.py (CRUD task + subtask + reorder) | `executor` | | | 1.8 | **Router Files** | | | Con 1.6 | | | | 1.8.1 - routers/files.py (upload + download + thumbnail) | `executor` | | | | | 1.8.2 - Configurazione storage disco (paths, limits) | `executor-low` | Con 1.8.1 | | 1.9 | **Router Settings** | | | Con 1.4 | | | | 1.9.1 - routers/settings.py (GET/PUT + logo upload) | `executor` | | | 1.10 | **Test Backend** | | | Dopo 1.4-1.9 | | | | 1.10.1 - conftest.py + test_auth.py | `tdd-guide` | | | | | 1.10.2 - test_recipes.py (CRUD + versioning + measurement count) | `tdd-guide` | Con 1.10.1 | | | | 1.10.3 - test_measurements.py (save + query + pass/fail) | `tdd-guide` | Con 1.10.1 | | 1.11 | **Review Backend** | | | Dopo 1.10 | | | | 1.11.1 - Code review completa | `code-reviewer` | | | | | 1.11.2 - Security review (API key, SQL injection, upload) | `security-reviewer` | Con 1.11.1 | --- ### FASE 2 - Client Base | # | Task | Subtask | Agente | Parallelo | |---|------|---------|--------|-----------| | 2.1 | **Layout e Tema** | | | | | | | 2.1.1 - base.html (layout, navbar, footer, logo, brand) | `designer` | | | | | 2.1.2 - themes.css (CSS variables: brand colors + dark/light) | `designer` | Con 2.1.1 | | | | 2.1.3 - Alpine.js init + tema toggle + localStorage | `designer` | Con 2.1.1 | | 2.2 | **Login e Profilo** | | | Dopo 2.1 | | | | 2.2.1 - blueprints/auth.py (routes Flask) | `executor` | | | | | 2.2.2 - login.html (logo azienda, form, lingua/tema) | `designer` | Con 2.2.1 | | | | 2.2.3 - profile.html (modifica: nome, lingua, tema) | `designer` | Con 2.2.1 | | 2.3 | **API Client** | | | **Parallelo con 2.1** | | | | 2.3.1 - services/api_client.py (wrapper requests + API key) | `executor` | | | 2.4 | **Navbar dinamica** | | | Dopo 2.1, 2.2 | | | | 2.4.1 - navbar.html (voci basate su ruoli utente) | `designer` | | | | | 2.4.2 - Logo + nome azienda caricati da settings API | `executor` | Con 2.4.1 | | 2.5 | **i18n Setup** | | | **Parallelo con 2.1** | | | | 2.5.1 - Configurare Flask-Babel + babel.cfg | `executor` | | | | | 2.5.2 - Configurare alpinejs-i18n per switch dinamico | `executor` | Con 2.5.1 | | | | 2.5.3 - Stringhe base IT/EN (login, navbar, common) | `writer` | Dopo 2.5.1 | --- ### FASE 3 - Flusso MeasurementTec | # | Task | Subtask | Agente | Parallelo | |---|------|---------|--------|-----------| | 3.1 | **Selezione Ricetta** | | | | | | | 3.1.1 - blueprints/measure.py (routes) | `executor` | | | | | 3.1.2 - select_recipe.html (lista + ricerca + lotto/seriale input) | `designer` | Con 3.1.1 | | | | 3.1.3 - Supporto parametro URL (?recipe=CODE&lot=X&serial=Y) | `executor` | Dopo 3.1.2 | | 3.2 | **Visualizzazione Task** | | | Dopo 3.1 | | | | 3.2.1 - task_list.html (lista task con miniature + progress bar) | `designer` | | | | | 3.2.2 - PDF.js viewer integrato per file PDF | `executor` | Con 3.2.1 | | | | 3.2.3 - Canvas overlay per annotazioni (display-only) | `executor` | Dopo 3.2.2 | | | | 3.2.4 - annotation-viewer.js (render Fabric.js JSON su canvas) | `executor` | Con 3.2.3 | | 3.3 | **Esecuzione Subtask** | | | Dopo 3.2 | | | | 3.3.1 - task_execute.html (split: immagine sx, misure dx) | `designer` | | | | | 3.3.2 - measurement_feedback.html (barra colore pass/warn/fail) | `designer` | Con 3.3.1 | | | | 3.3.3 - next_measurement.html (indicatore prossima misura) | `designer` | Con 3.3.1 | | | | 3.3.4 - Salvataggio misure via API + calcolo pass/fail client | `executor` | Dopo 3.3.1 | | 3.4 | **Tastierino Touch (Numpad)** | | | **Parallelo con 3.3** | | | | 3.4.1 - numpad.html (componente Alpine.js) | `designer` | | | | | 3.4.2 - numpad.js (cifre, punto, +/-, backspace, clear, conferma) | `designer` | Con 3.4.1 | | | | 3.4.3 - numpad.css (bottoni 56x56px, touch-friendly) | `designer` | Con 3.4.1 | | | | 3.4.4 - Integrazione numpad nel form task_execute | `executor` | Dopo 3.4.2 | | 3.5 | **Export CSV** | | | Dopo 3.3 | | | | 3.5.1 - csv-export.js (Blob API + config delimiter/decimal) | `executor` | | | | | 3.5.2 - Bottone download CSV in riepilogo | `designer` | Con 3.5.1 | | 3.6 | **Completamento Task** | | | Dopo 3.3 | | | | 3.6.1 - task_complete.html (riepilogo: tutte misure + pass/fail + CSV) | `designer` | | | 3.7 | **Router Measurements API** | | | **Parallelo con 3.1** | | | | 3.7.1 - routers/measurements.py (POST singola, POST batch, GET query) | `executor` | | | | | 3.7.2 - services/measurement_service.py (pass/fail calc, deviation) | `executor` | Con 3.7.1 | --- ### FASE 4 - Editor Maker | # | Task | Subtask | Agente | Parallelo | |---|------|---------|--------|-----------| | 4.1 | **Lista Ricette** | | | | | | | 4.1.1 - blueprints/maker.py (routes) | `executor` | | | | | 4.1.2 - recipe_list.html (CRUD, filtri, badge versione, stato) | `designer` | Con 4.1.1 | | 4.2 | **Editor Ricetta** | | | Dopo 4.1 | | | | 4.2.1 - recipe_editor.html (form metadati + upload area) | `designer` | | | | | 4.2.2 - Upload immagine/PDF con anteprima live | `executor` | Con 4.2.1 | | | | 4.2.3 - Ricerca Context7 docs Fabric.js per annotazioni | `researcher` | **Prima di 4.2.4** | | | | 4.2.4 - annotation-editor.js (Fabric.js: canvas, oggetti, eventi) | `executor-high` | Dopo 4.2.3 | | | | 4.2.5 - Toolbar: frecce, marker numerati, rettangoli area, elimina | `designer-high` | Con 4.2.4 | | | | 4.2.6 - Export/import annotazioni JSON (save/load Fabric.js canvas) | `executor` | Dopo 4.2.4 | | 4.3 | **Editor Task/Subtask** | | | Dopo 4.2 | | | | 4.3.1 - task_editor.html (CRUD task inline, drag reorder) | `designer` | | | | | 4.3.2 - Form subtask: marker#, descrizione, tipo, nominale, UTL/UWL/LWL/LTL, unita | `designer` | Con 4.3.1 | | | | 4.3.3 - Collegamento bidirezionale marker Fabric.js ↔ subtask list | `executor-high` | Dopo 4.3.2 | | 4.4 | **Anteprima Ricetta** | | | Dopo 4.2, 4.3 | | | | 4.4.1 - recipe_preview.html (esattamente come vista MeasurementTec) | `designer` | | | 4.5 | **Versioning UI** | | | Dopo 4.2 | | | | 4.5.1 - Avviso "N misure esistenti" su modifica + conferma | `executor` | | | | | 4.5.2 - version_history.html (storico versioni + change notes) | `designer` | Con 4.5.1 | --- ### FASE 5 - Calibro USB + Barcode | # | Task | Subtask | Agente | Parallelo | |---|------|---------|--------|-----------| | 5.1 | **Web Serial API (Calibro USB)** | | | | | | | 5.1.1 - Ricerca Context7 docs Web Serial API | `researcher` | | | | | 5.1.2 - caliper.js (requestPort, open, read, parse protocollo) | `executor` | Dopo 5.1.1 | | | | 5.1.3 - caliper_status.html (icona: disconnesso/connesso/errore) | `designer` | Con 5.1.2 | | | | 5.1.4 - Integrazione: dato calibro → campo numpad automatico | `executor` | Dopo 5.1.2 | | 5.2 | **Barcode Scanner** | | | **Parallelo con 5.1** | | | | 5.2.1 - barcode.js (html5-qrcode: init camera, decode callback) | `executor` | | | | | 5.2.2 - barcode_scanner.html (modal con preview camera) | `designer` | Con 5.2.1 | | | | 5.2.3 - Integrazione: barcode decodificato → API /recipes/code/{code} | `executor` | Dopo 5.2.1 | --- ### FASE 6 - Dashboard Metrologist | # | Task | Subtask | Agente | Parallelo | |---|------|---------|--------|-----------| | 6.1 | **Backend SPC** | | | | | | | 6.1.1 - Ricerca librerie SPC Python (spc-plotly, scipy.stats) | `researcher` | | | | | 6.1.2 - services/spc_service.py (Cp, Cpk, Pp, Ppk, X-bar, R, sigma) | `executor-high` | Dopo 6.1.1 | | | | 6.1.3 - routers/statistics.py (tutti gli endpoint con filtri) | `executor` | Con 6.1.2 | | | | 6.1.4 - test_spc.py (test calcoli con dataset noti) | `tdd-guide` | Dopo 6.1.2 | | 6.2 | **Frontend Dashboard** | | | Dopo 6.1 | | | | 6.2.1 - blueprints/statistics.py (routes Flask) | `executor` | | | | | 6.2.2 - dashboard.html (overview: riepilogo + capability + alert) | `designer` | Con 6.2.1 | | | | 6.2.3 - filters.html (componente filtri riusabile con htmx) | `designer` | Con 6.2.1 | | 6.3 | **Grafici SPC Plotly.js** | | | Dopo 6.2 | | | | 6.3.1 - spc-charts.js (configurazioni Plotly: layout, colori, zone) | `executor` | | | | | 6.3.2 - control_chart.html (X-bar / R con zone colorate) | `designer` | Con 6.3.1 | | | | 6.3.3 - histogram.html (distribuzione + curva normale sovrapposta) | `designer` | Con 6.3.1 | | | | 6.3.4 - capability.html (gauge Cp/Cpk/Pp/Ppk con indicatori) | `designer` | Con 6.3.1 | | | | 6.3.5 - trend.html (trend temporali + confronto periodi + versioni) | `designer` | Con 6.3.1 | | 6.4 | **Alert e Regole** | | | Dopo 6.3 | | | | 6.4.1 - Western Electric rules detection in spc_service.py | `executor-high` | | | | | 6.4.2 - Visualizzazione alert su dashboard (badge + dettaglio) | `designer` | Dopo 6.4.1 | | 6.5 | **Report PDF** | | | Dopo 6.3 | | | | 6.5.1 - services/report_service.py (WeasyPrint + Kaleido) | `executor` | | | | | 6.5.2 - base_report.html (layout report con logo azienda + brand) | `designer` | Con 6.5.1 | | | | 6.5.3 - spc_report.html (grafici SVG + tabelle statistiche) | `designer` | Con 6.5.1 | | | | 6.5.4 - measurement_report.html (tabella misure dettagliata) | `designer` | Con 6.5.1 | | | | 6.5.5 - routers/reports.py (genera + serve PDF download) | `executor` | Dopo 6.5.1 | --- ### FASE 7 - Polish & Testing | # | Task | Subtask | Agente | Parallelo | |---|------|---------|--------|-----------| | 7.1 | **i18n Completo** | | | | | | | 7.1.1 - Estrarre tutte le stringhe traducibili (pybabel extract) | `executor` | | | | | 7.1.2 - Traduzione IT completa (messages.po) | `writer` | Dopo 7.1.1 | | | | 7.1.3 - Traduzione EN completa (messages.po) | `writer` | Con 7.1.2 | | | | 7.1.4 - Stringhe client-side Alpine.js (JSON IT/EN) | `writer` | Con 7.1.2 | | 7.2 | **Ottimizzazione Tablet** | | | **Parallelo con 7.1** | | | | 7.2.1 - Test responsive su risoluzioni tablet Windows | `designer` | | | | | 7.2.2 - Touch target minimi 44x44px su tutti i bottoni | `designer` | Con 7.2.1 | | | | 7.2.3 - Performance: lazy load PDF.js, ottimizzare bundle JS | `executor` | Con 7.2.1 | | 7.3 | **Testing End-to-End** | | | Dopo 7.1 | | | | 7.3.1 - Test flusso MeasurementTec completo | `tdd-guide` | | | | | 7.3.2 - Test flusso Maker completo (incluso versioning) | `tdd-guide` | Con 7.3.1 | | | | 7.3.3 - Test flusso Metrologist completo (SPC + PDF) | `tdd-guide` | Con 7.3.1 | | 7.4 | **Security & Review finale** | | | Dopo 7.3 | | | | 7.4.1 - Security review completa (OWASP top 10) | `security-reviewer` | | | | | 7.4.2 - Code review finale | `code-reviewer` | Con 7.4.1 | | | | 7.4.3 - Verifica architettura con architect | `architect` | Con 7.4.1 | | 7.5 | **Documentazione** | | | **Parallelo con 7.3** | | | | 7.5.1 - API.md (documentazione API REST con esempi) | `writer` | | | | | 7.5.2 - DEPLOYMENT.md (guida: server, client, MySQL, ZeroTier) | `writer` | Con 7.5.1 | | | | 7.5.3 - USER_GUIDE.md (guida per MeasurementTec, Maker, Metrologist) | `writer` | Con 7.5.1 | --- ## 11. Versioning Ricette ### Principio: Immutable Copy-on-Write **Regola fondamentale**: le versioni delle ricette sono **IMMUTABILI**. Una volta creata, una versione non viene mai modificata. Ogni modifica crea una nuova versione. ### Flusso di Modifica Ricetta ``` 1. Maker apre ricetta "COUPLING-256" (versione corrente: v3) 2. Maker clicca "Modifica" 3. Sistema chiama GET /api/recipes/{id}/versions/3/measurement-count 4. Risultato: ├── SE measurement_count > 0: │ └── Mostra avviso: │ ╔══════════════════════════════════════════════════╗ │ ║ Attenzione: Esistono 847 misure per la v3. ║ │ ║ La modifica creera la versione v4. ║ │ ║ Le misure esistenti resteranno legate a v3. ║ │ ║ ║ │ ║ Motivo modifica: [________________________] ║ │ ║ ║ │ ║ [Procedi] [Annulla] ║ │ ╚══════════════════════════════════════════════════╝ │ └── SE measurement_count == 0: └── Procede alla modifica (crea comunque nuova versione per audit) 5. Maker effettua modifiche (task, subtask, annotazioni, tolleranze) 6. Maker salva → Server: a. Crea v4 copiando struttura da v3 b. Applica le modifiche del Maker c. Copia file immagini/PDF nella cartella v4 d. UPDATE recipe_versions SET is_current = FALSE WHERE version_number = 3 e. INSERT recipe_versions (version_number = 4, is_current = TRUE) f. INSERT recipe_version_audit (change_type = 'UPDATE', change_reason = ...) 7. MeasurementTec successivi lavoreranno con v4 8. Misure storiche restano legate a v3 (immutabile, intoccabile) ``` ### Query Metrologist Cross-Versione Il Metrologist puo: - Filtrare misure per **versione specifica** della ricetta - Vedere **tutte le versioni aggregate** (timeline completa) - **Confrontare statistiche tra versioni** (es: "la v4 ha migliorato il Cpk?") - Vedere quando una versione e stata attivata e perche (audit trail) --- ## 12. Gestione File Server ### Struttura Storage ``` server/uploads/ # Root (configurabile via UPLOAD_DIR env var) ├── images/ # Immagini task │ └── {recipe_id}/ │ └── {version_id}/ │ ├── task_1_drawing.jpg # Originale │ └── task_1_drawing_thumb.jpg # Miniatura 200px auto-generata │ ├── pdfs/ # PDF task (single page consigliato) │ └── {recipe_id}/ │ └── {version_id}/ │ └── task_2_technical.pdf │ ├── logos/ # Logo azienda configurabile │ └── company_logo.png # Caricato da Admin │ └── reports/ # Report PDF generati (temporanei) └── spc_report_20260206_a1b2c3.pdf # Auto-pulizia dopo 24h ``` ### Regole Storage | Regola | Dettaglio | |--------|-----------| | **Dimensione max upload** | Configurabile via `system_settings` (default 50MB) | | **Formati immagine** | JPG, JPEG, PNG, WebP, BMP | | **Formati PDF** | Solo PDF | | **Miniature** | Auto-generate a 200px con Pillow per lista task | | **Naming** | `task_{order}_{original_name}.{ext}` (sanitizzato) | | **Versioning file** | File copiati fisicamente quando si crea nuova versione ricetta | | **Pulizia report** | Cron/scheduled task elimina report > 24h | | **Backup** | Directory `uploads/` inclusa nei backup (escluso `reports/`) | | **Spazio disco** | Monitorare con health check endpoint | ### Configurazione ```python # server/config.py UPLOAD_DIR = os.environ.get("UPLOAD_DIR", "./uploads") MAX_UPLOAD_SIZE_MB = int(os.environ.get("MAX_UPLOAD_SIZE_MB", "50")) ALLOWED_IMAGE_EXTENSIONS = {".jpg", ".jpeg", ".png", ".webp", ".bmp"} ALLOWED_PDF_EXTENSIONS = {".pdf"} THUMBNAIL_SIZE = (200, 200) REPORT_RETENTION_HOURS = 24 ``` --- ## 13. Tastierino Touch (Numpad) ### Design Visuale ``` ┌───────────────────────────────────────────┐ │ Marker #2 - Diametro Interno (mm) │ │ Nominale: 12.500 Tolleranza: ±0.050 │ │ │ │ ┌─────────────────────────────────┐ │ │ │ 12.487 │ │ │ └─────────────────────────────────┘ │ │ ████████████████████████████░░░░░░ PASS │ │ │ │ ┌──────┬──────┬──────┬──────┐ │ │ │ │ │ │ │ │ │ │ 7 │ 8 │ 9 │ ⌫ │ │ │ │ │ │ │ │ │ │ ├──────┼──────┼──────┼──────┤ │ │ │ │ │ │ │ │ │ │ 4 │ 5 │ 6 │ C │ │ │ │ │ │ │ │ │ │ ├──────┼──────┼──────┼──────┤ │ │ │ │ │ │ │ │ │ │ 1 │ 2 │ 3 │ +/- │ │ │ │ │ │ │ │ │ │ ├──────┼──────┼──────┼──────┤ │ │ │ │ │ │ │ │ │ │ 0 │ . │ │ ✓ │ │ │ │ │ │ │ (OK) │ │ │ └──────┴──────┴──────┴──────┘ │ │ │ │ → Prossima: Marker #3 - Lunghezza totale │ └───────────────────────────────────────────┘ ``` ### Specifiche | Caratteristica | Dettaglio | |----------------|-----------| | **Dimensione bottoni** | Minimo 56x56px per touch ottimale su tablet | | **Layout** | 4x4 grid: cifre 0-9, punto `.`, backspace `⌫`, clear `C`, +/- , conferma `✓` | | **Font display** | JetBrains Mono, dimensione grande (24px+), ben leggibile | | **Feedback colore** | Bordo campo cambia in tempo reale: verde/giallo/rosso | | **Barra feedback** | Progress bar colorata sotto il display con stato PASS/WARNING/FAIL | | **Validazione** | Impedisce doppio punto, max 6 decimali, range ragionevole | | **Auto-focus** | Numpad si attiva sul subtask corrente automaticamente | | **Tasto Enter HW** | Tasto Enter da tastiera fisica = bottone conferma ✓ | | **USB override** | Dato da calibro USB popola il campo e mostra feedback automaticamente | | **Navigazione** | Dopo conferma, avanza automaticamente al subtask successivo | | **Vibrazione** | `navigator.vibrate(50)` su pressione tasto (se supportato) | --- ## 14. Internazionalizzazione e Temi ### i18n: Italiano / Inglese **Approccio ibrido**: | Layer | Tecnologia | Stringhe | |-------|-----------|----------| | **Server (Jinja2)** | Flask-Babel | Template HTML, messaggi errore, label form | | **Client (Alpine.js)** | alpinejs-i18n | Stringhe dinamiche, numpad, feedback real-time | | **Report PDF** | Flask-Babel | Contenuto report generato server-side | **Workflow traduzione**: 1. Sviluppatore marca stringhe: `{{ _('Dashboard') }}` o `{% trans %}Misure{% endtrans %}` 2. `pybabel extract` → genera `messages.pot` 3. `pybabel update` → aggiorna `it/messages.po` e `en/messages.po` 4. Traduttore compila → `pybabel compile` → file `.mo` **Preferenza utente**: salvata in `users.language_pref`, applicata su ogni request. ### Tema Dark / Light **Implementazione CSS Variables**: ```css /* themes.css */ :root { /* Brand colors (sempre uguali) */ --color-primary: #2563EB; --color-secondary: #64748B; --color-accent: #1E40AF; --color-pass: #059669; --color-warning: #D97706; --color-fail: #DC2626; /* Light theme (default) */ --bg-primary: #F8FAFC; --bg-secondary: #F1F5F9; --bg-card: #FFFFFF; --text-primary: #0F172A; --text-secondary: #475569; --border-color: #E2E8F0; } .dark { /* Dark theme */ --bg-primary: #0F172A; --bg-secondary: #1E293B; --bg-card: #334155; --text-primary: #F1F5F9; --text-secondary: #94A3B8; --border-color: #475569; } ``` **Preferenza utente**: salvata in `users.theme_pref` + `localStorage` per applicazione immediata. --- ## 15. Sicurezza e Rete ### Autenticazione API Key | Aspetto | Dettaglio | |---------|-----------| | **Header** | `X-API-Key: ` su ogni request | | **Generazione** | 64 caratteri random (secrets.token_urlsafe) | | **Storage** | Hash nel DB, chiave in chiaro solo al momento della generazione | | **Rotazione** | Admin puo rigenerare API key per utente | | **Rate limiting** | Opzionale (future): limitare request per API key | ### HTTPS su ZeroTier | Ambiente | Certificato | Note | |----------|-------------|------| | **Sviluppo** | Self-signed | Generato con openssl, accettare nel browser | | **Produzione** | Let's Encrypt + Caddy | Caddy reverse proxy con auto-HTTPS | ### Best Practice Sicurezza - Password hashate con bcrypt (cost factor 12) - SQL injection: prevenuta da SQLAlchemy ORM (query parametrizzate) - XSS: Jinja2 auto-escaping attivo, CSP headers - Upload: validazione tipo file, dimensione max, sanitizzazione nome - CORS: configurato solo per dominio client Flask - API Key: mai loggata in chiaro, trasmessa solo via HTTPS - Session Flask: cookie `HttpOnly`, `Secure`, `SameSite` --- ## 16. Evoluzioni Future ### v2.0 - Misura Digitale via Camera ``` Tablet camera → Frame capture → OpenCV/MediaPipe → Edge detection → Calibrazione (riferimento noto) → Misura calcolata → Validazione operatore (accetta/rifiuta/ripeti) ``` - **Tecnologie**: OpenCV.js (browser) o Python+OpenCV (server) - **Prerequisito gia previsto**: campo `input_method` estendibile (aggiungere `'camera'`) - **API modulare**: aggiungere endpoint senza modifiche strutturali ### v2.1 - Rete Neurale Analisi Buono/Scarto ``` Immagine pezzo → CNN classificazione (buono/scarto/dubbio) → Confidence score: > 95% → Auto-classificazione 70-95% → Review operatore < 70% → Classificazione manuale ``` - **Tecnologie**: PyTorch/TensorFlow (training), ONNX Runtime (inferenza server), TensorFlow.js (inferenza tablet) - **Training**: dataset da misure storiche, transfer learning (ResNet/EfficientNet) - **Prerequisito gia previsto**: sistema immagini, misure storiche nel DB - **Nuovo**: tabella `ai_predictions` per audit trail predizioni ML ### v2.2 - Altre Evoluzioni | Feature | Descrizione | |---------|-------------| | **Offline mode (PWA)** | Service worker, IndexedDB locale, sync alla riconnessione | | **Dashboard real-time** | WebSocket per aggiornamento live grafici SPC | | **Notifiche** | Alert email/push quando Cpk scende sotto soglia configurabile | | **Integrazione ERP** | API per scambio dati con SAP, Oracle, etc. | | **Multi-stabilimento** | Supporto multi-sede con dati centralizzati | | **Calibrazione strumenti** | Gestione scadenze calibrazione calibri, alert scadenza | | **Export AQDEF** | Formato standard automotive per scambio dati qualita | --- ## 17. Decisioni Architetturali | # | Decisione | Motivazione | |---|-----------|-------------| | D1 | Monorepo server + client | Deploy semplificato, versioning unificato | | D2 | FastAPI async + asyncmy | Performance per tablet multipli simultanei | | D3 | Versioning immutabile ricette (copy-on-write) | Integrita dati storici, compliance QMS/ISO | | D4 | TailwindCSS + CSS Variables | Personalizzazione tema dark/light, look moderno professionale | | D5 | Plotly.js (browser) + Kaleido + WeasyPrint (PDF) | Grafici interattivi + report PDF professionali vettoriali | | D6 | Fabric.js per editor annotazioni | Editor completo drag-and-drop, export JSON, MIT license | | D7 | Web Serial API + fallback input manuale | Supporto calibri USB con fallback universale | | D8 | API Key authentication | Semplice, adeguata per rete ZeroTier privata | | D9 | Ruoli combinabili JSON + flag admin separato | Flessibilita massima senza tabelle join complesse | | D10 | File organizzati per recipe_id/version_id | Isolamento versioni, backup granulare, pulizia facile | | D11 | Numpad touch custom (56x56px) | UX ottimale su tablet, nessuna dipendenza tastiera fisica | | D12 | Branding configurabile (logo + nome da DB) | Riusabilita del sistema per clienti/installazioni diverse | | D13 | i18n ibrido Flask-Babel + alpinejs-i18n | Copertura completa IT/EN: server-side + client-side | | D14 | Font Inter + JetBrains Mono | UI professionale + numeri allineati e leggibili | | D15 | Nome "TieMeasureFlow" by Tielogic | Brand diretto: collega (Tie) misure (Measure) in un flusso (Flow) | --- > **Prossimo passo**: Approvazione piano → Inizio implementazione FASE 0