-- ============================================================ -- Migration 056: Definitive RLS fix -- -- Root cause: (select auth.uid()) inside a policy that queries -- org_members triggers PostgreSQL 42P17 infinite recursion, -- because org_members' own SELECT policy also queries org_members. -- -- Fix (per Supabase docs tip #4 & #5): -- 1. Create SECURITY DEFINER helper functions that bypass RLS -- 2. Use those in all policies — no self-referencing, no recursion -- 3. Wrap function calls in (select ...) for InitPlan caching -- ============================================================ -- ============================================================ -- STEP 1: Create helper functions (SECURITY DEFINER = bypass RLS) -- ============================================================ -- Returns all org_ids the current user belongs to CREATE OR REPLACE FUNCTION public.get_user_org_ids() RETURNS SETOF uuid LANGUAGE sql STABLE SECURITY DEFINER SET search_path = '' AS $$ SELECT org_members.org_id FROM public.org_members WHERE user_id = auth.uid(); $$; -- Returns the user's role in a specific org (or NULL if not a member) CREATE OR REPLACE FUNCTION public.get_user_org_role(org_id uuid) RETURNS text LANGUAGE sql STABLE SECURITY DEFINER SET search_path = '' AS $$ SELECT role FROM public.org_members WHERE org_members.org_id = get_user_org_role.org_id AND user_id = auth.uid() LIMIT 1; $$; -- is_org_member already exists from migration 039, just ensure it's correct CREATE OR REPLACE FUNCTION public.is_org_member(org_id uuid) RETURNS boolean LANGUAGE sql STABLE SECURITY DEFINER SET search_path = '' AS $$ SELECT EXISTS ( SELECT 1 FROM public.org_members WHERE org_members.org_id = is_org_member.org_id AND user_id = auth.uid() ); $$; -- Returns true if user has editor+ role in the given org CREATE OR REPLACE FUNCTION public.is_org_editor(org_id uuid) RETURNS boolean LANGUAGE sql STABLE SECURITY DEFINER SET search_path = '' AS $$ SELECT EXISTS ( SELECT 1 FROM public.org_members WHERE org_members.org_id = is_org_editor.org_id AND user_id = auth.uid() AND role IN ('owner', 'admin', 'editor') ); $$; -- Returns true if user has admin+ role in the given org CREATE OR REPLACE FUNCTION public.is_org_admin(org_id uuid) RETURNS boolean LANGUAGE sql STABLE SECURITY DEFINER SET search_path = '' AS $$ SELECT EXISTS ( SELECT 1 FROM public.org_members WHERE org_members.org_id = is_org_admin.org_id AND user_id = auth.uid() AND role IN ('owner', 'admin') ); $$; -- ============================================================ -- STEP 2: Drop ALL existing policies on all public tables -- ============================================================ DO $$ DECLARE r record; BEGIN FOR r IN SELECT schemaname, tablename, policyname FROM pg_policies WHERE schemaname = 'public' LOOP EXECUTE format('DROP POLICY IF EXISTS %I ON %I.%I', r.policyname, r.schemaname, r.tablename); END LOOP; END; $$; -- ============================================================ -- STEP 3: Recreate ALL policies using helper functions -- ============================================================ -- ── profiles ── CREATE POLICY "Profiles are viewable by everyone" ON public.profiles FOR SELECT TO authenticated USING (true); CREATE POLICY "Users can update own profile" ON public.profiles FOR UPDATE TO authenticated USING ((select auth.uid()) = id); -- ── organizations ── CREATE POLICY "Anyone can create organizations" ON public.organizations FOR INSERT TO authenticated WITH CHECK (true); CREATE POLICY "Members can view their organizations" ON public.organizations FOR SELECT TO authenticated USING ( (select public.is_platform_admin()) OR (select public.is_org_member(id)) ); CREATE POLICY "Admins can update organizations" ON public.organizations FOR UPDATE TO authenticated USING ( (select public.is_platform_admin()) OR (select public.is_org_admin(id)) ) WITH CHECK ( (select public.is_platform_admin()) OR (select public.is_org_admin(id)) ); CREATE POLICY "Owners can delete organizations" ON public.organizations FOR DELETE TO authenticated USING ( (select public.is_platform_admin()) OR EXISTS ( SELECT 1 FROM public.org_members WHERE org_id = organizations.id AND user_id = auth.uid() AND role = 'owner' ) ); -- ── org_members ── -- KEY FIX: use get_user_org_ids() to avoid self-referencing recursion CREATE POLICY "Members can view org members" ON public.org_members FOR SELECT TO authenticated USING (org_id IN (select public.get_user_org_ids())); CREATE POLICY "Allow member inserts" ON public.org_members FOR INSERT TO authenticated WITH CHECK ( (select public.is_org_admin(org_id)) OR org_members.user_id = (select auth.uid()) ); CREATE POLICY "Admins can update members" ON public.org_members FOR UPDATE TO authenticated USING ((select public.is_org_admin(org_id))) WITH CHECK ((select public.is_org_admin(org_id))); CREATE POLICY "Admins can delete members" ON public.org_members FOR DELETE TO authenticated USING ((select public.is_org_admin(org_id))); -- ── org_roles ── CREATE POLICY "Org members can view roles" ON public.org_roles FOR SELECT TO authenticated USING ((select public.is_org_member(org_id))); CREATE POLICY "Admins can manage roles" ON public.org_roles FOR ALL TO authenticated USING ((select public.is_org_admin(org_id))); -- ── org_invites ── CREATE POLICY "Anyone can view invite by token" ON public.org_invites FOR SELECT TO anon, authenticated USING (true); CREATE POLICY "Admins can manage invites" ON public.org_invites FOR ALL TO authenticated USING ((select public.is_org_admin(org_id))); -- ── documents ── CREATE POLICY "Members can manage documents" ON public.documents FOR ALL TO authenticated USING ((select public.is_org_member(org_id))) WITH CHECK ((select public.is_org_member(org_id))); -- ── document_locks ── CREATE POLICY "Org members can view document locks" ON public.document_locks FOR SELECT TO authenticated USING (EXISTS ( SELECT 1 FROM public.documents d WHERE d.id = document_locks.document_id AND (select public.is_org_member(d.org_id)) )); CREATE POLICY "Users can insert their own locks" ON public.document_locks FOR INSERT TO authenticated WITH CHECK (user_id = (select auth.uid())); CREATE POLICY "Users can update their own locks" ON public.document_locks FOR UPDATE TO authenticated USING (user_id = (select auth.uid())); CREATE POLICY "Users can delete locks" ON public.document_locks FOR DELETE TO authenticated USING (user_id = (select auth.uid()) OR last_heartbeat < (now() - interval '2 minutes')); -- ── kanban_boards ── CREATE POLICY "Members can manage boards" ON public.kanban_boards FOR ALL TO authenticated USING ((select public.is_org_member(org_id))) WITH CHECK ((select public.is_org_member(org_id))); -- ── kanban_columns ── CREATE POLICY "Members can manage columns" ON public.kanban_columns FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.kanban_boards b WHERE b.id = kanban_columns.board_id AND (select public.is_org_member(b.org_id)) )); -- ── kanban_cards ── CREATE POLICY "Members can manage cards" ON public.kanban_cards FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.kanban_columns c JOIN public.kanban_boards b ON c.board_id = b.id WHERE c.id = kanban_cards.column_id AND (select public.is_org_member(b.org_id)) )); -- ── card_assignees ── CREATE POLICY "Card assignees inherit card access" ON public.card_assignees FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.kanban_cards kc JOIN public.kanban_columns kcol ON kcol.id = kc.column_id JOIN public.kanban_boards kb ON kb.id = kcol.board_id WHERE kc.id = card_assignees.card_id AND (select public.is_org_member(kb.org_id)) )); -- ── checklist_items ── CREATE POLICY "Members can manage checklist items" ON public.checklist_items FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.kanban_cards c JOIN public.kanban_columns col ON c.column_id = col.id JOIN public.kanban_boards b ON col.board_id = b.id WHERE c.id = checklist_items.card_id AND (select public.is_org_member(b.org_id)) )); -- ── kanban_checklist_items ── CREATE POLICY "Checklist items inherit card access" ON public.kanban_checklist_items FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.kanban_cards c JOIN public.kanban_columns col ON c.column_id = col.id JOIN public.kanban_boards b ON col.board_id = b.id WHERE c.id = kanban_checklist_items.card_id AND (select public.is_org_member(b.org_id)) )); -- ── kanban_comments ── CREATE POLICY "Comments inherit card access" ON public.kanban_comments FOR SELECT TO authenticated USING (EXISTS ( SELECT 1 FROM public.kanban_cards c JOIN public.kanban_columns col ON c.column_id = col.id JOIN public.kanban_boards b ON col.board_id = b.id WHERE c.id = kanban_comments.card_id AND (select public.is_org_member(b.org_id)) )); CREATE POLICY "Users can insert own comments" ON public.kanban_comments FOR INSERT TO authenticated WITH CHECK ( user_id = (select auth.uid()) AND EXISTS ( SELECT 1 FROM public.kanban_cards c JOIN public.kanban_columns col ON c.column_id = col.id JOIN public.kanban_boards b ON col.board_id = b.id WHERE c.id = kanban_comments.card_id AND (select public.is_org_member(b.org_id)) ) ); CREATE POLICY "Users can update own comments" ON public.kanban_comments FOR UPDATE TO authenticated USING (user_id = (select auth.uid())); CREATE POLICY "Users can delete own comments" ON public.kanban_comments FOR DELETE TO authenticated USING (user_id = (select auth.uid())); -- ── kanban_labels ── CREATE POLICY "Labels accessible to org members" ON public.kanban_labels FOR ALL TO authenticated USING ((select public.is_org_member(org_id))); -- ── card_labels ── CREATE POLICY "Card labels inherit card access" ON public.card_labels FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.kanban_cards c JOIN public.kanban_columns col ON c.column_id = col.id JOIN public.kanban_boards b ON col.board_id = b.id WHERE c.id = card_labels.card_id AND (select public.is_org_member(b.org_id)) )); -- ── tags ── CREATE POLICY "Users can view tags in their orgs" ON public.tags FOR SELECT TO authenticated USING (org_id IN (select public.get_user_org_ids())); CREATE POLICY "Admins can manage tags" ON public.tags FOR ALL TO authenticated USING ((select public.is_org_admin(org_id))); -- ── card_tags ── CREATE POLICY "Members can manage card tags" ON public.card_tags FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.tags t WHERE t.id = card_tags.tag_id AND (select public.is_org_member(t.org_id)) )); -- ── teams ── CREATE POLICY "Users can view teams in their orgs" ON public.teams FOR SELECT TO authenticated USING (org_id IN (select public.get_user_org_ids())); CREATE POLICY "Admins can manage teams" ON public.teams FOR ALL TO authenticated USING ((select public.is_org_admin(org_id))); -- ── team_members ── CREATE POLICY "Users can view team members" ON public.team_members FOR SELECT TO authenticated USING (EXISTS ( SELECT 1 FROM public.teams t WHERE t.id = team_members.team_id AND (select public.is_org_member(t.org_id)) )); CREATE POLICY "Admins can manage team members" ON public.team_members FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.teams t WHERE t.id = team_members.team_id AND (select public.is_org_admin(t.org_id)) )); -- ── calendar_events ── CREATE POLICY "Members can manage calendar events" ON public.calendar_events FOR ALL TO authenticated USING ((select public.is_org_member(org_id))) WITH CHECK ((select public.is_org_member(org_id))); -- ── event_attendees ── CREATE POLICY "Members can manage event attendees" ON public.event_attendees FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.events e WHERE e.id = event_attendees.event_id AND (select public.is_org_member(e.org_id)) )); -- ── org_google_calendars ── CREATE POLICY "Members can view org calendar" ON public.org_google_calendars FOR SELECT TO authenticated USING ((select public.is_org_member(org_id))); CREATE POLICY "Admins can manage org calendar" ON public.org_google_calendars FOR ALL TO authenticated USING ((select public.is_org_admin(org_id))); -- ── activity_log ── CREATE POLICY "Users can view org activity" ON public.activity_log FOR SELECT TO authenticated USING ((select public.is_org_member(org_id))); CREATE POLICY "Users can insert own activity" ON public.activity_log FOR INSERT TO authenticated WITH CHECK (user_id = (select auth.uid())); -- ── user_preferences ── CREATE POLICY "Users can manage own preferences" ON public.user_preferences FOR ALL TO authenticated USING (user_id = (select auth.uid())); -- ── matrix_credentials ── CREATE POLICY "Users can read own matrix credentials" ON public.matrix_credentials FOR SELECT TO authenticated USING ((select auth.uid()) = user_id); CREATE POLICY "Users can insert own matrix credentials" ON public.matrix_credentials FOR INSERT TO authenticated WITH CHECK ((select auth.uid()) = user_id); CREATE POLICY "Users can update own matrix credentials" ON public.matrix_credentials FOR UPDATE TO authenticated USING ((select auth.uid()) = user_id); CREATE POLICY "Users can delete own matrix credentials" ON public.matrix_credentials FOR DELETE TO authenticated USING ((select auth.uid()) = user_id); -- ── events ── CREATE POLICY "Members can manage events" ON public.events FOR ALL TO authenticated USING ((select public.is_org_member(org_id))) WITH CHECK ((select public.is_org_member(org_id))); -- ── event_members ── CREATE POLICY "Members can manage event members" ON public.event_members FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.events e WHERE e.id = event_members.event_id AND (select public.is_org_member(e.org_id)) )) WITH CHECK (EXISTS ( SELECT 1 FROM public.events e WHERE e.id = event_members.event_id AND (select public.is_org_member(e.org_id)) )); -- ── event_roles ── CREATE POLICY "Members can manage event roles" ON public.event_roles FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.events e WHERE e.id = event_roles.event_id AND (select public.is_org_member(e.org_id)) )); -- ── event_departments ── CREATE POLICY "Members can manage event departments" ON public.event_departments FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.events e WHERE e.id = event_departments.event_id AND (select public.is_org_member(e.org_id)) )) WITH CHECK (EXISTS ( SELECT 1 FROM public.events e WHERE e.id = event_departments.event_id AND (select public.is_org_member(e.org_id)) )); -- ── event_member_departments ── CREATE POLICY "Members can manage member departments" ON public.event_member_departments FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_members em JOIN public.events e ON em.event_id = e.id WHERE em.id = event_member_departments.event_member_id AND (select public.is_org_member(e.org_id)) )); -- ── event_task_columns ── CREATE POLICY "Members can manage event task columns" ON public.event_task_columns FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.events e WHERE e.id = event_task_columns.event_id AND (select public.is_org_member(e.org_id)) )); -- ── event_tasks ── CREATE POLICY "Members can manage event tasks" ON public.event_tasks FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.events e WHERE e.id = event_tasks.event_id AND (select public.is_org_member(e.org_id)) )); -- ── department_dashboards ── CREATE POLICY "Members can manage department dashboards" ON public.department_dashboards FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON ed.event_id = e.id WHERE ed.id = department_dashboards.department_id AND (select public.is_org_member(e.org_id)) )); -- ── dashboard_panels ── CREATE POLICY "Members can manage dashboard panels" ON public.dashboard_panels FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.department_dashboards dd JOIN public.event_departments ed ON dd.department_id = ed.id JOIN public.events e ON ed.event_id = e.id WHERE dd.id = dashboard_panels.dashboard_id AND (select public.is_org_member(e.org_id)) )); -- ── department_checklists ── CREATE POLICY "Members can manage department checklists" ON public.department_checklists FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON ed.event_id = e.id WHERE ed.id = department_checklists.department_id AND (select public.is_org_member(e.org_id)) )); -- ── department_checklist_items ── CREATE POLICY "Members can manage dept checklist items" ON public.department_checklist_items FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.department_checklists dc JOIN public.event_departments ed ON dc.department_id = ed.id JOIN public.events e ON ed.event_id = e.id WHERE dc.id = department_checklist_items.checklist_id AND (select public.is_org_member(e.org_id)) )); -- ── department_notes ── CREATE POLICY "Members can manage department notes" ON public.department_notes FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON ed.event_id = e.id WHERE ed.id = department_notes.department_id AND (select public.is_org_member(e.org_id)) )); -- ── schedule_stages ── CREATE POLICY "schedule_stages_select" ON public.schedule_stages FOR SELECT TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON e.id = ed.event_id WHERE ed.id = schedule_stages.department_id AND (select public.is_org_member(e.org_id)) )); CREATE POLICY "schedule_stages_insert" ON public.schedule_stages FOR INSERT TO authenticated WITH CHECK (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON e.id = ed.event_id WHERE ed.id = schedule_stages.department_id AND (select public.is_org_editor(e.org_id)) )); CREATE POLICY "schedule_stages_update" ON public.schedule_stages FOR UPDATE TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON e.id = ed.event_id WHERE ed.id = schedule_stages.department_id AND (select public.is_org_editor(e.org_id)) )); CREATE POLICY "schedule_stages_delete" ON public.schedule_stages FOR DELETE TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON e.id = ed.event_id WHERE ed.id = schedule_stages.department_id AND (select public.is_org_editor(e.org_id)) )); -- ── schedule_blocks ── CREATE POLICY "schedule_blocks_select" ON public.schedule_blocks FOR SELECT TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON e.id = ed.event_id WHERE ed.id = schedule_blocks.department_id AND (select public.is_org_member(e.org_id)) )); CREATE POLICY "schedule_blocks_insert" ON public.schedule_blocks FOR INSERT TO authenticated WITH CHECK (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON e.id = ed.event_id WHERE ed.id = schedule_blocks.department_id AND (select public.is_org_editor(e.org_id)) )); CREATE POLICY "schedule_blocks_update" ON public.schedule_blocks FOR UPDATE TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON e.id = ed.event_id WHERE ed.id = schedule_blocks.department_id AND (select public.is_org_editor(e.org_id)) )); CREATE POLICY "schedule_blocks_delete" ON public.schedule_blocks FOR DELETE TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON e.id = ed.event_id WHERE ed.id = schedule_blocks.department_id AND (select public.is_org_editor(e.org_id)) )); -- ── department_contacts ── CREATE POLICY "department_contacts_select" ON public.department_contacts FOR SELECT TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON e.id = ed.event_id WHERE ed.id = department_contacts.department_id AND (select public.is_org_member(e.org_id)) )); CREATE POLICY "department_contacts_insert" ON public.department_contacts FOR INSERT TO authenticated WITH CHECK (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON e.id = ed.event_id WHERE ed.id = department_contacts.department_id AND (select public.is_org_editor(e.org_id)) )); CREATE POLICY "department_contacts_update" ON public.department_contacts FOR UPDATE TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON e.id = ed.event_id WHERE ed.id = department_contacts.department_id AND (select public.is_org_editor(e.org_id)) )); CREATE POLICY "department_contacts_delete" ON public.department_contacts FOR DELETE TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON e.id = ed.event_id WHERE ed.id = department_contacts.department_id AND (select public.is_org_editor(e.org_id)) )); -- ── budget_categories ── CREATE POLICY "Members can manage budget categories" ON public.budget_categories FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON ed.event_id = e.id WHERE ed.id = budget_categories.department_id AND (select public.is_org_member(e.org_id)) )); -- ── budget_items ── CREATE POLICY "Members can manage budget items" ON public.budget_items FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON ed.event_id = e.id WHERE ed.id = budget_items.department_id AND (select public.is_org_member(e.org_id)) )); -- ── sponsor_tiers ── CREATE POLICY "Members can manage sponsor tiers" ON public.sponsor_tiers FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON ed.event_id = e.id WHERE ed.id = sponsor_tiers.department_id AND (select public.is_org_member(e.org_id)) )); -- ── sponsors ── CREATE POLICY "Members can manage sponsors" ON public.sponsors FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON ed.event_id = e.id WHERE ed.id = sponsors.department_id AND (select public.is_org_member(e.org_id)) )); -- ── sponsor_deliverables ── CREATE POLICY "Members can manage sponsor deliverables" ON public.sponsor_deliverables FOR ALL TO authenticated USING (EXISTS ( SELECT 1 FROM public.sponsors s JOIN public.event_departments ed ON s.department_id = ed.id JOIN public.events e ON ed.event_id = e.id WHERE s.id = sponsor_deliverables.sponsor_id AND (select public.is_org_member(e.org_id)) )); -- ── sponsor_allocations ── CREATE POLICY "sponsor_allocations_select" ON public.sponsor_allocations FOR SELECT TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON e.id = ed.event_id WHERE ed.id = sponsor_allocations.department_id AND (select public.is_org_member(e.org_id)) )); CREATE POLICY "sponsor_allocations_insert" ON public.sponsor_allocations FOR INSERT TO authenticated WITH CHECK (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON e.id = ed.event_id WHERE ed.id = sponsor_allocations.department_id AND (select public.is_org_editor(e.org_id)) )); CREATE POLICY "sponsor_allocations_update" ON public.sponsor_allocations FOR UPDATE TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON e.id = ed.event_id WHERE ed.id = sponsor_allocations.department_id AND (select public.is_org_editor(e.org_id)) )); CREATE POLICY "sponsor_allocations_delete" ON public.sponsor_allocations FOR DELETE TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON e.id = ed.event_id WHERE ed.id = sponsor_allocations.department_id AND (select public.is_org_editor(e.org_id)) )); -- ── org_contacts ── CREATE POLICY "org_contacts_select" ON public.org_contacts FOR SELECT TO authenticated USING ((select public.is_org_member(org_id))); CREATE POLICY "org_contacts_insert" ON public.org_contacts FOR INSERT TO authenticated WITH CHECK ((select public.is_org_editor(org_id))); CREATE POLICY "org_contacts_update" ON public.org_contacts FOR UPDATE TO authenticated USING ((select public.is_org_editor(org_id))); CREATE POLICY "org_contacts_delete" ON public.org_contacts FOR DELETE TO authenticated USING ((select public.is_org_editor(org_id))); -- ── department_pinned_contacts ── CREATE POLICY "dept_pinned_contacts_select" ON public.department_pinned_contacts FOR SELECT TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON e.id = ed.event_id WHERE ed.id = department_pinned_contacts.department_id AND (select public.is_org_member(e.org_id)) )); CREATE POLICY "dept_pinned_contacts_insert" ON public.department_pinned_contacts FOR INSERT TO authenticated WITH CHECK (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON e.id = ed.event_id WHERE ed.id = department_pinned_contacts.department_id AND (select public.is_org_editor(e.org_id)) )); CREATE POLICY "dept_pinned_contacts_delete" ON public.department_pinned_contacts FOR DELETE TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON e.id = ed.event_id WHERE ed.id = department_pinned_contacts.department_id AND (select public.is_org_editor(e.org_id)) )); -- ── map_layers ── CREATE POLICY "Org members can view map layers" ON public.map_layers FOR SELECT TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON ed.event_id = e.id WHERE ed.id = map_layers.department_id AND (select public.is_org_member(e.org_id)) )); CREATE POLICY "Editors can insert map layers" ON public.map_layers FOR INSERT TO authenticated WITH CHECK (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON ed.event_id = e.id WHERE ed.id = map_layers.department_id AND (select public.is_org_member(e.org_id)) )); CREATE POLICY "Editors can update map layers" ON public.map_layers FOR UPDATE TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON ed.event_id = e.id WHERE ed.id = map_layers.department_id AND (select public.is_org_member(e.org_id)) )) WITH CHECK (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON ed.event_id = e.id WHERE ed.id = map_layers.department_id AND (select public.is_org_member(e.org_id)) )); CREATE POLICY "Editors can delete map layers" ON public.map_layers FOR DELETE TO authenticated USING (EXISTS ( SELECT 1 FROM public.event_departments ed JOIN public.events e ON ed.event_id = e.id WHERE ed.id = map_layers.department_id AND (select public.is_org_member(e.org_id)) )); -- ── map_pins ── CREATE POLICY "Org members can view map pins" ON public.map_pins FOR SELECT TO authenticated USING (EXISTS ( SELECT 1 FROM public.map_layers ml JOIN public.event_departments ed ON ml.department_id = ed.id JOIN public.events e ON ed.event_id = e.id WHERE ml.id = map_pins.layer_id AND (select public.is_org_member(e.org_id)) )); CREATE POLICY "Editors can insert map pins" ON public.map_pins FOR INSERT TO authenticated WITH CHECK (EXISTS ( SELECT 1 FROM public.map_layers ml JOIN public.event_departments ed ON ml.department_id = ed.id JOIN public.events e ON ed.event_id = e.id WHERE ml.id = map_pins.layer_id AND (select public.is_org_member(e.org_id)) )); CREATE POLICY "Editors can update map pins" ON public.map_pins FOR UPDATE TO authenticated USING (EXISTS ( SELECT 1 FROM public.map_layers ml JOIN public.event_departments ed ON ml.department_id = ed.id JOIN public.events e ON ed.event_id = e.id WHERE ml.id = map_pins.layer_id AND (select public.is_org_member(e.org_id)) )) WITH CHECK (EXISTS ( SELECT 1 FROM public.map_layers ml JOIN public.event_departments ed ON ml.department_id = ed.id JOIN public.events e ON ed.event_id = e.id WHERE ml.id = map_pins.layer_id AND (select public.is_org_member(e.org_id)) )); CREATE POLICY "Editors can delete map pins" ON public.map_pins FOR DELETE TO authenticated USING (EXISTS ( SELECT 1 FROM public.map_layers ml JOIN public.event_departments ed ON ml.department_id = ed.id JOIN public.events e ON ed.event_id = e.id WHERE ml.id = map_pins.layer_id AND (select public.is_org_member(e.org_id)) )); -- ── map_shapes ── CREATE POLICY "Org members can view map shapes" ON public.map_shapes FOR SELECT TO authenticated USING (EXISTS ( SELECT 1 FROM public.map_layers ml JOIN public.event_departments ed ON ml.department_id = ed.id JOIN public.events e ON ed.event_id = e.id WHERE ml.id = map_shapes.layer_id AND (select public.is_org_member(e.org_id)) )); CREATE POLICY "Editors can insert map shapes" ON public.map_shapes FOR INSERT TO authenticated WITH CHECK (EXISTS ( SELECT 1 FROM public.map_layers ml JOIN public.event_departments ed ON ml.department_id = ed.id JOIN public.events e ON ed.event_id = e.id WHERE ml.id = map_shapes.layer_id AND (select public.is_org_member(e.org_id)) )); CREATE POLICY "Editors can update map shapes" ON public.map_shapes FOR UPDATE TO authenticated USING (EXISTS ( SELECT 1 FROM public.map_layers ml JOIN public.event_departments ed ON ml.department_id = ed.id JOIN public.events e ON ed.event_id = e.id WHERE ml.id = map_shapes.layer_id AND (select public.is_org_member(e.org_id)) )) WITH CHECK (EXISTS ( SELECT 1 FROM public.map_layers ml JOIN public.event_departments ed ON ml.department_id = ed.id JOIN public.events e ON ed.event_id = e.id WHERE ml.id = map_shapes.layer_id AND (select public.is_org_member(e.org_id)) )); CREATE POLICY "Editors can delete map shapes" ON public.map_shapes FOR DELETE TO authenticated USING (EXISTS ( SELECT 1 FROM public.map_layers ml JOIN public.event_departments ed ON ml.department_id = ed.id JOIN public.events e ON ed.event_id = e.id WHERE ml.id = map_shapes.layer_id AND (select public.is_org_member(e.org_id)) ));