Skip to content

16 — Templates (Screen 4, `/app/testimonial-templates`)

Cursor-ready plan: request/reminder template editor with variables, preview, and send-test for email/SMS outreach.

Source: 02-Implementation-Blueprint.mdScreen 4 - Templates (/app/testimonial-templates).

Product alignment: 01-Post-Purchase-Video-Testimonial-Collector-Plan.md — Messaging in MVP (request + reminders).

This document is a build spec only. No code changes are implied until a task references this file.

Related: 07-email-sms-request-delivery-pipeline.md (template consumption in sender worker), 13-requests-log-blueprint-screen-10.md (diagnostics), 03-Pricing-Options.md (incentive messaging context).


Merchants can create/edit message templates for initial and reminder outreach, use trusted variables, preview final output, and run a safe send-test before turning campaigns on.


ItemValue
Suggested fileapp/routes/app.testimonial-templates.jsx
URL/app/testimonial-templates

Auth: authenticate.admin(request); templates are shop-scoped.


Use blueprint TestimonialTemplate (§5.4):

  • shopId
  • campaignId (nullable for default/global template)
  • channel (email, sms)
  • templateType (initial_request, reminder_1, reminder_2)
  • subject (email only)
  • body
  • isDefault

Retain unique constraint:

  • @@unique([shopId, campaignId, channel, templateType])

  1. Template selector
    • Channel: Email / SMS
    • Template type: Initial / Reminder 1 / Reminder 2
    • Scope: Global default vs campaign-specific (if campaigns exist)
  2. Editor
    • Subject (shown only when channel=email)
    • Body editor (plain textarea v1; rich editor optional v2)
  3. Variables help panel
    • {{customer_first_name}}
    • {{shop_name}}
    • {{product_name}}
    • {{submission_link}}
    • {{incentive_text}}
  4. Preview pane
    • Render subject/body with sample data
  5. Actions
    • Save template
    • Send test

Create a shared helper (e.g. app/lib/testimonial-template-render.server.js) used by both:

  • this screen preview,
  • send-test action,
  • actual sending worker (07).
  • Unknown tokens remain unchanged (helps detect typos).
  • Missing value fallback:
    • customer_first_name -> there
    • incentive_text -> empty string
  • Collapse extra blank lines after replacement.
  • Enforce allowed token set only (warn on unsupported token patterns).
  • Body required for all channels.
  • Subject required only for email.
  • SMS length warning (e.g. > 320 chars) but do not block save unless product requires.

Use synthetic sample data in loader:

  • customer_first_name = "Alex"
  • shop_name = current shop name
  • product_name = "Sample Product"
  • submission_link = https://{app}/t/sample-token
  • incentive_text = "Get 10% off after approved submission"

Preview updates live as user edits.


  • Test recipient email (for email channel) or phone (for sms channel)
  • Optional sample product name override
  • Intent: send_test_template
  • Render selected template with sample payload.
  • Send through existing provider integrations:
    • Email: app/lib/email.server.js
    • SMS: provider adapter used in 07
  • Rate-limit send-test per shop/user (e.g. 10/hour).
  • Mark message as test in subject/body prefix: [TEST].
  • Log send result (optional TemplateSendTestLog table or structured app logs).

  • Intent: save_template
  • Upsert by (shopId, campaignId, channel, templateType).
  • Track updatedAt.
  • Return toast on success.

Optional:

  • “Reset to default” button for campaign-specific template deletes custom row and falls back to global default.

8) Fallback resolution order (critical for worker)

Section titled “8) Fallback resolution order (critical for worker)”

When sender pipeline requests a template:

  1. Campaign-specific template (campaignId = X)
  2. Shop-level default (campaignId = null, isDefault=true)
  3. Hardcoded system fallback (last resort, deterministic text)

This order must be identical in:

  • send-test,
  • preview,
  • delivery worker.

  • Save email and sms templates independently.
  • Subject hidden/ignored for SMS.
  • Variables render correctly in preview.
  • Unknown variable warning appears.
  • Send-test dispatches and records success/failure.
  • Campaign-specific template overrides default in resolution order.
  • Cross-shop access blocked.

  1. Build loader with selector state + existing template fetch.
  2. Build template render helper with strict allowed variables.
  3. Add save action (upsert).
  4. Add preview pane.
  5. Add send-test action + rate limit.
  6. Wire sender worker (07) to shared template resolver.

  • 02-Implementation-Blueprint.md — Screen 4, §5.4
  • 07-email-sms-request-delivery-pipeline.md — template consumption in sends/reminders
  • 13-requests-log-blueprint-screen-10.md — debugging delivery failures

This folder already includes 05 through 15 plans. This file is 16-... for consistent sequence.