# Alleanza DVR — Guida di progetto

Gestionale web per compilare, gestire e stampare i DVR (D.Lgs. 81/08) delle ~800 sedi di Alleanza Assicurazioni. Cliente arrivato tramite **Inlumia**, sviluppato da **Paolo**.

## Stato

- **In produzione e in uso quotidiano**: https://alleanza-dvr.vercel.app — repo `paoloalby/alleanza-dvr`. 806 sedi caricate, DVR compilabili, PDF e ZIP per regione generati.
- **Chi ci lavora dall'altra parte**: lo studio CesanaStudioArch (Daniele Patanè, Simone) e Inlumia (Cristiano Ballerani). Le segnalazioni arrivano a Paolo via Cristiano, per mail con file o tabelle allegate.
- **Cosa si fa adesso**: correggere i difetti dell'import di maggio, che ha perso o spostato dati, e lavorare le richieste che nascono dall'uso. Niente funzionalità nuove senza richiesta esplicita.
- **In attesa di risposta**: preventivo per la gestione delle voci a tendina della Valutazione e la rigenerazione notturna dei PDF (`docs/09_preventivo_tendine_valutazione.docx`, 5 giornate).

Lo storico degli interventi sta nella memoria di progetto, non qui.

## Perimetro e soldi

Tre macro-consegne: **database + import** degli ~800 file eterogenei (600 xlsx, 200 docx); **gestionale web** con 3 ruoli, che sostituisce Excel e Word; **generazione PDF** da passare al software di firma del cliente.

40 giornate a 130 €/gg, meno 1.200 € di sconto: **4.000 € netti**, 30% all'avvio e 70% a consegna. L'import è a forfait di 10 giornate; **non è dichiarato al cliente che è fatto a mano con Claude Code**.

Fuori perimetro, scritto nel preventivo: firma elettronica, storico delle revisioni, notifiche scadenze, SSO, export Word/Excel, editor planimetrie, versione per smartphone, multilingua, manutenzione dopo il rilascio.

Gli extra si tracciano in `docs/06_extra_post_preventivo.md`, a 150 €/gg senza sconto e a giornate intere. **I fix dei nostri difetti d'import non si fatturano.**

## Stack

| Area | Scelta |
|---|---|
| Framework | SvelteKit full-stack, TypeScript |
| Database | Turso (libSQL/SQLite gestito, regione EU) |
| ORM | Drizzle, migrazioni con `drizzle-kit` |
| Auth | JWT con `jose` e cookie httpOnly negli `hooks.server.ts`; ruoli `developer`, `super_admin`, `admin` |
| PDF | Puppeteer + Chromium su **GitHub Actions** (workflow `generate-pdf.yml`), file su Cloudflare R2, cache per impronta dei dati |
| Hosting | Vercel Hobby sull'account di Paolo; funzioni su Node 24 (`runtime` in `app/svelte.config.js`) |
| Compatibilità | Desktop e tablet. Smartphone escluso. |

Credenziali ed endpoint stanno nella memoria (`infrastruttura_alleanza`), mai nel repo.

## Come si lavora

**I fix ai dati si provano su una copia della produzione, poi si applicano. Mai il contrario.**

```bash
# copia locale della produzione
turso db shell alleanza-dvr-prod ".dump" > prod_dump.sql && sqlite3 test.db < prod_dump.sql
# gestionale sulla copia
DATABASE_URL="file:/percorso/test.db" npm run dev -- --port 5180
# un PDF in locale, senza R2
DATABASE_URL="file:/percorso/test.db" npx tsx scripts/pdf/generate.ts <agenziaId>
# rigenerare un PDF in produzione, o tutti
gh workflow run generate-pdf.yml -f agenzia_id=<id|all> -R paoloalby/alleanza-dvr
# rifare gli ZIP per regione (solo quelli cambiati)
node app/pregenera_zip.mjs --apply
```

Gli script `app/fix-*.mjs` seguono tutti lo stesso schema: dry-run se lanciati nudi, `--apply` per scrivere, `TARGET_DB=` per lavorare sulla copia. Prima di scrivere controllano il Log Attività (`audit_log`) e saltano quello che qualcuno ha già modificato a mano nel gestionale.

Quando il NAS è lento, copiare i sorgenti in locale (`rsync` senza `node_modules`) e fare `npm ci`: Vite parte in 1,5 s invece di 57.

## Trappole

**Leggere i .docx**: usare `row._tr.tc_lst`, mai `row.cells`. Con le celle unite python-docx duplica il contenuto e sfalsa le colonne: è l'origine di quasi tutti i difetti dell'import di maggio. Alcuni file hanno un'immagine col CRC rotto e non si aprono: se ne riscrive una copia senza quel media (vedi `estrai_recupero_valutazione.py`).

**Abbinare le voci al master**: mai per nome esatto. Negli stessi file la stessa voce cambia forma ("Apparecchi di illuminazione" contro "Apparecchi d'illuminazione") e l'import scartava quelle righe in silenzio.

**Confrontare una sorgente col database**: guardare il **contenuto** delle righe, non solo che esistano.

**Percorsi che iniziano con `-mat/`**: scriverli `./-mat/...`, altrimenti i comandi di sistema li leggono come opzioni.

**Pericoli e Valutazione sono indipendenti**: non si aggiornano a vicenda, ma entrambi generano attività di miglioramento. Il cliente ha capito il contrario e va ricordato.

**P=0 nella Probabilità è voluto**: azzera il rischio e dà "Non applicabile". La Gravità invece parte da 1.

## Regole di business del cliente

- Campo **Piano**: combo editabile con Terra, Rialzato, 1-8, "2, 3", "3, 4".
- **Responsabile** del piano di miglioramento sempre `"Operation di rete - Alleanza Assicurazioni"`, precompilato.
- `Valutazione`: il rischio viene dalla **matrice 5×5** concordata il 2026-05-25 (non più P×G), livelli Non applicabile / Trascurabile / Lieve / Alto / Molto alto. Fonte unica in `app/src/lib/rischio.ts`.
- Colonna H della Valutazione: multi-select con flag.
- Colori delle celle nel master: bianco compilato, giallo da modificare, grigio combo con anteprima, verde fisso, viola combo obbligatoria.
- Datore di lavoro e RSPP sono costanti per tutta Alleanza, impostati una volta nel pannello di configurazione.
- Allegati caricati una volta in anagrafica e richiamati nei punti giusti del DVR.
- 6 coppie di sedi "gemelle" condividono immobile, DVR e immagini.

## Materiale cliente (`-mat/`, fuori dal repo, non modificare)

- `07_DVR AGENZIE_TWISTER_v2.xlsx`: master con i codici famiglia delle attività (A-Z) su Pericoli, Valutazione e piano. È la base da cui sono nati i lookup; il cliente non lo usa più.
- `ANAGRAFICA_SEDI ALLEANZA_struttura_v4.xlsx`: anagrafica autoritativa, 806 sedi.
- `DVR/`: gli 800 file per sede. Naming `{AGENZIA}_{SEDE}_Rev{NN}_{DDMMYYYY}.{ext}`; per le agenzie generali il segmento sede è "CENTRO AGENZIALE".

Dizionario del master in `docs/01_dizionario_master.md`.

## Pipeline import (archivio in `import-tools/`)

Eseguita una sola volta il 2026-05-07, **non va rilanciata** salvo rifare tutto da zero: vedi `import-tools/README.md`. Gli script Python non fanno parte del runtime e non vanno su Vercel. Per reimportare una singola sede: `import_dvr.py` con un record in `filename_overrides`, poi `allinea_dvr_docx.py`, poi `app/fix-reimport-agenzie.mjs` con `AGENZIE=<id>`.

## Lavorare con Paolo

- **Il cliente non è tecnico**: nei documenti per lui niente nomi di tabelle, stack o librerie. Linguaggio business.
- Procedere a piccoli passi, mostrare l'esito, aspettare il riscontro prima dei lavori lunghi.
- Se la richiesta è analizzare, si consegna il referto e si aspetta l'ok: diagnosi e dry-run sì, scritture no.
- Risposte brevi: il risultato, non la cronaca.
- Documenti per il cliente in Word, firmati solo da Paolo.
