Permissions & Roles
Who can do what in the Puck editor: confirmed as a real, structured system, not
guessed. This closes a gap flagged elsewhere in this documentation (the Drupal
comparison page previously said this was unconfirmed); found by reading
@pantheon-systems/puck-css’s content-type-templates feature directly, not
inferred from the dashboard UI.
The four content roles
ContentRole is a real, exported type: "admin" | "editor" | "author" | "junior-editor".
Permissions are computed per role via getPermissionsForRole(), documented directly
in the package’s own source:
| Role | Structural control (add/remove/move components) | Edit component props |
|---|---|---|
admin | Full access: can create/edit templates too | Yes |
editor | Pinned components locked (can’t move/delete); can add/remove non-pinned | Yes |
author | Same component permissions as editor | Yes |
junior-editor | None: no structural changes at all | Yes (props only) |
Pinned components are locked for every role, including admin. A pinned
component (one a Template author locked into place, see
Templates) can never be dragged or deleted by anyone
editing a page built from that template. Only structural control over
non-pinned components varies by role.
Two states override role entirely:
- Blank pages (no template):
admin/editorget full permissions;junior-editorstill gets none of the structural ones. - Historical versions: viewing a past version disables all structural permissions
for every role,
adminincluded: you can look, not edit, until you’re back on the current draft. See Publishing for how version history itself works.
How a role gets assigned
useResolveContentRole() auto-detects a user’s role by calling
GET /api/sites/{siteId}/auth/role against the CSS backend, mapping its response
onto the four ContentRole values:
| CSS backend role | Maps to ContentRole |
|---|---|
ADMIN | admin |
EDITOR | editor |
VIEWER | junior-editor (read-only structural access) |
NO_ACCESS | junior-editor (most restrictive) |
author has no backend mapping. The ContentRole type supports four values,
but the auto-resolution table above only ever produces three of them. Nothing in
the CSS backend’s role system maps to author. If a project needs that
permission tier, it has to be set explicitly (passing role="author" directly
rather than relying on auto-resolution). Worth confirming with Pantheon whether
there’s a backend-side way to assign it, or whether it’s meant purely as an
application-level override today.
If the backend role lookup fails or is unavailable, useResolveContentRole falls
back to a caller-supplied default role rather than failing closed or open silently.
Worth deciding deliberately what that fallback should be for a given site (probably
the most restrictive, junior-editor, not the most permissive).
WordPress / Drupal comparison
| P1 | WordPress | Drupal |
|---|---|---|
admin | Administrator | Full content permissions |
editor | Editor | A role with “edit any content” |
author | Author (own posts): unconfirmed whether P1’s author is similarly scoped to “own content only,” or just a fourth generic tier | A role with “edit own content” |
junior-editor | Contributor (needs approval to publish) | A restricted role |
Treat this table as a starting orientation, not a confirmed equivalence: unlike the Puck-side permission mechanics above (which are read directly from source), we haven’t independently verified whether P1’s roles carry WordPress’s own-content-vs-any-content distinction, or Drupal’s per-entity-operation granularity.
What’s still unconfirmed
- How are these roles actually assigned to a real user account? The dashboard presumably has a UI for this (inviting a teammate, setting their role), but nothing in the SDK surfaces that flow: this is a dashboard-only capability we haven’t walked through directly.
- Is there any permission granularity below “role” (per-branch, per-document,
or per-Template access control), or is a
ContentRolea single global setting per user per site? The types read above only show role-based component permissions inside the editor; nothing suggests a finer-grained ACL exists. - Does
author’s “own content only” behavior (if any) get enforced anywhere, or is the fourth tier purely a naming placeholder with identical behavior toeditortoday? The permission matrix (getPermissionsForRole) showsauthorandeditorcomputing identicalComponentPermissions: confirm whether that’s deliberate (they’re meant to differ only in something outside component permissions, like publish rights) or simply not yet differentiated.