nis2-agile/docs/DESIGN_MODULO_QUESTIONARI_FORNITORI.md
DevEnv nis2-agile 27b2ba1762 [DOCS] Design modulo questionari fornitori configurabile (proposta, no codice)
Richiesta utente: anagrafica fornitore + compilazione online, questionari per categoria,
domande estensibili (anche procedure interne), gestione scadenze/aggiornamenti, accesso
fornitore per profilo. Doc: schema DB, API, UI, 4 fasi incrementali, accesso IBRIDO
(token-first + account-on-demand), sicurezza, domande aperte. Da approvare prima di implementare.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 08:31:26 +02:00

8.7 KiB

Design — Modulo Questionari Fornitori configurabile

Stato: PROPOSTA DI DESIGN (nessun codice scritto). Da approvare prima dell'implementazione. Autore: sessione 2026-05-31. Origine: richiesta utente (Cristiano Benassati). Riferimenti prodotto attuali: SupplyChainController (self-assessment a link-token già esistente, P3), supplier-assessment.html, tabella supplier_questionnaires (migrazione 027), acn_requirements (migrazione 031).


1. Obiettivo

Evolvere l'attuale self-assessment fornitori (link-token usa-e-getta, 8 domande fisse) in un modulo questionari configurabile e ricorrente, che copra 4 capacità richieste:

  1. Anagrafica fornitore con possibilità per il fornitore di compilare online.
  2. Questionari diversi per categoria fornitore (es. cloud provider, MSP/MSSP, manutentore hardware, consulenza, logistica…).
  3. Domande configurabili ed estensibili dall'azienda — non solo NIS2, ma anche per procedure interne (qualità, privacy, 231, ESG…).
  4. Gestione scadenze e ricorrenze, con accesso del fornitore in base al profilo registrato e gestione degli aggiornamenti nel tempo.

Valore: trasforma il modulo Supply Chain da "valutazione una tantum" a due-diligence continua dei fornitori — coerente con Art. 21.2(d) NIS2 e con le best practice (ENISA supply chain, ISO 28000).


2. Cosa esiste già (base di partenza)

Componente esistente Riuso
SupplyChainController::sendQuestionnaire (link-token + scadenza 30gg) base per le "campagne"
publicQuestionnaire / submitPublicQuestionnaire (no-auth via token) base per la compilazione online senza account
supplier_questionnaires (token_hash, status, score, expires_at) da estendere con template_id e recurrence
supplier-assessment.html (pagina pubblica) da rendere dinamica (render del template)
costante QUESTIONNAIRE (8 domande hardcoded) da migrare in DB configurabile

Gap da colmare: le 8 domande sono hardcoded nel controller; non c'è categoria fornitore, né editor domande, né ricorrenza/scadenze gestite, né profilo fornitore persistente.


3. Decisione architetturale chiave — accesso fornitore (ibrido)

Richiesta utente: valutare ibrido. Proposta:

Modello consigliato: token-per-campagna come default + account fornitore opzionale ("upgrade")

Aspetto Link-token (default) Account fornitore (opzionale)
Onboarding fornitore zero attrito: clic sul link email registrazione/credenziali
Sicurezza token sha256 + scadenza, single-purpose superficie auth nuova da proteggere
Storico per il fornitore no (lo vede solo l'azienda) sì: portale con questionari passati/scadenze
Ricorrenza/aggiornamenti nuovo link a ogni campagna il fornitore rientra e aggiorna
Costo implementativo basso (estende l'esistente) alto (auth esterna, sessioni, recovery)

Raccomandazione: partire token-per-campagna esteso (Fase 1-2), e introdurre l'account fornitore solo in Fase 4, quando il valore lo giustifica. Un fornitore può "rivendicare" il proprio profilo (claim) partendo da un token valido → diventa account. Questo è l'ibrido: token-first, account-on-demand, senza costruire subito un IdP esterno.

Sicurezza account fornitore (se/quando attivato): utenti in tabella separata supplier_users (MAI in users interni), password Argon2id, rate-limit, scope limitato alla sola anagrafica/questionari del proprio fornitore, nessun accesso ai dati dell'organizzazione cliente. Valutare riuso del pattern token effimero invece di password.


4. Schema dati proposto (migrazioni nuove, additive)

supplier_categories
  id, organization_id (NULL = globale/sistema), name, slug, description, active

questionnaire_templates
  id, organization_id, category_id (FK supplier_categories, NULL = tutte),
  name, version, scope ENUM('nis2','privacy','quality','231','esg','custom'),
  recurrence_months (NULL = una tantum), is_active, created_by, created_at
  -- versioning: come policy_versions, snapshot a ogni pubblicazione

questionnaire_questions
  id, template_id, order_index, code, text,
  type ENUM('yes_no_partial','scale_1_5','single_choice','multi_choice','text','number','file'),
  options JSON (per choice), weight, required, help_text
  -- estensibili: l'azienda aggiunge domande per procedure interne

questionnaire_campaigns
  id, organization_id, supplier_id, template_id, template_version,
  status ENUM('draft','sent','in_progress','completed','expired','overdue'),
  token_hash, sent_to_email, sent_at, due_at, completed_at,
  reminder_count, next_reminder_at, score, risk_level

questionnaire_answers
  id, campaign_id, question_id, answer_value, answer_text, file_ref, answered_at

-- Fase 4 (opzionale):
supplier_users
  id, supplier_id, email, password_hash, status, last_login_at, ...

suppliers esistente: aggiungere category_id (FK), default_contact_email già presente come contact_email.


5. API proposte

Lato azienda (JWT):

  • GET/POST /api/supply-chain/categories — CRUD categorie fornitore
  • GET/POST/PUT /api/supply-chain/templates — CRUD template + versioning
  • GET/POST/PUT/DELETE /api/supply-chain/templates/{id}/questions — editor domande
  • POST /api/supply-chain/{supplierId}/campaigns — avvia campagna (sceglie template per categoria, imposta scadenza/ricorrenza)
  • GET /api/supply-chain/campaigns — cruscotto campagne con scadenze/stato

Lato fornitore (no-auth via token, evoluzione dell'esistente):

  • GET /api/supply-chain/public-questionnaire?token= — ritorna il template dinamico (domande dal DB, non più hardcoded)
  • POST /api/supply-chain/submit-public-questionnaire — salva risposte multi-tipo + calcola score pesato

Scadenze (cron):

  • scripts/supplier-questionnaire-cron.sh (Europe/Rome): invia reminder, marca overdue, apre la campagna ricorrente alla scadenza recurrence_months.

6. UI proposta

  • supply-chain.html: tab "Categorie" + "Template questionari" (editor domande drag&drop o lista ordinabile); sulla scheda fornitore, dropdown categoria + "Avvia campagna" (sceglie template, scadenza, ricorrenza).
  • supplier-assessment.html: reso dinamico — renderizza qualsiasi template/tipi di domanda dal token.
  • Cruscotto scadenze: lista campagne con semaforo (in regola / in scadenza / scaduta), reminder inviati.
  • (Fase 4) portale fornitore: login separato, "i miei questionari", storico, prossime scadenze.

7. Fasi incrementali (proposta)

Fase Contenuto Rischio Valore
1 Categorie fornitore + template/domande configurabili in DB (migra le 8 domande hardcoded) + editor base lato azienda. supplier-assessment.html dinamico. Basso (additivo) Questionari per categoria + estensibili
2 Campagne con scadenza + reminder (cron) + cruscotto stato. Ricorrenza (recurrence_months). Medio (cron) Gestione scadenze/aggiornamenti
3 Tipi domanda avanzati (allegati, scale, multi-choice) + scoring configurabile per peso. Medio Flessibilità procedure interne
4 Account fornitore (portale persistente, claim da token). Alto (auth esterna) Self-service completo

Ogni fase è rilasciabile da sola. Le Fasi 1-2 coprono già l'80% della richiesta.


8. Sicurezza / conformità (da rispettare)

  • Token: sq_ + 20 byte random, hash SHA-256 in DB, scadenza, single-use sul completamento (già fatto, da mantenere).
  • Endpoint pubblici: nessun dato di altre org accessibile dal token (no IDOR — già verificato sul modulo attuale).
  • Dati fornitore = dati personali del referente → rispetto GDPR (minimizzazione, retention, diritto cancellazione).
  • Account fornitore (Fase 4): tabella separata, mai mischiare con users; secret nel vault se servono integrazioni.
  • Audit: ogni invio/compilazione loggato (riuso logAudit).

9. Domande aperte per l'utente (prima di implementare)

  1. Le categorie fornitore sono libere (definite dall'azienda) o vuoi un set predefinito di partenza (cloud/MSP/hardware/consulenza/logistica)?
  2. La ricorrenza tipica: annuale? configurabile per template?
  3. I reminder: quanti e a che intervallo prima/dopo la scadenza?
  4. Lo scoring: soglia "requisiti soddisfatti" come oggi (≥70) o configurabile per template?
  5. Fase 4 account fornitore: serve davvero o il link-token ricorrente basta?

10. Stima (indicativa, multi-sessione)

  • Fase 1: ~1 sessione (migrazione + CRUD template/domande + render dinamico).
  • Fase 2: ~1 sessione (campagne + cron scadenze + cruscotto).
  • Fase 3: ~0.5 sessione.
  • Fase 4: ~1-2 sessioni (auth fornitore + portale, la più delicata).

Nessuna di queste tocca i moduli esistenti in modo distruttivo: tutto additivo.