Skip to content

feat(cohort): operator-confirmed reconcile of external members into Blueshell#372

Open
jorisjonkers-dev-agents[bot] wants to merge 7 commits into
mainfrom
platform/cohort-inbound-reconcile
Open

feat(cohort): operator-confirmed reconcile of external members into Blueshell#372
jorisjonkers-dev-agents[bot] wants to merge 7 commits into
mainfrom
platform/cohort-inbound-reconcile

Conversation

@jorisjonkers-dev-agents

@jorisjonkers-dev-agents jorisjonkers-dev-agents Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Operator-confirmed reconcile of an external list's members back into the domain, built on the generic cohort target abstraction (#371) rather than a Brevo-specific path.

  • A small InboundReconcile use case with a write-free preview and a token-validated apply. It fetches external members through the generic TargetStrategy.members(target) (so it works for any system, not just Brevo), computes the shared diff, and matches extras to users by external-id mapping only (USER/BREVO) — duplicates, conflicts, inactive, and unmatched are skipped and never written.
  • A FactWriters registry keyed by CohortFactKind with one ContributionPaidWriter (idempotent ensurePaid, no-op when already true, then re-evaluates the user's cohorts). Other fact kinds are unsupported until a writer exists. Adding a writable fact = one writer class.
  • apply runs an async job; each user's contribution is written in its own transaction and linkUser is never called, so the import only adds domain facts and never mutates mappings or removes anyone externally. No audit tables — job execution plus the apply response cover it.
  • Includes the domain fix so a closed historical membership or a user update no longer strips a member's MEMBER role when another active membership exists.
  • A compact preview/confirm modal shows matched (real names, already-true) and skipped (reasons) rows, with writable-only selection.

The previous bespoke 501-line inbound service, its audit tables, and the standalone 252-line modal are gone; the flow reuses the generic target/diff machinery.

Verification

  • ./gradlew :services:api:test --tests '*Inbound*' --tests '*FactWriter*' --tests '*Target*' --tests '*Contribution*' --tests '*EventListener*' — the inbound/fact/target/listener unit tests pass (the suite's OIDC/Vault security and DB-backed context tests cannot run in the local sandbox; they pass in CI).
  • OpenAPI spec + Blueshell client regenerated; git diff --exit-code clean.
  • Frontend typecheck/lint + modal vitest.

Stacks on the generic target catalog (#371); merge that first.

@jorisjonkers-dev-agents jorisjonkers-dev-agents Bot added the enhancement New feature or request label Jun 29, 2026
@jorisjonkers-dev-agents jorisjonkers-dev-agents Bot force-pushed the platform/cohort-inbound-reconcile branch from 4895fdb to 6035998 Compare June 30, 2026 09:09
Agents Agent added 7 commits June 30, 2026 11:01
…stems

Introduce a system-agnostic CohortTarget core: one TargetStrategy port
(with a TargetDescriptor carrying kind, labels and capabilities), a
TargetStrategies facade, and a generic TargetCatalog + controller. Brevo
becomes one strategy; adding Discord/Google is one strategy class plus a
TargetSystem value, not a new table/service/picker. The kindFor(system)
switches in targeting and provisioning are removed — kind comes from the
strategy descriptor.
Replace the Brevo-specific picker with one component driven by each
system's target descriptor: the CATALOG capability renders a searchable
combobox (fetched once, filtered client-side), otherwise a manual id
field, with create/folder fields shown per capability. One picker serves
Brevo lists, and future Discord roles / Google groups, with no
per-system branches.
@jorisjonkers-dev-agents jorisjonkers-dev-agents Bot force-pushed the platform/cohort-inbound-reconcile branch from 6035998 to 72ccdaf Compare June 30, 2026 12:27
@jorisjonkers-dev-agents jorisjonkers-dev-agents Bot changed the title feat(cohort): operator-confirmed reconcile of Brevo lists into Blueshell (contribution paid) feat(cohort): operator-confirmed reconcile of external members into Blueshell Jun 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant