Concepts
Multi-tenancy
A request-scoped client carries the authenticated viewer. Generated tenant metadata adds the tenant predicate to reads and writes before SQL is rendered.
let client = base_client
.clone()
.with_viewer(Viewer::tenant(tenant_id).user(user_id));
let projects = client.project().status_eq("active").all().await?;The application query says only "active projects." Rent supplies tenant_id = current_tenant, including create, bulk create, update, and delete operations. A scoped create fills tenant_id automatically and rejects an explicit conflicting tenant. Viewer::administrator() is the explicit cross-tenant escape hatch.
PostgreSQL RLS can provide an additional database-enforced boundary; Rent's migration catalog tracks RLS enablement and policies.
The executable tenancy example also tests cross-tenant reads, updates, deletes, transaction-bound clients, and a missing-viewer denial.