campaign-service — Jira-Ready Epics & User Stories
Status: populated Owner: Product Last updated: 2026-04-21 Service prefix: CAMP Scope: Campaign builder (segments, schedule, throttle, A/B, kill-switch); template catalog with merge fields, conditional content, multi-language; approved-template workflow paired with
EP-CE-13; campaign reporting. Per ADR-0004 §3 and07-epics-and-user-stories.md§6.11.
Epic Summary
| Epic ID | Title | Stories | Points |
|---|---|---|---|
| EP-CAMP-01 | Campaign Builder (segments, schedule, throttle, A/B, kill-switch) | US-CAMP-001 – US-CAMP-008 | 38 |
| EP-CAMP-02 | Template Catalog (merge fields, conditional content, multi-language) | US-CAMP-009 – US-CAMP-014 | 24 |
| EP-CAMP-03 | Approved-Template Workflow (paired with EP-CE-13) | US-CAMP-015 – US-CAMP-018 | 16 |
| EP-CAMP-04 | Campaign Reporting (deliverability, spend, opt-outs, conversion) | US-CAMP-019 – US-CAMP-022 | 14 |
| Total | 22 stories | 92 |
EP-CAMP-01 · Campaign Builder (segments, schedule, throttle, A/B, kill-switch)
Context: Tenants build, schedule, throttle, A/B-test, and emergency-stop campaigns. Throttle policy must respect tenant TPS budgets and per-MNO ceilings. Kill-switch must take effect within 5 s end-to-end. Pre-flight cost estimate prevents bill-shock.
US-CAMP-001 · Define Recipient Segment Using JSON DSL
Type: Feature | Points: 8
Description: As a campaign manager, I need to define a recipient segment using a JSON DSL (filters on consent scope, country, opt-in date, custom tenant attributes) so I can target the exact audience without writing SQL.
Acceptance Criteria:
-
POST /v1/campaigns/segmentsaccepts JSON DSL with predicates (eq,in,gt,lt,between,not,and,or) - Predicate fields:
consent.scope,consent.grantedAfter,country,lineType(mobile/fixed), tenant-defined attribute keys - Returns
segmentId+estimatedCount(P95 ≤ 2 s for segments < 5 M) - Segment materialised in
camp.segmentsand snapshot stored - Saved segment re-usable across campaigns
US-CAMP-002 · Schedule Campaign (one-shot, recurring, time-zone aware)
Type: Feature | Points: 5
Description: As a campaign manager, I want to schedule a campaign one-shot at a specific time, recurring (daily/weekly/monthly), or immediately, with proper time-zone handling.
Acceptance Criteria:
-
POST /v1/campaigns/{id}/scheduleaccepts{ type: ONE_SHOT|RECURRING|IMMEDIATE, scheduledAt, tz, recurrenceRule (RRULE) } - Tz mandatory; default Asia/Kabul
- Scheduled campaigns visible on a calendar view
- Recurrence honours regulator quiet windows (per
EP-RE-07)
US-CAMP-003 · Throttle Dispatch by Tenant TPS and Per-MNO Ceiling
Type: Feature | Points: 8
Description: As a campaign manager, I want dispatch throttled to my tenant's TPS budget and per-MNO contracts so a campaign cannot exceed reserved capacity.
Acceptance Criteria:
- Token-bucket rate-limit at submit-time; tenant TPS reads from
auth.tenant_rate_limits - Per-MNO TPS ceiling enforced via
routing-enginereservation (perEP-RE-06) - Excess work queued; pacing metric
camp_pacing_seconds_in_queue - Tenant can override TPS down (not up) per campaign
US-CAMP-004 · A/B Variant Assignment by Consistent Hashing
Type: Feature | Points: 5
Description: As a campaign manager, I want A/B variant assignment by consistent hashing on recipient MSISDN so the same recipient sees the same variant across resends.
Acceptance Criteria:
-
POST /v1/campaigns/{id}/variantsdefines variants with weights (must sum 1.0) - Assignment:
bucketIdx = murmur3(msisdn || campaignId) mod totalWeight - Variant assignment persisted in
camp.variant_assignments - Re-running same campaign yields same variant per recipient
US-CAMP-005 · Kill-Switch Halts In-Flight Dispatch Within 5 s
Type: Feature | Points: 5
Description: As a campaign manager, I want a kill-switch that halts in-flight dispatch end-to-end within 5 s so a problematic campaign can be stopped immediately.
Acceptance Criteria:
-
POST /v1/campaigns/{id}/killflips Redis flagcamp:kill:{id} - All workers consult flag every 1 s; on positive, abort current batch
- In-flight messages already at smpp-connector NOT recallable (documented)
- Audit row +
camp.killed.v1event with kill timestamp + initiator - Test: 1 M-recipient campaign killed within 5 s end-to-end
US-CAMP-006 · Pause and Resume Campaign
Type: Feature | Points: 3
Description: As a campaign manager, I want to pause and resume a long-running campaign without losing state.
Acceptance Criteria:
-
POST /v1/campaigns/{id}/pauseand/resume - Pause stops dispatch; queued recipients held in
camp.pending - Resume continues from last checkpoint
- Status transitions logged
US-CAMP-007 · Pre-Flight Spend Estimate
Type: Feature | Points: 3
Description: As a campaign manager, I want a pre-flight cost estimate before I launch so I avoid bill-shock.
Acceptance Criteria:
-
POST /v1/campaigns/{id}/estimatereturns{ recipients, perRecipientPrice, totalEstimated, currency, breakdownByMno } - Pricing pulled from
billing-service - Estimated count from US-CAMP-001 segment snapshot
- Estimate refreshed if segment is re-materialised
US-CAMP-008 · Per-Tenant Quotas (Active Campaigns, Daily Volume, Segment Size)
Type: Feature | Points: 3
Description: As a platform admin, I need per-tenant quotas on active campaigns, daily volume, and segment size to prevent platform-wide abuse.
Acceptance Criteria:
-
camp.tenant_quotastable with defaults per tenant tier - Quota check at create + at launch
- Breach → 422 with code
QUOTA_EXCEEDED - Override requires platform-admin role + audit
EP-CAMP-02 · Template Catalog (merge fields, conditional content, multi-language)
US-CAMP-009 · Create Template with Mustache + ICU Plurals
Type: Feature | Points: 5
Description: As a campaign manager, I need to create a template using Mustache merge fields and ICU plurals so localisation and personalisation work correctly.
Acceptance Criteria:
- Template body supports
{{firstName}}Mustache +{count, plural, =0 {none} =1 {one} other {#}}ICU - Variables declared in
variableSchema(name, type, required, default) - Validation rejects undeclared variables
- Unit tests cover ICU plurals for Pashto/Dari/Arabic/English
US-CAMP-010 · Template Versioning
Type: Feature | Points: 3
Description: As a campaign manager, I want template edits to create new versions without breaking running campaigns.
Acceptance Criteria:
- Each save creates a new
camp.template_versionsrow; previous versions immutable - Running campaigns continue with the version they started with
- New campaigns use latest by default; explicit pin available
US-CAMP-011 · Multi-Language Template Variants
Type: Feature | Points: 5
Description: As a campaign manager, I want a single logical template with per-language variants (Pashto/Dari/Arabic/English) so recipients receive their preferred language.
Acceptance Criteria:
- Template object has
variants[]keyed by language ISO 639-1 - Recipient language inferred from
consent-ledger-serviceprofile or default tenant locale - Missing variant → fallback to default language
- Localisation glossary linked (
EP-CUST-09)
US-CAMP-012 · Conditional Content Blocks
Type: Feature | Points: 5
Description: As a campaign manager, I want conditional content blocks so the same template renders different content for different recipient attributes.
Acceptance Criteria:
- Syntax:
{{#if isPremium}} … {{/if}} - Conditions can reference any segment attribute
- Linter prevents nested conditions deeper than 3
- Preview tool renders sample for each attribute combination
US-CAMP-013 · Template Catalog Search and Filter
Type: Feature | Points: 3
Description: As a campaign manager, I want to search and filter the template catalog so I find re-usable templates fast.
Acceptance Criteria:
- Filters: tenant, category, status (DRAFT/APPROVED/SUSPENDED), language, last-used date
- Free-text search on name + body excerpt
- Default sort: most recently used first
US-CAMP-014 · Template Quality Score
Type: Feature | Points: 3
Description: As a campaign manager, I want a quality score per template (length, link count, opt-out instruction presence, language correctness) so I can improve templates before launch.
Acceptance Criteria:
- Score 0–100 computed at template-save time
- Components: length (penalty for >2 segments), opt-out presence (mandatory for marketing), language-spelling, link-count (penalty for >2)
- Score visible in template editor with improvement suggestions
EP-CAMP-03 · Approved-Template Workflow (paired with EP-CE-13)
US-CAMP-015 · Submit Template for Compliance Approval
Type: Feature | Points: 5
Description: As a campaign manager, I want to submit a template for compliance approval so it can be used by trusted-tenant fast-path.
Acceptance Criteria:
-
POST /v1/campaigns/templates/:id/submit-approval→ statusPENDING_APPROVAL - Routes to compliance-engine via gRPC
SubmitTemplate(EP-CE-13) - Tenant receives notification on decision (APPROVED/REJECTED/REQUEST_INFO)
US-CAMP-016 · Trusted-Tenant Fast-Path (EP-CE-13)
Type: Feature | Points: 3
Description: As a trusted tenant, I want approved templates to be eligible for the trusted-tenant fast-path so OTP-class messages skip blocking compliance evaluation.
Acceptance Criteria:
- On approval,
compliance.template.approved.v1consumed; template flagged eligible - Orchestrator (per
EP-ORCH-07) verifies fingerprint + tenant grant at submit - Eligible flag visible in template editor
US-CAMP-017 · Approval Workflow States and Reviewer Actions
Type: Feature | Points: 5
Description: As a compliance reviewer, I want approve/reject/request-info actions with mandatory reason for templates.
Acceptance Criteria:
- Reviewer UI in admin-dashboard
- Three actions; reason mandatory
- APPROVED valid 12 months; renewal required
- REJECTED → tenant sees reason; can edit + resubmit
US-CAMP-018 · Template Approval SLA & Auto-Escalation
Type: Feature | Points: 3
Description: As a tenant, I want approval SLA enforced so I can plan launches.
Acceptance Criteria:
- SLA: 2 business days; cron flags overdue
- Auto-escalation to compliance lead at +1 day
- Tenant-portal countdown visible
EP-CAMP-04 · Campaign Reporting (deliverability, spend, opt-outs, conversion)
US-CAMP-019 · Campaign Reporting Dashboard (Deliverability, Spend, Opt-Outs)
Type: Feature | Points: 5
Description: As a campaign manager, I want a per-campaign dashboard showing deliverability, spend, opt-outs, conversion in real time.
Acceptance Criteria:
- Live tiles: total recipients, sent, delivered, failed, opted-out, spend
- Per-MNO breakdown
- Per-variant breakdown (when A/B)
- Updates every 30 s via WebSocket
US-CAMP-020 · Conversion Tracking via Signed Callback URL
Type: Feature | Points: 3
Description: As a campaign manager, I want to track conversion via a per-recipient signed callback URL so I can attribute outcomes to the campaign.
Acceptance Criteria:
- Per-recipient short-link
https://g.ghasi.io/c/{token}; HMAC-signed token - Click handler logs
camp.conversion.v1event with campaign, variant, recipient - Click→destination redirect; tenant configures destination per campaign
- Conversion rate visible on campaign dashboard
US-CAMP-021 · Live Opt-Out Drop During Running Campaign
Type: Feature | Points: 3
Description: As a compliance officer, I want recipients who opt-out mid-campaign to be dropped from remaining dispatches within 60 s.
Acceptance Criteria:
- Consumer for
consent.revoked.v1; matches against running-campaign queues - Matched recipients removed; metric
camp_opt_out_dropped_totalincremented - Audit row written
US-CAMP-022 · Per-Variant Reporting with Statistical Significance
Type: Feature | Points: 3
Description: As a campaign manager, I want per-variant deliverability and conversion with statistical-significance indicator so I can decide a winner.
Acceptance Criteria:
- Two-proportion z-test computed at p < 0.05 threshold
- Winner indicator only displayed once significance reached
- Sample-size advisory shown when too small