Appearance
0006 — Two-plane RBAC with reconciled role model ​
Status: Accepted — extended by ADR 0023 (2026-06-18: adds comms_author) and extended by ADR 0037 (2026-06-23: adds infra_admin at level 7, promotes ministry_leader to level 6, adds media_steward, and adds five homeschool portal roles). The two-plane model and core server-side enforcement principle are unchanged.
Date: 2026-06-17
ADO work item: AB#3073
Deciders: Kristopher Turner (platform owner)
Context ​
The platform has two distinct authorization concerns that must never be conflated:
- Plane 1 — Infrastructure access: operators and CI/CD systems touching Azure, GitHub, ADO, and Key Vault. This is where Microsoft Entra is used. Governed by Azure RBAC + Entra roles + managed identities with least-privilege assignments.
- Plane 2 — Application authorization: community members accessing platform features based on their ministry role. This has nothing to do with Entra.
A known inconsistency existed between database/schema.sql (four permission levels) and docs/internal/overview/ministry-leadership-overview.md / README (five Main-Hub roles). This ADR reconciles them into one canonical model.
Decision ​
Plane 1 (infrastructure): Azure RBAC + Entra. Only platform operators and CI/CD service principals are Entra identities. No community member ever holds an Entra role.
Plane 2 (application): canonical roles enforced server-side in the API only (five at acceptance; a sixth,
comms_author, added by ADR 0023 — see the role table). The client never sends a role claim that the server trusts. A Clerk JWTsubclaim maps to aUsersrow; the server readsUsers.rolefrom the database for every authorization check.
Canonical role model (Plane 2) ​
Updated by ADR 0037 (2026-06-23). The table below reflects the complete role set after that expansion. See ADR 0037 for full rationale, migration details, and authorization middleware consequences.
Roles are divided into two types:
- Ordinal roles carry a numeric permission level.
requireRole(minLevel)checks pass for any user whose level is greater than or equal tominLevel. - Feature roles carry permissionLevel 0. They are treated as
member-level in ordinal checks. UserequireAnyRole()for feature-specific endpoint guards.
| Role | Slug | Level | Type | Description |
|---|---|---|---|---|
| Infrastructure Admin | infra_admin | 7 | ordinal | Added by ADR 0037. Infrastructure and platform operators. God-mode access. Not for community administration. |
| Ministry Leader | ministry_leader | 6 | ordinal | Minister. Level promoted from 4 → 6 by ADR 0037. Community spiritual and ministry authority; passes all admin-level checks. |
| Community Admin | admin | 5 | ordinal | Day-to-day community administration; member approval authority; all community configuration. |
| (reserved) | — | 4 | — | Level 4 is reserved for future use. |
| Small Group Leader | group_leader | 3 | ordinal | Manages their assigned small group. |
| Member | member | 2 | ordinal | Standard access; family management (with approval). |
| Visitor / Prospective | visitor | 1 | ordinal | Approval-gated; minimal read access only. |
| Sermon and Music Manager | media_steward | — | feature | Added by ADR 0037. Manages worship media uploads, music library, and sermon content. Scoped to the Sermons and Music portal. |
| Communications Author | comms_author | — | feature | Added by ADR 0023 (2026-06-18). Drafts Announcements and submits to the approval queue. Cannot approve, reject, or publish. Scoped to Announcements only. |
| Homeschool Administrator | homeschool_admin | — | feature | Added by ADR 0037. Administrates the homeschool program. Capabilities TBD when homeschool portal is built. |
| Homeschool Teacher | homeschool_teacher | — | feature | Added by ADR 0037. Teaches classes in the homeschool program. Capabilities TBD. |
| Homeschool Advisor | homeschool_advisor | — | feature | Added by ADR 0037. Advises and counsels students and families. Capabilities TBD. |
| High School Student | highschool_student | — | feature | Added by ADR 0037. Enrolled in the once-weekly high school program. Capabilities TBD. |
| Homeschool Student | homeschool_student | — | feature | Added by ADR 0037. Base homeschool portal access. Capabilities TBD. |
The model is thirteen Plane-2 roles as of 2026-06-23 (six ordinal, seven feature). Children are a sub-account type (see ADR 0007), not a separate role — they inherit a restricted scope of the member role as defined by their parent's approval settings.
How a social-login subject maps to an app user + role ​
- Clerk validates the Apple/Google token and issues a session JWT containing the provider
subclaim. - On first sign-in, the API creates a
Usersrow withcredential_type = 'social',role = 'visitor', andstatus = 'pending_approval'. - A minister reviews and approves the user — the API updates
Users.roleandUsers.status. - On subsequent API calls, the server reads
Users.rolefrom the database. The JWT'ssubis the only trusted claim from the client; the role is never trusted from the client.
Alternatives considered ​
| Option | Pros | Cons | Why not chosen |
|---|---|---|---|
| Five roles, server-side enforcement (chosen) | Matches the ministry's actual structure; Visitor role enables approval-gated onboarding | Requires schema update (four → five roles) | — chosen |
| Four roles (schema as-is, no Visitor) | No schema change | Loses the ability to represent prospective members in the DB before approval | Approval workflow requires a Visitor/pending state |
| ABAC (attribute-based) | Fine-grained; composable | Significantly more complex to implement and reason about | Not justified for a community of ~200 with well-defined roles |
| Client-asserted roles (JWT claims only) | Less DB lookups | Fundamental security anti-pattern — clients cannot be trusted | Hard security requirement |
Consequences ​
Positive ​
- Clean separation: Entra never appears in community member auth flows; application roles never appear in Azure RBAC.
- Server-side enforcement means a compromised client cannot escalate privileges.
- The five-role model matches the ministry leadership structure as documented — no translation layer needed.
- The Visitor role enables a clean approval-gated onboarding flow without special-casing.
Negative / trade-offs ​
database/schema.sqlmust be updated: four permission levels → five canonical roles. This is a Phase 2 migration. (The Role enum was further extended by ADR 0037 via Prisma migration20260623000000_rbac_role_expansion.)- Every API endpoint must perform a
Users.rolelookup (or cache it in the session). Mitigation: includerolein the server-side session object after auth; do not re-query on every request.
Risks ​
- Role escalation via DB — if a row in
Userscan be updated by a non-admin, privilege escalation is possible. Mitigation: role updates are admin-only API operations; no endpoint allows a member to self-modify their role. - Child scope creep — children's access must be explicitly bounded by parent approval, not just by role. The application layer must enforce per-section access controls on top of the role check for
member-scoped child sub-accounts.
References ​
- Platform strategy — RBAC section
- ADR 0003 — Authentication: Clerk — JWT
sub→ Users row mapping - ADR 0007 — Account & Family-Group identity — child sub-account scope
- ADR 0023 — Communications authoring and approval — adds
comms_author - ADR 0037 — RBAC role expansion — adds
infra_admin, promotesministry_leader, addsmedia_stewardand homeschool roles database/schema.sql— requires update in Phase 2 (four → five roles); further extended by ADR 0037