any2human / supabase /schema.sql
idnameraj's picture
Upload 75 files
b387e01 verified
Raw
History Blame Contribute Delete
3.78 kB
-- PlainRewrite — run once in Supabase SQL Editor
-- Auth: enable Email + Google in Authentication → Providers
create extension if not exists "pgcrypto";
-- Packages (edit in Table Editor; Stripe later)
create table if not exists public.plans (
id text primary key,
name text not null,
daily_rewrites int not null,
max_words_per_request int not null,
daily_word_cap int not null,
price_inr_monthly int not null default 0,
active boolean not null default true
);
insert into public.plans (id, name, daily_rewrites, max_words_per_request, daily_word_cap, price_inr_monthly)
values
('free', 'Free', 5, 400, 1500, 0),
('pro', 'Pro', 50, 2000, 15000, 199),
('plus', 'Plus', 200, 5000, 50000, 499)
on conflict (id) do update set
name = excluded.name,
daily_rewrites = excluded.daily_rewrites,
max_words_per_request = excluded.max_words_per_request,
daily_word_cap = excluded.daily_word_cap,
price_inr_monthly = excluded.price_inr_monthly;
create table if not exists public.profiles (
id uuid primary key references auth.users (id) on delete cascade,
email text,
display_name text,
role text not null default 'user' check (role in ('user', 'admin')),
plan_id text not null default 'free' references public.plans (id),
status text not null default 'active' check (status in ('active', 'disabled')),
created_at timestamptz not null default timezone('utc', now()),
updated_at timestamptz not null default timezone('utc', now())
);
create table if not exists public.usage_daily (
user_id uuid not null references public.profiles (id) on delete cascade,
usage_date date not null default (timezone('utc', now())::date),
rewrite_count int not null default 0,
word_count int not null default 0,
primary key (user_id, usage_date)
);
create index if not exists usage_daily_date_idx on public.usage_daily (usage_date);
-- Auto-create profile on signup
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, display_name, role, plan_id)
values (
new.id,
new.email,
coalesce(new.raw_user_meta_data->>'full_name', split_part(new.email, '@', 1)),
'user',
'free'
)
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();
alter table public.plans enable row level security;
alter table public.profiles enable row level security;
alter table public.usage_daily enable row level security;
-- Public can read active plans (pricing page later)
drop policy if exists "plans_read_active" on public.plans;
create policy "plans_read_active"
on public.plans for select
using (active = true);
-- Users read/update own profile (plan/role only via service role / admin in dashboard)
drop policy if exists "profiles_select_own" on public.profiles;
create policy "profiles_select_own"
on public.profiles for select
using (auth.uid() = id);
drop policy if exists "profiles_update_own_name" on public.profiles;
create policy "profiles_update_own_name"
on public.profiles for update
using (auth.uid() = id)
with check (auth.uid() = id);
drop policy if exists "usage_select_own" on public.usage_daily;
create policy "usage_select_own"
on public.usage_daily for select
using (auth.uid() = user_id);
-- FastAPI uses the service role key (bypasses RLS) for quota writes.
-- Promote an admin in SQL after first login:
-- update public.profiles set role = 'admin' where email = 'you@example.com';