External applications bring their own hierarchy

Some applications do not exist inside a single account — they are shaped like an organization chart of their own. A retail platform (call it Broit Portal) runs area companies, cities, and stores; a factory suite runs plants, lines, and cells. DotID lets such an application own its hierarchy and map it onto the organization structure, instead of flattening the business into one account per subsidiary with hand-managed grants.

The model

Your application’s hierarchy

DotID object

The application itself

an organization (/identity/v1/orgs)

Top-level grouping (headquarters)

root OU of the organization

Region / area company

OU under the root

City / district

OU under the area

Store / plant / site

OU under the city

Each store’s identity on the platform

an account inside the store OU

The account is the only object your application creates for its sites; the hierarchy above it is entirely OUs. Grants are OU-scoped assignments: a permission set assigned to an OU reaches every account under that OU. Reach is decided at assignment time by looking up the account’s OU ancestry — there is no stored foreign key from the account to a grant, so moving an account between OUs changes what it can do with no grant bookkeeping.

See hierarchical-access for the OU-assignment mechanics and the policy simulator for how the PDP resolves an account’s OU chain. The full design rationale is DID-0069.

When to use this pattern

  • Your application has a stable, hierarchical shape (areas → cities → stores).

  • Access to platform resources should follow the hierarchy: everyone in a store shares the store’s capabilities, managers in an area see all its stores.

  • You want to delegate administration of a subtree to a regional company without handing over the whole organization.

Per-account assignments still make sense for one-off grants; the OU-scoped model replaces the bulk of per-account work, not the exceptional case.

What the example proves

The runnable example at examples/external-app-own-hierarchy drives this whole pattern against the live platform through the published API and the fgai CLI only — no internal endpoints, no privileged shortcuts:

  • the application creates its own org with a root OU and a full area → city → store subtree, and an account per store;

  • a store staff principal (workforce user) can operate only inside the store’s account;

  • an area-company workforce principal manages every account under the area OU through one OU-scoped assignment;

  • the application hands a delegated administrator to an area company — the delegatee account is placed in a sibling subtree (not inside the delegated subtree, which the platform refuses), scoped to the delegated permission sets, and capped by a permission boundary;

  • every grant is verified end-to-end with the CLI’s authorize check, including the IC-session path where the credential was minted for an OU-assigned permission set.

Status: the delegated-administrator leg authors inside an org member account by first assuming the OrganizationAccountAccessRole bootstrap role that account materialization provisions (DotID#291 — landed and deployed): fgai identity sts assume-role --body '{"role_frn":"frn:<account>:iam:role/OrganizationAccountAccessRole","role_session_name":"…"}' (snake_case on the wire), then runs the account-scoped commands under the minted ASIA credential. The example exercises the leg adaptively: it completes when the role is live, and otherwise records the observed gap and reports the affected checks as skipped.

Ordering rules that hold

  • A delegatee account must not sit inside the subtree being delegated to it — create the delegatee account in a sibling subtree at the same level.

  • A permission set used in an OU-scoped assignment must exist before the assignment references it.

  • Accounts are materialized when you grant them an operator; until then they are placeholders. Placeholder hierarchy can be torn down freely; a materialized account must be closed (terminal state) before it disappears.