-- Contexta DB Migration -- Run this in your Supabase SQL Editor -- ── chatbots: new columns ───────────────────────────────────────────────────── ALTER TABLE chatbots ADD COLUMN IF NOT EXISTS logo_url TEXT; ALTER TABLE chatbots ADD COLUMN IF NOT EXISTS show_branding BOOLEAN DEFAULT TRUE; ALTER TABLE chatbots ADD COLUMN IF NOT EXISTS lead_capture_enabled BOOLEAN DEFAULT FALSE; ALTER TABLE chatbots ADD COLUMN IF NOT EXISTS lead_capture_fields JSONB DEFAULT '["email"]'; ALTER TABLE chatbots ADD COLUMN IF NOT EXISTS lead_capture_trigger VARCHAR(50) DEFAULT 'after_first_message'; ALTER TABLE chatbots ADD COLUMN IF NOT EXISTS handoff_enabled BOOLEAN DEFAULT FALSE; ALTER TABLE chatbots ADD COLUMN IF NOT EXISTS handoff_message TEXT DEFAULT 'I''ll connect you with our team. Please wait.'; ALTER TABLE chatbots ADD COLUMN IF NOT EXISTS handoff_email TEXT; ALTER TABLE chatbots ADD COLUMN IF NOT EXISTS handoff_keywords JSONB DEFAULT '["human", "agent", "speak to someone", "talk to a person", "real person"]'; -- ── messages: new columns ───────────────────────────────────────────────────── ALTER TABLE messages ADD COLUMN IF NOT EXISTS confidence_score DECIMAL(4,3) DEFAULT NULL; ALTER TABLE messages ADD COLUMN IF NOT EXISTS is_handoff BOOLEAN DEFAULT FALSE; -- ── leads table ─────────────────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS leads ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), chatbot_id UUID REFERENCES chatbots(id) ON DELETE CASCADE, conversation_id UUID REFERENCES conversations(id) ON DELETE SET NULL, email VARCHAR(255), name VARCHAR(255), phone VARCHAR(50), company VARCHAR(255), created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_leads_chatbot ON leads(chatbot_id); CREATE INDEX IF NOT EXISTS idx_leads_created ON leads(created_at DESC); ALTER TABLE leads ENABLE ROW LEVEL SECURITY; CREATE POLICY "leads_owner" ON leads FOR ALL USING ( chatbot_id IN ( SELECT c.id FROM chatbots c JOIN companies co ON c.company_id = co.id WHERE co.owner_id = auth.uid() ) ); -- ── url_sources table ───────────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS url_sources ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), chatbot_id UUID REFERENCES chatbots(id) ON DELETE CASCADE, url TEXT NOT NULL, status VARCHAR(50) DEFAULT 'pending', page_title TEXT, chunk_count INT DEFAULT 0, error_message TEXT, created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_url_sources_chatbot ON url_sources(chatbot_id); ALTER TABLE url_sources ENABLE ROW LEVEL SECURITY; CREATE POLICY "url_sources_owner" ON url_sources FOR ALL USING ( chatbot_id IN ( SELECT c.id FROM chatbots c JOIN companies co ON c.company_id = co.id WHERE co.owner_id = auth.uid() ) ); -- ── message_feedback table ──────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS message_feedback ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), message_id UUID REFERENCES messages(id) ON DELETE CASCADE, chatbot_id UUID REFERENCES chatbots(id) ON DELETE CASCADE, feedback VARCHAR(20) NOT NULL CHECK (feedback IN ('positive', 'negative')), created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_feedback_chatbot ON message_feedback(chatbot_id); ALTER TABLE message_feedback ENABLE ROW LEVEL SECURITY; CREATE POLICY "feedback_insert" ON message_feedback FOR INSERT WITH CHECK (true); CREATE POLICY "feedback_select_owner" ON message_feedback FOR SELECT USING ( chatbot_id IN ( SELECT c.id FROM chatbots c JOIN companies co ON c.company_id = co.id WHERE co.owner_id = auth.uid() ) ); -- ── Supabase Storage ────────────────────────────────────────────────────────── -- Create the 'logos' bucket manually in the Supabase dashboard: -- Storage → New bucket → Name: logos → Public: ON -- ── channel_connections table ───────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS channel_connections ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), chatbot_id UUID NOT NULL REFERENCES chatbots(id) ON DELETE CASCADE, channel VARCHAR(20) NOT NULL CHECK (channel IN ('telegram', 'whatsapp')), bot_token TEXT, bot_username TEXT, wa_keyword VARCHAR(50), is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(chatbot_id, channel) ); CREATE INDEX IF NOT EXISTS idx_channel_connections_chatbot ON channel_connections(chatbot_id); CREATE INDEX IF NOT EXISTS idx_channel_connections_wa_keyword ON channel_connections(wa_keyword) WHERE channel = 'whatsapp'; ALTER TABLE channel_connections ENABLE ROW LEVEL SECURITY; CREATE POLICY "channel_connections_owner" ON channel_connections FOR ALL USING ( chatbot_id IN ( SELECT c.id FROM chatbots c JOIN companies co ON c.company_id = co.id WHERE co.owner_id = auth.uid() ) ); -- ── channel_sessions table ──────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS channel_sessions ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), chatbot_id UUID NOT NULL REFERENCES chatbots(id) ON DELETE CASCADE, channel VARCHAR(20) NOT NULL, external_id TEXT NOT NULL, session_id TEXT NOT NULL, last_active TIMESTAMPTZ DEFAULT NOW(), created_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(channel, external_id) ); CREATE INDEX IF NOT EXISTS idx_channel_sessions_lookup ON channel_sessions(channel, external_id);