Add institutional provenance and approval gates
This commit is contained in:
@@ -2,7 +2,11 @@ from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from govoplan_core.core.access import CAPABILITY_AUTH_PERMISSION_EVALUATOR, CAPABILITY_AUTH_PRINCIPAL_RESOLVER
|
||||
from govoplan_core.core.access import (
|
||||
CAPABILITY_AUTH_PERMISSION_EVALUATOR,
|
||||
CAPABILITY_AUTH_PRINCIPAL_RESOLVER,
|
||||
)
|
||||
from govoplan_core.core.approvals import CAPABILITY_APPROVAL_REQUESTS
|
||||
from govoplan_core.core.campaigns import (
|
||||
CAPABILITY_CAMPAIGNS_ACCESS,
|
||||
CAPABILITY_CAMPAIGNS_DELIVERY_TASKS,
|
||||
@@ -10,7 +14,10 @@ from govoplan_core.core.campaigns import (
|
||||
CAPABILITY_CAMPAIGNS_POLICY_CONTEXT,
|
||||
CAPABILITY_CAMPAIGNS_RETENTION,
|
||||
)
|
||||
from govoplan_core.core.module_guards import drop_table_retirement_provider, persistent_table_uninstall_guard
|
||||
from govoplan_core.core.module_guards import (
|
||||
drop_table_retirement_provider,
|
||||
persistent_table_uninstall_guard,
|
||||
)
|
||||
from govoplan_core.core.ownership import OwnershipProviderRegistration
|
||||
from govoplan_core.core.modules import (
|
||||
DocumentationCondition,
|
||||
@@ -39,12 +46,17 @@ from govoplan_core.core.postbox import (
|
||||
from govoplan_core.core.references import CAPABILITY_ACCESS_REFERENCE_OPTIONS
|
||||
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
|
||||
from govoplan_campaign.backend.documentation import (
|
||||
CAMPAIGN_USER_DOCUMENTATION,
|
||||
documentation_topics,
|
||||
)
|
||||
|
||||
register_campaign_change_tracking()
|
||||
|
||||
|
||||
def _permission(scope: str, label: str, description: str, category: str) -> PermissionDefinition:
|
||||
def _permission(
|
||||
scope: str, label: str, description: str, category: str
|
||||
) -> PermissionDefinition:
|
||||
module_id, resource, action = scope.split(":", 2)
|
||||
return PermissionDefinition(
|
||||
scope=scope,
|
||||
@@ -59,32 +71,162 @@ def _permission(scope: str, label: str, description: str, category: str) -> Perm
|
||||
|
||||
|
||||
PERMISSIONS = (
|
||||
_permission("campaigns:campaign:read", "View campaigns", "Open campaign metadata, versions and permitted message summaries.", "Campaigns"),
|
||||
_permission("campaigns:campaign:create", "Create campaigns", "Create new campaigns in an accessible tenant scope.", "Campaigns"),
|
||||
_permission("campaigns:campaign:update", "Edit campaigns", "Edit current working campaign versions.", "Campaigns"),
|
||||
_permission("campaigns:campaign:copy", "Copy campaigns", "Create campaigns or working versions from existing campaigns.", "Campaigns"),
|
||||
_permission("campaigns:campaign:archive", "Archive campaigns", "Archive campaigns without destroying audit evidence.", "Campaigns"),
|
||||
_permission("campaigns:campaign:delete", "Delete campaigns", "Delete draft-only campaigns where retention policy allows it.", "Campaigns"),
|
||||
_permission("campaigns:campaign:share", "Share campaigns", "Grant or revoke explicit campaign access.", "Campaigns"),
|
||||
_permission("campaigns:ownership:accept_group", "Accept group campaign ownership", "Accept or decline campaign ownership on behalf of a group the actor belongs to.", "Campaign governance"),
|
||||
_permission("campaigns:ownership:recover", "Recover campaign ownership", "Participate in delayed, quorum-backed administrative campaign ownership recovery.", "Campaign governance"),
|
||||
_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: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: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 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 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"),
|
||||
_permission("campaigns:recipient:import", "Import recipients", "Bulk-import recipient lists.", "Recipients"),
|
||||
_permission("campaigns:recipient:export", "Export recipients", "Export recipient data and reports.", "Recipients"),
|
||||
_permission("campaigns:report:read", "View reports", "View campaign delivery reports and aggregate outcomes.", "Reports"),
|
||||
_permission("campaigns:report:export", "Export reports", "Download detailed campaign reports.", "Reports"),
|
||||
_permission("campaigns:report:send", "Send reports", "Email campaign reports to configured recipients.", "Reports"),
|
||||
_permission(
|
||||
"campaigns:campaign:read",
|
||||
"View campaigns",
|
||||
"Open campaign metadata, versions and permitted message summaries.",
|
||||
"Campaigns",
|
||||
),
|
||||
_permission(
|
||||
"campaigns:campaign:create",
|
||||
"Create campaigns",
|
||||
"Create new campaigns in an accessible tenant scope.",
|
||||
"Campaigns",
|
||||
),
|
||||
_permission(
|
||||
"campaigns:campaign:update",
|
||||
"Edit campaigns",
|
||||
"Edit current working campaign versions.",
|
||||
"Campaigns",
|
||||
),
|
||||
_permission(
|
||||
"campaigns:campaign:copy",
|
||||
"Copy campaigns",
|
||||
"Create campaigns or working versions from existing campaigns.",
|
||||
"Campaigns",
|
||||
),
|
||||
_permission(
|
||||
"campaigns:campaign:archive",
|
||||
"Archive campaigns",
|
||||
"Archive campaigns without destroying audit evidence.",
|
||||
"Campaigns",
|
||||
),
|
||||
_permission(
|
||||
"campaigns:campaign:delete",
|
||||
"Delete campaigns",
|
||||
"Delete draft-only campaigns where retention policy allows it.",
|
||||
"Campaigns",
|
||||
),
|
||||
_permission(
|
||||
"campaigns:campaign:share",
|
||||
"Share campaigns",
|
||||
"Grant or revoke explicit campaign access.",
|
||||
"Campaigns",
|
||||
),
|
||||
_permission(
|
||||
"campaigns:ownership:accept_group",
|
||||
"Accept group campaign ownership",
|
||||
"Accept or decline campaign ownership on behalf of a group the actor belongs to.",
|
||||
"Campaign governance",
|
||||
),
|
||||
_permission(
|
||||
"campaigns:ownership:recover",
|
||||
"Recover campaign ownership",
|
||||
"Participate in delayed, quorum-backed administrative campaign ownership recovery.",
|
||||
"Campaign governance",
|
||||
),
|
||||
_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: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: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 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 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",
|
||||
),
|
||||
_permission(
|
||||
"campaigns:recipient:import",
|
||||
"Import recipients",
|
||||
"Bulk-import recipient lists.",
|
||||
"Recipients",
|
||||
),
|
||||
_permission(
|
||||
"campaigns:recipient:export",
|
||||
"Export recipients",
|
||||
"Export recipient data and reports.",
|
||||
"Recipients",
|
||||
),
|
||||
_permission(
|
||||
"campaigns:report:read",
|
||||
"View reports",
|
||||
"View campaign delivery reports and aggregate outcomes.",
|
||||
"Reports",
|
||||
),
|
||||
_permission(
|
||||
"campaigns:report:export",
|
||||
"Export reports",
|
||||
"Download detailed campaign reports.",
|
||||
"Reports",
|
||||
),
|
||||
_permission(
|
||||
"campaigns:report:send",
|
||||
"Send reports",
|
||||
"Email campaign reports to configured recipients.",
|
||||
"Reports",
|
||||
),
|
||||
)
|
||||
|
||||
OPERATOR_QUEUE_REQUIRED_ANY = (
|
||||
@@ -108,9 +250,7 @@ ROLE_TEMPLATES = (
|
||||
slug="campaign_aggregate_reader",
|
||||
name="Campaign aggregate reader",
|
||||
description="View privacy-protected outcome totals without recipient or delivery diagnostics.",
|
||||
permissions=(
|
||||
"campaigns:report:read",
|
||||
),
|
||||
permissions=("campaigns:report:read",),
|
||||
),
|
||||
RoleTemplate(
|
||||
slug="campaign_manager",
|
||||
@@ -166,7 +306,11 @@ ROLE_TEMPLATES = (
|
||||
def _tenant_summary(session, tenant_id: str) -> dict[str, int]:
|
||||
from govoplan_campaign.backend.db.models import Campaign
|
||||
|
||||
return {"campaigns": session.query(Campaign).filter(Campaign.tenant_id == tenant_id).count()}
|
||||
return {
|
||||
"campaigns": session.query(Campaign)
|
||||
.filter(Campaign.tenant_id == tenant_id)
|
||||
.count()
|
||||
}
|
||||
|
||||
|
||||
def _tenant_summary_batch(session, tenant_ids) -> dict[str, dict[str, int]]:
|
||||
@@ -183,10 +327,7 @@ def _tenant_summary_batch(session, tenant_ids) -> dict[str, dict[str, int]]:
|
||||
.group_by(Campaign.tenant_id)
|
||||
.all()
|
||||
)
|
||||
return {
|
||||
tenant_id: {"campaigns": int(count)}
|
||||
for tenant_id, count in rows
|
||||
}
|
||||
return {tenant_id: {"campaigns": int(count)} for tenant_id, count in rows}
|
||||
|
||||
|
||||
def _campaigns_router(context: ModuleContext):
|
||||
@@ -207,14 +348,21 @@ manifest = ModuleManifest(
|
||||
id="campaigns",
|
||||
name="Campaigns",
|
||||
version="0.1.12",
|
||||
required_capabilities=(CAPABILITY_AUTH_PRINCIPAL_RESOLVER, CAPABILITY_AUTH_PERMISSION_EVALUATOR),
|
||||
optional_capabilities=(CAPABILITY_ACCESS_REFERENCE_OPTIONS,),
|
||||
required_capabilities=(
|
||||
CAPABILITY_AUTH_PRINCIPAL_RESOLVER,
|
||||
CAPABILITY_AUTH_PERMISSION_EVALUATOR,
|
||||
),
|
||||
optional_capabilities=(
|
||||
CAPABILITY_ACCESS_REFERENCE_OPTIONS,
|
||||
CAPABILITY_APPROVAL_REQUESTS,
|
||||
),
|
||||
optional_dependencies=(
|
||||
"files",
|
||||
"mail",
|
||||
"notifications",
|
||||
"addresses",
|
||||
"postbox",
|
||||
"approvals",
|
||||
),
|
||||
provides_interfaces=(
|
||||
ModuleInterfaceProvider(name="campaigns.access", version="0.1.6"),
|
||||
@@ -278,6 +426,12 @@ manifest = ModuleManifest(
|
||||
version_max_exclusive="0.2.0",
|
||||
optional=True,
|
||||
),
|
||||
ModuleInterfaceRequirement(
|
||||
name=CAPABILITY_APPROVAL_REQUESTS,
|
||||
version_min="0.1.0",
|
||||
version_max_exclusive="0.2.0",
|
||||
optional=True,
|
||||
),
|
||||
),
|
||||
permissions=PERMISSIONS,
|
||||
route_factory=_campaigns_router,
|
||||
@@ -285,7 +439,13 @@ manifest = ModuleManifest(
|
||||
tenant_summary_providers=(_tenant_summary,),
|
||||
tenant_summary_batch_providers=(_tenant_summary_batch,),
|
||||
nav_items=(
|
||||
NavItem(path="/campaigns", label="Campaigns", icon="campaign", required_any=CAMPAIGN_MODULE_REQUIRED_ANY, order=20),
|
||||
NavItem(
|
||||
path="/campaigns",
|
||||
label="Campaigns",
|
||||
icon="campaign",
|
||||
required_any=CAMPAIGN_MODULE_REQUIRED_ANY,
|
||||
order=20,
|
||||
),
|
||||
),
|
||||
frontend=FrontendModule(
|
||||
module_id="campaigns",
|
||||
@@ -321,8 +481,16 @@ manifest = ModuleManifest(
|
||||
FrontendRoute(path="/templates", component="TemplatesPage", order=90),
|
||||
),
|
||||
nav_items=(
|
||||
NavItem(path="/campaigns", label="Campaigns", icon="campaign", required_any=CAMPAIGN_MODULE_REQUIRED_ANY, order=20),
|
||||
NavItem(path="/templates", label="Templates", icon="layout-template", order=90),
|
||||
NavItem(
|
||||
path="/campaigns",
|
||||
label="Campaigns",
|
||||
icon="campaign",
|
||||
required_any=CAMPAIGN_MODULE_REQUIRED_ANY,
|
||||
order=20,
|
||||
),
|
||||
NavItem(
|
||||
path="/templates", label="Templates", icon="layout-template", order=90
|
||||
),
|
||||
),
|
||||
view_surfaces=(
|
||||
ViewSurface(
|
||||
@@ -384,21 +552,34 @@ manifest = ModuleManifest(
|
||||
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"),
|
||||
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"),
|
||||
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"),
|
||||
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.",),
|
||||
unlocks=(
|
||||
"Audited direct, derived, combined, and pre-acceptance fallback delivery to Postboxes.",
|
||||
),
|
||||
metadata={
|
||||
"kind": "workflow",
|
||||
"route": "/campaigns/{campaign_id}/global-settings",
|
||||
@@ -439,8 +620,16 @@ manifest = ModuleManifest(
|
||||
),
|
||||
links=(
|
||||
DocumentationLink(label="Campaigns", href="/campaigns", 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"),
|
||||
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",),
|
||||
unlocks=("Profile-backed SMTP delivery and optional IMAP append-to-Sent.",),
|
||||
@@ -480,13 +669,27 @@ manifest = ModuleManifest(
|
||||
conditions=(
|
||||
DocumentationCondition(
|
||||
required_modules=("campaigns", "mail"),
|
||||
any_scopes=("mail:profile:write", "admin:policies:read", "system:settings:read"),
|
||||
any_scopes=(
|
||||
"mail:profile:write",
|
||||
"admin:policies:read",
|
||||
"system:settings:read",
|
||||
),
|
||||
),
|
||||
),
|
||||
links=(
|
||||
DocumentationLink(label="Mail profiles", href="/settings?section=mail-profiles", kind="runtime"),
|
||||
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"),
|
||||
DocumentationLink(
|
||||
label="Mail profiles",
|
||||
href="/settings?section=mail-profiles",
|
||||
kind="runtime",
|
||||
),
|
||||
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"),
|
||||
unlocks=("Auditable, reusable transport configuration across campaigns.",),
|
||||
@@ -514,13 +717,27 @@ manifest = ModuleManifest(
|
||||
conditions=(
|
||||
DocumentationCondition(
|
||||
required_modules=("campaigns", "mail"),
|
||||
any_scopes=("campaigns:diagnostic:read", "campaigns:campaign:reconcile", "mail:profile:test"),
|
||||
any_scopes=(
|
||||
"campaigns:diagnostic:read",
|
||||
"campaigns:campaign:reconcile",
|
||||
"mail:profile:test",
|
||||
),
|
||||
),
|
||||
),
|
||||
links=(
|
||||
DocumentationLink(label="Campaign operator queue", href="/campaigns/queue", kind="runtime"),
|
||||
DocumentationLink(label="Campaign reports", href="/campaigns/reports", kind="runtime"),
|
||||
DocumentationLink(label="Campaign delivery runbook", href="govoplan-campaign/docs/CAMPAIGN_DELIVERY_RUNBOOK.md", kind="repository"),
|
||||
DocumentationLink(
|
||||
label="Campaign operator queue",
|
||||
href="/campaigns/queue",
|
||||
kind="runtime",
|
||||
),
|
||||
DocumentationLink(
|
||||
label="Campaign reports", href="/campaigns/reports", kind="runtime"
|
||||
),
|
||||
DocumentationLink(
|
||||
label="Campaign delivery runbook",
|
||||
href="govoplan-campaign/docs/CAMPAIGN_DELIVERY_RUNBOOK.md",
|
||||
kind="repository",
|
||||
),
|
||||
),
|
||||
related_modules=("mail", "audit"),
|
||||
unlocks=("Fail-closed recovery without exposing Mail credentials.",),
|
||||
@@ -548,16 +765,30 @@ manifest = ModuleManifest(
|
||||
conditions=(
|
||||
DocumentationCondition(
|
||||
required_modules=("campaigns",),
|
||||
required_scopes=("campaigns:campaign:update", "campaigns:campaign:validate", "campaigns:campaign:build"),
|
||||
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"),
|
||||
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.",),
|
||||
unlocks=(
|
||||
"A reviewable build whose exact recipient-specific effects can be inspected before delivery.",
|
||||
),
|
||||
metadata={
|
||||
"kind": "workflow",
|
||||
"route": "/campaigns/{campaign_id}/global-settings",
|
||||
@@ -608,15 +839,24 @@ manifest = ModuleManifest(
|
||||
conditions=(
|
||||
DocumentationCondition(
|
||||
required_modules=("campaigns",),
|
||||
required_scopes=("campaigns:campaign:read", "campaigns:campaign:review"),
|
||||
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"),
|
||||
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.",),
|
||||
unlocks=(
|
||||
"An attributable review-completion record for the exact built messages inspected.",
|
||||
),
|
||||
metadata={
|
||||
"kind": "workflow",
|
||||
"route": "/campaigns/{campaign_id}/review",
|
||||
@@ -652,20 +892,38 @@ manifest = ModuleManifest(
|
||||
conditions=(
|
||||
DocumentationCondition(
|
||||
required_modules=("campaigns",),
|
||||
any_scopes=("campaigns:campaign:retry", "campaigns:campaign:reconcile", "campaigns:diagnostic:read"),
|
||||
any_scopes=(
|
||||
"campaigns:campaign:retry",
|
||||
"campaigns:campaign:reconcile",
|
||||
"campaigns:diagnostic:read",
|
||||
),
|
||||
),
|
||||
),
|
||||
links=(
|
||||
DocumentationLink(label="Campaign operator queue", href="/campaigns/queue", kind="runtime"),
|
||||
DocumentationLink(label="Campaign delivery runbook", href="govoplan-campaign/docs/CAMPAIGN_DELIVERY_RUNBOOK.md", kind="repository"),
|
||||
DocumentationLink(
|
||||
label="Campaign operator queue",
|
||||
href="/campaigns/queue",
|
||||
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.",),
|
||||
unlocks=(
|
||||
"Evidence-backed recovery without accidental duplicate external effects.",
|
||||
),
|
||||
metadata={
|
||||
"kind": "workflow",
|
||||
"route": "/campaigns/queue",
|
||||
"screen": "Campaign operator queue",
|
||||
"help_contexts": ["campaign.review-send", "campaign.report", "campaign.audit"],
|
||||
"help_contexts": [
|
||||
"campaign.review-send",
|
||||
"campaign.report",
|
||||
"campaign.audit",
|
||||
],
|
||||
"prerequisites": [
|
||||
"You may perform the selected retry or reconciliation action.",
|
||||
"Provider, mailbox, worker, and campaign evidence has been preserved.",
|
||||
@@ -691,20 +949,40 @@ manifest = ModuleManifest(
|
||||
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"),
|
||||
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"),
|
||||
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"),
|
||||
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", "postbox", "files", "addresses", "audit"),
|
||||
unlocks=("A repeatable, supportable Campaign demonstration rather than an unverified module assembly.",),
|
||||
unlocks=(
|
||||
"A repeatable, supportable Campaign demonstration rather than an unverified module assembly.",
|
||||
),
|
||||
metadata={
|
||||
"kind": "reference",
|
||||
"route": "/campaigns",
|
||||
@@ -735,8 +1013,16 @@ manifest = ModuleManifest(
|
||||
),
|
||||
),
|
||||
links=(
|
||||
DocumentationLink(label="Campaign operator queue", href="/campaigns/queue", kind="runtime"),
|
||||
DocumentationLink(label="Campaign delivery runbook", href="govoplan-campaign/docs/CAMPAIGN_DELIVERY_RUNBOOK.md", kind="repository"),
|
||||
DocumentationLink(
|
||||
label="Campaign operator queue",
|
||||
href="/campaigns/queue",
|
||||
kind="runtime",
|
||||
),
|
||||
DocumentationLink(
|
||||
label="Campaign delivery runbook",
|
||||
href="govoplan-campaign/docs/CAMPAIGN_DELIVERY_RUNBOOK.md",
|
||||
kind="repository",
|
||||
),
|
||||
),
|
||||
related_modules=("files", "ops", "mail"),
|
||||
metadata={
|
||||
@@ -800,9 +1086,22 @@ manifest = ModuleManifest(
|
||||
maturity="vertical_slice",
|
||||
documentation_ref="docs/CAMPAIGN_HANDBOOK.md",
|
||||
test_ref="tests/test_execution_snapshot_integrity.py",
|
||||
known_limits=("Target-environment recovery and accessibility evidence is incomplete for reference-ready maturity.",),
|
||||
owned_concepts=("campaign", "campaign version", "recipient snapshot", "delivery job", "delivery report"),
|
||||
non_owned_concepts=("mail transport", "postbox", "durable address directory", "file storage"),
|
||||
known_limits=(
|
||||
"Target-environment recovery and accessibility evidence is incomplete for reference-ready maturity.",
|
||||
),
|
||||
owned_concepts=(
|
||||
"campaign",
|
||||
"campaign version",
|
||||
"recipient snapshot",
|
||||
"delivery job",
|
||||
"delivery report",
|
||||
),
|
||||
non_owned_concepts=(
|
||||
"mail transport",
|
||||
"postbox",
|
||||
"durable address directory",
|
||||
"file storage",
|
||||
),
|
||||
recovery_docs=("docs/CAMPAIGN_DELIVERY_RUNBOOK.md",),
|
||||
security_docs=("docs/ACCESS_EXPLANATION_COVERAGE.md",),
|
||||
operations_docs=("docs/CAMPAIGN_DELIVERY_RUNBOOK.md",),
|
||||
|
||||
Reference in New Issue
Block a user