Skip to content
OwnlyPlans

supabase-schema.sql

Tables, vote view, triggers and RLS policies. Save as supabase/schema.sql.

Part of Feedback Board with Voting and a Public Roadmap by Admin

Download Open the item
83 lines
-- Feedback board schema. Run in Supabase -> SQL Editor.

create table public.profiles (
  id uuid primary key references auth.users on delete cascade,
  display_name text,
  is_admin boolean not null default false,
  created_at timestamptz not null default now()
);

create table public.ideas (
  id bigint generated always as identity primary key,
  author_id uuid not null references public.profiles(id) on delete cascade,
  title text not null check (char_length(title) between 5 and 120),
  body text not null default '' check (char_length(body) <= 4000),
  status text not null default 'under_review'
    check (status in ('under_review','planned','in_progress','done','closed')),
  created_at timestamptz not null default now()
);

create table public.votes (
  idea_id bigint not null references public.ideas(id) on delete cascade,
  user_id uuid not null references public.profiles(id) on delete cascade,
  created_at timestamptz not null default now(),
  primary key (idea_id, user_id)
);

create table public.comments (
  id bigint generated always as identity primary key,
  idea_id bigint not null references public.ideas(id) on delete cascade,
  author_id uuid not null references public.profiles(id) on delete cascade,
  body text not null check (char_length(body) between 1 and 2000),
  created_at timestamptz not null default now()
);

create view public.idea_scores with (security_invoker = on) as
  select i.*, (select count(*) from public.votes v where v.idea_id = i.id) as votes
  from public.ideas i;

-- New users get a profile automatically.
create function public.handle_new_user() returns trigger
language plpgsql security definer set search_path = '' as $$
begin
  insert into public.profiles (id, display_name)
  values (new.id, split_part(new.email, '@', 1));
  return new;
end; $$;
create trigger on_auth_user_created after insert on auth.users
  for each row execute function public.handle_new_user();

create function public.is_admin() returns boolean
language sql stable security definer set search_path = '' as $$
  select coalesce((select is_admin from public.profiles where id = (select auth.uid())), false);
$$;

alter table public.profiles enable row level security;
alter table public.ideas    enable row level security;
alter table public.votes    enable row level security;
alter table public.comments enable row level security;

create policy "profiles readable" on public.profiles for select using (true);
create policy "update own profile" on public.profiles for update
  using ((select auth.uid()) = id) with check ((select auth.uid()) = id);
-- Users may only change their display name, never is_admin.
revoke update on public.profiles from authenticated, anon;
grant update (display_name) on public.profiles to authenticated;

create policy "ideas readable" on public.ideas for select using (true);
create policy "post own idea" on public.ideas for insert
  with check ((select auth.uid()) = author_id and status = 'under_review');
create policy "admin updates ideas" on public.ideas for update using (public.is_admin());
create policy "admin deletes ideas" on public.ideas for delete using (public.is_admin());

create policy "votes readable" on public.votes for select using (true);
create policy "vote as self" on public.votes for insert with check ((select auth.uid()) = user_id);
create policy "remove own vote" on public.votes for delete using ((select auth.uid()) = user_id);

create policy "comments readable" on public.comments for select using (true);
create policy "comment as self" on public.comments for insert with check ((select auth.uid()) = author_id);
create policy "delete own or admin" on public.comments for delete
  using ((select auth.uid()) = author_id or public.is_admin());

-- After you sign up once, make yourself admin:
-- update public.profiles set is_admin = true where id = (select id from auth.users where email = 'you@example.com');

Your AI tool
Starter prompt

		

Download the plan