Substitutes the real admin UID everywhere the placeholder appeared, points the Edge Functions base URL at the deployed project, and adds production JWT verification: trigger functions now send the anon key as a bearer token so verify_jwt can stay enabled instead of leaving the functions open to unauthenticated calls from the public internet. Also adds scripts/create-admin.ts (one-off helper used to create Mira's admin auth user), documents the seed script's non-VITE env vars in .env.example, and closes a gitignore gap where plain .env wasn't excluded alongside .env.local. Claude-Session: https://claude.ai/code/session_01NhxA4npAXAxmCDEJt6kxSH
129 lines
5.1 KiB
SQL
129 lines
5.1 KiB
SQL
-- Products, services, availability schedule, bookings, inquiries, and the
|
|
-- public booked_slots mirror. See docs/superpowers/specs/2026-08-08-phase2-backend-foundation-supabase-design.md.
|
|
|
|
create table public.products (
|
|
id text primary key,
|
|
name text not null,
|
|
category text not null check (category in ('hair-care', 'extensions', 'tools', 'accessories')),
|
|
price numeric not null,
|
|
image text not null,
|
|
description text not null,
|
|
in_stock boolean not null default true
|
|
);
|
|
|
|
create table public.services (
|
|
id text primary key,
|
|
name text not null,
|
|
duration_minutes integer not null,
|
|
price_from numeric not null,
|
|
description text not null,
|
|
image text not null
|
|
);
|
|
|
|
create table public.schedule_template (
|
|
id text primary key default 'default',
|
|
working_days integer[] not null,
|
|
start_time time not null,
|
|
end_time time not null,
|
|
slot_minutes integer not null
|
|
);
|
|
|
|
create table public.schedule_exceptions (
|
|
date date primary key,
|
|
closed boolean not null,
|
|
note text
|
|
);
|
|
|
|
create table public.bookings (
|
|
id uuid primary key default gen_random_uuid(),
|
|
service_id text not null references public.services(id),
|
|
date date not null,
|
|
time text not null,
|
|
contact_name text not null,
|
|
contact_phone text not null,
|
|
contact_email text not null,
|
|
contact_notes text not null default '',
|
|
status text not null default 'confirmed' check (status in ('confirmed', 'cancelled')),
|
|
created_at timestamptz not null default now()
|
|
);
|
|
|
|
create index bookings_service_id_idx on public.bookings (service_id);
|
|
|
|
create table public.booked_slots (
|
|
date date not null,
|
|
time text not null,
|
|
primary key (date, time)
|
|
);
|
|
|
|
create table public.inquiries (
|
|
id uuid primary key default gen_random_uuid(),
|
|
product_id text not null references public.products(id),
|
|
contact_name text not null,
|
|
contact_email text not null,
|
|
contact_notes text not null default '',
|
|
status text not null default 'new' check (status in ('new', 'read')),
|
|
created_at timestamptz not null default now()
|
|
);
|
|
|
|
create index inquiries_product_id_idx on public.inquiries (product_id);
|
|
|
|
-- Row Level Security
|
|
|
|
alter table public.products enable row level security;
|
|
alter table public.services enable row level security;
|
|
alter table public.schedule_template enable row level security;
|
|
alter table public.schedule_exceptions enable row level security;
|
|
alter table public.bookings enable row level security;
|
|
alter table public.booked_slots enable row level security;
|
|
alter table public.inquiries enable row level security;
|
|
|
|
-- products: public read, admin write
|
|
create policy "products_public_read" on public.products
|
|
for select using (true);
|
|
create policy "products_admin_write" on public.products
|
|
for all using ((select auth.uid()) = '21c90224-e0b2-412e-a431-8e7f097c1cef'::uuid)
|
|
with check ((select auth.uid()) = '21c90224-e0b2-412e-a431-8e7f097c1cef'::uuid);
|
|
|
|
-- services: public read, admin write
|
|
create policy "services_public_read" on public.services
|
|
for select using (true);
|
|
create policy "services_admin_write" on public.services
|
|
for all using ((select auth.uid()) = '21c90224-e0b2-412e-a431-8e7f097c1cef'::uuid)
|
|
with check ((select auth.uid()) = '21c90224-e0b2-412e-a431-8e7f097c1cef'::uuid);
|
|
|
|
-- schedule_template: public read, admin write
|
|
create policy "schedule_template_public_read" on public.schedule_template
|
|
for select using (true);
|
|
create policy "schedule_template_admin_write" on public.schedule_template
|
|
for all using ((select auth.uid()) = '21c90224-e0b2-412e-a431-8e7f097c1cef'::uuid)
|
|
with check ((select auth.uid()) = '21c90224-e0b2-412e-a431-8e7f097c1cef'::uuid);
|
|
|
|
-- schedule_exceptions: public read, admin write
|
|
create policy "schedule_exceptions_public_read" on public.schedule_exceptions
|
|
for select using (true);
|
|
create policy "schedule_exceptions_admin_write" on public.schedule_exceptions
|
|
for all using ((select auth.uid()) = '21c90224-e0b2-412e-a431-8e7f097c1cef'::uuid)
|
|
with check ((select auth.uid()) = '21c90224-e0b2-412e-a431-8e7f097c1cef'::uuid);
|
|
|
|
-- bookings: anyone can insert (submit a booking); only admin can read/update/delete
|
|
create policy "bookings_public_insert" on public.bookings
|
|
for insert with check (true);
|
|
create policy "bookings_admin_all" on public.bookings
|
|
for all using ((select auth.uid()) = '21c90224-e0b2-412e-a431-8e7f097c1cef'::uuid)
|
|
with check ((select auth.uid()) = '21c90224-e0b2-412e-a431-8e7f097c1cef'::uuid);
|
|
|
|
-- booked_slots: public read; only admin policy exists for writes (in practice only
|
|
-- the security-definer trigger in the next migration ever writes here)
|
|
create policy "booked_slots_public_read" on public.booked_slots
|
|
for select using (true);
|
|
create policy "booked_slots_admin_write" on public.booked_slots
|
|
for all using ((select auth.uid()) = '21c90224-e0b2-412e-a431-8e7f097c1cef'::uuid)
|
|
with check ((select auth.uid()) = '21c90224-e0b2-412e-a431-8e7f097c1cef'::uuid);
|
|
|
|
-- inquiries: anyone can insert; only admin can read/update/delete
|
|
create policy "inquiries_public_insert" on public.inquiries
|
|
for insert with check (true);
|
|
create policy "inquiries_admin_all" on public.inquiries
|
|
for all using ((select auth.uid()) = '21c90224-e0b2-412e-a431-8e7f097c1cef'::uuid)
|
|
with check ((select auth.uid()) = '21c90224-e0b2-412e-a431-8e7f097c1cef'::uuid);
|