Commit Graph

7 Commits

Author SHA1 Message Date
Adriano 71da162e1f feat(vision): il worker che espone il runner, versione stampata al build
Container FastAPI separato (Dockerfile.vision, python:3.13-slim) che
espone run_graph/engine_version del Task 2 via POST /run e GET /health,
cosi' l'immagine del server principale non importa mai VisionSuite.

engine_version() ora legge VISION_ENGINE_VERSION se impostata, altrimenti
ricade su git rev-parse nel checkout di sviluppo, e non inventa mai un
valore: senza nessuna delle due solleva un errore esplicito. Nel container
il fallback a git non puo' funzionare (.git del submodule punta fuori dal
build context), quindi Dockerfile.vision prende il commit come build arg
e lo fissa in ambiente; i compose file lo passano da VISION_ENGINE_VERSION.

Nessuna porta pubblicata e nessuna label Traefik sul servizio vision: e'
raggiungibile solo dal server, su tmflow-net.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014BBnuACZSCJqXrMYC3LUMU
2026-08-16 18:12:04 +02:00
Adriano Dal Pastro a159eb2b8b feat(stations): ricette in lista, reset per riga e cambio stazione al volo
Punto 7 del documento modifiche del 28/07, terza richiesta di Menoncin.

GET /api/stations ora usa StationWithRecipesResponse, che era gia' definita nello
schema senza che nessun endpoint la usasse. Non costa query in piu':
Station.assignments e' gia' selectin-loaded. In lista compaiono le sole ricette
attive, coerente con cio' che l'operatore vede davvero a quella stazione.

DELETE /api/stations/{id}/recipes azzera le assegnazioni di una stazione senza
eliminarla, cosi' si riassegna da capo. E' idempotente: azzerare una stazione gia'
vuota risponde removed=0, non 404. In tabella e' un pulsante per riga, con
conferma perche' l'azione e' distruttiva.

Il cambio stazione al volo (?station=CODE, override in sessione) serve al
collaudo: senza, provare N stazioni richiede N PC. E' dietro il flag
STATION_SWITCH_ENABLED, default 0. Non e' legato al ruolo admin perche'
/measure/select richiede MeasurementTec, e gatearlo su is_admin avrebbe escluso
proprio chi fa il collaudo. In fabbrica l'identita' della stazione viene
dall'installazione locale, e misurare contro le ricette di un'altra stazione
romperebbe in silenzio la tracciabilita': per questo il codice richiesto e'
validato prima di essere memorizzato - un refuso lascia l'operatore sulla
stazione configurata con un messaggio, invece di incastrarlo su una stazione
inesistente - e quando l'override e' attivo la pagina lo dichiara, con il codice
configurato accanto e un link per ripristinare.

Le traduzioni: pybabel update aveva indovinato dieci voci da stringhe simili
marcandole fuzzy, in entrambi i cataloghi. "Azzera Stazione" era diventato "Crea
Stazione", l'opposto, su un dialogo distruttivo. Non si vedeva perche' la
compilazione salta le fuzzy e ricade sul sorgente italiano, ma sarebbe emerso al
primo build con --use-fuzzy. Tradotte per esteso le 17 stringhe nuove in IT ed EN
e tolti i flag.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 15:42:17 +00:00
Adriano Dal Pastro d2bf0b5828 feat(maker): AI parsing schede tecniche PDF via OpenRouter
- Nuovo servizio ai_service.py: estrae testo da PDF (pdfplumber) + analisi AI (OpenRouter)
- Endpoint POST /api/recipes/{id}/parse-technical-sheet con validazione file
- UI: bottone "Importa da PDF" nel task editor con modale upload + preview editabile
- Task suggeriti modificabili/rimovibili prima della creazione bulk
- Config: OPENROUTER_API_KEY e OPENROUTER_MODEL in .env
- Dipendenze: pdfplumber + httpx aggiunti a server deps

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 11:01:00 +00:00
Adriano 2a2d40bec9 fix(admin): two more apostrophe-in-translation regressions + UX rework
UX rework — recipe assignment modal on /admin/stations
- Replace the single "select recipe + Assegna" dropdown with a two-
  column layout: Ricette disponibili (left) and Assegnate alla
  stazione (right), each row with an inline action button. Top search
  filter narrows both columns at once. Empty states explain *why* the
  list is empty (no recipes in system, all already assigned, no match
  for the filter).
- Rationale: the old dropdown silently hid every option once a recipe
  was assigned, leaving the user unable to tell whether the system
  was broken or simply out of unassigned recipes.

Apostrophe regressions
- /admin/stations alert/errorMsg literals reworded with double-quoted
  outer JS strings ("Errore nella eliminazione" / "...assegnazione").
- /admin/users toggle confirm modal: x-text expression contained
  '{{ _('… l\'utente') }}'. Inside a Jinja-rendered HTML attribute,
  the apostrophe in "l'utente" closed the JS literal early, killing
  the binding. Fixed by using &quot; as the JS string delimiter so
  the inner apostrophe is harmless.

Alpine x-if templates can't host nested templates
- Replaced two nested-template empty-state blocks with x-text bound
  to computed getters (unassignedEmptyMessage,
  assignedEmptyMessage). Alpine errored with
  "Cannot set properties of null (setting '_x_dataStack')" when the
  outer template's child wasn't a single root element.

Test guard widened
- src/frontend/flask_app/tests/test_template_js_syntax.py now also
  parses every Alpine attribute (x-*, @*, :*) on the rendered HTML
  and runs `node --check` on each expression wrapped in `void (…)`.
  Previously it only inspected inline <script> bodies, which is why
  the x-text bug on /admin/users slipped through. Verified the
  extended test catches the original l'utente regression by reverting
  + running + restoring.

Layout regression — UPLOAD_DIR defaulted to server/uploads
- The previous .env.example shipped UPLOAD_DIR=server/uploads, which
  matched the V1.x layout but pointed outside the new project tree.
  Updated to UPLOAD_DIR=uploads so files land in the project-root
  uploads/ volume that src/backend/config.py.upload_path resolves.
- Added uploads/general/ to .gitignore (per-user uploads, not source).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 14:49:23 +02:00
Adriano 958f6ac0b0 feat(client): add STATION_CODE env var and config attribute
Reads STATION_CODE from the environment and exposes it as Config.STATION_CODE
(None when unset or empty). Adds the variable to .env.example with a
per-station deployment note, and covers both read and missing-key paths with
new pytest tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 23:18:24 +02:00
Adriano c9d9c0f9dd feat: V1.0.1 - Setup page, Docker, README
Add password-protected setup page (/api/setup) for DB initialization,
admin creation, and demo data seeding. Dockerize the full stack with
server, client, nginx reverse proxy, and MySQL services. Add project
README with architecture overview, quick start, and VPS deployment guide.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 18:00:29 +01:00
Adriano dbdbb77daf feat: FASE 0 - Setup progetto TieMeasureFlow
Struttura monorepo completa con server FastAPI e client Flask:
- Server: FastAPI + SQLAlchemy 2.0 async + Alembic migrations
- Client: Flask + blueprints (auth, measure, maker, statistics)
- Database: docker-compose MySQL 8.0 + Alembic async config
- Config: pydantic-settings, TailwindCSS, Flask-Babel i18n
- Piano implementazione completo (18 sezioni, 1600 righe)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 00:16:54 +01:00