Files
Benjamin Boenisch 504dd3591b feat: Add Academy, Whistleblower, Incidents, Vendor, DSB, SSO, Reporting, Multi-Tenant and Industry backends
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>
2026-02-13 21:11:27 +01:00

194 lines
7.3 KiB
PL/PgSQL

-- ============================================================================
-- Migration 005: Roadmap Schema
-- Compliance Roadmap Management with Import Support
-- ============================================================================
-- Roadmaps table
CREATE TABLE IF NOT EXISTS roadmaps (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES compliance_tenants(id) ON DELETE CASCADE,
namespace_id UUID REFERENCES compliance_namespaces(id) ON DELETE SET NULL,
title VARCHAR(255) NOT NULL,
description TEXT,
version VARCHAR(50) DEFAULT '1.0',
-- Links to other entities
assessment_id UUID REFERENCES ucca_assessments(id) ON DELETE SET NULL,
portfolio_id UUID, -- Will reference portfolio table when created
-- Status tracking
status VARCHAR(50) DEFAULT 'draft', -- draft, active, completed, archived
total_items INT DEFAULT 0,
completed_items INT DEFAULT 0,
progress INT DEFAULT 0, -- Percentage 0-100
-- Timeline
start_date DATE,
target_date DATE,
-- Audit
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by UUID NOT NULL
);
-- Roadmap items table
CREATE TABLE IF NOT EXISTS roadmap_items (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
roadmap_id UUID NOT NULL REFERENCES roadmaps(id) ON DELETE CASCADE,
-- Core fields
title VARCHAR(500) NOT NULL,
description TEXT,
category VARCHAR(50) DEFAULT 'TECHNICAL', -- TECHNICAL, ORGANIZATIONAL, PROCESSUAL, DOCUMENTATION, TRAINING
priority VARCHAR(50) DEFAULT 'MEDIUM', -- CRITICAL, HIGH, MEDIUM, LOW
status VARCHAR(50) DEFAULT 'PLANNED', -- PLANNED, IN_PROGRESS, BLOCKED, COMPLETED, DEFERRED
-- Compliance mapping
control_id VARCHAR(100), -- e.g., "CTRL-AVV"
regulation_ref VARCHAR(255), -- e.g., "DSGVO Art. 28"
gap_id VARCHAR(100), -- e.g., "GAP_AVV_MISSING"
-- Effort estimation
effort_days INT,
effort_hours INT,
estimated_cost INT, -- EUR
-- Assignment
assignee_id UUID,
assignee_name VARCHAR(255),
department VARCHAR(255),
-- Timeline
planned_start DATE,
planned_end DATE,
actual_start DATE,
actual_end DATE,
-- Dependencies (JSONB arrays of UUIDs)
depends_on JSONB DEFAULT '[]',
blocked_by JSONB DEFAULT '[]',
-- Evidence
evidence_required JSONB DEFAULT '[]', -- Array of strings
evidence_provided JSONB DEFAULT '[]', -- Array of strings
-- Notes
notes TEXT,
risk_notes TEXT,
-- Import metadata
source_row INT,
source_file VARCHAR(500),
-- Ordering
sort_order INT DEFAULT 0,
-- Audit
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Import jobs table
CREATE TABLE IF NOT EXISTS roadmap_import_jobs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES compliance_tenants(id) ON DELETE CASCADE,
roadmap_id UUID REFERENCES roadmaps(id) ON DELETE SET NULL,
-- File info
filename VARCHAR(500) NOT NULL,
format VARCHAR(50) NOT NULL, -- EXCEL, CSV, JSON
file_size BIGINT,
content_type VARCHAR(255),
-- Status
status VARCHAR(50) DEFAULT 'pending', -- pending, parsing, parsed, validating, completed, failed
error_message TEXT,
-- Parsing results
total_rows INT DEFAULT 0,
valid_rows INT DEFAULT 0,
invalid_rows INT DEFAULT 0,
imported_items INT DEFAULT 0,
-- Parsed items (before confirmation)
parsed_items JSONB DEFAULT '[]',
-- Audit
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
completed_at TIMESTAMPTZ,
created_by UUID NOT NULL
);
-- ============================================================================
-- Indexes
-- ============================================================================
-- Roadmaps indexes
CREATE INDEX IF NOT EXISTS idx_roadmaps_tenant ON roadmaps(tenant_id);
CREATE INDEX IF NOT EXISTS idx_roadmaps_status ON roadmaps(tenant_id, status);
CREATE INDEX IF NOT EXISTS idx_roadmaps_assessment ON roadmaps(assessment_id) WHERE assessment_id IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_roadmaps_portfolio ON roadmaps(portfolio_id) WHERE portfolio_id IS NOT NULL;
-- Roadmap items indexes
CREATE INDEX IF NOT EXISTS idx_roadmap_items_roadmap ON roadmap_items(roadmap_id);
CREATE INDEX IF NOT EXISTS idx_roadmap_items_status ON roadmap_items(roadmap_id, status);
CREATE INDEX IF NOT EXISTS idx_roadmap_items_priority ON roadmap_items(roadmap_id, priority);
CREATE INDEX IF NOT EXISTS idx_roadmap_items_category ON roadmap_items(roadmap_id, category);
CREATE INDEX IF NOT EXISTS idx_roadmap_items_assignee ON roadmap_items(assignee_id) WHERE assignee_id IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_roadmap_items_control ON roadmap_items(control_id) WHERE control_id IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_roadmap_items_deadline ON roadmap_items(planned_end) WHERE planned_end IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_roadmap_items_sort ON roadmap_items(roadmap_id, sort_order);
-- Import jobs indexes
CREATE INDEX IF NOT EXISTS idx_import_jobs_tenant ON roadmap_import_jobs(tenant_id);
CREATE INDEX IF NOT EXISTS idx_import_jobs_status ON roadmap_import_jobs(tenant_id, status);
CREATE INDEX IF NOT EXISTS idx_import_jobs_roadmap ON roadmap_import_jobs(roadmap_id) WHERE roadmap_id IS NOT NULL;
-- ============================================================================
-- Triggers for updated_at
-- ============================================================================
-- Trigger function (reuse if exists)
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ language 'plpgsql';
-- Roadmaps trigger
DROP TRIGGER IF EXISTS update_roadmaps_updated_at ON roadmaps;
CREATE TRIGGER update_roadmaps_updated_at
BEFORE UPDATE ON roadmaps
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
-- Roadmap items trigger
DROP TRIGGER IF EXISTS update_roadmap_items_updated_at ON roadmap_items;
CREATE TRIGGER update_roadmap_items_updated_at
BEFORE UPDATE ON roadmap_items
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
-- Import jobs trigger
DROP TRIGGER IF EXISTS update_roadmap_import_jobs_updated_at ON roadmap_import_jobs;
CREATE TRIGGER update_roadmap_import_jobs_updated_at
BEFORE UPDATE ON roadmap_import_jobs
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
-- ============================================================================
-- Comments
-- ============================================================================
COMMENT ON TABLE roadmaps IS 'Compliance implementation roadmaps';
COMMENT ON TABLE roadmap_items IS 'Individual items/tasks in a compliance roadmap';
COMMENT ON TABLE roadmap_import_jobs IS 'Track file imports for roadmap items';
COMMENT ON COLUMN roadmap_items.control_id IS 'Reference to controls catalog (e.g., CTRL-AVV)';
COMMENT ON COLUMN roadmap_items.regulation_ref IS 'Reference to regulation article (e.g., DSGVO Art. 28)';
COMMENT ON COLUMN roadmap_items.gap_id IS 'Reference to gap mapping (e.g., GAP_AVV_MISSING)';
COMMENT ON COLUMN roadmap_items.depends_on IS 'Array of item IDs this item depends on';
COMMENT ON COLUMN roadmap_items.blocked_by IS 'Array of item IDs currently blocking this item';