docs: R4 WCD 生产任务契约(designData→词云)与路线文档

This commit is contained in:
2026-08-12 19:10:41 +08:00
parent 3e0346ad35
commit 85356e7a39
3 changed files with 359 additions and 42 deletions
+120
View File
@@ -0,0 +1,120 @@
# 设计数据 → WCD 生产任务契约 v1
> 跨路线契约:**R2(数据生产者)与本路线 R4(WCD 打包消费者)共同遵守**。
> 冻结目的:R4 下单后要把设计清单以 `.wcd` 包投递到词云平台形成生产任务
> (见 `docs/routes/route-r4-upload-wordcloud.md` §3)。R4 能打包,取决于 R2
> 保存的 `designData` 携带哪些字段。本文档把这些字段**先定死**。
>
> 版本规则:字段只能新增 optional 字段;改名/改语义/改类型必须升版本并同步本文件。
## 1. 为什么需要本契约
词云平台用 `.wcd`Zip`manifest.json` + `document.json` + `assets/`)还原整套画布。
还原需要三样东西全部可用:
1. **画布尺寸 / 背景** ← 来自 `category.mask`
2. **贴纸布局**(位置、大小、旋转、层级)← 来自 `stickers[]`
3. **贴纸图片字节** ← 来自每个贴纸的**持久 URL**(COS)。
第 3 点是关键约束:如果贴纸图是 `wxfile://`/`tmp` 临时路径,后端打包时下载不到字节,
WCD 生产任务直接失败。因此本契约把"图片必须持久化"从 R2 的已知限制升级为**冻结约束**。
## 2. 冻结的 `designData` 结构(v1
与现有前端 `DesignItem.designData` 对齐,保留 `imageSrc/imagePos` 兼容旧版,**新增**如下字段:
```ts
/** 设计数据 v1 —— 支持 R4 WCD 生产任务打包 */
interface DesignDataV1 {
/** 结构版本,缺省按 v1 处理;旧数据可由后端/前端按版本迁移 */
version?: 1
/** 商品品类(已有)。mask 是画布尺寸来源,保存清单时必须保留 */
category?: {
id: string
mask: { shape: 'rect' | 'circle'; width: number; height: number; borderRadius?: number }
tone?: [number, number, number]
}
/** 底图(已有 imageSrc 语义的规范化):src 必须是持久 URL */
background?: {
src: string // COS 持久 URL;禁止 wxfile:// / tmp 临时路径
color?: string // 画布底色(缺省由 mask/主题决定)
pos?: { x: number; y: number; scale: number } // 兼容旧 imagePos
}
/**
* 词云信息(R4 在词云生成后写入;R2 保存/更新清单时原样保留这组字段,
* 后端 items JSON 白名单放行)。
*/
wordcloud?: {
jobId?: string // 生成该词云的 wxmp_backend 侧任务 id
imageUrl: string // 词云结果图持久 URL(COS)
names: string[] // 名单快照(≤200),生产/重建用,可为空
}
/** 贴纸列表(已有)。每个贴纸的 src 升级为持久 URL 约束 */
stickers?: Array<{
id: string
src: string // ★ 必须为 COS 持久 URLhttps),禁止 wxfile:// / tmp / 空
x: number
y: number
scale: number
width: number
height: number
rotation?: number // 已冻结(2026-08-12 决策#2):本期 DIY 持久化;无旋转则省略
zIndex?: number // 已冻结(2026-08-12 决策#2):图层顺序;WCD 按 zIndex 排列元素
isOverlapping?: boolean
edits?: {
brightness?: number // -100~100
hue?: number // -180~180
contrast?: number // -100~100
sketchSrc?: string
}
}>
}
```
关系说明:
- `DesignItem.designData`(前端类型文件 `src/types/index.ts`)与后端 `design-list.items[].designData`
(服务端 JSON)为**同一份**结构;前端类型以本契约为准,后端只做白名单校验不改业务 JSON。
- `imageSrc/imagePos` 保留为兼容旧版字段;新写入统一走 `background.src/pos`
WCD 打包器同时兜底读旧字段。
## 3. 冻结约束(R2 需落地)
| # | 约束 | 说明 |
|---|---|---|
| 1 | **贴纸图持久化(R4 负责)** | 决策#4:**贴纸持久化由 R4 完成**。R2 允许保存/更新清单时贴纸 `src` 暂为本地路径(`wxfile://`/`tmp`);**R4 在下单/派单前**把本地图上传为 COS 持久 URL 并回写 `designData.stickers[].src`。WCD 打包只消费持久 URL。R2 需保证该字段可被 R4 回写 |
| 2 | **词云字段保留** | `designData.wordcloud` 由 R4 写入后,R2 的 PATCH/列表接口不得丢弃该分组 |
| 3 | **mask 必须存在** | `designData.category.mask` 是画布尺寸来源;缺 mask 的旧数据 WCD 打包按产品默认尺寸兜底 |
| 4 | **布局字段持久化** | 决策#2`rotation`/`zIndex` 本期由 DIY 随贴纸持久化(当前 `StickerItem` 缺 rotation,需补) |
| 5 | **白名单放行** | 后端 `design-list` 的 items JSON 白名单放行 `version/background/wordcloud/rotation/zIndex` 字段;单条 ≤1MB 上限以新结构复核(图片在远端 URL,JSON 本体仍应很小) |
| 6 | **状态映射不变** | `ordered` 继续由 `orderId != null` 派生,本契约不改变 R2 状态机 |
## 4. 边界(本期不做)
- 贴纸 `edits`(亮度/色相/对比度/`sketchSrc` 线稿)无法由词云平台 `.wcd`
`document.json` 表达,本期不随 WCD 携带;仅记录在 `manifest.meta`。若后续生产需要
线稿还原,需单独升 WCD 契约(wordcloud 侧支持后再谈)。
- 字体不随包携带(wordcloud 第一阶段不做字体打包)。
- `.wcd` 只做"订单 → wordcloud"单向投递;暂不做"词云平台 → 小程序"的反向导出。
## 5. 落地位置
| 文件 | 内容 |
|---|---|
| 前端类型 | `wechat_wc/src/types/index.ts``DesignItem.designData` 按本契约补齐字段 |
| 前端页面 | `diy`(保存 designData)、`checkout`(下单前确认 designData 完整) |
| 后端白名单 | `wxmp_backend/src/design-list/*` 的 items 校验放行新字段 |
| 契约发行 | `wxmp_backend/docs/api-contract-v1.md` §5 引用本文档 |
## 6. 决策记录(2026-08-12 冻结)
| 评审点 | 决策 |
|---|---|
| 1. `background`/`wordcloud` 命名 | **接受**,按 §2 结构冻结 |
| 2. `rotation`/`zIndex` 是否本期持久化 | **本期持久化**DIY 随贴纸保存(见约束 #4 |
| 3. 名单快照 `wordcloud.names` 是否必须 | **小程序可不必须**`names` 保持 optional,小程序可不带;R4 生成词云后按实际写入,生产侧不强依赖 |
| 4. 贴纸图持久化由谁触发 | **R4 负责**:下单/派单前把本地贴纸图上传为 COS 持久 URL 并回写 `src`(见约束 #1 |