Files
atlas-seller-kit/docs/api/platform-catalog-admin.md
2026-09-20 15:23:44 +08:00

130 lines
9.6 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.
# 平台类目与属性管理 API
> 2026-09-18 新增契约,2026-09-20 增加平台刷新策略和类型属性批次。平台级目录供系统管理员维护,普通商品编辑器和首次发布预检也已切换到同一平台缓存;旧门店目录仅保留兼容/回滚。平台参考目录的归属见 [`platform-product-reference-catalog.md`](../architecture/platform-product-reference-catalog.md),新鲜度与优先级规则见 [`platform-catalog-cache-refresh-plan.md`](../architecture/platform-catalog-cache-refresh-plan.md)。
## 权限与安全
- 本模块接口都要求有效登录会话。除 `GET /api/system/access` 外,必须具有数据库授予且未撤销的 `system_admin` 全局权限;工作空间 `owner/admin` 不等于系统管理员。未授权返回 `403 SYSTEM_ADMIN_REQUIRED`。
- 系统管理员授权只能由受控数据库运维操作授予或撤销,不提供自助提权 HTTP 接口。权限变更在下一次请求时生效;前端菜单只是展示控制。
- 目录、同步来源和任务均按 `platform_id` 分区,不使用客户工作空间的 `workspace_id` 承载平台任务。Ozon `Client-Id` / `Api-Key` 只经 TLS 提交至 API,Key 加密落库,不写日志、Outbox 或响应。
- Wildberries 等其他平台可展示目录空状态;未实现适配器时发起同步返回 `422 PLATFORM_CATALOG_UNSUPPORTED`。
### 首位系统管理员初始化
系统管理员不能通过产品界面自助获得权限。目标用户先完成正常注册,再由数据库运维账号执行以下 SQL;应用运行账号 `atlas_app` 已被禁止修改该表:
```sql
INSERT INTO atlas.system_admin_grants (user_id)
SELECT id FROM atlas.users WHERE lower(email) = lower('管理员邮箱')
ON CONFLICT (user_id) DO UPDATE SET revoked_at = NULL, granted_at = now();
```
撤销权限时设置 `revoked_at = now()`,不要删除用户或改变其工作空间角色。授权和撤销均在下一次请求时生效。
## 接口
`GET /api/system/access`
返回 `{ "data": { "is_system_admin": boolean } }`,供已登录 Web 决定是否展示系统管理入口;服务端权限判断仍以数据库授权为准。
`GET /api/system/platform-catalog/platforms`
返回 `{ "data": [{ "id", "code", "name", "source": { "configured", "client_id_hint", "updated_at" }, "summary": { "category_count", "last_tree_sync_at", "next_tree_sync_at", "last_error" } }] }`。`client_id_hint` 仅为脱敏末尾字符,不返回 API Key、密文或指纹。`next_tree_sync_at` 固定为最近成功时间后 7 天;从未成功时为 `null` 并由调度器尽快创建首次任务。
`PUT /api/system/platform-catalog/platforms/{platform_id}/source`
Body:`{ "client_id": "...", "api_key": "..." }`。仅 Ozon 适配器接受当前配置;重复提交同一凭据不产生新版本或重复任务。首次配置或更换凭据时返回脱敏来源状态,并为该平台排队一次类目树同步;更换后旧版本的未完成任务不得用新密钥执行。
`GET /api/system/platform-catalog/platforms/{platform_id}/categories`
返回当前平台的全部树节点 `{ id, parent_id, external_category_id, external_type_id, name, path, is_active, synced_at, attribute_last_success_at, attribute_cache_status, attribute_last_error, attribute_last_error_at }`;按父子关系在客户端构建树,目录节点可展开,仅可发布类型叶子用于查看属性。纯目录节点的属性状态为 `null`;可发布类型状态为 `fresh | stale | expired | missing`。
`GET /api/system/platform-catalog/platforms/{platform_id}/refresh-policy`
返回平台目录刷新策略:
```json
{
"data": {
"attribute_fresh_days": 14,
"attribute_expire_days": 21,
"dictionary_fresh_days": 14,
"dictionary_expire_days": 21,
"updated_at": "2026-09-20T00:00:00Z"
}
}
```
尚未显式配置的平台返回相同默认值。类目树固定每 7 天同步,不属于可配置策略。
`PUT /api/system/platform-catalog/platforms/{platform_id}/refresh-policy`
Body 必须完整提交 `{ "attribute_fresh_days", "attribute_expire_days", "dictionary_fresh_days", "dictionary_expire_days" }`。四项均为 `1..365` 的整数,同类资源的 `expire_days` 必须严格大于 `fresh_days`。成功保存后立即影响后续状态判断,但不得因此主动扫描或创建属性/字典任务;服务端记录修改人和时间。
`GET /api/system/platform-catalog/platforms/{platform_id}/categories/{category_id}/attributes`
返回该类型的属性定义 `{ id, platform_attribute_id, complex_id, name, description, group_name, value_type, is_required, is_aspect, is_collection, max_value_count, dictionary_id, is_active, synced_at, last_success_at, cache_status, last_error_message, last_error_at, dictionary_last_success_at, dictionary_cache_status, dictionary_is_complete, dictionary_last_error_message, dictionary_last_error_at, dictionary_value_count }`。类型级 `last_success_at/cache_status` 会在该类型的每个属性行重复,便于管理页展示;没有任何属性行时应结合属性汇总或资源状态判断 missing。`category_id` 不属于所选平台时返回 404。
`GET /api/system/platform-catalog/platforms/{platform_id}/attributes/{attribute_id}/values?q={keyword}&page={number}`
仅字典属性可查;`page` 从 1 开始、每页最多 100,返回 `{ "data": [{ "id", "external_value_id", "value", "info", "picture" }], "meta": { "page", "page_size", "total", "is_complete" } }`。搜索只查 Atlas 缓存;`is_complete=false` 表示已缓存部分候选值,不表示 Ozon 字典只有这些值。
`POST /api/system/platform-catalog/platforms/{platform_id}/syncs`
Headers:`Idempotency-Key`(UUID)必填。Body:`{ "scope": "tree" | "attributes" | "dictionary", "category_id"?: "uuid", "attribute_id"?: "uuid" }`。树同步不带其他 ID;兼容的单类型属性同步需要当前平台的可发布 `category_id`;字典同步需要该类型下带字典的 `attribute_id`。同作用域已有 queued/running 任务时返回已有任务,并将本次幂等键持久映射到该任务;同一用户重试不会在原任务完成后意外创建第二个任务。成功排队返回 `202` 与 `{ "data": { "id", "platform_id", "scope", "status", "trigger", "priority", "created_at" } }`。同步由 Worker 异步执行,失败保留上次成功缓存。树任务优先级独立决定;属性和字典根据资源年龄选择 `low` 或 `high`,missing/严格超过过期阈值为 `high`。
`GET /api/system/platform-catalog/platforms/{platform_id}/attribute-sync-summary`
返回当前策略下活动可发布类型的聚合数量:
```json
{
"data": {
"total": 7365,
"fresh": 100,
"stale": 200,
"expired": 300,
"missing": 6765,
"active_batch_id": null,
"evaluated_at": "2026-09-20T00:00:00Z"
}
}
```
状态边界严格按平台策略和最近成功时间计算:`age < fresh_days` 为 fresh,`fresh_days ≤ age ≤ expire_days` 为 stale,`age > expire_days` 为 expired,从未成功为 missing。
`POST /api/system/platform-catalog/platforms/{platform_id}/attribute-sync-batches`
Headers:`Idempotency-Key`(UUID)必填。Body:
```json
{ "mode": "missing_expired" | "missing_stale_expired" | "all" }
```
- `missing_expired` 固定 missing、expired 类型快照;
- `missing_stale_expired` 固定 missing、stale、expired 类型快照;
- `all` 固定全部活动可发布类型快照,包含 fresh。
没有命中类型时返回 `422 CATALOG_ATTRIBUTE_BATCH_EMPTY`。同一平台已有 queued/running 批次时返回 `409 CATALOG_ATTRIBUTE_BATCH_ACTIVE` 和现有批次 ID,避免两个全量扫描互相竞争。成功返回 `202` 与批次 `{ id, platform_id, mode, status, total_count, pending_count, running_count, succeeded_count, failed_count, cancelled_count, created_at, started_at, completed_at }`。Worker 每分钟限量领取批次项;missing/expired 子任务为高优先级,fresh/stale 子任务为低优先级。批次创建后新增的类型不加入本批次。
`GET /api/system/platform-catalog/platforms/{platform_id}/attribute-sync-batches?limit={number}`
返回最近批次及实时聚合进度,最多 50 条。批次允许部分失败:任一子任务失败时最终状态为 `failed`,但成功类型继续保留且不会回滚。
`GET /api/system/platform-catalog/platforms/{platform_id}/attribute-sync-batches/{batch_id}`
返回单个批次的相同进度字段;批次不属于当前平台时返回 404。
`GET /api/system/platform-catalog/platforms/{platform_id}/syncs?limit={number}`
返回该平台最近的同步任务(最多 50 条),包括作用域、触发方式、状态、开始/完成时间、数量摘要及脱敏错误。系统管理员可据此查看手动和定时更新结果。
类目树调度固定为最近一次成功后 7 天。类型属性和属性字典没有周期性自动扫描;它们只由管理员操作、普通用户访问和发布预检创建任务。
## 管理页面交互
- 类目搜索框固定在树卡片顶部;搜索结果会展开到命中节点,普通目录节点可展开,只有活动的可发布类型可以选中查看属性。
- “缓存新鲜度设置”以操作区按钮打开弹窗,不在主页面常驻表单。保存成功后关闭弹窗并刷新策略、类目和当前属性状态;失败时保留弹窗及用户输入。
- “最近同步任务”的手动刷新按钮在请求期间显示 loading;成功显示 message,失败显示统一 API 错误。页面每 5 秒的自动轮询保持静默,不重复打扰管理员。
- 类型属性提供 missing+expired、missing+stale+expired 和全部三种批次按钮;全部同步使用红色危险按钮并二次确认。字典仍在选定属性后逐个手动同步。