逐项根因定位(代码依据)+ 修复方案 + 契约影响 + 留意点: 1 重叠误报(CSS 钳制/原始像素与碰撞盒不一致,含旧数据兼容) 2 草稿持久化(防抖写缓存+服务端,status 不动) 3 SUBMITTED 触发点提前到进入工作台(决策#6 注记更新) 4 编辑页空白(问题2 修复即自动修复) 5 TouchSlider 启用 + CSS filter 预览替代 ctx.filter 6 checkout 地址同步滞后(R3 红线文件,记入 R3 待办) 问题5/6 的 R3 侧待办同步至 routes/R2/README.md Co-Authored-By: Claude <noreply@anthropic.com>
65 lines
4.8 KiB
Markdown
65 lines
4.8 KiB
Markdown
# 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,
|
||
包内不再携带)。
|
||
|
||
## 给 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)。
|
||
3. **删除保护(R3 落地项)**:R2 的 DELETE/batch-delete **没有**做"有订单关联的清单
|
||
禁止删除"的守卫。R3 建 Order→DesignList 关联时必须同步加 delete-guard 或明确外键行为
|
||
(SetNull),否则用户可删掉订单引用的设计快照。
|
||
4. orders / orderDetail / profile 页仍读本地 store,R3 接入时一并切 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)。
|
||
5. 金额重算:按契约用服务端 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)。
|
||
|
||
## 给 R1(商品目录)
|
||
|
||
1. R2 的 `productId` **不做存在性校验**(当时商品表未 seed 的阶段0 决策#7)。
|
||
R1 落地后如需收紧,属于契约语义变更,需同步 `api-contract` 版本。
|
||
2. `productIcon` 不入库(决策#3):设计清单页图标按 `PRODUCT_ICON_MAP[productId]` 兜底。
|
||
R1 商品表有 `iconImg` 后可改为服务端 optional 下发(契约允许字段新增)。
|