nis2-agile/public/architecture.html
Cristiano Benassati 52fd45fac9 [FEAT] i18n IT/EN, Help Online contestuale, pagina Architettura
- i18n.js: sistema traduzioni IT/EN con ~150 chiavi, localStorage, data-i18n
- help.js: help contestuale per 10 pagine con riferimenti NIS2
- architecture.html: descrizione architettura sistema completa
- common.js: language toggle sidebar (IT/EN), link Architettura, icone
- Integrato i18n + help in tutte le 14 pagine app + 3 admin

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 08:34:37 +01:00

1089 lines
48 KiB
HTML

<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Architettura - NIS2 Agile</title>
<link rel="stylesheet" href="css/style.css">
<style>
/* ── Architecture Page Styles ────────────────────────────────── */
.arch-section {
margin-bottom: 32px;
}
.arch-section:last-child {
margin-bottom: 0;
}
.arch-section .card-header h3 {
display: flex;
align-items: center;
gap: 10px;
}
.arch-section .card-header h3 .section-number {
width: 28px;
height: 28px;
border-radius: 50%;
background: var(--primary);
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.75rem;
font-weight: 700;
flex-shrink: 0;
}
/* Overview text */
.arch-overview p {
font-size: 0.9375rem;
line-height: 1.75;
color: var(--gray-600);
margin-bottom: 12px;
}
.arch-overview p:last-child {
margin-bottom: 0;
}
.arch-highlight {
display: inline;
font-weight: 600;
color: var(--gray-800);
}
/* Tech Stack Grid */
.tech-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 16px;
}
.tech-item {
background: var(--gray-50);
border: 1px solid var(--gray-200);
border-radius: var(--border-radius);
padding: 20px;
text-align: center;
transition: all var(--transition-fast);
}
.tech-item:hover {
border-color: var(--primary);
background: var(--primary-bg);
transform: translateY(-2px);
box-shadow: var(--card-shadow);
}
.tech-icon {
width: 48px;
height: 48px;
border-radius: var(--border-radius);
margin: 0 auto 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.25rem;
font-weight: 800;
}
.tech-icon.frontend { background: #fef3c7; color: #d97706; }
.tech-icon.backend { background: #e0e7ff; color: #4338ca; }
.tech-icon.database { background: #dbeafe; color: #1d4ed8; }
.tech-icon.server { background: #d1fae5; color: #059669; }
.tech-icon.container { background: #e0f2fe; color: #0284c7; }
.tech-icon.ai { background: #fce7f3; color: #be185d; }
.tech-icon.auth { background: #fef9c3; color: #a16207; }
.tech-item h4 {
font-size: 0.8125rem;
font-weight: 700;
color: var(--gray-800);
margin-bottom: 6px;
text-transform: uppercase;
letter-spacing: 0.03em;
}
.tech-item p {
font-size: 0.8125rem;
color: var(--gray-500);
line-height: 1.5;
}
/* Architecture Diagram */
.arch-diagram {
padding: 32px 16px;
overflow-x: auto;
}
.arch-flow {
display: flex;
align-items: center;
justify-content: center;
gap: 0;
min-width: 700px;
flex-wrap: nowrap;
}
.arch-box {
padding: 16px 20px;
border-radius: var(--border-radius);
text-align: center;
font-size: 0.8125rem;
font-weight: 600;
min-width: 120px;
position: relative;
flex-shrink: 0;
}
.arch-box .arch-box-sub {
font-size: 0.7rem;
font-weight: 400;
margin-top: 4px;
opacity: 0.85;
}
.arch-box.client {
background: #dbeafe;
border: 2px solid #3b82f6;
color: #1e40af;
}
.arch-box.nginx {
background: #d1fae5;
border: 2px solid #10b981;
color: #065f46;
}
.arch-box.php {
background: #e0e7ff;
border: 2px solid #6366f1;
color: #3730a3;
}
.arch-box.controller {
background: #fef3c7;
border: 2px solid #f59e0b;
color: #92400e;
}
.arch-box.database {
background: #fce7f3;
border: 2px solid #ec4899;
color: #9d174d;
}
.arch-arrow {
display: flex;
align-items: center;
flex-shrink: 0;
padding: 0 4px;
}
.arch-arrow svg {
width: 32px;
height: 20px;
fill: var(--gray-400);
}
/* Routing sub-flow */
.arch-routing {
margin-top: 24px;
padding: 20px 24px;
background: var(--gray-50);
border: 1px solid var(--gray-200);
border-radius: var(--border-radius);
}
.arch-routing h4 {
font-size: 0.8125rem;
font-weight: 700;
color: var(--gray-700);
margin-bottom: 12px;
text-transform: uppercase;
letter-spacing: 0.03em;
}
.routing-flow {
display: flex;
align-items: center;
justify-content: center;
gap: 0;
flex-wrap: wrap;
}
.routing-step {
background: var(--card-bg);
border: 1px solid var(--gray-300);
border-radius: var(--border-radius-sm);
padding: 8px 16px;
font-size: 0.8rem;
font-weight: 600;
color: var(--gray-700);
font-family: var(--font-mono);
}
.routing-arrow {
padding: 0 8px;
color: var(--gray-400);
font-size: 1rem;
flex-shrink: 0;
}
/* Directory Tree */
.dir-tree {
background: var(--gray-900);
color: #e2e8f0;
border-radius: var(--border-radius);
padding: 24px 28px;
font-family: var(--font-mono);
font-size: 0.8125rem;
line-height: 1.8;
overflow-x: auto;
white-space: pre;
}
.dir-tree .dir-name {
color: #60a5fa;
font-weight: 600;
}
.dir-tree .dir-comment {
color: #6b7280;
}
.dir-tree .dir-file {
color: #a5b4fc;
}
/* Data Model */
.data-model {
overflow-x: auto;
padding: 24px 0;
}
.data-model-grid {
display: flex;
flex-direction: column;
gap: 24px;
min-width: 600px;
}
.data-model-row {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
flex-wrap: nowrap;
}
.data-entity {
background: var(--card-bg);
border: 2px solid var(--gray-300);
border-radius: var(--border-radius);
padding: 12px 18px;
text-align: center;
min-width: 130px;
flex-shrink: 0;
transition: all var(--transition-fast);
}
.data-entity:hover {
border-color: var(--primary);
box-shadow: var(--card-shadow);
}
.data-entity.primary-entity {
border-color: var(--primary);
background: var(--primary-bg);
}
.data-entity h5 {
font-size: 0.8rem;
font-weight: 700;
color: var(--gray-800);
font-family: var(--font-mono);
}
.data-entity p {
font-size: 0.7rem;
color: var(--gray-500);
margin-top: 2px;
}
.data-rel {
color: var(--gray-400);
font-size: 0.875rem;
flex-shrink: 0;
font-weight: 700;
}
.data-children {
display: flex;
flex-wrap: wrap;
gap: 10px;
justify-content: center;
padding: 0 16px;
}
.data-child {
background: var(--gray-50);
border: 1px solid var(--gray-200);
border-radius: var(--border-radius-sm);
padding: 8px 14px;
font-size: 0.75rem;
font-weight: 600;
color: var(--gray-600);
font-family: var(--font-mono);
transition: all var(--transition-fast);
}
.data-child:hover {
border-color: var(--primary);
color: var(--primary);
background: var(--primary-bg);
}
.data-arrow-down {
display: flex;
justify-content: center;
padding: 4px 0;
color: var(--gray-400);
}
.data-note {
margin-top: 16px;
padding: 12px 16px;
background: var(--info-bg);
border-radius: var(--border-radius-sm);
border-left: 3px solid var(--primary);
font-size: 0.8125rem;
color: var(--gray-600);
}
.data-note code {
background: rgba(26, 115, 232, 0.12);
padding: 2px 6px;
border-radius: 3px;
font-family: var(--font-mono);
font-size: 0.75rem;
font-weight: 600;
color: var(--primary);
}
/* Security List */
.security-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 16px;
}
.security-item {
display: flex;
align-items: flex-start;
gap: 12px;
padding: 16px;
background: var(--gray-50);
border-radius: var(--border-radius);
border: 1px solid var(--gray-200);
}
.security-icon {
width: 36px;
height: 36px;
border-radius: 50%;
background: var(--secondary-bg);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.security-icon svg {
width: 18px;
height: 18px;
fill: #15803d;
}
.security-item h4 {
font-size: 0.8125rem;
font-weight: 700;
color: var(--gray-800);
margin-bottom: 4px;
}
.security-item p {
font-size: 0.8rem;
color: var(--gray-500);
line-height: 1.5;
}
/* Module cards */
.module-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 16px;
}
.module-card {
background: var(--card-bg);
border: 1px solid var(--gray-200);
border-radius: var(--border-radius);
padding: 20px;
transition: all var(--transition-fast);
border-top: 3px solid var(--primary);
}
.module-card:hover {
box-shadow: var(--card-shadow-hover);
transform: translateY(-2px);
}
.module-card:nth-child(2) { border-top-color: #f59e0b; }
.module-card:nth-child(3) { border-top-color: var(--danger); }
.module-card:nth-child(4) { border-top-color: #8b5cf6; }
.module-card:nth-child(5) { border-top-color: #06b6d4; }
.module-card:nth-child(6) { border-top-color: #10b981; }
.module-card:nth-child(7) { border-top-color: #ec4899; }
.module-card:nth-child(8) { border-top-color: #f97316; }
.module-card:nth-child(9) { border-top-color: var(--gray-600); }
.module-card h4 {
font-size: 0.9375rem;
font-weight: 700;
color: var(--gray-800);
margin-bottom: 4px;
}
.module-card .module-ref {
font-size: 0.7rem;
font-weight: 600;
color: var(--primary);
text-transform: uppercase;
letter-spacing: 0.03em;
margin-bottom: 8px;
}
.module-card p {
font-size: 0.8125rem;
color: var(--gray-500);
line-height: 1.6;
}
/* Integration items */
.integration-list {
display: flex;
flex-direction: column;
gap: 16px;
}
.integration-item {
display: flex;
align-items: flex-start;
gap: 16px;
padding: 20px;
background: var(--gray-50);
border-radius: var(--border-radius);
border: 1px solid var(--gray-200);
}
.integration-icon {
width: 44px;
height: 44px;
border-radius: var(--border-radius);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
font-size: 1.125rem;
font-weight: 800;
}
.integration-icon.ext { background: #e0e7ff; color: #4338ca; }
.integration-icon.visura { background: #fef3c7; color: #d97706; }
.integration-icon.claude { background: #fce7f3; color: #be185d; }
.integration-item h4 {
font-size: 0.9375rem;
font-weight: 700;
color: var(--gray-800);
margin-bottom: 4px;
}
.integration-item p {
font-size: 0.8125rem;
color: var(--gray-500);
line-height: 1.6;
}
/* Deploy items */
.deploy-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 16px;
}
.deploy-item {
display: flex;
align-items: flex-start;
gap: 14px;
padding: 20px;
background: var(--gray-50);
border-radius: var(--border-radius);
border: 1px solid var(--gray-200);
}
.deploy-icon {
width: 40px;
height: 40px;
border-radius: var(--border-radius);
background: var(--gray-800);
color: #fff;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.deploy-icon svg {
width: 20px;
height: 20px;
fill: currentColor;
}
.deploy-item h4 {
font-size: 0.875rem;
font-weight: 700;
color: var(--gray-800);
margin-bottom: 4px;
}
.deploy-item p {
font-size: 0.8125rem;
color: var(--gray-500);
line-height: 1.5;
}
/* RBAC role badges */
.role-list {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 8px;
}
.role-badge {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 5px 12px;
font-size: 0.75rem;
font-weight: 600;
border-radius: 100px;
font-family: var(--font-mono);
}
.role-badge.sa { background: var(--danger-bg); color: var(--danger); }
.role-badge.oa { background: #fef3c7; color: #92400e; }
.role-badge.cm { background: var(--primary-bg); color: var(--primary); }
.role-badge.bm { background: #e0e7ff; color: #4338ca; }
.role-badge.au { background: var(--secondary-bg); color: #15803d; }
.role-badge.em { background: var(--gray-100); color: var(--gray-600); }
/* Responsive overrides */
@media (max-width: 768px) {
.tech-grid {
grid-template-columns: repeat(2, 1fr);
}
.module-grid {
grid-template-columns: 1fr;
}
.security-grid {
grid-template-columns: 1fr;
}
.deploy-grid {
grid-template-columns: 1fr;
}
.arch-flow {
min-width: 580px;
}
}
@media (max-width: 480px) {
.tech-grid {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div class="app-layout">
<!-- Sidebar -->
<aside class="sidebar" id="sidebar"></aside>
<!-- Main Content -->
<main class="main-content">
<header class="content-header">
<h2>Architettura del Sistema</h2>
<div class="content-header-actions">
<span class="badge badge-neutral">v1.0</span>
</div>
</header>
<div class="content-body">
<!-- ═══ 1. Panoramica ═══════════════════════════════════ -->
<div class="arch-section">
<div class="card">
<div class="card-header">
<h3><span class="section-number">1</span> Panoramica</h3>
</div>
<div class="card-body arch-overview">
<p>
<span class="arch-highlight">NIS2 Agile</span> e' una piattaforma di gestione della conformita' progettata
per la <span class="arch-highlight">Direttiva NIS2 dell'Unione Europea (2022/2555)</span>. La piattaforma
guida le organizzazioni italiane attraverso tutti i requisiti normativi, fornendo strumenti strutturati per
la valutazione del rischio, la gestione degli incidenti, la generazione di policy e il monitoraggio della conformita'.
</p>
<p>
L'applicazione e' costruita specificamente per le organizzazioni italiane classificate come
<span class="badge badge-danger">Soggetti Essenziali</span> e
<span class="badge badge-warning">Soggetti Importanti</span>
ai sensi della direttiva, con supporto completo per i requisiti degli Articoli 20-25.
</p>
<p>
L'architettura adotta un modello <span class="arch-highlight">multi-tenant SaaS</span> con controllo degli
accessi basato sui ruoli (RBAC), consentendo a piu' organizzazioni di operare in modo sicuro e isolato
sulla stessa istanza della piattaforma.
</p>
</div>
</div>
</div>
<!-- ═══ 2. Stack Tecnologico ════════════════════════════ -->
<div class="arch-section">
<div class="card">
<div class="card-header">
<h3><span class="section-number">2</span> Stack Tecnologico</h3>
</div>
<div class="card-body">
<div class="tech-grid">
<div class="tech-item">
<div class="tech-icon frontend">FE</div>
<h4>Frontend</h4>
<p>HTML5, CSS3 (Custom Design System), Vanilla JavaScript (no framework)</p>
</div>
<div class="tech-item">
<div class="tech-icon backend">BE</div>
<h4>Backend</h4>
<p>PHP 8.4 (vanilla, no framework), Front Controller pattern</p>
</div>
<div class="tech-item">
<div class="tech-icon database">DB</div>
<h4>Database</h4>
<p>MySQL 8.0 con PDO (prepared statements)</p>
</div>
<div class="tech-item">
<div class="tech-icon server">WS</div>
<h4>Web Server</h4>
<p>Nginx 1.27 Alpine + PHP-FPM 8.4</p>
</div>
<div class="tech-item">
<div class="tech-icon container">DC</div>
<h4>Containerizzazione</h4>
<p>Docker Compose (multi-container orchestration)</p>
</div>
<div class="tech-item">
<div class="tech-icon ai">AI</div>
<h4>Intelligenza Artificiale</h4>
<p>Claude API (Anthropic) per generazione policy e analisi</p>
</div>
<div class="tech-item">
<div class="tech-icon auth">JW</div>
<h4>Autenticazione</h4>
<p>JWT HS256 (access token 2h + refresh token 7d)</p>
</div>
</div>
</div>
</div>
</div>
<!-- ═══ 3. Architettura dell'Applicazione ═══════════════ -->
<div class="arch-section">
<div class="card">
<div class="card-header">
<h3><span class="section-number">3</span> Architettura dell'Applicazione</h3>
</div>
<div class="card-body">
<div class="arch-diagram">
<div class="arch-flow">
<div class="arch-box client">
Client Browser
<div class="arch-box-sub">HTML/CSS/JS</div>
</div>
<div class="arch-arrow">
<svg viewBox="0 0 32 20"><path d="M0 10h26l-6-6 1.5-1.5L30 10l-8.5 7.5L20 16l6-6H0z"/></svg>
</div>
<div class="arch-box nginx">
Nginx
<div class="arch-box-sub">Reverse Proxy</div>
</div>
<div class="arch-arrow">
<svg viewBox="0 0 32 20"><path d="M0 10h26l-6-6 1.5-1.5L30 10l-8.5 7.5L20 16l6-6H0z"/></svg>
</div>
<div class="arch-box php">
PHP-FPM
<div class="arch-box-sub">Front Controller</div>
</div>
<div class="arch-arrow">
<svg viewBox="0 0 32 20"><path d="M0 10h26l-6-6 1.5-1.5L30 10l-8.5 7.5L20 16l6-6H0z"/></svg>
</div>
<div class="arch-box controller">
Controllers
<div class="arch-box-sub">Business Logic</div>
</div>
<div class="arch-arrow">
<svg viewBox="0 0 32 20"><path d="M0 10h26l-6-6 1.5-1.5L30 10l-8.5 7.5L20 16l6-6H0z"/></svg>
</div>
<div class="arch-box database">
MySQL 8.0
<div class="arch-box-sub">Database</div>
</div>
</div>
</div>
<div class="arch-routing">
<h4>Flusso di Routing</h4>
<div class="routing-flow">
<div class="routing-step">index.php</div>
<div class="routing-arrow">&rarr;</div>
<div class="routing-step">Router</div>
<div class="routing-arrow">&rarr;</div>
<div class="routing-step">Controller</div>
<div class="routing-arrow">&rarr;</div>
<div class="routing-step">Service</div>
<div class="routing-arrow">&rarr;</div>
<div class="routing-step">JSON Response</div>
</div>
</div>
</div>
</div>
</div>
<!-- ═══ 4. Struttura del Progetto ═══════════════════════ -->
<div class="arch-section">
<div class="card">
<div class="card-header">
<h3><span class="section-number">4</span> Struttura del Progetto</h3>
</div>
<div class="card-body">
<div class="dir-tree"><span class="dir-name">nis2-agile/</span>
<span class="dir-name">├── application/</span>
<span class="dir-name">│ ├── controllers/</span> <span class="dir-comment"># Controller PHP (BaseController, Auth, Assessment, etc.)</span>
<span class="dir-name">│ ├── services/</span> <span class="dir-comment"># Servizi business logic (VisuraService, AI)</span>
<span class="dir-name">│ ├── models/</span> <span class="dir-comment"># Modelli dati</span>
│ └── <span class="dir-name">config/</span> <span class="dir-comment"># Configurazione e Database class</span>
<span class="dir-name">├── public/</span> <span class="dir-comment"># Web root (document root Nginx)</span>
│ ├── <span class="dir-file">index.php</span> <span class="dir-comment"># Front Controller + Router</span>
│ ├── <span class="dir-name">css/</span> <span class="dir-comment"># Foglio di stile principale</span>
│ ├── <span class="dir-name">js/</span> <span class="dir-comment"># API client, Common utilities, i18n, Help</span>
│ └── <span class="dir-file">*.html</span> <span class="dir-comment"># Pagine frontend (SPA-like)</span>
<span class="dir-name">├── docker/</span> <span class="dir-comment"># Docker Compose, Dockerfile, Nginx config</span>
└── <span class="dir-name">docs/</span>
├── <span class="dir-name">sql/</span> <span class="dir-comment"># Migrazioni database (001-004)</span>
└── <span class="dir-name">questionnaire/</span> <span class="dir-comment"># Questionario NIS2 (JSON)</span></div>
</div>
</div>
</div>
<!-- ═══ 5. Modello Dati ═════════════════════════════════ -->
<div class="arch-section">
<div class="card">
<div class="card-header">
<h3><span class="section-number">5</span> Modello Dati</h3>
</div>
<div class="card-body">
<div class="data-model">
<div class="data-model-grid">
<!-- Core relationship: users <-> user_organizations <-> organizations -->
<div class="data-model-row">
<div class="data-entity primary-entity">
<h5>users</h5>
<p>Utenti piattaforma</p>
</div>
<div class="data-rel">&harr;</div>
<div class="data-entity">
<h5>user_organizations</h5>
<p>Associazione N:M</p>
</div>
<div class="data-rel">&harr;</div>
<div class="data-entity primary-entity">
<h5>organizations</h5>
<p>Organizzazioni tenant</p>
</div>
</div>
<!-- Arrow down from organizations -->
<div class="data-arrow-down">
<svg width="24" height="32" viewBox="0 0 24 32" fill="var(--gray-400)">
<path d="M12 0v26l-6-6-1.5 1.5L12 30l7.5-8.5L18 20l-6 6V0z"/>
</svg>
</div>
<!-- Children tables -->
<div class="data-children">
<div class="data-child">assessments</div>
<div class="data-child">assessment_answers</div>
<div class="data-child">risks</div>
<div class="data-child">incidents</div>
<div class="data-child">policies</div>
<div class="data-child">suppliers</div>
<div class="data-child">training_courses</div>
<div class="data-child">assets</div>
<div class="data-child">compliance_controls</div>
<div class="data-child">non_conformities</div>
<div class="data-child">capa_actions</div>
</div>
</div>
</div>
<div class="data-note">
<strong>Multi-tenancy:</strong> Tutte le tabelle operative contengono la chiave esterna
<code>organization_id</code> che garantisce l'isolamento completo dei dati tra le diverse
organizzazioni all'interno della stessa istanza.
</div>
</div>
</div>
</div>
<!-- ═══ 6. Sicurezza ════════════════════════════════════ -->
<div class="arch-section">
<div class="card">
<div class="card-header">
<h3><span class="section-number">6</span> Sicurezza</h3>
</div>
<div class="card-body">
<div class="security-grid">
<div class="security-item">
<div class="security-icon">
<svg viewBox="0 0 20 20"><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>
</div>
<div>
<h4>Autenticazione JWT</h4>
<p>Token di accesso HS256 (2h) con refresh token (7d) per sessioni sicure e scalabili.</p>
</div>
</div>
<div class="security-item">
<div class="security-icon">
<svg viewBox="0 0 20 20"><path fill-rule="evenodd" d="M4.083 9h1.946c.089-1.546.383-2.97.837-4.118A6.004 6.004 0 004.083 9zM10 2a8 8 0 100 16 8 8 0 000-16zm0 2c-.076 0-.232.032-.465.262-.238.234-.497.623-.737 1.182-.389.907-.673 2.142-.766 3.556h3.936c-.093-1.414-.377-2.649-.766-3.556-.24-.56-.5-.948-.737-1.182C10.232 4.032 10.076 4 10 4zm3.971 5c-.089-1.546-.383-2.97-.837-4.118A6.004 6.004 0 0115.917 9h-1.946zm-2.003 2H8.032c.093 1.414.377 2.649.766 3.556.24.56.5.948.737 1.182.233.23.389.262.465.262.076 0 .232-.032.465-.262.238-.234.497-.623.737-1.182.389-.907.673-2.142.766-3.556zm1.166 4.118c.454-1.147.748-2.572.837-4.118h1.946a6.004 6.004 0 01-2.783 4.118zm-6.268 0C6.412 13.97 6.118 12.546 6.03 11H4.083a6.004 6.004 0 002.783 4.118z" clip-rule="evenodd"/></svg>
</div>
<div>
<h4>Configurazione CORS</h4>
<p>Header CORS configurati per controllare le origini autorizzate delle richieste cross-origin.</p>
</div>
</div>
<div class="security-item">
<div class="security-icon">
<svg viewBox="0 0 20 20"><path fill-rule="evenodd" d="M2.166 4.999A11.954 11.954 0 0010 1.944 11.954 11.954 0 0017.834 5c.11.65.166 1.32.166 2.001 0 5.225-3.34 9.67-8 11.317C5.34 16.67 2 12.225 2 7c0-.682.057-1.35.166-2.001zm11.541 3.708a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/></svg>
</div>
<div>
<h4>SQL Injection Prevention</h4>
<p>Validazione input e prevenzione SQL injection tramite prepared statements PDO su tutte le query.</p>
</div>
</div>
<div class="security-item">
<div class="security-icon">
<svg viewBox="0 0 20 20"><path fill-rule="evenodd" d="M12.316 3.051a1 1 0 01.633 1.265l-4 12a1 1 0 11-1.898-.632l4-12a1 1 0 011.265-.633zM5.707 6.293a1 1 0 010 1.414L3.414 10l2.293 2.293a1 1 0 11-1.414 1.414l-3-3a1 1 0 010-1.414l3-3a1 1 0 011.414 0zm8.586 0a1 1 0 011.414 0l3 3a1 1 0 010 1.414l-3 3a1 1 0 11-1.414-1.414L16.586 10l-2.293-2.293a1 1 0 010-1.414z" clip-rule="evenodd"/></svg>
</div>
<div>
<h4>Prevenzione XSS</h4>
<p>Escape sistematico di tutti gli output HTML tramite funzione <code>escapeHtml()</code> lato client.</p>
</div>
</div>
<div class="security-item">
<div class="security-icon">
<svg viewBox="0 0 20 20"><path d="M9 6a3 3 0 11-6 0 3 3 0 016 0zM17 6a3 3 0 11-6 0 3 3 0 016 0zM12.93 17c.046-.327.07-.66.07-1a6.97 6.97 0 00-1.5-4.33A5 5 0 0119 16v1h-6.07zM6 11a5 5 0 015 5v1H1v-1a5 5 0 015-5z"/></svg>
</div>
<div>
<h4>RBAC (Role-Based Access Control)</h4>
<p>Sei ruoli con permessi granulari per il controllo degli accessi alle risorse.</p>
<div class="role-list">
<span class="role-badge sa">super_admin</span>
<span class="role-badge oa">org_admin</span>
<span class="role-badge cm">compliance_manager</span>
<span class="role-badge bm">board_member</span>
<span class="role-badge au">auditor</span>
<span class="role-badge em">employee</span>
</div>
</div>
</div>
<div class="security-item">
<div class="security-icon">
<svg viewBox="0 0 20 20"><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>
</div>
<div>
<h4>Audit Logging</h4>
<p>Registrazione completa di tutte le operazioni sensibili con tracciamento utente, azione e timestamp.</p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- ═══ 7. Moduli Funzionali ════════════════════════════ -->
<div class="arch-section">
<div class="card">
<div class="card-header">
<h3><span class="section-number">7</span> Moduli Funzionali</h3>
</div>
<div class="card-body">
<div class="module-grid">
<div class="module-card">
<div class="module-ref">Art. 21 - Direttiva NIS2</div>
<h4>Gap Analysis</h4>
<p>Assessment di conformita' NIS2 su 10 categorie con punteggio automatico e analisi AI delle lacune.</p>
</div>
<div class="module-card">
<div class="module-ref">Art. 21.2.a</div>
<h4>Gestione Rischi</h4>
<p>Matrice del rischio, piani di trattamento, monitoraggio continuo e classificazione per impatto e probabilita'.</p>
</div>
<div class="module-card">
<div class="module-ref">Art. 23</div>
<h4>Gestione Incidenti</h4>
<p>Timeline di notifica NIS2 completa: pre-allarme 24h, notifica 72h, relazione finale 30 giorni.</p>
</div>
<div class="module-card">
<div class="module-ref">Art. 21</div>
<h4>Policy Management</h4>
<p>Generazione assistita da AI di policy di sicurezza con workflow di approvazione e versionamento.</p>
</div>
<div class="module-card">
<div class="module-ref">Art. 21.2.d</div>
<h4>Supply Chain</h4>
<p>Valutazione del rischio dei fornitori, monitoraggio della catena di approvvigionamento e classificazione.</p>
</div>
<div class="module-card">
<div class="module-ref">Art. 20.2</div>
<h4>Formazione</h4>
<p>Tracciamento della formazione obbligatoria per il management, corsi, completamento e scadenze.</p>
</div>
<div class="module-card">
<div class="module-ref">Art. 21.2.i</div>
<h4>Asset Management</h4>
<p>Inventario degli asset IT/OT, mappatura delle dipendenze e classificazione per criticita'.</p>
</div>
<div class="module-card">
<div class="module-ref">NCR / CAPA</div>
<h4>Non Conformita' e Azioni Correttive</h4>
<p>Tracciamento delle non conformita' con azioni correttive e preventive strutturate.</p>
</div>
<div class="module-card">
<div class="module-ref">Compliance</div>
<h4>Audit e Report</h4>
<p>Generazione di evidenze di conformita', report per l'autorita' competente e dashboard di monitoraggio.</p>
</div>
</div>
</div>
</div>
</div>
<!-- ═══ 8. Integrazione Esterna ═════════════════════════ -->
<div class="arch-section">
<div class="card">
<div class="card-header">
<h3><span class="section-number">8</span> Integrazione Esterna</h3>
</div>
<div class="card-body">
<div class="integration-list">
<div class="integration-item">
<div class="integration-icon ext">SG</div>
<div>
<h4>SistemiG.agile</h4>
<p>Predisposizione per la sincronizzazione delle non conformita' (NCR) tramite webhook e API REST.
Permette l'integrazione bidirezionale con il sistema di gestione qualita' SistemiG.agile per una
governance unificata.</p>
</div>
</div>
<div class="integration-item">
<div class="integration-icon visura">VC</div>
<div>
<h4>Visura Camerale</h4>
<p>Analisi automatizzata delle visure camerali tramite upload PDF. Estrazione intelligente dei dati
aziendali (ragione sociale, codice ATECO, sede, organi di amministrazione) mediante AI per la
classificazione NIS2 dell'organizzazione.</p>
</div>
</div>
<div class="integration-item">
<div class="integration-icon claude">AI</div>
<div>
<h4>Claude AI (Anthropic)</h4>
<p>Integrazione con l'API Claude di Anthropic per la generazione automatica di policy di sicurezza
personalizzate, l'analisi dei gap di conformita' e raccomandazioni contestuali basate sul profilo
dell'organizzazione.</p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- ═══ 9. Deploy ═══════════════════════════════════════ -->
<div class="arch-section">
<div class="card">
<div class="card-header">
<h3><span class="section-number">9</span> Deploy</h3>
</div>
<div class="card-body">
<div class="deploy-grid">
<div class="deploy-item">
<div class="deploy-icon">
<svg viewBox="0 0 20 20"><path fill-rule="evenodd" d="M2 5a2 2 0 012-2h12a2 2 0 012 2v2a2 2 0 01-2 2H4a2 2 0 01-2-2V5zm14 1a1 1 0 11-2 0 1 1 0 012 0zM2 13a2 2 0 012-2h12a2 2 0 012 2v2a2 2 0 01-2 2H4a2 2 0 01-2-2v-2zm14 1a1 1 0 11-2 0 1 1 0 012 0z" clip-rule="evenodd"/></svg>
</div>
<div>
<h4>Docker Compose</h4>
<p>Orchestrazione con 3 container: app (PHP-FPM), web (Nginx), db (MySQL).</p>
</div>
</div>
<div class="deploy-item">
<div class="deploy-icon">
<svg viewBox="0 0 20 20"><path fill-rule="evenodd" d="M5.05 4.05a7 7 0 119.9 9.9L10 18.9l-4.95-4.95a7 7 0 010-9.9zM10 11a2 2 0 100-4 2 2 0 000 4z" clip-rule="evenodd"/></svg>
</div>
<div>
<h4>Produzione</h4>
<p>Hosting su Hetzner Cloud con infrastruttura europea per conformita' GDPR.</p>
</div>
</div>
<div class="deploy-item">
<div class="deploy-icon">
<svg viewBox="0 0 20 20"><path fill-rule="evenodd" d="M12.316 3.051a1 1 0 01.633 1.265l-4 12a1 1 0 11-1.898-.632l4-12a1 1 0 011.265-.633zM5.707 6.293a1 1 0 010 1.414L3.414 10l2.293 2.293a1 1 0 11-1.414 1.414l-3-3a1 1 0 010-1.414l3-3a1 1 0 011.414 0zm8.586 0a1 1 0 011.414 0l3 3a1 1 0 010 1.414l-3 3a1 1 0 11-1.414-1.414L16.586 10l-2.293-2.293a1 1 0 010-1.414z" clip-rule="evenodd"/></svg>
</div>
<div>
<h4>Git Deployment</h4>
<p>Deploy basato su Git tramite Gitea con workflow di build e rilascio.</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
<script src="js/api.js"></script>
<script src="js/common.js"></script>
<script src="js/i18n.js"></script>
<script src="js/help.js"></script>
<script>
if (!checkAuth()) throw new Error('Not authenticated');
loadSidebar();
I18n.init();
</script>
</body>
</html>