Files
Benjamin Admin 66a70ab31c feat(pipeline): G1 Decision Trace — compliance decision tracking
New table: decision_traces (status, reason, evidence, fix plan per control)
New API:
  POST/GET/PUT /v1/decision-traces (CRUD for decisions)
  GET /v1/decision-traces/stats (compliance dashboard)
  GET /v1/controls/{id}/full-trace (Regulation→Obligation→Control→Decision→Evidence)

454 tests pass, 0 regressions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-06 18:26:21 +02:00

59 lines
1.8 KiB
PL/PgSQL

-- Migration 006: Decision Traces (G1)
-- Schema: compliance
-- Run: ssh macmini "docker exec -i bp-core-postgres psql -U breakpilot -d breakpilot_db" < control-pipeline/migrations/006_decision_traces.sql
SET search_path TO compliance, public;
CREATE TABLE IF NOT EXISTS decision_traces (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
control_uuid UUID NOT NULL,
regulation_id VARCHAR(100),
obligation_id VARCHAR(100),
-- Decision
status VARCHAR(30) NOT NULL DEFAULT 'not_assessed'
CHECK (status IN ('not_assessed', 'compliant', 'partially_compliant',
'not_compliant', 'not_applicable', 'under_remediation')),
decision_reason TEXT,
decided_by VARCHAR(100),
decided_at TIMESTAMPTZ,
-- Fix/Remediation
fix_strategy TEXT,
fix_owner VARCHAR(100),
fix_target_date DATE,
fix_completed_date DATE,
-- Evidence
evidence_ids JSONB DEFAULT '[]',
confidence NUMERIC(3,2) DEFAULT 0.0,
-- Multi-tenant
tenant_id UUID,
project_id UUID,
metadata JSONB DEFAULT '{}',
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_dt_control ON decision_traces(control_uuid);
CREATE INDEX IF NOT EXISTS idx_dt_status ON decision_traces(status);
CREATE INDEX IF NOT EXISTS idx_dt_tenant ON decision_traces(tenant_id);
CREATE INDEX IF NOT EXISTS idx_dt_decided_at ON decision_traces(decided_at);
-- Updated-at trigger
CREATE OR REPLACE FUNCTION update_decision_traces_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS trg_decision_traces_updated_at ON decision_traces;
CREATE TRIGGER trg_decision_traces_updated_at
BEFORE UPDATE ON decision_traces
FOR EACH ROW
EXECUTE FUNCTION update_decision_traces_updated_at();