Validate view-as tenants, scope service-role mutations by tenant_id, add documents RLS, refuse portfolio-wide data dumps, and block Meta publish when a Page/IG is linked to another client. Co-authored-by: Cursor <cursoragent@cursor.com>
45 lines
1.5 KiB
SQL
45 lines
1.5 KiB
SQL
-- Tenant isolation for editorial calendars and other documents.
|
|
-- Clients only see their own tenant_id; agency uses service role / viaView APIs.
|
|
|
|
alter table public.documents enable row level security;
|
|
|
|
drop policy if exists documents_tenant_select on public.documents;
|
|
drop policy if exists documents_tenant_insert on public.documents;
|
|
drop policy if exists documents_tenant_update on public.documents;
|
|
drop policy if exists documents_tenant_delete on public.documents;
|
|
|
|
create policy documents_tenant_select on public.documents
|
|
for select using (
|
|
tenant_id::text = coalesce(
|
|
auth.jwt() -> 'app_metadata' ->> 'tenant_id',
|
|
auth.jwt() -> 'user_metadata' ->> 'tenant_id'
|
|
)
|
|
);
|
|
|
|
create policy documents_tenant_insert on public.documents
|
|
for insert with check (
|
|
tenant_id::text = coalesce(
|
|
auth.jwt() -> 'app_metadata' ->> 'tenant_id',
|
|
auth.jwt() -> 'user_metadata' ->> 'tenant_id'
|
|
)
|
|
);
|
|
|
|
create policy documents_tenant_update on public.documents
|
|
for update using (
|
|
tenant_id::text = coalesce(
|
|
auth.jwt() -> 'app_metadata' ->> 'tenant_id',
|
|
auth.jwt() -> 'user_metadata' ->> 'tenant_id'
|
|
)
|
|
);
|
|
|
|
create policy documents_tenant_delete on public.documents
|
|
for delete using (
|
|
tenant_id::text = coalesce(
|
|
auth.jwt() -> 'app_metadata' ->> 'tenant_id',
|
|
auth.jwt() -> 'user_metadata' ->> 'tenant_id'
|
|
)
|
|
);
|
|
|
|
comment on table public.documents is
|
|
'Tenant-scoped docs (type=calendar RRSS plans, etc.). RLS: JWT tenant only; agency writes via service role.';
|