- diy-fix-workflow:新增两份契约逐项核对总表 - design-data-contract-v1:stickers[].width/height/x/y 语义 = 画布显示像素 (实现注记,非版本升级),历史数据读端按 mask 归一化兼容 Co-Authored-By: Claude <noreply@anthropic.com>
6.7 KiB
6.7 KiB
设计数据 → 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/)还原整套画布。
还原需要三样东西全部可用:
- 画布尺寸 / 背景 ← 来自
category.mask。 - 贴纸布局(位置、大小、旋转、层级)← 来自
stickers[]。 - 贴纸图片字节 ← 来自每个贴纸的持久 URL(COS)。
第 3 点是关键约束:如果贴纸图是 wxfile:///tmp 临时路径,后端打包时下载不到字节,
WCD 生产任务直接失败。因此本契约把"图片必须持久化"从 R2 的已知限制升级为冻结约束。
2. 冻结的 designData 结构(v1)
与现有前端 DesignItem.designData 对齐,保留 imageSrc/imagePos 兼容旧版,新增如下字段:
/** 设计数据 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 持久 URL(https),禁止 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 打包器同时兜底读旧字段。
实现注记(2026-09-12,DIY 修正,非版本升级):
stickers[].width/height的语义为 画布显示像素(坐标空间 =category.mask的宽高),x/y同为画布内坐标。 渲染、碰撞检测、WCD 打包三方按同一语义消费,打包时不再做像素换算。 历史数据中按「图片原始像素」写入的值(width > mask 宽高)由读取端按 mask 等比归一化兼容, 不做存量迁移。addSticker时即归一化到画布空间(建议初始占 mask 短边 60%)。
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线稿)无法由词云平台.wcddocument.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) |