Files
TieMeasureFlow/README.md
T
Adriano 563b7789f4 docs(readme): rewrite for V2.0.0 — uv, src/ layout, stations, docs index
Brings the entry-point README in line with the V2.0.0 restructure:

- Replace all server/ + client/ paths with src/backend/ +
  src/frontend/flask_app/.
- Replace pip install -r requirements.txt with the uv workflow
  (uv sync --extra server --extra client --extra dev).
- Manual setup section uses uv run uvicorn / uv run flask /
  uv run alembic / uv run pybabel, all driven from the project root.
- Document the V2.0.0 additions: STATION_CODE per-tablet, /admin/
  stations GUI, gunicorn 5x4 + uvicorn 4 worker scaling, X-Forwarded
  -For-aware rate limiting (RATE_LIMIT_GENERAL default 300).
- Add tooling section (uv, pyproject.toml, uv.lock, .python-version,
  pytest stack).
- Documentation section now points at the new docs/ index plus the
  STATO_PROGETTO + ROADMAP architecture pair as the canonical "what
  is done / what is next" references.
- Variabili d'Ambiente: add STATION_CODE, RATE_LIMIT_LOGIN,
  RATE_LIMIT_GENERAL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 12:48:51 +02:00

405 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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:** V2.0.0 (in sviluppo) — branch default `V2.0.0`.
> Per stato dettagliato e prossimi passi vedi [`docs/architecture/STATO_PROGETTO.md`](docs/architecture/STATO_PROGETTO.md) e [`docs/architecture/ROADMAP.md`](docs/architecture/ROADMAP.md).
---
## 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)
- 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)
---
## 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.x (CDN) | Reattività leggera lato client |
| TailwindCSS | 3.x | CSS utility-first |
| Plotly.js | CDN | Grafici SPC interattivi |
| Fabric.js | 5.3.1 (CDN) | Editor annotazioni disegni tecnici |
| html5-qrcode | CDN | Scanner barcode/QR camera |
| Flask-Babel | ultima stabile | i18n IT/EN |
### 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.
```bash
# 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`](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-DEFAULT` con 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](https://docs.astral.sh/uv/) installato
### 1. Database MySQL
```bash
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
```bash
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)
```bash
uv sync --extra server --extra client --extra dev
```
### 4. Backend FastAPI
```bash
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
```bash
# 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)
```bash
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`) |
| **Metrologist** | Analisi qualità: dashboard SPC (X-bar, R, Cp, Cpk, Pp, Ppk), filtri multi-dimensionali, export report PDF, analisi capability e control chart |
| **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
├── 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
│ │ └── api/ # Pydantic v2 schemas request/response
│ ├── services/ # recipe_service, measurement_service,
│ │ # spc_service, report_service,
│ │ # auth_service, station_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
│ └── js/ # numpad, caliper, barcode, csv-export,
│ # spc-charts, annotation-editor/viewer
├── 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.*`.
```bash
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:
```bash
docker compose exec server uv run alembic -c src/backend/migrations/alembic.ini upgrade head
```
### i18n (Traduzioni)
```bash
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)
```bash
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.
```bash
# 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: **171 pass, 4 fail pre-esistenti** (vedi `docs/architecture/STATO_PROGETTO.md`).
---
## 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`](docs/README.md).
### Stato e direzione
| Documento | Contenuto |
|---|---|
| [`docs/architecture/STATO_PROGETTO.md`](docs/architecture/STATO_PROGETTO.md) | Snapshot V2.0.0: cosa funziona oggi, test status, decisioni architetturali |
| [`docs/architecture/ROADMAP.md`](docs/architecture/ROADMAP.md) | Cosa resta da fare (Fasi 2-7 rev04, decisioni cliente aperte, stime) |
### Riferimenti operativi
| Documento | Contenuto |
|---|---|
| [`docs/API.md`](docs/API.md) | Riferimento completo API REST (endpoint, parametri, schemi) |
| [`docs/DEPLOYMENT.md`](docs/DEPLOYMENT.md) | Guida deployment VPS: Docker, Traefik, SSL, DNS, firewall |
| [`docs/USER_GUIDE.md`](docs/USER_GUIDE.md) | Manuale utente per ruolo (Maker, MeasurementTec, Metrologist) |
| [`docs/I18N_SETUP.md`](docs/I18N_SETUP.md) | Setup e workflow traduzioni (Flask-Babel + Alpine.js) |
### Piani dettagliati
| Documento | Contenuto |
|---|---|
| [`docs/superpowers/plans/2026-04-17-rev04-master-roadmap.md`](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`](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.