语默未来 · 第 2 版拼团营销
P0–P4 验收视频

每个板块一段:前半段是后台操作,后半段是手机视口(390×844)的小程序端。含主流程与关键分支。

集成分支 feat/201-v2-group-buy PR #211 录制:Playwright + ffmpeg
P0

拼团主链路 #203

后台配置拼团活动并上架;小程序开团、参团、支付、团长免单、成团名次;后台整团发货;含满员/解散等分支。

1:50
录制细节 / 分支说明

P0 拼团主链路 · 证明视频

  • 交付:`/home/yams/proof-artifacts/v3/site/videos/P0.mp4`(**109.8s**,1280×720 H.264 / 25fps / yuv420p);后台 1440×900,小程序 390×844 移动仿真(isMobile/hasTouch/DPR 2),手机段为居中竖屏画幅(抽帧 `15-video-frame-mobile.png`)。录制脚本 `p0/record.mjs`,截图 19 张在 `p0/shots/`;只用 `mock:p0rec`(团长)与 `mock:p0member2`(团员),未用 demo 用户。
  • 后台建活动:拼团活动列表 → 新建 `P0演示-1923`(商品 `演示·拼团毛绒`、系列 `萌宠乐园`、2 人成团、`7 天内发货`、起止 2026-10-31 00:00 → 2026-11-07 23:59)→ 保存为草稿 → 按名称筛选 → 上架并确认,列表变「进行中」;C 端活动接口回读配置一致。截图 `01-activity-form.png`、`01b-activity-form-dates.png`、`02a-activity-draft.png`、`02-activity-active.png`。
  • 小程序开团 + 参团支付:活动页「立即开团」→ 选款 `垂耳兔`(显示「已选」)→ 确认开团 → 团详情「待成团 / 已加入 1/2」;`mock:p0member2` 经 API 参团 + 模拟支付(¥4.95)后回读为「已加入 2/2 / 已付款 1 人」。截图 `03-activity-page.png`、`04-open-sheet.png`、`05-group-forming.png`、`06-group-full.png`。
  • 团长奖励与成功:选择奖励 → `免单` → 确认选择 → 状态「拼团成功」、`系列第 6 名`、2/2 已付款,团订单实付 ¥4.95。截图 `07-reward-sheet.png`、`08-success.png`、`08b-success-order.png`。
  • 负向分支:① 同一成员再次 `POST /groups/:id/join` 返回 **409 `GROUP_ALREADY_JOINED`(你已参加过该团)**,团状态不变(`run.log` 可见;已有成员在 UI 上无「参团」按钮,故为 API 级验证,画面保留满员 2/2 证据 `06-group-full.png`);② API 再开一小团,小程序团详情点「解散拼团」→ 确认解散 → 显示「已关闭 / 团长解散 / 团长已解散该团,退款处理中」,DB 回查 `closed/dissolved`(`09-dissolved.png`)。
  • 后台履约 + 回读:拼团管理按团号 `G20261031474053` 命中 → 团详情(2/2,已付 2)→ 整团发货(顺丰速运 + `SF-P0-DEMO`)→「已发货」;小程序回读「已发货 / 整团物流 / 顺丰速运 / SF-P0-DEMO」。截图 `10-admin-groups.png`、`11-admin-group-detail.png`、`12-admin-ship-modal.png`、`13-admin-shipped.png`、`14-mini-shipped.png`、`14b-mini-tracking.png`。限制:成片由 4 段 page 录像拼接以保持节奏(前两段单独编码,末两段用 `finalize()` 输出后 concat);共享开发库保留前几次彩排的 `P0演示-1914/1916/1919`,本轮为 `P0演示-1923`,团列表按团号筛选故不混淆。
P1

券与营销 #205

券模板与「券中心公开领取」规则;小程序领取、重复领取限领、结算用券、券包已使用;后台发券记录。

1:45
录制细节 / 分支说明

P1 券与营销 — 录屏说明

  • 交付:`/home/yams/proof-artifacts/v3/site/videos/P1.mp4`(104.8s,1280×720 H.264);后台 1440×900,小程序 390×844 移动仿真(拼接后为居中竖屏手机画幅)。截图 16 张见 `/home/yams/proof-artifacts/v3/p1/shots/`(01 模板列表 … 16 发券记录)。
  • 后台建券:券模板 `P1演示-满100减20-1916`,权益类型满减(默认)、门槛 ¥100、减额 ¥20、到账后有效天数 30、全场;随后新建发放规则绑定该模板(场景人工发放默认、个人限领 1、发放额度 100、开启「在券中心公开可领」)。
  • 小程序领取:券中心「领取」成功(剩余 100→99);第二次领取被规则级个人限领拦下,按钮显示「已达个人限领次数」——分支 A(个人限领)。
  • 用券下单:首页 → 周边「街头萌物·迷你双肩包」¥129 → 立即购买 → 结算选该 20 元券,优惠 -¥20.00、实付 ¥109.00;提交订单后走开发「模拟支付成功」,订单变待发货,券包「已使用」tab 出现该券——分支 B(券被订单消耗)。
  • 后台核对:发券记录中该实例来源「券中心」、状态「已使用」、用户「P1演示用户」、使用订单 `cmvwb52jh02invfem5g12v9zg`(订单号 `S1793445492488698583`,另经后台订单接口核对 status=paid、discount=2000、payAmount=10900)。
  • 限制:可选分支「拼团订单无券入口」未纳入本片;共享开发库中其它并发会话的券模板/发放记录会同时出现在券中心与后台列表(截图中可见 PROBE/演示 等行),不影响本流程断言。
P2

榜单与触达 #206

后台公告;小程序弹窗、已读不再弹、重新通知再次弹;系列榜单与我的名次;站内消息;福利到账弹窗。

1:43
录制细节 / 分支说明

P2 榜单与触达 · 证明视频

  • 成片:`/home/yams/proof-artifacts/v3/site/videos/P2.mp4`
  • 截图:`/home/yams/proof-artifacts/v3/p2/shots/`(13 张)
  • 录制脚本:`/home/yams/proof-artifacts/v3/p2/record.mjs`(夹具 `fixture.mjs`,全部在仓库外)
  • 环境:Admin `http://100.125.34.72:3002`、H5 `http://100.125.34.72:10086`、API `127.0.0.1:3001`
  • 专用用户:`mock:p2rec`(`cmvwatbzx00covfemxkelkdpx`,昵称 `P2录制用户`),未使用 demo 用户
  • 录制参数:后台 1440×900;小程序 390×844 + 移动仿真(isMobile/hasTouch/DPR 2)
  • 成片规格:1280×720 / H.264 / 25fps / yuv420p,**102.8s**,1.06 MB(`ffprobe` 实测)
  • 画幅处理:后台画面缩放到 1280×800 上下补黑边;手机画面缩放到 332×720 居中、左右黑边,手机竖屏画幅清晰可辨

前置(不录屏,脚本自动完成)

1. 后台 API 登录,`GET /api/admin/notices` 后把现有 `active` 公告全部 `POST /:id/status {status:'paused'}`;本轮开始时已无 active 公告需新暂停(`演示·福利公告` 在前一次尝试中已置 paused);预清理后 `active` 公告数为 0。

2. 清理上一轮 P2 演示公告/人工券;把专用用户遗留的 `welfare/pending` 全部 `POST /welfare/seen` 标记已读。

3. 幂等夹具:临时把专用用户加入「萌宠乐园」已有成功团(rankNo=2)让榜单出现「我的名次」;临时写一条 `groupSucceeded` 消息供消息中心展示。录制结束后两条夹具均已删除(复查 `groupMember=0`、夹具消息=0)。

4. 校验:预清理后 `GET /notices/pending -> null`、`GET /welfare/pending -> []`,新公告是唯一弹窗。

分步流程(片内时间轴)

| 时间 | 步骤 | 可见结果 / 断言 |

|---|---|---|

| 0:00–0:20 | 后台「普通公告」→ 新建公告 | 标题 `P2演示-福利公告-1921`、正文、按钮 `知道了`、跳转 `不跳转`、人群 `所有用户`、频率 `每次打开一次`、优先级 60、`立即启用` 打开;保存后列表显示「生效中」,API 回查字段一致 |

| 0:20–0:30 | 小程序首页 | 弹出同一标题公告 + 正文 + `知道了`;点击 `知道了` 关闭,服务端已读(`/notices/pending -> null`) |

| 0:30–0:40 | 小程序重载首页(分支) | 公告**不再出现**;服务端已读跨设备生效,不是仅前端隐藏 |

| 0:40–0:52 | 系列榜单 → 萌宠乐园 | 列表显示「萌宠乐园 / 已产生 N 个名次 / 榜首:王小明」;进入详情显示前 100 名与「我的名次 第 2 名」「已上榜」 |

| 0:52–1:02 | 消息中心 | 显示「消息中心 / 1 条未读」与真实消息「拼团成功」+「名次第 2 名」正文 |

| 1:02–1:09 | 后台「重新通知」 | 表格行操作 → 确认,toast「已重新通知(第 1 次),已读状态按频率重算」;API 回查 `renotifyVersion=1` |

| 1:09–1:18 | 小程序重载首页(分支) | 同一条公告**再次弹出**(版本失效重算),截图后点 `知道了` 关闭 |

| 1:18–1:31 | 后台「发券记录」→ 人工发券 | 选择规则 `演示·满100减20`,输入用户 ID → 查找并核对显示「P2录制用户」→ 确定;toast「发券成功」,记录列表出现该用户与券模板 |

| 1:31–1:42 | 小程序重载首页(分支) | 福利到账弹窗「福利已到账」显示 `演示·满100减20`、`满 ¥100.00 减 ¥20.00`、`包邮`、有效期;点 `稍后看` 关闭,服务端福利待办清空 |

分支证据

  • **已读持久化**:关闭公告后 `GET /notices/pending` 返回 `null`;重载首页无弹窗(截图 `04-mini-no-repopup.png`)。
  • **重新通知/版本**:后台 `renotifyVersion` 0→1;重载首页同一公告再次弹出(截图 `09-mini-notice-renotified.png`)。
  • **福利优先且不重复**:人工发券后首页先弹福利(公告已读不抢焦点);关闭后 `GET /welfare/pending` 为空,券仍在券包(截图 `12/13-mini-welfare*.png`)。
  • 全程可见文本断言,任一不匹配脚本直接抛错,不存在静默跳过。

截图清单

`01-admin-notice-form.png`、`02-admin-notice-created.png`、`03-mini-notice-popup.png`、`04-mini-no-repopup.png`、`05-mini-ranking-list.png`、`06-mini-ranking-detail.png`、`07-mini-messages.png`、`08-admin-renotify.png`、`09-mini-notice-renotified.png`、`10-admin-manual-grant.png`、`11-admin-grant-record.png`、`12-mini-welfare.png`、`13-mini-welfare-closed.png`

收尾与遗留

  • 本轮公告已暂停(`status=paused`,`renotifyVersion=1`,`readCount=1`),避免影响其它板块录制;行保留可复查。
  • 临时榜单成员、消息夹具已删除;专用用户保留一张未使用券 `演示·满100减20`(福利流程的真实结果,作为证据保留)。
  • 录制期间其它板块也在写同一 dev 库(榜单出现额外名次、发券记录有其他用户),不影响本轮断言;脚本按模板名精确选择 `演示·满100减20`,并校验福利批次券名。

复现

```bash

cd /home/yams/proof-artifacts/v3/p2

PLAYWRIGHT_BROWSERS_PATH=/home/yams/.local/share/playwright-browsers node record.mjs

```

P3

售后与风控 #207

售后受理、审核退款、完成;驳回分支;风控记录与人工解除;小程序售后列表/详情状态。

2:16
录制细节 / 分支说明

P3 售后与风控 · 证明视频

  • 成片:`/home/yams/proof-artifacts/v3/site/videos/P3.mp4`(**136.2s** / 1280×720 / H.264 / 25fps,`ffprobe` 实测)
  • 截图:`/home/yams/proof-artifacts/v3/p3/shots/`(18 张);抽帧校验:`/home/yams/proof-artifacts/v3/p3/frames/`
  • 录制脚本:`/home/yams/proof-artifacts/v3/p3/record.mjs`;夹具脚本:`/home/yams/proof-artifacts/v3/p3/fixture.mjs`(全部在仓库外,未改仓库、未装依赖、未重启 dev)
  • 环境:Admin `http://100.125.34.72:3002`、H5 `http://100.125.34.72:10086`、API `127.0.0.1:3001`
  • 专用用户:`mock:p3rec` → `mock-p3rec`(id `cmvwau6av00cvvfem57m996wc`,昵称 `P3REC 演示用户`);`setupMiniUser` + `injectUser`,**未使用 demo 用户**
  • 录制参数:后台 1440×900;小程序 390×844 + 移动仿真(`isMobile` / `hasTouch` / DPR 2)
  • 画幅:后台段缩放后左右补黑边;手机段为 332×720 竖屏手机画框、左右黑边,移动画幅清晰可辨

夹具(录前由脚本创建,`P3REC-` 前缀,全部唯一)

| 用途 | 订单 | 商品行 | 实付 | 售后单 | 状态 |

|---|---|---|---|---|---|

| 审核通过 → 退款 → 完成 | `P3REC-20261031112735-A`(shipped,1 天前发货,收货人 林小满 / 深圳南山) | 亚麻托特包 ¥198 + 陶瓷马克杯 ¥89 | ¥287.00 | `AS20261031495408` | refundOnly / quality / 凭证 `/static/images/bag.jpg` |

| 驳回(不退款) | `P3REC-20261031112735-B`(shipped) | 香薰蜡烛 ¥128 | ¥128.00 | `AS20261031863428` | refundOnly / quality / 同一凭证 |

  • 售后由 C 端 API `POST /api/after-sales` 以 P3 用户身份提交(整单,`reason=quality`,`evidenceUrls=['/static/images/bag.jpg']`)。
  • 风控:Prisma 直建 `RiskRecord(subjectType=user, status=active, count/threshold=3/3, windowDays=30, suspendedActions=['group.create','group.join'])`,命中原因 `P3REC-… 售后风控命中:质量问题 3 件(阈值 3 件 / 30 天)`。
  • 重跑前会清理该专用用户上一轮 `P3REC-` 前缀的售后/订单/商品/风控夹具,队列始终只有本轮两张单。

分步流程(片内时间轴)

| 时间 | 步骤 | 可见结果 / 断言 |

|---|---|---|

| 0:00–0:15 | 后台登录 → 售后管理队列 | 按 `P3REC` 关键字过滤出 2 条待受理单;用户 `P3REC 演示用户`、类型 `仅退款` |

| 0:15–0:30 | 打开第一张 → **受理** → 打开「审核通过」 | 详情显示 `待受理`、`仅退款`、现金退款上限 `¥287.00`、商品行快照;受理后状态 `审核中`;审核弹窗显示处理方式 `仅退款`、退款金额 `¥287.00`、原因必填 |

| 0:30–0:45 | 填原因 → **确认通过** → **完成** | 状态 `处理中`、退款 `已退款` ¥287.00;完成弹窗「处理方式:仅退款,退款 ¥287.00」→ 状态 `已完成`,订单退款维度 `已退款`、已退 ¥287.00 |

| 0:45–1:08 | 回队列 → 打开第二张 → **驳回** → 填原因 → 确认驳回 | 队列里第一张显示 `已完成`;第二张 `待受理` → 驳回后状态 `已驳回`,原因「凭证无法证明是商品质量问题,且已超出售后期协商范围」回显,退款 `未退款`(分支:驳回不退款) |

| 1:08–1:16 | 风控管理:列表/汇总 → 筛选 | 汇总 `限制中 1 / 已解除 0`;行显示命中原因、`3 / 3 件(30 天)`、限制 `新开团、新参团`、状态 `限制中` |

| 1:16–1:35 | **解除风险** → 确认解除 | 填「人工复核:质量问题已协商解决,误伤,恢复新开团/新参团」;解除后状态 `已解除`、汇总 `限制中 0 / 已解除 1`,解除人/时间/原因回显 |

| 1:35–2:16 | 小程序:我的 → 我的售后 → 已完成详情 → 已驳回详情 | 「我的」页显示 `P3REC 演示用户` 与 `我的售后` 入口;列表两张单 `已完成 / ¥287.00`、`已驳回`;已完成详情 `已完成` + `退款金额 ¥287.00` + `已退款` + `退款单号` + 问题凭证;已驳回详情 `已驳回` + `驳回原因:凭证无法证明是商品质量问题…` + `未退款` + `¥0.00` |

分支证据

  • **审核通过(退款)**:后台状态 `处理中` → 退款维度 `已退款`、金额 ¥287.00;完成后 `已完成`(截图 04/05/06/07)。
  • **驳回(不退款)**:状态 `已驳回`、原因回显、退款 `未退款`;小程序侧同样显示 `已驳回` + 原因(截图 10/11/23)。
  • **风控解除**:`active → released`,列表状态 `已解除`,汇总 `限制中 0 / 已解除 1`,解除信息完整(截图 12/13/14)。
  • **双端一致**:同一批售后单在小程序列表/详情读到与后台一致的状态、退款金额、驳回原因。
  • 每步都做可见文本断言(`body.innerText` 包含目标文案),任一不匹配脚本抛错;**没有静默跳过**(公告弹窗等遮挡也会显式关闭/报错)。

截图清单

`01-after-sale-queue.png`、`02-after-sale-submitted.png`、`03-accepted.png`、`04-approve-modal.png`、`05-processing-refunded.png`、`06-complete-modal.png`、`07-completed.png`、`08-queue-after-complete.png`、`09-second-submitted.png`、`10-reject-modal.png`、`11-rejected.png`、`12-risk-list.png`、`13-risk-release-modal.png`、`14-risk-released.png`、`20-mini-mine.png`、`21-mini-after-sale-list.png`、`22-mini-completed.png`、`23-mini-rejected.png`

复现

```bash

1) 夹具(根 .env 提供 DATABASE_URL;脚本从 packages/db 解析 @shelf/db)

cd /home/yams/shelf-miniapp-integration/packages/db

set -a; source ../../.env; set +a

pnpm exec tsx /home/yams/proof-artifacts/v3/p3/fixture.mjs

2) 录制 + 断言 + 拼接

cd /home/yams/proof-artifacts/v3/p3

PLAYWRIGHT_BROWSERS_PATH=/home/yams/.local/share/playwright-browsers node record.mjs

```

已知问题(本轮发现,未改仓库)

  • **整单仅退款且订单含运费时,后台「审核通过」会 500**:`allocateItemRefunds` 按「含运费的退款额」比例回填各 `AfterSaleItem.refundAmount`,可能大于该行 `allocatedAmount`(分摊实付不含运费),触发 DB CHECK `after_sale_item_amount_valid`,接口返回 `INTERNAL_ERROR`。复现:订单 freight > 0、整单 refundOnly。本轮夹具把运费设为 0(¥287 商品全额)绕开,未修改仓库代码。
  • 小程序「我的」页偶发运营公告弹窗遮挡点击;本轮录制时公告已全部 `paused`,脚本仍保留「逐个关闭可见遮罩,关不掉即报错」的兜底,不静默跳过。
P4

数据概览 #208

今日日更快照与指标;重算;商品标准成本录入后不再「待补」;异常清单与恢复。

1:14
录制细节 / 分支说明

P4 · 数据概览 / 成本录入 / 异常清单(后台)

  • **产物**:`/home/yams/proof-artifacts/v3/site/videos/P4.mp4`(1280x720,H.264,**74.04s**,1.0MB)
  • **录制**:Playwright Chromium,admin **1440x900** 录制(`finalizeSingle` 转 1280x720 加黑边);仅后台,无 C 端页面
  • **环境**:http://100.125.34.72:3002(admin/admin123456),API 3001,dev 库 `shelf`
  • **截图**:`/home/yams/proof-artifacts/v3/p4/shots/01..10`(含 `09b` 处理记录特写);脚本 `p4/record.mjs`
  • **断言**:每一步都等可见文本/Toast 并校验,不匹配直接抛错;本次 `EXIT:0`,无静默跳过

流程与实测结果(2026-10-31)

| 步骤 | 实测 |

|---|---|

| 数据概览默认昨天 | 统计日期 `2026-10-30`,付费成交订单 0、实收 ¥0.00(全零) |

| 改范围为今天 → 查询 | `2026-10-31`:新增付费用户 5、付费成交订单 199、实收-商品款 ¥2,944.85、开团数 8、券到账 5 |

| 成本录入前 | 区间汇总「商品标准成本 = 待补」(详情表同) |

| 点「重算」 | 最后更新 `2026-10-31 18:20 → 19:20`,Toast「已重算 1 天」 |

| 商品标准成本 | `演示·拼团毛绒`(DEMO-GROUP-PLUSH)录 **200.00 元** → 状态「已设置」 |

| 额外消耗(免单/补发) | `免单/赠出` **10 元** + 备注,落表 ¥10.00 |

| 回概览再「重算」 | 商品标准成本 **待补 → ¥2,201.00**(成本已回填,不再按 0/缺失) |

| 异常清单 | 实时扫描显示 **待处理 29 条 / 筛选结果 32 条**,均为 `paidStateNotUpdated` |

| 异常处理(分支) | 首行订单 `S1793393904422780659`(paid 但 status=cancelled)填说明点「确认恢复」→ 被拒:**「异常事实仍存在,请先完成原业务处理后再确认恢复」** |

| 修复后恢复 | Prisma 将订单 status `cancelled → paid`,同一弹窗再次确认 → Toast「已确认恢复(后端已重查事实,写审计)」,行变 **已恢复**,处理记录可见备注 |

| 导出 CSV | 点「导出 CSV」→ Toast「已导出(写入导出审计)」 |

演示前夹具 / 数据说明(透明记录)

  • **异常未人工 seed**:库中已有 30 条 `paidStateNotUpdated` 真实异常(历史已支付但状态 cancelled 的订单);最终录制时 29 条待处理(另 1 条在前一次试录中已真实修复并恢复),首行被用于演示;未凭空造 sourceId。
  • **订单修复是真的**:`S1793393904422780659` 由 cancelled 改为 paid 后才通过后端事实重查;不是只改异常状态。
  • **整日标准成本夹具**:当天 199 笔支付横跨 174 个商品,其中 173 个(大量为历史 E2E/归档测试商品)`standardCost` 为空;只给演示商品录 200 元时,整日汇总仍会是「待补」。故**录制前**用 Prisma 把这 173 个商品的标准成本预置为 ¥1.00 作为背景夹具;UI 中真正演示录入的仍是 `演示·拼团毛绒 = 200 元`。不预置则无法出现「待补 → 数字」的整日汇总。
  • 录制前把 `演示·拼团毛绒` 成本/当日订单项成本重置为 null、删除当日快照并重新生成(`generatedAt` 回拨 1h),保证「待补」起点和「最后更新」变化可见。
  • 额外消耗录入写审计;异常恢复写 `anomaly.resolve` 审计。

备注

  • 视频开头约 5s 为后台登录/鉴权加载(空白/“正在验证登录状态”),随后进入业务画面;页面整页刷新时会有 1–2s 鉴权 loading。
  • 录制脚本与 DB 辅助脚本均在 `/home/yams/proof-artifacts/v3/p4/`,未改仓库、未安装依赖、未重启 dev server。