18 — Campaign Create/Edit (Screen 3, `/app/testimonial-campaigns/:id`)
Cursor-ready plan: create/update testimonial campaigns with trigger, delay, audience targeting, channel, reminders, and incentives.
18 — Campaign Create/Edit (Screen 3)
Section titled “18 — Campaign Create/Edit (Screen 3)”Source: 02-Implementation-Blueprint.md — Screen 3 - Campaign Create/Edit (/app/testimonial-campaigns/:id).
Product alignment: 01-Post-Purchase-Video-Testimonial-Collector-Plan.md — post-purchase automation rules with reminders and optional incentives.
This document is a build spec only. No code changes are implied until a task references this file.
Related: 17-campaigns-list-screen-2.md (table + row actions), 16-templates-screen-4.md (message content), 07-email-sms-request-delivery-pipeline.md (campaign execution), 12-moderation-settings-screen-9.md (content gate rules are separate).
0) Goal (one sentence)
Section titled “0) Goal (one sentence)”Merchants can create or edit a campaign that defines when to request testimonials, who receives requests, how (email/sms/both), reminder policy, and incentive details, with strong validation before activation.
1) Route and file
Section titled “1) Route and file”| Item | Value |
|---|---|
| Suggested file | app/routes/app.testimonial-campaign.$id.jsx |
| URLs | /app/testimonial-campaigns/new (create) and /app/testimonial-campaigns/:id (edit) |
You can implement create mode with :id = "new" or separate route; keep URL semantics easy for deep links from Screen 2.
Auth: authenticate.admin(request); scope every read/write by shopId.
2) Form fields (must match blueprint)
Section titled “2) Form fields (must match blueprint)”From Screen 3:
- Campaign name (text)
- Active toggle (boolean)
- Trigger event (select)
- Delay days (int, min 0, max 60)
- Audience:
- All products toggle
- Collection selector (multi)
- Product selector (multi)
- Channel (
email,sms,both) - Reminder rules:
- Enable reminder (boolean)
- Reminder delay days (int)
- Max reminders (int)
- Incentive:
- Enabled (boolean)
- Incentive type (
discount_code,gift_card,none) - Incentive value/code
3) Data model mapping
Section titled “3) Data model mapping”Primary model: TestimonialCampaign (§5.2).
Targeting linkage:
TestimonialCampaignProduct(§5.3) for product targeting.
3.1 Collection targeting note
Section titled “3.1 Collection targeting note”Blueprint includes collection targeting, but only product mapping table is specified in §5.3.
Choose one path and document:
- Add
TestimonialCampaignCollectionmodel now, or - Store collection ids in JSON field on campaign for v1, migrate later.
Do not fake collection support in UI if persistence path is not implemented.
4) Loader behavior
Section titled “4) Loader behavior”4.1 Create mode
Section titled “4.1 Create mode”- Return default form values.
- Provide product/collection options lists for selectors.
4.2 Edit mode
Section titled “4.2 Edit mode”- Fetch campaign by
id + shopId. - Fetch related product mappings (+ collection mappings if implemented).
- Map DB values to form defaults.
4.3 Shared reference data
Section titled “4.3 Shared reference data”- Product options:
- Preferred: local
Productmirror table. - Fallback: Shopify Admin API search if mirror unavailable.
- Preferred: local
- Collection options:
- Mirror/API depending on what exists in app.
5) Validation rules (server-side required)
Section titled “5) Validation rules (server-side required)”5.1 Core
Section titled “5.1 Core”name: required, trimmed, max length (e.g. 120).triggerEvent: allowed values only (order_paid,order_fulfilled).delayDays: integer between 0 and 60.channel: one ofemail,sms,both.
5.2 Audience
Section titled “5.2 Audience”- If
allProducts=true, ignore product/collection selections. - If
allProducts=false, require at least one product or collection target. - Prevent duplicate product ids.
5.3 Reminder
Section titled “5.3 Reminder”- If
reminderEnabled=false, forcemaxReminders=0(or keep as entered but ignored—pick one and document). - If enabled:
reminderDelayDays >= 1maxReminderswithin safe range (e.g. 1..3 v1)
5.4 Incentive
Section titled “5.4 Incentive”- If
incentiveEnabled=false, set type/value null ornone. - If enabled:
- type required (
discount_codeorgift_card) - value/code required
- type required (
5.5 Activation guardrail
Section titled “5.5 Activation guardrail”If merchant sets campaign active, block activation with clear error when:
- no valid audience,
- channel/template mismatch (e.g. SMS channel but no SMS template fallback from Screen 4),
- invalid reminder config.
6) Action intents
Section titled “6) Action intents”Use single route action with intents:
intent=create_campaignintent=update_campaignintent=toggle_active- optional
intent=delete_campaign(if you want hard delete; blueprint suggests archive from list)
6.1 Transaction behavior
Section titled “6.1 Transaction behavior”For create/update:
- Upsert campaign row
- Replace target mapping rows atomically:
- Delete existing mappings for campaign
- Insert current selection set
Use Prisma $transaction for consistency.
6.2 Status field alignment
Section titled “6.2 Status field alignment”Blueprint has status (active, paused, archived) plus “Active toggle”.
Map active toggle to:
active=true=>status='active'active=false=>status='paused'
Do not allow toggling archived campaign back to active from this screen unless explicitly supported.
7) UI layout (Polaris)
Section titled “7) UI layout (Polaris)”Suggested section cards:
- Basic info
- Name, active toggle
- Trigger & schedule
- Trigger event, delay days
- Audience
- All products checkbox
- Product/collection multi-select (enabled when allProducts=false)
- Channel
- Email/SMS/Both
- Reminders
- Enable, delay, max reminders
- Incentive
- Enable + type + value
- Save actions
- Save draft, Save & activate (optional split action)
7.1 UX details
Section titled “7.1 UX details”- Show helper text examples for trigger/delay.
- Inline validation near each field.
- Warning banner if active campaign has missing template coverage.
8) Template dependency checks (Screen 4)
Section titled “8) Template dependency checks (Screen 4)”Before allowing status=active, verify available template resolution:
- If channel includes email:
initial_requestemail template must exist via fallback chain. - If reminders enabled: reminder template(s) exist or system fallback exists.
- If channel includes sms: sms templates available or explicit fallback.
Reference resolver from 16-templates-screen-4.md (campaign-specific -> shop default -> system fallback).
9) Integration with sender pipeline (07)
Section titled “9) Integration with sender pipeline (07)”07 campaign selection should assume this screen enforces valid config.
Required contract from this screen to pipeline:
triggerEventdelayDaysstatuschannelallProducts+ mapped targetsreminderEnabled,reminderDelayDays,maxReminders- incentive fields for template variables (
{{incentive_text}})
10) Testing checklist
Section titled “10) Testing checklist”- Create campaign with minimal valid fields (allProducts=true).
- Create campaign with product targeting and saved mapping rows.
- Validation blocks activation when audience empty.
- Reminder constraints enforced (delay/max).
- Incentive fields enforced when enabled.
- Editing campaign updates mappings atomically (no stale targets).
- Cross-shop campaign id access blocked.
- Archived campaign cannot be accidentally reactivated.
11) Implementation order (for Cursor)
Section titled “11) Implementation order (for Cursor)”- Build loader for create/edit modes.
- Build Polaris form sections and state mapping.
- Add server validation and create/update actions.
- Add mapping replace logic in transaction.
- Add activation guardrail checks (templates + audience).
- Connect navigation back to Screen 2 list.
12) References
Section titled “12) References”02-Implementation-Blueprint.md— Screen 3,§5.2,§5.317-campaigns-list-screen-2.md— status model and list actions16-templates-screen-4.md— template fallback and send-test expectations07-email-sms-request-delivery-pipeline.md— runtime execution
13) Note on numbering
Section titled “13) Note on numbering”This folder already includes 05 through 17 plans. This file is 18-....