docs(t215): freeze admin order authorization contract
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
---
|
||||
id: T-215
|
||||
title: Admin 候选确认与一次性下单授权
|
||||
phase: 2
|
||||
deps:
|
||||
- T-214
|
||||
status: DOING
|
||||
created: 2026-07-28
|
||||
context_ref: 56e7a2b
|
||||
work_branch: null
|
||||
write_paths:
|
||||
- docs/tasks/T-215.md
|
||||
- docs/00-ai-start-here.md
|
||||
- docs/02-requirements.md
|
||||
- docs/04-architecture.md
|
||||
- docs/06-tasks.md
|
||||
- docs/07-user-stories.md
|
||||
- docs/08-interaction-checklist.md
|
||||
- docs/api.md
|
||||
- docs/current-state.md
|
||||
- docs/routes.md
|
||||
- backend-api/migrations/**
|
||||
- backend-api/internal/domain/**
|
||||
- backend-api/internal/usecase/**
|
||||
- backend-api/internal/repository/sqlite/**
|
||||
- backend-api/internal/transport/httpapi/**
|
||||
- backend-api/internal/transport/webui/**
|
||||
---
|
||||
|
||||
## 问题 / 背景
|
||||
|
||||
T-214 已给每个候选建立 execution-scoped `candidate_key`,但任务仍由手机上的采购员
|
||||
提交 human review 并结束。新需求要求 Admin 采购员查看 Top 5 后选择商品,再把明确
|
||||
授权同步给同一台 Roubao 设备;候选列表或 URL 本身不能成为下单许可。
|
||||
|
||||
本任务实现后台选择、逐候选理由和不可变的一次性授权。它不实现设备拉取或拼多多
|
||||
点击;T-216 才把待投递授权转换为设备命令。
|
||||
|
||||
## 冻结合约
|
||||
|
||||
### 等待确认
|
||||
|
||||
1. 当前 execution 首次成功保存非空候选批次后,任务在同一事务从 `RUNNING` 进入
|
||||
`WAITING_CONFIRMATION`,增加 task version,并追加 `CANDIDATES_READY` 事件。
|
||||
2. 设备 heartbeat 在该状态继续有效,但不能凭候选回传重新开始页面动作。空候选
|
||||
仍允许现有 `NO_MATCH/MANUAL_REQUIRED` 终态,不创建授权。
|
||||
3. Admin 只能为当前活跃 execution、当前 task content hash 和 v7 identity 完整的
|
||||
observation 授权;取消已请求、授权到期、终态或旧 execution 一律拒绝。
|
||||
|
||||
### Admin 决策与授权
|
||||
|
||||
新增管理会话鉴权、CSRF/幂等保护的
|
||||
`POST /api/v1/tasks/{task_id}/order-authorizations`:
|
||||
|
||||
```json
|
||||
{
|
||||
"execution_id": "uuid",
|
||||
"task_content_sha256": "64-char-lowercase-hex",
|
||||
"expected_task_version": 4,
|
||||
"candidate_key": "64-char-lowercase-hex",
|
||||
"reason_schema_version": 1,
|
||||
"primary_reason_code": "SELECTED_BEST_MATCH",
|
||||
"note": "",
|
||||
"supersedes_authorization_id": null,
|
||||
"items": [
|
||||
{
|
||||
"candidate_key": "selected-key",
|
||||
"label": "ACCEPT",
|
||||
"primary_reason_code": "SKU_MATCH",
|
||||
"reason_codes": ["SKU_MATCH", "IMAGE_MATCH"],
|
||||
"note": ""
|
||||
},
|
||||
{
|
||||
"candidate_key": "rejected-key",
|
||||
"label": "REJECT",
|
||||
"primary_reason_code": "NOT_BEST_MATCH",
|
||||
"reason_codes": ["NOT_BEST_MATCH"],
|
||||
"note": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
1. `items` 必须按 candidate key 恰好覆盖当前 execution 的全部 observation,且只有
|
||||
顶层 `candidate_key` 对应项为 `ACCEPT`。理由沿用 T-208 schema v1 allowlist 和
|
||||
`OTHER` 备注规则;无预算任务仍禁止价格类理由。
|
||||
2. 仓储在一个 immediate transaction 内把 candidate key 映射回原 ordinal,追加一版
|
||||
`candidate_human_reviews`(`actor_device_id=NULL`),再创建一条不可变
|
||||
`order_authorizations`。不得信任请求传入的 ordinal、SKU、数量、价格或 URL。
|
||||
3. 授权快照由服务端读取:task/execution/content hash、candidate key、review ID/
|
||||
version、原始 SKU、任务数量、候选规格摘要、组合价格和四个身份指纹。数量只能来自
|
||||
原始任务,Admin 不能在选品表单中改写。
|
||||
4. 授权初始状态为 `PENDING_DELIVERY`,版本从 1 递增;同一 execution 同时最多一条
|
||||
active 授权。相同幂等键和请求返回原结果,不新增 review、授权或事件。
|
||||
5. 设备领取前允许 Admin 改选,但请求必须引用当前 active
|
||||
`supersedes_authorization_id`;旧授权原子变为 `SUPERSEDED`,review/授权历史均不
|
||||
覆盖。非当前引用、已投递或已执行授权拒绝修改。
|
||||
6. 每次创建或改选追加 `ORDER_AUTHORIZATION_CREATED` 任务事件,事件只记录授权 ID、
|
||||
版本和 candidate key 的短前缀,不记录第三方 URL 或页面全文。
|
||||
|
||||
### Admin API/Web
|
||||
|
||||
1. Admin 任务详情返回结构化 observations、当前/历史 review 和 order authorization,
|
||||
每项展示标题、SKU 摘要、组合价格、受控详情/规格截图、candidate key 和模型理由。
|
||||
2. `WAITING_CONFIRMATION` 且存在候选时显示单选候选、选择理由、对其余候选批量拒绝
|
||||
理由、可选备注和“确认商品并授权下单”按钮。表单服务端展开为逐候选 items。
|
||||
3. 页面必须明确“仅授权创建待付款订单,不授权付款”;没有可授权候选、数据版本冲突
|
||||
或已有不可修改授权时禁用提交并给出可操作状态。
|
||||
4. Admin API/Web 不请求第三方商品/图片 URL,也不提供由浏览器直接触发设备动作的
|
||||
通道。
|
||||
|
||||
## 数据模型
|
||||
|
||||
v8 新增:
|
||||
|
||||
- `order_authorizations`:授权 ID、task/execution、版本、candidate key、内容 hash、
|
||||
review、原始 SKU/数量、候选 SKU/价格、四个指纹、状态、创建人、时间和可空
|
||||
supersedes ID。
|
||||
- `admin_order_authorization_requests`:管理员、幂等键、请求 hash、task 和授权引用。
|
||||
|
||||
状态预留 `PENDING_DELIVERY/DELIVERED/ACKNOWLEDGED/EXECUTING/CONSUMED/FAILED/
|
||||
REVOKED/SUPERSEDED`;T-215 只产生 `PENDING_DELIVERY` 和 `SUPERSEDED`。存在授权数据
|
||||
时 v8 destructive down 必须失败。
|
||||
|
||||
## 验收要点
|
||||
|
||||
- [ ] 非空候选批次原子进入 `WAITING_CONFIRMATION`,重复回传不重复增加事件/version。
|
||||
- [ ] Admin 请求只用 candidate key,完整覆盖候选且每项接受/拒绝都有合法理由。
|
||||
- [ ] review、授权、旧授权 supersede、任务事件和幂等记录原子提交。
|
||||
- [ ] 跨任务/execution、旧 hash/version、伪造 key、缺 identity 和并发双授权被拒绝。
|
||||
- [ ] 授权数量/SKU/价格/指纹均由服务端快照,Admin 不能篡改。
|
||||
- [ ] Admin API/Web 可选候选、查看证据和理由,明确只创建待付款订单且不授权付款。
|
||||
- [ ] v8 migration、Go test/race/vet、根验证和管理页面桌面/移动视口通过。
|
||||
|
||||
## 边界
|
||||
|
||||
- 不让设备拉取或确认授权;属于 T-216。
|
||||
- 不重新打开拼多多、选择 SKU/数量或进入订单确认页;属于 T-217。
|
||||
- 不提交订单、读取订单号或付款;属于 T-218/T-219。
|
||||
- 不使用 URL、ordinal、模型推荐或旧手机 review 直接代替 Admin 明确授权。
|
||||
|
||||
## 执行记录
|
||||
|
||||
- 2026-07-28:T-214 实现提交 `56e7a2b` 后领取。决定复用
|
||||
`WAITING_CONFIRMATION`,并把 Admin review 与一次性授权放在同一事务;设备投递和
|
||||
页面动作继续保持为后续独立权限层。
|
||||
Reference in New Issue
Block a user