docs: expand adaptive Campaign guidance

This commit is contained in:
2026-07-21 17:29:08 +02:00
parent 25a69b3fa9
commit 9f4eab07f6
2 changed files with 186 additions and 7 deletions

View File

@@ -56,7 +56,7 @@ PERMISSIONS = (
_permission("campaigns:campaign:share", "Share campaigns", "Grant or revoke explicit campaign access.", "Campaigns"), _permission("campaigns:campaign:share", "Share campaigns", "Grant or revoke explicit campaign access.", "Campaigns"),
_permission("campaigns:campaign:validate", "Validate campaigns", "Run technical validation and manage validation locks.", "Campaigns"), _permission("campaigns:campaign:validate", "Validate campaigns", "Run technical validation and manage validation locks.", "Campaigns"),
_permission("campaigns:campaign:build", "Build campaigns", "Build exact messages and attachment evidence.", "Campaigns"), _permission("campaigns:campaign:build", "Build campaigns", "Build exact messages and attachment evidence.", "Campaigns"),
_permission("campaigns:campaign:review", "Approve campaign review", "Approve or reject built messages and review conditions.", "Campaigns"), _permission("campaigns:campaign:review", "Complete campaign review", "Record review completion and the exact built messages inspected.", "Campaigns"),
_permission("campaigns:campaign:send_test", "Mock-send campaigns", "Use mock delivery and verification tools.", "Campaigns"), _permission("campaigns:campaign:send_test", "Mock-send campaigns", "Use mock delivery and verification tools.", "Campaigns"),
_permission("campaigns:campaign:queue", "Queue campaigns", "Place approved executions into the delivery queue.", "Campaigns"), _permission("campaigns:campaign:queue", "Queue campaigns", "Place approved executions into the delivery queue.", "Campaigns"),
_permission("campaigns:campaign:control", "Control delivery", "Pause, resume or cancel queued and sending jobs.", "Campaigns"), _permission("campaigns:campaign:control", "Control delivery", "Pause, resume or cancel queued and sending jobs.", "Campaigns"),
@@ -94,7 +94,7 @@ ROLE_TEMPLATES = (
RoleTemplate( RoleTemplate(
slug="campaign_reviewer", slug="campaign_reviewer",
name="Campaign reviewer", name="Campaign reviewer",
description="Inspect and approve prepared campaign messages.", description="Inspect prepared campaign messages and record review completion.",
permissions=( permissions=(
"campaigns:campaign:read", "campaigns:campaign:read",
"campaigns:campaign:validate", "campaigns:campaign:validate",
@@ -274,18 +274,19 @@ manifest = ModuleManifest(
conditions=( conditions=(
DocumentationCondition( DocumentationCondition(
required_modules=("campaigns", "mail"), required_modules=("campaigns", "mail"),
any_scopes=("campaigns:campaign:read", "mail:profile:use"), required_scopes=("campaigns:campaign:update", "mail:profile:use"),
), ),
), ),
links=( links=(
DocumentationLink(label="Campaigns", href="/campaigns", kind="runtime"), DocumentationLink(label="Campaigns", href="/campaigns", kind="runtime"),
DocumentationLink(label="Mail profiles", href="/mail", kind="runtime"), DocumentationLink(label="Mail profiles", href="/settings?section=mail-profiles", kind="runtime"),
DocumentationLink(label="Campaign handbook", href="govoplan-campaign/docs/CAMPAIGN_HANDBOOK.md", kind="repository"),
), ),
related_modules=("mail",), related_modules=("mail",),
unlocks=("Profile-backed SMTP delivery and optional IMAP append-to-Sent.",), unlocks=("Profile-backed SMTP delivery and optional IMAP append-to-Sent.",),
metadata={ metadata={
"kind": "workflow", "kind": "workflow",
"route": "/campaigns/{campaign_id}/mail", "route": "/campaigns/{campaign_id}/mail-settings",
"screen": "Campaign Mail settings", "screen": "Campaign Mail settings",
"prerequisites": [ "prerequisites": [
"Campaign and Mail are installed.", "Campaign and Mail are installed.",
@@ -322,8 +323,9 @@ manifest = ModuleManifest(
), ),
), ),
links=( links=(
DocumentationLink(label="Mail profiles", href="/mail", kind="runtime"), DocumentationLink(label="Mail profiles", href="/settings?section=mail-profiles", kind="runtime"),
DocumentationLink(label="Campaign schema", href="/api/v1/campaigns/schema", kind="api"), DocumentationLink(label="Campaign schema", href="/api/v1/campaigns/schema", kind="api"),
DocumentationLink(label="Mail profile boundary", href="govoplan-campaign/docs/MAIL_PROFILE_BOUNDARY.md", kind="repository"),
), ),
related_modules=("mail", "access"), related_modules=("mail", "access"),
unlocks=("Auditable, reusable transport configuration across campaigns.",), unlocks=("Auditable, reusable transport configuration across campaigns.",),
@@ -357,6 +359,7 @@ manifest = ModuleManifest(
links=( links=(
DocumentationLink(label="Campaign operator queue", href="/operator", kind="runtime"), DocumentationLink(label="Campaign operator queue", href="/operator", kind="runtime"),
DocumentationLink(label="Campaign reports", href="/reports", kind="runtime"), DocumentationLink(label="Campaign reports", href="/reports", kind="runtime"),
DocumentationLink(label="Campaign delivery runbook", href="govoplan-campaign/docs/CAMPAIGN_DELIVERY_RUNBOOK.md", kind="repository"),
), ),
related_modules=("mail", "audit"), related_modules=("mail", "audit"),
unlocks=("Fail-closed recovery without exposing Mail credentials.",), unlocks=("Fail-closed recovery without exposing Mail credentials.",),
@@ -372,6 +375,174 @@ manifest = ModuleManifest(
], ],
}, },
), ),
DocumentationTopic(
id="campaigns.workflow.prepare-validate-and-build",
title="Prepare, validate, and build a campaign",
summary="Turn governed recipient, template, attachment, and Mail-profile inputs into exact built messages for review.",
body="Prepare each input in its owning surface, resolve every blocking validation issue, and build exact recipient messages before review. Campaign freezes recipient and attachment evidence for the selected version; later source changes do not silently alter that build.",
layer="configured",
documentation_types=("user",),
audience=("campaign_manager", "campaign_author"),
order=49,
conditions=(
DocumentationCondition(
required_modules=("campaigns",),
required_scopes=("campaigns:campaign:update", "campaigns:campaign:validate", "campaigns:campaign:build"),
),
),
links=(
DocumentationLink(label="Campaigns", href="/campaigns", kind="runtime"),
DocumentationLink(label="Campaign handbook", href="govoplan-campaign/docs/CAMPAIGN_HANDBOOK.md", kind="repository"),
DocumentationLink(label="Recipient import guide", href="govoplan-campaign/docs/RECIPIENT_IMPORT_GUIDE.md", kind="repository"),
),
related_modules=("addresses", "files", "mail"),
unlocks=("A reviewable build whose exact recipient-specific effects can be inspected before delivery.",),
metadata={
"kind": "workflow",
"route": "/campaigns/{campaign_id}/global-settings",
"screen": "Campaign workspace",
"prerequisites": [
"The campaign has an owner and a clear communication purpose.",
"You may edit, validate, and build the selected campaign version.",
"Optional source modules needed by this campaign are installed and authorized.",
],
"steps": [
"Set campaign-wide fields and purpose, then define the recipient fields and templates.",
"Import or select recipients and inspect provenance, exclusions, and review-required rows.",
"Select managed attachment versions and an authorized Mail profile when those capabilities are used.",
"Validate the relevant sections and resolve every blocker without hiding warnings.",
"Build the selected version and inspect representative and exceptional rendered messages.",
],
"outcome": "The selected version has exact built messages and frozen source evidence ready for an independent review.",
"verification": "Open Review, confirm the build belongs to the intended version, and inspect counts, warnings, recipients, addressing, rendered content, and attachment evidence.",
"related_topic_ids": [
"campaigns.workflow.complete-review",
"campaigns.mail-profile-user-journey",
"files.workflow.import-managed-snapshot",
],
},
),
DocumentationTopic(
id="campaigns.workflow.complete-review",
title="Inspect built messages and complete review",
summary="Review the exact immutable candidate and record which built messages were inspected before delivery is enabled.",
body="Review completion records the inspected message keys for the selected build. The current baseline does not persist a separate approve/reject decision or review reason, so do not present completion as a richer decision record. Any material input or non-secret transport-identity change requires validation and a new build.",
layer="configured",
documentation_types=("user",),
audience=("campaign_reviewer",),
order=50,
conditions=(
DocumentationCondition(
required_modules=("campaigns",),
required_scopes=("campaigns:campaign:read", "campaigns:campaign:review"),
),
),
links=(
DocumentationLink(label="Campaigns", href="/campaigns", kind="runtime"),
DocumentationLink(label="Campaign handbook", href="govoplan-campaign/docs/CAMPAIGN_HANDBOOK.md", kind="repository"),
),
related_modules=("files", "mail"),
unlocks=("An attributable review-completion record for the exact built messages inspected.",),
metadata={
"kind": "workflow",
"route": "/campaigns/{campaign_id}/review",
"screen": "Review and send",
"prerequisites": [
"The selected campaign version is validated and built.",
"You may read the campaign and complete its review.",
],
"steps": [
"Confirm the campaign, owner, selected version, recipient count, warnings, and exclusions.",
"Inspect representative and exceptional messages, addressing, templates, and attachment evidence.",
"Confirm that the selected Mail profile is suitable and authorized for the current context.",
"Record review completion for the exact message keys inspected.",
],
"outcome": "The reviewed build is eligible for a separately authorized queue or send action.",
"verification": "Reload Review and confirm completion is tied to the same version and message build; changed inputs must invalidate or supersede it.",
"related_topic_ids": [
"campaigns.workflow.prepare-validate-and-build",
"campaigns.workflow.retry-and-reconcile",
],
},
),
DocumentationTopic(
id="campaigns.workflow.retry-and-reconcile",
title="Retry only known failures and reconcile uncertain effects",
summary="Keep safe-to-retry failures separate from SMTP or IMAP effects whose outcome is unknown.",
body="A retry creates new attempt evidence and is valid only for an explicitly eligible state. Never blindly retry an unknown SMTP or IMAP effect. Inspect external evidence, reconcile SMTP as accepted or not sent, and reconcile IMAP as appended or not appended; repairing Sent never resends accepted SMTP mail.",
layer="evidence",
documentation_types=("admin", "user"),
audience=("campaign_sender", "campaign_operator"),
order=51,
conditions=(
DocumentationCondition(
required_modules=("campaigns",),
any_scopes=("campaigns:campaign:retry", "campaigns:campaign:reconcile", "campaigns:diagnostic:read"),
),
),
links=(
DocumentationLink(label="Campaign operator queue", href="/operator", kind="runtime"),
DocumentationLink(label="Campaign delivery runbook", href="govoplan-campaign/docs/CAMPAIGN_DELIVERY_RUNBOOK.md", kind="repository"),
),
related_modules=("mail", "audit"),
unlocks=("Evidence-backed recovery without accidental duplicate external effects.",),
metadata={
"kind": "workflow",
"route": "/operator",
"screen": "Campaign operator queue",
"prerequisites": [
"You may perform the selected retry or reconciliation action.",
"Provider, mailbox, worker, and campaign evidence has been preserved.",
],
"steps": [
"Classify the job and latest SMTP and IMAP attempts independently.",
"Retry only an explicitly temporary, permanent-with-override, or unattempted eligible state.",
"For an unknown effect, inspect provider or mailbox evidence and record the factual reconciliation with a note.",
"Verify the resulting protected state before allowing more work for that job.",
],
"outcome": "Every investigated job is either protected as effected, explicitly retryable, or still visibly unresolved.",
"verification": "Confirm the previous attempt remains in history, a retry has a new attempt number, and no accepted SMTP effect was repeated to repair IMAP state.",
"related_topic_ids": [
"campaigns.mail-profile-operations",
"campaigns.reference.composition-assurance",
],
},
),
DocumentationTopic(
id="campaigns.reference.composition-assurance",
title="Assure the Campaign reference composition",
summary="Release Campaign only with aligned contracts, role-safe surfaces, durable effect evidence, optional-module isolation, and recoverable data.",
body="Campaign is a reference composition only when Core, Mail, Files, Addresses, workers, storage, policies, and documentation are tested in the exact installed combination. Normal readers see business state rather than paths, storage keys, worker claims, or raw provider diagnostics; diagnostic and export authority remain separate.",
layer="evidence",
documentation_types=("admin",),
audience=("platform_operator", "security_reviewer", "release_reviewer", "integrator"),
order=52,
conditions=(
DocumentationCondition(
required_modules=("campaigns",),
any_scopes=("campaigns:diagnostic:read", "campaigns:report:read", "system:settings:read", "admin:modules:read"),
),
),
links=(
DocumentationLink(label="Campaign handbook", href="govoplan-campaign/docs/CAMPAIGN_HANDBOOK.md", kind="repository"),
DocumentationLink(label="Reference examples and release checklist", href="govoplan-campaign/docs/EXAMPLE_CAMPAIGNS_AND_RELEASE_CHECKLIST.md", kind="repository"),
),
related_modules=("mail", "files", "addresses", "audit"),
unlocks=("A repeatable, supportable Campaign demonstration rather than an unverified module assembly.",),
metadata={
"kind": "reference",
"route": "/campaigns",
"screen": "Campaign reference composition",
"section": "Release, security, integration, and recovery assurance",
"verification": "Run the maintained examples, module-permutation tests, migration and restore drills, target SMTP/IMAP checks, version-alignment gate, WebUI/i18n checks, and full security audit for the pinned composition.",
"related_topic_ids": [
"campaigns.workflow.prepare-validate-and-build",
"campaigns.workflow.complete-review",
"campaigns.workflow.retry-and-reconcile",
"mail.reference.credentials-egress-retirement",
],
},
),
), ),
capability_factories={ capability_factories={
CAPABILITY_CAMPAIGNS_ACCESS: lambda context: __import__( CAPABILITY_CAMPAIGNS_ACCESS: lambda context: __import__(

View File

@@ -50,7 +50,11 @@ def test_mail_profile_documentation_is_classified_for_adaptive_views() -> None:
workflow = topics["campaigns.mail-profile-user-journey"] workflow = topics["campaigns.mail-profile-user-journey"]
assert workflow.metadata["kind"] == "workflow" assert workflow.metadata["kind"] == "workflow"
assert workflow.metadata["route"] == "/campaigns/{campaign_id}/mail" assert workflow.metadata["route"] == "/campaigns/{campaign_id}/mail-settings"
assert workflow.conditions[0].required_scopes == (
"campaigns:campaign:update",
"mail:profile:use",
)
assert workflow.metadata["prerequisites"] assert workflow.metadata["prerequisites"]
assert workflow.metadata["steps"] assert workflow.metadata["steps"]
assert workflow.metadata["outcome"] assert workflow.metadata["outcome"]
@@ -59,6 +63,10 @@ def test_mail_profile_documentation_is_classified_for_adaptive_views() -> None:
assert topics["campaigns.mail-profile-governance"].metadata["kind"] == "reference" assert topics["campaigns.mail-profile-governance"].metadata["kind"] == "reference"
assert topics["campaigns.mail-profile-operations"].metadata["kind"] == "reference" assert topics["campaigns.mail-profile-operations"].metadata["kind"] == "reference"
assert topics["campaigns.workflow.prepare-validate-and-build"].metadata["kind"] == "workflow"
assert topics["campaigns.workflow.complete-review"].metadata["kind"] == "workflow"
assert topics["campaigns.workflow.retry-and-reconcile"].metadata["kind"] == "workflow"
assert topics["campaigns.reference.composition-assurance"].metadata["kind"] == "reference"
@pytest.mark.parametrize("legacy_key", ["smtp", "imap", "credentials", "inherit_smtp_credentials", "profile_id"]) @pytest.mark.parametrize("legacy_key", ["smtp", "imap", "credentials", "inherit_smtp_credentials", "profile_id"])