Authorization & Access
How Chronicler decides who may do what, why the rule lives in one layer only, and how a reveal to one player stays contained.
Authorization answers the question that comes right after "who are you": may you do this. Chronicler's answer is role-based access control, and it treats RBAC as the single source of truth. There is no second path, no scattering of hand-written if checks that each has to be kept in step. One check before an account is even considered runs earlier still: a suspended or unverified account is stopped before any permission is evaluated, so lifecycle gating never depends on getting the permission logic right.
A permission is a grant over a target
Every capability is one grant of an action mask over a target with three axes: a securable from a fixed, closed vocabulary, an optional chronicle-authored kind, and an optional single instance. That shape covers "may create resources of any kind here" and "may edit this one resource" with the same machinery.
There is deliberately no separate Admin action. Administration is just ordinary Create, Write, and Delete on the securables that govern a scope. Folding admin into the normal actions means there is one permission model to reason about, not a normal one and a shadow one for privileged users. Resolving a caller's permissions is a uniform widening of grants, where a broader grant fills in for a narrower one, combined with a bitwise OR into an effective-permissions view.
The check lives in the service layer, and nowhere else
Authorization is enforced only in the service layer. Not in the API handler, which is too early and too easy to bypass, and not in the store, which is too late and does not know the intent. A service method authorises first, and the authoriser hands back the actor for the write, so the check and the identity it produced travel together.
The rule is kept honest by a build-time lint. A service method that touches data without an authorization call is a failed build, not a code-review note someone might miss. Route metadata still describes what a route needs, but that description is documentation. The enforcement is the service check.
Roles people can actually manage
Roles come with an immutable starter ladder, so a fresh chronicle is usable without anyone designing a permission scheme first. A role can be renamed, and a Protected role has its definition frozen while its membership stays open, which is how a built-in role stays safe to assign but impossible to accidentally redefine. The same role-management capability works across the system, chronicle, and workspace scopes, mounted per scope, so there is one way to manage roles rather than three.
Keeping a reveal in its lane
The subtle case is play. When a game master reveals one resource to a campaign's players, that permission hangs off a campaign-scoped role. The danger is that a grant meant for one campaign quietly answers a wider question, such as a canon read of the same resource, or a read in a sibling campaign of the same world.
Chronicler closes this by making the campaign a third grant anchor, beside chronicle and workspace. A campaign role stops answering chronicle-level checks, and a campaign check filters by campaign id, so a reveal grant answers only play checks in its own campaign. Both leaks close by construction, not by a filter someone has to remember to apply.
Where this connects
Authorization decides what a principal may do. That principal comes from Authentication, and the reveal machinery it protects lives in Play, reveals and campaigns.
Read the record for the detail
This page is the guide. The full records under docs/adrs carry the exact action masks, the securable vocabulary, and the alternatives that were weighed and rejected.