Otto decisioni dal brainstorming, con il motivo di ognuna: motore su entrambi i lati con versione in lockstep, agente sottile, server che non importa mai VisionSuite, device a livello PC, esecuzione decisa dalla stazione, verdetto tenuto fuori dal grafo, sorgente immagine astratta. Modello dati, API, errori e le quattro domande che restano aperte. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014BBnuACZSCJqXrMYC3LUMU
TieMeasureFlow by Tielogic
Sistema di gestione task per misurazioni con calibro manuale. Soluzione tablet-first, multi-ruolo, con statistiche SPC (Statistical Process Control) integrate, identità per-stazione e rate limiting per-tablet.
Versione corrente: V3.0.0 (in sviluppo) — branch
V3.0.0. Per stato dettagliato e prossimi passi vedidocs/architecture/STATO_PROGETTO.mdedocs/architecture/ROADMAP.md. V3.0.0 lavora sui quindici punti diTieMeasureFlow_modifiche_2026-07-28.md: vedi Novità di V3.0.0.
Panoramica
TieMeasureFlow guida l'operatore attraverso sequenze di misurazione definite dal Maker, registra i valori (da calibro USB HID o numpad touch), e valuta automaticamente la conformità rispetto alle tolleranze configurate. I dati raccolti alimentano una dashboard SPC con indici di capability e control chart, esportabili in PDF.
Caratteristiche principali:
- Recipe versioning condizionale (copy-on-write se esistono misurazioni, update in-place altrimenti)
- Calcolo pass/fail/warning su quattro limiti di tolleranza (UTL, UWL, LWL, LTL)
- Tracciamento del tempo di inserimento per ogni misura (
input_duration_ms): il client misura quanto tempo l'operatore impiega su ciascun subtask, dall'attivazione al salvataggio, utile per analisi di tempo ciclo e produttività - SPC: Cp, Cpk, Pp, Ppk, control chart UCL/LCL, istogramma con curva normale — puro stdlib (no numpy)
- Annotazioni grafiche su disegni tecnici (Fabric.js) con viewer sincronizzato all'esecuzione
- Identità per-stazione (
STATION_CODE): ogni tablet vede solo le ricette assegnate alla propria stazione, gestione assegnazioni via GUI admin - Interfaccia completamente localizzata IT/EN, dark mode, ottimizzata per tablet touch
- Autenticazione API Key, rate limiting sliding window per-IP reale (X-Forwarded-For-aware), audit log persistente
- Capacità testata per ~20 tablet contemporanei (gunicorn 5 workers × 4 thread + uvicorn 4 workers async)
Novità di V3.0.0
V3.0.0 lavora sui quindici punti raccolti in TieMeasureFlow_modifiche_2026-07-28.md,
dal sopralluogo del 28/07. Quanto segue è fatto e in esercizio.
| # | Punto | Cosa cambia |
|---|---|---|
| 1 · 6 | Produzione con una vita propria | production_runs e production_events sul server: avvio, fermo linea, ripresa e fine produzione esistono come stato, non come pulsanti. La fine produzione emette il file di statistica dell'intera produzione |
| 2 | Tipo di task dichiarato | task_type (note, measure, drawing, xf_compare, camera_measure) al posto di «ha subtask, quindi è una misura»: un task di misura senza quote non si comporta più come una nota |
| 3 | Ciclo di misura | L'intervallo della ricetta vive sul server, sopravvive al cambio pagina, conta anche il ritardo (in rosso, oltre lo zero) e riporta l'operatore alla misura. Cicalino via WebAudio |
| 5 | Fuori tolleranza vincolante | Una quota fuori tolleranza blocca l'avanzamento finché il capoturno non autorizza — o finché quella stessa quota non viene rimisurata dentro i limiti. L'autorizzazione resta scritta sulla misura e nel CSV |
| 7 | Stazioni | Ricette per stazione, cambio stazione da URL per il collaudo, reset per riga |
| 8 | Tracciabilità obbligatoria | requires_lot / requires_serial per ricetta, verificati sul server: nessuna porta d'ingresso li aggira, barcode compreso |
| 9 | Blocco inserimento manuale | allow_manual_input: con la ricetta a solo calibro il tastierino non viene disegnato affatto, e il server rifiuta comunque un valore digitato a mano |
| 10 | Sequenza per l'operatore | La ricetta si apre sul primo task, non su un elenco. La lista scende a secondo livello e dice quali task sono rimasti incompiuti (2/3). «Fine ciclo misura» è visibile da subito e spento finché mancano quote |
| 11 | Descrizioni formattate | **grassetto** e a capo nelle descrizioni dei task, con marcatura e non HTML: la sanificazione è per costruzione |
| 12 | Funzionamento senza internet | Tutte le librerie e i font nell'installazione, versioni congelate e verificate per impronta, Content-Security-Policy a sola origine locale |
| 14 | Layout stabile | Una cornice sola per tutte le viste, allineata alla navbar; spazio della barra di scorrimento sempre riservato; schermata di misura su 100dvh. Vedi docs/architecture/LAYOUT.md |
| 15 | Statistica separata | Si registra sempre, si consulta a parte: nessun percorso dell'operatore porta alla statistica (verificato da test) |
Aperto: il punto 4 (numero di tentativi prima del capoturno) attende le risposte del cliente su modalità di autorizzazione e numero di tentativi; il punto 13 (generazione task dalla scheda tecnica con l'AI) è fuori offerta.
Architettura
Browser/Tablet
|
Reverse Proxy (Nginx — sviluppo | Traefik+SSL — produzione)
|
Flask Frontend :5000 (rendering server-side, Jinja2 + Alpine.js)
| X-API-Key + X-Forwarded-For
FastAPI Backend :8000 (API REST asincrona)
|
MySQL 8.0
Il frontend Flask non espone mai le credenziali al browser: ogni chiamata al backend avviene server-side con l'header X-API-Key estratto dalla sessione Flask. L'IP reale del tablet è propagato in X-Forwarded-For per il rate limiter.
Stack Tecnologico
Backend (src/backend/)
| Componente | Versione | Ruolo |
|---|---|---|
| FastAPI | ultima stabile | Framework API REST asincrono |
| SQLAlchemy 2.0 | async | ORM con pool connessioni 10+20 |
| asyncmy | ultima stabile | Driver MySQL asincrono |
| MySQL | 8.0 | Database relazionale |
| Alembic | ultima stabile | Migrazioni schema |
| Pydantic v2 | v2 | Validazione I/O |
| WeasyPrint | ultima stabile | Generazione report PDF |
| Kaleido | ultima stabile | Export grafici Plotly in SVG |
| bcrypt | ultima stabile | Hashing password |
| Pillow | ultima stabile | Thumbnail automatici upload |
Frontend (src/frontend/flask_app/)
| Componente | Versione | Ruolo |
|---|---|---|
| Flask | 3.x | Framework web server-side |
| gunicorn | 21+ | WSGI server (5 workers × 4 thread gthread) |
| Jinja2 | incluso in Flask | Template engine |
| Alpine.js | 3.15.12 (locale) | Reattività leggera lato client |
| TailwindCSS | 3.4.19 (build) | CSS utility-first, compilato nell'immagine |
| Plotly.js | 2.32.0 (locale) | Grafici SPC interattivi |
| PDF.js | 3.11.174 (locale) | Visualizzazione disegni PDF, worker incluso |
| Fabric.js | 5.3.1 (locale) | Editor annotazioni disegni tecnici |
| Inter + JetBrains Mono | woff2 locali | Font UI e numeri |
| Flask-Babel | ultima stabile | i18n IT/EN |
Nessuna libreria arriva dalla rete. Tutte stanno in
src/frontend/flask_app/static/vendor/
con versione nel nome e impronta SHA-256 verificata da un test: l'installazione a
Tràfilo è su rete di produzione isolata, dove una pagina che aspetta un CDN è una
pagina bianca. Una Content-Security-Policy a sola origine locale (app.py) fa sì che
un tag verso l'esterno aggiunto in futuro venga rifiutato alla scrivania, non in
reparto.
Tooling
| Componente | Ruolo |
|---|---|
| uv | Package manager Python (no requirements.txt) |
pyproject.toml |
Dipendenze monorepo con extra server/client/dev |
uv.lock |
Lockfile per build riproducibili |
.python-version |
Pin Python 3.11 |
| pytest + pytest-asyncio + httpx + aiosqlite | Test stack |
Quick Start con Docker
Docker Compose è il metodo raccomandato. Gestisce database, migrazioni, build delle immagini con uv e configurazione Nginx in un solo comando.
# 1. Clona il repository
git clone ssh://git@git.tielogic.xyz:222/Adriano/TieMeasureFlow.git
cd TieMeasureFlow
# 2. Configura le variabili d'ambiente
cp .env.example .env
# Modifica .env: credenziali DB, chiavi segrete, SETUP_PASSWORD, STATION_CODE per ogni tablet
# 3. Avvia i servizi (ambiente di sviluppo)
docker compose -f docker-compose.dev.yml up -d --build
# 4. Verifica lo stato dei container
docker compose -f docker-compose.dev.yml ps
# 5. Setup iniziale (solo al primo avvio)
# Apri http://localhost/api/setup nel browser
# Usa SETUP_PASSWORD configurata in .env
# Lo script seed crea anche la stazione ST-DEFAULT con tutte le ricette assegnate
L'applicazione sarà disponibile su:
- Frontend: http://localhost
- API: http://localhost/api
- Pagina setup: http://localhost/api/setup
- Admin stazioni: http://localhost/admin/stations (solo
is_admin)
Per il deployment in produzione (Traefik + SSL) consulta docs/DEPLOYMENT.md.
Setup Iniziale
Dopo il primo avvio, la pagina /api/setup (protetta da SETUP_PASSWORD) permette di:
- Initialize Database — crea tutte le tabelle
- Create Admin User — crea l'utente amministratore con credenziali da
.env - Seed Demo Data — carica ricette, misurazioni e utenti di esempio + crea stazione
ST-DEFAULTcon tutte le ricette assegnate - Reset Database — elimina e ricrea tutte le tabelle (attenzione: cancella tutti i dati)
- Gestione utenti — crea, modifica, attiva/disattiva account dalla stessa pagina
Se SETUP_PASSWORD è vuota o assente nel .env, l'endpoint è disabilitato.
Per gestire stazioni e assegnazioni ricette dopo il setup: /admin/stations (richiede login admin).
Setup Manuale (Senza Docker)
Requisiti
- Python 3.11 o superiore
- Node.js 18 o superiore (per TailwindCSS)
- MySQL 8.0
- uv installato
1. Database MySQL
mysql -u root -p <<'SQL'
CREATE DATABASE tiemeasureflow CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'tielogic'@'localhost' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON tiemeasureflow.* TO 'tielogic'@'localhost';
FLUSH PRIVILEGES;
SQL
2. Configurazione
cp .env.example .env
# Imposta DB_HOST, DB_USER, DB_PASSWORD, DB_NAME, SERVER_SECRET_KEY,
# CLIENT_SECRET_KEY, SETUP_PASSWORD, STATION_CODE
3. Installa dipendenze (uv)
uv sync --extra server --extra client --extra dev
4. Backend FastAPI
uv run alembic -c src/backend/migrations/alembic.ini upgrade head
uv run uvicorn src.backend.main:app --reload --host 0.0.0.0 --port 8000
5. Frontend Flask
# Compila i cataloghi i18n una volta
cd src/frontend/flask_app && uv run --project ../../.. pybabel compile -d translations && cd -
# Avvia (development)
cd src/frontend/flask_app && uv run --project ../../.. flask run --host 0.0.0.0 --port 5000
6. TailwindCSS (watch per sviluppo)
cd src/frontend/flask_app
npx tailwindcss -i static/css/input.css -o static/css/tailwind.css --watch
Accesso diretto (senza Nginx):
- Frontend: http://localhost:5000
- API: http://localhost:8000
Ruoli Utente
I ruoli sono combinabili (array JSON per utente). Il flag is_admin è separato dai ruoli funzionali.
| Ruolo | Descrizione |
|---|---|
| Maker | Crea e gestisce ricette di misurazione: caricamento disegni (PDF/immagini), annotazioni Fabric.js, definizione task/subtask, configurazione tolleranze, versioning copy-on-write |
| MeasurementTec | Esegue misurazioni: scansione barcode per selezione ricetta, interfaccia task-driven, input da calibro USB HID o numpad touch, validazione real-time pass/warning/fail. Vede solo le ricette assegnate alla propria stazione (STATION_CODE) |
| Supervisor (capoturno) | Autorizza ciò che l'operatore non può decidere da solo: una quota fuori tolleranza che deve restare, il fermo linea, la fine produzione. L'autorizzazione resta scritta sulla misura (supervisor_id, authorised_at) e finisce nel file di statistica |
| Metrologist | Analisi qualità: dashboard SPC (X-bar, R, Cp, Cpk, Pp, Ppk), filtri multi-dimensionali, export report PDF, analisi capability e control chart. L'operatore non raggiunge la statistica da nessun percorso |
| Admin (flag) | Gestione sistema: CRUD utenti, cambio password, attivazione/disattivazione account, CRUD stazioni e assegnazioni ricette |
Struttura Progetto
TieMeasureFlow/
├── pyproject.toml # Dipendenze monorepo (uv)
├── uv.lock # Lockfile riproducibile
├── .python-version # 3.11
├── Dockerfile # Backend (uv + uvicorn)
├── Dockerfile.frontend # Frontend (uv + gunicorn + Tailwind + Babel)
├── docker-compose.dev.yml # Sviluppo (Nginx, porta 80)
├── docker-compose.yml # Produzione (Traefik, SSL)
├── nginx/ # Config Nginx (dev)
├── uploads/ # Volume Docker file caricati
├── scripts/ # Script del progetto (seed ricette di collaudo)
├── docs/ # Documentazione (vedi indice docs/README.md)
└── src/
├── backend/ # FastAPI Backend
│ ├── main.py # Entry point, lifespan, middleware, 11 router
│ ├── config.py # Settings (pydantic_settings.BaseSettings)
│ ├── database.py # SQLAlchemy 2.0 async engine
│ ├── api/
│ │ ├── routers/ # auth, users, recipes, tasks, measurements,
│ │ │ # files, settings, statistics, reports,
│ │ │ # setup, stations
│ │ └── middleware/ # api_key, rate_limit, security_headers, logging
│ ├── models/
│ │ ├── orm/ # SQLAlchemy: User, Recipe, RecipeVersion,
│ │ │ # RecipeTask, RecipeSubtask, Measurement,
│ │ │ # AccessLog, SystemSetting,
│ │ │ # RecipeVersionAudit, Station,
│ │ │ # StationRecipeAssignment,
│ │ │ # ProductionRun, ProductionEvent
│ │ └── api/ # Pydantic v2 schemas request/response
│ ├── services/ # recipe_service, measurement_service,
│ │ # spc_service, report_service,
│ │ # auth_service, station_service,
│ │ # production_service,
│ │ # production_export_service
│ ├── migrations/ # Alembic (alembic.ini + env.py)
│ ├── templates/ # Pagina setup (Jinja2)
│ └── tests/ # pytest + httpx + aiosqlite
└── frontend/
└── flask_app/ # Flask Frontend
├── app.py # Factory + ProxyFix + CSRF + Babel
├── config.py # STATION_CODE, API_SERVER_URL, ecc.
├── compile_translations.py
├── blueprints/ # auth, maker, measure, statistics, admin
├── services/ # APIClient (proxy verso FastAPI con XFF)
├── templates/ # Jinja2 + Alpine.js
├── static/
│ ├── css/ # TailwindCSS compilato + themes.css
│ │ # (cornice pagina, temi, scrollbar)
│ ├── js/ # numpad, caliper, barcode, csv-export,
│ │ # spc-charts, annotation-editor/viewer,
│ │ # production-clock, rich-text
│ └── vendor/ # Alpine, Plotly, PDF.js (+worker), Fabric,
│ # font woff2 — vedi VERSIONS.md
├── translations/ # Flask-Babel .po/.mo IT/EN
└── tests/
Comandi Utili
Docker
| Comando | Descrizione |
|---|---|
docker compose -f docker-compose.dev.yml up -d --build |
Avvia servizi in sviluppo (build incluso) |
docker compose -f docker-compose.dev.yml down |
Ferma e rimuove i container |
docker compose logs -f server |
Segui log server in tempo reale |
docker compose logs -f client |
Segui log client in tempo reale |
docker compose ps |
Stato di tutti i servizi |
docker compose build --no-cache |
Ricostruisci immagini senza cache |
docker compose exec mysql mysql -u root -p tiemeasureflow |
CLI MySQL |
Alembic (migrations)
alembic.ini si trova in src/backend/migrations/, è richiesto il flag -c. env.py aggiunge la project root a sys.path per risolvere src.backend.*.
uv run alembic -c src/backend/migrations/alembic.ini upgrade head # Applica migrazioni
uv run alembic -c src/backend/migrations/alembic.ini revision --autogenerate -m "descrizione" # Genera
uv run alembic -c src/backend/migrations/alembic.ini downgrade -1 # Rollback ultima
Via Docker:
docker compose exec server uv run alembic -c src/backend/migrations/alembic.ini upgrade head
i18n (Traduzioni)
cd src/frontend/flask_app
uv run --project ../../.. pybabel extract -F babel.cfg -k _ -o translations/messages.pot . # Estrai
uv run --project ../../.. pybabel update -i translations/messages.pot -d translations # Aggiorna
uv run --project ../../.. pybabel compile -d translations # Compila .po → .mo
Gestione dipendenze (uv)
uv add <pacchetto> # core (entrambi)
uv add --optional server <pacchetto> # solo backend
uv add --optional client <pacchetto> # solo frontend
uv add --optional dev <pacchetto> # solo dev/test
uv sync --extra server --extra client --extra dev # reinstalla
uv lock # rigenera uv.lock
Testing
Il backend usa SQLite in-memory tramite aiosqlite: i test girano senza MySQL installato.
# Tutti i test (backend + frontend)
uv run pytest
# Solo backend
uv run pytest src/backend/tests/
uv run pytest src/backend/tests/test_auth.py
uv run pytest src/backend/tests/test_auth.py::test_login_success
uv run pytest --cov src/backend
# Solo frontend
uv run pytest src/frontend/flask_app/tests/
Stato corrente su V3.0.0: 360 pass, 0 fail (212 backend + 148 frontend).
Alcuni test frontend non renderizzano niente e leggono i sorgenti, perché guardano proprietà che sopravvivono solo se qualcuno le controlla:
| File | Cosa impedisce |
|---|---|
test_offline.py |
Una libreria caricata dalla rete, un worker PDF.js lasciato sul CDN, una libreria sostituita senza aggiornare l'impronta |
test_layout_shell.py |
Una vista che torna a dichiararsi la propria larghezza |
test_template_js_syntax.py |
Una traduzione con l'apostrofo dentro una stringa JS a virgolette singole, che spegne Alpine su tutta la pagina |
Variabili d'Ambiente
Copia .env.example in .env e configura:
| Variabile | Descrizione |
|---|---|
DB_HOST, DB_PORT, DB_NAME |
Connessione MySQL |
DB_USER, DB_PASSWORD |
Credenziali utente MySQL |
DB_ROOT_PASSWORD |
Password root MySQL (solo Docker) |
SERVER_SECRET_KEY |
Chiave segreta FastAPI |
SERVER_CORS_ORIGINS |
Origini CORS ammesse |
CLIENT_SECRET_KEY |
Chiave segreta Flask (sessioni, CSRF) |
API_SERVER_URL |
URL del backend visto dal client (es. http://server:8000) |
STATION_CODE |
Per-tablet — codice stazione (es. ST-001). Senza, il client mostra errore configurazione. |
UPLOAD_DIR |
Percorso upload file (default: uploads, project root) |
MAX_UPLOAD_SIZE_MB |
Limite dimensione upload (default 50) |
RATE_LIMIT_LOGIN |
Login req/min/IP (default 5) |
RATE_LIMIT_GENERAL |
Richieste req/min/IP (default 300, per-tablet) |
NGINX_PORT, NGINX_SSL_PORT |
Porte Nginx (solo compose dev) |
SETUP_PASSWORD |
Password pagina setup (vuota = endpoint disabilitato) |
SSL_CERTFILE, SSL_KEYFILE |
Certificato SSL (solo setup manuale) |
Documentazione
Indice completo: docs/README.md.
Stato e direzione
| Documento | Contenuto |
|---|---|
TieMeasureFlow_modifiche_2026-07-28.md |
I quindici punti del 28/07: cosa deve cambiare, dove intervenire, decisioni in attesa del cliente (D-1…D-9) |
docs/architecture/STATO_PROGETTO.md |
Snapshot V2.0.0: cosa funziona oggi, test status, decisioni architetturali |
docs/architecture/ROADMAP.md |
Cosa resta da fare (Fasi 2-7 rev04, decisioni cliente aperte, stime) |
Riferimenti operativi
| Documento | Contenuto |
|---|---|
docs/API.md |
Riferimento completo API REST (endpoint, parametri, schemi) |
docs/DEPLOYMENT.md |
Guida deployment VPS: Docker, Traefik, SSL, DNS, firewall |
docs/USER_GUIDE.md |
Manuale utente per ruolo (Maker, MeasurementTec, Metrologist) |
docs/I18N_SETUP.md |
Setup e workflow traduzioni (Flask-Babel + Alpine.js) |
docs/architecture/LAYOUT.md |
La cornice delle pagine: perché il layout si spostava e la regola che lo tiene fermo |
src/frontend/flask_app/static/vendor/VERSIONS.md |
Librerie di terze parti in locale: versioni, impronte, come aggiornarle |
Piani dettagliati
| Documento | Contenuto |
|---|---|
docs/superpowers/plans/2026-04-17-rev04-master-roadmap.md |
Master plan rev04 (M1 + M2, decisioni aperte, stime) |
docs/superpowers/plans/2026-04-17-rev04-phase1-stations.md |
Piano TDD Fase 1 stazioni (completato) |
Licenza
Proprietary — Tielogic. All rights reserved.
Questo software è di proprietà esclusiva di Tielogic ed è protetto dalle leggi sul copyright. Non è consentita la distribuzione, modifica o utilizzo senza autorizzazione scritta.