chore(docs): consolidate documentation, drop dead files

Cleanup
- Remove src/backend/Dockerfile.legacy and
  src/frontend/flask_app/Dockerfile.legacy (history is in git, build
  uses the new uv-based root Dockerfile / Dockerfile.frontend).
- Remove src/frontend/flask_app/verify_i18n.py (had hardcoded paths
  pointing at the old client/ tree).

Group docs/
- New docs/README.md indexes everything in one place.
- New docs/architecture/STATO_PROGETTO.md: snapshot of what works in
  V2.0.0 (inherited V1.0.7 features, rev04 Phase 1 stations,
  worker scaling, src/ restructure, test status, stack, decisions).
- New docs/architecture/ROADMAP.md: what's next — Phases 2-7 of the
  rev04 migration with status, open client decisions (D-0.1 through
  D-0.10), tech debt and time estimates for M1 / M2.
- Move PIANO_IMPLEMENTAZIONE.md (90KB V1.0.0 plan) to
  docs/archive/2026-02-06-piano-implementazione-v1.md (historical).
- Move Schema sviluppo SW TieFlow_rev04-2026.docx to docs/specs/
  with ISO date filename so the customer spec is now tracked.
- Move src/frontend/flask_app/I18N_SETUP.md to docs/I18N_SETUP.md
  and rewrite paths to the new src/frontend/flask_app/ tree.

.dockerignore: simplified now that legacy Dockerfiles are gone;
docs/ stays excluded from the build context.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-25 12:43:57 +02:00
parent 1a0431366f
commit e4b29c0b2d
10 changed files with 262 additions and 185 deletions
+240
View File
@@ -0,0 +1,240 @@
# TieMeasureFlow i18n Setup Guide
## Overview
TieMeasureFlow supports complete internationalization (i18n) with:
- **Server-side**: Flask-Babel for Python/Jinja2 templates
- **Client-side**: alpinejs-i18n for JavaScript/Alpine.js
- **Supported languages**: Italian (IT - default) and English (EN)
## Directory Structure
```
src/frontend/flask_app/
├── translations/ # Flask-Babel translations
│ ├── babel.cfg # Extraction config
│ ├── it/LC_MESSAGES/
│ │ ├── messages.po # Italian strings
│ │ └── messages.mo # Compiled binary (generated)
│ └── en/LC_MESSAGES/
│ ├── messages.po # English translations
│ └── messages.mo # Compiled binary (generated)
├── static/js/locales/ # Alpine.js i18n
│ ├── it.json # Italian client-side strings
│ └── en.json # English client-side strings
└── compile_translations.py # Utility to compile .po → .mo
```
## How It Works
### Language Selection
1. **User session**: Language stored in `session["language"]` (persistent)
2. **Browser fallback**: Uses `Accept-Language` header if no session
3. **Default**: Italian (IT)
### Server-Side (Flask-Babel)
**In Python code:**
```python
from flask_babel import gettext as _
flash(_("Profilo aggiornato con successo"))
```
**In Jinja2 templates:**
```jinja2
<h1>{{ _('Accedi al sistema') }}</h1>
{# With variables #}
<p>{{ _('Benvenuto, %(name)s!', name=user.display_name) }}</p>
```
### Client-Side (Alpine.js i18n)
**Load i18n in base template:**
```html
<script src="/static/js/lib/alpinejs-i18n.min.js"></script>
<script>
// Initialize i18n with current language
Alpine.plugin(AlpineI18n);
Alpine.store('i18n', {
locale: '{{ current_language }}',
fallbackLocale: 'it',
messages: {}
});
// Load locale files
fetch('/static/js/locales/{{ current_language }}.json')
.then(r => r.json())
.then(data => Alpine.store('i18n').messages['{{ current_language }}'] = data);
</script>
```
**Use in templates:**
```html
<button @click="submit" x-text="$t('numpad.submit')"></button>
<p x-text="$t('auth.welcome', {name: userName})"></p>
```
## Workflow
### 1. Add New Strings
**Python/Templates:**
1. Wrap strings with `_()` or `{{ _() }}`
2. Extract strings: `pybabel extract -F translations/babel.cfg -o translations/messages.pot .`
3. Update catalogs: `pybabel update -i translations/messages.pot -d translations`
4. Edit `translations/*/LC_MESSAGES/messages.po` files
5. Compile: `python compile_translations.py`
**JavaScript/Alpine:**
1. Add keys to `static/js/locales/it.json` (Italian strings)
2. Add translations to `static/js/locales/en.json`
3. No compilation needed (loaded at runtime)
### 2. Compile Translations
After editing .po files:
```bash
cd src/frontend/flask_app
python compile_translations.py
```
This generates `.mo` binary files that Flask-Babel uses at runtime.
### 3. Language Switching
**Endpoint**: `GET /set-language/<lang>`
**Example**:
```html
<a href="{{ url_for('set_language', lang='en') }}">English</a>
<a href="{{ url_for('set_language', lang='it') }}">Italiano</a>
```
**With Alpine.js**:
```html
<button @click="$store.i18n.locale = 'en'; window.location.href='/set-language/en'">
English
</button>
```
## Translation Keys
### Server-Side (messages.po)
56 strings covering:
- **Login**: "Accedi al sistema", "Credenziali non valide", etc.
- **Navbar**: "Misure", "Ricette", "Statistiche", etc.
- **Profile**: "Profilo Utente", "Salva Modifiche", etc.
- **Flash messages**: "Benvenuto, %(name)s!", "Logout effettuato", etc.
- **Common UI**: "Caricamento...", "Salva", "Annulla", "Conferma", etc.
- **Measurements**: "Conforme", "Non Conforme", etc.
### Client-Side (locales/*.json)
Structured keys:
```json
{
"numpad": { "title", "clear", "submit", "decimal", "close" },
"measurement": { "pass", "warning", "fail", "value", "next" },
"common": { "loading", "save", "cancel", "confirm", "delete", "edit", ... },
"theme": { "light", "dark", "toggle" },
"language": { "switch", "it", "en" },
"auth": { "login", "username", "password", "signIn", ... },
"nav": { "measurements", "recipes", "statistics", ... },
"profile": { "title", "displayName", "language", "theme", ... }
}
```
## Configuration
**config.py** must define:
```python
BABEL_DEFAULT_LOCALE = 'it'
BABEL_TRANSLATION_DIRECTORIES = 'translations'
LANGUAGES = {
'it': 'Italiano',
'en': 'English'
}
```
**app.py** provides:
- `get_locale()`: Language selector function
- `/set-language/<lang>`: Language switch endpoint
- `inject_globals()`: Exposes `current_language` and `languages` to templates
## Best Practices
1. **Always use Italian as msgid**: Italian strings are the canonical keys
2. **Keep client/server keys synced**: Use similar naming across .po and .json
3. **Test both languages**: Switch languages and verify all pages
4. **Recompile after editing**: Run `compile_translations.py` after changing .po files
5. **Use variables for dynamic content**: `_('Welcome, %(name)s!', name=user)` or `$t('auth.welcome', {name})`
6. **Avoid hardcoded strings**: Always use translation functions
## Troubleshooting
**Translations not appearing:**
- Verify `.mo` files exist: `find translations -name "*.mo"`
- Check session language: `session["language"]` or browser console
- Recompile: `python compile_translations.py`
- Restart Flask server
**Client-side i18n not working:**
- Check browser console for fetch errors
- Verify JSON files exist: `static/js/locales/{it,en}.json`
- Check Alpine.js i18n plugin is loaded
- Verify `Alpine.store('i18n')` is initialized
**Missing translations show as keys:**
- Add missing keys to .po or .json files
- Recompile .po files if server-side
- Reload page if client-side
## Commands Reference
```bash
# Extract translatable strings from code
pybabel extract -F translations/babel.cfg -o translations/messages.pot .
# Initialize new language (first time)
pybabel init -i translations/messages.pot -d translations -l en
# Update existing catalogs with new strings
pybabel update -i translations/messages.pot -d translations
# Compile .po to .mo (required after editing)
python compile_translations.py
# Check translation statistics
msgfmt --statistics translations/it/LC_MESSAGES/messages.po
msgfmt --statistics translations/en/LC_MESSAGES/messages.po
```
## Future Expansion
To add a new language (e.g., German):
1. **Server-side**:
```bash
pybabel init -i translations/messages.pot -d translations -l de
# Edit translations/de/LC_MESSAGES/messages.po
python compile_translations.py
```
2. **Client-side**:
- Create `static/js/locales/de.json`
- Add to config: `LANGUAGES = {..., 'de': 'Deutsch'}`
3. **Update loader**: Modify base template to support new locale
## Resources
- Flask-Babel: https://python-babel.github.io/flask-babel/
- Babel: http://babel.pocoo.org/
- Alpine.js i18n: https://github.com/alpine-collective/alpine-i18n
- PO file format: https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html
+43
View File
@@ -0,0 +1,43 @@
# Documentazione TieMeasureFlow
Indice della documentazione del progetto.
## Stato e direzione
| Documento | Scopo |
|---|---|
| [`architecture/STATO_PROGETTO.md`](architecture/STATO_PROGETTO.md) | Cosa è fatto oggi (V2.0.0). Snapshot del sistema, componenti e capacità. |
| [`architecture/ROADMAP.md`](architecture/ROADMAP.md) | Cosa resta da fare. Fasi 2-7 della migrazione rev04 verso V1.1.0/M1 demo cliente. |
## Riferimenti operativi
| Documento | Scopo |
|---|---|
| [`API.md`](API.md) | Riferimento endpoint REST esposti dal backend FastAPI. |
| [`DEPLOYMENT.md`](DEPLOYMENT.md) | Guida deploy su VPS (Hostinger/Tielogic con Traefik + Let's Encrypt). |
| [`USER_GUIDE.md`](USER_GUIDE.md) | Manuale utente (operatore, maker, metrologist, admin). |
| [`I18N_SETUP.md`](I18N_SETUP.md) | Setup e workflow traduzioni (Flask-Babel + Alpine.js). |
## Piani dettagliati TDD (rev04)
| Documento | Scopo |
|---|---|
| [`superpowers/plans/2026-04-17-rev04-master-roadmap.md`](superpowers/plans/2026-04-17-rev04-master-roadmap.md) | Master plan rev04 V1.0.7 → V1.1.0, le 7 fasi e le decisioni aperte. |
| [`superpowers/plans/2026-04-17-rev04-phase1-stations.md`](superpowers/plans/2026-04-17-rev04-phase1-stations.md) | Piano TDD dettagliato Fase 1 (stazioni e identità per-tablet). **COMPLETATO.** |
## Specifiche esterne (binari)
| Documento | Scopo |
|---|---|
| [`specs/2026-04-16-schema-sviluppo-rev04.docx`](specs/2026-04-16-schema-sviluppo-rev04.docx) | Schema sviluppo SW TieFlow rev04-2026 fornito dal committente. |
## Storico
| Documento | Scopo |
|---|---|
| [`archive/2026-02-06-piano-implementazione-v1.md`](archive/2026-02-06-piano-implementazione-v1.md) | Piano implementazione V1.0.0 originale (riferimento storico). |
## Ulteriori riferimenti nel repo
- [`/CLAUDE.md`](../CLAUDE.md) — guidance per Claude Code (architettura, comandi, pattern critici).
- [`/README.md`](../README.md) — entry point del progetto.
+93
View File
@@ -0,0 +1,93 @@
# Roadmap TieMeasureFlow — V2.0.0 → V1.1.0 (rev04 / M1 demo cliente)
> Aggiornare ad ogni Fase chiusa.
## Riferimenti
- Master plan dettagliato: [`../superpowers/plans/2026-04-17-rev04-master-roadmap.md`](../superpowers/plans/2026-04-17-rev04-master-roadmap.md)
- Spec sorgente: [`../specs/2026-04-16-schema-sviluppo-rev04.docx`](../specs/2026-04-16-schema-sviluppo-rev04.docx)
- Stato corrente: [`STATO_PROGETTO.md`](STATO_PROGETTO.md)
## Strategia: due milestone
| Milestone | Scope | Obiettivo |
|---|---|---|
| **M1 — Demo cliente** | Fasi 1-5 + deploy "demo" | Sistema testabile end-to-end col cliente per raccogliere feedback |
| **M2 — Produzione** | Fasi 6-7 + correzioni post-feedback + GAIA live | Rollout su tablet/PC reali |
## Stato Fasi (M1)
| Fase | Scope | Stato | Branch / Commit |
|---|---|---|---|
| **1** | Stazioni + identità per-tablet | ✅ **COMPLETATA** | `V2.0.0` (merge `ea8e468` da `feature/rev04-phase1-stations`) |
| 2 | Ruolo Capoturno (Supervisor) + override token breve | ⏳ Da iniziare | — |
| 3 | Editor ricetta a blocchi (preparation + measurement) | ⏳ Da iniziare | — |
| 4 | Workflow operatore (retry/timer/autologout/avvio produzione) | ⏳ Da iniziare | — |
| 5 (M1) | `ImportOnlyGaiaClient` + UI import dati cliente reali | ⏳ Da iniziare | — |
| Deploy M1 | VPS demo (compose + Traefik + LE, no registry) | ⏳ Da iniziare | — |
## Stato Fasi (M2)
| Fase | Scope | Stato |
|---|---|---|
| 5 (M2) | GAIA reale (protocollo TBD, polling, comandi produzione) | ⏳ Bloccata da decisioni cliente (D-0.1, D-0.2) |
| 6 | Deploy B industriale (registry privato + Watchtower + STATION_ID per-tablet + CI release) | ⏳ Pianificata |
| 7 | Hardening, security review, E2E sito pilota, docs aggiornati, i18n delta | ⏳ Pianificata |
## Decisioni aperte (bloccanti per M2 / future fasi)
Da: master plan §0 "Precondizioni e Decisioni Aperte". Da risolvere col cliente prima della Fase 5/6.
| ID | Decisione | Stato | Bloccante per |
|---|---|---|---|
| D-0.1 | Protocollo integrazione GAIA (REST / DB shared / OPC-UA / file) | **Aperta** | Fase 5 reale (M2) |
| D-0.2 | Credenziali e rete GAIA (VPN / firewall / whitelist IP) | **Aperta** | Fase 5 reale (M2) |
| D-0.3 | Target hardware "tablet" (Windows / Linux industriale / Android) | **Aperta** | Fase 6 (deploy B) |
| D-0.4 | Cicalino/luce avviso (audio HTML5 / hardware USB / entrambi) | **Rimandata a M2** | Fase 4 finale |
| D-0.5 | Parametri runtime modificabili vs versione immutabile | **Aperta** (raccomandato B: separare volatili) | Fase 3 |
| D-0.6 | Auth capoturno durante override (modale / PIN / RFID) | **Aperta** | Fase 2 |
| D-0.7 | Timeout auto-logout | **Risolta** | — |
| D-0.8 | Naming ruolo capoturno | **Proposta:** `Supervisor` | Fase 2 |
| D-0.9 | Tag versione immagine docker | **Proposta:** SemVer + `latest` | Fase 6 |
| D-0.10 | Registry esposto su Internet o solo VPN | **Proposta:** solo VPN cliente | Fase 6 |
## Tech debt da chiudere
| Item | Priorità | Note |
|---|---|---|
| 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. |
| `.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. |
| 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`. |
## Open per scelta utente prima della prossima sessione
1. **Quale fase iniziare adesso?** Opzioni: Fase 2 (Supervisor — sblocca workflow), Fase 3 (block editor — independente), Fase 5 (import GAIA dati reali — sblocca demo).
2. **Revisione decisioni aperte col cliente** — D-0.1 / D-0.2 / D-0.3 / D-0.6 prima di pianificare Fase 5 e 6.
3. **Smoke test Docker** della nuova struttura V2.0.0 (`docker compose -f docker-compose.dev.yml up --build`) per validare i Dockerfile riscritti.
4. **Test di carico** (k6/locust) a 20 VU su `/measure/save-measurement` per validare la scalatura worker (capacità annunciata: 20-30 tablet contemporanei).
## Stima tempi residui M1 (post-Fase 1)
| Task | Stima full-time |
|---|---|
| Fase 2 — Supervisor + override | 1 settimana |
| Fase 3 — Block editor | 1.5 settimane |
| Fase 4 — Workflow operatore | 2 settimane |
| Fase 5 (M1) — Import-only GAIA | 1 settimana |
| Deploy M1 demo | 0.5 settimane |
| **Totale M1 residuo** | **~6 settimane** |
## Stima tempi M2 (dopo feedback)
| Task | Stima |
|---|---|
| Aggiustamenti post-feedback | variabile (1-2 sett.) |
| Fase 5 reale GAIA | 1-2 settimane |
| Fase 6 deploy B | 1 settimana |
| Fase 7 hardening | 1-2 settimane |
| **Totale M2** | **~4-7 settimane** |
**Totale fino a produzione:** ~10-13 settimane full-time da oggi (2026-04-25), assumendo decisioni aperte risolte in tempo utile.
+122
View File
@@ -0,0 +1,122 @@
# Stato Progetto TieMeasureFlow — V2.0.0
> Snapshot al 2026-04-25. 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-For``X-Real-IP``request.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.
## 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/
```
## Test status
| Suite | Pass | Fail | Note |
|---|---|---|---|
| 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`. |
| **Totale** | **171** | **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.0``V1.0.7` (release branches storiche)
- **Mergiato e chiuso:** `feature/rev04-phase1-stations` (in `V2.0.0` con commit `ea8e468`)
File diff suppressed because it is too large Load Diff
Binary file not shown.