Files
atlas-seller-kit/docs/api/watermarks-and-assets.md
T

202 lines
7.3 KiB
Markdown
Raw 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.
# 水印与素材 API
> 素材主数据只保存 `storage_provider + bucket + object_key`。API 只在需要时签发短时上传/访问 URL,绝不返回或持久化对象存储的公开永久 URL。
## 1. 媒体上传:两阶段直传
水印图片和后续商品图片都复用此协议。上传意图是短时、一次性的受控动作;它不是公开文件地址。
### 1.1 创建上传意图
`POST /api/media/upload-intents`
Headers:`Idempotency-Key` 必填。
```json
{
"purpose": "watermark_image",
"filename": "brand-mark.png",
"content_type": "image/png",
"byte_size": 182736,
"checksum_sha256": "hex-sha256"
}
```
允许 `image/png`、`image/jpeg`、`image/webp`。`watermark_image` 最大 5 MiB、宽高 1–8192 px;`product_image` 最大 20 MiB、宽高 1–10000 px。服务端按用途校验大小/尺寸策略,生成随机 `object_key` 和 10 分钟有效的预签名上传地址。返回 `201 Created`:
```json
{
"data": {
"upload_id": "uuid",
"expires_at": "2026-09-02T08:10:00Z",
"upload": {
"method": "PUT",
"url": "https://short-lived-upload-url",
"headers": { "content-type": "image/png" }
}
}
}
```
前端必须以服务器返回的 method、URL 与 headers 上传,不能自行拼接对象路径;上传 URL 仅可写入该次目标对象。
### 1.2 完成与校验上传
`POST /api/media/upload-intents/{upload_id}/complete`
Headers:`Idempotency-Key` 必填。
```json
{ "checksum_sha256": "hex-sha256" }
```
服务端检查对象存在、文件大小、声明 MIME、文件魔数、哈希和图片尺寸;校验通过后创建/复用 `media_asset` 并返回 `201 Created`。校验失败时上传意图标记为失败,不能被水印模板引用。
```json
{
"data": {
"asset": {
"id": "uuid",
"content_type": "image/png",
"byte_size": 182736,
"width_px": 800,
"height_px": 400,
"created_at": "2026-09-02T08:02:00Z"
}
}
}
```
`object_key` 是服务端内部字段,不放在普通客户端响应。上传意图和完成状态均持久化在数据库,不能只存在于 Redis 或预签名 token 中;Worker 每 5 分钟将逾期未完成意图标记为 `expired`,并删除 `failed` / `expired` 意图的临时对象。删除成功才记录清理时间;失败会在下一轮重试。
### 1.3 临时预览 URL
`POST /api/media-assets/{asset_id}/access-urls`
```json
{ "purpose": "preview" }
```
返回 10 分钟有效的短时 `url` 与 `expires_at`。仅当前工作空间的素材可签发;前端在 URL 过期后重新请求,不能把 URL 写回业务表或长期缓存。
`GET /api/media-assets/product-uploads` 返回当前工作空间最近 100 个已经完成校验的 `product_image` 素材。每项包含 `MediaAsset` 字段及 10 分钟有效的 `preview_url`、`preview_url_expires_at`,供编辑页“上传图片”候选区展示;该地址不得写入草稿。
### 1.4 网络商品图片导入
`POST /api/media-assets/product-imports`,需 `Idempotency-Key`,请求 `{ "url": "https://example.com/image.jpg" }`。只接受 HTTPS、无用户信息和自定义端口、路径以 `.jpg`、`.jpeg` 或 `.png` 结尾的链接。服务端在每次重定向时解析域名并把连接固定到已检查的公网 IPv4;最多跟随 3 次重定向,下载上限 5 MiB,校验文件内容、MIME 与最大边长 10,000 px。成功返回 `201`,`data` 为 `ProductImportedImage`:`MediaAsset` 字段、原始 `source_url`、10 分钟有效的 `preview_url` 和 `preview_url_expires_at`。重复 URL 更新当前候选素材;原有 SKU 选图不被自动替换。
`GET /api/media-assets/product-imports` 返回当前工作空间最近 100 条已导入的网络图片,响应项同上。图片已生成正式素材 ID 后才可进入 SKU 草稿;网络来源地址和预览地址均不得写入 `media_asset_ids`。
## 2. 可用字体
`GET /api/watermark-fonts`
返回渲染服务已部署且状态为 `active` 的字体:
```json
{ "data": [{ "code": "NotoSans", "display_name": "Noto Sans" }] }
```
客户端不得读取浏览器或开发机字体列表;字体 code 是水印模板的稳定保存值。
## 3. 水印模板资源
水印模板的读取形状:
```json
{
"id": "uuid",
"name": "右下角品牌",
"kind": "image",
"current_version": 3,
"config": {
"image_asset": { "id": "uuid", "preview_url": "https://short-lived", "preview_url_expires_at": "2026-09-02T08:15:00Z" },
"opacity": "0.8000",
"scale_ratio": "0.2500",
"position": "bottom_right"
},
"created_at": "2026-09-02T08:00:00Z",
"updated_at": "2026-09-02T08:03:00Z",
"revision": 8
}
```
文字模板的 `config` 为:
```json
{
"text_content": "Atlas",
"font_code": "NotoSans",
"font_size_px": 24,
"opacity": "0.8000",
"position": "bottom_right"
}
```
`position` 只能是 `top_left`、`top_center`、`top_right`、`middle_left`、`center`、`middle_right`、`bottom_left`、`bottom_center`、`bottom_right`。`opacity` 范围 `"0"`–`"1"`;图片 `scale_ratio` 范围 `"0.1"`–`"2"`;文字 `font_size_px` 范围 12–60。
### 3.1 查询
`GET /api/watermark-templates?cursor={opaque}&limit=20`
按 `created_at DESC, id DESC` 返回当前工作空间活动模板。图片模板响应可带短时 `preview_url`;过期后应重新读取列表/详情或请求素材访问 URL。
`GET /api/watermark-templates/{template_id}`
返回模板当前版本,供编辑弹窗和“查看效果”使用。固定演示底图由前端内置,前端按 `config` 实时渲染预览,不在每次滑动 Slider 时创建服务端图片。
### 3.2 创建
`POST /api/watermark-templates`
Headers:`Idempotency-Key` 必填。
文字水印示例:
```json
{
"name": "右下角文字",
"kind": "text",
"config": {
"text_content": "Atlas",
"font_code": "NotoSans",
"font_size_px": 24,
"opacity": "0.8",
"position": "bottom_right"
}
}
```
图片水印示例:
```json
{
"name": "品牌图标",
"kind": "image",
"config": {
"image_asset_id": "uuid",
"scale_ratio": "0.25",
"opacity": "0.8",
"position": "bottom_right"
}
}
```
模板名称在当前工作空间内唯一;图片资产必须属于当前工作空间且已完成校验。成功返回 `201 Created` 与模板资源。
### 3.3 编辑与删除
`PATCH /api/watermark-templates/{template_id}`
Headers:`If-Match` 与 `Idempotency-Key` 必填。请求体与创建相同,但可只提交待改字段;若切换 `kind`,须提交新类型完整 `config`,服务端不保留旧类型专属字段。
每次影响渲染的更新都会创建新的 `watermark_template_version`,并增加模板 `current_version`。旧版本不会被覆盖,供已生成派生图追溯;模板改名只更新模板名称,不需要创建渲染版本。
`DELETE /api/watermark-templates/{template_id}`
Headers:`Idempotency-Key` 必填。服务端在同一事务软删除模板并解除所有当前店铺绑定,返回 `204 No Content`。不删除原始图片资产,也不影响已生成水印派生图和历史发布快照。
## 4. 与商品编辑的边界
本文件只定义水印模板和通用素材。商品编辑的“图片悬浮 → 编辑 → 添加水印”将在商品接口中定义:它选择这里的活动模板、创建持久化派生任务、固化模板版本,并将生成的独立素材替换当前 SKU 已选图片位置;不会在上架时临时加水印。