feat: add governed postbox delivery and report hardening
This commit is contained in:
@@ -26,7 +26,12 @@ from govoplan_core.core.modules import (
|
||||
PermissionDefinition,
|
||||
RoleTemplate,
|
||||
)
|
||||
from govoplan_core.core.views import ViewSurface
|
||||
from govoplan_core.db.base import Base
|
||||
from govoplan_core.core.postbox import (
|
||||
CAPABILITY_POSTBOX_DELIVERY,
|
||||
CAPABILITY_POSTBOX_DIRECTORY,
|
||||
)
|
||||
from govoplan_campaign.backend.change_tracking import register_campaign_change_tracking
|
||||
from govoplan_campaign.backend.db import models as campaign_models # noqa: F401 - populate Campaign ORM metadata
|
||||
from govoplan_campaign.backend.documentation import CAMPAIGN_USER_DOCUMENTATION, documentation_topics
|
||||
@@ -62,9 +67,9 @@ PERMISSIONS = (
|
||||
_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:control", "Control delivery", "Pause, resume or cancel queued and sending jobs.", "Campaigns"),
|
||||
_permission("campaigns:campaign:send", "Send campaigns", "Start real SMTP delivery.", "Campaigns"),
|
||||
_permission("campaigns:campaign:send", "Send campaigns", "Start real Mail or Postbox delivery.", "Campaigns"),
|
||||
_permission("campaigns:campaign:retry", "Retry delivery", "Retry failed or unattempted delivery jobs.", "Campaigns"),
|
||||
_permission("campaigns:campaign:reconcile", "Reconcile delivery", "Resolve outcome-unknown SMTP or IMAP attempts after inspection.", "Campaigns"),
|
||||
_permission("campaigns:campaign:reconcile", "Reconcile delivery", "Resolve outcome-unknown Mail, Postbox, or IMAP attempts after inspection.", "Campaigns"),
|
||||
_permission("campaigns:diagnostic:read", "View campaign diagnostics", "Inspect worker claims and internal storage locators for campaign delivery troubleshooting.", "Campaign operations"),
|
||||
_permission("campaigns:recipient:read", "View recipients", "Read recipient lists and recipient-specific campaign data.", "Recipients"),
|
||||
_permission("campaigns:recipient:write", "Edit recipients", "Create and edit recipient rows and field values.", "Recipients"),
|
||||
@@ -157,9 +162,15 @@ def _campaigns_router(context: ModuleContext):
|
||||
manifest = ModuleManifest(
|
||||
id="campaigns",
|
||||
name="Campaigns",
|
||||
version="0.1.11",
|
||||
version="0.1.12",
|
||||
required_capabilities=(CAPABILITY_AUTH_PRINCIPAL_RESOLVER, CAPABILITY_AUTH_PERMISSION_EVALUATOR),
|
||||
optional_dependencies=("files", "mail", "notifications", "addresses"),
|
||||
optional_dependencies=(
|
||||
"files",
|
||||
"mail",
|
||||
"notifications",
|
||||
"addresses",
|
||||
"postbox",
|
||||
),
|
||||
provides_interfaces=(
|
||||
ModuleInterfaceProvider(name="campaigns.access", version="0.1.6"),
|
||||
ModuleInterfaceProvider(name="campaigns.delivery_tasks", version="0.1.6"),
|
||||
@@ -192,6 +203,18 @@ manifest = ModuleManifest(
|
||||
version_max_exclusive="0.2.0",
|
||||
optional=True,
|
||||
),
|
||||
ModuleInterfaceRequirement(
|
||||
name=CAPABILITY_POSTBOX_DELIVERY,
|
||||
version_min="0.1.1",
|
||||
version_max_exclusive="0.2.0",
|
||||
optional=True,
|
||||
),
|
||||
ModuleInterfaceRequirement(
|
||||
name=CAPABILITY_POSTBOX_DIRECTORY,
|
||||
version_min="0.1.1",
|
||||
version_max_exclusive="0.2.0",
|
||||
optional=True,
|
||||
),
|
||||
),
|
||||
permissions=PERMISSIONS,
|
||||
route_factory=_campaigns_router,
|
||||
@@ -268,6 +291,15 @@ manifest = ModuleManifest(
|
||||
NavItem(path="/reports", label="Reports", icon="clipboard-pen-line", required_any=("campaigns:report:read",), order=70),
|
||||
NavItem(path="/templates", label="Templates", icon="layout-template", order=90),
|
||||
),
|
||||
view_surfaces=(
|
||||
ViewSurface(
|
||||
id="campaigns.widget.activity",
|
||||
module_id="campaigns",
|
||||
kind="section",
|
||||
label="Campaign activity widget",
|
||||
order=50,
|
||||
),
|
||||
),
|
||||
),
|
||||
migration_spec=MigrationSpec(
|
||||
module_id="campaigns",
|
||||
@@ -285,6 +317,7 @@ manifest = ModuleManifest(
|
||||
campaign_models.AttachmentInstance,
|
||||
campaign_models.SendAttempt,
|
||||
campaign_models.ImapAppendAttempt,
|
||||
campaign_models.PostboxDeliveryAttempt,
|
||||
label="Campaigns",
|
||||
),
|
||||
retirement_notes="Destructive retirement drops campaign-owned database tables after the installer captures a database snapshot.",
|
||||
@@ -301,11 +334,57 @@ manifest = ModuleManifest(
|
||||
campaign_models.AttachmentInstance,
|
||||
campaign_models.SendAttempt,
|
||||
campaign_models.ImapAppendAttempt,
|
||||
campaign_models.PostboxDeliveryAttempt,
|
||||
label="Campaigns",
|
||||
),
|
||||
),
|
||||
documentation=(
|
||||
*CAMPAIGN_USER_DOCUMENTATION,
|
||||
DocumentationTopic(
|
||||
id="campaigns.postbox-delivery",
|
||||
title="Deliver Campaign messages to Postboxes",
|
||||
summary="Target one or more exact or organization-derived Postboxes per recipient row, independently or alongside Mail.",
|
||||
body="Configure campaign-wide targets and optional per-row additions or replacements. Derived targets resolve a published Postbox template with organization unit, function, and optional context values, including values sourced from Campaign fields. Targets are frozen during build. Fallback crosses to the second channel only after a confirmed pre-acceptance rejection; accepted or outcome-unknown effects never trigger fallback.",
|
||||
layer="available",
|
||||
documentation_types=("user", "admin"),
|
||||
audience=("campaign_manager", "campaign_reviewer", "campaign_sender", "campaign_operator"),
|
||||
order=45,
|
||||
conditions=(
|
||||
DocumentationCondition(
|
||||
required_modules=("campaigns", "postbox"),
|
||||
any_scopes=("campaigns:recipient:write", "campaigns:campaign:send", "campaigns:campaign:reconcile"),
|
||||
),
|
||||
),
|
||||
links=(
|
||||
DocumentationLink(label="Campaigns", href="/campaigns", kind="runtime"),
|
||||
DocumentationLink(label="Postboxes", href="/postbox", kind="runtime"),
|
||||
DocumentationLink(label="Campaign schema", href="/api/v1/campaigns/schema", kind="api"),
|
||||
),
|
||||
related_modules=("postbox", "organizations", "idm", "mail", "audit"),
|
||||
unlocks=("Audited direct, derived, combined, and pre-acceptance fallback delivery to Postboxes.",),
|
||||
metadata={
|
||||
"kind": "workflow",
|
||||
"route": "/campaigns/{campaign_id}/global-settings",
|
||||
"screen": "Campaign delivery defaults and recipient data",
|
||||
"prerequisites": [
|
||||
"Campaign and Postbox are installed and active.",
|
||||
"At least one exact Postbox or published Postbox template is available.",
|
||||
],
|
||||
"steps": [
|
||||
"Choose Postbox, Mail and Postbox, or an ordered fallback policy.",
|
||||
"Configure one or more campaign-wide targets.",
|
||||
"Optionally add or replace targets for individual recipient rows.",
|
||||
"Validate and build to freeze the resolved Postbox addresses before review.",
|
||||
"Review, queue, and inspect channel-specific delivery evidence in the report.",
|
||||
],
|
||||
"outcome": "Each active row resolves an auditable set of Postbox targets without introducing a hard Campaign dependency on Postbox.",
|
||||
"verification": "Confirm the frozen target list in the built job and verify accepted, rejected, or outcome-unknown attempts in Campaign reporting.",
|
||||
"related_topic_ids": [
|
||||
"campaigns.workflow.prepare-validate-and-build",
|
||||
"campaigns.workflow.retry-and-reconcile",
|
||||
],
|
||||
},
|
||||
),
|
||||
DocumentationTopic(
|
||||
id="campaigns.mail-profile-user-journey",
|
||||
title="Choose a Mail profile for campaign delivery",
|
||||
@@ -527,8 +606,8 @@ manifest = ModuleManifest(
|
||||
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.",
|
||||
summary="Keep safe-to-retry failures separate from Mail, Postbox, 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 Mail, Postbox, or IMAP effect. Inspect external evidence and reconcile the affected channel before continuing. Accepted Mail attempts and accepted Postbox targets are immutable during partial retries, and repairing Sent never resends accepted Mail.",
|
||||
layer="evidence",
|
||||
documentation_types=("admin", "user"),
|
||||
audience=("campaign_sender", "campaign_operator"),
|
||||
@@ -587,14 +666,14 @@ manifest = ModuleManifest(
|
||||
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"),
|
||||
related_modules=("mail", "postbox", "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.",
|
||||
"verification": "Run the maintained examples, module-permutation tests, migration and restore drills, target Mail/Postbox/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",
|
||||
|
||||
Reference in New Issue
Block a user