Commit Graph

95 Commits

Author SHA1 Message Date
Adriano 17ea010f7e Test: quota NaN chiede il capoturno, migrazione 022 conserva le righe
Refs #125

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-28 22:07:18 +01:00
Adriano 2f0a5aaf1e Deviazione NaN nelle esportazioni CSV per le quote non misurate
Refs #124

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-28 22:06:43 +01:00
Adriano b01bba536a Test check: la quota non prodotta entra come NaN/fail
Refs #118

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-28 21:41:22 +01:00
Adriano 17344aae13 Monitor: quota con soli NaN resta in elenco con media null e fuori tolleranza
Refs #118

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-28 21:30:11 +01:00
Adriano 06f308be6f Visione: quota non prodotta salvata come NaN (value NULL, fail) invece del 422; migrazione 022
Refs #118

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-28 21:21:54 +01:00
Adriano 6080e6aebc vision: ricetta DXF riapribile, immagine salvata, rotte source e files, soglia segue la quota (Refs #105)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jbf7qKuxsnAVjxthRy7dnB
2026-10-25 16:25:37 +01:00
Adriano ebaafbe6e9 vision: anteprima DXF nel worker e nel backend (Refs #101)
Worker: POST /dxf/preview legge il DXF con read_xld_dxf (lo stesso lettore di
CompareDxf) e ritorna contorni in mm con y verso il basso, bbox, dimensioni,
entita e punti (tetto 20000, decimazione uniforme). Backend: POST
/api/vision/dxf-preview (Maker) che inoltra al worker; 422 inoltrato.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 15:55:43 +01:00
Adriano 444dc0a6d1 backend: immagini BMP ammesse nelle rotte visione (Refs #99)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 15:46:58 +01:00
Adriano 661b782bad backend: test camera e modo di analisi nel task, /vision/check (Refs #97)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 18:26:26 +02:00
Adriano 8ce7b489d6 Merge branch 'lavoro/daitarn-tmf-seedfiera' into lavoro/daitarn-tmf-dxfcal 2026-10-24 10:17:47 +02:00
Adriano bc90d327f1 seed fiera: password 123 per tutti, chiesta da Adriano (#85)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jbf7qKuxsnAVjxthRy7dnB
2026-10-24 10:17:45 +02:00
Adriano e46965cb51 Merge branch 'lavoro/daitarn-tmf-seedfiera' into lavoro/daitarn-tmf-dxfcal 2026-10-24 00:55:21 +02:00
Adriano 990b5d0db8 Seed fiera: utenti, stazione, ricette e storico misure (#85)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jbf7qKuxsnAVjxthRy7dnB
2026-10-23 23:51:00 +02:00
Adriano ad6ce5d11d Backend: ricetta DXF compare da camera e calibrazione letta dall'acquisitore (#83)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-23 22:44:15 +02:00
Adriano f8f5f248ff setup: init-db e reset-db stampano head in un thread (TieMeasureFlow#80)
_stamp_head esegue env.py di alembic, che fa asyncio.run() e dentro il loop
di FastAPI dava RuntimeError (500). Ora gira con asyncio.to_thread. Nuovo
test_setup_stamp.py senza monkeypatch di _stamp_head, su file SQLite.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-17 14:25:24 +02:00
Adriano f23e87e585 Merge piano B: report PDF su Windows offline (TieMeasureFlow#78) 2026-10-17 12:39:35 +02:00
Adriano 8431aa7095 Report PDF su Windows: MathJax locale per Kaleido (niente CDN offline) e test con WeasyPrint/Edge veri (TieMeasureFlow#78)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-17 09:16:29 +02:00
Adriano 242add047b Backend su file SQLite locale: DB_URL, PRAGMA FK/WAL, UPLOAD_DIR assoluto (TieMeasureFlow#77)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-17 09:07:45 +02:00
Adriano 1453b31cee by-code: auth da utente loggato qualunque, come /recipes (#72)
Lo chiama il proxy Flask con la chiave dell'operatore MeasurementTec, quindi
get_current_user al posto di require_admin_user. Test: MeasurementTec 200,
senza chiave 401.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 09:53:33 +02:00
Adriano b9f43a0ede Stazioni: camera_url e camera_source, GET /api/stations/by-code/{code} (#72)
Migrazione 020 con le due colonne su stations, campi in modello, schemi e
servizio (validatore http(s) come vision_worker_url), nuova route by-code
dichiarata prima di /{station_id}. Test di migrazione su e giu e di API.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 09:50:14 +02:00
Adriano 74fe5665b5 015_api_key_hash idempotente: DB da create_all e 015 a metà su MySQL (#71)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 09:25:07 +02:00
Adriano c911449b7c Statistica: endpoint esiti, note, campi e allegati dei task di una sessione (#58)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NABedeMX43pyXZbDNUgA5B
2026-10-11 18:07:06 +00:00
Adriano 275bbd1a5f Test worker di visione per stazione, API stazioni, migrazione 019 (#45)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NABedeMX43pyXZbDNUgA5B
2026-10-11 17:38:03 +00:00
Adriano b7cb061fee Suite: test PIN, cornice e worker PDF allineati all'integrazione (#65)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 13:46:27 +02:00
Adriano 2564498915 Test copy-on-write dei task: rilettura della collezione in sessione condivisa (#53)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 13:11:30 +02:00
Adriano 21f8bae5ac Task results: upload allegati per MeasurementTec, percorsi in task_results/, test e migrazione 018 (#55 #53 #54)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 12:50:42 +02:00
Adriano 743f246cbf Merge lavoro/daitarn-trafilo-pin 2026-10-07 12:38:56 +02:00
Adriano f7d6d008c7 Merge lavoro/daitarn-trafilo-duplica 2026-10-07 12:33:02 +02:00
Adriano 837f3d1069 Merge lavoro/daitarn-trafilo-statsessione 2026-10-07 12:33:02 +02:00
Adriano f5a2affa0f Merge lavoro/daitarn-trafilo-monitor 2026-10-07 12:33:02 +02:00
Adriano 3b3ecceb2a Merge lavoro/daitarn-trafilo-settings 2026-10-07 12:33:02 +02:00
Adriano 4e52095423 Statistiche per sessione di produzione: filtro production_run_id, elenco sessioni, select Sessione (#58)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 12:28:35 +02:00
Adriano 23bfc93f1c Impostazioni: durata loop, tolleranze, anagrafiche; tab Utenti con reset password (#47 #48 #49 #50 #51)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 12:28:31 +02:00
Adriano 07e23b957d PIN a 4 cifre: migrazione 017, login-pin, pin-users, PUT pin, capoturno via PIN (#59)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 12:27:31 +02:00
Adriano fc1902a1bb Ricetta: il digest della cartella copre anche i file di meta (#46)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 12:27:04 +02:00
Adriano 3c1d5f1323 Duplica ricetta: servizio, endpoint e test backend (#52)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 12:25:25 +02:00
Adriano db5d686938 Monitor stazioni: GET /api/production-runs/open (#57)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 12:25:16 +02:00
Adriano 86290274e5 Test ricetta v2, execute dxf_compare, migrazione 016 (#46)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 12:15:02 +02:00
Adriano ee0f65ed39 Endpoint ricetta VisionSuite v2, execute con overlay e immagine salvata (#46)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 12:12:50 +02:00
Adriano 7ac291b8ac Backend: date dei filtri dei report e utenti setup in ora italiana/UTC esplicito (#42)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 11:59:07 +02:00
Adriano 486e1288bf Backend: UTC nel DB, +00:00 nelle API, ora italiana solo in presentazione (#42)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 11:41:22 +02:00
Adriano 0d004c43ff Login: cancella le key scadute dell'utente (#41)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 11:34:30 +02:00
Adriano 35f46926a9 API key come hash SHA-256, una per sessione, TTL rinnovabile (#41)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 11:34:30 +02:00
Adriano 1d93eded27 Ripristino delle quote già misurate nel ciclo in corso dopo un reload (#40)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 11:31:57 +02:00
Adriano 70e2072b79 File di riferimento rimossi con il task, immagini animate rifiutate, filtro production_run_id (#43)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 11:27:23 +02:00
Adriano 96dd8d6ea3 fix(vision): reference image sopravvive al copy-on-write (#38.6)
_copy_tasks_to_version non copiava le righe VisionReferenceImage del
task sorgente: il task copiato perdeva le immagini di riferimento del
grafo di visione. Ora copia le righe sul task nuovo, stesso path e
stessi metadati (stesso file su disco, non duplicato).
Di conseguenza il file va cancellato solo se nessun'altra riga
VisionReferenceImage referenzia lo stesso path: nuova
vision_service.file_still_referenced(), usata dalla route DELETE
prima di remove_reference_file.
Test: copy-on-write elenca l'immagine sulla nuova versione; DELETE di
una delle due righe lascia il file; DELETE dell'ultima lo rimuove.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 23:27:29 +02:00
Adriano 2b00f83a2e test(tasks): copre recipe_id nel copy-on-write di create_task (#4)
Sospetto MissingGreenlet su TaskResponse.recipe_id (via RecipeTask.version)
quando create_task passa per il copy-on-write - il task appena creato non
ha .version precaricato. Test aggiunto: verde, non riproducibile. La
lazy load risolve via identity map (new_version è già nella sessione,
FK semplice → use_get), senza toccare il DB. Test tenuto come guardia
di regressione.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 23:25:17 +02:00
Adriano 2b59c3ec49 fix(recipe): measurement_interval_minutes e image_path si possono di nuovo azzerare (#37.3)
recipe_editor.html saveRecipe(): i due campi vengono sempre inviati nel
payload (valore o null esplicito), non più omessi quando svuotati.
recipe_service.py _header_fields(): per i due campi (unica eccezione
concordata al confine dei lotti, righe ~37-60) distingue "non inviato" da
"inviato null" con model_fields_set, invece di getattr(...) is not None —
altrimenti un null esplicito veniva scartato allo stesso modo di un campo
assente e il valore restava bloccato per sempre. Gli altri campi header
(name, description, requires_*, allow_manual_input) non toccati.
Test backend in test_recipes.py: TestUpdateRecipeClearNullableFields.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 23:05:51 +02:00
Adriano e20299548f fix(migrations): schema base 000 per DB vuoti, stamp head dopo create_all (#6)
upgrade head partiva dalla 001, che sa solo aggiungere colonne a tabelle
che assume gia' esistenti: su un DB davvero vuoto falliva subito. Nuova
000_base_schema.py (revision "000_base", down_revision None) crea lo
schema pre-001 esplicitamente (create_table, non Base.metadata.create_all,
che porterebbe gia' le colonne di 001-013 e farebbe fallire 001 su
"Duplicate column"). No-op se la tabella recipes esiste gia'
(sa.inspect(bind).has_table("recipes")). 001 ora ha down_revision =
"000_base".

setup.py: init-db e reset-db, dopo create_all/drop_all+create_all,
eseguono l'equivalente di "alembic stamp head" (nuovo _stamp_head(),
command.stamp con la config di src/backend/migrations/alembic.ini) cosi'
un DB nato da create_all non ritenta le migrazioni 001-013 al prossimo
deploy.

Test: catena upgrade head su SQLite vuoto, tabelle/colonne confrontate
con Base.metadata; DB con recipes gia' nello stato pre-001 -> upgrade
head non fallisce (000 no-op). _stamp_head si appoggia a
migrations/env.py, che costruisce una connessione propria da
settings.database_url (non modificabile dai test tramite l'engine
patchato di setup.py): nei test di setup.py e' quindi no-op via
monkeypatch, cosi' init-db/reset-db continuano a girare su SQLite senza
toccare un MySQL vero.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 22:49:38 +02:00
Adriano 805f41c757 fix(upload): tipo da magic bytes, non da Content-Type dichiarato (#36 punto 2)
Il Content-Type del client non era verificato: un file "x.html" dichiarato
image/png veniva salvato e poi servito per estensione come text/html,
eseguito dal browser. Nuova detect_file_type() (PNG/JPEG/GIF/WebP/PDF) in
files.py, usata anche dal logo in settings.py; l'estensione salvata segue
sempre il tipo rilevato, mai il nome file dichiarato dal client. Il logo
rifiuta SVG a prescindere (puo' portare script). Upload letti a blocchi da
1MB, interrotti appena superano il limite invece di bufferizzare tutto
prima di controllare la dimensione.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 22:48:52 +02:00