From 5c7c4a1581667028d8529e2b545705c142239de8 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 29 Aug 2026 14:24:09 +0000 Subject: [PATCH] docs(configure): define the org-membership tier vocabulary on the users page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `sys_member.role`'s four tiers (`owner`, `admin`, `delegated_admin`, `member` — ADR-0108) were used on two pages and defined on none, so a reader who met `delegated_admin` had nowhere in the corpus to go. Add a dedicated "Organization-membership tiers" section to `configure/users.mdx` — the page that already lists `sys_member` among the objects it covers. The section gives each tier a one-line meaning, states that a tier is a grade deciding what you can reach rather than a bundle of what you may do, separates `delegated_admin` from the `adminScope` mechanism documented as "Delegated administration" on the permission-sets page, and separates `sys_member` from the `sys_business_unit_member` org-tree placement the page already covers. The two consuming pages (`configure/notifications.mdx`, `build/automation/approvals.mdx`) now link to it. Those are link-only edits: no word is added or removed, only re-wrapped. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_016TUrhcggSFrYctvp5dsV1A --- content/docs/build/automation/approvals.mdx | 7 +-- content/docs/configure/notifications.mdx | 3 +- content/docs/configure/users.mdx | 57 +++++++++++++++++++++ 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/content/docs/build/automation/approvals.mdx b/content/docs/build/automation/approvals.mdx index 35b0fe2..964b9ce 100644 --- a/content/docs/build/automation/approvals.mdx +++ b/content/docs/build/automation/approvals.mdx @@ -74,7 +74,7 @@ Each entry in `approvers` names a `type` and a `value`: | `team` | Members of a flat collaboration team | | `field` | The user id held in a field on the triggering record | | `user` | One named user id | -| `org_membership_level` | An org-membership tier (`owner` / `admin` / `delegated_admin` / `member`) | +| `org_membership_level` | An [org-membership tier](/docs/configure/users#organization-membership-tiers) (`owner` / `admin` / `delegated_admin` / `member`) | | `expression` | A CEL expression resolved at node entry — see below | Prefer the indirect bindings (`manager`, `position`, `department`, @@ -84,8 +84,9 @@ should no longer see them. > **Warning — `position` vs the membership tier.** > `{ type: 'position', value: 'finance_manager' }` routes to the holders of a -> position (`sys_user_position`). The org-membership tier (`sys_member.role`: -> `owner`/`admin`/`delegated_admin`/`member`) is addressed as +> position (`sys_user_position`). The +> [org-membership tier](/docs/configure/users#organization-membership-tiers) +> (`sys_member.role`: `owner`/`admin`/`delegated_admin`/`member`) is addressed as > `type: 'org_membership_level'` since 16.0; the old spelling `role` is a > **deprecated alias for one release** — it still loads and resolves > identically, with a warning, and is removed in the next major. A position name diff --git a/content/docs/configure/notifications.mdx b/content/docs/configure/notifications.mdx index 5788af1..28b47e3 100644 --- a/content/docs/configure/notifications.mdx +++ b/content/docs/configure/notifications.mdx @@ -134,7 +134,8 @@ selector string goes through the same resolver. Whether either belongs in a standing subscription is an open question the platform has not settled. > **`role:` here means the organization-membership tier, not a job function.** -> The tiers are `owner`, `admin`, `delegated_admin`, and `member` — the standing +> The tiers are [`owner`, `admin`, `delegated_admin`, and +> `member`](/docs/configure/users#organization-membership-tiers) — the standing > a user holds in the organization. Job function is a > [position](/docs/configure/permissions/positions), and position names are not > addressable here: `role:sales_manager` matches nobody. *Role* is retired diff --git a/content/docs/configure/users.mdx b/content/docs/configure/users.mdx index a34ee70..94d5d46 100644 --- a/content/docs/configure/users.mdx +++ b/content/docs/configure/users.mdx @@ -87,6 +87,63 @@ breakdown. Payloads, password policies, and phone-only accounts are covered in [Authentication → Admin user management](/docs/configure/authentication#admin-user-management-objectstack-143). +## Organization-membership tiers + +Every membership row (`sys_member`) carries a **tier** — the standing a +user holds in the organization. The vocabulary is closed and owned by +the platform (ADR-0108): these four values, and nothing an app declares +widens them. + +| Tier | What it means | +|---|---| +| `owner` | Top standing in the organization. May invite at any tier, and is the only tier that may remove another owner | +| `admin` | Administers the organization. May invite at any tier except `owner` | +| `delegated_admin` | May issue organization invitations **without** being an org admin. That reach is the whole of it — the tier itself resolves to no permissions; see below | +| `member` | Ordinary standing. No administrative reach; access arrives through positions and permission sets, like everyone else's | + +> **Two different records are called a "membership" on this page.** +> `sys_member` answers *which organization do you belong to, and at what +> tier*. `sys_business_unit_member` — +> [the next section](#place-people-in-the-org-tree-memberships) — +> answers *which business unit do you sit in*. Placing someone in the +> org tree changes no tier, and changing a tier places nobody. + +The tier is chosen on the invitation (`sys_invitation.role`) and stored +on the membership row (`sys_member.role`). Both fields are the same +fixed four-value select, so an application's own business role +(`sales_manager`) cannot be stored in either, and an invitation naming +one is rejected before any row is written. Job function is a +[position](/docs/configure/permissions/positions). + +Two rules bound who may hand out which tier: an invitation may never +confer a tier above the issuer's own, and an issuer below `admin` may +invite only as `member`. + +**A tier is a grade that decides what you can *reach* — never a bundle +of what you may *do*.** The visible power of `owner` and `admin` comes +from a separate mechanism: memberships at those two tiers are +automatically granted an organization-admin permission set scoped to +that organization. That permission set carries the authority; the tier +only decides who receives it. + +### `delegated_admin` is not delegated administration + +Two mechanisms with near-identical names. Reaching for the wrong one is +the mistake this section exists to prevent: + +| | `delegated_admin` (a membership tier) | [Delegated administration](/docs/configure/permissions/permission-sets#delegated-administration) (a permission set) | +|---|---|---| +| Lives on | `sys_member.role` | An `adminScope` carried by a permission set | +| Answers | *Can you reach the invitation flow at all?* | *What may you actually grant* — which business units, which permission sets | +| On its own | Lets you invite a plain member, and place nobody | Lets you administer through the ordinary assignment path, but not issue invitations | + +The two are **doubly opt-in and independent**: someone must set the +membership tier **and** grant an `adminScope` before a scoped delegate +can issue an invitation that also places the new person in a business +unit with positions. Granting one is not granting the other — holding +`delegated_admin` confers none of the powers listed under +[delegated administration](/docs/configure/permissions/permission-sets#delegated-administration). + ## Place people in the org tree (memberships) Placing a person in the org tree is a separate record: a **Business