Scopes
The typed catalogue contains exactly 23 scopes: 14 club and 9 federation. A route requires every scope declared on it. Missing scope metadata is a server wiring error and fails closed; /v1/me and /v1/club/profile explicitly require a valid signature but no business scope. /health alone is public.
Club scopes
| Scope | Surface |
|---|---|
club.contacts.read | Masked contact lists, timelines and households |
club.contacts.read_pii | Unmasked contact profile; audited |
club.contacts.write | Contact and household writes |
club.compliance.read | Compliance, signing state, templates, consent and restrictions |
club.compliance.read_files | Short-lived signed file URLs; audited |
club.compliance.write | Signing-request create/preview/actions and renewal |
club.safety.read | Incident summaries, restrictions and credentials |
club.safety.read_sensitive | Full incident detail; audited |
club.safety.write | Incident, witness and staff-credential writes |
club.billing.read | Invoices, intakes and products; read-only |
club.messages.read | Messages, recipients and templates; read-only |
club.coaches.read | Coach admission cards and credentials |
club.coaches.write | Coach invite/suspend/resume/revoke |
club.federations.read | Club federation memberships and sharing posture |
Federation scopes
| Scope | Surface |
|---|---|
federation.members.read | Member clubs and governance view |
federation.aggregate.read | Aggregate compliance/enrolment/overview |
federation.people.read | Federation people registry |
federation.people.write | Register/correct/activate/deactivate people |
federation.audit.read | Federation audit feed |
federation.safety.read | Federation-level incidents/removals; sensitive detail audited |
federation.compliance.read | Federation credentials/compliance view |
federation.memberships.read | Membership applications and memberships |
federation.rules.read | Sharing rules and consent states |
A grant request is the workspace catalog intersected with the human issuer's existing Academy permissions. Subscription restrictions are explicitly deferred; package, status, module, rate and free-form JSON values are not entitlement evidence. Five club scopes are reserved to the current club's actual OWNER: club.compliance.read_files, club.safety.read_sensitive, club.coaches.read, club.coaches.write, and club.federations.read. OWNER evidence is resolved independently from an active, non-deleted Role(type=STAFF, subtype=OWNER) row for the issuer and exact target club tenant. ADMIN, a custom wildcard holder, and an OWNER of another club cannot grant them; * is never interpreted as a role. A matching OWNER can grant all 14 club scopes, while a non-OWNER wildcard remains limited to the 9 ordinary club scopes. Broad safety scopes require both the incident/removal module and the independently configurable credential-register module. Federation people, safety and compliance access still requires explicit staff-matrix evidence; federation admin and * do not supply it.
The same server-owned grant list gates catalog display, create, and update. A key receives only its persisted scopes and exact workspace binding; it does not inherit OWNER. Losing OWNER does not silently revoke an existing key: non-OWNER managers may strictly reduce it, but may not re-submit an equal ungrantable set, replace one owner-only scope with another, or add one. Rotation preserves rather than expands the persisted scopes.
The Academy control-plane .../partner/credentials/scopes response retains top-level scopes as the grantable list and adds groups as the full workspace catalog in stable order. Groups contain localization keys only, no wildcard or per-item grantable flag. Group labels use partner.scopeGroup.<group-id>.label; each scope uses partner.scope.<scope>.label and partner.scope.<scope>.description. UI descriptions must make PII, file, sensitive safety and audited access explicit. A future server-only subscription ceiling must use [] when enabled evidence is missing; the ceiling is not accepted from request DTOs.