Implement governed hybrid campaign delivery
This commit is contained in:
+46
-14
@@ -30,12 +30,13 @@ The shorter task documents remain useful companions:
|
||||
|
||||
## What Campaign is for
|
||||
|
||||
Campaign turns governed source data into individually built messages and then
|
||||
controls their review, delivery, and evidence. It is intentionally a
|
||||
composition module: it demonstrates how one user journey can use optional Mail,
|
||||
Files, Addresses, and Notifications capabilities alongside Core access/audit
|
||||
infrastructure without copying ownership from those modules. Policy may consume
|
||||
Campaign context through a narrow capability; Campaign does not import Policy.
|
||||
Campaign turns governed source data into individually built messages or
|
||||
printable output and then controls their review, delivery, and evidence. It is
|
||||
intentionally a composition module: it demonstrates how one user journey can
|
||||
use optional Mail, Files, Addresses, Distribution Lists, Templates, Postbox,
|
||||
and Notifications capabilities alongside Core access/audit infrastructure
|
||||
without copying ownership from those modules. Policy may consume Campaign
|
||||
context through a narrow capability; Campaign does not import Policy.
|
||||
|
||||
Campaign owns:
|
||||
|
||||
@@ -66,9 +67,9 @@ The supported process is a controlled progression, not a single "send" call:
|
||||
create/edit
|
||||
-> validate and resolve policy/integrations
|
||||
-> review warnings and blockers
|
||||
-> build exact recipient messages
|
||||
-> build exact recipient messages and/or printable artifacts
|
||||
-> complete review and queue
|
||||
-> SMTP attempt per job
|
||||
-> selected Mail, Postbox, or print effect per job
|
||||
-> optional IMAP append per accepted job
|
||||
-> report, retry, reconcile, or correct
|
||||
-> archive when no active/uncertain delivery remains
|
||||
@@ -413,6 +414,7 @@ Current principal contracts include:
|
||||
| `addresses.lookup` 0.1.x | Addresses -> Campaign | Optional address suggestions |
|
||||
| `addresses.recipient_source` 0.1.x | Addresses -> Campaign | Optional versioned recipient-source snapshots |
|
||||
| `dist_lists.source` / `dist_lists.expand` 0.1.x | Distribution Lists -> Campaign | Discover, preview, and freeze reusable audiences without importing module internals |
|
||||
| `templates.catalog` / `templates.renderer` 0.1.x | Templates -> Campaign | Select compatible published printable templates and produce deterministic, evidence-bearing artifacts |
|
||||
| `campaigns.access` 0.1.x | Campaign -> platform | Explain campaign access/existence without exporting ORM objects |
|
||||
| `campaigns.mail_policy_context` 0.1.x | Campaign -> Mail | Resolve campaign tenant/owner context for Mail policy |
|
||||
| `campaigns.delivery_tasks` 0.1.x | Campaign -> workers | Execute narrow queued send/append tasks |
|
||||
@@ -433,16 +435,46 @@ the resulting rows into the editable Campaign version.
|
||||
|
||||
Each copied row retains the list and revision IDs, definition and expansion
|
||||
hashes, snapshot ID, source entry IDs, provider references, channel candidates,
|
||||
the one selected route where it is unambiguous, fallback candidates, and the
|
||||
decision explanation. Campaign-only fields, attachment rules, review state,
|
||||
and outcomes remain local to Campaign and never mutate the reusable list.
|
||||
the explicitly selected primary route, optional fallback, and the decision
|
||||
explanation. Campaign-only fields, attachment rules, review state, and outcomes
|
||||
remain local to Campaign and never mutate the reusable list.
|
||||
|
||||
A later list revision only raises a drift warning. Refresh is deliberate and
|
||||
uses append or replace; saving that changed Campaign version clears prior
|
||||
validation, build, review, and execution state through the normal content
|
||||
invalidation path. Postal-only or otherwise unsupported routes remain present
|
||||
in the frozen evidence but inactive until a compatible Campaign output path is
|
||||
configured.
|
||||
invalidation path. Preferred or single usable candidates are preselected
|
||||
visibly; ambiguous rows must be decided before freezing. Postal and
|
||||
internal-mail routes remain active when a compatible published Templates output
|
||||
is selected.
|
||||
|
||||
### Governed hybrid and printable delivery
|
||||
|
||||
Campaign supports Mail, Postbox, printable output, and bounded ordered
|
||||
fallbacks without making any of those provider modules mandatory. Opt-in and
|
||||
channel-preference data are inputs to the visible routing decision; they never
|
||||
silently cause duplicate delivery.
|
||||
|
||||
For a printable route, select a published label, envelope, serial-letter,
|
||||
form-letter, list-layout, or generic template on the Template page. Validation
|
||||
checks the selected revision, output format, and required fields. Build sends
|
||||
one deterministic item collection to `templates.renderer`, records template,
|
||||
input, output, actor, route, and artifact hashes, and stores the resulting
|
||||
artifact through Files when configured. The review stage exposes that exact
|
||||
artifact and its hashes before execution.
|
||||
|
||||
Each recipient job records an idempotent print acceptance attempt for its item
|
||||
in the frozen artifact. `mail_then_print` and `postbox_then_print` invoke print
|
||||
only after a confirmed rejection before acceptance. An accepted or
|
||||
outcome-unknown digital effect never falls through to print because that could
|
||||
produce duplicate delivery. Reports and CSV exports include route provenance,
|
||||
print state, attempts, artifact reference, and hashes.
|
||||
|
||||
Without Templates, Campaign still loads and Mail/Postbox authoring remains
|
||||
available; validation explains why a configured print route cannot proceed.
|
||||
Without Files, Templates may return a bounded artifact instead of a managed
|
||||
file. Campaign copies that payload into shared object storage and exposes it
|
||||
through the Campaign ACL plus `campaigns:recipient:read`; it never redistributes
|
||||
the broader Templates URL. A print-only Campaign does not require Mail or Postbox.
|
||||
|
||||
### External API expectations
|
||||
|
||||
|
||||
Reference in New Issue
Block a user