Skip to content

RLS Policy Reference ​

Overview ​

Row Level Security (RLS) is PostgreSQL's built-in mechanism for restricting which rows a given user can read or modify. LenserFight enables RLS on every table across all schemas. Policies are additive: a row is accessible if any matching policy grants access.

The service_role key bypasses RLS entirely and should only be used in trusted server-side contexts (Edge Functions, background jobs).

Auth Tiers ​

TierDescriptionRLS Behavior
anonUnauthenticated requests (public API key only)Restricted to explicitly public data
authenticatedLogged-in user with a valid JWTScoped to own data plus public data
service_roleServer-side key with elevated privilegesBypasses RLS completely

Policy Inventory ​

lensers Schema ​

profiles ​

OperationTierConditionNotes
SELECTanonAll rowsPublic profile data
SELECTauthenticatedAll rowsPublic profile data
INSERTauthenticateduser_id = auth.uid()User creates own profile
UPDATEauthenticateduser_id = auth.uid()User edits own profile
DELETE--Not allowedSoft-delete via deletion_requested_at

Soft-delete pattern: users set deletion_requested_at via UPDATE. A background job handles actual removal after a grace period.


content Schema ​

threads ​

OperationTierConditionNotes
SELECTanonvisibility = 'public'Public threads only
SELECTauthenticatedvisibility = 'public' OR lenser_id = lensers.get_auth_lenser_id()Own threads plus public
INSERTauthenticatedlenser_id = lensers.get_auth_lenser_id()Create own threads
UPDATEauthenticatedlenser_id = lensers.get_auth_lenser_id()Edit own threads
DELETEauthenticatedlenser_id = lensers.get_auth_lenser_id()Delete own threads

xp Schema ​

rules ​

OperationTierConditionNotes
SELECTanon / authenticatedAll rowsPublic reference data
INSERT / UPDATE / DELETEservice_role--Admin-managed only

events ​

OperationTierConditionNotes
SELECTauthenticatedlenser_id = lensers.get_auth_lenser_id()Own events only
INSERT--Via xp.apply() (SECURITY DEFINER)Never inserted directly

totals, levels, streaks, seasons ​

OperationTierConditionNotes
SELECTauthenticatedlenser_id = lensers.get_auth_lenser_id()Read own data
INSERT / UPDATE / DELETE--Managed by triggers and functionsNo direct writes

ai Schema ​

models ​

OperationTierConditionNotes
SELECTanon / authenticatedis_public = truePublic models only
INSERT / UPDATE / DELETEservice_role--Admin-managed

generations ​

OperationTierConditionNotes
SELECTauthenticatedlenser_id = lensers.get_auth_lenser_id()Own generations
INSERTauthenticatedlenser_id = lensers.get_auth_lenser_id()Create own

tenancy Schema ​

workspaces ​

PolicyOperationTierConditionNotes
members_select_own_workspacesSELECTauthenticatedUser is a member of the workspaceMembers can see their own workspaces
admin_update_workspaceUPDATEauthenticatedUser is admin/owner of the workspaceAdmin/owner can update workspace
authenticated_insert_workspaceINSERTauthenticatedowner_id = lensers.get_auth_lenser_id()Authenticated users can create workspaces they own

workspace_members ​

PolicyOperationTierConditionNotes
members_select_same_workspaceSELECTauthenticatedUser is a member of the same workspaceMembers can see co-members
admin_insert_membersINSERTauthenticatedUser is admin/owner of the workspaceAdmin/owner can add members
admin_delete_membersDELETEauthenticatedUser is admin/owner of the workspaceAdmin/owner can remove members

media Schema ​

objects ​

PolicyOperationTierConditionNotes
authenticated_select_own_or_publicSELECTauthenticatedOwner, public visibility, or workspace memberOwner, public, or workspace member
anon_select_publicSELECTanonvisibility = 'public'Public objects visible to anonymous
authenticated_insert_ownINSERTauthenticatedOwner + workspace memberOwner + workspace member can create
authenticated_update_ownUPDATEauthenticatedowner_id = lensers.get_auth_lenser_id()Owner can update
authenticated_delete_ownDELETEauthenticatedowner_id = lensers.get_auth_lenser_id()Owner can delete

attachments ​

PolicyOperationTierConditionNotes
authenticated_select_attachmentsSELECTauthenticatedParent object is accessible to userCan see if object is accessible
anon_select_public_attachmentsSELECTanonParent object is publicPublic object attachments visible to anon
authenticated_insert_attachmentsINSERTauthenticatedUser owns the parent objectObject owner can attach
authenticated_delete_attachmentsDELETEauthenticatedUser owns the parent objectObject owner can detach

lenses Schema ​

lenses ​

OperationTierConditionNotes
SELECTanonvisibility = 'public' AND status = 'published'Public published only
SELECTauthenticated(visibility IN ('public','community') AND status = 'published') OR lenser_id = ownerOwn + public/community
INSERTauthenticatedis_active_lenser(uid()) AND lenser_id = current_active_lenser_id()Active lenser check
UPDATEauthenticatedSame owner check in USING + WITH CHECKOwner only
DELETEauthenticatedSame owner checkOwner only

versions ​

OperationTierConditionNotes
SELECTanonParent lens is public + publishedVia public lens
SELECTauthenticatedParent lens owner OR public/community + publishedOwn + public
INSERTauthenticatedParent lens owned by callerCreate on own lens
UPDATEauthenticatedParent lens owned by caller AND version status = draftDraft only

version_parameters ​

OperationTierConditionNotes
SELECTanonParent lens is public + publishedVia public lens
SELECTauthenticatedParent lens owner OR public/community + publishedOwn + public
INSERTauthenticatedParent lens owned AND version is draftDraft only
UPDATEauthenticatedParent lens owned AND version is draftDraft only

parameters (DEPRECATED) ​

OperationTierConditionNotes
SELECTanonParent lens is public + publishedRead-only for all
SELECTauthenticatedParent lens owner OR public/community + publishedRead-only

Note: lenses.parameters is deprecated. Use lenses.version_parameters instead.

Grant Summary ​

Tableanonauthenticated
lensesSELECTSELECT, INSERT, UPDATE, DELETE
versionsSELECTSELECT, INSERT, UPDATE
parametersSELECTSELECT (read-only legacy)
version_parametersSELECTSELECT, INSERT, UPDATE, DELETE
version_resourcesSELECTSELECT, INSERT, DELETE

Common Patterns ​

lensers.get_auth_lenser_id() ​

A helper function that maps auth.uid() (Supabase auth UUID) to the internal lenser_id in the lensers.profiles table. Used in most authenticated policies to avoid repeated subqueries.

Immutable Votes ​

Votes cannot be updated. To change a vote, the user must DELETE their existing vote and INSERT a new one. This preserves an audit-friendly pattern and avoids partial-update edge cases.

Soft-Delete ​

Tables using soft-delete (rubrics, templates) include deleted_at IS NULL in their USING clauses. Rows with a non-null deleted_at are invisible to all non-service-role queries.