feat: add appointments, campaigns, admin, storage, tests and various updates

- Add new routers: admin, appointments, campaigns
- Add storage service and logging config
- Add migrations directory and test suite with pytest config
- Add supabase_migration_features.sql
- Update models, dependencies, config, and existing routers
- Remove whatsapp_service (deleted)
- Update pyproject.toml and uv.lock dependencies

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
belviskhoremk
2026-04-03 09:11:58 +00:00
parent 9dccc83293
commit 92d4c2fc5e
51 changed files with 7076 additions and 515 deletions

View File

@@ -0,0 +1,97 @@
-- Contexta — Features Migration (Phase 1, 2, 3)
-- Run this in your Supabase SQL Editor
-- ══════════════════════════════════════════════════════════════
-- PHASE 1 — Live Chat Inbox + Lead CRM
-- ══════════════════════════════════════════════════════════════
-- Add status to conversations (open → agent_handling → resolved)
ALTER TABLE conversations
ADD COLUMN IF NOT EXISTS status VARCHAR(20) DEFAULT 'open',
ADD COLUMN IF NOT EXISTS last_agent_reply_at TIMESTAMPTZ;
-- Add CRM fields to leads
ALTER TABLE leads
ADD COLUMN IF NOT EXISTS status VARCHAR(20) DEFAULT 'new',
ADD COLUMN IF NOT EXISTS notes TEXT;
-- ══════════════════════════════════════════════════════════════
-- PHASE 2a — Appointment Booking
-- ══════════════════════════════════════════════════════════════
-- Add booking toggle to chatbots
ALTER TABLE chatbots
ADD COLUMN IF NOT EXISTS booking_enabled BOOLEAN DEFAULT FALSE;
-- Business hours per chatbot (one row per weekday)
CREATE TABLE IF NOT EXISTS business_hours (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
chatbot_id UUID NOT NULL REFERENCES chatbots(id) ON DELETE CASCADE,
day_of_week INTEGER NOT NULL CHECK (day_of_week BETWEEN 0 AND 6), -- 0=Mon, 6=Sun
is_open BOOLEAN DEFAULT TRUE,
open_time TIME NOT NULL DEFAULT '09:00',
close_time TIME NOT NULL DEFAULT '17:00',
slot_duration_minutes INTEGER NOT NULL DEFAULT 60,
UNIQUE(chatbot_id, day_of_week)
);
CREATE INDEX IF NOT EXISTS idx_business_hours_chatbot ON business_hours(chatbot_id);
ALTER TABLE business_hours ENABLE ROW LEVEL SECURITY;
CREATE POLICY "business_hours_owner" ON business_hours 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()
)
);
-- Appointments table
CREATE TABLE IF NOT EXISTS appointments (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
chatbot_id UUID NOT NULL REFERENCES chatbots(id) ON DELETE CASCADE,
conversation_id UUID REFERENCES conversations(id) ON DELETE SET NULL,
customer_name TEXT NOT NULL,
customer_contact TEXT NOT NULL, -- email or phone
service TEXT,
slot_start TIMESTAMPTZ NOT NULL,
slot_end TIMESTAMPTZ NOT NULL,
status VARCHAR(20) DEFAULT 'pending' CHECK (status IN ('pending','confirmed','cancelled','completed')),
notes TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_appointments_chatbot ON appointments(chatbot_id);
CREATE INDEX IF NOT EXISTS idx_appointments_slot ON appointments(chatbot_id, slot_start);
ALTER TABLE appointments ENABLE ROW LEVEL SECURITY;
CREATE POLICY "appointments_owner" ON appointments 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()
)
);
-- Allow anonymous inserts (customers booking without auth)
CREATE POLICY "appointments_insert_public" ON appointments FOR INSERT WITH CHECK (true);
-- ══════════════════════════════════════════════════════════════
-- PHASE 2b — Telegram Campaigns
-- ══════════════════════════════════════════════════════════════
CREATE TABLE IF NOT EXISTS campaigns (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
chatbot_id UUID NOT NULL REFERENCES chatbots(id) ON DELETE CASCADE,
title TEXT NOT NULL,
message TEXT NOT NULL,
status VARCHAR(20) DEFAULT 'draft' CHECK (status IN ('draft','sending','sent','failed')),
recipients_count INTEGER DEFAULT 0,
sent_count INTEGER DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT NOW(),
sent_at TIMESTAMPTZ
);
CREATE INDEX IF NOT EXISTS idx_campaigns_chatbot ON campaigns(chatbot_id);
ALTER TABLE campaigns ENABLE ROW LEVEL SECURITY;
CREATE POLICY "campaigns_owner" ON campaigns 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()
)
);