2026-08-03 12:13:39 +08:00
|
|
|
|
# 架构设计
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
> 本文定义系统结构、职责、单趟采购流程、安全边界和数据模型。框架与运行命令见
|
|
|
|
|
|
> [技术栈](03-tech-stack.md),双端线协议以 [API 合约](api.md)为唯一权威。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
|
|
|
|
|
## 一、系统结构
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
2026-08-04 16:25:34 +08:00
|
|
|
|
人工填链接(MVP) Excel / ERP(V2)
|
|
|
|
|
|
│ │
|
|
|
|
|
|
└──────────────┬───────────────┘
|
|
|
|
|
|
v
|
2026-08-03 12:13:39 +08:00
|
|
|
|
┌─────────────────────────────────────────┐
|
2026-08-04 16:25:34 +08:00
|
|
|
|
│ 采购服务(admin/,Go) │
|
|
|
|
|
|
│ · 建单、查询、开始采购授权与任务状态 │
|
|
|
|
|
|
│ · 提交围栏、结果调和、内部证据与审计 │
|
|
|
|
|
|
│ · 服务端渲染管理页面 │
|
|
|
|
|
|
└───────────────────┬─────────────────────┘
|
|
|
|
|
|
│ HTTPS / JSON
|
|
|
|
|
|
│ Bearer + 设备绑定
|
|
|
|
|
|
v
|
2026-08-03 12:13:39 +08:00
|
|
|
|
┌─────────────────────────────────────────┐
|
2026-08-04 16:25:34 +08:00
|
|
|
|
│ 采购工具(client/,Python + PySide6) │
|
|
|
|
|
|
│ · 轮询领取、单趟执行、回传状态与证据 │
|
|
|
|
|
|
│ · 本地完整节点树与执行轨迹 │
|
|
|
|
|
|
└───────────────────┬─────────────────────┘
|
|
|
|
|
|
│ ADB(USB / WiFi)
|
|
|
|
|
|
v
|
|
|
|
|
|
Android 手机(拼多多 App)
|
2026-08-03 12:13:39 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
- 采购服务:Go + gin,SQLite,goose migration,本地 SHA-256 证据存储。
|
|
|
|
|
|
- 采购工具:Python + uiautomator2 + PySide6;执行器只依赖 `TaskSource` / `ResultSink` 抽象。
|
|
|
|
|
|
- 页面判据与拼多多 App 版本绑定;版本不同即停止,不把前序项目页面结构当作事实。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
|
|
|
|
|
## 二、职责划分
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
### 采购服务(`admin/`)
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
独占以下权威:
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
- 任务创建、批量开始采购、状态流转和终态判定;
|
|
|
|
|
|
- **一次性采购授权的签发**:管理员点击“开始采购”是唯一的人类授权动作;
|
|
|
|
|
|
- 任务不可变字段和最高总价校验;
|
|
|
|
|
|
- 提交订单前的原子围栏与点击后结果调和;
|
|
|
|
|
|
- 管理员会话、设备凭据、内部截图证据和审计记录。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
采购服务不连接手机、不发 ADB 命令、不解析拼多多页面,也不持有支付或 AI provider 凭据。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
### 采购工具(`client/`)
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
独占以下设备能力:
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
- ADB 连接、设备健康检查和已取证 App 版本校验;
|
|
|
|
|
|
- 打开商品、识别页面、精确选规格、设置数量、读取价格;
|
|
|
|
|
|
- 在满足全部门禁并取得服务端围栏后,精确点击一次“提交订单”;
|
|
|
|
|
|
- 截图、完整节点树和执行日志的本地采集,显式上传内部截图。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
采购工具不自行修改任务约束、不扩大金额上限、不领取 `DRAFT`,也不能签发授权。没有服务端
|
|
|
|
|
|
明确返回 `click_permitted=true` 时,任何本地判断都不能创建订单。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
|
|
|
|
|
### 权威冲突规则
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
服务端校验锁定的任务约束,客户端校验当前真机事实。任一端拒绝或两端摘要不一致,一律停止并
|
|
|
|
|
|
转人工;不能为了“继续跑”选择相信其中一端。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
## 三、单趟采购执行
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
MVP 只做任务自带商品链接的 A 路径。创建任务与开始采购分离,但管理员开始后不再插入试选确认:
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
|
|
|
|
|
```text
|
2026-08-04 16:25:34 +08:00
|
|
|
|
管理员创建 DRAFT
|
|
|
|
|
|
│
|
|
|
|
|
|
├─ 勾选 DRAFT,查看选中数与最高总额
|
|
|
|
|
|
└─ 点击“开始采购(只创建待付款订单)”
|
|
|
|
|
|
│ 同一事务:校验版本 + 创建一次性授权 + PENDING
|
|
|
|
|
|
v
|
|
|
|
|
|
采购工具领取授权任务
|
|
|
|
|
|
│ 1. 打开 canonical 商品链接
|
|
|
|
|
|
│ 2. 通过证据/版本绑定、精确唯一的受控入口打开规格面板
|
|
|
|
|
|
│ 3. 按维度精确选择并读回颜色、尺码
|
|
|
|
|
|
│ 4. 【闸门一】读 SKU 单价;单价×数量不得超过最高总价
|
|
|
|
|
|
│ 5. 设置数量并精确读回
|
|
|
|
|
|
│ 6. 【闸门二】重读规格与单价;规格不变且价格等于闸门一
|
|
|
|
|
|
│ 7. 进入订单确认页
|
|
|
|
|
|
│ 8. 【闸门三】规格/数量一致,应付总额不超最高总价
|
|
|
|
|
|
│ 9. 上传验证摘要并申请服务端提交围栏
|
|
|
|
|
|
│ 10. 仅在 click_permitted=true 且提交控件唯一时点击一次
|
|
|
|
|
|
│ 11. 回传观察结果;不确定时只调和,不重试
|
|
|
|
|
|
v
|
|
|
|
|
|
WAITING_PAYMENT ──人核对与付款──> SUCCEEDED
|
|
|
|
|
|
或
|
|
|
|
|
|
RECONCILIATION_REQUIRED ──人工核查同一提交──> WAITING_PAYMENT / FAILED
|
2026-08-03 12:13:39 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
“开始采购”锁定的是管理员填写的 `goods_id`、颜色、尺码、数量和**最高总价**,不是一张旧页面
|
|
|
|
|
|
截图里观察到的价格。价格在执行时实时读取,因此取消试选确认不会取消价格保护。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
### 受控规格面板入口
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
T-103 真机证据表明:拼多多 `8.17.0`、goods_id `937122477375` 通过精确文本“快要抢光”打开
|
|
|
|
|
|
规格面板。T-110 已批准把该**特定证据、版本和页面状态**绑定的点击定义为受控导航。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
- 只能精确唯一匹配;缺失、重复、版本失配或打开后面板不唯一时零后续点击。
|
|
|
|
|
|
- “免拼购买 / 单独购买 / 直接拼成”等其他文案不能用包含、前缀、同义或坐标兜底。
|
|
|
|
|
|
- 受控入口只负责进入已取证面板,不等于支付授权,也不能暴露通用任意点击能力。
|
|
|
|
|
|
- T-103 的隔离验证 capability 只包含开商品、开面板、选规格、读价和安全退出;数量、确认页、
|
|
|
|
|
|
提交和支付仍由后续真机任务分别取证后才能接入生产单趟执行器。
|
2026-08-04 10:59:40 +08:00
|
|
|
|
|
2026-08-03 12:13:39 +08:00
|
|
|
|
### 三道价格闸门
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
| 闸门 | 当前页面 | 判据 | 拒绝条件 |
|
2026-08-03 12:13:39 +08:00
|
|
|
|
| --- | --- | --- | --- |
|
2026-08-04 16:25:34 +08:00
|
|
|
|
| 一 | 规格面板,选中目标规格后 | 单价唯一可读;`单价 × 授权数量 <= 最高总价` | 不可读、有歧义或超上限 |
|
|
|
|
|
|
| 二 | 规格面板,数量读回后 | 颜色、尺码仍正确;重读单价与闸门一完全相等 | 规格漂移或价格变化 |
|
|
|
|
|
|
| 三 | 订单确认页 | 规格、数量正确;应付总额唯一可读且不超最高总价 | 任一不一致、不可读或超上限 |
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
金额一律使用十进制字符串和十进制定点运算,不用浮点数。价格只从规格面板和订单确认页读取;
|
|
|
|
|
|
详情正文、搜索卡片、底部购买/提交按钮的数字不作为价格来源。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
闸门一与闸门二发生在同一设备会话中。它们用于发现选择或设置数量造成的页面变化,不需要管理员
|
|
|
|
|
|
在中间确认。旧截图、缓存值和发布前 dry-run 都不能替代这次实时读取。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
### B 路径(V2)
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
没有商品链接时由图片搜索只产出 `goods_id`,再汇入上述流程。不在搜索结果页读取价格或规格。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
|
|
|
|
|
## 四、安全边界(硬约束)
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
以下每条都必须有测试证明,不得在任务中顺手放宽:
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
| 边界 | 规则 | 防止什么 |
|
2026-08-03 12:13:39 +08:00
|
|
|
|
| --- | --- | --- |
|
2026-08-04 16:25:34 +08:00
|
|
|
|
| 不付款 | 不点击支付、免密支付、先用后付或任何扣款控件 | 真实资金损失 |
|
|
|
|
|
|
| 提交四条件 | 授权+围栏、闸门二、闸门三、控件唯一同时成立,只点一次 | 误下单 / 重复下单 |
|
|
|
|
|
|
| 确认页零点击 | 除返回和满足四条件后的“提交订单”外不点击任何控件 | 未知副作用 |
|
|
|
|
|
|
| 规格精确匹配 | 维度内等值唯一匹配,防 `红/粉红`、`1/10` 前缀碰撞 | 买错规格 |
|
|
|
|
|
|
| 数量读回复核 | 设置后精确读回,不一致即停 | 买错数量 |
|
|
|
|
|
|
| 三道价格闸门 | 任一道不可读、有歧义或不通过都停,不用别处数字凑 | 超预算 |
|
|
|
|
|
|
| 受控页面能力 | 页面动作按任务与证据分层;不得把通用 `click` 传入业务流程 | 边界扩散 |
|
|
|
|
|
|
| 外部支付页 | 检测到外部支付交接立即停止,不读取、保存或输入凭据 | 凭据泄露 |
|
|
|
|
|
|
| 安全校验 | 验证码、风控、人脸、短信出现即停止,不绕过 | 封号 / 违规 |
|
|
|
|
|
|
| 内部截图 | 可上传页面已显示的地址/手机号;不解析成字段或日志,完整 XML 不上传 | 非必要扩散 |
|
|
|
|
|
|
| 授权一次性 | 一条任务版本只有一份有效授权;幂等重放不生成第二份 | 重复采购 |
|
|
|
|
|
|
| 服务端提交围栏 | 点击前原子创建唯一提交记录;失败或响应不明不得点击 | 并发 / 断网重复下单 |
|
|
|
|
|
|
| App 版本绑定 | 运行版本不同于证据版本时停止并重新取证 | 旧判据误点 |
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
|
|
|
|
|
### 提交订单的四个前置条件
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
“提交订单”是系统唯一会创建真实待付款订单的动作。以下四项同时满足才允许点击一次:
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
1. **一次性授权有效且服务端提交围栏已建立**:围栏把授权、任务、领取和本次验证摘要原子绑定到
|
|
|
|
|
|
唯一 `order_submission`;明确响应包含 `click_permitted=true`。
|
|
|
|
|
|
2. **闸门二通过**:目标规格未漂移,第二次规格面板单价等于第一次。
|
|
|
|
|
|
3. **闸门三通过**:确认页规格、数量正确,应付总额不超过授权最高总价。
|
|
|
|
|
|
4. **提交控件唯一**:文本精确等于“提交订单”,可点击祖先唯一。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
围栏请求超时、断网、冲突或响应不明时不得点击。围栏建立后:
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
| 观察结果 | 处置 |
|
2026-08-03 12:13:39 +08:00
|
|
|
|
| --- | --- |
|
2026-08-04 16:25:34 +08:00
|
|
|
|
| 明确进入订单结果 / 待付款页 | 上报 `SUBMITTED`,任务转 `WAITING_PAYMENT` |
|
|
|
|
|
|
| 跳转外部支付 | 立即停止,上报结果不明确,不执行支付 |
|
|
|
|
|
|
| 出现验证码 / 风控 / 人脸 / 短信 | 立即停止,上报结果不明确,不绕过 |
|
|
|
|
|
|
| 超时、断连、页面无法判定 | 转 `RECONCILIATION_REQUIRED`,保留围栏和金额额度 |
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
后三种情况都禁止释放围栏、重新授权、重新领取或再次点击。只能调和同一提交记录。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
### 发布前 dry-run 与生产围栏的区别
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
首次启用某一 App 版本的真实提交能力前,必须用独立真机任务完成只读 dry-run:进入确认页,验证
|
|
|
|
|
|
规格、数量、金额与提交控件唯一,然后退出且不点击。它用于证明判据和不可达测试,不是每笔采购的
|
|
|
|
|
|
“第一趟”,也不产生可复用页面事实。生产任务仍在同一趟内重新通过三道闸门并申请服务端围栏。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
|
|
|
|
|
## 五、数据模型
|
|
|
|
|
|
|
|
|
|
|
|
### 5.1 核心实体
|
|
|
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
|
CREATE TABLE tasks (
|
|
|
|
|
|
id TEXT PRIMARY KEY,
|
2026-08-04 16:25:34 +08:00
|
|
|
|
source TEXT NOT NULL, -- MANUAL | EXCEL | ERP
|
|
|
|
|
|
source_ref TEXT,
|
|
|
|
|
|
title TEXT NOT NULL,
|
|
|
|
|
|
goods_id TEXT NOT NULL,
|
|
|
|
|
|
sku_color TEXT NOT NULL,
|
|
|
|
|
|
sku_size TEXT NOT NULL,
|
|
|
|
|
|
quantity INTEGER NOT NULL CHECK (quantity > 0),
|
|
|
|
|
|
max_total_price TEXT NOT NULL, -- 十进制字符串
|
|
|
|
|
|
reference_asset_id TEXT,
|
|
|
|
|
|
status TEXT NOT NULL,
|
|
|
|
|
|
version INTEGER NOT NULL DEFAULT 1,
|
2026-08-03 12:13:39 +08:00
|
|
|
|
created_at TEXT NOT NULL,
|
2026-08-04 16:25:34 +08:00
|
|
|
|
updated_at TEXT NOT NULL
|
2026-08-03 12:13:39 +08:00
|
|
|
|
);
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
-- 管理员点击“开始采购”产生;锁定任务约束,不锁定旧观察价
|
2026-08-03 12:13:39 +08:00
|
|
|
|
CREATE TABLE order_authorizations (
|
|
|
|
|
|
id TEXT PRIMARY KEY,
|
|
|
|
|
|
task_id TEXT NOT NULL REFERENCES tasks(id),
|
2026-08-04 16:25:34 +08:00
|
|
|
|
task_version INTEGER NOT NULL,
|
|
|
|
|
|
start_key TEXT NOT NULL,
|
2026-08-03 12:13:39 +08:00
|
|
|
|
goods_id TEXT NOT NULL,
|
|
|
|
|
|
sku_color TEXT NOT NULL,
|
|
|
|
|
|
sku_size TEXT NOT NULL,
|
|
|
|
|
|
quantity INTEGER NOT NULL,
|
2026-08-04 16:25:34 +08:00
|
|
|
|
total_price_cap TEXT NOT NULL,
|
|
|
|
|
|
status TEXT NOT NULL, -- ACTIVE | CLAIMED | FENCED | CONSUMED | EXPIRED | ABANDONED
|
2026-08-03 12:13:39 +08:00
|
|
|
|
created_by TEXT NOT NULL,
|
|
|
|
|
|
created_at TEXT NOT NULL,
|
2026-08-04 16:25:34 +08:00
|
|
|
|
expires_at TEXT NOT NULL,
|
|
|
|
|
|
UNIQUE (task_id, task_version),
|
|
|
|
|
|
UNIQUE (start_key, task_id)
|
2026-08-03 12:13:39 +08:00
|
|
|
|
);
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
-- 一次领取产生一条可恢复执行;保存步骤摘要,不接收完整 XML
|
|
|
|
|
|
CREATE TABLE purchase_attempts (
|
|
|
|
|
|
id TEXT PRIMARY KEY,
|
|
|
|
|
|
task_id TEXT NOT NULL REFERENCES tasks(id),
|
|
|
|
|
|
authorization_id TEXT NOT NULL REFERENCES order_authorizations(id),
|
|
|
|
|
|
claim_generation INTEGER NOT NULL,
|
|
|
|
|
|
status TEXT NOT NULL,
|
|
|
|
|
|
gate1_unit_price TEXT,
|
|
|
|
|
|
gate2_unit_price TEXT,
|
|
|
|
|
|
quantity_read INTEGER,
|
|
|
|
|
|
confirm_amount TEXT,
|
|
|
|
|
|
failure_code TEXT,
|
|
|
|
|
|
started_at TEXT NOT NULL,
|
|
|
|
|
|
finished_at TEXT,
|
|
|
|
|
|
UNIQUE (task_id, claim_generation)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
-- 真机真实点击前建立;一份授权最多一条
|
2026-08-03 12:13:39 +08:00
|
|
|
|
CREATE TABLE order_submissions (
|
|
|
|
|
|
id TEXT PRIMARY KEY,
|
|
|
|
|
|
task_id TEXT NOT NULL REFERENCES tasks(id),
|
|
|
|
|
|
authorization_id TEXT NOT NULL REFERENCES order_authorizations(id),
|
2026-08-04 16:25:34 +08:00
|
|
|
|
attempt_id TEXT NOT NULL REFERENCES purchase_attempts(id),
|
|
|
|
|
|
status TEXT NOT NULL, -- FENCED | SUBMITTED | RECONCILIATION_REQUIRED | MANUAL_RESOLVED
|
|
|
|
|
|
gate1_unit_price TEXT NOT NULL,
|
|
|
|
|
|
gate2_unit_price TEXT NOT NULL,
|
|
|
|
|
|
quantity_read INTEGER NOT NULL,
|
|
|
|
|
|
confirm_amount TEXT NOT NULL,
|
|
|
|
|
|
created_at TEXT NOT NULL,
|
|
|
|
|
|
resolved_at TEXT,
|
2026-08-03 12:13:39 +08:00
|
|
|
|
UNIQUE (authorization_id),
|
2026-08-04 16:25:34 +08:00
|
|
|
|
UNIQUE (attempt_id)
|
2026-08-03 12:13:39 +08:00
|
|
|
|
);
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
MVP 不再用 `spec_trials` 作为审批记录,也不存在 `authorized_unit_price`。实际读价属于
|
|
|
|
|
|
`purchase_attempts` / `order_submissions` 的执行与审计事实;管理员授权的资金边界始终是
|
|
|
|
|
|
`total_price_cap`。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
|
|
|
|
|
### 5.2 状态机
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
2026-08-04 16:25:34 +08:00
|
|
|
|
DRAFT
|
|
|
|
|
|
└─开始采购(创建授权)→ PENDING
|
|
|
|
|
|
└─claim→ CLAIMED ─start→ ORDERING
|
|
|
|
|
|
├─围栏前验证失败→ NEEDS_MANUAL ─人工处理/重置→ DRAFT
|
|
|
|
|
|
├─围栏前授权过期/安全释放→ DRAFT
|
|
|
|
|
|
└─submission FENCED
|
|
|
|
|
|
├─明确创建→ WAITING_PAYMENT ─人工付款并标记→ SUCCEEDED
|
|
|
|
|
|
└─结果不明→ RECONCILIATION_REQUIRED
|
|
|
|
|
|
└─人工调和同一提交→ WAITING_PAYMENT / FAILED
|
|
|
|
|
|
|
|
|
|
|
|
DRAFT / PENDING / NEEDS_MANUAL ─管理员取消(围栏前)→ CANCELED
|
2026-08-03 12:13:39 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
| 状态 | 含义与安全下一步 |
|
2026-08-03 12:13:39 +08:00
|
|
|
|
| --- | --- |
|
2026-08-04 16:25:34 +08:00
|
|
|
|
| `DRAFT` | 已保存,未授权;管理员可编辑/取消或点击开始采购;设备不可领取 |
|
|
|
|
|
|
| `PENDING` | 已有有效一次性授权,等待采购工具领取 |
|
|
|
|
|
|
| `CLAIMED` | 已由一个设备实例持有租约,尚未开始页面操作 |
|
|
|
|
|
|
| `ORDERING` | 单趟执行中,正在选规格、过闸门或申请围栏 |
|
|
|
|
|
|
| `NEEDS_MANUAL` | 围栏前失败;显示原因,由人核查后重置为 DRAFT 或取消 |
|
|
|
|
|
|
| `WAITING_PAYMENT` | 订单已明确创建,等待人在拼多多付款;**不是成功** |
|
|
|
|
|
|
| `RECONCILIATION_REQUIRED` | 围栏后结果不明;只能核查同一提交,不能重试 |
|
|
|
|
|
|
| `SUCCEEDED` | 人已付款并完成核对 |
|
|
|
|
|
|
| `FAILED` | 人工调和确认订单未创建或任务无法完成 |
|
|
|
|
|
|
| `CANCELED` | 围栏前由管理员取消,不再执行 |
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
批量 `DRAFT → PENDING` 必须全有或全无。服务端同时创建授权;“先改状态、稍后补授权”无效。
|
|
|
|
|
|
`WAITING_CONFIRMATION`、`PENDING_RETRIAL`、`AUTHORIZED` 和 `RUNNING(TRIAL)` 不再属于 MVP 状态。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
### 5.3 授权、租约与恢复
|
2026-08-03 15:00:49 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
- 授权带 `expires_at`,只有围栏前可转 `EXPIRED` / `ABANDONED`;任务回到 `DRAFT`,必须重新点击
|
|
|
|
|
|
开始采购。旧授权永不复活。
|
|
|
|
|
|
- 设备租约丢失不等于授权可安全重用。只有服务端确认该 attempt 未建立围栏,才能关闭 attempt 并
|
|
|
|
|
|
回到 `DRAFT` / `NEEDS_MANUAL`;不能自动重新领取并重复页面动作。
|
|
|
|
|
|
- 围栏建立后即使租约过期也只恢复同一 `order_submission` 的调和,不能回到可领取队列。
|
|
|
|
|
|
- 每种非终态都必须给出安全下一步,不能出现隐藏表单导致任务永久锁死。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
|
|
|
|
|
### 5.4 证据分层
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
| 数据 | 位置 | 边界 |
|
2026-08-03 12:13:39 +08:00
|
|
|
|
| --- | --- | --- |
|
2026-08-04 16:25:34 +08:00
|
|
|
|
| 商品 / 规格 / 确认页原始 screenshot | 采购工具本机 + 采购服务内部证据存储 | 可含页面已显示地址/手机号;设备鉴权上传、管理员登录查看,不遮罩 |
|
|
|
|
|
|
| 完整 XML | 仅采购工具本机隔离目录 | 可在内存解析页面判据;不上传、不写日志、Git、Vikunja |
|
|
|
|
|
|
| 最小 XML fixture | 采购工具测试 / Git | 只保留判据所需结构,确认无地址、手机号、支付凭据 |
|
|
|
|
|
|
| 外部支付页或支付凭据 | 不保存、不上传 | 检测到交接立即停止 |
|
|
|
|
|
|
| AI 调用记录(V2) | 仅采购工具本地 | 不进入采购服务 |
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
截图上传器只能接收调用方显式指定的截图,不能枚举证据目录或顺带上传 XML/manifest。证据响应
|
|
|
|
|
|
使用 `Cache-Control: no-store`,不能暴露为免登录静态目录。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
|
|
|
|
|
## 六、关键技术难点
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
| 难点 | 风险 | 应对 |
|
2026-08-03 12:13:39 +08:00
|
|
|
|
| --- | --- | --- |
|
2026-08-04 16:25:34 +08:00
|
|
|
|
| 页面结构随版本变化 | 旧选择器误点新页面 | 每条判据先真机取证,记录 App 版本、截图、XML、goods_id |
|
|
|
|
|
|
| 购买语义入口才打开面板 | 能力范围易扩散 | 只批准证据绑定的精确唯一入口;每种文案单独取证 |
|
|
|
|
|
|
| 当前价与原价/按钮价混杂 | 读错价格 | 限定已取证结构和语义;价格只在面板/确认页读,歧义即停 |
|
|
|
|
|
|
| 单趟页面状态变化 | 数量或促销导致价格变化 | 同一趟两次读规格面板价,再以确认页总额兜底 |
|
|
|
|
|
|
| WiFi ADB / 双通道 | 断连或操作错设备 | serial 必填;USB/WiFi 同设备或身份不明时 fail closed |
|
|
|
|
|
|
| 不可逆动作超时 | 可能已创建订单 | 服务端围栏 + 点击一次 + 只调和,不重试 |
|
|
|
|
|
|
| 双端契约漂移 | 静默不兼容 | [api.md](api.md) 唯一权威;契约改动跑完整双端门禁 |
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
|
|
|
|
|
## 七、推荐开发顺序
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
1. **Phase 0 地基**:双端骨架、测试命令、初始化脚本和原型。
|
|
|
|
|
|
2. **Phase 1 真机取证**:逐段验证商品打开、受控面板入口、精确规格与读价、数量、确认页和提交
|
|
|
|
|
|
控件;真实点击前先完成独立 dry-run。每个 spike 的 capability 只覆盖当期动作。
|
|
|
|
|
|
3. **Phase 2 采购服务核心**:DRAFT 建单/列表、批量开始采购与授权、状态/证据/围栏/调和接口。
|
|
|
|
|
|
4. **Phase 3 双端打通**:设备身份、原子领取、单趟执行到围栏前、事件与截图。
|
|
|
|
|
|
5. **Phase 4 闭环**:经明确真机授权验证一次提交、待付款收口、失败分类、打包。
|
|
|
|
|
|
6. **V2**:图搜、Excel、ERP、自动核对、AI、多设备。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
T-103 继续作为“规格选择与读价”的隔离前置,不含数量、确认页或提交。生产单趟并不意味着在一个
|
|
|
|
|
|
任务里跳过逐段取证;它只意味着这些已验证能力集成后,每笔业务任务不再等待中途人工确认。
|
2026-08-04 10:42:28 +08:00
|
|
|
|
|
2026-08-03 12:13:39 +08:00
|
|
|
|
## 八、项目结构
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
cmbuyer/
|
|
|
|
|
|
├── docs/
|
2026-08-04 16:25:34 +08:00
|
|
|
|
├── admin/
|
2026-08-03 12:13:39 +08:00
|
|
|
|
│ ├── cmd/server/
|
2026-08-04 16:25:34 +08:00
|
|
|
|
│ ├── internal/domain/
|
|
|
|
|
|
│ ├── internal/usecase/
|
|
|
|
|
|
│ ├── internal/transport/httpapi/
|
|
|
|
|
|
│ ├── internal/transport/webui/
|
|
|
|
|
|
│ ├── internal/storage/
|
2026-08-03 12:13:39 +08:00
|
|
|
|
│ └── migrations/
|
2026-08-04 16:25:34 +08:00
|
|
|
|
├── client/
|
|
|
|
|
|
│ ├── src/cmbuyer_client/device/
|
|
|
|
|
|
│ ├── src/cmbuyer_client/pdd/
|
|
|
|
|
|
│ ├── src/cmbuyer_client/core/
|
|
|
|
|
|
│ ├── src/cmbuyer_client/remote/
|
|
|
|
|
|
│ ├── src/cmbuyer_client/app/
|
2026-08-03 12:13:39 +08:00
|
|
|
|
│ └── tests/
|
|
|
|
|
|
└── scripts/
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
执行器依赖 `TaskSource` / `ResultSink`,不直接读取 Excel 或拼接 HTTP。来源变化不得改变安全执行器。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
|
|
|
|
|
## 九、架构纪律
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
- 业务事实和 schema 变化同步本文与 [api.md](api.md),代码不得另起一套字段或状态。
|
|
|
|
|
|
- 第四节安全边界只能收紧。需要变更时先更新架构、任务边界和理由。
|
|
|
|
|
|
- 页面高风险能力先真机取证并隔离测试,再接入完整流程。
|
|
|
|
|
|
- 前序项目 `cmroubao` / `cmpdd` 只提供设计理由,不提供可直接复用的页面事实。
|