docs: define idempotent Client registration contract (#12)

This commit is contained in:
chengma
2026-08-06 17:21:36 +08:00
parent 62d46bf10a
commit 02073eab37
8 changed files with 306 additions and 206 deletions
+39 -10
View File
@@ -8,9 +8,10 @@
本文档中 `[必须]` / `[建议]` / `[待定]` 的含义见 [文档索引](../README.md#文档标注说明)。
## 1. 一共只有三个接口
## 1. 一共四个接口
```http
PUT /api/v1/client/registration 登记或更新 Client
POST /api/v1/client/tasks/claim 领一个任务
POST /api/v1/client/tasks/{task_id}/result 提交成功结果
POST /api/v1/client/tasks/{task_id}/failure 提交失败/需人工
@@ -20,6 +21,31 @@ POST /api/v1/client/tasks/{task_id}/failure 提交失败/需人工
理由见 Client 契约 §1.1:本项目人工付款,重复下单只产生重复的**未付款**订单,
不值得为它引入一整套中断逻辑。
### 1.1 独立登记接口
设置页保存当前设备时调用:
```http
PUT /api/v1/client/registration
X-Client-Id: <stable-client-id>
```
请求体与 claim 的 Client、设备和能力部分相同。相同 `X-Client-Id` 重复调用执行 upsert,统一返回 `200 OK`:
```json
{
"registered": true,
"client_id": "CLIENT-123456",
"registered_at": "2026-08-06T09:00:00Z"
}
```
`[必须]` 本接口只登记 Client,不查询、领取或修改任务,也不返回任务。
`[必须]` 显式登记携带非空名称时允许更新名称;空名称更新保留现有名称,新建时使用 Client ID 兜底。设备、能力、`last_seen_at` 和 `updated_at` 正常更新。
`[必须]` 校验 `client.name` 最多 50 字、任务类型、执行模式和结构版本。错误使用统一 JSON 结构,至少覆盖 `MISSING_CLIENT_ID`、`INVALID_BODY`、`INVALID_CLIENT_PROFILE` 和 `CLIENT_REGISTER_FAILED`。
## 2. 领取任务
```http
@@ -76,11 +102,11 @@ WHERE task_id = ? AND status = 'assigned';
这些在建任务时就该校验住(见 [01 需求](01-requirements.md) §5),
不要等到这里才发现发不出去。
## 3. 客户端注册就在领取里做
## 3. claim 保留隐式登记作为兼容兜底
`[必须]` **不设单独的注册接口,也不设心跳接口。**
`[必须]` **有独立登记接口,但不设心跳接口。**
`claim` 请求里已经带齐了初始化需要的东西:
旧 Client 可能直接调用 `claim`,其请求里已经带齐初始化需要的信息:
```http
X-Client-Id: client-001 ← 序列号,主键
@@ -96,14 +122,14 @@ X-Client-Id: client-001 ← 序列号,主键
}
```
> **已定案:** `client.name` 是对 Client 契约 §5 的一处小扩展。
> **已定案:** `client.name` 同时用于显式登记和 claim 兼容登记。
> Client 的设置页本来就有「设备名」输入框(`deviceNameInput`,50 字上限),
> 把它带上即可。**Admin 仍然容忍它缺失**——没有就用 `X-Client-Id` 当显示名,
> 所以 Client 先不发也不影响登记。
> 显式登记会更新非空名称;claim 对已有 Client 不覆盖名称。
> Admin 容忍名称缺失,新建时用 `X-Client-Id` 当显示名。
>
> 登记流程的完整说明见 [07 设备登记联调手册](07-设备登记联调手册.md)。
处理:
claim 的兼容登记处理:
```text
upsert clients:
@@ -122,8 +148,7 @@ upsert clients:
`[必须]` `result` 和 `failure` 接口**也要刷新 `last_seen_at`**。
否则客户端执行长任务期间不调 claim,会被误判成离线。
**新客户端第一次来必然拿不到任务**(还没人给它分配),返回 `204` 是正常的。
它这时已经登记进列表了,操作员就能给它分配任务。
新客户端直接调用 claim 时,`204` 是正常的无任务结果,Client 必须正常处理;如果已经预先分配任务,也可能首次调用就返回 `200`。
## 4. 提交结果
@@ -231,6 +256,10 @@ MVP 阶段只在内网/本机运行。
Client 契约里散落的 Admin 侧硬要求,汇总在这里,**可以直接当验收标准用**:
- [ ] `PUT /registration` 相同 Client ID 幂等 upsert,不创建重复记录
- [ ] 登记接口不读取、领取或修改任务
- [ ] 显式登记更新非空名称,空名称更新保留已有名称
- [ ] 登记接口校验名称、任务类型、执行模式和结构版本
- [ ] `claim` 一次只返回一个任务,且只返回分配给该客户端的
- [ ] `claim` 原子完成,并发下不会把同一任务发给两个客户端
- [ ] `claim` 无任务时返回 `204`,不是 `200` 加空对象