RLS & roles

Coming soon

This page is a placeholder for an upcoming topic — shipping alongside the client portal (Phase 3). The URL is stable, so any links you write today won't rot when the real page lands. For now, the `supabase/policies/` directory covers the closest live topic.

What it'll cover

The exact RLS policy attached to every public schema table, plus how the four user surfaces (/admin, /app portal, ingest API, unauthenticated marketing) actually authorize a query.

The short version today:

  • profiles, admins, org_members — RLS-respecting, controlled by who you're authenticated as via Supabase Auth.
  • access_requests — staff-only via the admin server actions.
  • clients, episodes, client_api_keys — service-role only in Phase 1. The admin UI accesses them through getSupabaseServiceClient() after a per-route role check; the ingest API does the same after validateApiKey() passes. The client portal (Phase 3) will add narrower RLS that lets a client read its own rows directly.
  • app_public_settings — public read (anon + authenticated), service-role write. This is what makes maintenance mode visible to the marketing edge proxy.

The canonical source is supabase/policies/ in the monorepo. Every new client-data table needs a policy file in the same PR as the migration, per AGENTS.md.

Why service-role for client data in Phase 1

It's a smaller blast radius. Phase 1 has no client portal — every read of clients / episodes / client_api_keys happens from trusted server code (admin Server Actions, ingest API route handlers) that's already verified the caller's role / API key. Adding RLS that mirrors those checks would duplicate logic without adding security.

When the client portal lands in Phase 3, we'll add per-client RLS so a client's browser session can read its own rows directly, without going through getSupabaseServiceClient().