Files
route-commerce/supabase/migrations/204_locations_public_read_policy.sql
T
tyler 49a9900d15 feat: add locations table + Locations tab in Stops & Routes
* New 'locations' table for reusable venues (Tractor Supply, Boot Barn,
  etc.) — each stop now links via stops.location_id while keeping the
  denormalized location text for backwards compat.
* 6 SECURITY DEFINER RPCs: admin_create_location, admin_create_locations_batch,
  admin_update_location, admin_delete_location, admin_attach_location_to_stop,
  get_locations_for_brand. Plus admin_list_locations for the admin tab.
* Backfill: 26 unique venues extracted from the 269 Tuxedo stops, all linked.
* Stops & Routes page now has tabs (Stops | Locations) via ?tab= query param.
  Locations tab has full CRUD UI: search, status filter, pagination, edit,
  delete, add-venue modal.
* StopsHeaderActions now tab-aware — Upload Schedule / Add Stop only show on
  Stops tab; Locations tab has its own Add Venue button inline.
2026-06-04 15:24:34 +00:00

20 lines
920 B
SQL

-- Migration 204: Add permissive read policy for locations
--
-- Why: The admin Stops & Routes page reads stops via the Supabase JS client
-- (anon key + RLS). The `stops` table has a `Public read stops` policy with
-- qual=true, which lets the anon role see all non-deleted stops — that's how
-- the page works in dev mode (no Supabase auth). The admin_locations tab needs
-- the same behavior so the server component can use the same pattern:
-- supabase.from("locations").select(...)
--
-- Brand scoping is enforced at the application layer in the server component
-- (eq("brand_id", adminUser.brand_id)), matching how stops are scoped.
--
-- Brand-scoped public reads (storefront pages) go through get_locations_for_brand
-- RPC, which filters active=true.
DROP POLICY IF EXISTS "Public read locations" ON public.locations;
CREATE POLICY "Public read locations" ON public.locations
FOR SELECT
USING (true);