# 平台类目与属性管理 API > 2026-09-18 新增契约。平台级目录供系统管理员维护;普通商品编辑器现有门店级 API 暂不改变。平台参考目录的归属见 [`platform-product-reference-catalog.md`](../architecture/platform-product-reference-catalog.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", "last_error" } }] }`。`client_id_hint` 仅为脱敏末尾字符,不返回 API Key、密文或指纹。 `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 }`;按父子关系在客户端构建树,目录节点可展开,仅可发布类型叶子用于查看属性。 `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, dictionary_value_count }`。`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", "created_at" } }`。同步由 Worker 异步执行,失败保留上次成功缓存。 `GET /api/system/platform-catalog/platforms/{platform_id}/syncs?limit={number}` 返回该平台最近的同步任务(最多 50 条),包括作用域、触发方式、状态、开始/完成时间、数量摘要及脱敏错误。系统管理员可据此查看手动和定时更新结果。