Skip to content

feat(resources): promote comment-viewer to a declarable resource — raw cdb_comment_viewer ids are the last host-specific ids left in ct-structure #151

Description

@2000game

Summary

cdb_comment_viewer is the one scope dimension a config cannot express portably today. ref.commentViewer resolves a scope by name, but there is no way to declare the viewers themselves, so a config that grants churchdb:view comments must write a raw, host-specific dataId — and that id silently means something different, or nothing at all, on another host.

This is not hypothetical. It is currently live in eqrm/ct-structure.

Evidence

GET /person/commentviewers, read on both hosts 2026-08-24 (prod CT 3.135.2, dev 3.136.0-RC14):

id prod dev
0 Alle Alle
1 Integration Gemeindeleitung
2 Data-Admins Admins
3 Pastoral Care —
4 Dienstbereich —
5 eGroups —

ct-structure's config carries raw prod ids 3 (three bereich_pastoral_care role instances), 4 (connectgruppe_roles) and 5 (struktur_roles). Dev has no rows 3/4/5 at all, and its 1/2 name different categories than prod's.

A ct apply --env dev on 2026-08-24 duly wrote a grant pointing at nothing:

group_type_role 27, authId 113, dataId 4   modifiedDate 2026-08-24T18:11:03Z

Nothing detects this. ct plan is a clean no-op in both directions, because the plan compares the declared id against the live id and they match — the id is simply meaningless on the target host. A row count does not see it either.

Why the obvious workaround does not work

Switching to { commentViewer: "Dienstbereich" } makes it worse: dev lacks the names as well as the ids, so the ref fails to resolve rather than resolving wrongly. A name ref is only portable once something guarantees the rows exist on both hosts — which is exactly what a declarable resource would do.

So the two available options are both bad: keep raw ids (dev silently unfaithful) or hand-create the viewers on each host (unmanaged master data, defeats the point of the tool).

What is being asked

Promote comment-viewer to a first-class declarable/adoptable resource, alongside security-level, so a config can say:

ct.commentViewer({ key: "dienstbereich", name: "Dienstbereich", sortKey: 40 });
...
{ right: "churchdb:view comments", scope: [{ commentViewer: "dienstbereich" }] }

Why this looks small

  • The table is already in scope for the master-data driver: epic(resources): generic master-data driver — 22 self-describing editable tables behind one endpoint #109 lists Kommentare-Viewer / cdb_comment_viewer (3 cols) among its 22 editable tables. That epic shipped security-level and others; this table was not picked up.
  • /person/commentviewers is conventional REST — [{id, name, sortKey}] plus POST/PUT/DELETE — live-probed on eqrm-dev CT 3.135.2, 2026-08-14, per the ref's own docblock.
  • The CLI already says so. From the ref.commentViewer docblock: "Catalog-only here, like ref.securityLevel: resolvable by name on any host, not declarable. Its REST surface would fit the resource registry unchanged, so promoting it later is a scope decision rather than a technical one." This issue is that scope decision.

Current state, for the record

$ ct adopt comment-viewer 4 --env prod --dry-run
✗ Unknown resource type "comment-viewer". Adoptable types: campus, group, group-type,
  age-group, target-group, relationship-type, person-status, department, security-level,
  group-role.

SCOPE_REF_KIND has cdb_comment_viewer: { kind: "comment-viewer", type: "comment-viewer", managed: false }, and commentViewer appears only as a ref resolver — there is no declaration builder behind it.

Impact if it lands

Closes the last host-specific id in eqrm/ct-structure's permission layer. It also unblocks the three Bereich Pastoral Care role instances that #102 originally cited as blocked by this dimension, and makes dev a faithful rehearsal for the five comment-viewer-scoped grants it currently cannot rehearse.

Suggested acceptance

  • ct adopt comment-viewer <id> emits a config entry and a state row.
  • ct.commentViewer({ key, name, sortKey }) declares one; plan/apply create and update, never delete implicitly.
  • { commentViewer: "<key>" } resolves against declared viewers first, then the live catalog by name (so existing name refs keep working).
  • Applying the same config to two hosts yields the same viewer names on both, and a view comments grant that means the same thing on each.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesttriageUnsorted intake — decide in the weekly sweep

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions