165 lines
6.4 KiB
SQL
165 lines
6.4 KiB
SQL
-- ============================================================
|
|
-- 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 $$;
|