docs: add product archive spec and plan
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
# 产品档案与词云归档:技术设计
|
||||
|
||||
> 前置需求:[requirements.md](requirements.md)
|
||||
|
||||
## 1. 设计结论
|
||||
|
||||
词云生成任务仍可在设计期间生成位置库,但该文件只是一份**临时工作区产物**;它在成功生成后默认保留 30 天。用户从画布执行“加入产品列表”时,系统才把当前可见画布实际使用的词云位置库复制为产品档案中的不可变快照。产品档案不依赖原始任务目录,因此原始任务后续清理不会影响已加工产品的查询能力。
|
||||
|
||||
“加入产品列表”是设计系统内可执行的归档授权;实体加工和上市不由当前系统自动推断。后续可从生产/MES/电商接口写入产品状态,但不改变“已归档产品数据不自动删除”的原则。
|
||||
|
||||
## 2. 生命周期
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> 临时设计数据: 词云生成成功
|
||||
临时设计数据 --> 临时设计数据: 设计、插入或移除画布
|
||||
临时设计数据 --> 待清理: 30 天未归档
|
||||
临时设计数据 --> 产品档案: 加入产品列表
|
||||
产品档案 --> 待清理: 解除关联或删除产品
|
||||
待清理 --> [*]: 30 天宽限期结束
|
||||
产品档案 --> 产品档案: 更新产品资料/添加图片
|
||||
```
|
||||
|
||||
清理前 7 天,系统在“产品档案/数据清理”管理界面显示提醒。首期不依赖邮件或外部通知服务。待清理状态允许恢复或延长;到达物理清理时间才删除文件。
|
||||
|
||||
## 3. 归档识别规则
|
||||
|
||||
归档由后端根据提交的画布文档重新计算,不能仅相信前端传来的词云列表。
|
||||
|
||||
1. 读取当前 `CanvasDocument` 的 `layers` 和 `elements`。
|
||||
2. 排除不可见图层中的元素。
|
||||
3. 在剩余元素中收集插入式素材的 `assetId`。
|
||||
4. 从素材元数据读取其词云来源;首期兼容现有 `job_id`,新字段统一为 `source_job_id` 与 `source_kind=wordcloud`。
|
||||
5. 仅接受存在成功任务且包含 `word_locations` SQLite 的来源;普通图片、无来源 SVG、WCD 合成任务等不计入词云档案。
|
||||
6. 以 `source_job_id` 去重;同一词云多次出现只归档一份位置库。
|
||||
7. 若零份词云可归档,允许创建产品但明确标记“无词云归档数据”;不得虚报归档成功。
|
||||
|
||||
词云从画布删除后不会出现在本次文档扫描中,因此不会随本次产品版本归档。已经归档的历史产品版本不因后来编辑画布而被改写。
|
||||
|
||||
## 4. 数据与文件边界
|
||||
|
||||
### 4.1 产品元数据 SQLite
|
||||
|
||||
新增独立且持久化的 `service_products/products.db`,而不是把产品数据放在当前未挂载的 `service_metadata/app.db` 中。
|
||||
|
||||
| 表 | 核心字段 | 用途 |
|
||||
|---|---|---|
|
||||
| `products` | `product_id`, `source`, `external_product_id`, `name`, `sku`, `specification`, `status`, `cover_image_id`, timestamps | 产品主档;`(source, external_product_id)` 唯一 |
|
||||
| `product_versions` | `version_id`, `product_id`, `design_snapshot_path`, `design_digest`, `wordcloud_count`, timestamps | 一次“加入产品列表”产生一个不可变设计版本 |
|
||||
| `product_wordcloud_archives` | `archive_id`, `version_id`, `source_job_id`, `source_asset_id`, `db_path`, `db_checksum`, timestamps | 产品版本与一份位置库快照的关系 |
|
||||
| `product_images` | `image_id`, `product_id`, `version_id?`, `kind`, `path`, `remote_source?`, `is_cover`, timestamps | 图片集合;首期使用 `design_preview` |
|
||||
| `cleanup_records` | `subject_type`, `subject_id`, `state`, `purge_after`, `reminded_at`, `reason` | 临时任务和已删除档案的可恢复清理状态 |
|
||||
|
||||
`external_product_id` 是接口幂等键,不作为默认显示字段。网页创建产品的 `product_id` 由服务生成;可选 SKU/规格用于人类识别。
|
||||
|
||||
### 4.2 档案文件
|
||||
|
||||
```text
|
||||
service_products/
|
||||
products.db
|
||||
<product_id>/
|
||||
<version_id>/
|
||||
design-preview.png
|
||||
wordclouds/
|
||||
<archive_id>.db
|
||||
```
|
||||
|
||||
- `design-preview.png` 是加入产品时的完整设计预览快照,首期默认作为封面。
|
||||
- 每份 `.db` 为原始任务 `wordcloud_hd.db` 的验证后拷贝,保留原有 `word_locations` 表结构。
|
||||
- 词云查找使用产品档案快照,不再要求原始 `service_workspace/<job_id>` 存在。
|
||||
- 图片模型支持未来的 `reality_photo`、`external_product_image`,并始终由 `cover_image_id` 指向当前封面。远端图片应下载/复制入档案,而非只保存易失效 URL。
|
||||
|
||||
### 4.3 原始任务与档案的关系
|
||||
|
||||
`job_id` 是来源追溯键,不是产品档案的身份。每次归档记录来源任务、素材和数据库校验和;当相同外部产品重新加入新的设计时,增加新的 `product_version`,旧版本继续可追溯。
|
||||
|
||||
## 5. 服务边界与接口
|
||||
|
||||
### 5.1 ProductArchiveStore
|
||||
|
||||
新增产品档案存储层,负责:产品幂等创建/更新、版本创建、数据库文件原子复制、封面文件保存、软删除、恢复和清理候选查询。文件复制采用临时文件、SQLite 可读性检查、校验和计算和原子重命名;任一失败都回滚元数据和临时文件,不能出现“列表显示已归档但数据库缺失”。
|
||||
|
||||
### 5.2 ProductProvider
|
||||
|
||||
定义产品来源适配层:
|
||||
|
||||
- `manual`:网页创建。
|
||||
- `external`:外部产品接口同步。首期只约定稳定 ID 和名称;SKU、规格、封面 URL 为可选字段。
|
||||
|
||||
外部接口尚未在当前仓库中实现,因此首期不绑定具体 URL、认证方式或字段名。适配层以 `source + external_product_id` 进行幂等 upsert,避免按名称错误合并。
|
||||
|
||||
### 5.3 建议 API
|
||||
|
||||
| 接口 | 责任 |
|
||||
|---|---|
|
||||
| `GET /api/products` | 搜索产品列表;按名称/SKU/状态筛选 |
|
||||
| `POST /api/products` | 网页创建产品 |
|
||||
| `POST /api/products/sync` | 由产品接口适配器批量 upsert;不在首期绑定外部协议 |
|
||||
| `GET /api/products/{product_id}` | 产品、图片、版本及词云归档摘要 |
|
||||
| `POST /api/products/{product_id}/versions` | 提交当前画布;服务端识别可见词云、保存预览并创建归档版本 |
|
||||
| `GET /api/products/{product_id}/archives/{archive_id}/locations` | 查询该产品词云名字位置 |
|
||||
| `DELETE /api/products/{product_id}` | 软删除,进入 30 天待清理期 |
|
||||
| `POST /api/products/{product_id}/restore` | 恢复待清理产品 |
|
||||
| `GET /api/maintenance/cleanup-candidates` | 管理员查看清理预览 |
|
||||
| `POST /api/maintenance/cleanup-run` | 仅清理已到期且未被档案引用的数据 |
|
||||
|
||||
产品、档案查询和清理接口沿用生产订单管理权限;加入产品动作也必须带同一管理身份,避免把包含人员名字的位置库暴露给匿名调用。
|
||||
|
||||
## 6. 前端体验
|
||||
|
||||
### 6.1 画布中的入口
|
||||
|
||||
在画布顶栏或文件操作区提供「加入产品列表」。点击后:
|
||||
|
||||
1. 扫描当前画布并显示“已检测到 N 份画布词云,将全部归档”。
|
||||
2. 用户搜索接口同步产品,或选择「新建产品」。
|
||||
3. 对新建产品填写名称,规格/SKU 为可选。
|
||||
4. 显示完整设计预览缩略图,说明“将作为产品封面;以后可替换为实景图”。
|
||||
5. 确认后显示“已归档至产品《名称》· N 份词云位置数据已长期保存”。
|
||||
|
||||
没有可归档词云时,仍可建立产品,但确认界面和产品状态必须显示“无词云归档数据”。
|
||||
|
||||
### 6.2 产品列表与产品详情
|
||||
|
||||
- 列表的主识别信息为封面、产品名称和规格/SKU,不显示完整 ID。
|
||||
- 列表状态为「已归档词云数据」「无词云数据」「待清理」等人类可读标签。
|
||||
- 详情页展示当前封面、大号设计预览、归档版本时间线、每版本词云数量及后续图片集合入口。
|
||||
- 完整 ID 仅在“系统信息”折叠区提供复制,供排错和接口对接。
|
||||
|
||||
视觉沿用当前深色工作台的工业化风格:现有 `DM Sans` / `DM Mono`、背景 `#101114`、面板 `#1c1f24`、操作强调 `#6ea8ff`、归档成功 `#58d69c`、待处理 `#e4b95a`。这是对通用 UI 规范字体/颜色限制的窄范围品牌继承。
|
||||
|
||||
## 7. 清理策略
|
||||
|
||||
| 对象 | 初始状态 | 提醒 | 物理清理 |
|
||||
|---|---|---|---|
|
||||
| 成功生成但未归档的词云任务 | 临时 | 第 23 天在管理界面提示 | 第 30 天 |
|
||||
| 已归档产品/词云版本 | 已归档 | 无自动删除 | 仅在显式解除关联/删除后 |
|
||||
| 已解除关联或删除的产品档案 | 待清理 | 可恢复期内显示 | 30 天后 |
|
||||
|
||||
清理执行时应删除完整的原始任务目录或档案版本目录,而不是仅删数据库的一部分;这避免留下指向失效数据库的元数据。清理器必须重新检查是否仍存在产品归档关联,避免并发“加入产品”和清理导致误删。
|
||||
|
||||
现有按素材引用跳过清理的逻辑需要改为按产品档案引用保护:普通画布素材引用只延长临时设计保留期,不构成永久保留理由。
|
||||
|
||||
## 8. 部署、迁移与兼容
|
||||
|
||||
当前 Docker Compose 挂载了工作区/素材目录,但未挂载 `service_metadata` 和 `service_orders`。产品档案必须新增持久化卷,例如 `wordcloud_products -> /app/service_products`;同时建议为元数据与订单目录补充独立持久化卷,避免容器重建后丢失关联记录。
|
||||
|
||||
上线时:
|
||||
|
||||
1. 创建产品存储与 schema,不修改既有 `word_locations` 结构。
|
||||
2. 既有任务默认视为临时数据,按其完成时间纳入清理候选;不自动把旧任务提升为产品档案。
|
||||
3. 只有用户通过“加入产品列表”确认的设计才创建新档案快照。
|
||||
4. 在第一次实际清理前,以只读 dry-run 展示候选清单,确认后才开启物理删除。
|
||||
|
||||
## 9. 验证策略
|
||||
|
||||
- 单元测试:可见图层筛选、来源识别、去重、隐藏图层排除、外部 ID 幂等、宽限期计算。
|
||||
- 服务测试:数据库快照原子复制和回滚、归档后原始任务删除仍可查询、软删除与恢复、到期清理二次引用检查。
|
||||
- 前端测试:归档扫描摘要、零词云提示、产品名称展示、设计预览默认封面、待清理状态提示。
|
||||
- 人工验证:将多份词云插入/删除/隐藏后加入产品;确认实际归档数量与画布可见内容一致;清理 dry-run 不包含已归档位置库。
|
||||
|
||||
## 10. 未纳入本阶段的开放项
|
||||
|
||||
- 外部产品接口的真实协议、认证与字段映射。
|
||||
- 实景图上传、图片多选与外部图片下载任务。
|
||||
- 实体加工、上市、退市状态如何从外部系统回传。
|
||||
- 多用户角色与精细权限;首期复用订单后台管理身份。
|
||||
@@ -0,0 +1,62 @@
|
||||
# 产品档案与词云归档:需求确认稿
|
||||
|
||||
## 问题与目标
|
||||
|
||||
当前词云位置库按生成任务保存,设计试验、废弃样例与实际产品没有明确边界,既会累积无用数据,也无法把已加工产品的名字位置稳定地归档。系统需要在设计环节将“画布实际使用的词云”归入产品档案,并让未归档的临时数据可被安全清理。
|
||||
|
||||
## 已确认的业务规则
|
||||
|
||||
- **长期保留依据**:产品已加入产品列表;这是设计端可执行的保留动作。实体产品已加工是其业务背景,但不依赖系统自动推断加工结果。
|
||||
- **归档对象**:加入产品时,扫描当前画布中实际插入、且可追溯至词云生成任务的素材;默认归档全部命中的词云。
|
||||
- **不归档对象**:仅生成但从未插入画布的词云、中间样例/废品、已从当前画布移除的词云、普通图片与不可追溯来源的 SVG。
|
||||
- **隐藏图层**:不视为当前成品内容,不归档其中的词云。
|
||||
- **去重**:同一来源词云在画布中出现多次时,只保存一份词云位置库快照。
|
||||
- **产品身份**:接口导入产品使用稳定的外部产品 ID;网页创建产品使用内部产品 ID。ID 是系统关联键,不是默认展示内容。
|
||||
- **人类识别**:默认展示产品名称;可辅以规格、SKU/款号与封面,不显示完整产品 ID。
|
||||
- **产品图片**:产品从一开始支持图片集合和当前封面;首期仅保存当前完整设计的预览快照,后续可添加实景图和产品接口图。
|
||||
- **归档介质**:产品档案保存词云位置库的独立快照,同时保留来源任务 ID 供追溯;不能只依赖可能被清理的原始任务目录。
|
||||
|
||||
## 范围
|
||||
|
||||
1. 在画布中提供“加入产品列表”动作。
|
||||
2. 支持选择接口同步的产品或在网页创建产品。
|
||||
3. 创建/更新产品档案、设计预览图和关联词云位置库快照。
|
||||
4. 在产品列表与设计界面显示归档状态及可读提示。
|
||||
5. 为临时设计数据提供自动清理候选、延期和人工清理能力。
|
||||
6. 为产品档案提供后续多图、外部产品接口与实体加工状态接入的扩展位。
|
||||
|
||||
## 非目标(首期)
|
||||
|
||||
- 不自动根据 WCD 合成任务成功推断“实体已加工”或“已上市”。
|
||||
- 不在首期接入实景图上传或外部产品图片;只保留可扩展的数据结构与封面选择入口。
|
||||
- 不以产品名称作为接口同步和去重依据。
|
||||
- 不删除已归档产品的词云位置库,除非用户显式删除产品档案或解除关联。
|
||||
|
||||
## 用户故事
|
||||
|
||||
1. 作为设计人员,我希望把当前设计加入产品列表,使成品使用的词云数据被长期保存。
|
||||
2. 作为设计人员,我希望系统自动识别当前画布中使用的词云,而不必逐项查找生成任务。
|
||||
3. 作为生产/运营人员,我希望通过产品名称、规格与预览图识别档案,而不是记住内部 ID。
|
||||
4. 作为管理人员,我希望未用于产品的临时设计数据能被定期清理,同时可在清理前人工保留或延后。
|
||||
5. 作为未来接口维护者,我希望外部产品能按稳定 ID 合并进同一个产品档案。
|
||||
|
||||
## 验收标准(EARS)
|
||||
|
||||
1. 当用户在画布中选择“加入产品列表”时,系统应扫描当前可见画布元素并识别可追溯的词云来源。
|
||||
2. 当扫描到多个可追溯词云时,系统应默认选择全部唯一来源并在确认界面显示数量和来源摘要。
|
||||
3. 当同一词云来源被多个画布元素引用时,系统应只创建一份位置库归档快照。
|
||||
4. 当词云仅存在于隐藏图层、未插入画布或已从当前画布删除时,系统不应将其归档为该产品的词云数据。
|
||||
5. 当用户确认加入已有产品或创建新产品时,系统应创建产品与词云归档版本的关联,并保存当前完整设计预览图。
|
||||
6. 当产品来自外部接口时,系统应使用外部产品 ID 作为幂等关联键;页面应默认显示产品名称而非该 ID。
|
||||
7. 当产品在网页内创建时,系统应生成内部产品 ID,并允许用户填写用于展示的产品名称及可选规格/SKU。
|
||||
8. 当归档成功时,系统应提示“已归档至产品”,并显示产品名称和已归档词云数量。
|
||||
9. 当设计数据尚未归档至产品时,系统应明确标记其为临时数据并显示清理策略或预计清理时间。
|
||||
10. 当产品档案仍关联某词云位置库时,自动清理流程不得删除该归档位置库。
|
||||
11. 当用户解除产品关联或删除产品档案时,系统应先进入可恢复的待清理状态,而非立即不可逆删除词云数据。
|
||||
12. 当后续加入实景图或外部产品图时,系统应能把它们作为产品图片候选,并允许选择当前封面而不丢失设计预览快照。
|
||||
|
||||
## 尚待确认的策略参数
|
||||
|
||||
- 临时设计数据的默认保留天数及清理前提醒时点。
|
||||
- 产品被删除、外部接口下架或解除关联后的宽限期。
|
||||
- 产品接口可提供的最小字段(稳定 ID、名称;建议另含 SKU/规格/封面 URL)。
|
||||
Reference in New Issue
Block a user