Skip to main content
Roles and data-access rules for a workspace live in a zite.permissions.json file at the workspace root. This is the schema reference; for the concepts and evaluation model, see Roles & permissions.

Structure

defaultPolicy is the master switch for roles, not a per-table default. Setting it to "deny" turns roles on: every rule is enforced, and any table without an allow rule is blocked. Any other value, including omitting the field or setting "allow", turns roles off and makes the entire file inert. The rules stay on disk, nothing is enforced, and there is no error to tell you.

Fields

  • version: always "1.0".
  • defaultPolicy: "deny" to enforce the file. See the warning above.
  • roles: your custom roles, each with a stable id and a display name. Rules reference roles by id, so renaming a role never invalidates a rule or a member’s assignment. Do not list the built-in roles here (see below).
  • tables: keyed by the table’s PascalCase SDK name, the string the generated client passes to createTableClient in .zite/db.ts ("Orders", not "orders"). Each entry has a rules array.
The permissions key is not the camelCase accessor you call in code. zite.orders is addressed as "Orders" here. A mis-cased key is still valid JSON and still passes validation, but it matches no table at runtime, so under "defaultPolicy": "deny" it silently grants nothing. See SDK names.

Built-in roles

Two roles exist on every workspace. They are virtual: reference their ids in rules, but never list them in the roles array. An entry carrying a built-in id and its exact name is stripped when the file is read, and a built-in id under any other name is rejected outright as a squat. builtin:all-users does not mean “signed in”. To require a session, set authenticated: true on the workflow or add a rowFilter on a userField.

Rules

Each rule is one role, one operation, and one optional filter. To grant a role several operations, write one rule per operation.
  • roleId: the id of a custom role, or a built-in id.
  • operation: one of read, create, update, delete.
  • rowFilter: restricts which rows the rule covers (like a Postgres USING clause).
Every rule is permissive. There are no deny rules: access is the union of the rules that match, and an operation with no matching rule is denied.
rowFilter does not apply to create. A create rule grants the operation outright, so enforce any constraint on new rows in your workflow.

Row filters

A comparison filter compares a record field to either a value from the signed-in user (userField) or a fixed staticValue (exactly one of the two) using eq, neq, contains, gt, gte, lt, or lte. Compose comparisons with and, or, and not. userField can reference the base user fields (id, email, firstName, lastName) plus any fields synced from your users table.

Example

Here every team member can read only the orders they own, while Managers can read, update, and delete all orders. Because defaultPolicy is deny, any table without rules is fully locked down.
Permissions are table- and row-level and govern the workspace database. There are no field-level permissions. Rules apply to internal and external apps alike. See Roles & permissions.