[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>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
47199f1e4e
commit
5368b0a61c
@@ -0,0 +1,92 @@
|
||||
-- ============================================================================
|
||||
-- Migration 042 — A4 Fase 4.2: Competenze (skill / requisiti ruolo / competenze
|
||||
-- possedute / mappatura corsi) + base per gap competenze e alert->azione.
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- 4 tabelle ADDITIVE. Idempotente (CREATE TABLE IF NOT EXISTS). Applicare con la
|
||||
-- STESSA connessione PDO dell'app (host MySQL servito da php-fpm), via runner.
|
||||
--
|
||||
-- Ancoraggio normativo (docs/DESIGN_A4_RELATIONAL.md sez.3/4): PR.AT-01 (tutti),
|
||||
-- PR.AT-02 (solo soggetti essenziali), GV.RR-04 (cyber nelle pratiche HR).
|
||||
--
|
||||
-- NOTA architetturale: l'alert "gap competenza -> azione" RIUSA il workflow
|
||||
-- NCR/CAPA gia esistente (tabelle non_conformities + capa_actions, mig.004).
|
||||
-- NON esiste alcuna tabella 'corrective_actions' (nome errato nel design): le
|
||||
-- azioni sono capa_actions, figlie obbligatorie di una non_conformity. Quindi
|
||||
-- questa migration NON crea/altera tabelle azioni: ancora il gap alla NCR via
|
||||
-- non_conformities.source_entity_type='competence_gap' + source_entity_id.
|
||||
-- ============================================================================
|
||||
|
||||
-- Catalogo competenze. organization_id NULL = competenza globale di sistema
|
||||
-- (visibile a tutte le org, come i corsi globali).
|
||||
CREATE TABLE IF NOT EXISTS skills (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
organization_id INT NULL,
|
||||
name VARCHAR(150) NOT NULL,
|
||||
area VARCHAR(100) NULL,
|
||||
description TEXT NULL,
|
||||
created_by INT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL,
|
||||
INDEX idx_skills_org (organization_id),
|
||||
INDEX idx_skills_area (area)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Competenze RICHIESTE da un ruolo dell'organigramma (m2m ruolo<->skill).
|
||||
CREATE TABLE IF NOT EXISTS role_skills (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
organization_id INT NOT NULL,
|
||||
role_id INT NOT NULL,
|
||||
skill_id INT NOT NULL,
|
||||
required_level TINYINT NOT NULL DEFAULT 3,
|
||||
created_by INT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (role_id) REFERENCES org_roles(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (skill_id) REFERENCES skills(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL,
|
||||
UNIQUE KEY uk_role_skill (role_id, skill_id),
|
||||
INDEX idx_role_skills_org (organization_id),
|
||||
INDEX idx_role_skills_skill (skill_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Competenze POSSEDUTE da un utente (m2m utente<->skill). acquired_via_course_id
|
||||
-- collega eventualmente la competenza al corso che l'ha erogata (registro corsi).
|
||||
CREATE TABLE IF NOT EXISTS user_skills (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
organization_id INT NOT NULL,
|
||||
user_id INT NOT NULL,
|
||||
skill_id INT NOT NULL,
|
||||
level TINYINT NOT NULL DEFAULT 1,
|
||||
acquired_via_course_id INT NULL,
|
||||
evidence VARCHAR(500) NULL,
|
||||
assessed_at DATETIME NULL,
|
||||
created_by INT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (skill_id) REFERENCES skills(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (acquired_via_course_id) REFERENCES training_courses(id) ON DELETE SET NULL,
|
||||
FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL,
|
||||
UNIQUE KEY uk_user_skill (organization_id, user_id, skill_id),
|
||||
INDEX idx_user_skills_user (user_id),
|
||||
INDEX idx_user_skills_skill (skill_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Mappatura competenza <-> corso che la eroga (m2m). Il corso puo essere globale
|
||||
-- (training_courses.organization_id NULL) o dell'org.
|
||||
CREATE TABLE IF NOT EXISTS skill_course_map (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
skill_id INT NOT NULL,
|
||||
training_course_id INT NOT NULL,
|
||||
created_by INT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (skill_id) REFERENCES skills(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (training_course_id) REFERENCES training_courses(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL,
|
||||
UNIQUE KEY uk_skill_course (skill_id, training_course_id),
|
||||
INDEX idx_skill_course_course (training_course_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
Reference in New Issue
Block a user