Skip to content

feat(cohort): generic reusable external target catalog and picker#371

Open
jorisjonkers-dev-agents[bot] wants to merge 3 commits into
mainfrom
platform/cohort-brevo-shadow-picker
Open

feat(cohort): generic reusable external target catalog and picker#371
jorisjonkers-dev-agents[bot] wants to merge 3 commits into
mainfrom
platform/cohort-brevo-shadow-picker

Conversation

@jorisjonkers-dev-agents

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

Copy link
Copy Markdown
Contributor

Summary

External cohort targets — Brevo lists today, Discord roles and Google Workspace groups next — are now one generic, reusable abstraction with a single picker, instead of Brevo-specific tables, services, and UI.

  • A TargetStrategy port: each external system implements catalog/resolve/members/add/remove/create/delete and exposes a TargetDescriptor (kind, labels, capabilities). A small TargetStrategies facade resolves the strategy for a system. TargetSystem stays a plain enum; the descriptor lives on the strategy so the shared kernel keeps no dependency on cohort types.
  • A generic TargetCatalog service + CohortTargetController (GET /management/cohort-targets/{system} and /systems) returns named, human-readable options annotated with whether each is already linked. Provider calls run outside DB transactions.
  • BrevoTargetStrategy is the one live provider (folder/list paging, members via the existing contact-list adapter). Adding Discord or Google is one strategy class plus a TargetSystem value — no new table, sync job, query service, or picker branch.
  • The duplicated kindFor(system) switches are gone; target kind comes from the descriptor.
  • linkExisting/switchTarget validate against the strategy but allow record-only binding when an id is not in the fetched catalog, so a paste-in id still works.
  • One descriptor-driven picker replaces the Brevo-only one: the CATALOG capability renders a searchable combobox (fetched once, filtered client-side), otherwise a manual id field, with create/folder fields shown per capability.

No shadow tables: target options are fetched live and filtered client-side. A generic cache can be added later if a provider's volume requires it.

Verification

  • ./gradlew :services:api:test --tests '*Target*' --tests '*cohort*' — 123 passed (the full suite's OIDC/Vault security tests cannot run in the local sandbox; they pass in CI).
  • OpenAPI spec + Blueshell client regenerated; git diff --exit-code clean.
  • Frontend typecheck/lint + picker vitest.

Agents Agent added 3 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-brevo-shadow-picker branch from 8e20a0e to b05d3a1 Compare June 30, 2026 11:02
@jorisjonkers-dev-agents jorisjonkers-dev-agents Bot changed the title feat(cohort): Brevo list shadow catalog and named target picker feat(cohort): generic reusable external target catalog and picker 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