[FEAT] Epic C / C5.2a — Attività stakeholder: questionari tipo + attività + calendario (mig.052)

Fondazione delle attività verso gli stakeholder (Simon C5 §4):
- Questionari tipo (template): tipo questionario-da-compilare / firma-di-avvenuta-lettura,
  domande (JSON) + collegamento m2m a procedure (policies) E a misure/requisiti del
  framework (cfg_nis2_misure/requisiti).
- Attività: basate (opz.) su un template, assegnabili a un CODICE stakeholder (tutti
  quelli di quel tipo) o a singoli stakeholder; pianificabili con data e scadenza.
- Calendario NIS2: review_schedule esteso (ENUM entity_type += 'stakeholder_activity');
  su create/update con scadenza la riga di calendario viene sincronizzata.
- Invio: genera un magic-link per destinatario (token SHA-256) per il portale esterno
  (C5.2b). Email disattivate (kill-switch) -> i link si condividono manualmente.

mig.052: stk_questionnaire_templates, stk_template_(procedures|misure|requisiti),
stk_activities, stk_activity_targets, stk_activity_procedures + ALTER review_schedule.
StakeholderActivityController + /api/stakeholder-activities/*; stakeholder-activities.html
(2 tab: attività / questionari tipo + dettaglio invio); voce sidebar V2; help/i18n.
Smoke prod OK (template m2m, attività by_code+calendario, assign, send magic-link,
anti-IDOR individual, negativi 422; cleanup org 151 pulita). Additivo. v1.20.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
DevEnv nis2-agile
2026-06-16 22:12:11 +02:00
co-authored by Claude Opus 4.8
parent c782aa54fa
commit a5ff29e0da
46 changed files with 1562 additions and 142 deletions
+19
View File
@@ -309,6 +309,25 @@ class NIS2API {
stkUpdate(id, d) { return this._acn(this.put(`/stakeholders/${id}`, d || {})); }
stkDelete(id) { return this._acn(this.del(`/stakeholders/${id}`)); }
// ═══════════════════════════════════════════════════════════════════
// Attività stakeholder (Epic C / C5.2). Tutti _acn.
// Questionari tipo (template) + attività (questionari/azioni) + assegnazione
// (per codice o singoli) + invio (genera magic-link per il portale esterno).
// ═══════════════════════════════════════════════════════════════════
stkActTemplates() { return this._acn(this.get('/stakeholder-activities/templates')); }
stkActGetTemplate(id) { return this._acn(this.get(`/stakeholder-activities/templates/${id}`)); }
stkActCreateTemplate(d) { return this._acn(this.post('/stakeholder-activities/templates', d || {})); }
stkActUpdateTemplate(id, d) { return this._acn(this.put(`/stakeholder-activities/templates/${id}`, d || {})); }
stkActDeleteTemplate(id) { return this._acn(this.del(`/stakeholder-activities/templates/${id}`)); }
stkActPickers() { return this._acn(this.get('/stakeholder-activities/pickers')); }
stkActList() { return this._acn(this.get('/stakeholder-activities/list')); }
stkActGet(id) { return this._acn(this.get(`/stakeholder-activities/${id}`)); }
stkActCreate(d) { return this._acn(this.post('/stakeholder-activities/create', d || {})); }
stkActUpdate(id, d) { return this._acn(this.put(`/stakeholder-activities/${id}`, d || {})); }
stkActDelete(id) { return this._acn(this.del(`/stakeholder-activities/${id}`)); }
stkActAssign(id, d) { return this._acn(this.post(`/stakeholder-activities/${id}/assign`, d || {})); }
stkActSend(id) { return this._acn(this.post(`/stakeholder-activities/${id}/send`, {})); }
// ═══════════════════════════════════════════════════════════════════
// Dashboard
// ═══════════════════════════════════════════════════════════════════
+1
View File
@@ -78,6 +78,7 @@
{ name: 'Policy', href: 'policies.html', icon: iconDocumentText(), i18nKey: 'nav.policies' },
{ name: 'Supply Chain', href: 'supply-chain.html', icon: iconLink(), i18nKey: 'nav.supply_chain' },
{ name: 'Stakeholder', href: 'stakeholders.html', icon: '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clip-rule="evenodd"/><path d="M5.5 7.5a2 2 0 11-2.999.001A2 2 0 015.5 7.5zM17.5 7.5a2 2 0 11-2.999.001A2 2 0 0117.5 7.5z"/></svg>', i18nKey: 'nav.stakeholders' },
{ name: 'Attività stakeholder', href: 'stakeholder-activities.html', icon: '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M9 2a1 1 0 000 2h2a1 1 0 100-2H9z" clip-rule="evenodd"/><path fill-rule="evenodd" d="M4 5a2 2 0 012-2 3 3 0 003 3h2a3 3 0 003-3 2 2 0 012 2v11a2 2 0 01-2 2H6a2 2 0 01-2-2V5zm3 4a1 1 0 000 2h.01a1 1 0 100-2H7zm3 0a1 1 0 000 2h3a1 1 0 100-2h-3zm-3 4a1 1 0 100 2h.01a1 1 0 100-2H7zm3 0a1 1 0 100 2h3a1 1 0 100-2h-3z" clip-rule="evenodd"/></svg>', i18nKey: 'nav.stk_activities' },
{ name: 'Segnalazioni', href: 'whistleblowing.html', icon: '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clip-rule="evenodd"/></svg>' },
{ name: 'Normative', href: 'normative.html', icon: '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4zm2 6a1 1 0 011-1h6a1 1 0 110 2H7a1 1 0 01-1-1zm1 3a1 1 0 100 2h6a1 1 0 100-2H7z" clip-rule="evenodd"/></svg>' },
{ name: 'AI Cross-Analysis', href: 'cross-analysis.html', icon: '<svg viewBox="0 0 20 20" fill="currentColor"><path d="M13 6a3 3 0 11-6 0 3 3 0 016 0zM18 8a2 2 0 11-4 0 2 2 0 014 0zM14 15a4 4 0 00-8 0v3h8v-3zM6 8a2 2 0 11-4 0 2 2 0 014 0zM16 18v-3a5.972 5.972 0 00-.75-2.906A3.005 3.005 0 0119 15v3h-3zM4.75 12.094A5.973 5.973 0 004 15v3H1v-3a3 3 0 013.75-2.906z"/></svg>' },
+36
View File
@@ -400,6 +400,40 @@ const HelpSystem = (function () {
'NOTA: gli obblighi normativi in Italia derivano dal D.Lgs. 138/2024; la matrice e i framework NIST CSF/ACN sono strumenti di supporto, non un parere legale.'
]
},
'stakeholder-activities': {
title: 'Guida - Attività stakeholder',
intro: 'Le attività verso gli stakeholder ti permettono di inviare questionari (da compilare o per firma di avvenuta lettura) e pianificare azioni, collegandoli alle procedure e alle misure/requisiti, con data e scadenza sul calendario NIS2. Strumento di supporto organizzativo, non un parere legale.',
sections: [
{
heading: 'Questionari tipo',
items: [
'Un <strong>questionario tipo</strong> è un modello riutilizzabile: scegli se è un <strong>questionario da compilare</strong> (con domande) o una <strong>richiesta di firma di avvenuta lettura</strong> (un testo da leggere e confermare).',
'Puoi collegare il questionario tipo alle <strong>procedure</strong> e alle <strong>misure/requisiti</strong> del framework (collegamento molti-a-molti), per documentare a cosa si riferisce.'
]
},
{
heading: 'Attività e assegnazione',
items: [
'Crea un\'<strong>attività</strong> basata (o no) su un questionario tipo e assegnala <strong>per codice stakeholder</strong> (tutti quelli di quel tipo) oppure a <strong>stakeholder singoli</strong> selezionati.',
'Indica una <strong>data pianificata</strong> e una <strong>scadenza</strong>: la scadenza compare automaticamente nel <strong>calendario NIS2</strong> (Scadenziario).',
'Con <strong>Invia</strong> il sistema genera un <strong>magic-link</strong> per ogni destinatario. Poiché le email sono disattivate, copia e condividi i link manualmente; gli stakeholder rispondono dal portale senza account.'
]
},
{
heading: 'Riferimenti normativi',
items: [
'<strong>GV.SC-02</strong>: ruoli e responsabilità verso fornitori, clienti e partner.',
'<strong>GV.SC-05 / GV.SC-07</strong>: requisiti di sicurezza negli accordi e monitoraggio/revisione delle terze parti nel tempo.',
'Le <strong>azioni</strong> correttive/preventive si gestiscono nel modulo NCR/CAPA.'
]
}
],
references: [
'NIST CSF 2.0 / GV.SC-02, GV.SC-05, GV.SC-07 - Coordinamento, accordi e monitoraggio delle terze parti',
'Obblighi: gestione della supply chain ai sensi dell\'art. 24 del D.Lgs. 138/2024.',
'NOTA: strumento di supporto organizzativo, non un parere legale.'
]
},
// ─── Risk Management ─────────────────────────────────────────
'risks': {
@@ -1248,6 +1282,8 @@ const HelpSystem = (function () {
'misure-requisiti': 'misure-requisiti',
'stakeholders.html': 'stakeholders',
'stakeholders': 'stakeholders',
'stakeholder-activities.html': 'stakeholder-activities',
'stakeholder-activities': 'stakeholder-activities',
'risks.html': 'risks',
'risks': 'risks',
'incidents.html': 'incidents',
+2
View File
@@ -72,8 +72,10 @@ const I18n = (function () {
'raci.title': { it: 'Matrice RACI', en: 'RACI Matrix' },
'nav.review_schedule': { it: 'Scadenziario', en: 'Review schedule' },
'nav.stakeholders': { it: 'Stakeholder', en: 'Stakeholders' },
'nav.stk_activities': { it: 'Attività stakeholder', en: 'Stakeholder activities' },
'rev.title': { it: 'Scadenziario', en: 'Review Schedule' },
'stk.title': { it: 'Stakeholder', en: 'Stakeholders' },
'sact.title': { it: 'Attività stakeholder', en: 'Stakeholder activities' },
'nav.risks': { it: 'Rischi', en: 'Risks' },
'nav.incidents': { it: 'Incidenti', en: 'Incidents' },
'nav.policies': { it: 'Policy', en: 'Policies' },