Files
nis2-agile/docs/DESIGN_A4_RELATIONAL.md
T
DevEnv nis2-agileandClaude Opus 4.8 5368b0a61c [FEAT] A4 Fase 4.2 — Competenze (skill/requisiti ruolo/gap) + alert→azione NCR+CAPA
Secondo modulo del modello relazionale A4 (docs/DESIGN_A4_RELATIONAL.md).

Backend:
- Migration 042 (docs/sql/042_competences.sql) + runner aggiornato (scripts/migrate-a4.php).
  4 tabelle additive/idempotenti: skills (org-owned o globali), role_skills
  (competenze richieste dal ruolo, UNIQUE role+skill), user_skills (possedute,
  UNIQUE org+user+skill), skill_course_map. APPLICATA su prod (nis2-db v8.0.45,
  TLSv1.3).
- CompetenceController (route 'competences'): catalog, skills CRUD, roleSkills,
  userSkills, skillCourses (map/unmap), gapGrid (richiesto−posseduto per ruolo
  con titolare), openAction. Multi-tenancy + anti-IDOR + livelli 1-5; competenze
  globali in sola lettura per gli utenti org.
- alert→azione: openAction RIUSA il workflow NCR/CAPA reale (la tabella azioni è
  capa_actions figlia di non_conformities, NON 'corrective_actions' che non
  esiste): crea NCR (source='management_review', source_entity_type='competence_gap',
  source_entity_id=role_skills.id) + capa_actions figlia. Anti-duplicato sul gap.
  Zero ALTER alle tabelle esistenti. Ancoraggio PR.AT-01/02, GV.RR-04, art.24 D.Lgs.

Frontend:
- competenze.html (4 schede: Catalogo, Requisiti per ruolo, Competenze persone,
  Gap & azioni) + js/competenze.js. Bootstrap Italia V2. CTA "Assegna corso"
  (riuso /training/assign) e "Apri non conformità".
- Voce sidebar "Competenze" (common.js + common-bi.js + BI_PAGES) + nav.competences
  i18n IT/EN. api.js: metodi comp* + assignTraining.

Help/KB/PWA:
- help.js: guida contestuale 'competences' (schede, calcolo gap, PR.AT-01/02,
  GV.RR-04, art.24 D.Lgs., disclaimer no-parere-legale) + mappa pagina.
- sw.js: nome cache nis2-shell-v1.17.0 (allineamento PWA).
- Design doc corretto (rettifica capa_actions vs corrective_actions) + avanzamento 4.1/4.2.

Cache-buster: ?v=20260618 dei 5 JS condivisi su 32 HTML. version.json 1.16.0 -> 1.17.0.
Smoke E2E su prod (fpm reale): catalogo, requisito, competenza, gap=2, openAction
(NCR+CAPA), anti-dup 409, mappatura corso — tutti verdi; dati di test ripuliti.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 19:01:32 +02:00

82 lines
9.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DESIGN — A4: Modello relazionale (organigramma RACI ↔ skill / formazione / inventario / procedure / rischi + scadenziario)
> Stato: **IN CORSO**. Contesto: segnalazioni Simon Fattori, punti **2, 3, 4, 5, 6, 7** (accolti in A4). Data: 2026-06-15.
> È l'epic più grande → da realizzare a **FASI**. Ancoraggio normativo verificato (Det. ACN 164179/2025 + D.Lgs. 138/2024). Vedi `reference-dlgs-articles`, `DESIGN_A2_ONBOARDING.md`.
>
> **AVANZAMENTO**: ✅ **4.1 Organigramma** (migration `041_org_roles.sql`, `OrgRoleController`, `organigramma.html`) — LIVE. ✅ **4.2 Competenze** (migration `042_competences.sql`: `skills`/`role_skills`/`user_skills`/`skill_course_map`; `CompetenceController`; `competenze.html`) — LIVE. ⏳ 4.3 RACI · 4.4 scadenziario · 4.5 stakeholder.
>
> 🔴 **RETTIFICA NOMI REALI (verificata sul codice)**: questo design parlava di una tabella **`corrective_actions`** che **NON ESISTE**. La tabella delle azioni reale è **`capa_actions`** (mig.004), **figlia obbligatoria** di **`non_conformities`** (NCR) via `ncr_id NOT NULL`, e **non ha** una colonna `source_type`. L'alert "gap → azione" (impl. in 4.2) quindi **NON** crea `corrective_actions`/`source_type`: crea una **`non_conformities`** ancorata al gap (`source='management_review'`, `source_entity_type='competence_gap'`, `source_entity_id=role_skills.id`) + una **`capa_actions`** figlia. Le menzioni di `corrective_actions`/`source_type` qui sotto vanno lette in questo senso.
## 0. Principio
A4 trasforma i moduli oggi "a silos" in un **grafo relazionale** con al centro l'**organigramma** (ruoli/responsabilità) e la **matrice RACI** come hub che lega i ruoli agli oggetti (inventario, procedure, rischi). Obiettivo: compliance *vissuta e dimostrabile in audit* (chi è responsabile di cosa, con quali competenze, con quali scadenze).
## 1. Stato attuale (da ESTENDERE)
| Ambito | Esiste? | Note |
|---|---|---|
| RACI ruoli | Parziale | `isms_roles` (mig.037): `role_name`, `user_id`, `responsibility`, `raci ENUM(R,A,C,I)` — ma **legato a un `isms_model`** (SGSI clausola 5.3), 1 valore RACI per ruolo, **non** matrice ruolo×oggetto |
| Organigramma org-wide | NO | nessuna gerarchia ruoli, nessun "nodo organo di gestione/board" |
| Skill / mansioni / competenze | NO | — |
| Gap competenze | NO | — |
| Formazione | SÌ | `training_courses` / `training_assignments` (`target_role` solo ENUM, non FK a ruolo) |
| Procedure | SÌ | `policies` (+ `policy_versions`, `next_review_date`) |
| Inventario | SÌ | `assets` (+ `relevance_score`/`is_nis2_relevant` GV.OC-04) |
| Rischi | SÌ | `risks` (+ `risk_treatments`, `kri`) |
| Fornitori/stakeholder | SÌ | `suppliers` (Supply Chain) |
| Azioni | SÌ | `non_conformities` / `corrective_actions` (mig.004) |
| Scadenziario centralizzato | NO | scadenze sparse (`policies.next_review_date`, `compliance_controls.next_review_date`, `*.due_date`) |
## 2. Modello entità + relazioni (il cuore)
**Nuove tabelle** (additive):
- **`org_roles`** — organigramma: `id, organization_id, role_name, parent_role_id NULL (gerarchia), holder_user_id NULL, is_governance_body TINYINT (nodo organi di amministrazione/direttivi, Art.23), description, created_at`. *(L'`isms_roles` SGSI può puntare a `org_roles` via `org_role_id` opzionale; non si duplica.)*
- **`skills`** — catalogo competenze: `id, organization_id NULL(=globali), name, area`.
- **`role_skills`** — competenze RICHIESTE da un ruolo: `role_id → org_roles, skill_id, required_level (1-5)`. (m2m ruolo↔skill)
- **`user_skills`** — competenze POSSEDUTE: `user_id, skill_id, level (1-5), acquired_via (course_id NULL → training), evidence`. (m2m utente↔skill, collegato al registro corsi)
- **`skill_course_map`** — skill ↔ corso che la eroga: `skill_id, training_course_id`. (collega competenze ↔ formazione)
- **`raci_assignments`** — **MATRICE RACI** (hub): `id, organization_id, role_id → org_roles, object_type ENUM('inventory','procedure','risk','supplier'), object_id, raci ENUM('R','A','C','I')`. → lega l'organigramma a inventario/procedure/rischi/fornitori (m2m via questa tabella).
- **link m2m diretti** (richiesti dalle segnalazioni 4/5/7): `procedure_inventory(procedure_id, asset_id)`, `procedure_risk(procedure_id, risk_id)`, `inventory_risk(asset_id, risk_id)`, `risk_measure(risk_id, measure_code)` (le misure ACN dell'assessment).
- **`review_schedule`** — **SCADENZIARIO centralizzato**: `id, organization_id, entity_type ENUM('role','skill','inventory','procedure','risk','supplier','measure'), entity_id, owner_role_id NULL, frequency_months, last_reviewed_at, next_review_date, status ENUM('ok','due','overdue'), notes`. Aggrega/sostituisce le scadenze sparse.
- **azione da alert** → **riuso `non_conformities` + `capa_actions`** (mig.004): l'alert (gap competenza, scadenza, rischio) crea una NCR ancorata via `source_entity_type`/`source_entity_id` (es. `'competence_gap'` + `role_skills.id`) e una `capa_actions` figlia. *(NON esiste `corrective_actions`/`source_type`: si riusa l'intero workflow CAPA senza alterarne lo schema.)*
**Relazioni chiave** (tutte m2m dove indicato dalle segnalazioni):
```
org_roles ──< raci_assignments >── (inventory | procedure | risk | supplier)
org_roles ──< role_skills >── skills ──< user_skills >── users
skills ──< skill_course_map >── training_courses
procedures ──< procedure_inventory >── inventory ──< inventory_risk >── risks
procedures ──< procedure_risk >── risks ──< risk_measure >── misure ACN (assessment)
(role|skill|inventory|procedure|risk|supplier) ──1:N── review_schedule
gap competenze / scadenze / rischi ──trigger──> non_conformities ──< capa_actions (workflow CAPA)
```
## 3. Gap competenze (segnalazione 3)
**Gap = `role_skills.required_level` (del ruolo che l'utente ricopre) − `user_skills.level`** per ciascuna skill richiesta. Vista `competence_gap` (calcolata): per ogni utente con `org_roles.holder_user_id`, confronto richiesto vs posseduto. **Alert** quando gap > 0 → apertura **azione** = NCR (`non_conformities`, `source_entity_type='competence_gap'`, `source_entity_id=role_skills.id`) + `capa_actions` figlia (+ in futuro voce nello **`review_schedule`**). Ancoraggio: **PR.AT-01** (tutti), **PR.AT-02** (solo essenziali), **GV.RR-04** (cyber nelle pratiche HR).
## 4. Ancoraggio normativo per entità (must-have)
- **Organigramma/ruoli** → **GV.RR-02** (ruoli, responsabilità e poteri stabiliti/comunicati) + **Art. 23 D.Lgs. 138/2024** (responsabilità organi di amministrazione e direttivi) → **`is_governance_body`** obbligatorio come nodo distinto con potere di approvazione.
- **Skill/formazione** → **PR.AT-01/02**, **GV.RR-04**.
- **Inventario** → **ID.AM-01/02** (+03 essenziali); collegare al **registro GV.OC-04** (`relevance_score`), non duplicarlo.
- **Procedure** → **GV.PO-01** (policy) + **GV.PO-02** (riesame/aggiornamento → scadenziario obbligatorio).
- **Rischi** → **Art. 24 D.Lgs.** + **GV.RM-03** + famiglia **ID.RA**; mappabili sulle misure (37 importanti / 43 essenziali, fino al livello requisito).
- **Stakeholder/fornitori** (segnalazione 6) → **GV.SC-02** include fornitori **+ clienti + partner** (non solo fornitori) + **GV.SC-04/05/07**; non duplicare il modulo Supply Chain esistente.
- **Scadenziario** → la revisione periodica è obbligo per **GV.PO-02**, **GV.SC-07**, **PR.AT**, **DE.CM** (periodicità puntuale come buona prassi dove non fissata).
## 5. Migration (additiva) — sketch
Nuova `041_relational_model.sql`: `org_roles`, `skills`, `role_skills`, `user_skills`, `skill_course_map`, `raci_assignments`, `procedure_inventory`, `procedure_risk`, `inventory_risk`, `risk_measure`, `review_schedule` (+ `corrective_actions.source_type`). Tutte con `organization_id` + FK + UNIQUE sulle coppie m2m. Idempotente (runner come 039/040).
## 6. UI (a fasi)
- **Organigramma**: vista ad albero (ruoli, holder, RACI badge), editor ruolo.
- **Matrice RACI**: griglia ruolo × oggetto con celle R/A/C/I.
- **Gap competenze**: dashboard per utente/ruolo (richiesto vs posseduto) + CTA "apri azione/assegna corso".
- **Scadenziario**: calendario/tabella unica delle revisioni (filtrabile per entità, owner, stato due/overdue).
- Link m2m editabili nelle pagine inventario/procedure/rischi.
## 7. Fasi consigliate (A4 è grande → spezzare)
- **4.1** `org_roles` (organigramma + nodo governance Art.23) + vista albero.
- **4.2** `skills`/`role_skills`/`user_skills`/`skill_course_map` + gap competenze (segn. 3) + alert→azione.
- **4.3** `raci_assignments` (matrice RACI) + link m2m procedure/inventario/rischi (segn. 4/5/7).
- **4.4** `review_schedule` centralizzato (segn. trasversale) + migrazione delle scadenze esistenti.
- **4.5** estensione stakeholder a clienti/partner (segn. 6, GV.SC-02) riusando Supply Chain.
## 8. Cosa NON cambia / riuso
Riuso `training_*`, `policies`, `assets` (+relevance GV.OC-04), `risks`, `suppliers`, `corrective_actions`. `isms_roles` resta per la SoA SGSI (può linkare `org_roles`). Nessuna modifica ai flussi auth/onboarding/incidenti. `entity_type`/schema esistente invariati.