refactor(douyin-mashida)!: 纠偏——删掉自建的皮肤通道,改回复用 affiliate_dash

上一轮我把皮肤交付做成了「另建一套执行器 + 独立领取接口 + 只提交账号就结束」,
跟买家实际要走的过程不一致(真正的完成信号是「扫码绑定后的 UID == 买家填的 UID」),
而且核销还触发了老通知逻辑,给买家**又发了一条 /redeem** —— 买家收到两条链接。
本次按用户要求改回**完全复用仓库现成的 affiliate_dash 通道**(= 旧的快手皮肤自动发货)。

**删掉**
- 执行器 `douyin_mashida_skin`(含 registry/types/planner/bootstrap/路由白名单注册)
- `services/claim/claim-skin-service.ts`、`routes/claim-skin.ts`、`/api/v1/claim-skin` 挂载
- 迁移 096 的 `claim_submission_json` 全链路(task-repo / rows / inputs / task-detail /
  admin-read-service 的 claimSubmission),并新增 **097 兜底迁移**把该列 DROP 掉
- 顺带清掉上一轮专为已删接口加的死代码(utils/http.ts 的 buildMessageSuccessPayload 等)

**改回复用**
- `resolveOrderItemClaimLink`:通用解析(只看订单项、不看执行器)→
  `buildConfiguredClaimUrl(claimLinkBase, token)`;多履约单元取 task id 最小并告警;
  **绝不回退** hash 形态的 `buildClaimUrl`
- `cert_link` 与付款后那条**唯一**消息共用同一个解析结果
- **核销后不再给抖音买家发第二条消息**(`shouldNotifyBuyerAfterVerify` 只放行非抖音 provider)
- 买家侧走既有流程:输 UID → 二维码 → 扫码绑定 → 比对 UID → delivered/REDEEMED;
  在 delivered 分支 best-effort 核销平台券(幂等、失败只 warn,不拖慢买家响应)
- 后台回显链接改按 **order.provider** 判断(抖音用 `claimLinkBase`)

**SQL 守卫**:允许「删除历史迁移」,但强制要求「同时新增兜底迁移」配对
(修改历史迁移仍禁止),并把改动来源换成 `git status --porcelain`(否则未跟踪的新迁移看不见)

`npm run check`:tests 671 / pass 668 / fail 0 / skipped 3(含新增的物品图回退用例)
This commit is contained in:
yml2213
2026-10-09 16:13:39 +08:00
parent 56ad06239b
commit 4fce07a621
37 changed files with 590 additions and 1300 deletions
@@ -1,20 +0,0 @@
-- 096_fulfillment_tasks_claim_submission.sql —— 皮肤自动发货「买家领取页」提交内容落库。
--
-- 背景:抖音码速达的皮肤类商品改为「自动发货 + 领取链接」,买家在 /claim-skin/:token
-- 提交游戏账号后,我们要把账号存下来交给运营发货(并防重复提交)。
--
-- 为什么单开一列而不是塞进 work_orders.material_json:
-- material_json 是发给打手的工单素材(还挂了搜索索引与统计),买家游戏账号属于隐私数据,
-- 写进去等于对外泄露(仓库既有隐私红线,见 douyin-mashida/order-mapper.ts 的 buyerWords 注释)。
-- fulfillment_tasks 只被履约/后台读取,工单侧(worker-platform)明确不 JOIN 该表,
-- 因此把账号留在任务自身上是最小暴露面的做法。
--
-- 幂等:全部 IF NOT EXISTS。
ALTER TABLE fulfillment_tasks
-- 买家领取页提交内容:{"gameAccount":"...","submittedAt":"...","source":"claim_skin"};
-- 空对象 {} 表示尚未提交(待领取)。
ADD COLUMN IF NOT EXISTS claim_submission_json JSONB NOT NULL DEFAULT '{}'::jsonb;
COMMENT ON COLUMN fulfillment_tasks.claim_submission_json IS
'买家领取页提交内容(gameAccount/submittedAt);隐私字段,禁止写入 work_orders.material_json';
@@ -0,0 +1,11 @@
-- 097_drop_claim_submission.sql —— 撤销上一轮「抖音皮肤独立领取流程」留下的买家提交列。
--
-- 背景(设计纠偏):抖音码速达皮肤/礼包类订单的交付改为**完全复用现成的 affiliate_dash 通道**
-- (一条链接 → 买家输 UID → 二维码 → 扫码绑定 → 比对「绑定 UID == 填的 UID」→ 发货完成),
-- 上一轮另建的 `douyin_mashida_skin` 执行器 / `/api/v1/claim-skin` 接口 / 独立领取页
-- 以及「只提交账号就结束」的 `claim_submission_json`(迁移 096)整条链路作废并删除。
-- 买家提交的游戏账号改由 affiliate_dash 领取流程的 `claimIdentity`(expectedUid/boundUid)承载。
--
-- 幂等:IF EXISTS;列不存在(未应用过 096 的环境)也不会报错。
ALTER TABLE fulfillment_tasks DROP COLUMN IF EXISTS claim_submission_json;