Deliver forum posting entitlements through managed group membership with identity linkage, periodic reconciliation, webhook handling, and an operator mapping surface. Include fake and live test environments, setup documentation, migrations, and end-to-end coverage.
4.3 KiB
discourse-group-sync Specification
Purpose
TBD - created by archiving change discourse-integration. Update Purpose after archive.
Requirements
Requirement: Desired state derives from provisions and org-membership union
Desired membership of a managed group SHALL be the set of linked persons holding an active membership in at least one organization currently conferred discourse_posting — computed as the OR-union across each person's organizations (both owned and member-of). Conferral SHALL be read from active pool provisions and the materialized boolean entitlement state; grants.status SHALL NOT be consulted for delivery.
Scenario: Person covered by two orgs loses one
- WHEN a person belongs to two entitled organizations and one org's entitlement ends
- THEN the person remains in desired membership because the other org still covers them
Scenario: Last covering org lapses
- WHEN the only organization conferring
discourse_postingfor a person ceases to confer it - THEN the person leaves desired membership and is removed from the managed group at next convergence
Scenario: Grant superseded but provision active
- WHEN an org's grant ledger contains superseded rows but an active provision confers the entitlement
- THEN the org counts as conferring and its members stay in desired membership
Requirement: Periodic full-sweep convergence
A singleton Temporal-scheduled sweep SHALL periodically compute desired membership for every managed group, diff it against observed membership, and converge Discourse via group add/remove calls. The sweep alone SHALL be sufficient for eventual correctness: any missed webhook or event costs at most one sweep interval of staleness.
Scenario: Drift introduced while webhooks are disabled
- WHEN managed-group membership is changed forum-side and no webhook is configured
- THEN the next sweep detects the difference and restores desired membership
Scenario: Sweep after downtime
- WHEN the console was down while entitlements and org memberships changed
- THEN the first sweep after restart converges all managed groups to current desired state
Requirement: Idempotent convergence operations
Convergence SHALL treat Discourse's already-converged responses as success — in particular a 422 response to add_members when all requested users are already members — and SHALL be safe to repeat.
Scenario: Add of an existing member
- WHEN convergence adds users to a group and Discourse responds 422 because all are already members
- THEN the operation is recorded as success and the sweep continues
Requirement: Managed-group ownership boundary
The reconciler SHALL modify membership only of groups present in the operator-configured mapping. Forum-side membership changes to managed groups SHALL be corrected to desired state and logged with the observed discrepancy. Groups not in the mapping SHALL never be touched.
Scenario: Forum admin removes an entitled member from a managed group
- WHEN a
user_removed_from_groupevent (or sweep diff) shows an entitled linked person missing from a managed group - THEN the person is re-added and the correction is logged
Scenario: Unmanaged group untouched
- WHEN convergence runs while unmanaged groups contain arbitrary membership
- THEN no API call modifies any unmanaged group
Requirement: Targeted reconcile with per-person serialization
Webhook events on managed groups and link establishment SHALL trigger a targeted reconcile scoped to the affected person, executed under a deterministic per-person Temporal workflow identity so concurrent triggers for the same person serialize.
Scenario: Concurrent triggers for one person
- WHEN a webhook event and a link establishment fire for the same person at nearly the same time
- THEN their reconciles execute serially and the final group state matches desired state
Requirement: Observed-state projection
The integration SHALL cache last-observed membership of managed groups in its own schema as an observed projection, refreshed by sweeps and webhook events, with Discourse remaining canonical.
Scenario: Sweep refreshes projection
- WHEN a sweep completes
- THEN the stored observed membership for each managed group reflects what Discourse reported during that sweep