Go handlers, models, stores and migrations for all SDK modules. Updates developer portal navigation and BYOEH page. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
112 lines
5.7 KiB
SQL
112 lines
5.7 KiB
SQL
-- ============================================================================
|
|
-- Migration 010: Incident/Breach Management Schema
|
|
-- DSGVO Art. 33 (Authority Notification) & Art. 34 (Data Subject Notification)
|
|
--
|
|
-- Art. 33 requires notification of the supervisory authority within 72 hours
|
|
-- of becoming aware of a personal data breach, unless the breach is unlikely
|
|
-- to result in a risk to the rights and freedoms of natural persons.
|
|
--
|
|
-- Art. 34 requires notification of affected data subjects without undue delay
|
|
-- when the breach is likely to result in a high risk to their rights and freedoms.
|
|
-- ============================================================================
|
|
|
|
-- Incident incidents table
|
|
CREATE TABLE IF NOT EXISTS incident_incidents (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES compliance_tenants(id) ON DELETE CASCADE,
|
|
|
|
-- Incident info
|
|
title VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
category VARCHAR(50) NOT NULL, -- data_breach, unauthorized_access, data_loss, system_compromise, phishing, ransomware, insider_threat, physical_breach, other
|
|
status VARCHAR(50) DEFAULT 'detected', -- detected, assessment, containment, notification_required, notification_sent, remediation, closed
|
|
severity VARCHAR(50) NOT NULL, -- critical, high, medium, low
|
|
|
|
-- Detection & reporting
|
|
detected_at TIMESTAMPTZ NOT NULL,
|
|
reported_by UUID NOT NULL,
|
|
|
|
-- Affected scope
|
|
affected_data_categories JSONB DEFAULT '[]', -- e.g. ["personal_data", "health_data", "financial_data"]
|
|
affected_data_subject_count INT DEFAULT 0,
|
|
affected_systems JSONB DEFAULT '[]', -- e.g. ["crm", "email_server", "database"]
|
|
|
|
-- Assessments & notifications (JSONB embedded objects)
|
|
risk_assessment JSONB, -- {likelihood, impact, risk_level, assessed_at, assessed_by, notes}
|
|
authority_notification JSONB, -- {status, deadline, submitted_at, authority_name, reference_number, contact_person, notes}
|
|
data_subject_notification JSONB, -- {required, status, sent_at, affected_count, notification_text, channel}
|
|
|
|
-- Resolution
|
|
root_cause TEXT,
|
|
lessons_learned TEXT,
|
|
|
|
-- Timeline (JSONB array of events)
|
|
timeline JSONB DEFAULT '[]', -- [{timestamp, action, user_id, details}, ...]
|
|
|
|
-- Audit
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
closed_at TIMESTAMPTZ
|
|
);
|
|
|
|
-- Incident measures table (corrective and preventive measures)
|
|
CREATE TABLE IF NOT EXISTS incident_measures (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
incident_id UUID NOT NULL REFERENCES incident_incidents(id) ON DELETE CASCADE,
|
|
|
|
-- Measure info
|
|
title VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
measure_type VARCHAR(50) NOT NULL, -- immediate, long_term
|
|
status VARCHAR(50) DEFAULT 'planned', -- planned, in_progress, completed
|
|
responsible VARCHAR(255),
|
|
due_date TIMESTAMPTZ,
|
|
completed_at TIMESTAMPTZ,
|
|
|
|
-- Audit
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
-- ============================================================================
|
|
-- Indexes
|
|
-- ============================================================================
|
|
|
|
-- Incident indexes
|
|
CREATE INDEX IF NOT EXISTS idx_incident_incidents_tenant ON incident_incidents(tenant_id);
|
|
CREATE INDEX IF NOT EXISTS idx_incident_incidents_status ON incident_incidents(tenant_id, status);
|
|
CREATE INDEX IF NOT EXISTS idx_incident_incidents_severity ON incident_incidents(tenant_id, severity);
|
|
CREATE INDEX IF NOT EXISTS idx_incident_incidents_detected_at ON incident_incidents(detected_at DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_incident_incidents_category ON incident_incidents(tenant_id, category);
|
|
|
|
-- Measure indexes
|
|
CREATE INDEX IF NOT EXISTS idx_incident_measures_incident ON incident_measures(incident_id);
|
|
CREATE INDEX IF NOT EXISTS idx_incident_measures_status ON incident_measures(incident_id, status);
|
|
|
|
-- ============================================================================
|
|
-- Triggers
|
|
-- ============================================================================
|
|
|
|
-- Reuse existing update_updated_at_column function
|
|
|
|
-- Incidents trigger
|
|
DROP TRIGGER IF EXISTS update_incident_incidents_updated_at ON incident_incidents;
|
|
CREATE TRIGGER update_incident_incidents_updated_at
|
|
BEFORE UPDATE ON incident_incidents
|
|
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
|
|
-- ============================================================================
|
|
-- Comments
|
|
-- ============================================================================
|
|
|
|
COMMENT ON TABLE incident_incidents IS 'Security and data breach incidents per DSGVO Art. 33/34';
|
|
COMMENT ON TABLE incident_measures IS 'Corrective and preventive measures for incidents';
|
|
|
|
COMMENT ON COLUMN incident_incidents.detected_at IS 'When the incident was first detected - starts the 72h Art. 33 notification clock';
|
|
COMMENT ON COLUMN incident_incidents.authority_notification IS 'JSONB: Supervisory authority notification tracking per DSGVO Art. 33 (72h deadline)';
|
|
COMMENT ON COLUMN incident_incidents.data_subject_notification IS 'JSONB: Data subject notification tracking per DSGVO Art. 34';
|
|
COMMENT ON COLUMN incident_incidents.risk_assessment IS 'JSONB: Risk assessment with likelihood, impact, and auto-calculated risk level';
|
|
COMMENT ON COLUMN incident_incidents.timeline IS 'JSONB array: Chronological record of all actions taken during incident response';
|
|
COMMENT ON COLUMN incident_incidents.affected_data_categories IS 'JSONB array: Categories of personal data affected (e.g. health, financial)';
|
|
COMMENT ON COLUMN incident_incidents.affected_systems IS 'JSONB array: Systems affected by the incident';
|
|
COMMENT ON COLUMN incident_measures.measure_type IS 'immediate = short-term containment, long_term = preventive/structural fix';
|