Files
wechat_wc/docs/routes/R2/README.md
T
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

92 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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. 环境坑:前端 `.env``OSS_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 页现在必须切换服务端 id**`POST /api/orders` 要传服务端 `designListId` /
`addressId`。checkout 目前仍读本地 store(R2 红线未动它);因 R2 会把服务端数据回写
缓存,过渡期读缓存能拿到服务端 id,但 R3 接入时应直接切 API。
2. **状态触发权归 R3**`PROCESSING`/`DONE` 由订单流程驱动(前端从不提交);
`ordered``orderId != null` 派生,只读。R2 已实现单向状态机
`DRAFT→SUBMITTED→PROCESSING→DONE`(后端校验,回退 400)。
**注意(2026-09-12 变更)**`SUBMITTED`designing)现在由 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. `persistDesignMedia``utils/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 下发(契约允许字段新增)。