# govoplan-campaign **Repository type:** module (domain). GovOPlaN Campaign is the campaign authoring, validation, review, sending-control, and reporting module. It bundles backend campaign APIs with the campaign WebUI package. ## Ownership This repository owns: - backend module manifest `campaigns` - campaign, recipient, report, and campaign-audit permissions - campaign/version/job/issue/send-attempt/append-attempt models and migrations - campaign JSON schema, validation, message building, attachment resolution, ZIP handling, reports, queue/control services, and mock-send paths - WebUI package `@govoplan/campaign-webui` - route contributions for `/campaigns`, the integrated `/campaigns/queue` view, `/campaigns/reports`, `/campaigns/:campaignId/*`, and `/templates` Core owns the auth facade, RBAC/capability contracts, database/session primitives, CSRF/API helpers, shell layout, and route rendering. Tenancy is an optional platform module for tenant administration and tenant resolver behavior. Files and mail own their respective storage and transport capabilities. When the optional Reporting module is enabled, Campaign contributes its recipient-free aggregate delivery report through the versioned Core report provider contract. Reporting owns the global `/reports` route. Campaign keeps its module-local `/campaigns/reports` view and does not claim the global route when Reporting is absent. Generated EML and printable artifacts are durable execution material, not a node-local runtime cache. Campaign stores EML through Core's shared object-storage contract under opaque Campaign-owned keys. Templates returns a bounded artifact or a Files-managed artifact for printable output. Database job rows retain the expected hashes and provenance. Workers resolve and verify the frozen evidence before delivery. Build failure compensates objects written before database commit. Retention uses a fenced forward-recovery operation and independently verifies both artifact absence and the committed locator update; partial or unobservable cleanup remains visible in Ops. An operator-only, dry-run-first reconciler inventories bounded tenant-prefix pages and removes only old objects that remain unreferenced after an active build-fence check. Applied runs are idempotent, fenced, audited, and preserve database references on every storage failure. ## Dependencies The module has one required runtime dependency: - `govoplan-core` for platform services, auth, RBAC, DB/session lifecycle, migrations, and WebUI shell integration Files, Mail, Distribution Lists, Templates, Postbox, and Calendar are optional module integrations declared in the campaign manifest: - `govoplan-files` enables managed attachment selection, frozen file-version evidence, and managed-file usage tracking. Server/API campaigns require this integration for attachments and never resolve caller-supplied local filesystem paths. Legacy file-oriented loading remains available only to explicitly trusted operator/library workflows. - `govoplan-mail` owns reusable profiles, encrypted SMTP/IMAP credentials, delivery policy checks, connection tests, and transport execution. Campaign JSON stores only `server.mail_profile_id`; inline transport settings and credentials are rejected. Without Mail, campaigns can still be authored, but profile validation and real delivery are unavailable. - `govoplan-dist-lists` expands reusable governed audiences. Campaign freezes the exact list revision, provider evidence, candidates, and explicit per-recipient primary/fallback route into its own version. - `govoplan-templates` validates and renders published label, envelope, letter, and list-layout templates for postal or internal-mail delivery. Generated output is hash-bound to its template, inputs, actor, route decisions, and Campaign version. - `govoplan-postbox` resolves exact or organization-derived Postbox targets and records provider acceptance and receipt evidence. It remains optional; Mail-only and print-only campaigns do not require it. - `govoplan-calendar` renders and mirrors individualized VEVENT invitations through the versioned `calendar.invitations` capability. Campaign freezes one METHOD:REQUEST attachment per recipient during build, creates the Calendar mirror only after delivery acceptance, and reads live RSVP state in bounded report batches. Mail may forward METHOD:REPLY parts from an authorized IMAP source. Calendar absence leaves ordinary Campaign authoring and delivery usable. Hybrid delivery never treats an opt-in as an implicit duplicate-send instruction. The Campaign author selects one primary route per recipient and may select a supported fallback. A fallback runs only after the first channel rejects before acceptance; accepted or outcome-unknown effects stop cross-channel retry. Printable output is generated once during build, optionally persisted through Files, reviewed with the exact Campaign version, and accepted idempotently per recipient job during delivery. Recurring schedules have two immutable modes. Manual mode remains the default and prepares independent drafts without Mail. Autonomous mode is explicit and Mail-only: it seals an already built and explicitly approved execution snapshot, rechecks approval, policy, credential/transport revision, live SMTP health, recipient and attachment evidence before each occurrence, and submits one Mail-owned durable command per frozen message. Occurrence-scoped idempotency is allocated before delivery. Accepted and outcome-unknown effects are never retried automatically; uncertain or systemic failures pause the schedule, notify its accountable operator, and retain non-secret recovery evidence. Generated EML retention excludes source versions while an autonomous schedule has a remaining occurrence, including while it is paused; once the schedule finishes, already accepted Mail commands retain their own encrypted payload and evidence under Mail policy. Campaign versions can also be exported as versioned portable JSON packages and imported as independently owned drafts. The privacy-safe export default is metadata plus template/configuration. Recipients, attachment rules, aggregate review state, and recipient-level delivery history are separate scopes with their existing fine-grained permissions. Packages include source provenance, scope/item/redaction manifests, and a SHA-256 integrity digest. They never contain attachment bytes, transport secrets, credential references, password-field values, local storage locators, shares, or ownership grants. Import previews schema and checksum compatibility plus every created/skipped domain. It clears deployment-bound Mail references and never replays locks, approvals, review decisions, jobs, attempts, or sent state. Public campaign, version, job, and report responses expose business data and delivery evidence, but never process-local paths, storage-backend keys, or worker claim tokens. Operational troubleshooting uses the dedicated job diagnostics endpoint and requires the tenant-level `campaigns:diagnostic:read` permission. The campaign sender role receives this permission; tenant-wide administrator scopes continue to grant it through the standard policy evaluator. Backend optional behavior is accessed through core-provided capabilities, not direct required imports. WebUI optional behavior uses core module metadata/capabilities so campaign pages can build and run without files or mail WebUI packages installed. Campaign also provides narrow kernel capabilities so other modules and core services can cooperate without importing campaign internals: - `campaigns.access` for campaign share/existence checks - `campaigns.mailPolicyContext` for campaign-scoped mail policy and owner context - `campaigns.policyContext` for retention/policy provenance - `campaigns.deliveryTasks` for queued send and append-to-Sent workers - `campaigns.retention` for campaign-owned retention cleanup - `privacy.dsar.campaigns` for tenant-scoped recipient, version, delivery, report-projection, and artifact-metadata discovery plus governed erasure planning Keep these capability payloads narrow: stable ids, policy payloads, and task results only. ## Development Install through the core environment: ```bash cd /mnt/DATA/git/govoplan-core ./.venv/bin/python -m pip install -r requirements-dev.txt ``` Run the WebUI from the core host: ```bash cd /mnt/DATA/git/govoplan-core/webui PATH=/home/zemion/.nvm/versions/node/v22.22.3/bin:$PATH /home/zemion/.nvm/versions/node/v22.22.3/bin/npm run dev ``` ## Module integration Backend entry point: ```toml [project.entry-points."govoplan.modules"] campaigns = "govoplan_campaign.backend.manifest:get_manifest" ``` Frontend package: ```text @govoplan/campaign-webui ``` Platform RBAC and governance rules are documented in `govoplan-core/docs/`. ## Operations - [Campaign handbook](docs/CAMPAIGN_HANDBOOK.md) provides the adaptive user, process, governance, technical, and operations perspectives. - [Campaign delivery runbook](docs/CAMPAIGN_DELIVERY_RUNBOOK.md) covers queueing, local vs Celery operation, retries, reconciliation, reports, and the live SMTP/IMAP test checklist. - Immediate delivery is bounded to 25 exact eligible recipient jobs by default. Deployments may set `GOVOPLAN_CAMPAIGN_SYNCHRONOUS_SEND_MAX_RECIPIENTS` (0–500), and tenants may narrow that ceiling through `campaign_delivery_policy.synchronous_send_max_recipients` in tenant settings. - Immediate Mail delivery preflights the selected SMTP transport before the first effect and reuses a healthy bounded connection through Mail. Review and send reports the batch state, connection/reconnect counts, and paused count. A systemic authentication, sender, or connectivity failure pauses remaining jobs; correct and test the Mail profile before explicitly resuming them. - Report-email preview uses the selected version's stored v5 Mail-profile evidence. Live report email fails closed until [govoplan-mail#17](https://git.add-ideas.de/GovOPlaN/govoplan-mail/issues/17) provides a durable, idempotent Mail-owned outbox and transport-attempt ledger; per-job CSV is off by default and requires `campaigns:recipient:export` when requested. - [Campaign/Mail profile boundary](docs/MAIL_PROFILE_BOUNDARY.md) defines profile-only delivery, runtime resolution, execution evidence, and the fail-closed legacy migration path. - [Recipient import guide](docs/RECIPIENT_IMPORT_GUIDE.md) covers user/admin workflows, mapping profiles, validation, and import evidence. - [Recipient and address boundary](docs/RECIPIENT_ADDRESS_BOUNDARY.md) defines the split between campaign-local recipients and future reusable address management. - [Example campaigns and release checklist](docs/EXAMPLE_CAMPAIGNS_AND_RELEASE_CHECKLIST.md) defines the maintained example scenarios and release gates. - [Campaign examples](examples/README.md) is the credential-free scenario catalogue that release fixtures must follow. - [SMTP/IMAP test bed](dev/mail-testbed/README.md) provides the GreenMail Docker Compose setup and transport smoke for dedicated non-production delivery tests. ## Release packaging The repository root includes a `package.json` for git-based WebUI installs. It exports the package `@govoplan/campaign-webui` from `webui/src` so release builds can depend on tagged git refs instead of local `file:` paths. Files and mail WebUI packages remain optional product-composition dependencies supplied by the core host build, not required campaign package dependencies.