Hierarchy
Model real organizational structure inside an Environment — typed nodes, parent-child rules, and role assignments that cascade down the tree.
Overview
A hierarchy is a tree of typed nodes representing the organizational structure inside an Environment — regions, offices, departments, teams, or whatever shape your customers actually have. Every Environment starts with a single root node (flat RBAC); switching to hierarchy mode lets you add child nodes and assign roles at any depth. The shape is yours to define via the Environment's hierarchy_schema; Canopy enforces the schema on every node create and move and walks the tree at evaluate-time to resolve permissions through inheritance.
Scope
Hierarchies are scoped to an Environment
Each Environment owns its own independent tree, root node, and hierarchy_schema. Sibling envs in the same Application can carry completely different shapes — development can run hierarchy mode while production stays flat, or both can run hierarchy with different node-type vocabularies. The schema lives on environment.settings, not on the Application.
This is what makes safe iteration possible: you can model an entire org tree in Development, test the evaluator against realistic node depths, and only flip Production over when you're confident the shape holds.
Schema & Node Types
The hierarchy_schema defines the rules your tree has to follow. It lists every node_type a node can be (e.g. region, office, department, team), the allowed_children map (which types can sit beneath which), the max_depth, and the root_node_type. Canopy validates against the schema on every node create and every node move — an invalid parent-child combination or a move that exceeds max_depth is rejected with a 400 before any data changes.
The schema is mutable via PATCH .../hierarchy-schema, but Canopy refuses changes that would invalidate existing nodes — you can extend the vocabulary freely, you can't retroactively delete a node type that's currently in use.
Node Operations
Nodes are managed through the standard env-scoped endpoints — create under any valid parent, move to a new parent if the schema allows, delete leaves (or whole subtrees if the dashboard's confirm flow accepts it). When a node moves, every assignment at or below it moves with it, and inheritance recalculates automatically; there is no separate publish step.
The dashboard's Hierarchy page wraps these endpoints behind a drag-and-drop tree editor; client apps can integrate directly via the same routes on the public API surface.
Inheritance & Cascade
When you assign a role to an identity at a node, the role's permissions apply at that node and every descendant. Canopy resolves permissions at evaluate-time by walking up the lineage from the target node to the root, gathering every active assignment along the way, and unioning the permissions:
An identity needs only one assignment at the highest applicable level — no per-leaf duplication. Assign a Regional Manager role at the North America node and it covers every office, team, and identity beneath it. Move a subtree to a new parent and the assignments come along; the lineage walk picks up the new ancestor's roles automatically.
Reverting to Flat
An Environment in hierarchy mode can collapse back to flat at any time via POST .../revert-to-flat. The operation consolidates surviving assignments at the root node and deletes every non-root node — but it does not silently change anyone's effective access:
The response includes assignments_moved, assignments_deduplicated, assignments_expired_dropped, and nodes_deleted so the admin sees exactly what happened. The env's hierarchy_schema is cleared and access_model flips to flat only after the assignment consolidation completes.