Skip to content

feat(groups): allowDuplicateName create opt-in + duplicate-adoption guidance - #79

Merged
2000game merged 2 commits into
mainfrom
feat/allow-duplicate-name-75
Jul 10, 2026
Merged

2000game merged 2 commits into
mainfrom
feat/allow-duplicate-name-75

Conversation

@2000game

Copy link
Copy Markdown
Member

Summary

  • Groups can now declare allowDuplicateName: true to opt into ChurchTools' force same-name group-creation flag, sent only on the CREATE POST /groups body — never diffed, never in state, never sent on update, never adopted, and never trips the unknown-field warning.
  • When a group create 400s on CT's same-name guard without the opt-in, the executor's stop message now appends one guidance line (via the existing formatError output, not a forked formatter) pointing at either adopting the likely-unmanaged existing group (ct adopt group <id> --key <key>) or setting allowDuplicateName: true if the duplicate is intentional.
  • Docs: README's group DSL section and docs/group-field-decisions.md's decision table now cover the flag.

Closes #75

Evidence for the force-param shape

POST /groups in the ChurchTools OpenAPI spec (churchtools-openapi.json, operationId post-groups) documents a top-level body boolean field:

"force": {
  "description": "Need to be true, if another group with that name already exists",
  "type": "boolean"
}

So the opt-in is force: true in the JSON body — not a ?force=true query param. POST /groups's own 400 response is undocumented beyond "Bad Request" in the spec, but the analogous POST /persons 400 (same duplicate-guard pattern) documents the exact error envelope:

{ "message": "Duplicate found. Use force flag to create person with same name.",
  "messageKey": "forbidden.duplicate.person",
  "translatedMessage": "..." }

Issue #75's own live dev-rehearsal report confirms the group case matches this shape verbatim, with messageKey: "forbidden.duplicate.group" and message text "Duplicate found. Use force flag to create group with same name." — the implementation checks the messageKey first, falling back to a text match (duplicate + "force flag" + "group") for defense in depth. No live instance was contacted for this PR.

Test plan

  • npm test — 531 passed, 5 skipped (0 failed); 23 new/updated assertions across tests/execute.test.ts, tests/context.test.ts, tests/plan.test.ts cover: force sent only on CREATE with the flag, force omitted without it, update path untouched even if a stale item carried the flag, unknown-field warning does not fire, non-boolean/non-group rejected at DSL eval time, duplicate-400 stop message contains the guidance (via messageKey and via text fallback), guidance suppressed when the flag is already set or the 400 is unrelated.
  • npm run typecheck — clean
  • npm run lint — clean

2000game added 2 commits July 10, 2026 11:37
…uidance (#75)

Groups declare `allowDuplicateName: true` to opt into CT's `force: true`
same-name create guard (`POST /groups` 400s `forbidden.duplicate.group`
otherwise) — needed when two groups legitimately share a name (e.g. an
archived and an active event signup). The flag is create-body-only: never
diffed, never in state, never sent on update, never trips the unknown-field
warning.

When a group create 400s on this guard without the opt-in, the stop message
now appends guidance pointing at adopting the likely-unmanaged existing group
(`ct adopt group <id> --key <key>`) or setting the flag if the duplicate is
intentional — reusing the shared formatError output rather than forking it.

Evidence for the force-param shape: ChurchTools OpenAPI spec's POST /groups
request body documents `force: boolean` ("Need to be true, if another group
with that name already exists"); its analogous POST /persons 400 documents
the `{ message, messageKey, translatedMessage }` envelope
(`forbidden.duplicate.person`) that issue #75's live dev rehearsal confirms
groups also use (`forbidden.duplicate.group`).
@2000game
2000game merged commit 0b187b1 into main Jul 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.

feat(groups): same-name group creation needs CT's force flag — declarative opt-in (allowDuplicateName)

1 participant