Spaces:
Sleeping
Sleeping
Vion Deploy
Claude Opus 4.8
Add auth, dashboards, LLM scoring, email notifications, scheduling, and new UI
dd935c0 Download db/schema.sql from vion-training/Vion: direct link, hf CLI and curl.
- Browser
- Download file 9.87 kB
-
https://huggingface.co/spaces/vion-training/Vion/resolve/main/db/schema.sql
- Command line
-
hf download hf://spaces/vion-training/Vion/db/schema.sql
-
curl -L -o schema.sql https://huggingface.co/spaces/vion-training/Vion/resolve/main/db/schema.sql
9.87 kB
| -- Vion Training β Supabase schema (Phase 1) | |
| -- Run this in the Supabase SQL Editor (Dashboard β SQL Editor β New query β paste β Run). | |
| -- Safe to re-run: uses IF NOT EXISTS / OR REPLACE throughout. | |
| -- | |
| -- Auth itself (email/password, password reset, JWT) is handled by Supabase's | |
| -- built-in `auth.users` table. Everything below is OUR application data, keyed | |
| -- to that user id. Row Level Security (RLS) ensures a user can only read their | |
| -- own rows, while admins can read everyone's. | |
| -- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| -- 1. Profiles β one row per auth user, holding app-level fields + role. | |
| -- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| create table if not exists public.profiles ( | |
| id uuid primary key references auth.users(id) on delete cascade, | |
| email text, | |
| full_name text, | |
| role text not null default 'user' check (role in ('user', 'admin')), | |
| language_preference text not null default 'en' check (language_preference in ('en', 'de')), | |
| theme text not null default 'system' check (theme in ('light', 'dark', 'system')), | |
| notifications_enabled boolean not null default true, | |
| created_at timestamptz not null default now() | |
| ); | |
| -- Auto-create a profile row whenever a new auth user signs up. | |
| create or replace function public.handle_new_user() | |
| returns trigger | |
| language plpgsql | |
| security definer set search_path = public | |
| as $$ | |
| begin | |
| insert into public.profiles (id, email, full_name) | |
| values (new.id, new.email, new.raw_user_meta_data->>'full_name') | |
| on conflict (id) do nothing; | |
| return new; | |
| end; | |
| $$; | |
| drop trigger if exists on_auth_user_created on auth.users; | |
| create trigger on_auth_user_created | |
| after insert on auth.users | |
| for each row execute function public.handle_new_user(); | |
| -- Helper: is the current request from an admin? (security definer avoids RLS recursion) | |
| create or replace function public.is_admin() | |
| returns boolean | |
| language sql | |
| security definer set search_path = public | |
| stable | |
| as $$ | |
| select exists ( | |
| select 1 from public.profiles | |
| where id = auth.uid() and role = 'admin' | |
| ); | |
| $$; | |
| -- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| -- 2. Sessions β one row per training call. | |
| -- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| create table if not exists public.sessions ( | |
| id uuid primary key default gen_random_uuid(), | |
| user_id uuid not null references public.profiles(id) on delete cascade, | |
| scenario_id text not null, | |
| persona_id text, | |
| language text not null default 'en', | |
| status text not null default 'created' | |
| check (status in ('created', 'active', 'ended', 'error')), | |
| transcript jsonb not null default '[]'::jsonb, | |
| user_notes text, -- the trainee's own notes on this call | |
| started_at timestamptz, | |
| ended_at timestamptz, | |
| created_at timestamptz not null default now() | |
| ); | |
| create index if not exists sessions_user_id_idx on public.sessions(user_id); | |
| create index if not exists sessions_created_at_idx on public.sessions(created_at desc); | |
| -- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| -- 3. Evaluations β the LLM-scored result of a call (1:1 with a session). | |
| -- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| create table if not exists public.evaluations ( | |
| id uuid primary key default gen_random_uuid(), | |
| session_id uuid not null unique references public.sessions(id) on delete cascade, | |
| user_id uuid not null references public.profiles(id) on delete cascade, | |
| score int check (score between 0 and 100), | |
| passed boolean, | |
| summary text, | |
| good_points jsonb not null default '[]'::jsonb, -- ["...", "..."] | |
| improvements jsonb not null default '[]'::jsonb, -- ["...", "..."] | |
| created_at timestamptz not null default now() | |
| ); | |
| create index if not exists evaluations_user_id_idx on public.evaluations(user_id); | |
| -- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| -- 4. Feedback β free-text app feedback from the "Feedback" dashboard item. | |
| -- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| create table if not exists public.feedback ( | |
| id uuid primary key default gen_random_uuid(), | |
| user_id uuid not null references public.profiles(id) on delete cascade, | |
| body text not null, | |
| created_at timestamptz not null default now() | |
| ); | |
| -- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| -- 5. Row Level Security β lock every table to its owner; admins see all. | |
| -- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| alter table public.profiles enable row level security; | |
| alter table public.sessions enable row level security; | |
| alter table public.evaluations enable row level security; | |
| alter table public.feedback enable row level security; | |
| -- Profiles: a user reads/updates their own row; admins read all. | |
| drop policy if exists profiles_select_own on public.profiles; | |
| create policy profiles_select_own on public.profiles | |
| for select using (id = auth.uid() or public.is_admin()); | |
| drop policy if exists profiles_update_own on public.profiles; | |
| create policy profiles_update_own on public.profiles | |
| for update using (id = auth.uid()); | |
| -- Sessions: owner full access; admins read-only. | |
| drop policy if exists sessions_owner_all on public.sessions; | |
| create policy sessions_owner_all on public.sessions | |
| for all using (user_id = auth.uid()) with check (user_id = auth.uid()); | |
| drop policy if exists sessions_admin_read on public.sessions; | |
| create policy sessions_admin_read on public.sessions | |
| for select using (public.is_admin()); | |
| -- Evaluations: owner reads; admins read. (Writes happen server-side via service key.) | |
| drop policy if exists evaluations_owner_read on public.evaluations; | |
| create policy evaluations_owner_read on public.evaluations | |
| for select using (user_id = auth.uid() or public.is_admin()); | |
| -- Feedback: owner inserts/reads own; admins read all. | |
| drop policy if exists feedback_owner on public.feedback; | |
| create policy feedback_owner on public.feedback | |
| for all using (user_id = auth.uid()) with check (user_id = auth.uid()); | |
| drop policy if exists feedback_admin_read on public.feedback; | |
| create policy feedback_admin_read on public.feedback | |
| for select using (public.is_admin()); | |
| -- NOTE: the FastAPI backend uses the SERVICE ROLE key, which bypasses RLS, to | |
| -- write sessions/evaluations on the user's behalf. The anon key (frontend) is | |
| -- always subject to the policies above. | |
| -- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| -- 6. Grants β table-level privileges for the API roles. | |
| -- Postgres requires BOTH a table privilege AND (for anon/authenticated) a | |
| -- passing RLS policy. RLS alone is not enough; without these grants every | |
| -- request 403s with "permission denied for table". Supabase normally adds | |
| -- these automatically, but tables created via raw SQL can miss them. | |
| -- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| grant usage on schema public to anon, authenticated, service_role; | |
| -- service_role bypasses RLS and does all server-side writes β full access. | |
| grant all privileges on all tables in schema public to service_role; | |
| grant all privileges on all sequences in schema public to service_role; | |
| grant all privileges on all functions in schema public to service_role; | |
| -- Logged-in users act as `authenticated`; RLS still restricts them to own rows. | |
| grant select, insert, update, delete on all tables in schema public to authenticated; | |
| grant usage, select on all sequences in schema public to authenticated; | |
| -- Make the same grants apply to any tables we add later. | |
| alter default privileges in schema public | |
| grant all privileges on tables to service_role; | |
| alter default privileges in schema public | |
| grant select, insert, update, delete on tables to authenticated; | |