diff --git a/crates/db/migrations/20260815000001_create_ai_guard_violations.down.sql b/crates/db/migrations/20260815000001_create_ai_guard_violations.down.sql new file mode 100644 index 0000000..6320de0 --- /dev/null +++ b/crates/db/migrations/20260815000001_create_ai_guard_violations.down.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS ai_guard_violations; diff --git a/crates/db/migrations/20260815000001_create_ai_guard_violations.up.sql b/crates/db/migrations/20260815000001_create_ai_guard_violations.up.sql new file mode 100644 index 0000000..d5ffba7 --- /dev/null +++ b/crates/db/migrations/20260815000001_create_ai_guard_violations.up.sql @@ -0,0 +1,16 @@ +-- AI Guard Violations — records every message blocked by the content guard. +-- Migration: 20260815000001 + +CREATE TABLE IF NOT EXISTS ai_guard_violations ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + user_id UUID REFERENCES users(id) ON DELETE SET NULL, + message_excerpt TEXT NOT NULL, -- first 200 chars, never the full text + guard_type VARCHAR(40) NOT NULL, -- 'keyword' | 'length' | 'flood' | 'moderation_api' + reason TEXT NOT NULL, -- human-readable rejection reason + categories JSONB, -- OpenAI moderation categories (moderation_api only) + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +CREATE INDEX IF NOT EXISTS idx_ai_guard_violations_user_id ON ai_guard_violations(user_id); +CREATE INDEX IF NOT EXISTS idx_ai_guard_violations_created_at ON ai_guard_violations(created_at DESC); +CREATE INDEX IF NOT EXISTS idx_ai_guard_violations_guard_type ON ai_guard_violations(guard_type);