Files
atlas-seller-kit/docs/architecture/media-storage-strategy.md
2026-09-08 16:19:38 +08:00

103 lines
9.4 KiB
Markdown
Raw Permalink 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.
# 商品采集媒体(图片与视频)存储策略
> 状态:采集阶段的按需物化已落地;正式商品编辑、水印、AI 图片处理和发布尚未接入选择动作。后续任何相关开发必须以本文为准;接口、数据模型和 Worker 改动须先在同一任务中完成相应契约更新。
## 1. 目标与基本原则
采集阶段的绝大多数图片和视频最终不会被用户选中、编辑或发布。首期因此采用**按需物化**:先保存可审查的来源候选信息,只有用户实际使用媒体时才下载、校验并写入 Atlas 对象存储。
1. `source_url` 是来源证据与即时预览地址,不是 Atlas 控制的正式素材,也不是可靠的长期地址。
2. `media_asset` 才是经过大小、格式、安全校验并由 Atlas 控制的正式素材;编辑、发布和需要稳定重试的处理链路只能引用它。
3. 浏览器可显示来源图片不代表后端或第三方 AI 服务可稳定下载它。来源可能有防盗链、临时 URL、限流、地区限制、图片替换或失效。
4. Worker 不携带来源站 Cookie,不能为了下载图片绕过来源站的会话或防盗链机制。
5. 首期不做“已选择但未发布素材”的自动生命周期删除。自动清理需要定义引用、编辑中状态、恢复和误删处理,复杂度与风险超过当前收益。
## 2. 场景决策表
| 场景 | 是否需要先转存原图 | 原因 |
|---|---:|---|
| 采集测试页预览 | 否 | 直接显示来源 URL;视频使用 `preload=none`,最快、零存储成本 |
| 采集箱暂存 | 否 | 只保存候选 URL、媒体类型、角色、SKU 关联、视频封面与证据 |
| 用户选图/视频进入编辑 | 建议是 | 转存选中的媒体,保证后续可用、可重试 |
| 加水印 | 不一定 | 可在任务中临时下载来源图→加水印→只保存水印结果;但来源失效后无法重试 |
| AI 生图 / AI 改图 | 通常要先转存或至少临时下载 | AI 服务需要实际图片字节,不能可靠地只依赖来源 URL |
| 正式发布 | 是 | 必须使用 Atlas 控制的已验证素材,不能依赖第三方 URL |
## 3. 推荐流程
```text
来源商品页
→ 采集候选 source_url、媒体类型、图片角色、SKU/规格关联、排序、视频封面和证据
→ 采集箱 / 测试页直接加载 source_url 供人工核对
→ 用户选择图片、请求水印/AI 处理或发起发布
→ 按需下载 → HTTPS/格式/大小/内容校验 → 创建或复用 media_asset
→ 编辑、派生任务和发布仅引用 media_asset
```
### 3.1 采集与即时预览
- 采集 API 只持久化来源候选信息;不得在采集完成后自动创建“下载全部候选图”的素材任务或 Outbox 事件。
- 测试页和后续采集箱详情优先以 `source_url` 作为 `<img>` 或 `<video preload="none">` 预览。跨域媒体通常可以由浏览器显示,但来源拒绝加载时只显示明确的失败状态与“查看来源”链接。
- 来源预览不得被误写入 `media_assets`、商品正式媒体关系、发布请求或长期缓存。
### 3.2 选择图片与正式编辑
- 用户首次把候选图设为商品主图、SKU 图、详情图,或进入依赖稳定原图的编辑操作时,服务端创建按需转存任务。
- 转存完成后,界面和后续操作切换到该 `media_asset` 的短时访问 URL;来源 URL 仍保留为采集证据。
- 转存失败或来源图已不可访问时,应提示用户重新采集/重新选择,而不是尝试携带来源 Cookie 或伪造 Referer 绕过限制。
### 3.3 水印与 AI 图片处理
- 水印任务可以临时下载来源图并只存储水印派生结果,以节约原图存储;但该模式无法在来源失效后可靠重试。需要稳定重试、再次编辑或保留原图时,应先转存原图。
- AI 生图不一定需要来源图;AI 改图、图生图、抠图等需要图片输入的能力,必须获得实际图片字节。实现可选择先物化 `media_asset`,或在单次任务内临时下载后提交给 AI 提供商。
- 向 AI 提供商发送来源图片字节或可访问 URL 属于对第三方的数据传输。产品界面、隐私说明和任务审计必须在该能力立项时明确告知;不得默认将所有采集候选图发送给 AI。
- 所有水印和 AI 的成功输出都必须保存为 Atlas 控制的 `media_asset`,并记录输入素材/来源、模板或模型版本与任务证据。
### 3.4 发布
- 发布前必须验证每张已选图片是当前工作空间内已校验的 `media_asset`。
- 禁止将来源站 URL 直接提交给目标销售平台;发布任务只能使用 Atlas 对象存储中的受控素材或由平台要求的上传结果。
## 4. 首期明确不做的能力
不实现“已选择但未发布素材在 7~30 天未使用即自动删除”。实现这一策略需要追踪编辑草稿、引用关系、处理中任务、发布快照、恢复窗口和误删申诉;在没有真实成本数据前,首期保留用户已按需转存的素材。
未来如存储成本成为问题,优先考虑只清理**从未被商品媒体、派生任务或发布快照引用**的素材,并在独立需求、数据模型、Worker 与用户通知方案评审后实施。
## 5. 已落地的按需物化边界
`POST /api/extension/materials` 已将图片和视频保存为 `collection_asset_transfers` 的 `pending_selection` 候选,不会创建素材 Worker 的 Outbox 事件。候选记录带 `media_type`,视频可另带 `poster_url`。重复采集会取消旧快照中尚未完成的候选或转存任务,并以新快照候选覆盖它们。
`POST /api/collection-items/{id}/asset-materializations` 是当前唯一的按需转存入口:请求必须包含当前快照中的一个或多个 `pending_selection` 候选 ID,并携带 `Idempotency-Key`。服务端将所选行标为 `queued`、创建 operation 并写入 `collection.assets.materialize.requested` Outbox 事件;既有 Worker 继续执行安全下载、校验、去重与 `media_asset` 创建。
`/collection-test/{id}` 对图片候选直接显示 `source_url`,对视频候选使用按需播放的来源 URL;已转存的历史素材则优先显示 Atlas 短时预览 URL。该测试页只核对数据,不能触发转存。
### 5.1 首期视频格式边界
- 当前采集器只接受来源商品结构化状态中明确给出的 HTTPS `MP4` / `WebM` 直链;Ozon 读取 `webGallery` / `webVideo`,1688 读取 `gallery.fields.video|videos`,淘宝/天猫读取 `item.videos`。绝不扫描整页 `video` 元素。
- `blob:` URL、`m3u8` / HLS、DRM 和无法识别的扩展不进入候选;转存 Worker 再以文件魔数确认 MP4/WebM。MP4/WebM 单文件上限为 200MB、最长下载等待 60 秒;图片保持 20MB 限制。
- 首期不做视频转码、封面抽帧、HLS 下载、DRM 处理、视频水印或发布。视频尺寸和时长也暂不解析;`media_asset.content_type` 是后续处理时的媒体判断依据。
下一阶段必须在正式商品编辑页实现选图后调用上述接口,并补齐来源失效、防盗链、重复点击、跨工作空间访问、AI/水印输入和发布前素材校验的集成测试;不得绕过该接口直接把来源 URL 写入正式商品媒体或发布请求。
## 6. 待优化 P1:来源站下载限流与退避
### 6.1 当前风险边界
按需物化已避免“采集一次下载全部图片”,但当前 Worker 尚未按来源平台或域名限流:单个转存任务内部逐张下载,Worker 总并发为 5;多个商品同时选图、多个 Worker 实例,或用户在测试页一次打开大量候选图片时,都可能在短时间向同一来源 CDN 发出多次请求。
- 测试页的候选图片预览由用户浏览器直接请求 `source_url`,不经过 Atlas Worker;它不会消耗 Atlas 存储,但多张图片同屏会形成来源站请求突发。
- Worker 下载会限制 HTTPS 公网地址、最多 3 次重定向、60 秒超时;图片上限 20MB、视频上限 200MB。这些是安全和资源保护,**不是来源站限流**。
- 当前 `429`、`503` 等下载失败会把候选标记为失败;不会读取 `Retry-After` 后延迟重试,因此不容易持续猛撞来源站,但会降低成功率。
- 素材仅在下载后按内容 SHA-256 去重;相同的来源 URL 被多个候选选中时,当前仍可能被重复下载。
### 6.2 正式编辑页接入前必须完成
1. 建立基于 Redis 的分布式下载限流器,限流键至少覆盖来源平台和规范化域名;初始建议每域名最多 2 个并发、每秒 2~3 个请求、短时突发不超过 4。实际阈值需按来源平台压测和运行数据调整。
2. 将 `429`、带 `Retry-After` 的响应和临时 `503` 转为可调度的延迟重试;遵守 `Retry-After`,使用指数退避与抖动,不能立即重试。
3. 对归一化后的来源 URL 建立下载任务去重:同一图片仅下载一次,完成后让多个候选关联同一 `media_asset`,而不是依赖下载后的哈希去重。
4. 对连续限流或临时不可用的来源建立熔断/降速窗口,并在操作状态中给出可理解的“来源暂时限流,稍后重试”反馈。
5. 测试页和正式采集箱详情采用懒加载、分页或虚拟列表,避免首次进入即请求全部来源预览图;来源图加载失败时保留“查看来源”链接,不能尝试携带 Cookie 或伪造 Referer 绕过防盗链。
在以上能力落地前,不允许将按需转存用于自动批量选图、全量素材预热或无人值守的大规模转存。