Files
braidsbymira/supabase/migrations/20260808000001_initial_schema.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()) = '00000000-0000-0000-0000-000000000001'::uuid)
with check ((select auth.uid()) = '00000000-0000-0000-0000-000000000001'::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()) = '00000000-0000-0000-0000-000000000001'::uuid)
with check ((select auth.uid()) = '00000000-0000-0000-0000-000000000001'::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()) = '00000000-0000-0000-0000-000000000001'::uuid)
with check ((select auth.uid()) = '00000000-0000-0000-0000-000000000001'::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()) = '00000000-0000-0000-0000-000000000001'::uuid)
with check ((select auth.uid()) = '00000000-0000-0000-0000-000000000001'::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()) = '00000000-0000-0000-0000-000000000001'::uuid)
with check ((select auth.uid()) = '00000000-0000-0000-0000-000000000001'::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()) = '00000000-0000-0000-0000-000000000001'::uuid)
with check ((select auth.uid()) = '00000000-0000-0000-0000-000000000001'::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()) = '00000000-0000-0000-0000-000000000001'::uuid)
with check ((select auth.uid()) = '00000000-0000-0000-0000-000000000001'::uuid);