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

9.6 KiB
Raw Permalink Blame History

平台类目与属性管理 API

2026-09-18 新增契约,2026-09-20 增加平台刷新策略和类型属性批次。平台级目录供系统管理员维护,普通商品编辑器和首次发布预检也已切换到同一平台缓存;旧门店目录仅保留兼容/回滚。平台参考目录的归属见 platform-product-reference-catalog.md,新鲜度与优先级规则见 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 已被禁止修改该表:

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

返回平台目录刷新策略:

{
  "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

返回当前策略下活动可发布类型的聚合数量:

{
  "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:

{ "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 和全部三种批次按钮;全部同步使用红色危险按钮并二次确认。字典仍在选定属性后逐个手动同步。