115 lines
4.7 KiB
SQL
115 lines
4.7 KiB
SQL
-- ==========================================
|
|
-- Migration 006: Unify Chats → Channels
|
|
-- ==========================================
|
|
-- "Everything is a channel." Merges the separate chats/channels
|
|
-- schema into a single unified channel model.
|
|
--
|
|
-- The old channels/channel_members/channel_messages tables (from 001)
|
|
-- were never populated — safe to drop and rebuild on top of chats.
|
|
-- ==========================================
|
|
|
|
-- ── 1. Drop unused legacy channel tables ────
|
|
-- These were placeholders from 001; no data, no handlers.
|
|
-- Order matters: drop dependents first.
|
|
|
|
-- Remove FK references in tool_usage_log before dropping
|
|
ALTER TABLE tool_usage_log DROP CONSTRAINT IF EXISTS tool_usage_log_channel_id_fkey;
|
|
ALTER TABLE tool_usage_log DROP COLUMN IF EXISTS channel_id;
|
|
|
|
DROP TABLE IF EXISTS channel_messages CASCADE;
|
|
DROP TABLE IF EXISTS channel_members CASCADE;
|
|
DROP TABLE IF EXISTS channels CASCADE;
|
|
|
|
-- Drop the old trigger (will re-create after rename)
|
|
DROP TRIGGER IF EXISTS channels_updated_at ON channels;
|
|
|
|
-- ── 2. Rename chats → channels ──────────────
|
|
|
|
ALTER TABLE chats RENAME TO channels;
|
|
ALTER TABLE chat_messages RENAME TO messages;
|
|
|
|
-- Rename columns to match new schema
|
|
ALTER TABLE messages RENAME COLUMN chat_id TO channel_id;
|
|
|
|
-- Rename indexes
|
|
ALTER INDEX IF EXISTS idx_chats_user RENAME TO idx_channels_user;
|
|
ALTER INDEX IF EXISTS idx_chats_updated RENAME TO idx_channels_updated;
|
|
ALTER INDEX IF EXISTS idx_chats_tags RENAME TO idx_channels_tags;
|
|
ALTER INDEX IF EXISTS idx_chat_messages_chat RENAME TO idx_messages_channel;
|
|
|
|
-- Rename constraints (PK and FK auto-renamed with table on some PG versions,
|
|
-- but let's be explicit for the FK)
|
|
-- Note: PG auto-renames PKs but not FKs or check constraints
|
|
|
|
-- Rename the updated_at trigger
|
|
DROP TRIGGER IF EXISTS chats_updated_at ON channels;
|
|
CREATE TRIGGER channels_updated_at BEFORE UPDATE ON channels
|
|
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
|
|
|
|
-- ── 3. Add channel type + description ───────
|
|
|
|
ALTER TABLE channels ADD COLUMN IF NOT EXISTS type VARCHAR(20) DEFAULT 'direct';
|
|
ALTER TABLE channels ADD COLUMN IF NOT EXISTS description TEXT;
|
|
|
|
COMMENT ON COLUMN channels.type IS 'direct=1:1 AI chat, group=multi-model, channel=named persistent';
|
|
|
|
-- Backfill: all existing rows are 1:1 AI chats
|
|
UPDATE channels SET type = 'direct' WHERE type IS NULL;
|
|
|
|
-- Index on type for filtered queries
|
|
CREATE INDEX IF NOT EXISTS idx_channels_type ON channels(type);
|
|
|
|
-- ── 4. Add message tree (parent_id) ─────────
|
|
|
|
ALTER TABLE messages ADD COLUMN IF NOT EXISTS parent_id UUID REFERENCES messages(id) ON DELETE SET NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_messages_parent ON messages(parent_id);
|
|
|
|
-- Backfill linear parent chains on existing messages.
|
|
-- Each message's parent is the previous message in the same channel (by created_at).
|
|
WITH ordered AS (
|
|
SELECT id, channel_id, created_at,
|
|
LAG(id) OVER (PARTITION BY channel_id ORDER BY created_at) AS prev_id
|
|
FROM messages
|
|
)
|
|
UPDATE messages m
|
|
SET parent_id = o.prev_id
|
|
FROM ordered o
|
|
WHERE m.id = o.id AND o.prev_id IS NOT NULL AND m.parent_id IS NULL;
|
|
|
|
-- ── 5. Add participant columns on messages ──
|
|
-- Decouples messages from user-only: AI models are participants too.
|
|
|
|
ALTER TABLE messages ADD COLUMN IF NOT EXISTS participant_type VARCHAR(10) DEFAULT 'user';
|
|
ALTER TABLE messages ADD COLUMN IF NOT EXISTS participant_id VARCHAR(255);
|
|
|
|
COMMENT ON COLUMN messages.participant_type IS 'user or model';
|
|
COMMENT ON COLUMN messages.participant_id IS 'user UUID or model identifier string';
|
|
|
|
-- Backfill: user messages get the channel owner's user_id;
|
|
-- assistant messages get the model name as participant_id.
|
|
UPDATE messages m
|
|
SET participant_type = CASE WHEN m.role = 'assistant' THEN 'model' ELSE 'user' END,
|
|
participant_id = CASE
|
|
WHEN m.role = 'assistant' THEN COALESCE(m.model, 'unknown')
|
|
ELSE (SELECT c.user_id::text FROM channels c WHERE c.id = m.channel_id)
|
|
END
|
|
WHERE m.participant_id IS NULL;
|
|
|
|
-- ── 6. Update model_routing_log FK ──────────
|
|
|
|
-- The FK column was named chat_id — rename it
|
|
ALTER TABLE model_routing_log RENAME COLUMN chat_id TO channel_id;
|
|
ALTER INDEX IF EXISTS idx_routing_log_chat RENAME TO idx_routing_log_channel;
|
|
|
|
-- message_id FK still valid (messages table was renamed, FK follows)
|
|
|
|
-- ── 7. Update tool_usage_log ────────────────
|
|
-- We already dropped the old channel_id column above.
|
|
-- Re-add it pointing to the unified channels table.
|
|
-- Also rename the old chat_id column.
|
|
|
|
ALTER TABLE tool_usage_log RENAME COLUMN chat_id TO channel_id;
|
|
-- The FK auto-follows the table rename, but let's be safe:
|
|
-- (chat_id FK pointed to chats(id), which is now channels(id) — PG handles this)
|