Skip to main content

Overview

Within a project, you often need to model organizational structures: departments, teams, divisions, and reporting hierarchies. This guide shows how to represent these structures in Bedrock.
These patterns are typically implemented at the Project level, where authorization is configured. The examples below assume you’re working within a project’s scope.

Common Organizational Patterns

Flat Teams

Project
└── Environment (Production)
    ├── Engineering
    ├── Sales
    ├── Marketing
    └── Finance

Hierarchical Departments

Project
└── Environment (Production)
    ├── Engineering
    │   ├── Backend
    │   ├── Frontend
    │   └── DevOps
    ├── Product
    │   ├── Design
    │   └── Research
    └── Operations
        ├── HR
        └── Finance

Matrix Organization

Project
├── Departments (functional, as scopes)
│   ├── Engineering
│   └── Design
└── Cross-functional teams (as tags)
    ├── Team Alpha (eng + design)
    └── Team Beta (eng + design)

Approach 1: Scopes as Org Units

Model each organizational unit as a scope within your project:
# Define org unit scope types at the project level
curl -X POST 'https://api.example.com/scope-types/batch' \
  -d '[
    {"id": "type_department", "name": "Department", "config": {"permissionMode": "merge"}},
    {"id": "type_team", "name": "Team", "config": {"permissionMode": "merge"}}
  ]'

# Define hierarchy (departments under environments, teams under departments)
curl -X POST 'https://api.example.com/scope-type-hierarchy/batch' \
  -d '[
    {"parentTypeId": "type_environment", "childTypeId": "type_department"},
    {"parentTypeId": "type_department", "childTypeId": "type_team"}
  ]'

# Create departments under an environment
curl -X POST 'https://api.example.com/scopes/batch' \
  -d '[
    {"id": "scope_engineering", "typeId": "type_department", "name": "Engineering"},
    {"id": "scope_product", "typeId": "type_department", "name": "Product"}
  ]'

# Create teams under departments
curl -X POST 'https://api.example.com/scopes/batch' \
  -d '[
    {"id": "scope_backend", "typeId": "type_team", "name": "Backend"},
    {"id": "scope_frontend", "typeId": "type_team", "name": "Frontend"}
  ]'

# Link hierarchy
curl -X POST 'https://api.example.com/scope-hierarchy/batch' \
  -d '[
    {"parentScopeId": "scope_env_production", "childScopeId": "scope_engineering"},
    {"parentScopeId": "scope_env_production", "childScopeId": "scope_product"},
    {"parentScopeId": "scope_engineering", "childScopeId": "scope_backend"},
    {"parentScopeId": "scope_engineering", "childScopeId": "scope_frontend"}
  ]'

Pros

  • Natural permission inheritance
  • Clear hierarchy
  • Easy to query

Cons

  • Deep hierarchies can be complex
  • Harder to model matrix organizations

Approach 2: Tags for Org Classification

Use tags to classify users and resources by org unit:
# Create org tag groups at the project level
curl -X POST 'https://api.example.com/tag-groups/batch' \
  -d '[
    {"scopeId": "scope_project", "name": "Departments", "key": "departments"},
    {"scopeId": "scope_project", "name": "Teams", "key": "teams"}
  ]'

# Create tags
curl -X POST 'https://api.example.com/tags/batch' \
  -d '[
    {"tagGroupId": "tg_departments", "identifier": "engineering", "label": "Engineering"},
    {"tagGroupId": "tg_departments", "identifier": "product", "label": "Product"},
    {"tagGroupId": "tg_teams", "identifier": "backend", "label": "Backend"},
    {"tagGroupId": "tg_teams", "identifier": "frontend", "label": "Frontend"}
  ]'

# Tag users
curl -X POST 'https://api.example.com/tag-assignments/batch' \
  -d '[
    {"tagId": "tag_engineering", "targetType": "subject", "targetId": "subject_jane"},
    {"tagId": "tag_backend", "targetType": "subject", "targetId": "subject_jane"}
  ]'

Pros

  • Flexible many-to-many relationships
  • Easy to model matrix orgs
  • Users can belong to multiple teams

Cons

  • Requires conditional permissions
  • Less intuitive hierarchy
Combine scopes for major boundaries and tags for classification:
# Scopes for major org boundaries (under environment)
curl -X POST 'https://api.example.com/scopes/batch' \
  -d '[
    {"id": "scope_engineering", "typeId": "type_department", "name": "Engineering"},
    {"id": "scope_product", "typeId": "type_department", "name": "Product"}
  ]'

# Tags for teams and specializations (at project level)
curl -X POST 'https://api.example.com/tag-groups' \
  -d '{"scopeId": "scope_project", "name": "Teams", "key": "teams"}'

curl -X POST 'https://api.example.com/tags/batch' \
  -d '[
    {"tagGroupId": "tg_teams", "identifier": "backend", "label": "Backend"},
    {"tagGroupId": "tg_teams", "identifier": "frontend", "label": "Frontend"},
    {"tagGroupId": "tg_teams", "identifier": "platform", "label": "Platform"}
  ]'

Role Patterns

Department-Level Roles

# Roles defined at department level
curl -X POST 'https://api.example.com/roles/batch' \
  -d '[
    {"name": "Engineering Lead", "scopeId": "scope_engineering"},
    {"name": "Tech Lead", "scopeId": "scope_engineering"},
    {"name": "Engineer", "scopeId": "scope_engineering"}
  ]'

Team-Specific Roles

# Roles for specific teams
curl -X POST 'https://api.example.com/roles/batch' \
  -d '[
    {"name": "Backend Lead", "scopeId": "scope_backend"},
    {"name": "Frontend Lead", "scopeId": "scope_frontend"}
  ]'

Cross-Functional Roles

# Roles that span departments (defined at project level)
curl -X POST 'https://api.example.com/roles/batch' \
  -d '[
    {"name": "Project Manager", "scopeId": "scope_project"},
    {"name": "Scrum Master", "scopeId": "scope_project"}
  ]'

Permission Patterns

Department Access

# Engineers can access engineering resources
curl -X POST 'https://api.example.com/permissions' \
  -d '{
    "scopeId": "scope_engineering",
    "action": "read",
    "resourceType": "code",
    "resourcePattern": "*",
    "key": "code:read:*"
  }'

Tag-Based Team Access

# Users can access resources tagged with their team
curl -X POST 'https://api.example.com/permissions' \
  -d '{
    "scopeId": "scope_project",
    "action": "read",
    "resourceType": "document",
    "resourcePattern": "*",
    "key": "document:read:team-match",
    "logic": {
      "some": [
        {"var": "resource.tags.teams"},
        {"in": [{"var": ""}, {"var": "subject.tags.teams"}]}
      ]
    }
  }'

Matrix Organization Example

For organizations where people belong to both functional teams and cross-functional initiatives:
# Functional departments as scopes (under environment)
curl -X POST 'https://api.example.com/scopes/batch' \
  -d '[
    {"id": "scope_engineering", "typeId": "type_department", "name": "Engineering"},
    {"id": "scope_design", "typeId": "type_department", "name": "Design"}
  ]'

# Cross-functional initiatives as tags
curl -X POST 'https://api.example.com/tag-groups' \
  -d '{"scopeId": "scope_project", "name": "Initiatives", "key": "initiatives"}'

curl -X POST 'https://api.example.com/tags/batch' \
  -d '[
    {"tagGroupId": "tg_initiatives", "identifier": "alpha", "label": "Initiative Alpha"},
    {"tagGroupId": "tg_initiatives", "identifier": "beta", "label": "Initiative Beta"}
  ]'

# Jane is in Engineering AND on Initiative Alpha
curl -X POST 'https://api.example.com/memberships' \
  -d '{"subjectId": "subject_jane", "scopeId": "scope_engineering"}'

curl -X POST 'https://api.example.com/tag-assignments' \
  -d '{"tagId": "tag_alpha", "targetType": "subject", "targetId": "subject_jane"}'

# Permission: Access initiative resources if tagged with your initiative
curl -X POST 'https://api.example.com/permissions' \
  -d '{
    "scopeId": "scope_project",
    "action": "read",
    "resourceType": "initiative-doc",
    "resourcePattern": "*",
    "key": "initiative-doc:read:match",
    "logic": {
      "some": [
        {"var": "resource.tags.initiatives"},
        {"in": [{"var": ""}, {"var": "subject.tags.initiatives"}]}
      ]
    }
  }'

Reporting Hierarchies

For manager → report relationships:
# Store manager relationship in subject metadata
curl -X POST 'https://api.example.com/subjects' \
  -d '{
    "subjectType": "user",
    "externalId": "jane",
    "displayName": "Jane Doe",
    "meta": {
      "managerId": "subject_bob",
      "level": 3
    }
  }'

# Permission: Managers can view their reports' data
curl -X POST 'https://api.example.com/permissions' \
  -d '{
    "scopeId": "scope_project",
    "action": "read",
    "resourceType": "employee-data",
    "resourcePattern": "*",
    "key": "employee-data:read:manager",
    "logic": {
      "==": [{"var": "subject.id"}, {"var": "resource.meta.managerId"}]
    }
  }'

Best Practices

Create scopes where you need distinct permission sets or inheritance breaks.
Use tags when users/resources belong to multiple groups or relationships are fluid.
Very deep hierarchies are hard to manage. Consider flattening with tags.
Organizations change. Design for easy restructuring.

Next Steps