Groundfloor Docs

SpiceDB Schema

The portal_* SpiceDB schema — definitions, relations, and permissions for Control Plane resources.

Control Plane stores authorization tuples in SpiceDB using the portal_* namespace. The canonical schema lives in the product repo as schema.zed.

Definitions

definition portal_user {}

definition portal_account {
  relation owner: portal_user
  relation billing_admin: portal_user
  relation member: portal_user

  permission administer = owner + billing_admin
  permission view_billing = administer
  permission manage_members = administer
  permission read = administer + member
}

definition portal_workspace {
  relation account: portal_account
  relation owner: portal_user
  relation admin: portal_user
  relation writer: portal_user
  relation member: portal_user

  permission administer = owner + admin + account->administer
  permission read = administer + writer + member
  permission write = administer + writer
  permission delete = administer + writer
  permission ddl = administer
  permission deploy = administer
  permission manage_members = administer
}

definition portal_environment {
  relation workspace: portal_workspace
  relation deployer: portal_user

  permission deploy = deployer + workspace->administer
  permission read = workspace->read
}

Permission inheritance

portal_account.administer
  └── portal_workspace.administer (via account->administer)
        └── portal_workspace.write / delete / ddl
        └── portal_environment.deploy (via workspace->administer)

Account owners inherit workspace administration. Workspace writer relations grant data-pillar mutations without full admin.

Write path

After a Postgres transaction commits (membership grant, workspace create, etc.):

  1. Control Plane writes the SpiceDB tuple via direct gRPC
  2. On failure, the tuple is enqueued to a DLQ (spicedb_write_failures)
  3. A background drain loop retries with exponential backoff
  4. An hourly drift reconciler re-TOUCHes membership tuples as a safety net

Customer data in Dataplane uses a separate schema namespace and optional permission projection at scale.

Schema changes

To add a relation or permission:

  1. Edit schema.zed in the Control Plane repo
  2. Push schema to SpiceDB
  3. Update app/auth/authorization.py closed vocabulary
  4. Migrate existing relationships if needed
  5. Land schema + code + docs in one change