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>
This commit is contained in:
@@ -57,10 +57,12 @@ Da: master plan §0 "Precondizioni e Decisioni Aperte". Da risolvere col cliente
|
|||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 3 test backend pre-esistenti rotti (`test_recipes`, `test_tasks`) | Media | Investigare prima di Fase 3 (toccano recipe + task router). |
|
| 3 test backend pre-esistenti rotti (`test_recipes`, `test_tasks`) | Media | Investigare prima di Fase 3 (toccano recipe + task router). |
|
||||||
| 1 test client pre-esistente rotto (`test_save_measurement_proxy`) | Bassa | Probabilmente CSRF/payload. Risolvere con Fase 4. |
|
| 1 test client pre-esistente rotto (`test_save_measurement_proxy`) | Bassa | Probabilmente CSRF/payload. Risolvere con Fase 4. |
|
||||||
|
| Pagina `task_complete` riepilogo: utente segnala riga vuota in alcuni scenari | Media | Da debuggare (rendering corretto via curl ma utente vede vuoto in browser, possibile interazione con sessione lot/serial). |
|
||||||
| `.env` rename a convenzione spec (SERVICE_NAME, SERVICE_DOMAIN, API_KEY) | Bassa | Rinviato (impatto deploy). |
|
| `.env` rename a convenzione spec (SERVICE_NAME, SERVICE_DOMAIN, API_KEY) | Bassa | Rinviato (impatto deploy). |
|
||||||
| Header `X-API-Key` rename a `X-Api-Key` | Bassa | Vedere se M2 lo richiede. |
|
| Header `X-API-Key` rename a `X-Api-Key` | Bassa | Vedere se M2 lo richiede. |
|
||||||
| Envelope risposta `{success,data,error}` | Bassa | Eventuale API v2 in M2. |
|
| Envelope risposta `{success,data,error}` | Bassa | Eventuale API v2 in M2. |
|
||||||
| `Dockerfile.frontend`: `pybabel compile` via `uv run` non testato in build reale | Alta | Verificare al primo `docker compose build`. |
|
| `Dockerfile.frontend`: `pybabel compile` via `uv run` non testato in build reale | Alta | Verificare al primo `docker compose build`. |
|
||||||
|
| Smoke test in container Docker (non solo locale uvicorn+gunicorn) | Alta | Validare che i Dockerfile riscritti con `uv` buildino e girino correttamente prima di chiudere V2.0.0. |
|
||||||
|
|
||||||
## Open per scelta utente prima della prossima sessione
|
## Open per scelta utente prima della prossima sessione
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Stato Progetto TieMeasureFlow — V2.0.0
|
# Stato Progetto TieMeasureFlow — V2.0.0
|
||||||
|
|
||||||
> Snapshot al 2026-04-25. Aggiornare ad ogni milestone.
|
> Snapshot al 2026-04-27. Aggiornare ad ogni milestone.
|
||||||
|
|
||||||
## Versione corrente
|
## Versione corrente
|
||||||
|
|
||||||
@@ -56,6 +56,19 @@ Il sistema base (V1.0.7) è completo e collaudato: ricette, task, misurazioni, S
|
|||||||
- Alembic env.py aggiunge project root a `sys.path`; `script_location = %(here)s` resta valido.
|
- Alembic env.py aggiunge project root a `sys.path`; `script_location = %(here)s` resta valido.
|
||||||
- `.dockerignore` aggiornato.
|
- `.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 `"..."` 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)
|
## Layout repository (V2.0.0)
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -90,13 +103,23 @@ TieMeasureFlow/
|
|||||||
└── tests/
|
└── tests/
|
||||||
```
|
```
|
||||||
|
|
||||||
## Test status
|
## Smoke test status
|
||||||
|
|
||||||
| Suite | Pass | Fail | Note |
|
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. |
|
| 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/`) | 44 | 1 | Fail pre-esistente: `test_save_measurement_proxy`. |
|
| 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** | **171** | **4** | Tutti i fallimenti tracciati come tech debt da risolvere. |
|
| **Totale** | **173** | **4** | Tutti i fallimenti tracciati come tech debt da risolvere. |
|
||||||
|
|
||||||
## Stack confermato
|
## Stack confermato
|
||||||
|
|
||||||
|
|||||||
@@ -175,7 +175,9 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for m in measurements|sort(attribute='task_info.order_index,subtask.marker_number') %}
|
{# Jinja's sort takes a single attribute. Chain stable sorts
|
||||||
|
to get task.order_index → subtask.marker_number ordering. #}
|
||||||
|
{% for m in measurements|sort(attribute='subtask.marker_number')|sort(attribute='task_info.order_index') %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center font-mono text-xs" style="color: var(--text-secondary);">
|
<td class="text-center font-mono text-xs" style="color: var(--text-secondary);">
|
||||||
{{ m.measured_at[:16]|replace('T', ' ') if m.measured_at else '-' }}
|
{{ m.measured_at[:16]|replace('T', ' ') if m.measured_at else '-' }}
|
||||||
|
|||||||
Reference in New Issue
Block a user