> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stackra.figentra.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 0208 — The IAM model: scope tree, roles, conditions and deny, delegation and permission names

> Accepted, amended by 0240, 0242, 0294, 0327, 0333, 0351 · 2026-10-20

> [!NOTE]
>
> Amended 2026-10-24 (STA-479) by
> [0351](https://docs.stackra.figentra.com/adr/0351-iam-conditions-on-a-dimension-another-service-owns-declared-dimensions-and-projections.md):
> a structured condition of decision 3 may also name a dimension another module or service owns and
> declares (a channel, a location, a market, a legal entity), tested on the record's dimension-id
> field and resolved in process against an event-fed projection of the owner's values; an
> unprojected, retired or unregistered value denies, and a retirement marks the grants that named it
> for the reviews of decision 7. Conditions stay structured, with no expressions. The other
> decisions stand.

> [!NOTE]
>
> Amended 2026-10-24 by [0333](https://docs.stackra.figentra.com/adr/0333-record-visibility-rules-who-can-see-which-records.md): a
> record visibility rule is a condition that the policy decision point evaluates under decision 3,
> with its audience taken from a scope node
> ([0327](https://docs.stackra.figentra.com/adr/0327-scope-package-owns-the-scope-tree-tenancy-is-a-consumer.md)), a segment
> ([0332](https://docs.stackra.figentra.com/adr/0332-stackra-segments-audiences-defined-by-rules.md)) or a role (decision 2). Decisions
> 1 to 7 stand unchanged.

> [!NOTE]
>
> Amended 2026-10-24 by [0327](https://docs.stackra.figentra.com/adr/0327-scope-package-owns-the-scope-tree-tenancy-is-a-consumer.md):
> the scope tree of decision 1 is held by `@stackra/scope`, not by `@stackra/iam`. IAM consumes the
> tree, and a grant or a role names a node of it. The levels that decision 1 names (platform,
> product and tenant) are the defaults of 0327, and a deployment may declare more levels as data.
> The tree is free code, and its depth is a plan entitlement
> ([0240](https://docs.stackra.figentra.com/adr/0240-scope-tree-is-free-code-with-depth-by-plan.md)). Decisions 2 to 7 stand unchanged.

> [!NOTE]
>
> Amended by [0294](https://docs.stackra.figentra.com/adr/0294-programming-model-v3-grammar-folders-identities-and-naming.md), the
> programming model v3: decision 2 is restated. A module declares its roles as
> `extends Role({ grants })` in its `access/` folder, and `grants` names `<Model>Permissions`
> statics. System roles are shipped this way. Gen checks each grant against the catalogue, and a
> system permission is never granted to a role. Decision 6 follows the amended
> [0132](https://docs.stackra.figentra.com/adr/0132-permissions-catalogue-and-policy-providers.md). Decisions 1, 3, 4, 5 and 7 are
> unchanged.
>
> Enforcement of this note: planned — STA-340 (gen checks: a role granting an unknown permission; a
> system permission granted to a role).

> [!NOTE]
>
> Supersedes decisions 4, 6 and 7 of [0087](https://docs.stackra.figentra.com/adr/0087-identity-and-iam-are-driver-packages.md),
> together with
> [0206](https://docs.stackra.figentra.com/adr/0206-zitadel-is-the-identity-provider-and-stackra-identity-is-provider-neutral.md). The
> scope tree is free code, and its depth is a plan entitlement (ADR 0240). This corrects the
> register's earlier "deep trees are Pro" line (C-04b).

> [!NOTE]
>
> The depth numbers in decision 5 are superseded by ADR 0240 and ADR 0242 (Starter 2, Pro 4,
> Business 8, Enterprise unlimited; no Free plan). The body is unchanged.

## Context

IAM decides who may do what in which scope. The owner's IAM answers (mem L594–595, L618–628, L878, 2026-10-20) define the scope tree, roles, conditions, delegation, and access reviews. The
scope-tree tier was first written as Pro and later changed to free code with plan-gated depth (L878, the later line wins).

## Decision

1. **Scope tree (A1).** A generic scope tree of platform, product, tenant, then levels declared by a product, on ltree. Grants inherit downward. The tree's shape is declared in code. **The tree is free code everywhere. Its depth is gated by the OS plan entitlement (ADR 0240).**
2. **Roles (A2).** System roles are shipped by modules. Tenants add custom roles. A grant is a role, a principal, a scope and an optional expiry.
3. **Conditions and deny (A3).** Structured conditions and explicit deny, with deny overriding allow, in the first release. No expressions.
4. **Delegation (A4).** A principal can delegate only at or below its own scope, and only roles it holds. Separation-of-duties role pairs are supported.
5. **Free and Pro lines (A7, as corrected).** Free: role-based access, custom roles, one level below the tenant, conditions and delegation. Paid entitlements: relationship-based access, separation-of-duties rules, unlimited depth, the edge decision point, and the OpenFGA and OPA adapters, which come later (Deferred in 0011, and 0227).
6. **Permission names (A10).** Are those of ADR 0132.
7. **Access reviews (A11).** Review campaigns run on a schedule.

## Consequences

* A tenant on the lowest plan still gets a usable hierarchy of one level, and it can grow by plan.
* A deny always wins, so a broad allow cannot override a specific restriction.

## Enforcement

planned — the IAM test suite checks deny-overrides-allow and the delegation bound; the depth limit is checked against the plan entitlement.

## Supersedes and sources

Supersedes: decisions 4, 6 and 7 of [0087](https://docs.stackra.figentra.com/adr/0087-identity-and-iam-are-driver-packages.md) (with [0206](https://docs.stackra.figentra.com/adr/0206-zitadel-is-the-identity-provider-and-stackra-identity-is-provider-neutral.md)).
Sources: owner IAM answers A1–A11 (`stackra-decisions-2026-10-19.md` L594–595, L618–628, 2026-10-20); the scope-tree answer (L878, 2026-10-20 night). Contradiction C-04b.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.