alter table if exists public.wg_gallery_photos add column if not exists color_family text, add column if not exists is_picked boolean not null default false, add column if not exists picked_at timestamptz, add column if not exists picked_by text, add column if not exists pick_note text, add column if not exists oss_bucket text, add column if not exists oss_object_key text, add column if not exists oss_url text, add column if not exists oss_synced_at timestamptz, add column if not exists oss_sync_error text; create table if not exists public.wg_photo_collections ( id uuid primary key default gen_random_uuid(), title text not null, slug text not null unique, description text, cover_photo_id uuid references public.wg_gallery_photos(id) on delete set null, is_published boolean not null default false, published_at timestamptz, created_at timestamptz not null default now(), updated_at timestamptz not null default now() ); create table if not exists public.wg_photo_collection_items ( id uuid primary key default gen_random_uuid(), collection_id uuid not null references public.wg_photo_collections(id) on delete cascade, photo_id uuid not null references public.wg_gallery_photos(id) on delete cascade, sort_order integer not null default 0, created_at timestamptz not null default now(), unique (collection_id, photo_id) ); create table if not exists public.wg_app_users ( id uuid primary key default gen_random_uuid(), auth_user_id uuid unique references auth.users(id) on delete set null, email text unique, password_hash text, display_name text, avatar_url text, auth_provider text not null default 'email', status text not null default 'active', created_at timestamptz not null default now(), updated_at timestamptz not null default now() ); create table if not exists public.wg_user_favorites ( user_id uuid not null references public.wg_app_users(id) on delete cascade, photo_id uuid not null references public.wg_gallery_photos(id) on delete cascade, created_at timestamptz not null default now(), primary key (user_id, photo_id) ); create table if not exists public.wg_user_settings ( user_id uuid primary key references public.wg_app_users(id) on delete cascade, preferences jsonb not null default '{}'::jsonb, download_preferences jsonb not null default '{}'::jsonb, updated_at timestamptz not null default now() ); create index if not exists wg_gallery_photos_pick_idx on public.wg_gallery_photos (is_picked, picked_at desc, photo_created_at desc); create index if not exists wg_gallery_photos_color_family_idx on public.wg_gallery_photos (color_family); create index if not exists wg_gallery_photos_color_idx on public.wg_gallery_photos (color); create index if not exists wg_photo_collections_published_idx on public.wg_photo_collections (is_published, published_at desc, created_at desc); create index if not exists wg_photo_collection_items_collection_sort_idx on public.wg_photo_collection_items (collection_id, sort_order, created_at); create index if not exists wg_photo_collection_items_photo_idx on public.wg_photo_collection_items (photo_id); create index if not exists wg_app_users_auth_user_idx on public.wg_app_users (auth_user_id); create index if not exists wg_app_users_email_idx on public.wg_app_users (email); alter table public.wg_gallery_photos enable row level security; alter table public.wg_photo_collections enable row level security; alter table public.wg_photo_collection_items enable row level security; alter table public.wg_app_users enable row level security; alter table public.wg_user_favorites enable row level security; alter table public.wg_user_settings enable row level security; drop policy if exists "Public can read gallery photos" on public.wg_gallery_photos; drop policy if exists "Public can read picked gallery photos" on public.wg_gallery_photos; create policy "Public can read picked gallery photos" on public.wg_gallery_photos for select to anon, authenticated using (is_picked = true); drop policy if exists "Public can read published collections" on public.wg_photo_collections; create policy "Public can read published collections" on public.wg_photo_collections for select to anon, authenticated using (is_published = true); drop policy if exists "Public can read published collection items" on public.wg_photo_collection_items; create policy "Public can read published collection items" on public.wg_photo_collection_items for select to anon, authenticated using ( exists ( select 1 from public.wg_photo_collections collections where collections.id = collection_id and collections.is_published = true ) and exists ( select 1 from public.wg_gallery_photos photos where photos.id = photo_id and photos.is_picked = true ) ); drop policy if exists "Users can read own profile" on public.wg_app_users; create policy "Users can read own profile" on public.wg_app_users for select to authenticated using (auth_user_id = auth.uid()); drop policy if exists "Users can update own profile" on public.wg_app_users; create policy "Users can update own profile" on public.wg_app_users for update to authenticated using (auth_user_id = auth.uid()) with check (auth_user_id = auth.uid()); drop policy if exists "Users can manage own favorites" on public.wg_user_favorites; create policy "Users can manage own favorites" on public.wg_user_favorites for all to authenticated using ( exists ( select 1 from public.wg_app_users users where users.id = user_id and users.auth_user_id = auth.uid() ) ) with check ( exists ( select 1 from public.wg_app_users users where users.id = user_id and users.auth_user_id = auth.uid() ) ); drop policy if exists "Users can manage own settings" on public.wg_user_settings; create policy "Users can manage own settings" on public.wg_user_settings for all to authenticated using ( exists ( select 1 from public.wg_app_users users where users.id = user_id and users.auth_user_id = auth.uid() ) ) with check ( exists ( select 1 from public.wg_app_users users where users.id = user_id and users.auth_user_id = auth.uid() ) ); grant select on table public.wg_gallery_photos to anon, authenticated; grant select on table public.wg_photo_collections to anon, authenticated; grant select on table public.wg_photo_collection_items to anon, authenticated; grant select, update on table public.wg_app_users to authenticated; grant select, insert, update, delete on table public.wg_user_favorites to authenticated; grant select, insert, update, delete on table public.wg_user_settings to authenticated; drop trigger if exists set_wg_photo_collections_updated_at on public.wg_photo_collections; create trigger set_wg_photo_collections_updated_at before update on public.wg_photo_collections for each row execute function public.set_wg_updated_at(); drop trigger if exists set_wg_app_users_updated_at on public.wg_app_users; create trigger set_wg_app_users_updated_at before update on public.wg_app_users for each row execute function public.set_wg_updated_at(); drop trigger if exists set_wg_user_settings_updated_at on public.wg_user_settings; create trigger set_wg_user_settings_updated_at before update on public.wg_user_settings for each row execute function public.set_wg_updated_at();