Wave 64-65 cleanup: Proto regeneration and build system updates from Tonic 0.12→0.14 upgrade Files updated: - Cargo.lock: Dependency resolution for Tonic 0.14.2 - All build.rs: Updated for tonic-prost-build - Proto files: Regenerated with tonic-prost 0.14 - Examples/tests: Updated for new gRPC API 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
319 lines
12 KiB
PL/PgSQL
319 lines
12 KiB
PL/PgSQL
-- 011_compliance_rules_dynamic.sql
|
|
-- Dynamic Compliance Rule Configuration with Hot-Reload Support
|
|
-- Implements database-backed rule configuration for ComplianceValidator
|
|
|
|
-- Enable required extensions
|
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
|
|
|
-- Compliance rule types enumeration
|
|
CREATE TYPE compliance_rule_type AS ENUM (
|
|
'POSITION_LIMIT',
|
|
'MARKET_ABUSE',
|
|
'CLIENT_SUITABILITY',
|
|
'BEST_EXECUTION',
|
|
'CONCENTRATION_RISK',
|
|
'LEVERAGE_LIMIT',
|
|
'CAPITAL_ADEQUACY',
|
|
'REGULATORY_REPORTING',
|
|
'CUSTOM'
|
|
);
|
|
|
|
-- Main compliance rules configuration table
|
|
CREATE TABLE compliance_rules (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
rule_id VARCHAR(100) UNIQUE NOT NULL,
|
|
name VARCHAR(255) NOT NULL,
|
|
description TEXT NOT NULL,
|
|
rule_type compliance_rule_type NOT NULL,
|
|
|
|
-- Rule activation and versioning
|
|
active BOOLEAN NOT NULL DEFAULT true,
|
|
version INTEGER NOT NULL DEFAULT 1,
|
|
|
|
-- Severity and priority
|
|
severity VARCHAR(20) NOT NULL CHECK (severity IN ('Info', 'Low', 'Medium', 'High', 'Critical')),
|
|
priority INTEGER NOT NULL DEFAULT 50, -- 0-100 scale
|
|
|
|
-- Flexible rule parameters as JSONB
|
|
-- Examples:
|
|
-- Position limit: {"instrument_id": "BTC-USD", "max_position": 1000000, "max_daily_turnover": 5000000}
|
|
-- Market abuse: {"threshold": 1000000, "window_seconds": 300, "check_volume_spike": true}
|
|
-- Client suitability: {"min_net_worth": 100000, "accredited_only": true}
|
|
parameters JSONB NOT NULL DEFAULT '{}',
|
|
|
|
-- Regulatory framework references
|
|
regulatory_framework VARCHAR(50), -- MiFID II, Basel III, Dodd-Frank, etc.
|
|
regulatory_reference TEXT, -- Specific article/section reference
|
|
|
|
-- Temporal validity
|
|
effective_date TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
expiry_date TIMESTAMP WITH TIME ZONE,
|
|
|
|
-- Audit trail
|
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
created_by UUID,
|
|
updated_by UUID,
|
|
|
|
-- Additional metadata
|
|
metadata JSONB DEFAULT '{}',
|
|
|
|
CONSTRAINT valid_priority CHECK (priority >= 0 AND priority <= 100)
|
|
);
|
|
|
|
-- Compliance rule version history for audit trail
|
|
CREATE TABLE compliance_rule_versions (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
rule_id VARCHAR(100) NOT NULL,
|
|
version INTEGER NOT NULL,
|
|
|
|
-- Snapshot of rule at this version
|
|
name VARCHAR(255) NOT NULL,
|
|
description TEXT NOT NULL,
|
|
rule_type compliance_rule_type NOT NULL,
|
|
active BOOLEAN NOT NULL,
|
|
severity VARCHAR(20) NOT NULL,
|
|
priority INTEGER NOT NULL,
|
|
parameters JSONB NOT NULL,
|
|
regulatory_framework VARCHAR(50),
|
|
regulatory_reference TEXT,
|
|
|
|
-- Version metadata
|
|
change_reason TEXT,
|
|
changed_by UUID,
|
|
changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
|
|
-- Link to current rule
|
|
current_rule_id UUID REFERENCES compliance_rules(id) ON DELETE CASCADE,
|
|
|
|
UNIQUE(rule_id, version)
|
|
);
|
|
|
|
-- Compliance rule execution audit (tracks rule evaluations)
|
|
CREATE TABLE compliance_rule_executions (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
rule_id VARCHAR(100) NOT NULL,
|
|
|
|
-- Execution context
|
|
order_id VARCHAR(100),
|
|
instrument_id VARCHAR(50),
|
|
portfolio_id VARCHAR(100),
|
|
client_id VARCHAR(100),
|
|
|
|
-- Execution result
|
|
result VARCHAR(20) NOT NULL CHECK (result IN ('PASS', 'WARN', 'FAIL', 'ERROR')),
|
|
violation_detected BOOLEAN NOT NULL DEFAULT false,
|
|
warning_generated BOOLEAN NOT NULL DEFAULT false,
|
|
|
|
-- Evaluation details
|
|
evaluated_value JSONB, -- The values that were evaluated
|
|
threshold_value JSONB, -- The threshold that was checked against
|
|
breach_amount DECIMAL(20, 8),
|
|
|
|
-- Timing
|
|
execution_timestamp TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
execution_duration_ms INTEGER,
|
|
|
|
-- Additional context
|
|
details JSONB DEFAULT '{}'
|
|
);
|
|
|
|
-- Indexes for performance
|
|
CREATE INDEX idx_compliance_rules_active ON compliance_rules(active, rule_type);
|
|
CREATE INDEX idx_compliance_rules_type ON compliance_rules(rule_type);
|
|
CREATE INDEX idx_compliance_rules_effective ON compliance_rules(effective_date, expiry_date)
|
|
WHERE active = true;
|
|
CREATE INDEX idx_compliance_rules_framework ON compliance_rules(regulatory_framework);
|
|
|
|
CREATE INDEX idx_compliance_rule_versions_rule ON compliance_rule_versions(rule_id, version DESC);
|
|
CREATE INDEX idx_compliance_rule_versions_changed ON compliance_rule_versions(changed_at DESC);
|
|
|
|
CREATE INDEX idx_compliance_rule_executions_rule ON compliance_rule_executions(rule_id, execution_timestamp DESC);
|
|
CREATE INDEX idx_compliance_rule_executions_result ON compliance_rule_executions(result, execution_timestamp DESC);
|
|
CREATE INDEX idx_compliance_rule_executions_instrument ON compliance_rule_executions(instrument_id, execution_timestamp DESC);
|
|
|
|
-- Function to archive rule version on update
|
|
CREATE OR REPLACE FUNCTION archive_compliance_rule_version()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
-- Only archive if this is an actual update (not insert)
|
|
IF TG_OP = 'UPDATE' THEN
|
|
INSERT INTO compliance_rule_versions (
|
|
rule_id, version, name, description, rule_type, active,
|
|
severity, priority, parameters, regulatory_framework,
|
|
regulatory_reference, change_reason, changed_by, current_rule_id
|
|
) VALUES (
|
|
OLD.rule_id, OLD.version, OLD.name, OLD.description, OLD.rule_type,
|
|
OLD.active, OLD.severity, OLD.priority, OLD.parameters,
|
|
OLD.regulatory_framework, OLD.regulatory_reference,
|
|
COALESCE(NEW.metadata->>'change_reason', 'Rule updated'),
|
|
NEW.updated_by, NEW.id
|
|
);
|
|
|
|
-- Increment version on the new row
|
|
NEW.version := OLD.version + 1;
|
|
NEW.updated_at := NOW();
|
|
END IF;
|
|
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE TRIGGER compliance_rule_version_trigger
|
|
BEFORE UPDATE ON compliance_rules
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION archive_compliance_rule_version();
|
|
|
|
-- Function to notify on rule changes (for hot-reload)
|
|
CREATE OR REPLACE FUNCTION notify_compliance_rule_change()
|
|
RETURNS TRIGGER AS $$
|
|
DECLARE
|
|
notification_payload TEXT;
|
|
BEGIN
|
|
-- Build notification payload
|
|
notification_payload := json_build_object(
|
|
'operation', TG_OP,
|
|
'rule_id', COALESCE(NEW.rule_id, OLD.rule_id),
|
|
'rule_type', COALESCE(NEW.rule_type::text, OLD.rule_type::text),
|
|
'active', COALESCE(NEW.active, false),
|
|
'timestamp', extract(epoch from now())
|
|
)::text;
|
|
|
|
-- Send notification on compliance_rules_changed channel
|
|
PERFORM pg_notify('compliance_rules_changed', notification_payload);
|
|
|
|
RETURN COALESCE(NEW, OLD);
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE TRIGGER compliance_rule_change_notify_trigger
|
|
AFTER INSERT OR UPDATE OR DELETE ON compliance_rules
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION notify_compliance_rule_change();
|
|
|
|
-- Function to load active compliance rules
|
|
CREATE OR REPLACE FUNCTION get_active_compliance_rules()
|
|
RETURNS TABLE (
|
|
id UUID,
|
|
rule_id VARCHAR(100),
|
|
name VARCHAR(255),
|
|
description TEXT,
|
|
rule_type compliance_rule_type,
|
|
active BOOLEAN,
|
|
version INTEGER,
|
|
severity VARCHAR(20),
|
|
priority INTEGER,
|
|
parameters JSONB,
|
|
regulatory_framework VARCHAR(50),
|
|
regulatory_reference TEXT,
|
|
effective_date TIMESTAMP WITH TIME ZONE,
|
|
expiry_date TIMESTAMP WITH TIME ZONE
|
|
) AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT
|
|
cr.id, cr.rule_id, cr.name, cr.description, cr.rule_type,
|
|
cr.active, cr.version, cr.severity, cr.priority, cr.parameters,
|
|
cr.regulatory_framework, cr.regulatory_reference,
|
|
cr.effective_date, cr.expiry_date
|
|
FROM compliance_rules cr
|
|
WHERE cr.active = true
|
|
AND cr.effective_date <= NOW()
|
|
AND (cr.expiry_date IS NULL OR cr.expiry_date > NOW())
|
|
ORDER BY cr.priority DESC, cr.created_at ASC;
|
|
END;
|
|
$$ LANGUAGE plpgsql STABLE;
|
|
|
|
-- Function to get rules by type
|
|
CREATE OR REPLACE FUNCTION get_compliance_rules_by_type(p_rule_type compliance_rule_type)
|
|
RETURNS TABLE (
|
|
id UUID,
|
|
rule_id VARCHAR(100),
|
|
name VARCHAR(255),
|
|
parameters JSONB,
|
|
severity VARCHAR(20)
|
|
) AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT cr.id, cr.rule_id, cr.name, cr.parameters, cr.severity
|
|
FROM compliance_rules cr
|
|
WHERE cr.active = true
|
|
AND cr.rule_type = p_rule_type
|
|
AND cr.effective_date <= NOW()
|
|
AND (cr.expiry_date IS NULL OR cr.expiry_date > NOW())
|
|
ORDER BY cr.priority DESC;
|
|
END;
|
|
$$ LANGUAGE plpgsql STABLE;
|
|
|
|
-- Function to record rule execution
|
|
CREATE OR REPLACE FUNCTION record_compliance_rule_execution(
|
|
p_rule_id VARCHAR(100),
|
|
p_result VARCHAR(20),
|
|
p_violation_detected BOOLEAN DEFAULT false,
|
|
p_order_id VARCHAR(100) DEFAULT NULL,
|
|
p_instrument_id VARCHAR(50) DEFAULT NULL,
|
|
p_evaluated_value JSONB DEFAULT NULL,
|
|
p_threshold_value JSONB DEFAULT NULL,
|
|
p_breach_amount DECIMAL DEFAULT NULL
|
|
) RETURNS UUID AS $$
|
|
DECLARE
|
|
v_execution_id UUID;
|
|
BEGIN
|
|
v_execution_id := uuid_generate_v4();
|
|
|
|
INSERT INTO compliance_rule_executions (
|
|
id, rule_id, result, violation_detected,
|
|
order_id, instrument_id, evaluated_value,
|
|
threshold_value, breach_amount
|
|
) VALUES (
|
|
v_execution_id, p_rule_id, p_result, p_violation_detected,
|
|
p_order_id, p_instrument_id, p_evaluated_value,
|
|
p_threshold_value, p_breach_amount
|
|
);
|
|
|
|
RETURN v_execution_id;
|
|
END;
|
|
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
|
|
|
-- Insert default compliance rules
|
|
INSERT INTO compliance_rules (rule_id, name, description, rule_type, severity, priority, parameters, regulatory_framework, regulatory_reference) VALUES
|
|
('position_limit_default', 'Default Position Limit', 'Default maximum position size for instruments without specific limits', 'POSITION_LIMIT', 'High', 90,
|
|
'{"max_position_size": 1000000, "max_daily_turnover": 5000000, "concentration_limit": 0.1}'::jsonb,
|
|
'Basel III', 'Capital Requirements'),
|
|
|
|
('market_abuse_large_order', 'Large Order Market Abuse Detection', 'Detect potentially manipulative large orders', 'MARKET_ABUSE', 'Critical', 95,
|
|
'{"threshold": 1000000, "window_seconds": 300, "volume_spike_multiplier": 3.0}'::jsonb,
|
|
'MAR', 'Market Abuse Regulation Article 15'),
|
|
|
|
('client_suitability_conservative', 'Conservative Client Suitability', 'Suitability checks for conservative risk profile clients', 'CLIENT_SUITABILITY', 'Medium', 70,
|
|
'{"max_order_value": 10000, "max_leverage": 2.0, "complex_products_allowed": false}'::jsonb,
|
|
'MiFID II', 'Article 25 - Suitability Assessment'),
|
|
|
|
('best_execution_monitoring', 'Best Execution Monitoring', 'Monitor best execution requirements', 'BEST_EXECUTION', 'High', 85,
|
|
'{"min_execution_quality_score": 0.70, "max_price_improvement_deviation": 0.05, "venue_analysis_required": true}'::jsonb,
|
|
'MiFID II', 'Article 27 - Best Execution'),
|
|
|
|
('capital_adequacy_basel', 'Basel III Capital Adequacy', 'Monitor capital adequacy ratios', 'CAPITAL_ADEQUACY', 'Critical', 100,
|
|
'{"min_capital_adequacy_ratio": 0.08, "min_leverage_ratio": 0.03, "tier1_minimum": 0.06}'::jsonb,
|
|
'Basel III', 'Capital Adequacy Requirements'),
|
|
|
|
('concentration_risk_limit', 'Portfolio Concentration Limit', 'Maximum concentration in single instrument', 'CONCENTRATION_RISK', 'High', 80,
|
|
'{"max_concentration_pct": 0.15, "max_sector_concentration": 0.30}'::jsonb,
|
|
'Internal Risk', 'Risk Management Policy Section 4.2');
|
|
|
|
-- Grant permissions
|
|
GRANT SELECT ON compliance_rules TO authenticated_users;
|
|
GRANT SELECT ON compliance_rule_versions TO authenticated_users;
|
|
GRANT INSERT ON compliance_rule_executions TO authenticated_users;
|
|
GRANT EXECUTE ON FUNCTION get_active_compliance_rules TO authenticated_users;
|
|
GRANT EXECUTE ON FUNCTION get_compliance_rules_by_type TO authenticated_users;
|
|
GRANT EXECUTE ON FUNCTION record_compliance_rule_execution TO authenticated_users;
|
|
|
|
-- Comments for documentation
|
|
COMMENT ON TABLE compliance_rules IS 'Dynamic compliance rules with hot-reload support via PostgreSQL NOTIFY/LISTEN';
|
|
COMMENT ON TABLE compliance_rule_versions IS 'Version history for compliance rule changes - full audit trail';
|
|
COMMENT ON TABLE compliance_rule_executions IS 'Audit trail of compliance rule evaluations';
|
|
COMMENT ON FUNCTION notify_compliance_rule_change IS 'Triggers PostgreSQL NOTIFY on compliance rule changes for hot-reload';
|
|
COMMENT ON FUNCTION get_active_compliance_rules IS 'Returns all currently active compliance rules';
|
|
COMMENT ON FUNCTION get_compliance_rules_by_type IS 'Returns active rules filtered by type';
|