Files
Adriano e4eb4cd932 docs: refresh stato + roadmap with smoke-test findings; fix sort syntax
STATO_PROGETTO.md
- Bumped snapshot date to 2026-04-27.
- Added "Hardening post-restructure (smoke test 2026-04-26)" section
  recording the four runtime regressions surfaced by the local smoke
  test (env_file path, missing Station import, UPLOAD_DIR default,
  apostrophe-in-translation in Alpine), plus the recipe-assignment
  modal UX rework and the new node-based JS syntax test guard.
- Added "Smoke test status" section listing the verified end-to-end
  flow (MySQL up, alembic, seed, login, admin pages, MeasurementTec
  workflow, hot reload).
- Bumped frontend test count 44 → 46 to reflect
  test_template_js_syntax.py.

ROADMAP.md
- Added a tech-debt entry for the user-reported task_complete
  riepilogo rendering anomaly (still under investigation: the curl
  fetch returns the table populated, but the user reports an empty
  body in the browser).
- Added a tech-debt entry for the still-pending Docker container
  smoke test of the new uv-based Dockerfiles.

src/frontend/flask_app/templates/measure/task_complete.html
- Replaced sort(attribute='task_info.order_index,subtask.marker_number')
  with two chained stable sorts. Jinja's sort filter does not accept a
  comma-separated multi-attribute string; the previous form sorted on
  a non-existent attribute and only worked by accident because the
  API already returned rows in the desired order.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 13:10:58 +02:00

9.4 KiB
Raw Permalink Blame History

Stato Progetto TieMeasureFlow — V2.0.0

Snapshot al 2026-04-27. Aggiornare ad ogni milestone.

Versione corrente

V2.0.0 (in sviluppo, branch V2.0.0 come default su git.tielogic.xyz).

Versione precedente di produzione: V1.0.7.

Sintesi esecutiva

Il sistema base (V1.0.7) è completo e collaudato: ricette, task, misurazioni, SPC, report PDF, gestione utenti, dashboard metrologist. La V2.0.0 in corso aggiunge il primo blocco della migrazione rev04 (stazioni per-tablet) e ristruttura l'intero monorepo secondo lo standard python-project-spec-design.md (uv + src/backend/ + src/frontend/flask_app/).

Cosa funziona oggi (V2.0.0 — branch corrente)

Funzionalità ereditate da V1.0.7

  • Autenticazione username/password + API key per-utente, ruoli combinabili (Maker, MeasurementTec, Metrologist) + flag is_admin.
  • Recipe versioning copy-on-write: una nuova versione si crea solo se la corrente ha già measurements; altrimenti update in-place.
  • Editor ricette (Maker) con annotation editor Fabric.js (~1200 LOC, collaudato su tablet).
  • Workflow operatore tablet: select_recipe → task_list → task_execute → task_complete, con barcode scanner e numpad touch (input USB calibro con burst detection).
  • Calcolo pass/fail con limiti UTL/UWL/LWL/LTL.
  • Dashboard SPC: capability (Cp/Cpk/Pp/Ppk), control chart (UCL/LCL = mean ± 3σ), istogramma con curva normale, calcoli puro stdlib (no numpy).
  • Report PDF (WeasyPrint + Kaleido SVG).
  • Setup page protetta da SETUP_PASSWORD per inizializzazione DB e seed.
  • i18n IT/EN (Flask-Babel + Alpine.js JSON).
  • Tema light/dark via Alpine.store('theme') + localStorage.

Aggiunte V2.0.0 (rev04 Fase 1 — Stazioni per-tablet)

  • Tabelle stations + station_recipe_assignments (Alembic migration 002_add_stations.py).
  • Modelli ORM: Station, StationRecipeAssignment con vincolo unique (station_id, recipe_id).
  • Schemas Pydantic: StationCreate/Update/Response, StationRecipeAssignmentCreate/Response, RecipeSummary.
  • Service station_service (CRUD + assegnazioni + cascade delete).
  • Router /api/stations con CRUD admin + endpoint operatore GET /api/stations/by-code/{code}/recipes.
  • Seed automatico ST-DEFAULT con tutte le ricette esistenti (idempotente).
  • Variabile env client STATION_CODE letta da Config, helper APIClient.get_station_recipes().
  • Filtro select_recipe: il client mostra solo le ricette assegnate alla propria stazione, errore se STATION_CODE non configurato.
  • GUI admin completa in /admin/stations: tabella con search, modal create/edit, modal gestione assegnazioni ricette, conferma eliminazione, link in navbar (desktop + mobile).
  • 47 nuovi test (32 server + 15 client) tutti pass.

Aggiunte V2.0.0 (performance + multi-utente)

  • Gunicorn 5 workers × 4 thread (gthread) — capacità ~20 richieste concorrenti Flask, regge 20+ tablet.
  • Uvicorn 4 workers + --proxy-headers --forwarded-allow-ips='*'.
  • Rate limit middleware: identificazione IP reale via X-Forwarded-ForX-Real-IPrequest.client.host.
  • Rate limit general 100 → 300 req/min/IP (per-tablet ora, non più condiviso).
  • Flask ProxyFix(x_for=1, x_proto=1, x_host=1) per IP reale dietro Nginx.
  • APIClient propaga X-Forwarded-For + X-Real-IP (sia JSON che multipart).
  • 12 test aggiuntivi (7 server + 5 client).

Aggiunte V2.0.0 (struttura monorepo)

  • pyproject.toml unico con extra server/client/dev. Niente più requirements.txt.
  • uv.lock (77 pacchetti) + .python-version (3.11) committati per build riproducibili.
  • Layout src/backend/ + src/frontend/flask_app/ (vedi sotto).
  • Dockerfile (root) + Dockerfile.frontend riscritti con uv sync --frozen --no-dev --extra server|client.
  • docker-compose.{dev,}.yml con build context ..
  • Alembic env.py aggiunge project root a sys.path; script_location = %(here)s resta valido.
  • .dockerignore aggiornato.

Hardening post-restructure (smoke test 2026-04-26)

Sequenza di smoke test in locale (uvicorn + gunicorn + MySQL Docker) ha fatto emergere quattro regressioni che sarebbero rimaste invisibili al test suite:

  • src/backend/config.py: env_file era cwd-relative (../../.env). Rotto fuori da src/backend/. Risolto con percorso assoluto Path(__file__).resolve().parents[2] / ".env".
  • src/backend/models/orm/__init__.py: Station e StationRecipeAssignment non erano esportati, quindi Base.metadata.create_all non creava le tabelle stations. Aggiunti agli import.
  • .env.example: UPLOAD_DIR=server/uploads era residuo della vecchia struttura → file landavano fuori dall'albero di progetto. Aggiornato a UPLOAD_DIR=uploads.
  • Apostrofi italiani in template Alpine (l'utente, nell'eliminazione, nell'assegnazione): chiudevano prematuramente JS string literals dentro x-text e blocchi <script>. Riscritti con delimitatori &quot;...&quot; o riformulazione testuale.

Inoltre UX rework della modale assegnazione ricette su /admin/stations: dropdown sostituita da layout a 2 colonne (disponibili / assegnate) con bottone inline + Assegna, search filter, empty state esplicativo (mostrava silenziosamente lista vuota se tutte le ricette erano già assegnate).

Test guard aggiunto: test_template_js_syntax.py valida ogni inline <script> E ogni espressione Alpine (x-*, @*, :*) della pagina con node --check. Cattura automaticamente il bug-class apostrofo. Skip se Node non è installato.

Layout repository (V2.0.0)

TieMeasureFlow/
├── pyproject.toml + uv.lock + .python-version
├── Dockerfile (backend) + Dockerfile.frontend
├── docker-compose.dev.yml + docker-compose.yml
├── nginx/
├── uploads/                      # volume Docker
├── docs/                         # raggruppata e indicizzata
│   ├── README.md (indice)
│   ├── API.md / DEPLOYMENT.md / USER_GUIDE.md / I18N_SETUP.md
│   ├── architecture/             # questo file + ROADMAP.md
│   ├── archive/                  # piani storici
│   ├── specs/                    # spec esterne (.docx)
│   └── superpowers/plans/        # piani TDD dettagliati
└── src/
    ├── backend/
    │   ├── main.py / config.py / database.py
    │   ├── api/{routers,middleware}/
    │   ├── models/{orm,api}/
    │   ├── services/
    │   ├── migrations/
    │   ├── templates/
    │   └── tests/
    └── frontend/
        └── flask_app/
            ├── app.py / config.py / compile_translations.py
            ├── blueprints/ (auth, maker, measure, statistics, admin)
            ├── services/ (api_client.py)
            ├── templates/ + static/ + translations/
            └── tests/

Smoke test status

Validazione end-to-end in locale (2026-04-26):

  • MySQL container Docker up, schema creato, alembic stamp head OK
  • uvicorn --reload su :8000, /api/health risponde
  • Seed /api/setup/seed con SETUP_PASSWORD=adriano77 → admin + 4 utenti demo + DEMO-001 + ST-DEFAULT con assegnazione automatica
  • Login admin/admin123 via web, sessione persistente
  • /admin/stations: tabella, modal create/edit, modal gestione assegnazioni a 2 colonne con search, eliminazione con cascade
  • /admin/users, /maker/recipes, /measure/select (filtrato per stazione), /statistics/dashboard
  • Workflow MeasurementTec end-to-end: select_recipe → task_list → task_execute → task_complete (riepilogo con misure)
  • Hot reload Flask + uvicorn --reload + Tailwind watch attivi durante lo sviluppo

Test status

| Backend (src/backend/tests/) | 127 | 3 | Fail pre-esistenti: test_recipes (2) + test_tasks (1). Nessuno introdotto dalla V2.0.0. | | Frontend (src/frontend/flask_app/tests/) | 46 | 1 | +2 test post-restructure (test_template_js_syntax.py). Fail pre-esistente: test_save_measurement_proxy. | | Totale | 173 | 4 | Tutti i fallimenti tracciati come tech debt da risolvere. |

Stack confermato

  • Backend: FastAPI + SQLAlchemy 2.0 async + MySQL 8 + Alembic + Pydantic v2 + WeasyPrint + Plotly/Kaleido.
  • Frontend: Flask + Jinja2 + Alpine.js + TailwindCSS + Fabric.js 5.3.1 + html5-qrcode + Plotly.js + Flask-Babel.
  • Deploy: Docker Compose. Dev = Nginx; Prod = Traefik + Let's Encrypt SSL.
  • Tooling: uv (package mgmt), pytest + pytest-asyncio + httpx + aiosqlite (test).

Decisioni architetturali rilevanti

Decisione Stato Note
Frontend Flask invece di React (deroga vs spec §8) Confermata Tablet UX server-side, USB calipers/barcode, Fabric.js editor, i18n Babel collaudato. Vedi conversazione 2026-04-25.
NATS messaging (spec §7) Skippato Monorepo single-host, no microservizi. Nessuno stub nats_client/ creato.
Envelope risposta {success,data,error} (spec §6) Rimandato Costo 4-5gg refactor + rotture client. Eventuale v2 API in M2.
Header X-API-Key vs spec X-Api-Key Mantenuto attuale Rinominare costa 50+ punti di codice + breaking per deploy. Rivedere in M2.
Variabili .env (DB_HOST, SERVER_PORT, ...) Mantenute attuali Rename a SERVICE_NAME/SERVICE_DOMAIN/API_KEY rinviato (impatta deploy esistenti).

Branch git

  • Default: V2.0.0 (lavoro corrente)
  • Mantenuti: V1.0.0V1.0.7 (release branches storiche)
  • Mergiato e chiuso: feature/rev04-phase1-stations (in V2.0.0 con commit ea8e468)