# 02 — Schema DB MySQL (bozza per preventivo)

**Nota**: questa è una bozza di schema pensata per supportare il preventivo, non per essere eseguita in produzione così com'è. Serve a dimostrare che abbiamo in mano la complessità del dominio e a dimensionare le ore di sviluppo. Il DDL completo è in `02_schema_db.sql`.

## Diagramma ER (testuale)

```
utenti (developer | super_admin | admin)

lookup_imprese_sopralluogo  ─┐
lookup_ispettorati_regionali ─┤
lookup_zone_sismiche         ─┤
lookup_gradi_rischio_idro    ─┤      ┌──> agenzie_rischi_ambientali <── lookup_rischi_ambientali
lookup_rischi_ambientali      │      │
lookup_gruppi_cat_protette   ─┤      ├──> agenzie_categorie_protette <── lookup_gruppi_cat_protette
                              ▼      │
                           agenzie ──┤
                              │      │
                              │      └──> dvr (1-1 con agenzie)
                              │              ├──> dvr_pericoli ─> lookup_requisiti_pericoli ─> lookup_combo_pericoli
                              │              ├──> dvr_valutazione ─> lookup_elementi_valutazione ─> lookup_combo_valutazione_h
                              │              ├──> dvr_incendio_doc ─> lookup_documenti_incendio
                              │              ├──> dvr_piano_miglioramento ─> lookup_azioni_piano_miglioramento
                              │              └──> dvr_allegati
```

## Tabelle (conta: 20)

### Utenti (1)
- `utenti` — email, hash password, ruolo (enum 3 valori), soft-delete.

### Lookup / seed (10)
Precaricati una volta sola, raramente aggiornati.
- `lookup_imprese_sopralluogo` (7 righe)
- `lookup_ispettorati_regionali` (~15-20 righe)
- `lookup_zone_sismiche` (13 righe)
- `lookup_gradi_rischio_idro` (~11 righe: frane+alluvioni)
- `lookup_rischi_ambientali` (~10 righe)
- `lookup_gruppi_categorie_protette` (~5 righe)
- `lookup_requisiti_pericoli` (~100 righe, ossatura foglio Pericoli)
- `lookup_combo_pericoli` (≈200-250 righe, tutte le opzioni combo)
- `lookup_elementi_valutazione` (~30 righe)
- `lookup_combo_valutazione_h` (≈80-120 righe)
- `lookup_documenti_incendio` (~18 righe)
- `lookup_azioni_piano_miglioramento` (~25 righe)

### Anagrafica (3)
- `agenzie` — core, con anagrafica + dati Sismica + rischi 1-a-1.
- `agenzie_rischi_ambientali` — M2M per multi-valore (un'agenzia può avere più rischi).
- `agenzie_categorie_protette` — dettaglio lavoratori.

### DVR compilato (6)
Una-a-una con `agenzie` (niente revisioning).
- `dvr` — master record con testi liberi di sezione Rischi e Incendio.
- `dvr_pericoli` — ~100 righe per sede (una per punto normativo).
- `dvr_valutazione` — ~30 righe per sede (una per elemento analisi).
- `dvr_incendio_doc` — ~18 righe per sede (una per documento obbligatorio).
- `dvr_piano_miglioramento` — 0-25 righe per sede (azioni).
- `dvr_allegati` — file upload (planimetria, luogo sicuro, foto, …).

**Totale righe DB a regime (800 sedi compilate)**:
- anagrafica: 800 agenzie + qualche migliaio di righe ponte
- DVR: 800 record master
- `dvr_pericoli`: ~80.000 righe
- `dvr_valutazione`: ~24.000 righe
- `dvr_incendio_doc`: ~14.000 righe
- Piano miglioramento: fino a 20.000 righe
- Allegati: qualche migliaio

MySQL 8 gestisce questi volumi senza problemi. Niente sharding, niente replica, niente warehousing — DB singolo su shared hosting basta.

## Scelte di design da giustificare

1. **Niente tabella revisioni, niente audit log.** Concordato fuori scope. Se in futuro serve revisioning: tabella `dvr` già separata da `agenzie`, basta aggiungere `rev_num` + unique (`agenzia_id`, `rev_num`).
2. **Valori combo salvati come testo, non FK.** Il record DVR resta stabile anche se la lookup viene aggiornata nel tempo. Le lookup servono solo a popolare le dropdown in UI e a dare coerenza ai nuovi DVR.
3. **H della Valutazione come JSON array di id.** Multi-select → JSON è più pragmatico di una tabella ponte per un attributo che non si interroga mai isolato.
4. **R = P × G calcolato e persisted.** Lo scriviamo a ogni update della riga valutazione così la dashboard KPI lo filtra senza calcolarlo al volo.
5. **Soft-delete solo su `agenzie` e `utenti`.** Le tabelle figlie del DVR cascadano. Obbligo conservazione dati: non buttiamo mai righe anagrafica.
6. **`codice_agenzia` come UNIQUE naturale.** Utile per import deterministici (posso rifare l'import senza duplicati).
7. **FK con ON DELETE CASCADE sulle figlie del DVR.** Semplifica la cancellazione logica (se mai servisse).

## Cosa aggiungere quando arriva l'anagrafica delle 800 sedi
Il cliente ci fornirà un file con i dati master. Probabilmente avrà campi in più rispetto al foglio Sismica (es. email referente sede, telefono, codice fiscale, partita IVA, data apertura, …). Lo schema è pensato per **estensibilità laterale**: basta aggiungere colonne a `agenzie` senza toccare il resto. Costo stimato: 1-2 ore di adattamento quando arriva.

## Ore stimate per implementare questo schema
Solo la parte DDL + seed + migration:
- scrittura DDL finale + migration system: 4h
- estrazione seed dai fogli del master → SQL: 8h
- script di setup (`php migrate.php`) + documentazione: 2h

**Totale schema DB**: ~14h (fa parte della macro-fase "impianto backend" del preventivo).
