Supabase RLS + Account Lifecycle Engineer
Mission
Enforce privacy and lifecycle rules at the data layer.
Hard requirements
- Private-profile access must be enforced by SQL policy/function, not just route guards.
- Deactivated and pending-deletion accounts must be hidden from non-owners across all reads.
- Deletion must be soft-first, purge-later.
- Sign-in during grace period must cancel pending deletion automatically.
- Legal data retention must be separated from removable content deletion.
Account lifecycle model
States
activedeactivatedpending_deletiondeleted
Transitions
active -> deactivateddeactivated -> activeactive -> pending_deletionpending_deletion -> activeon successful sign-in during grace windowpending_deletion -> deletedafter purge workflow completes
Do not allow direct public reads of deactivated, pending_deletion, or deleted accounts.
RLS approach
Profiles
Create policies so that:
- owner can select own profile for all non-deleted states needed for recovery
- approved followers can select full profile when subject is
activeandvisibility='private' - strangers can select only a restricted-shell projection for
active privateprofiles - everyone can select allowed public projection for
active publicprofiles - blocked viewers get no access or a safer unavailable result depending on product choice
Prefer:
- base tables highly restricted
- security-definer views/functions for controlled projections
Content tables
For threads, prompts, battles, follower lists, etc.:
active public-> visible by normal policyactive private-> visible only to owner and approved followers where policy says yesdeactivated/pending_deletion/deleted-> not visible to non-owner
Deletion model
Removable content
Define separate purge procedures for:
- threads
- prompts
- battle artifacts if removable
- social graph rows
- profile media not legally required
- search index documents
- cache/CDN invalidation records
Retained legal/compliance data
Retain separately:
- audit logs
- billing/financial records
- abuse/security evidence
- consent history where required
- minimal account tombstone record
pg_cron workflow
fn_schedule_account_deletion(profile_id)
- sets
account_status='pending_deletion' - sets
deletion_scheduled_for = now() + interval '30 days' - hides profile from non-owner reads immediately
fn_cancel_account_deletion_on_login(auth_uid)
- if linked profile is
pending_deletionand grace period not expired:- set
account_status='active' - nullify
deletion_scheduled_for - nullify
deleted_at - restore visibility behavior
- set
Call this on successful sign-in path or post-auth hook.
fn_purge_due_accounts()
Run from pg_cron.
Process accounts where:
account_status='pending_deletion'deletion_scheduled_for <= now()
Steps:
- lock target rows
- delete removable content
- preserve compliance records
- tombstone username if needed
- mark
account_status='deleted' - set
deleted_at=now()
Must be idempotent.
Security warnings
- Never expose pending deletion rows in public search.
- Never physically delete the main row before dependent cleanup finishes.
- Never rely on frontend logout/login timing for cancellation.
- Never mix compliance retention tables with user-facing profile tables.
Deliverables
Produce:
- RLS policy matrix
- security-definer function design
- pg_cron job plan
- purge order specification
- rollback / recovery strategy