D10 — RLS role provisioning & grants (code-verified)
Architecture decision record, relocated verbatim from the retired single-file
docs/tenancy/decision log. Status, thematic clusters, and how to record a new ADR: the decision log index.
tenants:rlscreates the RLS login role viaCREATE USER … LOGIN PASSWORD(Postgres defaults it toNOBYPASSRLS✓) and appliesENABLE+FORCE ROW LEVEL SECURITY($forceRls = true). FORCE means the table owner is also subject to RLS, so the central role must haveBYPASSRLSto see all tenants (localstablesis a superuser ⇒ fine; staging/prod set it explicitly instables-core-infra).grantPermissionsre-runs on everytenants:rlscall andGRANTs on all current tables, so the rule "runtenants:rlsafter every migration" also keeps grants current for new tables. Thereforetenants:rlsis added todocker/dev-start-app.shright aftermigrate, and the deploy pipeline runsmigrate --force && tenants:rls.- Hardening (tracked): the package
GRANTsALL(incl.TRUNCATE, which bypasses RLS and could wipe every tenant's rows) on existing tables to the RLS role. The app never issuesTRUNCATEin tenant context, but for least-privilege we override the schema manager to grant onlySELECT, INSERT, UPDATE, DELETE(+ sequence usage). See §3.