Files

188 lines
7.3 KiB
SQL
Raw Permalink Normal View History

-- +goose Up
-- Support auto series (agent 5/10): richer ticket detail, message auto metadata,
-- category taxonomy, activity timeline. Agent 3: add KB/templates in 032_* (do not
-- re-ALTER these ticket/message columns). Agent 4: reuse auto_reply_* + message
-- auto_* fields for AI outcomes — do not duplicate.
ALTER TABLE support_tickets DROP CONSTRAINT IF EXISTS support_tickets_category_check;
CREATE TABLE IF NOT EXISTS support_categories (
slug TEXT PRIMARY KEY,
label TEXT NOT NULL,
parent_slug TEXT REFERENCES support_categories(slug) ON DELETE SET NULL,
sort_order INT NOT NULL DEFAULT 0,
is_active BOOLEAN NOT NULL DEFAULT true,
match_intents TEXT[] NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
INSERT INTO support_categories (slug, label, sort_order, match_intents) VALUES
('billing', 'Billing', 10, ARRAY['billing','invoice','stripe']),
('billing_credits', 'Billing / credits', 11, ARRAY['credits','quota']),
('bug', 'Bug / error', 20, ARRAY['bug','error','crash']),
('account', 'Account / access', 30, ARRAY['login','password','access']),
('integrations', 'Integrations', 40, ARRAY['woocommerce','shopify','api']),
('processing', 'Processing / AI', 50, ARRAY['processing','ai','gpt']),
('export', 'Export / channels', 60, ARRAY['export','feed','channel']),
('other', 'Other', 100, ARRAY[]::TEXT[])
ON CONFLICT (slug) DO NOTHING;
ALTER TABLE support_tickets
ADD COLUMN IF NOT EXISTS tags TEXT[] NOT NULL DEFAULT '{}',
ADD COLUMN IF NOT EXISTS related_product_id UUID REFERENCES processed_products(id) ON DELETE SET NULL,
ADD COLUMN IF NOT EXISTS related_sku TEXT,
ADD COLUMN IF NOT EXISTS customer_context JSONB NOT NULL DEFAULT '{}'::jsonb,
ADD COLUMN IF NOT EXISTS auto_reply_disabled BOOLEAN NOT NULL DEFAULT false,
ADD COLUMN IF NOT EXISTS auto_reply_status TEXT NOT NULL DEFAULT 'none',
ADD COLUMN IF NOT EXISTS auto_reply_attempted_at TIMESTAMPTZ,
ADD COLUMN IF NOT EXISTS auto_reply_message_id UUID,
ADD COLUMN IF NOT EXISTS auto_reply_meta JSONB NOT NULL DEFAULT '{}'::jsonb;
-- +goose StatementBegin
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_constraint WHERE conname = 'support_tickets_auto_reply_message_id_fkey'
) THEN
ALTER TABLE support_tickets
ADD CONSTRAINT support_tickets_auto_reply_message_id_fkey
FOREIGN KEY (auto_reply_message_id) REFERENCES support_messages(id) ON DELETE SET NULL;
END IF;
END $$;
-- +goose StatementEnd
ALTER TABLE support_tickets DROP CONSTRAINT IF EXISTS support_tickets_auto_reply_status_check;
ALTER TABLE support_tickets
ADD CONSTRAINT support_tickets_auto_reply_status_check
CHECK (auto_reply_status IN (
'none', 'matched', 'ai_draft', 'ai_sent', 'skipped', 'failed', 'handed_off'
));
ALTER TABLE support_tickets DROP CONSTRAINT IF EXISTS support_tickets_related_sku_len_check;
ALTER TABLE support_tickets
ADD CONSTRAINT support_tickets_related_sku_len_check
CHECK (related_sku IS NULL OR char_length(related_sku) <= 128);
CREATE INDEX IF NOT EXISTS support_tickets_tags_gin_idx
ON support_tickets USING GIN (tags);
CREATE INDEX IF NOT EXISTS support_tickets_auto_reply_status_idx
ON support_tickets (auto_reply_status)
WHERE auto_reply_status <> 'none';
CREATE INDEX IF NOT EXISTS support_tickets_related_product_idx
ON support_tickets (related_product_id)
WHERE related_product_id IS NOT NULL;
ALTER TABLE support_messages
ADD COLUMN IF NOT EXISTS auto_source TEXT,
ADD COLUMN IF NOT EXISTS auto_confidence REAL,
ADD COLUMN IF NOT EXISTS auto_ref_type TEXT,
ADD COLUMN IF NOT EXISTS auto_ref_id UUID,
ADD COLUMN IF NOT EXISTS is_auto_reply BOOLEAN NOT NULL DEFAULT false;
ALTER TABLE support_messages DROP CONSTRAINT IF EXISTS support_messages_auto_source_check;
ALTER TABLE support_messages
ADD CONSTRAINT support_messages_auto_source_check
CHECK (auto_source IS NULL OR auto_source IN ('kb', 'template', 'ai'));
CREATE TABLE IF NOT EXISTS support_ticket_activity (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
ticket_id UUID NOT NULL REFERENCES support_tickets(id) ON DELETE CASCADE,
company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE,
kind TEXT NOT NULL,
actor_role TEXT NOT NULL DEFAULT 'system'
CHECK (actor_role IN ('user', 'agent', 'system', 'ai')),
actor_user_id UUID REFERENCES users(id) ON DELETE SET NULL,
message_id UUID REFERENCES support_messages(id) ON DELETE SET NULL,
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
CONSTRAINT support_ticket_activity_kind_check CHECK (kind IN (
'created',
'customer_message',
'agent_message',
'system_message',
'auto_reply',
'ai_draft',
'ai_sent',
'ai_failed',
'handed_off',
'claimed',
'released',
'status_changed',
'auto_disabled',
'auto_enabled',
'note'
))
);
CREATE INDEX IF NOT EXISTS support_ticket_activity_ticket_idx
ON support_ticket_activity (ticket_id, created_at ASC);
CREATE INDEX IF NOT EXISTS support_ticket_activity_company_idx
ON support_ticket_activity (company_id, created_at DESC);
ALTER TABLE support_notifications DROP CONSTRAINT IF EXISTS support_notifications_kind_check;
ALTER TABLE support_notifications
ADD CONSTRAINT support_notifications_kind_check
CHECK (kind IN (
'ticket_created',
'agent_reply',
'status_changed',
'user_reply',
'ticket_claimed',
'csat_requested',
'auto_reply'
));
-- +goose Down
ALTER TABLE support_notifications DROP CONSTRAINT IF EXISTS support_notifications_kind_check;
ALTER TABLE support_notifications
ADD CONSTRAINT support_notifications_kind_check
CHECK (kind IN (
'ticket_created',
'agent_reply',
'status_changed',
'user_reply',
'ticket_claimed',
'csat_requested'
));
DROP INDEX IF EXISTS support_ticket_activity_company_idx;
DROP INDEX IF EXISTS support_ticket_activity_ticket_idx;
DROP TABLE IF EXISTS support_ticket_activity;
ALTER TABLE support_messages DROP CONSTRAINT IF EXISTS support_messages_auto_source_check;
ALTER TABLE support_messages
DROP COLUMN IF EXISTS is_auto_reply,
DROP COLUMN IF EXISTS auto_ref_id,
DROP COLUMN IF EXISTS auto_ref_type,
DROP COLUMN IF EXISTS auto_confidence,
DROP COLUMN IF EXISTS auto_source;
DROP INDEX IF EXISTS support_tickets_related_product_idx;
DROP INDEX IF EXISTS support_tickets_auto_reply_status_idx;
DROP INDEX IF EXISTS support_tickets_tags_gin_idx;
ALTER TABLE support_tickets DROP CONSTRAINT IF EXISTS support_tickets_auto_reply_message_id_fkey;
ALTER TABLE support_tickets DROP CONSTRAINT IF EXISTS support_tickets_related_sku_len_check;
ALTER TABLE support_tickets DROP CONSTRAINT IF EXISTS support_tickets_auto_reply_status_check;
ALTER TABLE support_tickets
DROP COLUMN IF EXISTS auto_reply_meta,
DROP COLUMN IF EXISTS auto_reply_message_id,
DROP COLUMN IF EXISTS auto_reply_attempted_at,
DROP COLUMN IF EXISTS auto_reply_status,
DROP COLUMN IF EXISTS auto_reply_disabled,
DROP COLUMN IF EXISTS customer_context,
DROP COLUMN IF EXISTS related_sku,
DROP COLUMN IF EXISTS related_product_id,
DROP COLUMN IF EXISTS tags;
DROP TABLE IF EXISTS support_categories;
ALTER TABLE support_tickets DROP CONSTRAINT IF EXISTS support_tickets_category_check;
ALTER TABLE support_tickets
ADD CONSTRAINT support_tickets_category_check
CHECK (category IN ('billing', 'bug', 'account', 'other'));