Groundfloor Docs

ReBAC Model

Platform membership roles, environment deployers, and how SpiceDB enforces actions — separate from app end-user roles.

Control Plane authorization is relationship-based (ReBAC), enforced by SpiceDB. Role names like owner and member are stored as relationships; API handlers check a closed action vocabulary against resource types.

Three role planes (do not mix)

PlaneWhoWhere you manage itEnforced by
Platform membershipPortal users on accounts/workspacesMembers & RolesSpiceDB portal_*
Environment deployerPortal users allowed to deploy to an envSpiceDB portal_environment (often via workspace admin)SpiceDB
Workspace site auth (app roles)End users of your productAuthenticationPer-workspace IdPlane / external IdP

Platform and app roles share labels like “admin” in casual speech — they are not the same grants.

Resource types

SpiceDB typeMaps toTypical scope
portal_userHuman portal userSubject of platform checks
portal_accountAccount (billing org)Top-level tenant
portal_workspaceWorkspaceData + apps + coderunners boundary
portal_environmentEnvironmentDeploy / promote target

Types are prefixed portal_ because SpiceDB is shared with Dataplane tenant schemas.

Platform membership roles

Users hold roles on accounts and workspaces via SpiceDB relationships (synced from memberships rows):

RoleTypical scopeGrants (conceptually)
owneraccount, workspaceFull administration
billing_adminaccount onlyBilling + account administer
adminaccount, workspaceAdminister resources and members
writeraccount, workspaceRead + write + delete on data pillars
memberaccount, workspaceRead access
partneraccount, workspaceRead-only external collaborator (portal membership)

Exact permission math lives in the SpiceDB schema. Handlers never trust the role string alone — they call check(action, …).

Environment deployer

RelationOnGrants
deployerenvironmentdeploy on that environment (plus anyone with workspace administer)

This is a platform relationship for deploy/promote targets — not an app end-user role.

Closed action vocabulary

Handlers call check(action, resource_type, resource_id) with one of:

ActionValid on
administeraccount, workspace
readaccount, workspace, environment
writeworkspace
deleteworkspace
ddlworkspace
deployworkspace, environment
manage_membersaccount, workspace
view_billingaccount

A 403 means SpiceDB denied the action — the JWT was valid but the user lacks the relationship.

Adding a new action requires a schema change, authorization code update, and documentation — all in the same change. See SpiceDB schema.

How checks run

PathSpiceDB consulted?
GET /v1/workspaces/{id}Yes — per-record check
GET /v1/workspaces (my workspaces)Indirect — filtered via memberships table
Workspace pillar APIsYes — action per endpoint

Control Plane talks to SpiceDB via direct gRPC — not through Dataplane.

Customer Portal mapping

Portal areaTypical action
Accounts listread on account
Create workspaceadminister on account
Data Vault writewrite on workspace
Secrets revealread + audited
Members add/revokemanage_members
Mint LLM virtual keyadminister on workspace
Workspace auth settingsadminister on workspace

On this page