Web 营销模块 — CUJ 关键用户旅程

Campaigns, Automation, Discounts, Tagging, Research Platform | 更新时间: 2026-03-02

路由口径:/admin/marketing/research 为主路径;/admin/marketing/experiments 仅保留兼容重定向别名。
TOUCHES (Pages — 25+): admin/marketing/promotion/page.tsx (6 tabs: Email Templates/SMS Templates/Email Designs/Campaigns/Triggers/Automation), admin/marketing/promotion/email-templates/page.tsx, admin/marketing/promotion/email-templates/editor/page.tsx, admin/marketing/promotion/email-templates/variables/page.tsx, admin/marketing/promotion/email-templates/preview/page.tsx, admin/marketing/promotion/sms-templates/page.tsx, admin/marketing/email-designs/[id]/page.tsx (Canvas Editor), admin/marketing/email-designs/[id]/preview/page.tsx, admin/marketing/email-designs/campaigns/page.tsx, admin/marketing/email-designs/campaigns/[id]/page.tsx (Campaign Detail/Progress), admin/marketing/discounts/page.tsx, admin/marketing/guest-tagging/page.tsx (3 tabs: Overview/Guests/Definitions), admin/marketing/messaging-settings/page.tsx, admin/marketing/strategies/page.tsx, admin/marketing/strategies/new/page.tsx, admin/marketing/strategies/[id]/edit/page.tsx, admin/marketing/research/page.tsx, admin/marketing/research/new/page.tsx, admin/marketing/research/[id]/page.tsx, admin/marketing/research/[id]/edit/page.tsx, admin/marketing/research/[id]/participants/page.tsx, admin/marketing/research/[id]/outreach/page.tsx, admin/marketing/research/[id]/analytics/page.tsx, admin/marketing/analytics/page.tsx

TOUCHES (Components): EmailBuilderEditor.tsx, CanvasEditor.tsx (Fabric.js), CampaignComposer.tsx (4-step wizard), TemplateLibrary.tsx, VariableTree.tsx, VariableDrawer.tsx, VariableCascader.tsx, VariableAutocomplete.tsx, VariableErrorMarker.tsx, DiscountCouponTable.tsx, TriggerTemplatesContent.tsx, AutomationRulesContent.tsx, GuestTagsList.tsx, TagStatsCard.tsx, TagFilterPanel.tsx, RuleBuilderModal.tsx, CompositeTagModal.tsx, EditTagDefinitionModal.tsx, PreviewModal.tsx

TOUCHES (Hooks): useExperimentApi.ts (legacy alias), useResearchApi.ts, useTemplateVariables.ts (supports 4 schema types), useDesignApi.ts

TOUCHES (Backend — API): api/marketing.js (2000+ lines), api/marketing/trigger-templates.js, api/marketing/automation-rules.js, api/discounts.js (1200+ lines), api/templates.js (Schema API + Variable API + Validation), api/email-template-builder.js, api/email-designs.js, api/experiments.js (legacy alias), api/research.js, api/tags.js, services/messaging.js

TOUCHES (Backend — Schema SSOT): schemas/variable-schemas/*.json (4 JSON: service-email, promotion-email, lifecycle-email, transactional-email), services/templating/schema-loader.js, services/templating/variable-engine.js, services/templating/variable-validator.js, services/templating/legacy-compat.js, services/templating/context-builders/promotion-context.js, services/templating/context-builders/service-context.js, services/templating/context-builders/lifecycle-context.js, services/templating/context-builders/transactional-context.js, services/automation/execution-processor.js

目录

CUJ 总览与优先级矩阵

范围界定:本文档覆盖营销相关功能。 礼品卡/忠诚度 → CUJ-M · 客户管理/标签查看 → CUJ-E · 消息通道配置 → CUJ-J
CUJ优先级描述触发角色业务价值E2E 状态
I1 P0 折扣与优惠券管理 admin+ 促销 — 提升转化率 已覆盖
I2 P0 邮件模板管理 admin+ 沟通 — 品牌一致的邮件 部分覆盖
I3 P1 SMS 模板管理 admin+ 触达 — 高打开率通道 未覆盖
I4 P0 营销活动发送 admin+ 核心 — 多渠道触达客户 未覆盖
I5 P1 自动化触发与规则 admin+ 效率 — 事件驱动营销 已覆盖
I6 P1 客户自动标签 admin+ 精准 — 行为驱动分群 未覆盖
I7 P2 营销实验 A/B 测试 admin+ 数据 — 科学决策 已覆盖
I8 P2 营销策略管理 admin+ 规划 — 多渠道策略编排 已覆盖
I9 P2 用户研究平台 admin+ 洞察 — 客户反馈收集 已覆盖
I10 P1 营销分析 admin+ 度量 — 效果追踪 已覆盖

营销模块架构

营销功能全景

flowchart TD
    subgraph Content["内容层"]
        ET["邮件模板 (Code)"]
        ED["邮件设计 (Canvas)"]
        ST["SMS 模板"]
        VB["可视化编辑器"]
    end

    subgraph Schema["Schema SSOT 层"]
        SS["变量 Schema (4 types)"]
        SL["Schema Loader"]
        LC["Legacy Compat"]
        VV["变量验证器"]
        CB["Context Builders (4)"]
    end

    subgraph Targeting["定向层"]
        TAG["自动标签"]
        SEG["客户分群"]
        DISC["折扣/优惠券"]
    end

    subgraph Execution["执行层"]
        CAMP["营销活动"]
        CC["Campaign Composer"]
        AUTO["自动化规则"]
        TRIG["触发器模板"]
    end

    subgraph Intelligence["分析层"]
        EXP["A/B 实验"]
        STR["营销策略"]
        RES["用户研究"]
        ANA["营销分析"]
    end

    ET --> CAMP
    ED --> CC
    CC --> CAMP
    ST --> CAMP
    VB --> ET
    VB --> ED
    SS --> SL
    SL --> VV
    SL --> CB
    LC --> CB
    CB --> ET
    CB --> ED
    CB --> ST
    TAG --> SEG
    SEG --> CAMP
    DISC --> CAMP
    TRIG --> AUTO
    ET --> AUTO
    ST --> AUTO
    CAMP --> ANA
    EXP --> ANA
    STR --> CAMP

    style CAMP fill:#c62828,stroke:#b71c1c,color:#fff
    style AUTO fill:#e65100,stroke:#bf360c,color:#fff
    style TAG fill:#1565c0,stroke:#0d47a1,color:#fff
    style EXP fill:#6a1b9a,stroke:#4a148c,color:#fff
    style SS fill:#00695c,stroke:#004d40,color:#fff
    style CC fill:#ad1457,stroke:#880e4f,color:#fff

模板变量体系 — Schema SSOT 架构 (v3.0)

Schema SSOT: 所有变量定义以 JSON Schema 文件为单一真相源 (backend/schemas/variable-schemas/*.json)。 前端通过 GET /api/templates/schemas/:type 获取,后端通过 schema-loader.js 加载。 旧的平面变量名(如 customer_name)通过 legacy-compat.js 自动映射到嵌套格式。

4 种 Schema 类型

Schema Type用途模板类别映射Schema 文件
service_email服务通知(预约确认/提醒/跟进)category: notificationservice-email.json
promotion_email营销推广(优惠券/活动邀请)category: promotionalpromotion-email.json
lifecycle_email生命周期(生日祝福/流失召回)category: lifecyclelifecycle-email.json
transactional_email交易通知(支付收据/退款通知)category: transactionaltransactional-email.json

变量分类详情

变量分类前缀示例可用 Schema
Guest (基本)guest.*{{guest.name}}, {{guest.email}}, {{guest.phone}}全部 4 种
Guest (忠诚度)guest.*{{guest.loyalty_points}}, {{guest.loyalty_tier}}promotion, lifecycle
Guest (生命周期)guest.*{{guest.birthday}}, {{guest.years_as_customer}}, {{guest.days_since_visit}}lifecycle
Appointmentappointment.*{{appointment.date}}, {{appointment.time}}, {{appointment.status}}service_email
Services[]services.*{{#each services}}{{name}} - {{price}}{{/each}}service_email
Guests[]guests.*{{#each guests}}{{name}}{{/each}}service_email
Techniciantechnician.*{{technician.name}}, {{technician.phone}}service_email
Campaigncampaign.*{{campaign.discount_code}}, {{campaign.expiry_date}}promotion_email
Transactiontransaction.*{{transaction.amount}}, {{transaction.receipt_url}}transactional_email
Transaction Items[]transaction.items.*{{#each transaction.items}}{{name}} ${{price}}{{/each}}transactional_email
Storestore.*{{store.name}}, {{store.address}}, {{store.phone}}全部 4 种
Systemsystem.*{{system.booking_link}}, {{system.unsubscribe_link}}全部 4 种
变量验证 (Schema-Driven): 每种 Schema 类型严格限定可用变量。例如 promotion_email 不能使用 appointment.* 变量。 validateAgainstSchema() 在保存时校验,_validateVariableContext() 在发送前校验(由 VARIABLE_SCHEMA_VALIDATION feature flag 控制,仅 warn 不阻断)。
Legacy 兼容:旧模板使用平面变量名(如 {{customer_name}})仍然可用。 legacy-compat.js 在渲染时自动将 ~25 个平面键映射为嵌套格式。 结构化日志记录每次 legacy 变量使用:{ event: 'legacy_variable_used', template_id, flat_keys }

CUJ-I1: 折扣与优惠券管理

P0 促销 — 创建折扣规则和优惠券

折扣类型

类型说明示例
Percentage百分比折扣20% off
Fixed Amount固定金额减免$10 off
Buy X Get Y买赠活动Buy 2 Get 1 Free
Service Bundle套餐价Manicure + Pedicure $60

优惠券类型

类型使用限制
Single-use一次性使用,用完自动失效
Multi-use可指定总使用次数上限
Unlimited不限使用次数(按有效期控制)

BDD 场景

场景 I1.1: 创建百分比折扣 + 优惠券

Given 用户已登录并拥有对应功能所需权限与范围(scope),在 /admin/marketing/discounts
When 点击"新建折扣"
  And 设置: 名称 "Spring Sale", 类型 "百分比", 值 20%
  And 有效期 3/1-3/31, 最低消费 $50, 最大折扣 $30
  And 适用门店: All Stores
  And 生成优惠券码, 类型 Multi-use, 总限 100 次
  And 保存
Then 折扣规则 + 优惠券创建成功 (1:1 关系)
  And 出现在折扣列表
  And 结账时输入优惠券码可应用折扣

测试: full-flow/02f-discount-crud.spec.ts

场景 I1.2: 折扣应用校验

Given 存在 "Spring Sale" 折扣 (20% off, 最低 $50)
When 客户结账金额为 $40
Then 折扣不可应用 (未达最低消费)
When 客户结账金额为 $200
Then 折扣金额为 $30 (触及最大折扣上限,200×20%=40 > 30)

测试: full-flow/02f-discount-crud.spec.ts

场景 I1.3: 折扣叠加策略

Given 存在两个折扣: "Spring Sale" 20% 和 "Member Discount" 10%
  And 叠加策略为 "best"(取最大)
When 两个优惠券同时应用
Then 仅应用 "Spring Sale" 20%

测试: 未覆盖

CUJ-I2: 邮件模板管理

P0 沟通 — 创建品牌一致的邮件模板(Schema-Driven 变量系统 v3.0)

2026-03 更新:模板系统已升级为 Schema SSOT 架构。 变量选择器从硬编码定义改为由 Schema API (GET /api/templates/schemas/:type) 驱动, 支持 4 种模板类型(Service/Promotion/Lifecycle/Transactional),每种类型仅展示其 Schema 中定义的变量。

Promotion 页面 Tab 结构 (6 tabs)

Tab说明关键组件
Email Templates代码式邮件模板(HTML + 变量),用于自动化规则EmailBuilderEditor
SMS Templates短信模板,字符计数 + 段数显示Textarea + VariableAutocomplete
Email Designs可视化邮件设计(Canvas/Fabric.js),缩略图画廊CanvasEditor, TemplateLibrary
Campaigns营销活动列表,4 步 Composer 创建流程CampaignComposer
Triggers触发器模板管理TriggerTemplatesContent
Automation自动化规则管理AutomationRulesContent

用户流程 — 邮件模板 (Code)

flowchart TD
    A["Promotion → Email Templates tab"] --> B["模板列表"]
    B --> C{"操作?"}
    C -->|"新建"| D["选择模板类型 (4 种)"]
    D -->|"Service"| E1["编辑器: 仅 service_email 变量"]
    D -->|"Promotion"| E2["编辑器: 仅 promotion_email 变量"]
    D -->|"Lifecycle"| E3["编辑器: 仅 lifecycle_email 变量"]
    D -->|"Transactional"| E4["编辑器: 仅 transactional_email 变量"]
    E1 --> F["VariableDrawer: Schema-Driven 变量选择器"]
    E2 --> F
    E3 --> F
    E4 --> F
    F --> G["插入 Handlebars 变量"]
    G --> H["预览 (示例数据)"]
    H --> I["发送测试邮件"]
    I --> J["保存"]
    C -->|"编辑"| F
    C -->|"复制"| K["Duplicate 模板"]

    style F fill:#00695c,stroke:#004d40,color:#fff
    style D fill:#2196F3,stroke:#1565C0,color:#fff
    style H fill:#4CAF50,stroke:#388E3C,color:#fff

用户流程 — 邮件设计 (Canvas) + Campaign

flowchart TD
    A["Promotion → Email Designs tab"] --> B["设计画廊 (缩略图)"]
    B -->|"新建"| C["Canvas 编辑器 (Fabric.js)"]
    C --> D["拖放元素 + 文本 + 图片"]
    D --> E["Canvas 变量选择器"]
    E --> F["保存设计"]
    F --> G["Promotion → Campaigns tab"]
    G -->|"新建 Campaign"| H["Step 1: 选择设计模板"]
    H --> I["Step 2: 填写标题/Subject + HTML 内容"]
    I --> J["Step 3: 选择收件人 (All/Segment/Manual)"]
    J --> K["Step 4: 预览 + 发送/定时"]
    K -->|"立即发送"| L["发送进度页 (实时刷新)"]
    K -->|"定时发送"| M["Scheduled 状态"]
    L --> N["追踪: 打开率/点击率/退订率"]
    B -->|"编辑"| C

    style C fill:#ad1457,stroke:#880e4f,color:#fff
    style H fill:#e65100,stroke:#bf360c,color:#fff
    style L fill:#4CAF50,stroke:#388E3C,color:#fff

变量选择器 UX (Schema-Driven)

变量选择器有 3 种形态:
A. VariableDrawer — 侧边面板,显示按 Schema 分组的变量树 + 示例数据预览 + 点击插入 {{path}}
B. VariableCascader — 级联选择器,Category → Field 两级选择
C. Canvas Variable Picker — Canvas 编辑器内的下拉菜单,按分类展示可用变量
所有形态均从 useTemplateVariables(schemaType) hook 获取数据, hook 调用 GET /api/templates/schemas/:type,API 不可用时 fallback 到静态定义。

BDD 场景

场景 I2.1: 创建 Service 邮件模板 — 变量按 Schema 过滤

Given 用户已登录并拥有 marketing:manage 权限,在邮件模板列表
When 点击"新建" → 选择 "Service" 类型
  And 打开 VariableDrawer
Then 变量树仅显示 service_email Schema 中的分类: guest, appointment, services[], guests[], technician, store, system
  And 不显示 campaign (promotion 专属) 和 transaction (transactional 专属) 分类
When 插入 {{guest.name}}{{appointment.date}}
  And 点击"预览"
Then PreviewModal 用示例数据渲染变量

测试: template-variable-schema.spec.ts, template-variable-system.spec.ts

场景 I2.2: 创建 Lifecycle 邮件模板 — 生日/召回场景

Given 用户已登录并拥有 marketing:manage 权限
When 创建 "Lifecycle" 类型模板
  And 打开 VariableDrawer
Then 变量树显示 lifecycle_email Schema 的分类: guest (含 birthday, years_as_customer, days_since_visit, preferred_service, loyalty_tier), store, system
When 插入 {{guest.birthday}}{{guest.days_since_visit}}
  And 保存模板
Then 模板自动关联 lifecycle_email Schema

测试: template-variable-schema.spec.ts

场景 I2.3: 创建 Transactional 邮件模板 — 支付收据

Given 用户已登录并拥有 marketing:manage 权限
When 创建 "Transactional" 类型模板
  And 打开 VariableDrawer
Then 变量树显示 transactional_email Schema 的分类: guest, transaction (含 items[]), store, system
When 使用 {{#each transaction.items}}...{{/each}} 循环
  And 预览模板
Then items 列表渲染为示例交易明细

测试: template-variable-schema.spec.ts

场景 I2.4: 变量类型隔离校验 (Schema-Driven)

Given 创建 "Promotion" 类型模板 (关联 promotion_email Schema)
When 手动输入 {{appointment.date}}service_email 变量)
Then validateAgainstSchema() 检测到 unknown 变量
  And 保存时 API 返回警告: "Variable 'appointment.date' is not defined in promotion_email schema"

测试: template-variable-schema.spec.ts

场景 I2.5: 发送测试邮件 (Context Builder)

Given 邮件模板编辑器中有内容,模板类型为 "Service"
When 点击"发送测试" → 输入收件人地址
Then 后端通过 variableEngine.buildContextByType('service', ...) 构建变量上下文
  And 使用 service-context.js Context Builder 生成嵌套数据
  And 测试邮件发送成功,变量使用示例数据填充

测试: 部分覆盖 (API test only)

场景 I2.6: Legacy 变量兼容

Given 存在旧模板使用 {{customer_name}} 等平面变量名
When 触发自动化发送该模板
Then legacy-compat.js 自动将 customer_name 映射为 guest.name
  And 模板正常渲染
  And 结构化日志记录 legacy 变量使用

测试: legacy-compat.test.js

CUJ-I3: SMS 模板管理

P1 触达 — 高打开率的短信通道

BDD 场景

场景 I3.1: 创建 SMS 模板

Given 用户已登录并拥有对应功能所需权限与范围(scope),在 Promotion → SMS Templates
When 创建新模板 "Appointment Reminder"
  And 输入内容: "Hi {{guest.first_name}}, your appointment is tomorrow at {{appointment.time}}."
Then 实时显示字符数和 SMS 段数
  And 保存成功

测试: 未覆盖

场景 I3.2: SMS 字符限制

Given 编辑 SMS 模板
When 内容超过 160 字符
Then 显示 "2 segments"(短信将分成 2 条发送)
  And 显示费用提醒

测试: 未覆盖

CUJ-I4: 营销活动发送

P0 核心 — 4 步 Campaign Composer 创建并发送邮件活动

活动创建流程 — CampaignComposer (4 Steps)

flowchart TD
    A["Promotion → Campaigns tab"] --> B["活动列表"]
    B -->|"新建"| S1

    subgraph Composer["Campaign Composer (4-Step Wizard)"]
        S1["Step 1: 选择 Email Design 模板"]
        S1 --> S2["Step 2: Campaign 名称 + Subject + HTML 内容"]
        S2 --> S3["Step 3: 选择收件人"]
        S3 --> S4["Step 4: 预览 + 发送/定时"]
    end

    S3 -->|"All Guests"| S4
    S3 -->|"Segment"| S4
    S3 -->|"Manual (paste emails)"| S4

    S4 -->|"立即发送"| P["发送进度页 (每5秒刷新)"]
    S4 -->|"定时发送"| SC["Scheduled (可选 weekly/monthly 循环)"]
    P --> T["追踪: 打开率, 点击率, 退订率, 投诉率"]

    style S1 fill:#e65100,stroke:#bf360c,color:#fff
    style S4 fill:#c62828,stroke:#b71c1c,color:#fff
    style P fill:#4CAF50,stroke:#388E3C,color:#fff
    style T fill:#1565c0,stroke:#0d47a1,color:#fff

Campaign 生命周期

状态说明用户可执行操作
draft草稿,尚未发送编辑、删除、发送
scheduled已设定发送时间编辑、取消
active / sending正在发送中查看进度、取消
completed发送完成查看追踪数据、克隆
cancelled已取消克隆
failed发送失败查看错误、重试

Campaign 进度与追踪页

进度页 UX:发送中状态每 5 秒自动轮询更新。显示内容:进度条 (% sent)、发送数/失败数、收件人日志表(email, status, open count, click count, 分页)。
追踪指标:Open Rate%, Click Rate%, Bounce Rate%, Complaint Rate%

BDD 场景

场景 I4.1: 4 步创建并发送邮件活动

Given 用户已登录并拥有 marketing:manage 权限,在 Promotion → Campaigns tab
  And 已有保存的 Email Design 模板
When 点击"新建活动",进入 CampaignComposer
  And Step 1: 从画廊选择一个 Email Design
  And Step 2: 填写活动名称 "Spring Promotion"、Subject "Special offer for you!"
  And Step 3: 选择收件人来源 "Segment",选择 "VIP Customers" 分群
  And Step 4: 预览邮件 → 点击"立即发送"
Then 跳转到 Campaign 进度页
  And 显示发送进度条 (每 5 秒刷新)
  And 发送完成后显示追踪指标 (Open/Click/Bounce/Complaint Rate)

测试: 未覆盖

场景 I4.2: 定时 + 循环发送

Given 用户已登录并拥有 marketing:manage 权限,在 Step 4 预览页
When 设置 Scheduled At: 明天上午 10:00
  And 设置 Recurrence: monthly
Then 活动状态为 "Scheduled"
  And 每月自动重复发送
  And 可在列表中编辑或取消

测试: 未覆盖

场景 I4.3: 手动收件人发送

Given CampaignComposer Step 3
When 选择收件人来源 "Manual"
  And 粘贴邮件地址列表
Then 显示有效邮件数量确认
  And 发送仅给指定的邮件地址

测试: 未覆盖

CUJ-I5: 自动化触发与规则

P1 效率 — 事件驱动的自动化营销

触发器架构

flowchart LR
    subgraph Events["触发事件"]
        E1["appointment_booked"]
        E2["appointment_reminder"]
        E3["appointment_no_show"]
        E4["birthday"]
        E5["loyalty_milestone"]
    end

    subgraph Trigger["触发器模板"]
        T1["时机: 事件后 X 时间"]
        T2["执行时间: 9:00 AM"]
    end

    subgraph Action["自动化规则"]
        A1["选择邮件/SMS 模板"]
        A2["选择目标受众"]
    end

    Events --> Trigger
    Trigger --> Action
    Action --> SEND["自动发送"]

    style SEND fill:#4CAF50,stroke:#388E3C,color:#fff

BDD 场景

场景 I5.1: 创建自动提醒规则

Given 用户已登录并拥有对应功能所需权限与范围(scope),在 Promotion → Triggers tab
When 创建触发器模板: 事件 "appointment_reminder", 时机 "1 day before", 时间 "9:00 AM"
  And 创建自动化规则: 关联该触发器 + 邮件模板 "Appointment Reminder"
  And 激活规则
Then 每天 9:00 AM 自动给明天有预约的客户发送提醒邮件

测试: marketing/rule-management.spec.ts

场景 I5.2: 查看自动化执行日志

Given 自动化规则已运行数天
When 查看规则的执行日志
Then 显示: 执行时间、发送数量、成功/失败统计

测试: marketing/rule-management.spec.ts

CUJ-I6: 客户自动标签

P1 精准 — 基于行为的自动客户分群

标签类别

类别 (category)说明示例规则
engagement参与度最近 30 天预约 >= 3 次
birthday生日相关本月生日的客户
demographics人口统计注册超过 1 年
purchase_history消费历史累计消费 > $500
membership会员状态会员等级 = Gold
custom自定义任意组合条件

BDD 场景

场景 I6.1: 创建自动标签规则

Given 用户已登录并拥有对应功能所需权限与范围(scope),在 /admin/marketing/guest-tagging → Definitions tab
When 打开 RuleBuilderModal
  And 设置条件: "最近 30 天预约次数 >= 3"
  And 标签名称: "Active Customer", 类别: "engagement"
  And 保存并激活
Then 标签定义出现在列表中
  And 系统自动评估所有客户
  And 符合条件的客户获得 "Active Customer" 标签

测试: 未覆盖

场景 I6.2: 创建组合标签

Given 已有 "Active Customer" 和 "High Spender" 两个标签
When 打开 CompositeTagModal
  And 创建组合标签 "VIP Candidate" = "Active Customer" AND "High Spender"
Then 同时满足两个条件的客户被标记为 "VIP Candidate"

测试: 未覆盖

场景 I6.3: 按标签查询客户

Given 用户已登录并拥有对应功能所需权限与范围(scope),在 Guests tab
When 在 TagFilterPanel 选择标签 "VIP" OR "Active Customer"
Then 显示所有拥有任一标签的客户列表
  And 显示客户数量和标签分布统计

测试: 未覆盖

CUJ-I7: 营销实验 A/B 测试

P2 数据 — 科学决策的实验框架

实验生命周期

flowchart LR
    D["Draft 草稿"] -->|"start"| R["Running 运行中"]
    R -->|"pause"| P["Paused 暂停"]
    P -->|"start"| R
    R -->|"complete"| C["Completed 完成"]
    D -->|"cancel"| X["Cancelled 取消"]
    R -->|"cancel"| X

    style D fill:#455a64,stroke:#37474f,color:#fff
    style R fill:#2e7d32,stroke:#1b5e20,color:#fff
    style C fill:#1565c0,stroke:#0d47a1,color:#fff

实验场景类型

场景 (scenario)说明
inbound_booking客户预约转化
inbound_inquiry客户咨询转化
outbound_reminder预约提醒效果
outbound_recall客户召回效果
outbound_promotion促销活动效果

BDD 场景

场景 I7.1: 创建并启动实验

Given 用户已登录并拥有对应功能所需权限与范围(scope),在 /admin/marketing/research
When 创建实验 "SMS vs Email Recall"
  And 设置场景: outbound_recall
  And 创建 3 组: Control (30%), SMS (35%), Email (35%)
  And 设置目标指标: 预约转化率
  And 保存为草稿 → 启动实验
Then 实验状态变为 "Running"
  And 客户按比例自动分配到各组

测试: marketing/research.spec.ts(含 experiments 重定向兼容用例)

场景 I7.2: 分析实验结果

Given 实验已运行 2 周
When 查看 /admin/marketing/research/[id]/analytics
Then 显示各组转化率对比
  And 显示统计显著性 (置信度)
  And 推荐最佳方案

测试: marketing/research.spec.ts

场景 I7.3: 复制实验

Given 已完成的实验 "SMS vs Email Recall"
When 点击"复制"
Then 创建新实验副本 (Draft 状态)
  And 保留原实验的配置(组、指标),清空参与者数据

测试: marketing/research.spec.ts

CUJ-I8: 营销策略管理

P2 规划 — 多渠道营销策略编排

策略类型

类型说明典型 KPI
Acquisition获客策略新客户数、首单转化率
Retention留存策略复购率、客户生命周期价值
Reactivation召回策略沉睡客户回归率
Upsell增购策略客单价提升、附加服务率
Referral推荐策略推荐转化率、口碑传播系数

BDD 场景

场景 I8.1: 创建留存策略

Given 用户已登录并拥有对应功能所需权限与范围(scope),在 /admin/marketing/strategies
When 创建策略 "Monthly Retention"
  And 类型: Retention, KPI: 复购率 > 60%
  And 关联活动: 月度会员优惠邮件 + 生日祝福 SMS
  And 保存
Then 策略出现在列表
  And 可追踪 KPI 达成情况

测试: marketing/strategies.spec.ts

CUJ-I9: 用户研究平台

P2 洞察 — 收集客户反馈和行为数据

研究类型

类型说明
Survey问卷调查
Interview深度访谈
Focus Group焦点小组讨论
Usability Test可用性测试

研究生命周期

flowchart LR
    D["Draft"] --> R["Recruiting 招募中"]
    R --> A["Active 进行中"]
    A --> C["Completed 完成"]
    D --> X["Cancelled"]
    R --> X

    style A fill:#2e7d32,stroke:#1b5e20,color:#fff

BDD 场景

场景 I9.1: 创建调查研究

Given 用户已登录并拥有对应功能所需权限与范围(scope),在 /admin/marketing/research
When 创建研究 "Service Satisfaction Q1 2026"
  And 类型: Survey
  And 配置问卷内容
  And 保存并进入招募状态
Then 研究出现在列表

测试: marketing/research.spec.ts

场景 I9.2: 邀请参与者并追踪

Given 研究处于 Recruiting 状态
When 在 Outreach 页发送邀请邮件给 VIP 标签客户
Then 邀请发送成功
  And Participants 页显示邀请状态
  And Analytics 页显示响应率和完成率

测试: marketing/research.spec.ts

CUJ-I10: 营销分析

P1 度量 — 营销效果追踪与优化

BDD 场景

场景 I10.1: 查看活动效果

Given 用户已登录并拥有对应功能所需权限与范围(scope),在 /admin/marketing/analytics
When 选择时间范围和活动
Then 显示: 发送量、打开率、点击率、退订率
  And 显示渠道对比 (Email vs SMS)
  And 显示受众分群表现对比

测试: marketing/analytics.spec.ts

跨模块依赖

本模块 CUJ依赖模块关系描述
I1 折扣 CUJ-F (Payments) 折扣在结账流程中应用,影响支付金额
I1 折扣 CUJ-M (Loyalty) 会员折扣与促销折扣叠加策略 (best/stack/member_first)
I2 邮件模板 Schema SSOT (049) 变量选择器由 GET /api/templates/schemas/:type 驱动,4 种 Schema 类型定义可用变量
I4 活动发送 CUJ-J (Settings) messaging-config 决定邮件/SMS 供应商 (SES/Resend, Twilio/Telnyx)
I5 自动化 CUJ-B (Appointments) 预约事件 (booked/reminder/no_show) 触发自动化消息;发送前执行 pre-send validation
I6 标签 CUJ-E (Guests) 标签结果在客户详情页展示,影响客户分群
I7 实验 CUJ-H (Reports) 实验分析结果可纳入营销报表

业务规则

  1. 变量 Schema 隔离 (4 类型):每种 Schema 类型严格限定可用变量。service_email 含 appointment/services/technician,promotion_email 含 campaign,lifecycle_email 含 guest 生命周期字段,transactional_email 含 transaction (items[])。跨类型变量使用在保存时被 validateAgainstSchema() 校验。
  2. Pre-Send Validation (Feature Flag):自动化发送前 _validateVariableContext() 检查缺失/未知变量,仅记录结构化警告 (warn-only),不阻断发送。由 VARIABLE_SCHEMA_VALIDATION feature flag 控制。
  3. Legacy 变量兼容:旧模板的平面变量名 (如 customer_name) 通过 legacy-compat.js 自动映射到嵌套格式 (如 guest.name)。每次 legacy 映射会记录结构化日志。
  4. 优惠券 1:1:每个 discount_rule 对应恰好一个 coupon 记录,统一 CRUD。
  5. 折扣叠加策略:三种模式 — "best"(取最高)、"stack"(叠加)、"member_first"(会员优先再叠促销)。
  6. 标签评估幂等:重复评估同一标签定义不会创建重复标签记录。
  7. 触发器系统/租户分离:trigger_templates 存储在 public schema(系统级 + 租户自定义),automation_rules 存储在租户 schema。
  8. 实验参与者不可交叉:同一客户在同一实验中只能属于一个组。
  9. 消息发送限流:邮件和 SMS 发送受熔断器控制,主供应商断路时自动切换备用。
  10. 模板继承:系统模板 (is_system: true) 只读,租户可复制为自定义模板后编辑。
  11. Campaign 4 步 Composer:必须先有保存的 Email Design 才能创建 Campaign。Step 1 选设计 → Step 2 填元数据 → Step 3 选收件人 → Step 4 预览+发送/定时。