# Integrazione analisi `docs/nis2/` → NIS2 Agile

> Data: 2026-05-29 (CEST) · Versione: v1.7.0 · Stato: **✅ DEPLOYATO ED ESEGUITO IN PRODUZIONE (Hetzner)**

## ✅ Eseguito in produzione (2026-05-29 ~17:06 CEST)
- **Codice**: live su `/var/www/nis2-agile` (stesso filesystem del container dev via bind mount → nessuno scp necessario). 5 nuovi endpoint verificati live (HTTP 401 auth, routing OK).
- **Migrazioni DB 020/021/022**: applicate e verificate (colonne assets/incidents + tabella `incident_pir` create).
- **Ingest KB**: **287 chunk** normativi indicizzati in Qdrant `nis2_kb` scope SYSTEM (171 NIS2 + 77 CER + 25 Det.333017 + 9 Det.164179 + 5 Ambiti). Retrieval verificato (query "preallarme CSIRT" → Direttiva NIS2; "settori alta criticità" → Ambiti Allegati I/II).
- **Backup**: `/root/backup_pre_v170_20260529_165447.sql`.

### ⚠️ Azione consigliata residua (richiede conferma — recreate container)
**Qdrant IP drift**: il container `nis2-qdrant` non ha IP statico in `docker-compose.yml` ed è driftato da `172.21.0.5` → `172.21.0.3`. Fallback in `VectorService.php` aggiornato a `.3` (live). Per evitare ricorrenze: in `docker/docker-compose.yml` assegnare `ipv4_address` statico al servizio `qdrant` e allineare `QDRANT_URL`, poi `docker compose up -d --force-recreate qdrant app`. NB: nota anche che `kb_uploaded_documents` non esiste su questo DB (migrazioni KB 012-014 non applicate qui) → il tracking MySQL dei doc KB è saltato (best-effort), ma la ricerca RAG legge da Qdrant e funziona.

---

Integrazione del materiale di analisi (mockup HTML + testi normativi PDF) nel prodotto NIS2 Agile.
Tutto il codice è scritto e lint-clean (`php -l` / `node --check`). **Le migrazioni DB e l'ingest KB
NON sono ancora stati eseguiti** (questo container dev non raggiunge il DB/Qdrant di produzione).

---

## Cosa è stato implementato

### Fase 1 — Asset Relevance Scoring NIS2 (GV.OC-04)
Metodologia di scoring 0-100 su 6 criteri pesati, soglia rilevanza ≥40, classi critico/alto/medio/basso/trascurabile.
- `docs/sql/020_asset_relevance.sql` — colonne `relevance_score`, `relevance_criteria` (JSON), `relevance_class`, `is_nis2_relevant`, `relevance_assessed_at/by` + indice
- `application/services/AssetScoringService.php` — logica pura + griglia ufficiale in costante
- `application/controllers/AssetController.php` — `GET scoringGrid`, `POST {id}/score`, `GET relevantSystems`, filtro `nis2_relevant`
- `public/assets.html` — colonna "Rilevanza NIS2" + modale di valutazione a 6 criteri con anteprima punteggio
- `public/js/api.js` — `getScoringGrid`, `scoreAsset`, `listRelevantSystems`, `deleteAsset`
- Verifica: esempio ERP del mockup = **91/100 → critico** ✓

### Fase 2 — Tassonomia incidenti (Determina ACN 164179/2025)
- `docs/sql/021_incident_nis2_taxonomy.sql` — colonne `nis2_incident_type` ENUM(IS-1..IS-4), `entity_obligation` ENUM(essential/important)
- `application/controllers/IncidentController.php` — `create()` deriva il regime (Allegato 3 essenziali / Allegato 4 importanti) e blocca IS-4 per gli importanti
- `application/services/AIService.php` — `classifyIncident()` cita le fonti e restituisce `nis2_incident_type` + `notification_basis`

### Fase 3 — Post-Incident Review + metriche TTD/TTC/TTR
- `docs/sql/022_incident_metrics_pir.sql` — timestamp di fase (`triaged_at`, `contained_at`, `eradicated_at`, `recovered_at`) + tabella `incident_pir` (5-Whys, metriche, costo, lesson learned)
- `IncidentController.php` — `GET {id}/metrics`, `GET {id}/pir`, `POST {id}/pir`; `update()` timbra i timestamp di fase al cambio stato
- `public/js/api.js` — `getIncidentMetrics`, `getIncidentPir`, `saveIncidentPir`, `aiClassifyIncident`

### Fase 4 — Layer mapping NIST CSF 2.0 (reference, non invasivo)
- `application/controllers/AuditController.php` — `GET nistCsfMapping`: 43 controlli NIST CSF 2.0 → NIS2 Art.21/23 → modulo. **Nessuna migrazione**, nessuna modifica all'assessment esistente.

### Fonti normative certe (richiesta esplicita: AI + help citano fonti certe)
- `application/config/nis2_sources.php` — **registry canonico citabile** (Dir. 2022/2555, Dir. 2022/2557, D.Lgs. 138/2024, Determina ACN 164179/2025, Determina ACN 333017/2025, Ambiti NIS2)
- `application/services/AIService.php` — `authoritativeSourcesBlock()` iniettato nei system prompt (default, RAG, classifyIncident): impone di citare le fonti e vieta riferimenti inventati
- `public/js/help.js` — riferimenti normativi italiani aggiunti a incidenti e asset
- `scripts/ingest-nis2-sources.php` — indicizza i 5 PDF normativi nella KB (Qdrant `nis2_kb`, scope SYSTEM) per il grounding RAG

### Report
- `ReportService::generateRelevantSystemsRegister()` + `GET /api/audit/relevantSystemsRegister` — registro formale "Sistemi Rilevanti NIS2" (GV.OC-04) HTML stampabile con citazioni.

---

## Deploy su Hetzner (da eseguire, in ordine — CHIEDERE CONFERMA UTENTE)

```bash
# 0) Backup pre-migrazione
ssh -i docs/credentials/hetzner_key root@135.181.149.254
mysqldump nis2_agile_db assets incidents > /root/backup_pre_v170_$(date +%F).sql

# 1) Deploy codice (bind mount: PHP live; verificare path reale di produzione)
cd /var/www/nis2-agile && git pull origin main   # dopo push su Gitea

# 2) Migrazioni DB (additive, idempotenti). NB: usare host MySQL, non docker exec nis2-db
mysql -h localhost nis2_agile_db -e "source /var/www/nis2-agile/docs/sql/020_asset_relevance.sql"
mysql -h localhost nis2_agile_db -e "source /var/www/nis2-agile/docs/sql/021_incident_nis2_taxonomy.sql"
mysql -h localhost nis2_agile_db -e "source /var/www/nis2-agile/docs/sql/022_incident_metrics_pir.sql"

# 3) Ingest fonti normative nella KB (richiede Qdrant + Voyage attivi)
docker exec -i nis2-app php /var/www/nis2-agile/scripts/ingest-nis2-sources.php --dry-run  # verifica
docker exec -i nis2-app php /var/www/nis2-agile/scripts/ingest-nis2-sources.php           # esegui

# 4) Smoke test
curl -s https://nis2.agile.software/api/assets/scoringGrid -H "Authorization: Bearer <jwt>" | head
```

### Rollback
Ogni `.sql` contiene la sezione ROLLBACK in coda. Per la KB: cancellare i chunk scope=SYSTEM/source=normativa o ripristinare la collection.

---

## Note
- **Phase 4** è volutamente reference-only (nessuna tabella/migrazione) per non toccare l'assessment Art.21 consolidato.
- I PDF normativi restano in `docs/nis2/*.pdf` come libreria sorgente referenziata da `nis2_sources.php`.
- I file `*copy.html` e `incidente_r00/` dei mockup non sono stati usati (duplicati/superati).
