feat(cohort): operator-confirmed reconcile of external members into Blueshell#372
Open
jorisjonkers-dev-agents[bot] wants to merge 7 commits into
Open
feat(cohort): operator-confirmed reconcile of external members into Blueshell#372jorisjonkers-dev-agents[bot] wants to merge 7 commits into
jorisjonkers-dev-agents[bot] wants to merge 7 commits into
Conversation
4895fdb to
6035998
Compare
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.
6035998 to
72ccdaf
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.
InboundReconcileuse case with a write-freepreviewand a token-validatedapply. It fetches external members through the genericTargetStrategy.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.FactWritersregistry keyed byCohortFactKindwith oneContributionPaidWriter(idempotentensurePaid, 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.applyruns an async job; each user's contribution is written in its own transaction andlinkUseris 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.MEMBERrole when another active membership exists.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).git diff --exit-codeclean.Stacks on the generic target catalog (#371); merge that first.