v0.85.0: site-declared role vocabularies over three capability levels
The extensible-roles window: sites now declare their own role vocabulary and map each role onto one of the engine's three fixed capability levels.
Added
- Site-declared roles.
defineRoleson the adapter's newrolesmember validates a vocabulary at construction; each role maps toowner(manages the roster),editor(writes and publishes), ornone(an authenticated identity with no engine content access). A site that declares nothing keeps the implicit{ owner, editor }pair, so a zero-config site sees no change anywhere in this release. - Typed read-side. The new
CairnRolesRegisterinterface (root export) lets a site augmentRolein its ownapp.d.ts, narrowinglocals.editor.roleto its declared names on custom admin routes.Editorgains a resolvedcapabilityfield, carried through the guard, the shell payload, and the editor log events. - The none contract. The new
requireEditorguard refuses a none-capability session with 403 on the engine's own content and roster surfaces while still authenticating it: the session carries a populated, typedlocals.editorand passes through theCairnAdminShellcustom-route seam untouched, so a site can grant such a role its own screens. The shell shows a none session only the site's custom nav. - Role-aware landing. A role can declare a
home, the/adminroute it lands on. A none-capability role with nohomegets a calm signed-in welcome view instead of the content list. - ManageEditors renders the vocabulary. The default pair keeps the owner/editor toggle; a larger vocabulary renders a labeled select naming each role's capability. The last-owner guard now counts owner-capability rows (set-based, still one atomic statement), not the literal
ownerstring. - Bootstrap owner.
CairnAdminDeps.auth.bootstrapOwnerseeds the very first owner row on an emptyeditortable from the ordinary magic-link request flow, nowrangler d1 executerequired. - Migration 0001 (
migrations/0001_roles.sql) drops theeditor.roleCHECK constraint; role validity moves to the app layer, validated against the declared vocabulary. A zero-config site can skip it. - Doctor checks
auth.role-vocabularyandauth.email-normalization; the owner-count diagnostic now counts owner-capability rows. New log eventsauth.role.unknownandeditor.bootstrapped. - Docs. A new guide, Give a role its own admin area, plus the roles reference, the site-contract updates in the architecture explanation and the adapter guide, and the upgrade-guide entry.
No consumer action needed for an existing site: the implicit owner/editor vocabulary behaves exactly as before. To open a larger vocabulary, declare roles with defineRoles, apply migration 0001, and augment CairnRolesRegister if you want the narrowed Role type. See the upgrade guide.