42 — TestimonialCampaign Model & Automation Rules (Blueprint §5.2)
Cursor-ready plan for implementing the core campaign model, activation rules, scheduling semantics, and pipeline contracts.
42 — TestimonialCampaign Model & Automation Rules (Blueprint §5.2)
Section titled “42 — TestimonialCampaign Model & Automation Rules (Blueprint §5.2)”Source: 02-Implementation-Blueprint.md — §5.2 New model: TestimonialCampaign.
This document is a build spec only. No code changes are implied until a task references this file.
Related: 17 (campaign list), 18 (campaign create/edit), 41 (campaign-product mapping), 07 (request pipeline), 39 (request lifecycle), 20 (schema).
0) Goal (one sentence)
Section titled “0) Goal (one sentence)”Implement TestimonialCampaign as the authoritative automation policy object that controls trigger, targeting mode, channel, reminder behavior, and incentives for outbound testimonial requests.
1) Blueprint model recap
Section titled “1) Blueprint model recap”Blueprint §5.2 fields:
idshopIdnamestatus(active|paused|archived)triggerEvent(order_paid|order_fulfilled)delayDayschannel(email|sms|both)allProductsreminderEnabledreminderDelayDaysmaxRemindersincentiveEnabledincentiveType(discount_code|gift_card)incentiveValue- timestamps
Index:
@@index([shopId, status])
2) Scope boundaries
Section titled “2) Scope boundaries”In scope
Section titled “In scope”- model + migration
- validation and activation constraints
- runtime interpretation by request pipeline
- campaign status lifecycle and safe transitions
Out of scope
Section titled “Out of scope”- A/B testing variants per campaign
- multi-trigger campaign orchestration
- campaign-level analytics rollups beyond existing screens
3) Canonical meaning of a campaign
Section titled “3) Canonical meaning of a campaign”A campaign is:
- a shop-scoped rule set
- deciding when to send (
triggerEvent,delayDays) - deciding who to send to (
allProducts+ mapping table) - deciding how to send (
channel, templates) - deciding follow-up behavior (
reminder*) - optionally attaching incentive messaging context
This model should not directly store request execution state (that belongs to TestimonialRequest).
4) Status lifecycle contract
Section titled “4) Status lifecycle contract”Allowed statuses:
activepausedarchived
Transition rules:
active <-> pausedactive|paused -> archived- archived is terminal by default (restore optional future action)
Runtime contract:
- pipeline selects only
status='active'.
5) Validation rules (server-side)
Section titled “5) Validation rules (server-side)”5.1 Core
Section titled “5.1 Core”namerequired, trimmedtriggerEventin allowed enumdelayDaysinteger between 0 and 60channelin allowed enum
5.2 Audience mode
Section titled “5.2 Audience mode”- if
allProducts=true-> no required product mappings - if
allProducts=false-> require at least one target in mapping table (41) or equivalent collection mapping
5.3 Reminder config
Section titled “5.3 Reminder config”- if
reminderEnabled=false:maxRemindersshould be 0 (or ignored by pipeline; choose one behavior)
- if enabled:
reminderDelayDays >= 1maxReminderswithin safe bounds (recommend 1..3 v1)
5.4 Incentive config
Section titled “5.4 Incentive config”- if
incentiveEnabled=false:- clear or ignore
incentiveType,incentiveValue
- clear or ignore
- if enabled:
- require valid
incentiveType - require non-empty
incentiveValue
- require valid
6) Activation guardrails
Section titled “6) Activation guardrails”Before setting status to active, ensure:
- audience is valid
- required templates resolve for selected channel and reminder stages
- schedule fields valid
If guardrail fails:
- block activation with actionable error details.
This prevents runtime failures in send worker.
7) Runtime pipeline contract
Section titled “7) Runtime pipeline contract”Sender/request planner should consume campaign as read-only input:
triggerEvent-> webhook matchdelayDays->scheduledForchannel-> template/provider path- reminder fields -> reminder scheduler
- incentive fields ->
{{incentive_text}}rendering context
Do not mutate campaign row during request processing except optional operational fields (lastSentAt if adopted).
8) Optional operational fields (recommended)
Section titled “8) Optional operational fields (recommended)”Not in blueprint but practical:
lastSentAt DateTime?lastErrorAt DateTime?lastErrorSummary String?
These improve campaign list diagnostics without scanning all requests.
If added, keep them nullable and non-blocking.
9) Query patterns
Section titled “9) Query patterns”9.1 Admin list (Screen 2)
Section titled “9.1 Admin list (Screen 2)”- filter by
shopId - status/channel/trigger filters
- sort by
updatedAtorlastSentAt
9.2 Pipeline
Section titled “9.2 Pipeline”- fetch active campaigns for shop + trigger
- prefetch targeting mappings in batch
10) Compliance and data retention
Section titled “10) Compliance and data retention”Campaigns contain no direct customer PII.
On shop redact:
- campaigns should delete via shop cascade.
Archived campaigns may be retained for merchant audit/history unless explicit delete action is introduced.
11) Acceptance criteria
Section titled “11) Acceptance criteria”- Campaign create/update persists all blueprint fields correctly.
- Invalid configs are blocked by server validation.
- Activation guardrails prevent broken active campaigns.
- Pipeline includes only active campaigns.
- Archive state removes campaign from runtime selection.
12) Suggested implementation order (for Cursor)
Section titled “12) Suggested implementation order (for Cursor)”- Add Prisma model + migration.
- Add shared validation schema/constants for campaign fields.
- Implement create/edit actions with status transition logic.
- Add activation guardrails (template + targeting checks).
- Wire request pipeline to consume campaign fields.
13) References
Section titled “13) References”02-Implementation-Blueprint.md— §5.218-campaign-create-edit-screen-3.md17-campaigns-list-screen-2.md41-testimonial-campaign-product-model-blueprint-section-5-3.md07-email-sms-request-delivery-pipeline.md
14) Note on numbering
Section titled “14) Note on numbering”This folder already includes 05 through 41 plans. This file is 42-....