- Cookie-based auth via backend proxy (httpOnly JWTs) - Supabase Postgres persistence for sessions/messages/profiles + RLS - Fix cross-user session leak (token cache keyed by full token, not 50-char prefix) - Fix missing table grants (42501) via migration; auto-provision profiles on user creation - Chat validation, ownership checks, rate limiting, /api/chat/sessions route ordering - Frontend auth-state reset + credentials include - OpenRouter AI provider (OpenAI-compatible base URL, reasoning disabled) - Tests: chatValidation, appState
81 lines
2.6 KiB
SQL
81 lines
2.6 KiB
SQL
-- Create sessions table
|
|
CREATE TABLE public.sessions (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
grade TEXT,
|
|
subject TEXT,
|
|
chapter TEXT,
|
|
preview TEXT,
|
|
created_at TIMESTAMPTZ DEFAULT now(),
|
|
updated_at TIMESTAMPTZ DEFAULT now()
|
|
);
|
|
|
|
-- Create messages table
|
|
CREATE TABLE public.messages (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
session_id UUID NOT NULL REFERENCES public.sessions(id) ON DELETE CASCADE,
|
|
role TEXT NOT NULL CHECK (role IN ('user', 'assistant')),
|
|
text TEXT NOT NULL,
|
|
created_at TIMESTAMPTZ DEFAULT now()
|
|
);
|
|
|
|
-- Create profiles table (optional, for future user metadata)
|
|
CREATE TABLE public.profiles (
|
|
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
email TEXT NOT NULL,
|
|
display_name TEXT,
|
|
avatar_url TEXT,
|
|
created_at TIMESTAMPTZ DEFAULT now(),
|
|
updated_at TIMESTAMPTZ DEFAULT now()
|
|
);
|
|
|
|
-- Create indexes for faster queries
|
|
CREATE INDEX idx_sessions_user_id ON public.sessions(user_id);
|
|
CREATE INDEX idx_messages_session_id ON public.messages(session_id);
|
|
|
|
-- Enable RLS
|
|
ALTER TABLE public.sessions ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE public.messages ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
|
|
|
|
-- RLS Policies for sessions: users can CRUD only their own sessions
|
|
CREATE POLICY "Users can view own sessions"
|
|
ON public.sessions FOR SELECT
|
|
USING (auth.uid() = user_id);
|
|
|
|
CREATE POLICY "Users can create sessions"
|
|
ON public.sessions FOR INSERT
|
|
WITH CHECK (auth.uid() = user_id);
|
|
|
|
CREATE POLICY "Users can update own sessions"
|
|
ON public.sessions FOR UPDATE
|
|
USING (auth.uid() = user_id)
|
|
WITH CHECK (auth.uid() = user_id);
|
|
|
|
CREATE POLICY "Users can delete own sessions"
|
|
ON public.sessions FOR DELETE
|
|
USING (auth.uid() = user_id);
|
|
|
|
-- RLS Policies for messages: users can CRUD only messages in their own sessions
|
|
CREATE POLICY "Users can view messages in own sessions"
|
|
ON public.messages FOR SELECT
|
|
USING (session_id IN (SELECT id FROM public.sessions WHERE user_id = auth.uid()));
|
|
|
|
CREATE POLICY "Users can insert messages in own sessions"
|
|
ON public.messages FOR INSERT
|
|
WITH CHECK (session_id IN (SELECT id FROM public.sessions WHERE user_id = auth.uid()));
|
|
|
|
CREATE POLICY "Users can delete own messages"
|
|
ON public.messages FOR DELETE
|
|
USING (session_id IN (SELECT id FROM public.sessions WHERE user_id = auth.uid()));
|
|
|
|
-- RLS Policies for profiles
|
|
CREATE POLICY "Users can view own profile"
|
|
ON public.profiles FOR SELECT
|
|
USING (auth.uid() = id);
|
|
|
|
CREATE POLICY "Users can update own profile"
|
|
ON public.profiles FOR UPDATE
|
|
USING (auth.uid() = id)
|
|
WITH CHECK (auth.uid() = id);
|