-- ============================================================ -- NIS2 Agile - Migration 007: Services API & Webhooks -- Tabelle per API Keys esterne, Webhook subscriptions e delivery log -- ============================================================ -- ── API KEYS ───────────────────────────────────────────────── -- Chiavi API per accesso esterno ai servizi NIS2 -- Separate dai JWT sessione, con scopo e permessi specifici CREATE TABLE IF NOT EXISTS api_keys ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, organization_id INT UNSIGNED NOT NULL, created_by INT UNSIGNED NOT NULL, name VARCHAR(100) NOT NULL, -- Nome descrittivo es. "SIEM Integration" key_prefix VARCHAR(12) NOT NULL, -- Prefisso visibile es. "nis2_abc123" key_hash VARCHAR(64) NOT NULL, -- SHA-256 della chiave completa scopes JSON NOT NULL, -- Array di scope: ["read:risks","read:incidents","read:all"] last_used_at TIMESTAMP NULL DEFAULT NULL, expires_at TIMESTAMP NULL DEFAULT NULL, is_active TINYINT(1) NOT NULL DEFAULT 1, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_org (organization_id), INDEX idx_key_hash (key_hash), INDEX idx_active (is_active) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- ── WEBHOOK SUBSCRIPTIONS ──────────────────────────────────── -- Sottoscrizioni webhook outbound: quando avvengono eventi NIS2, -- NIS2 notifica sistemi esterni (SIEM, GRC, 231 Agile, SustainAI) CREATE TABLE IF NOT EXISTS webhook_subscriptions ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, organization_id INT UNSIGNED NOT NULL, created_by INT UNSIGNED NOT NULL, name VARCHAR(100) NOT NULL, -- Es. "231 Agile Notify" url VARCHAR(512) NOT NULL, -- URL destinazione POST secret VARCHAR(64) NOT NULL, -- Usato per HMAC-SHA256 firma events JSON NOT NULL, -- Array eventi: ["incident.created","risk.high_created"] is_active TINYINT(1) NOT NULL DEFAULT 1, last_triggered_at TIMESTAMP NULL DEFAULT NULL, failure_count INT UNSIGNED DEFAULT 0, -- Errori consecutivi (auto-pause se >10) created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_org (organization_id), INDEX idx_active (is_active) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- ── WEBHOOK DELIVERIES ─────────────────────────────────────── -- Log di ogni tentativo di consegna webhook (audit + retry) CREATE TABLE IF NOT EXISTS webhook_deliveries ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, subscription_id INT UNSIGNED NOT NULL, organization_id INT UNSIGNED NOT NULL, event_type VARCHAR(60) NOT NULL, -- Es. "incident.created" event_id VARCHAR(36) NOT NULL, -- UUID dell'evento payload MEDIUMTEXT NOT NULL, -- JSON payload inviato status ENUM('pending','delivered','failed','retrying') DEFAULT 'pending', http_status SMALLINT UNSIGNED NULL, -- Codice HTTP risposta response_body TEXT NULL, -- Risposta del server (max 2KB) attempt TINYINT UNSIGNED DEFAULT 1, -- Tentativo corrente (max 3) next_retry_at TIMESTAMP NULL DEFAULT NULL, -- Prossimo retry schedulato delivered_at TIMESTAMP NULL DEFAULT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_subscription (subscription_id), INDEX idx_org (organization_id), INDEX idx_status (status), INDEX idx_event (event_type, event_id), INDEX idx_retry (status, next_retry_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- ── FOREIGN KEYS ───────────────────────────────────────────── ALTER TABLE api_keys ADD CONSTRAINT fk_apikeys_org FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE, ADD CONSTRAINT fk_apikeys_user FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE CASCADE; ALTER TABLE webhook_subscriptions ADD CONSTRAINT fk_webhooksub_org FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE, ADD CONSTRAINT fk_webhooksub_user FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE CASCADE; ALTER TABLE webhook_deliveries ADD CONSTRAINT fk_webhookdel_sub FOREIGN KEY (subscription_id) REFERENCES webhook_subscriptions(id) ON DELETE CASCADE;