Developer Docs · 09

RBAC & Access Levels

Three distinct role systems gate the platform. Permissions are checked one way — User.has_permission — with resource.action strings.

Admin roles and access levels in the admin.
Admin roles and access levels in the admin.

Three role systems

SystemGatesSurfaced as
Coarse User.role enumbroad identity (user / admin / guest)
AdminRolethe admin app (/admin)“Roles”
AccessLevelthe user app (/user)“Access Levels”

Admin roles and user access levels are separate grant systems; the live check for both is User.has_permission(...).

Permission format

Permissions are resource.action strings — e.g. invoices.manage, cms.manage, settings.manage. Wildcards are supported (* = superadmin; cms.* = all CMS actions). Edit pages distinguish view from manage.

Declaring permissions from a plugin

# on the plugin object
permissions = [
    {"key": "myfeature.view",   "label": "View my feature"},
    {"key": "myfeature.manage", "label": "Manage my feature"},
]

# guard a route
@require_auth
@require_permission("myfeature.manage")
def update(): ...

GDPR

Never expose one user's personal data to another. Personal-data entities (users, user details, invoices) are GDPR-blocked from cross-entity search and are never broadcast on the event bus. Owner-scoped features must fail-closed: if an owner can't be resolved, deliver nothing.