Files
cmautobuy/docs/client/01-requirements.md
T

246 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 01 Client 产品需求基线
- 文档状态:基线草案,待需求评审
- 适用范围:`client/`
- 产品类型:Windows 桌面自动化客户端
本文档中 `[必须]` / `[建议]` / `[待定]` 的含义见 [文档索引](../README.md#文档标注说明)。没有标注的默认是 `[必须]`。看不懂的词查 [术语表](00-glossary.md)。
## 1. 背景与目标
Client 从 Admin 获取拼多多任务,在一台已授权的 Android 设备上通过 uiautomator2 执行商品数据采集或采购操作,并将结果可靠地提交回 Admin。
产品目标:
1. 在统一界面中查看、搜索和跟踪**本机已领取**的全部 PDD 任务(含正在做的和做完的)。
2. 自动领取并串行执行采集任务和采购任务。
3. 在 Admin 或网络暂时不可用时保存结果并安全重试,不能丢失采集结果或重复采购。
4. 为失败、异常页面和不确定订单提供可诊断、可恢复的人工处理入口。
5. 在 Admin 尚未完成时,通过本地模拟接口完成大部分 Client 开发和测试。
## 2. 用户与外部系统
- **操作人员:**配置 Admin 和 Android 设备,启动或停止自动获取任务,查看状态和详情,处理异常。
- **Admin:**创建任务、分配任务、维护任务状态,并接收 Client 执行结果。
- **Android 设备:**登录并运行拼多多应用,由 Client 独占一个自动化执行会话。
- **拼多多应用:**被自动化操作的外部系统,不属于本项目控制范围。
## 3. 产品范围
Client 顶级导航仅包含:
1. **PDD 任务**:本机已领取任务的展示、搜索、自动执行和详情查看。
2. **设置**:Admin、Android 设备、自动化、安全和诊断设置。
设备连接不作为独立顶级模块,统一放入设置页。
**Client 不显示 Admin 任务池。** 本地只保存本机已领取的任务(含执行中和已完成),
不缓存"待领取"的任务。要拿新任务只有一条路——由任务引擎向 Admin 领取。
操作人员想知道队列里还有多少活没派下来,去 Admin 自己的界面看。
这条决定的完整理由见 [03 数据模型](03-data-model.md) §3.1。
## 4. 任务类型
### 4.1 采集任务
输入至少包含远程任务编号和商品链接。Client 应采集:
- 商品编号、商品链接和商品标题;
- 店铺名称(无障碍树未提供时允许留空并保存诊断证据);
- 已拼数量及原始显示文字;
- 评价数量及原始显示文字(当前首页未提供时允许留空,不能为此反复滚动并阻塞规格采集);
- 所有规格维度及其可见值;
- 每个规格组合对应的价格、币种和可用状态;
- 采集时间、设备及必要诊断产物引用。
颜色、尺码和价格不能只保存为互不关联的列表,必须以 SKU 规格组合保存价格关系。对于“1.2 万+”等近似数值,同时保存规范化数值、原始文字和近似标记。
### 4.2 采购任务
输入至少包含:
- 远程任务编号;
- 商品编号或商品链接;
- 目标颜色和尺码;
- 采购数量;
- 预期价格或最高允许价格;
- 任务版本及幂等信息。
Client 应执行:
1. 校验商品、规格、数量、库存和价格保护条件。
2. 选择指定颜色、尺码和数量。
3. 进入订单提交前状态并再次校验价格。
4. 在允许真实下单时提交订单。
5. 获取并核对订单编号和下单时间。
6. 保存本地结果并提交 Admin。
仅凭“我的订单”列表中的最新一条记录不能认定为当前任务订单。必须结合任务开始时间、商品、规格、数量和金额核对;存在多个候选时进入人工处理状态,不得猜测或重新下单。
## 5. PDD 任务页需求
页面分为三个稳定区域。
### 5.1 顶部命令区
- “获取任务”是持续任务引擎的主操作,启动后按钮文字切换为“停止获取”。
- 停止只停止领取新任务;当前任务应运行到安全停止点。
- 搜索条件至少支持任务类型、任务状态和关键词。
- 关键词搜索任务编号、商品编号和商品标题。
- “搜索”只查询本地数据库,不触发任务执行。
### 5.2 中部任务表格
表格显示的是**本机已领取的全部任务**,包括正在做的和早已做完的。已完成的任务永久保留,不会被清理。
表格要让操作人员一眼看出:这是什么任务、买的什么、什么规格、多少钱、现在到哪一步了。
**具体列有哪些、每列怎么显示,以 [05 界面交互规范](05-ui-specification.md) §5.1 为准**(那是唯一权威定义,改列只改那一处)。
本文只规定不可动摇的业务要求:
- 默认按 `updated_at DESC, id DESC` 稳定排序。
- 所有任务可通过增量加载访问,禁止为每个单元格创建常驻复杂控件。
- `pdd_data` 是详情数据,不作为隐藏表格列整体加载;表格模型只保留稳定任务编号,查看详情时从数据库读取。
- 单击行只选择,双击、Enter 或“详情”打开任务详情。
### 5.3 底部状态区
持续显示:
- 自动获取是否开启;
- 当前任务编号和类型;
- 当前执行步骤;
- 最近一次领取到任务的时间;
- 最近一次成功或可恢复错误摘要。
重要错误应同时使用持久信息条提供重试或进入设置的入口,不能只依赖自动消失提示。
## 6. 设置页需求
设置分为以下组:
1. **Admin:**服务地址、Client 编号、认证状态、请求超时和测试连接。
2. **Android 设备:**ADB 地址、拼多多包名、设备测试连接。
3. **自动化:**轮询周期、任务超时、最大重试次数和演练模式。
4. **安全与诊断:**价格允许偏差、最大购买数量、日志目录、截图/XML 保留周期。
密码和访问令牌不得以明文写入普通 SQLite 设置或日志。
## 7. 任务状态
任务共有 8 个标准状态:`claimed`、`running`、`result_pending`、`retry_wait`、`manual_review`、`succeeded`、`failed`、`cancelled`。
没有"待领取"状态——任务在领取成功那一刻才写进本地库,见 [03 数据模型](03-data-model.md) §3.1。
**每个状态的中文显示、含义和允许的转换,以 [03 数据模型](03-data-model.md) §7 为准**(那是唯一权威定义,写代码和写测试都看那一张表)。
本文只强调两条产品级红线:
- 任何自动流程都不许把 `manual_review` 改回执行中状态,必须由人处理。
- Client 拿到任务就做完。中途 Admin 取消了这个任务,Client **不管**,照做完照提交,由人工审核时处理。
- 程序崩溃后,处于不可逆采购阶段的任务只能执行订单核对,**不能重新下单**。
## 8. MVP 范围
MVP 包含:
- 两模块 Fluent 界面;
- SQLite 数据库和迁移;
- 本地任务表格、搜索、筛选和详情;
- Mock Admin 接口;
- 任务领取与串行执行;
- 后台任务协调器、轮询、停止、重试和结果待提交队列;
- 真实商品采集及 SKU 数据组装;
- 采购演练模式,完成规格和数量选择但不执行最终下单;
- 重启恢复、断网、设备断开和重复提交测试。
MVP 之后:
- 接入真实 Admin HTTP 接口;
- 经过安全验收后启用真实订单提交;
- 完成订单核对和人工处理流程;
- 打包成 exe 并做生产环境验证(策略见 §8.1)。
### 8.1 打包策略
**打包动作属于 MVP 之后**,但策略现在就定下来,避免写代码时留下不好打包的结构。
**工具:** PyInstaller 6.x,**one-dir 模式**(不是 one-file)。
one-file 每次启动都要解压到临时目录,启动慢,出错几乎没法排查;one-dir 缺什么文件一眼就能看见。
**产出目录结构:**
```text
CMAutoBuy/ 整个文件夹拷到任何机器都能用
├── launcher.exe 双击这个启动
├── app/ 运行时依赖,用户不要动
│ ├── python310.dll
│ ├── PyQt5/Qt5/
│ │ ├── bin/ Qt5Core.dll / Qt5Gui.dll / Qt5Widgets.dll …
│ │ └── plugins/platforms/qwindows.dll
│ ├── qfluentwidgets/ qss 样式、字体、图标资源
│ ├── adbutils/binaries/ adb.exe
│ └── …
└── data/ 本地数据,升级时保留(见 [03 数据模型](03-data-model.md) §2.1)
├── client.db
├── logs/
└── artifacts/
```
`app/` 这个名字来自 PyInstaller 的 `--contents-directory app` 参数(默认叫 `_internal`)。
**升级方式:** 删掉 `launcher.exe` 和 `app/`,换成新版本,**`data/` 原样不动**。
数据库靠 `PRAGMA user_version` 自动迁移,见 [03](03-data-model.md) §2.3。
**已知风险点**(打包工单必须逐项验证):
| 风险 | 症状 |
|---|---|
| Qt 平台插件没收集到 | 启动即报 `could not find or load the Qt platform plugin "windows"` |
| `qfluentwidgets` 资源没收集到 | 能启动,但界面全白、控件没样式 |
| `adbutils` 的 adb 二进制没收集到 | 界面正常,但连不上手机 |
| `uiautomator2` 初始化流程 | 打包后没有 `python -m uiautomator2 init` 这条命令,需确认辅助 App 怎么装 |
| 杀软误报 | 空白版本信息的 exe 最容易被拦。必须给 exe 加图标和版本信息(产品名、版本号)。根治需要代码签名证书 |
| 装到 `C:\Program Files\` | 无写权限,数据被重定向到 VirtualStore,设置改了不生效 |
具体的 PyInstaller 参数和 hook 配置跟依赖版本强相关,**不在本文档固化**,
由打包工单在真实 Windows 环境上验证后写进归档。
## 9. 非目标
- 不开发 Admin 管理界面或 Admin 数据库。
- 不自动注册、登录或绕过拼多多验证码、风控和安全机制。
- 不自动完成支付;当前采购范围止于创建订单并获取订单信息。
- MVP 不支持一台 Client 同时并行控制多台设备。
- 不保证拼多多未公开界面在所有版本中保持兼容,必须通过版本化适配和诊断产物处理变化。
## 10. 非功能需求
- 所有网络、数据库长操作和 uiautomator2 操作不得阻塞 Qt 主线程。
- 同一设备同一时间只执行一个任务。
- 任务领取、结果提交和采购操作必须具有去重或幂等保护。
- 结果先本地持久化,再提交 Admin;Admin 暂时不可用不能导致重新采购。
- 时间在数据库和接口中使用带时区的 ISO 8601,内部优先使用 UTC,界面转换为本地时间。
- 金额以人民币分的整数保存,禁止使用浮点数作为业务金额。
- 任务、日志和诊断信息不得包含密码、访问令牌、Cookie 或不必要的个人信息。
## 11. 待确认事项
这些还没定下来,但**不许因此停工**。先按"临时默认值"做,等定了再按工单改。
| # | 待确认什么 | 临时默认值(先这么做) | 定下来之前会卡住什么 |
|---|---|---|---|
| 1 | Admin 的认证方式和 Client 注册方式 | Mock Gateway 不做认证;HTTP 实现预留 `Authorization: Bearer` 请求头,token 从设置读 | 只卡真实 HTTP 联调,不卡 MVP |
| 2 | 真实采购启用条件和人工确认策略 | 真实下单开关**保持关闭**,一律走演练模式 | 卡真实下单,不卡 MVP |
| 3 | 价格允许偏差 | 默认 0 分(即实际价格必须等于预期价格才继续),可在设置页改 | 不卡。先按最严的来 |
| 4 | 是否存在颜色、尺码之外的第三个规格维度 | **按"可能有任意多个维度"实现**,用 `dimensions` 数组,不要写死两个 | 不卡。写死才会返工 |
第 4 条特别注意:即使目前见到的商品都只有颜色和尺码两个维度,也**不许**把数据结构写成两个固定字段。见 [03 数据模型](03-data-model.md) §8.1。
**已定案(不再是待确认项):**
- Admin 只分配任务给指定 Client,Client 不读全局任务池。见 [04](04-admin-api-contract.md) §5.1。
- **没有租约、没有心跳、没有状态回查。** 任务流程只有领取、提交结果、提交失败三个调用;设置页另有无任务副作用的幂等 Client 登记调用。见 [04](04-admin-api-contract.md) §1、§4.1。
- 本地只存已领取任务,已完成任务**永久保留**。诊断产物(截图、XML、日志)仍按 `diagnostics.retention_days` 清理,两者不是一回事。见 [03](03-data-model.md) §3.1。