Skip to content

Organizations

MapexOS is multi-tenant by design. An organization represents a real operational boundary: ownership, permissions, data retention, and event visibility are scoped by organization.

Applies to v1.0.0 — Hierarchical organizations with RBAC, scope propagation, and inheritance controls.


Organization hierarchy

Organizations form a hierarchical tree structure representing the physical and logical structure of a tenant's environment.

Organization types

TypeDescriptionDepth
VendorRoot organization (top-level tenant)0
CustomerClient organization under a vendor1
SitePhysical location2
BuildingBuilding within a site3
FloorFloor level within a building4
ZoneSpecific area within a floor5

Hierarchy example

txt
Vendor: Acme Corp
└── Customer: Factory Alpha
    ├── Site: São Paulo Plant
    │   └── Building: Main Warehouse
    │       ├── Floor: Ground Floor
    │       │   ├── Zone: Loading Dock
    │       │   └── Zone: Storage Area
    │       └── Floor: Second Floor
    │           └── Zone: Office Area
    └── Site: Rio de Janeiro Plant
        └── Building: Distribution Center

Identifiers: orgId vs pathKey

MapexOS uses two identifiers for organizations:

IdentifierWhat it isWhat it is used for
orgIdStable unique ID for the organizationCRUD operations, references from assets/memberships
pathKeyHierarchical position (path)Descendant lookups, authorization scoping, and tree queries

PathKey (hierarchical identification)

Each organization has a PathKey that represents its position in the hierarchy using a hierarchical path format (Base36 encoded for efficiency).

PathKey structure

txt
000001                          → Vendor (root)
000001/000001                   → Customer (under Vendor)
000001/000001/0001              → Site (under Customer)
000001/000001/0001/0001         → Building (under Site)
000001/000001/0001/0001/0001    → Floor (under Building)
000001/000001/0001/0001/0001/01 → Zone (under Floor)

Why PathKey matters

  • Efficient range queries — Find all descendants using prefix matching (pathKey LIKE '000001/000001/%')
  • No recursive joins — Fetch entire subtrees without recursion
  • Audit visibility — Hierarchical context is visible in a single identifier
  • Scalable — Performs well with deep hierarchies

In practice, pathKey is commonly used for:

  • scoping “recursive” memberships
  • enforcing inheritance boundaries
  • filtering events/assets to a subtree

Access policies

Each organization defines an AccessPolicy that controls how permissions flow within the hierarchy.

AccessPolicy fields

FieldValuesDescription
RolePolicymerge / strictControls whether the org accepts inherited permissions from parent nodes
DefaultScopelocal / recursiveDefault scope suggested by the UI when creating memberships

RolePolicy behavior

ValueEffect
mergeAccepts inherited permissions from parent organizations
strictBlocks inheritance — only local memberships apply

Example

txt
Customer X (RolePolicy: merge)
├── Site SP (RolePolicy: merge)
│   └── Building A (RolePolicy: merge)
└── Site RJ (RolePolicy: strict)   ← Blocks inheritance
    └── Building B (RolePolicy: merge)

If a user has recursive access at Customer X:

  • Site SP — access granted (inherits from Customer X)
  • Building A — access granted (inherits through Site SP)
  • Site RJ — access denied (strict blocks inheritance)
  • Building B — access denied (parent blocked inheritance)

DefaultScope

DefaultScope is a UX helper only. It pre-fills the scope when creating memberships. It does not change authorization logic.


Identity and access (IAM)

MapexOS uses a Role-Based Access Control (RBAC) model with hierarchical organization support.

Core entities

EntityDescription
UserIndividual identity that authenticates and operates the platform
GroupCollection of users — assign permissions to groups to simplify governance
RoleReusable set of permissions (e.g., assets.read, rules.create)
MembershipConnects user/group + roles + organization + scope

Memberships

A Membership is the glue that connects assignees, organizations, and roles.

Membership components

ComponentDescription
AssigneeWho receives permissions (user or group)
OrganizationWhere permissions apply
RolesWhat permissions are granted
ScopeHow far permissions propagate

Scope behavior

ScopeEffect
localPermissions apply only to the specified organization
recursivePermissions apply to the org and all descendants

Membership JSON example

json
{
  "assigneeType": "user",
  "assigneeId": "user123",
  "orgId": "org111",
  "roleIds": ["role789"],
  "scope": "recursive"
}

Permission inheritance

When checking whether a user can perform an action in an organization:

  1. Local user memberships — direct memberships at the target organization
  2. Local group memberships — memberships assigned to groups the user belongs to
  3. Inherited permissions — if RolePolicy = merge, evaluate recursive memberships in ancestors

Recursive scope propagates only to descendants. It never crosses to sibling branches.

Inheritance flow

txt
User wants to access Building A


┌────────────────────────────────────┐
│ 1) Local user membership?          │
└────────────────┬───────────────────┘

      ┌──────────┴──────────┐
      │ NO                  │ YES
      ▼                     ▼
┌─────────────────────┐   ✅ ACCESS GRANTED
│ 2) Local group       │
│    membership?       │
└──────────┬──────────┘

    ┌──────┴──────┐
    │ NO           │ YES
    ▼              ▼
┌─────────────────────┐   ✅ ACCESS GRANTED
│ 3) Org accepts       │
│    inheritance?      │
│    (RolePolicy=merge)│
└──────────┬──────────┘

    ┌──────┴──────┐
    │ NO (strict) │ YES (merge)
    ▼             ▼
❌ ACCESS      ┌─────────────────────┐
   DENIED      │ 4) Any ancestor has │
               │    RECURSIVE        │
               │    membership?      │
               └──────────┬──────────┘

               ┌──────────┴──────────┐
               │ NO                  │ YES
               ▼                     ▼
          ❌ ACCESS              ✅ ACCESS
             DENIED                 GRANTED

Common operations (enterprise patterns)

Create a new Site under a Customer

Use the Customer as the parent organization, then create a child org of type Site. The new Site inherits defaults (policy and visibility) from its parent.

Grant recursive access to an Operations team

Create a Group (e.g., ops) and assign a membership at the Customer or Site level with scope = recursive. This grants access to all descendants without duplicating memberships.

Isolate sensitive locations (strict boundary)

Set RolePolicy = strict on a Site or Building that must be isolated (e.g., clinics, restricted labs). This blocks inherited permissions from parent organizations.


Enterprise governance

Data isolation

  • Tenants are isolated by the organization hierarchy.
  • Users can only access organizations where they have memberships (direct or inherited).
  • Subtree queries leverage pathKey to enforce boundaries efficiently.

Best practices

PracticeRecommendation
Prefer groupsUse group-based memberships for enterprise clients
Avoid excessive recursionUse recursive scope at the appropriate level (not always at root)
Use strict where requiredApply strict policy for hard isolation boundaries
Audit routinelyReview memberships and group composition periodically

Next steps

Business Source License (BSL 1.1)