Skip to content

feat(permissions): manage the person-status grant domain (ct.status) - #90

Merged
2000game merged 2 commits into
mainfrom
feat/person-status-permission-domain
Aug 10, 2026
Merged

2000game merged 2 commits into
mainfrom
feat/person-status-permission-domain

Conversation

@2000game

Copy link
Copy Markdown
Member

Why

ChurchTools' status permission domain grants a right to every person carrying that person status. It is the only instance-wide lever CT offers — per-person domains are permanently out of scope (src/engine/guard.ts) — but until now it could only be clicked in the admin UI, so eqrm's instance-wide grants lived entirely outside the config.

Concretely: churchcore:login to external system (authId 18) is what lets someone sign in to a connected OAuth client with their ChurchTools account. Equippers wants that for everyone who holds a login, which means grants on three person statuses. There was no way to declare them.

What

  • DomainType gains "status"; new DSL function ct.status({ key, personStatus | id, grants }).
  • New person-status ref kind resolving against GET /statuses — a flat [{id, name}] catalog, live-verified on eqrm prod. This is a different dimension from GROUP status (groupStatusId), which still has no catalog at all (bug(refs): group-status sugar resolves against /group/memberstatus — the wrong dimension (member statuses, string ids); no REST group-status catalog exists #67) and stays numeric; both the code and the docs say so at every touch point.
  • Numeric scope guard relaxed. It accepted only positive integers, which rejected two legitimate values:
    • -1 — CT's "all values of this dimension" sentinel (here: every OAuth client). CT reads it back verbatim, so a declared -1 diffs to a no-op rather than churning.
    • 0 — a real dataId on several dimensions; campus "Mainz" is id 0 on eqrm prod.
  • ct adopt grants status <id> emits a paste-ready ct.status block.

plan and apply needed no changes — both are domain-type agnostic and already address /permissions/<domainType>/<domainId>.

Verification

  • 570 tests / typecheck / lint green. New coverage: catalog resolution (including status id 0), the -1 sentinel round-trip, an end-to-end status-domain plan that reconciles to a no-op, and the personStatus eval-time guards.
  • Against eqrm prod (read-only): ct adopt grants status 6 --env prod round-trips the live grant, confirming scopeField: "oauth_client" and dataId: -1.
  • Against eqrm prod with a consuming config: ct plan reports No permission changes. Desired grants match ChurchTools. for the three declared statuses.

Follow-up

Consumers need a published version before they can use ct.status — @eqrm/ct-cli 1.3.2 fails with ct.status is not a function. eqrm/ct-structure has a companion PR that depends on this release.

https://claude.ai/code/session_01VDTyxvXYSAUSSZi8ceT6zs

CT's `status` permission domain grants a right to every person carrying that
person status — the only instance-wide lever available, since per-person
domains are permanently out of scope (engine/guard.ts). Until now it could
only be clicked in the admin UI, so eqrm's instance-wide grants lived entirely
outside the config.

- DomainType gains "status"; `ct.status({ key, personStatus | id, grants })`.
- New `person-status` ref kind resolving against `GET /statuses` (a flat
  `[{id, name}]` catalog — live-verified on eqrm prod). Distinct from the GROUP
  status dimension, which still has no catalog at all (#67) and stays numeric.
- The numeric-scope guard accepted only positive integers. It now accepts 0 (a
  real dataId — campus "Mainz" is id 0 on eqrm prod) and -1 (CT's "all values of
  this dimension" sentinel, e.g. every external system for
  `churchcore:login to external system`). CT reads -1 back verbatim, so a
  declared -1 diffs to a no-op instead of churning.
- `ct adopt grants status <id>` emits a paste-ready `ct.status` block.

Plan/apply needed no changes — both are domain-type agnostic and already
address `/permissions/<domainType>/<domainId>`.

Verified against eqrm prod: `ct adopt grants status 6 --env prod` round-trips
the live `churchcore:login to external system` grant (scopeField `oauth_client`,
dataId -1).

Claude-Session: https://claude.ai/code/session_01VDTyxvXYSAUSSZi8ceT6zs
…buch issue

The `status` domain work is PR #90 / issue #91; #89 is the unrelated
docs-publishing issue.

Claude-Session: https://claude.ai/code/session_01KPxjSEkqMiU7WE3vg6C3am
@2000game
2000game merged commit 7a3066a into main Aug 10, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant