diff --git a/README.md b/README.md index 84968fb..d807b41 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ # TieMeasureFlow by Tielogic -Sistema di gestione task per misurazioni con calibro manuale. Soluzione tablet-first, multi-ruolo, con statistiche SPC (Statistical Process Control) integrate. +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). --- @@ -14,8 +17,10 @@ Caratteristiche principali: - 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, audit log persistente +- 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) --- @@ -26,25 +31,25 @@ Browser/Tablet | Reverse Proxy (Nginx — sviluppo | Traefik+SSL — produzione) | -Flask Client :5000 (rendering server-side, Jinja2 + Alpine.js) - | X-API-Key -FastAPI Server :8000 (API REST asincrona) +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 client 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. +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 (server/) +### Backend (`src/backend/`) | Componente | Versione | Ruolo | |---|---|---| | FastAPI | ultima stabile | Framework API REST asincrono | -| SQLAlchemy 2.0 | async | ORM con pool connessioni | +| 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 | @@ -54,35 +59,47 @@ Il client Flask non espone mai le credenziali al browser: ogni chiamata al backe | bcrypt | ultima stabile | Hashing password | | Pillow | ultima stabile | Thumbnail automatici upload | -### Frontend (client/) +### 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) | Reattivita leggera lato client | +| 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 e configurazione Nginx in un solo comando. +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 +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 +# 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 +docker compose -f docker-compose.dev.yml up -d --build # 4. Verifica lo stato dei container docker compose -f docker-compose.dev.yml ps @@ -90,6 +107,7 @@ 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: @@ -97,8 +115,9 @@ 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). +Per il deployment in produzione (Traefik + SSL) consulta [`docs/DEPLOYMENT.md`](docs/DEPLOYMENT.md). --- @@ -108,12 +127,14 @@ Dopo il primo avvio, la pagina `/api/setup` (protetta da `SETUP_PASSWORD`) perme - **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 +- **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) @@ -121,8 +142,9 @@ Se `SETUP_PASSWORD` è vuota o assente nel `.env`, l'endpoint è disabilitato. ### Requisiti - Python 3.11 o superiore -- Node.js 18 o superiore +- Node.js 18 o superiore (per TailwindCSS) - MySQL 8.0 +- [uv](https://docs.astral.sh/uv/) installato ### 1. Database MySQL @@ -139,35 +161,37 @@ SQL ```bash cp .env.example .env -# Imposta DB_HOST, DB_USER, DB_PASSWORD, DB_NAME, SERVER_SECRET_KEY, CLIENT_SECRET_KEY, SETUP_PASSWORD +# Imposta DB_HOST, DB_USER, DB_PASSWORD, DB_NAME, SERVER_SECRET_KEY, +# CLIENT_SECRET_KEY, SETUP_PASSWORD, STATION_CODE ``` -### 3. Server FastAPI +### 3. Installa dipendenze (uv) ```bash -cd server -python -m venv venv -source venv/bin/activate # Windows: venv\Scripts\activate -pip install -r requirements.txt -alembic -c migrations/alembic.ini upgrade head -uvicorn main:app --reload --host 0.0.0.0 --port 8000 +uv sync --extra server --extra client --extra dev ``` -### 4. Client Flask +### 4. Backend FastAPI ```bash -cd client -python -m venv venv -source venv/bin/activate # Windows: venv\Scripts\activate -pip install -r requirements.txt -pybabel compile -d translations -flask run --host 0.0.0.0 --port 5000 +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. TailwindCSS (watch per sviluppo) +### 5. Frontend Flask ```bash -cd client +# 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 ``` @@ -185,9 +209,9 @@ I ruoli sono combinabili (array JSON per utente). Il flag `is_admin` è separato | 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 | +| **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 | +| **Admin** (flag) | Gestione sistema: CRUD utenti, cambio password, attivazione/disattivazione account, **CRUD stazioni e assegnazioni ricette** | --- @@ -195,39 +219,53 @@ I ruoli sono combinabili (array JSON per utente). Il flag `is_admin` è separato ``` TieMeasureFlow/ -├── server/ # FastAPI Backend -│ ├── main.py # Entry point, lifespan, middleware, 10 router -│ ├── config.py # Settings (pydantic_settings.BaseSettings) -│ ├── database.py # SQLAlchemy 2.0 async engine -│ ├── models/ # ORM: User, Recipe, RecipeVersion, RecipeTask, -│ │ # RecipeSubtask, Measurement, AccessLog, -│ │ # SystemSetting, RecipeVersionAudit -│ ├── schemas/ # Pydantic v2 per validazione I/O API -│ ├── routers/ # auth, users, recipes, tasks, measurements, -│ │ # files, settings, statistics, reports, setup -│ ├── services/ # recipe_service, measurement_service, -│ │ # spc_service, report_service, auth_service -│ ├── middleware/ # api_key, rate_limit, security_headers, logging -│ ├── migrations/ # Alembic (alembic.ini + env.py) -│ └── templates/ # Template HTML pagina setup -├── client/ # Flask Frontend -│ ├── app.py # Factory pattern, CSRF, Babel -│ ├── blueprints/ # auth, maker, measure, statistics, admin -│ ├── services/ # APIClient singleton (proxy verso FastAPI) -│ ├── 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 -├── nginx/ # Configurazione Nginx (dev) -├── docs/ # Documentazione tecnica -│ ├── API.md # Riferimento API REST -│ ├── DEPLOYMENT.md # Guida deployment VPS (Traefik, SSL, DNS) -│ └── USER_GUIDE.md # Manuale utente per ruolo -├── docker-compose.yml # Produzione (Traefik, SSL) -├── docker-compose.dev.yml # Sviluppo (Nginx, porta 80) -└── .env.example # Template variabili d'ambiente +├── 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/ ``` --- @@ -238,7 +276,7 @@ TieMeasureFlow/ | Comando | Descrizione | |---|---| -| `docker compose -f docker-compose.dev.yml up -d` | Avvia servizi in sviluppo | +| `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 | @@ -248,47 +286,62 @@ TieMeasureFlow/ ### Alembic (migrations) -Nota: `alembic.ini` si trova dentro `server/migrations/`, è richiesto il flag `-c`. +`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 -cd server -alembic -c migrations/alembic.ini upgrade head # Applica migrazioni -alembic -c migrations/alembic.ini revision --autogenerate -m "descrizione" # Genera migrazione -alembic -c migrations/alembic.ini downgrade -1 # Rollback ultima +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 alembic -c migrations/alembic.ini upgrade head +docker compose exec server uv run alembic -c src/backend/migrations/alembic.ini upgrade head ``` ### i18n (Traduzioni) ```bash -cd client -pybabel extract -F babel.cfg -k _ -o translations/messages.pot . # Estrai stringhe -pybabel update -i translations/messages.pot -d translations # Aggiorna catalogo -pybabel compile -d translations # Compila .po → .mo +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 # core (entrambi) +uv add --optional server # solo backend +uv add --optional client # solo frontend +uv add --optional dev # solo dev/test +uv sync --extra server --extra client --extra dev # reinstalla +uv lock # rigenera uv.lock ``` --- ## Testing -Il server usa SQLite in-memory tramite `aiosqlite`: i test girano senza MySQL installato. +Il backend usa SQLite in-memory tramite `aiosqlite`: i test girano senza MySQL installato. ```bash -# Server -cd server && pytest # Tutti i test -cd server && pytest tests/test_auth.py # Singolo modulo -cd server && pytest tests/test_auth.py::test_login_success # Singolo test -cd server && pytest --cov # Con copertura +# Tutti i test (backend + frontend) +uv run pytest -# Client -cd client && 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 @@ -304,8 +357,11 @@ Copia `.env.example` in `.env` e configura: | `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`) | -| `UPLOAD_DIR` | Percorso upload file (default: `uploads`, relativo a `server/`) | -| `MAX_UPLOAD_SIZE_MB` | Limite dimensione upload | +| `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) | @@ -314,16 +370,35 @@ Copia `.env.example` in `.env` e configura: ## Documentazione +Indice completo: [`docs/README.md`](docs/README.md). + +### Stato e direzione + | 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/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. +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.