Staff roles and capabilities

Four roles — owner, admin, support, sales — each holding a named list of capabilities, resolved in one file so no route can quietly widen who gets in.

What it is

Every agency-panel surface asks for a capability (tenants.view, billing.view, tenants.impersonate, staff.manage…), never for a person or a role. A single module maps role to capabilities and answers the question once. The owner is resolved from source code before the database is consulted at all.

Also called: who can see my data · vendor access control · support permissions · platform roles · least privilege

See it
Staff roles and capabilities
CustomerBuildingAmountStatus
Marlin Hoover40×64 Shop$11,270Draft
Sutter Kline40×64 Shop$18,110Sent
Marlin Hoover30×40 Garage$4,810Approved
Sutter KlineHobby Shop$13,360Draft
Ronan PetschBarndominium$14,120Draft
The ROLE_CAPABILITIES table in platformAccess.ts rendered as a role x capability grid, with billing.view lit only for owner. Sample data — no customer information appears here.
How it works
  1. 1A route calls requirePlatformCapability('tenants.manage') — it never compares an email itself.
  2. 2The resolver short-circuits for the owner from code, then reads platform_staff for everyone else.
  3. 3Roles are presets, not per-person checkbox grids, so 'who can see customer billing?' stays a glance instead of a query.
  4. 4Admins deliberately do NOT hold billing.view: platform revenue is the owner's alone.
  5. 5Support holds tenants.view and tenants.impersonate — they can come into an account to help, and cannot change what anyone pays.
  6. 6The UI hides what a role cannot use; the server refuses it regardless.
Why we built it

The file opens with the incident: 'Before this, "may this person administer the platform?" was answered by ~40 route handlers each holding their own copy of the same email comparison. That is exactly the shape the July SEV-1 took: an authorization rule spread thin enough that widening it in one place looked local and turned out not to be.' The narrowing of admin is quoted too — 'the admins don't need to be able to see the money either.'

The problem
  • An authorization rule copied into forty handlers cannot be audited or safely widened.
  • A sales rep could otherwise read a customer's billing history while qualifying them.
  • The owner could be locked out of his own platform by a bad query or an empty table.
Sound familiar?
What you get
Every power a staff member holds is written down in one screen-sized table.
Money is visible to exactly one person by design.
Adding a role or moving a capability is one edit, not forty.

See it on your own jobs

Twenty minutes, your numbers, no slide deck. We’ll build one of your real buildings in front of you and send you the estimate link at the end — yours to keep either way.

or keep browsing features →