initial commit: rocket.new export of broadcastbeat
This commit is contained in:
164
supabase/migrations/20260322250000_ai_console_hybrid_router.sql
Normal file
164
supabase/migrations/20260322250000_ai_console_hybrid_router.sql
Normal file
@@ -0,0 +1,164 @@
|
||||
-- ============================================================
|
||||
-- AI Console & Hybrid AI Routing — Database Schema
|
||||
-- Sections A-D: AI Console, Sessions, Health Log, Settings
|
||||
-- ============================================================
|
||||
|
||||
-- ─── AI Console Settings ─────────────────────────────────────
|
||||
CREATE TABLE IF NOT EXISTS public.ai_console_settings (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
ollama_endpoint text NOT NULL DEFAULT '',
|
||||
ollama_model_default text NOT NULL DEFAULT '',
|
||||
ollama_model_translation text NOT NULL DEFAULT '',
|
||||
ollama_model_background text NOT NULL DEFAULT '',
|
||||
auto_failover boolean NOT NULL DEFAULT true,
|
||||
failover_timeout_seconds integer NOT NULL DEFAULT 8,
|
||||
default_site_id integer NOT NULL DEFAULT 1,
|
||||
default_pen_name_bb text NOT NULL DEFAULT 'Michael Strand',
|
||||
default_pen_name_av text NOT NULL DEFAULT 'Rex Chandler',
|
||||
save_session_history boolean NOT NULL DEFAULT true,
|
||||
history_retention_days integer NOT NULL DEFAULT 30,
|
||||
streaming_enabled boolean NOT NULL DEFAULT true,
|
||||
background_use_local boolean NOT NULL DEFAULT true,
|
||||
background_timeout_seconds integer NOT NULL DEFAULT 120,
|
||||
priority_queue_enabled boolean NOT NULL DEFAULT true,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
-- ─── AI Console Sessions ─────────────────────────────────────
|
||||
CREATE TABLE IF NOT EXISTS public.ai_console_sessions (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id uuid NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
||||
site_id integer NOT NULL DEFAULT 1,
|
||||
pen_name text,
|
||||
first_message_preview text NOT NULL DEFAULT '',
|
||||
provider_used text NOT NULL DEFAULT 'anthropic',
|
||||
model_used text NOT NULL DEFAULT 'claude-sonnet-4-20250514',
|
||||
last_message_at timestamptz NOT NULL DEFAULT now(),
|
||||
created_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_ai_console_sessions_user_id
|
||||
ON public.ai_console_sessions(user_id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_ai_console_sessions_last_message
|
||||
ON public.ai_console_sessions(last_message_at DESC);
|
||||
|
||||
-- ─── AI Console Messages ─────────────────────────────────────
|
||||
CREATE TABLE IF NOT EXISTS public.ai_console_messages (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
session_id uuid NOT NULL REFERENCES public.ai_console_sessions(id) ON DELETE CASCADE,
|
||||
role text NOT NULL CHECK (role IN ('user', 'assistant', 'system')),
|
||||
content text NOT NULL DEFAULT '',
|
||||
provider_used text,
|
||||
created_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_ai_console_messages_session_id
|
||||
ON public.ai_console_messages(session_id);
|
||||
|
||||
-- ─── AI Health Log ────────────────────────────────────────────
|
||||
CREATE TABLE IF NOT EXISTS public.ai_health_log (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
provider text NOT NULL CHECK (provider IN ('ollama', 'anthropic')),
|
||||
success boolean NOT NULL DEFAULT true,
|
||||
latency_ms integer NOT NULL DEFAULT 0,
|
||||
model_used text NOT NULL DEFAULT '',
|
||||
priority integer NOT NULL DEFAULT 4,
|
||||
error_message text,
|
||||
is_failover boolean NOT NULL DEFAULT false,
|
||||
logged_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_ai_health_log_logged_at
|
||||
ON public.ai_health_log(logged_at DESC);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_ai_health_log_provider
|
||||
ON public.ai_health_log(provider, logged_at DESC);
|
||||
|
||||
-- Auto-purge logs older than 30 days (keep table lean)
|
||||
-- This is handled by a periodic cleanup; no trigger needed for now.
|
||||
|
||||
-- ─── RLS Policies ────────────────────────────────────────────
|
||||
|
||||
-- ai_console_settings: admin read/write only
|
||||
ALTER TABLE public.ai_console_settings ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_policies WHERE tablename = 'ai_console_settings' AND policyname = 'admin_all'
|
||||
) THEN
|
||||
CREATE POLICY admin_all ON public.ai_console_settings
|
||||
FOR ALL
|
||||
USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM public.user_profiles
|
||||
WHERE id = auth.uid() AND role IN ('administrator', 'admin')
|
||||
)
|
||||
);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- ai_console_sessions: users own their sessions
|
||||
ALTER TABLE public.ai_console_sessions ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_policies WHERE tablename = 'ai_console_sessions' AND policyname = 'owner_all'
|
||||
) THEN
|
||||
CREATE POLICY owner_all ON public.ai_console_sessions
|
||||
FOR ALL
|
||||
USING (user_id = auth.uid());
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- ai_console_messages: users own messages via session ownership
|
||||
ALTER TABLE public.ai_console_messages ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_policies WHERE tablename = 'ai_console_messages' AND policyname = 'owner_via_session'
|
||||
) THEN
|
||||
CREATE POLICY owner_via_session ON public.ai_console_messages
|
||||
FOR ALL
|
||||
USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM public.ai_console_sessions
|
||||
WHERE id = ai_console_messages.session_id AND user_id = auth.uid()
|
||||
)
|
||||
);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- ai_health_log: admin read, service role write (health-log route uses service role implicitly)
|
||||
ALTER TABLE public.ai_health_log ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_policies WHERE tablename = 'ai_health_log' AND policyname = 'admin_read'
|
||||
) THEN
|
||||
CREATE POLICY admin_read ON public.ai_health_log
|
||||
FOR SELECT
|
||||
USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM public.user_profiles
|
||||
WHERE id = auth.uid() AND role IN ('administrator', 'admin')
|
||||
)
|
||||
);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_policies WHERE tablename = 'ai_health_log' AND policyname = 'service_insert'
|
||||
) THEN
|
||||
CREATE POLICY service_insert ON public.ai_health_log
|
||||
FOR INSERT
|
||||
WITH CHECK (true);
|
||||
END IF;
|
||||
END $$;
|
||||
Reference in New Issue
Block a user