Files
wechat_wc/docs/routes/R2
lhmin0604andClaude b109451e29 docs(r2): 交接文档复核更新——DIY 修正批次新事实 + 契约核对结论
- README:新增修正批次落地事实(草稿随时 PATCH、SUBMITTED 触发点、
  edits 落库与消费、width/height 语义、x/y 允许超界、onShow 同步通病)、
  契约核对结论与已知偏差(wxfile:// 以冻结决策为准)
- r2-workflow:决策#6 注记 SUBMITTED 触发点提前
- design-data-contract:实现注记明确 x/y 允许超出画布边界(钳制已撤销)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-09-12 20:10:18 +08:00
..

R2 交接收口说明(给其他线路)

R2(地址 + 设计清单服务端化)已于 2026-09-12 完成阶段 1-5 核心验收, 分支 feat/r2-address-design(前后端成对)。本文档记录其他线路接入时必须知道的 事实与红线,避免重复踩坑。实现细节见 docs/r2-workflow.md

已生效的事实(所有线路)

  1. 地址/设计清单的真数据源是服务端PostgreSQL),本地 utils/store 已降级为 「离线兜底缓存」:页面 API 成功回写缓存、失败读缓存、联网刷新以服务端为准覆盖, 旧本地数据不自动合并(用户反馈"我的设计没了"是预期行为,相关页面需要文案兜底)。
  2. designData 是服务端持久化 JSON(白名单 7 键:version/category/background/wordcloud/ stickers/imageSrc/imagePos,单条 ≤1MB)。DIY 保存时 category 裁剪为 {id, mask, tone} mask 已验证完整落库(WCD 画布尺寸来源)。
  3. 真机验证:贴纸 src 目前落库为 wxfile:// 本地路径(persistDesignMedia 因后端 upload 模块占位而静默降级保留本地图)——契约允许,但 R4 的 COS 上传是派单前硬前置
  4. 后端补齐了 PATCH /api/users/me(契约 §2 历史遗漏,service 早有 updateProfile 但 controller 未注册路由,Profile 页保存资料曾 404)。
  5. 后端 JSON body 上限 2MB(≤1MB 受理 / 1MB~2MB → 400 / >2MB → 413), multipart 上传不走此限制
  6. 环境坑:前端 .envOSS_BASE_URL)不入库。新机器 clone 后必须手动创建,否则 assetUrl('/img/...') 退化为找包内本地文件 → 首页大图全空白(大图 8 月已迁 OSS, 包内不再携带)。
  7. DIY 修正批次已全部落地2026-09-12commits eea6c3f → 190e59a,详见 docs/diy-fix-workflow.md),新增事实:
    • 清单条目会随时被 PATCH:DIY 工作台贴纸变化防抖 800ms 静默同步服务端 (含 DRAFT 状态条目,designData 白名单/1MB 校验与状态无关),切后台/跳转前强制 flush。R4 读改写 designData 时必须整包合并(红线已在下方给 R4 第 1 条)。
    • SUBMITTED 触发点 = 进入 DIY 工作台(新建创建后立即 PATCH designing, 继续设计同样推进),不再是「确认完成」。状态机方向不变(r2-workflow 决策#6 已注记)。
    • 贴纸 edits 现在会真实落库并被 DIY 渲染端消费CSS filter:亮度/色相/对比度); 贴纸 src 在纯滤镜编辑下保持不变(裁剪/线稿才替换 src)。
    • stickers[].width/height = 画布显示像素addSticker 按 mask 短边 60% 归一化; 旧数据(原始像素语义)由读取端按 mask 等比归一化兼容,不做存量迁移
    • x/y 允许超出画布边界2026-09-12 需求确认撤销了坐标钳制):负坐标/超界是 合法状态,渲染端 overflow: hidden 裁切显示,WCD 打包按原值还原,不要钳制。
    • 页面栈返回不刷新是通病DIY 已加 useDidShow 从缓存同步贴纸;其他页面若 存在「子页面修改数据 → navigateBack 后不更新」,同样要用 onShow 双时机读取。
  8. 契约核对(2026-09-12route DO/DON'T + 双契约):checkout 未改动(本分支 0 diff); region[] 转换只在 api/address.ts;前端只提交契约内状态码(designing); isDefault 唯一性由后端事务保证(本地 store 仅离线镜像);设计数据 7 键白名单 /1MB/wordcloud 保留全部遵守。已知且已被契约接受的偏差:贴纸 src 暂存 wxfile://route 文档 DON'T 写于冻结决策之前,以 design-data-contract 约束#1/决策#4 为准,R4 派单前必须上传 COS)。

给 R3(订单 + 支付)

  1. checkout 页现在必须切换服务端 idPOST /api/orders 要传服务端 designListId / addressId。checkout 目前仍读本地 store(R2 红线未动它);因 R2 会把服务端数据回写 缓存,过渡期读缓存能拿到服务端 id,但 R3 接入时应直接切 API。
  2. 状态触发权归 R3PROCESSING/DONE 由订单流程驱动(前端从不提交); orderedorderId != null 派生,只读。R2 已实现单向状态机 DRAFT→SUBMITTED→PROCESSING→DONE(后端校验,回退 400)。 注意(2026-09-12 变更)SUBMITTEDdesigning)现在由 R2 前端在「进入 DIY 工作台」时即提交(不再等确认完成)——R3 不要假设 DRAFT 表示"用户还没动过设计", DRAFT 仅表示条目创建后从未打开过工作台。
  3. 删除保护(R3 落地项)R2 的 DELETE/batch-delete 没有做"有订单关联的清单 禁止删除"的守卫。R3 建 Order→DesignList 关联时必须同步加 delete-guard 或明确外键行为 (SetNull),否则用户可删掉订单引用的设计快照。
  4. orders / orderDetail / profile 页仍读本地 storeR3 接入时一并切 API (读的是 R2 回写的缓存,过渡期数据可用)。
  5. checkout 地址读取是一次性的(仅 mount 读缓存,无 onShow 刷新)——用户从 checkout 进入新建地址后返回不会同步,要重进页面才刷新。R3 切 checkout 时改为 mount + onShow 双时机读取(详见 docs/diy-fix-workflow.md 问题 6)。
  6. checkout 预览不消费贴纸 edits(亮度/色相/对比度):DIY 渲染端套 CSS filter 呈现编辑效果,checkout 预览接入时需同样消费(R3 待办,见 diy-fix-workflow 问题 5)。
  7. 金额重算:按契约用服务端 Product 真实价格 + designList.items[0] 快照, 忽略客户端金额;下单带 requestId 幂等。

给 R4(上传 / 词云 / 派单)

  1. 回写 designData 必须整包合并提交PATCH 的 items 是全量替换。R4 写入 wordcloud 分组或回写贴纸 COS URL 时,要先取服务端最新 designData、合并后再整包 PATCH——不能只传改动片段,否则会冲掉其他字段(与 DIY 保存同一条红线, 见 docs/design-data-contract-v1.md 约束#2)。
  2. persistDesignMediautils/api/upload.ts)已就位且真机验证为静默降级——R4 把 upload 模块做实后,现有调用点无需改动即自动生效。
  3. 前端 DesignDataV1.category 类型已收窄为 {id, mask, tone}(契约 §2 冻结形状), R4 不要往该字段塞完整 ProductCategory。
  4. DIY 贴纸目前不产生 rotation(无旋转手势)、zIndex 仅渲染层使用——两字段类型已 备好但值可能缺席,WCD 打包按 optional 处理(契约决策#2)。
  5. 2026-09-12 起)width/height = 画布显示像素(mask 短边 60% 归一化起步), x/y 为画布坐标空间且允许超界(含负值,不钳制)——打包按原值还原布局即可, 不要按「图片原始像素」换算,也不要对坐标做边界裁剪(契约实现注记)。

给 R1(商品目录)

  1. R2 的 productId 不做存在性校验(当时商品表未 seed 的阶段0 决策#7)。 R1 落地后如需收紧,属于契约语义变更,需同步 api-contract 版本。
  2. productIcon 不入库(决策#3):设计清单页图标按 PRODUCT_ICON_MAP[productId] 兜底。 R1 商品表有 iconImg 后可改为服务端 optional 下发(契约允许字段新增)。