From 767bd7f9470849581bdf4088fd156c20603e021b Mon Sep 17 00:00:00 2001 From: Adriano Date: Wed, 25 Feb 2026 14:24:02 +0100 Subject: [PATCH] docs: fix middleware order and add missing details to CLAUDE.md Correct the middleware stack order (was documented backwards due to Starlette's add_middleware wrapping behavior), document fabric-debug.js local copy, and note full 50-900 shade palettes for Tailwind colors. Co-Authored-By: Claude Opus 4.6 --- CLAUDE.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 1e6f93c..65964f8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -84,7 +84,7 @@ Il client Flask è un frontend server-side che comunica col backend via REST API - **database.py**: SQLAlchemy 2.0 async engine con `AsyncSession`, pool 10+20 overflow, `pool_recycle=3600`, `expire_on_commit=False` - **routers/**: auth, users, recipes, tasks, measurements, files, settings, statistics, reports, setup. Il task router (`tasks.py`) usa URL pattern misti: `/api/recipes/{id}/tasks` (list/create), `/api/tasks/{id}` (get/update/delete), `/api/tasks/reorder`, `/api/tasks/{id}/subtasks`, `/api/subtasks/{id}` - **services/**: recipe_service (versioning copy-on-write), measurement_service (calcolo pass/fail), spc_service (Cp/Cpk/control chart, puro stdlib senza numpy), report_service (WeasyPrint PDF + Kaleido SVG), auth_service (bcrypt + API key) -- **middleware/**: Stack order (outermost→innermost): RateLimitMiddleware → SecurityHeadersMiddleware → CORSMiddleware → AccessLogMiddleware. api_key.py (auth dependency `get_current_user()`), rate_limit.py (sliding window 60s per-IP, in-memory dicts), security_headers.py (CSP con `unsafe-eval` per Plotly.js, HSTS solo con SSL), logging.py (audit trail async su DB, esclude /api/health, /docs, /openapi.json, /redoc) +- **middleware/**: Stack order (outermost→innermost): AccessLogMiddleware → CORSMiddleware → SecurityHeadersMiddleware → RateLimitMiddleware. Nota: `add_middleware()` in Starlette wrappa l'app, quindi l'ultimo aggiunto (AccessLog) è il più esterno. Il commento in `main.py` dice "outermost" per RateLimit ma è fuorviante. api_key.py (auth dependency `get_current_user()`), rate_limit.py (sliding window 60s per-IP, in-memory dicts), security_headers.py (CSP con `unsafe-eval` per Plotly.js, HSTS solo con SSL), logging.py (audit trail async su DB, esclude /api/health, /docs, /openapi.json, /redoc) - **models/**: User (include `email`, `language_pref`, `theme_pref`), Recipe (`image_path` per preview), RecipeVersion, RecipeTask, RecipeSubtask (`image_path` per immagine specifica), Measurement (`synced_to_csv`, `input_method`), AccessLog, SystemSetting, RecipeVersionAudit - **schemas/**: Pydantic v2 per validazione I/O API - **migrations/**: Alembic con `alembic.ini` e `env.py` nella directory `server/migrations/` @@ -95,7 +95,7 @@ Il client Flask è un frontend server-side che comunica col backend via REST API - **blueprints/**: auth (login/logout/session), maker (editor ricette con Fabric.js), measure (esecuzione misurazioni), statistics (dashboard SPC con Plotly.js), admin (gestione utenti CRUD, cambio password, toggle attivo — solo `is_admin`) - **services/api_client.py**: singleton `APIClient` — wrapper HTTP (get/post/put/delete) con gestione errori normalizzata, timeout 30s, header X-API-Key da session - **templates/**: Jinja2 con `{{ _('string') }}` per i18n. Context processor inietta `current_user`, `current_theme`, `current_language`, `company_logo`, `languages` in tutti i template. Filtro custom `tojson_attr` per JSON sicuro in attributi HTML (escapa `"` → `"`) -- **static/js/**: Alpine.js 3.x (CDN), Fabric.js 5.3.1 (CDN), locales JSON (it.json, en.json), alpine-init.js (theme store). Componenti specializzati: `numpad.js` (input numerico touch con rilevamento burst USB HID), `caliper.js` (monitor calibro USB passivo), `barcode.js` (scanner QR/barcode con camera via html5-qrcode), `csv-export.js` (export CSV con locale italiano: `;` separatore, `,` decimale), `spc-charts.js` (grafici SPC con Plotly.js), `annotation-editor.js` / `annotation-viewer.js` (editor/viewer annotazioni Fabric.js) +- **static/js/**: Alpine.js 3.x (CDN), Fabric.js 5.3.1 (CDN) + `fabric-debug.js` (copia locale 5.3.0 per debug), locales JSON (it.json, en.json), alpine-init.js (theme store). Componenti specializzati: `numpad.js` (input numerico touch con rilevamento burst USB HID), `caliper.js` (monitor calibro USB passivo), `barcode.js` (scanner QR/barcode con camera via html5-qrcode), `csv-export.js` (export CSV con locale italiano: `;` separatore, `,` decimale), `spc-charts.js` (grafici SPC con Plotly.js), `annotation-editor.js` / `annotation-viewer.js` (editor/viewer annotazioni Fabric.js) - **translations/**: Flask-Babel, cataloghi .po/.mo per IT/EN. Locale selector: `session["language"]` → Accept-Language → `"it"` - **config.py**: `PERMANENT_SESSION_LIFETIME=28800` (8h), cookie secure in produzione, `BABEL_DEFAULT_TIMEZONE="Europe/Rome"` @@ -238,8 +238,8 @@ Variabili d'ambiente in `.env` (copiare da `.env.example`): - SSL: `SSL_CERTFILE`, `SSL_KEYFILE` ## Brand & Tailwind Custom Colors -- Colore primario: #2563EB (blu industriale) → `primary` in tailwind.config.js -- Colore secondario: #64748B (grigio acciaio) → `steel` in tailwind.config.js +- Colore primario: #2563EB (blu industriale) → `primary` in tailwind.config.js (palette completa 50–900) +- Colore secondario: #64748B (grigio acciaio) → `steel` in tailwind.config.js (palette completa 50–900) - Colori misurazioni: `measure-pass` (#059669), `measure-warning` (#D97706), `measure-fail` (#DC2626) - Font UI: Inter - Font numeri: JetBrains Mono