feat(P4B.T1): whiteboards + whiteboard_strokes tables with RLS + realtime
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
-- Phase 4B: per-conversation whiteboards.
|
||||
--
|
||||
-- conversation_whiteboards: one row per whiteboard. Created by a member; the
|
||||
-- bubble that appears in the chat message timeline is a normal `messages`
|
||||
-- row whose plaintext payload is `{v:1, type:'whiteboard', whiteboard_id:<id>}`.
|
||||
--
|
||||
-- whiteboard_strokes: append-only stream of drawing operations. Each row is
|
||||
-- one user gesture (pen-down → pen-up); stroke_json carries the tool/color/
|
||||
-- width/points. Realtime subscribers replay rows in created_at order.
|
||||
|
||||
create table if not exists public.conversation_whiteboards (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
conversation_id uuid not null references public.conversations(id) on delete cascade,
|
||||
owner_user_id uuid not null references auth.users(id) on delete cascade,
|
||||
created_at timestamptz not null default now()
|
||||
);
|
||||
|
||||
create index if not exists conversation_whiteboards_conv_idx
|
||||
on public.conversation_whiteboards(conversation_id, created_at desc);
|
||||
|
||||
create table if not exists public.whiteboard_strokes (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
whiteboard_id uuid not null references public.conversation_whiteboards(id) on delete cascade,
|
||||
author_user_id uuid not null references auth.users(id) on delete cascade,
|
||||
stroke_json jsonb not null,
|
||||
created_at timestamptz not null default now()
|
||||
);
|
||||
|
||||
create index if not exists whiteboard_strokes_board_idx
|
||||
on public.whiteboard_strokes(whiteboard_id, created_at asc);
|
||||
|
||||
alter table public.conversation_whiteboards enable row level security;
|
||||
alter table public.whiteboard_strokes enable row level security;
|
||||
|
||||
drop policy if exists conversation_whiteboards_select on public.conversation_whiteboards;
|
||||
drop policy if exists conversation_whiteboards_insert on public.conversation_whiteboards;
|
||||
drop policy if exists conversation_whiteboards_delete on public.conversation_whiteboards;
|
||||
drop policy if exists whiteboard_strokes_select on public.whiteboard_strokes;
|
||||
drop policy if exists whiteboard_strokes_insert on public.whiteboard_strokes;
|
||||
drop policy if exists whiteboard_strokes_delete on public.whiteboard_strokes;
|
||||
|
||||
create policy conversation_whiteboards_select
|
||||
on public.conversation_whiteboards
|
||||
for select
|
||||
using (public.is_conversation_member(conversation_id));
|
||||
|
||||
create policy conversation_whiteboards_insert
|
||||
on public.conversation_whiteboards
|
||||
for insert
|
||||
with check (
|
||||
public.is_conversation_member(conversation_id)
|
||||
and owner_user_id = auth.uid()
|
||||
);
|
||||
|
||||
create policy conversation_whiteboards_delete
|
||||
on public.conversation_whiteboards
|
||||
for delete
|
||||
using (owner_user_id = auth.uid());
|
||||
|
||||
create policy whiteboard_strokes_select
|
||||
on public.whiteboard_strokes
|
||||
for select
|
||||
using (
|
||||
exists (
|
||||
select 1
|
||||
from public.conversation_whiteboards w
|
||||
where w.id = whiteboard_strokes.whiteboard_id
|
||||
and public.is_conversation_member(w.conversation_id)
|
||||
)
|
||||
);
|
||||
|
||||
create policy whiteboard_strokes_insert
|
||||
on public.whiteboard_strokes
|
||||
for insert
|
||||
with check (
|
||||
author_user_id = auth.uid()
|
||||
and exists (
|
||||
select 1
|
||||
from public.conversation_whiteboards w
|
||||
where w.id = whiteboard_id
|
||||
and public.is_conversation_member(w.conversation_id)
|
||||
)
|
||||
);
|
||||
|
||||
create policy whiteboard_strokes_delete
|
||||
on public.whiteboard_strokes
|
||||
for delete
|
||||
using (
|
||||
exists (
|
||||
select 1
|
||||
from public.conversation_whiteboards w
|
||||
where w.id = whiteboard_strokes.whiteboard_id
|
||||
and public.is_conversation_member(w.conversation_id)
|
||||
)
|
||||
);
|
||||
|
||||
alter table public.conversation_whiteboards replica identity full;
|
||||
alter table public.whiteboard_strokes replica identity full;
|
||||
|
||||
do $$
|
||||
begin
|
||||
if not exists (
|
||||
select 1
|
||||
from pg_publication_tables
|
||||
where pubname = 'supabase_realtime'
|
||||
and schemaname = 'public'
|
||||
and tablename = 'conversation_whiteboards'
|
||||
) then
|
||||
execute 'alter publication supabase_realtime add table public.conversation_whiteboards';
|
||||
end if;
|
||||
|
||||
if not exists (
|
||||
select 1
|
||||
from pg_publication_tables
|
||||
where pubname = 'supabase_realtime'
|
||||
and schemaname = 'public'
|
||||
and tablename = 'whiteboard_strokes'
|
||||
) then
|
||||
execute 'alter publication supabase_realtime add table public.whiteboard_strokes';
|
||||
end if;
|
||||
end
|
||||
$$;
|
||||
Reference in New Issue
Block a user