Skip to main content

Agency RBAC Model

Purpose

This document describes the org RBAC model that is actually implemented today for the client-work slice.

Use it as a current-state contract, not as an aspirational permission matrix.

Implemented Role Model

The active org membership roles stored in orgUsers are:

  • owner
  • admin
  • account_manager
  • staff

These roles are real and are already used in membership resolution and client-scope checks.

Implemented Visibility Model

The current org client-work slice uses a two-part access model.

1. Org membership

The user must have an active orgUsers membership in the organization.

Without that, the org surface is not accessible.

2. Client visibility scope

Client visibility is resolved through clientAccessAssignments.

Current rule set:

  • owner has global client visibility in the organization
  • admin, account_manager, and staff are scoped by active assignment rows
  • there is no currently implemented non-owner all_clients mode in the client-work slice
  • if a non-owner has no active assignment rows, they see no client accounts in this slice

This is the key org visibility assumption the docs must preserve.

What The Current Capability System Actually Covers

The repo already has a real org capability system through:

  • orgRolePolicies
  • per-membership capabilityMode
  • per-membership capabilityOverrides

That system is currently strongest in these areas:

  • org settings and admin actions
  • billing access and billing write authority
  • portal/admin configuration actions

Important limitation:

The new client-work routes do not yet use a full dedicated client-work permission grammar. Older product docs that describe clients.view, project.updates.publish, or documents.request as enforced today are ahead of the implementation.

Current Client-Work Action Rules

These are the current rules in code.

Client accounts

  • visible to any active org member inside their client scope
  • create and edit are currently allowed for owner, admin, and account_manager
  • client-access assignment management is currently owner only

Projects

  • visible to any active org member inside their client scope
  • project creation is currently allowed for owner, admin, and account_manager
  • project detail and update publishing are not yet surfaced

Time

  • visible to any active org member inside their client scope
  • any active org member can create their own draft time entries in that scope
  • approval-style distinctions are not yet surfaced

Documents

  • visible to any active org member inside their client scope
  • any active org member can upload documents in that scope
  • richer document-management permissions are not yet surfaced

Billing

  • billing route access is controlled by the existing org capability system
  • client scope still applies after billing access is granted
  • billing is the most mature area of capability-based enforcement in this slice

Current Default Shape By Role

This is the real behavior to document today.

BehaviorOwnerAdminAccount ManagerStaff
Global client visibilityYesNoNoNo
Visible clients require clientAccessAssignmentsNoYesYesYes
Create/edit client accountsYesYesYesNo
Manage client assignmentsYesNoNoNo
Create projectsYesYesYesNo
Create own time entriesYesYesYesYes
Upload documentsYesYesYesYes
Billing accessYesDepends on org capabilitiesDepends on org capabilitiesDepends on org capabilities

What Is Not Yet True

Do not document these as shipped behavior yet:

  • dedicated client-work capability keys for every route and action
  • separate view/create/edit/publish rules for project updates
  • separate document request, visibility, and metadata-management permissions
  • separate time approval authority surfaced in the app

Those may still be the next design target, but they are not the current implementation contract. | projects.archive | Yes | Yes | No | No | | project.updates.view | Yes | Yes | Yes | Yes | | project.updates.create | Yes | Yes | Yes | No | | project.updates.edit | Yes | Yes | Yes | No | | project.updates.publish | Yes | Yes | Yes | No |

Files And Docs

CapabilityOwnerAdminAccount ManagerStaff
documents.viewYesYesYesYes
documents.uploadYesYesYesYes
documents.editYesYesYesNo
documents.manageYesYesNoNo
documents.requestYesYesYesNo
documents.visibility.manageYesYesNoNo

Time

CapabilityOwnerAdminAccount ManagerStaff
time.view_ownYesYesYesYes
time.view_allYesYesNoNo
time.createYesYesYesYes
time.edit_ownYesYesYesYes
time.edit_allYesYesNoNo
time.approveYesYesNoNo

Billing

CapabilityOwnerAdminAccount ManagerStaff
billing.viewYesYesYesNo
billing.invoice.createYesYesYesNo
billing.invoice.editYesYesYesNo
billing.invoice.sendYesYesNoNo
billing.invoice.voidYesNoNoNo
billing.subscription.viewYesYesYesNo
billing.subscription.manageYesYesNoNo
billing.connection.manageYesNoNoNo

Override Guidance

The owner can change non-owner defaults when the agency needs it.

Most common override examples:

  • allow an admin to remove staff or assign roles
  • allow an account manager to lose portal invite ability
  • allow a staff member to draft project updates
  • remove billing visibility from account managers in agencies that keep finance tightly restricted

A common starting point should look like this:

  • owner: all capabilities
  • admin: most operational capabilities, with financial and destructive capabilities based on owner choice
  • account manager: assigned-client operations with separate view, edit, publish, and finance toggles where those distinctions matter
  • staff: assigned-client work capabilities only, with read and write permissions split where operational risk differs

Hard Guardrails

Even with configurable permissions, some guardrails should remain.

  • owner always has full oversight
  • no billing permission means no billing visibility
  • client access does not automatically grant billing authority
  • a user should not manage clients they cannot access
  • permission design should stay understandable for a 1-to-10 person agency

Product Bias

Bias toward the most common small-agency pattern:

  • simple role templates
  • owner-controlled toggles
  • occasional user-specific exceptions

Do not start with blank-slate custom roles, deep inheritance trees, or enterprise policy builders.

Do start with capability names that are clean enough to survive implementation without a six-month refactor.