[FEAT] Services API: 5 nuovi endpoint lg231 (gap-analysis, measures, incidents, training, deadlines)

- GET /services/gap-analysis — gap per dominio NIS2 Art.21 con mapping MOG 231 pillars
- GET /services/measures — compliance_controls con mog_area e nis2_article derivati
- GET /services/incidents — incidenti con Art.23 CSIRT compliance per step (24h/72h/30d)
- GET /services/training — corsi + completamento board (Art.20 compliance flag)
- GET /services/deadlines — scadenze aggregate da 4 sorgenti con ?days= filter

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
DevEnv nis2-agile 2026-03-17 14:10:17 +01:00
parent cfaead6121
commit a122b49721

View File

@ -1626,7 +1626,7 @@ class ServicesController extends BaseController
$controls = Database::fetchAll(
"SELECT id, control_code, framework, title, status,
implementation_percentage, nis2_article, next_review_date, updated_at
implementation_percentage, next_review_date
FROM compliance_controls
WHERE {$where}
ORDER BY framework, control_code",
@ -1640,24 +1640,30 @@ class ServicesController extends BaseController
$s = $c['status'] ?? 'not_started';
if (isset($stats[$s])) $stats[$s]++;
$code = $c['control_code'] ?? '';
// Derive mog_area from control_code
$mogArea = 'other';
$code = $c['control_code'] ?? '';
foreach ($mogAreaMap as $prefix => $area) {
if (str_starts_with($code, $prefix)) { $mogArea = $area; break; }
}
if ($mogArea === 'other' && str_starts_with($code, 'ISO')) $mogArea = 'iso27001_control';
// Derive nis2_article from code (e.g. "NIS2-21.2.a" → "Art.21.2.a")
$nis2Article = null;
if (preg_match('/^NIS2-(\S+)/', $code, $m)) {
$nis2Article = 'Art.' . $m[1];
}
$measures[] = [
'id' => (int) $c['id'],
'code' => $code,
'framework' => $c['framework'],
'title' => $c['title'],
'status' => $s,
'id' => (int) $c['id'],
'code' => $code,
'framework' => $c['framework'],
'title' => $c['title'],
'status' => $s,
'implementation_percentage' => (int) ($c['implementation_percentage'] ?? 0),
'nis2_article' => $c['nis2_article'],
'mog_area' => $mogArea,
'next_review_date' => $c['next_review_date'],
'nis2_article' => $nis2Article,
'mog_area' => $mogArea,
'next_review_date' => $c['next_review_date'],
];
}