docs(erp): define freight ingestion tasks

This commit is contained in:
QiuSW
2026-07-28 22:39:18 +08:00
parent 78dc595815
commit cc847c9aed
15 changed files with 547 additions and 6 deletions
+3 -1
View File
@@ -62,7 +62,9 @@ T-205 原子领取/租约状态机、T-206 Android 登录/有限离线、T-207
结构化人工理由和修订历史也已完成。T-214 商品持久身份和重新定位指纹、T-215 结构化人工理由和修订历史也已完成。T-214 商品持久身份和重新定位指纹、T-215
Admin 候选确认、不可变待投递授权、T-216 设备命令可靠投递及 T-217 已授权商品 Admin 候选确认、不可变待投递授权、T-216 设备命令可靠投递及 T-217 已授权商品
重新定位与订单 dry-run、T-218 单次订单提交围栏和订单回读,以及 T-219 Admin 重新定位与订单 dry-run、T-218 单次订单提交围栏和订单回读,以及 T-219 Admin
待付款提醒与端到端验收均已完成。下一任务是 T-301 P0 UI 完整交互验收。 待付款提醒与端到端验收均已完成。采购任务来源现扩展为顺运宝 ERP:T-220 至
T-224 将依次完成安全字段契约、精确单号 Connector、货运信息存储/Admin、待采购
需求生成和日期增量同步;完成后再进入 T-301 P0 UI 完整交互验收。
不得直接把候选链接或列表 ordinal 当成授权。 不得直接把候选链接或列表 ordinal 当成授权。
手机从管理后端领取任务并回传结果,VLM、拼多多自动化和人工确认在 App 本地完成。 手机从管理后端领取任务并回传结果,VLM、拼多多自动化和人工确认在 App 本地完成。
T-206 增加有限离线执行;T-207 已复用 Roubao 端上 OpenAI 兼容适配器并加密本地 Key。 T-206 增加有限离线执行;T-207 已复用 Roubao 端上 OpenAI 兼容适配器并加密本地 Key。
+17 -1
View File
@@ -6,7 +6,7 @@
| 项 | 当前事实 | | 项 | 当前事实 |
| --- | --- | | --- | --- |
| 任务来源 | 其他管理后台或本项目管理 Web 采集商品标题、SKU、描述、图片、数量和预算。 | | 任务来源 | 顺运宝 ERP 货运单/商品明细是主要来源;本项目 Admin 先保存并复核货运信息,再生成不可变采购任务。管理 Web 手工创建继续作为补充入口。 |
| 第一层样本来源 | 本机目录中的蝦皮订单文本和参考图;二者以蝦皮订单号作为同名文件名。 | | 第一层样本来源 | 本机目录中的蝦皮订单文本和参考图;二者以蝦皮订单号作为同名文件名。 |
| 执行方式 | 采购人员使用 Android App 操作拼多多;需求提取、动态词搜索、最多 5 个候选证据采集、匹配建议和人工确认停止点已可运行。 | | 执行方式 | 采购人员使用 Android App 操作拼多多;需求提取、动态词搜索、最多 5 个候选证据采集、匹配建议和人工确认停止点已可运行。 |
| 核心痛点 | 人工把图片和描述转成搜索词、逐条比较商品并记录结果,耗时且不一致。 | | 核心痛点 | 人工把图片和描述转成搜索词、逐条比较商品并记录结果,耗时且不一致。 |
@@ -18,6 +18,8 @@
- **采购管理员**:创建、查看、取消未执行任务,或请求执行中任务安全停止,并查看结果。 - **采购管理员**:创建、查看、取消未执行任务,或请求执行中任务安全停止,并查看结果。
- **采购执行员**:在 App 上检查设备状态、手动领取、执行和人工确认任务。 - **采购执行员**:在 App 上检查设备状态、手动领取、执行和人工确认任务。
- **设备身份**:代表一台获得授权的 Android 设备领取任务和上报状态。 - **设备身份**:代表一台获得授权的 Android 设备领取任务和上报状态。
- **ERP Connector 身份**:只读查询顺运宝并向后端提交最小化货运数据,不能领取任务、
创建下单授权或访问拼多多结果。
- **系统管理员/审核员**:目标架构角色,MVP 不提供完整管理界面。 - **系统管理员/审核员**:目标架构角色,MVP 不提供完整管理界面。
- **未登录用户**:不能访问任务、图片、执行证据或设备接口。 - **未登录用户**:不能访问任务、图片、执行证据或设备接口。
@@ -34,6 +36,8 @@
| F-007 | 结果与异常回传 | 管理员和采购员看到成功、失败、取消及可恢复建议。 | P0 | US-002、US-006 | | F-007 | 结果与异常回传 | 管理员和采购员看到成功、失败、取消及可恢复建议。 | P0 | US-002、US-006 |
| F-009 | 手机独立执行与 VLM | App 本地完成模型判断和自动化,后端只控制任务并接收结果。 | P0 | US-009 | | F-009 | 手机独立执行与 VLM | App 本地完成模型判断和自动化,后端只控制任务并接收结果。 | P0 | US-009 |
| F-010 | 授权创建待付款订单 | Admin 选品后签发一次性授权,Roubao 选择已确认 SKU/数量并创建待付款订单;付款始终人工完成。 | P0 | US-010 | | F-010 | 授权创建待付款订单 | Admin 选品后签发一次性授权,Roubao 选择已确认 SKU/数量并创建待付款订单;付款始终人工完成。 | P0 | US-010 |
| F-011 | 导入 ERP 货运信息 | 管理员按完整单号或日期区间同步顺运宝货运头和全部商品明细,重复同步不重复。 | P0 | US-011 |
| F-012 | 从货运明细生成采购任务 | 管理员复核商品标题、SKU、数量和参考图后,从一条商品明细生成一条不可变采购任务。 | P0 | US-012 |
### F-009 手机独立执行与 VLM ### F-009 手机独立执行与 VLM
@@ -136,6 +140,18 @@ T-206/T-207 已跑通领取、执行、候选/证据和最小结果回传;T-20
唯一且文本精确为“提交订单”。出现添加地址、立即支付、免密支付、先用后付或其他 唯一且文本精确为“提交订单”。出现添加地址、立即支付、免密支付、先用后付或其他
自动扣款语义时必须停止。围栏创建后即使 App 在实际点击前退出,也只能查订单或 自动扣款语义时必须停止。围栏创建后即使 App 在实际点击前退出,也只能查订单或
转人工,不能重新提交。 转人工,不能重新提交。
24. 顺运宝查询使用 `stock.id` 作为货运单外部身份,`detail.details[].id` 作为商品
明细外部身份;用户输入单号只是查询条件,不作为数据库主键。
25. ERP 同步先保存货运头和全部商品明细,再提取待采购需求;禁止 ERP 响应直接创建
或修改采购任务。
26. 一条商品明细最多对应一条同 revision 的采购任务;多商品货运单拆成多条采购需求,
不合并 SKU 或使用货运头总数量代替商品数量。
27. 采购任务生成前必须存在明确标题、原始 SKU/规格、正整数数量和已验证参考图。
`productThumb` 等未确认 ERP 引用不能当成可下载图片 URL。
28. ERP 来源更新不得覆盖已生成采购任务。系统保存新 revision/hash 并提示人工处理;
是否取消旧任务和生成新任务由管理员明确决定。
29. 收件人、电话、详细地址、ERP 账号、Cookie、JWT、验证码和完整响应不得进入采购
任务、Roubao、VLM、普通日志或 Git;货运模块也只保存采购所需最小字段。
## 六、第一层本地样本约定 ## 六、第一层本地样本约定
+6
View File
@@ -21,6 +21,7 @@
| 数据访问 | 标准库 `database/sql` | MVP 已定 | 领域层通过仓储接口访问,避免先引入 ORM 和代码生成复杂度。 | | 数据访问 | 标准库 `database/sql` | MVP 已定 | 领域层通过仓储接口访问,避免先引入 ORM 和代码生成复杂度。 |
| 数据迁移 | Goose v3.26.0,使用嵌入式 SQL migration | 已验证 | v3.26.0 是已核实仍声明 Go 1.23.0 的最高版本;v3.27.x 要求 Go 1.25。 | | 数据迁移 | Goose v3.26.0,使用嵌入式 SQL migration | 已验证 | v3.26.0 是已核实仍声明 Go 1.23.0 的最高版本;v3.27.x 要求 Go 1.25。 |
| 管理 Web | Gin + `html/template` + `embed` + 少量原生 JS/CSS | MVP 已定 | 不单独引入 SPA 工程,模板和静态资源随服务构建。 | | 管理 Web | Gin + `html/template` + `embed` + 少量原生 JS/CSS | MVP 已定 | 不单独引入 SPA 工程,模板和静态资源随服务构建。 |
| ERP Connector | Python 3.10+、requests 2.31+;可选 FastAPI/uvicorn 内部服务 | T-220 至 T-224 | 复用已验证顺运宝协议客户端;只监听 loopback、服务密钥鉴权,ERP 凭证不进入 Go 后端。 |
| 数据库 | SQLite | MVP 已定 | 单服务、单设备验证足够;多实例或并发提升前迁移 PostgreSQL。 | | 数据库 | SQLite | MVP 已定 | 单服务、单设备验证足够;多实例或并发提升前迁移 PostgreSQL。 |
| 图片/截图 | 后端受控本地文件目录 + `golang.org/x/image` v0.28.0 | 已验证 | JPEG/PNG/WebP 真解码后白底缩放并编码为 JPEG;数据库只存元数据和随机相对键。 | | 图片/截图 | 后端受控本地文件目录 + `golang.org/x/image` v0.28.0 | 已验证 | JPEG/PNG/WebP 真解码后白底缩放并编码为 JPEG;数据库只存元数据和随机相对键。 |
| 管理鉴权 | bcrypt + 8 小时 opaque 服务端会话 Cookie | T-204 已验证 | `authctl` 预置 ADMIN;数据库只存密码 hash 与 session SHA-256,完整 RBAC 为 V2。 | | 管理鉴权 | bcrypt + 8 小时 opaque 服务端会话 Cookie | T-204 已验证 | `authctl` 预置 ADMIN;数据库只存密码 hash 与 session SHA-256,完整 RBAC 为 V2。 |
@@ -124,6 +125,9 @@ backend-api/
internal/transport/httpapi/ # Gin 路由、健康检查和 HTTP Server internal/transport/httpapi/ # Gin 路由、健康检查和 HTTP Server
migrations/ # 嵌入式 Goose SQL migration migrations/ # 嵌入式 Goose SQL migration
var/ # 本地运行数据,必须忽略 var/ # 本地运行数据,必须忽略
erp-connector/
src/shunyunbaoerp/ # 顺运宝登录、查询、规范化与内部 HTTP 适配
tests/ # 伪响应和脱敏结构测试,不访问线上 ERP
docs/ docs/
``` ```
@@ -163,3 +167,5 @@ T-205 已在该分层上增加独立 `LifecycleService` 与 SQLite immediate tra
PowerShell 等价环境变量,确保依赖没有暗中要求更高 Go 版本。 PowerShell 等价环境变量,确保依赖没有暗中要求更高 Go 版本。
- handler 不直接写 SQL,repository 不依赖 Gin,domain/usecase 不导入具体数据库驱动。 - handler 不直接写 SQL,repository 不依赖 Gin,domain/usecase 不导入具体数据库驱动。
- 密钥和设备令牌通过环境变量或本地忽略配置注入,不进入 Git。 - 密钥和设备令牌通过环境变量或本地忽略配置注入,不进入 Git。
- ERP 账号、密码、Cookie、JWT 和 Connector 服务密钥只通过环境变量/受控秘密注入;
Go 后端不保存 ERP 会话,Connector 不把完整响应或 PII 写普通日志。
+44
View File
@@ -14,6 +14,8 @@
统一 Backend API 统一 Backend API
| |
+--> SQLite / 文件存储 +--> SQLite / 文件存储
|
+--> loopback ERP Connector ----> 顺运宝 ERP
^ ^
| |
Android 采购 App --------------------> VLM Provider Android 采购 App --------------------> VLM Provider
@@ -29,6 +31,8 @@ Android 采购 App --------------------> VLM Provider
- 拼多多是第三方受控边界,只能由 Android 设备在已登录会话中操作。 - 拼多多是第三方受控边界,只能由 Android 设备在已登录会话中操作。
- VLM 配置和 Key 位于手机,Key 使用 Android Keystore 包装的加密存储;管理后端不 - VLM 配置和 Key 位于手机,Key 使用 Android Keystore 包装的加密存储;管理后端不
保存、下发或代理模型调用。 保存、下发或代理模型调用。
- ERP 账号、验证码会话、Cookie 和 JWT 只存在于 loopback Python Connector;
Go 后端只接收最小化规范货运数据。
## 二、模块职责 ## 二、模块职责
@@ -128,6 +132,29 @@ App 支持两个显式模式:
- `MANUAL_FIRST`:从原始标题/SKU 产生有界搜索词,由人员判断候选,不要求 VLM。 - `MANUAL_FIRST`:从原始标题/SKU 产生有界搜索词,由人员判断候选,不要求 VLM。
- `AI_ASSISTED`:使用 App 本地配置的 OpenAI 兼容 provider 做需求提取和候选评估。 - `AI_ASSISTED`:使用 App 本地配置的 OpenAI 兼容 provider 做需求提取和候选评估。
### 2.4 顺运宝 ERP Connector
Connector 是外部系统防腐层,不属于采购任务状态机:
```text
Admin 创建 sync run
-> Go 后台 worker 调用 loopback Connector
-> Connector 使用受控 ERP 会话查询 list/listTotal/listByStock
-> Connector 规范化并去除收件 PII
-> Go 同事务 upsert freight order/items
-> Admin 复核 procurement request
-> 显式生成不可变 purchase task
```
- Python 进程默认只监听 `127.0.0.1`,使用独立服务密钥;Go 不传输或保存 ERP 密码。
- 精确单号只是查询条件,外部身份固定为 `stock.id` 和 `details[].id`。
- Connector 不写本项目 SQLite,不调用 Roubao/拼多多/VLM,也不打印响应 body。
- Go handler 只创建 sync run;外部查询由有界 worker 执行,避免把验证码或 ERP
延迟绑定到浏览器请求。
- 未确认的 `productThumb` 只按 ERP 引用保存,不能拼接 URL 或越权下载。
- ERP 接口由页面协议观察得到,正式生产前需确认开放 API、服务账号、调用频率、
缓存和个人信息处理权限。
模式在 execution 开始时固定并写入结果;AI 失败后只能由人员明确切换,不能静默降级。 模式在 execution 开始时固定并写入结果;AI 失败后只能由人员明确切换,不能静默降级。
App 同时固定 provider ID、model、prompt/schema version 和证据 SHA-256,作为非秘密 App 同时固定 provider ID、model、prompt/schema version 和证据 SHA-256,作为非秘密
provenance 回传。Key、Authorization、完整 endpoint 和供应商原始响应正文不回传。 provenance 回传。Key、Authorization、完整 endpoint 和供应商原始响应正文不回传。
@@ -457,6 +484,23 @@ IDLE
- 管理和 App 登录在 bcrypt 前共享一个内存有界限流器,但使用独立 scope + 服务端 - 管理和 App 登录在 bcrypt 前共享一个内存有界限流器,但使用独立 scope + 服务端
`RemoteAddr` 键;成功登录清零,超限返回 `429` 与 `Retry-After`。 `RemoteAddr` 键;成功登录清零,超限返回 `429` 与 `Retry-After`。
### ERP 货运来源层
| 表 | 主要内容 |
| --- | --- |
| `erp_sync_runs` | 查询模式、匿名查询 hash、时间范围、状态、计数、错误码和成功水位 |
| `freight_orders` | creator、source system、external stock id、来源单号、店铺、状态、ERP 时间、canonical hash/revision |
| `freight_order_items` | freight order、external item id、标题、规格、SKU、数量、图片引用、采购状态、canonical hash/revision |
| `procurement_requests` | 货运明细 revision 的不可变采购字段、校验状态、参考图和来源变化状态 |
| `purchase_task_sources` | procurement request/revision 与现有 purchase task 的幂等关联 |
货运层只保存采购所需字段,不保存 receiver、receiverTel、receiverAddr、Cookie、JWT
或完整原始 JSON。重复同步按外部 ID upsert;内容 hash 不变时不增加 revision。
来源变化只产生新 revision/状态,绝不修改已生成的采购任务。
一个货运单可以有多个商品明细;一个采购任务仍保持单商品、单 SKU、单参考图。
缺少明确标题/SKU/正整数数量/有效参考图的请求停在 `NEEDS_REVIEW/NEEDS_IMAGE`。
### `purchase_tasks` ### `purchase_tasks`
| 字段 | 约束 | 说明 | | 字段 | 约束 | 说明 |
+5
View File
@@ -52,6 +52,11 @@
| T-217 | 已授权商品重新定位与订单 dry-run | T-216 | 重新核对持久指纹并唯一选择 SKU/数量,停在最终提交前 | | T-217 | 已授权商品重新定位与订单 dry-run | T-216 | 重新核对持久指纹并唯一选择 SKU/数量,停在最终提交前 |
| T-218 | 单次订单提交与订单回读 | T-217 | 一次性提交后从订单列表读取订单号/时间并对账,不支付 | | T-218 | 单次订单提交与订单回读 | T-217 | 一次性提交后从订单列表读取订单号/时间并对账,不支付 |
| T-219 | Admin 待付款提醒与端到端验收 | T-218 | 三态展示可核对订单并提醒采购员去拼多多确认付款;不提供支付入口 | | T-219 | Admin 待付款提醒与端到端验收 | T-218 | 三态展示可核对订单并提醒采购员去拼多多确认付款;不提供支付入口 |
| T-220 | 顺运宝 ERP 字段契约与凭证安全基线 | T-219 | 明文凭证和私有响应不进 Git/日志;冻结货运头、商品明细和采购字段映射 |
| T-221 | 顺运宝精确单号 Connector | T-220 | 受控 Python 服务按完整单号读取货运头与全部商品明细;失败稳定且不泄露 PII |
| T-222 | 货运信息存储、API 与 Admin 页面 | T-221 | Go 后端幂等保存同步记录、货运单和明细;Admin 可按单号导入、列表和查看 |
| T-223 | 待采购需求提取与任务生成 | T-222 | 一条有效商品明细形成一条可复核采购需求;参考图齐备后幂等生成采购任务 |
| T-224 | ERP 日期增量同步 | T-223 | 按 ERP 创建日期区间分页同步,重叠窗口去重;失败不推进成功水位 |
## Phase 3:端到端验证 ## Phase 3:端到端验证
+32
View File
@@ -17,6 +17,38 @@
| US-008 | 积累可信的候选决策样本 | P1 | 采购执行员、优化人员 | 用真实曝光和人工理由评估并改进模型 | F-008 | IX-009 | 已定,T-208 后置 | | US-008 | 积累可信的候选决策样本 | P1 | 采购执行员、优化人员 | 用真实曝光和人工理由评估并改进模型 | F-008 | IX-009 | 已定,T-208 后置 |
| US-009 | 手机独立完成采购任务 | P0 | 采购执行员 | 后端短时不可用时仍在有限授权内安全执行 | F-009 | IX-010 | 已定,T-206/T-207 | | US-009 | 手机独立完成采购任务 | P0 | 采购执行员 | 后端短时不可用时仍在有限授权内安全执行 | F-009 | IX-010 | 已定,T-206/T-207 |
| US-010 | 审批并创建待付款订单 | P0 | 采购管理员、采购执行员 | Admin 选定候选后只创建一笔可核对的待付款订单 | F-006、F-010 | IX-011 | 已定,T-215 至 T-219 | | US-010 | 审批并创建待付款订单 | P0 | 采购管理员、采购执行员 | Admin 选定候选后只创建一笔可核对的待付款订单 | F-006、F-010 | IX-011 | 已定,T-215 至 T-219 |
| US-011 | 导入并查看 ERP 货运单 | P0 | 采购管理员 | 按单号或时间同步货运单及全部商品明细,知道同步是否完整 | F-011 | IX-012 | 已定,T-220 至 T-224 |
| US-012 | 从货运明细生成采购任务 | P0 | 采购管理员 | 复核来源商品并幂等生成一条可执行采购任务 | F-012 | IX-013 | 已定,T-223 |
## US-011 导入并查看 ERP 货运单
- 关联页面:管理 Web `/freight`、`/freight/import`、`/freight/{id}`
- 前置条件:ERP Connector 已建立受控登录会话。
作为采购管理员,我想按完整单号或时间范围同步顺运宝货运信息,并查看每张货运单的
全部商品明细,从而不再手工抄写采购资料。
**验收场景**
1. 同一单号重复同步不会增加重复货运单或商品明细。
2. 一张货运单有多个商品时,Admin 展示全部明细而不是只保留最后一条。
3. Connector 未登录、ERP 超时、查询过宽或响应缺字段时显示可重试失败,不写半批数据。
4. 页面和日志不显示收件电话、详细地址、ERP Cookie/JWT 或完整原始响应。
## US-012 从货运明细生成采购任务
- 关联页面:管理 Web `/freight/{id}`
- 前置条件:商品明细已导入,标题、SKU、数量和参考图可核对。
作为采购管理员,我想从一条 ERP 商品明细生成一条采购任务,从而让 Roubao 使用
经过核对的不可变来源快照执行采购。
**验收场景**
1. 每条商品明细独立显示标题、规格/SKU、数量、图片和来源 revision。
2. 缺图、数量非法、SKU 含糊或来源状态不允许时禁止生成并指出原因。
3. 重复点击或网络重试返回同一采购任务。
4. ERP 来源变化不修改已领取或执行中的采购任务,而是提示来源已更新。
## US-001 创建清晰的采购任务 ## US-001 创建清晰的采购任务
+2
View File
@@ -18,6 +18,8 @@
| IX-009 | US-008 | App 候选理由/管理端决策详情 | 接受、拒绝、改选或修正 | 保存逐候选结构化人工标签 | P1 | T-208 已实现 | | IX-009 | US-008 | App 候选理由/管理端决策详情 | 接受、拒绝、改选或修正 | 保存逐候选结构化人工标签 | P1 | T-208 已实现 |
| IX-010 | US-009 | App 独立执行设置/同步状态 | 配置模式、离线执行或补报 | 授权内独立执行并可审计同步 | P0 | T-206 离线控制已实现,结果补报待 T-207 | | IX-010 | US-009 | App 独立执行设置/同步状态 | 配置模式、离线执行或补报 | 授权内独立执行并可审计同步 | P0 | T-206 离线控制已实现,结果补报待 T-207 |
| IX-011 | US-010 | Admin 候选授权/App 订单执行 | 选择候选并授权、设备领取执行 | 创建一笔可对账的待付款订单并提醒人工付款 | P0 | T-215 至 T-219 已完成 | | IX-011 | US-010 | Admin 候选授权/App 订单执行 | 选择候选并授权、设备领取执行 | 创建一笔可对账的待付款订单并提醒人工付款 | P0 | T-215 至 T-219 已完成 |
| IX-012 | US-011 | Admin 货运导入/列表/详情 | 输入完整单号或日期区间并同步 | 幂等保存货运头与全部商品明细,显示同步结果 | P0 | T-220 至 T-224 |
| IX-013 | US-012 | Admin 货运商品明细 | 核对来源字段、补充参考图并生成 | 创建或重放同一采购任务,不覆盖来源/任务历史 | P0 | T-223 |
## IX-001 管理 Web 登录 ## IX-001 管理 Web 登录
+93
View File
@@ -164,6 +164,99 @@ T-203 成功返回 `201`。使用相同 `Idempotency-Key` 和相同图片内容
受鉴权的文件流。只能读取用户有权查看的任务资产;不返回服务端文件路径。 受鉴权的文件流。只能读取用户有权查看的任务资产;不返回服务端文件路径。
## ERP Connector 与货运信息
Connector 是 loopback 内部服务,不复用 ADMIN/BUYER 凭证。除 `/health` 外要求
`X-API-Key`,密钥至少 32 字节并由两进程环境变量注入;请求和响应不得写 body 日志。
### Connector `POST /v1/freight/query`
```json
{"order_number":"完整单号"}
```
成功返回最小化规范结构:
```json
{
"schema_version": 1,
"query": {"mode":"ORDER_NUMBER"},
"orders": [{
"external_stock_id": "99001122",
"source_code": "masked-at-log-boundary",
"platform_order_no": "optional",
"shop_name": "来源店铺",
"source_created_at": "2026-07-28T08:00:00+08:00",
"order_status": "0",
"purchase_status": "0",
"is_canceled": false,
"items": [{
"external_item_id": "880011",
"title": "商品标题",
"product_spec": "灰色,2XL",
"sku": "原始 SKU",
"quantity": 2,
"product_thumb_ref": "190000000",
"purchase_status": "0"
}]
}]
}
```
不得返回 receiver、receiverTel、receiverAddr、Cookie、JWT、ERP 用户资料或完整原始
对象。多商品必须全部保留;缺失详情返回协议错误,不允许部分成功。
### `POST /api/v1/freight-syncs`
ADMIN 创建异步同步记录,必须带 `Idempotency-Key`:
```json
{"mode":"ORDER_NUMBER","order_number":"完整单号"}
```
T-224 增加:
```json
{
"mode":"CREATED_RANGE",
"created_from":"2026-07-27T16:00:00Z",
"created_to":"2026-07-28T16:00:00Z"
}
```
响应 `202`,返回 sync id/status。订单号不进入 URL、事件 message 或访问日志;数据库
只保存规范值及用于审计/检索的受控字段,不保存 Connector 密钥。
### `GET /api/v1/freight-syncs/{sync_id}`
返回 `PENDING/RUNNING/SUCCEEDED/FAILED`、查询模式、匿名查询摘要、开始/结束时间、
订单/商品计数和稳定错误码。失败不返回 ERP 原始 body 或个人信息。
### `GET /api/v1/freight-orders`
支持 `q`、`sync_status`、`created_from/to`、`limit/cursor`。`q` 匹配受控来源单号、
店铺或内部 UUID,不匹配电话/地址。稳定排序为 `source_created_at DESC, id DESC`。
### `GET /api/v1/freight-orders/{id}`
返回货运头、全部商品明细、revision/hash 状态、采购需求和已生成 task 引用。不存在和
跨 creator 统一 404;响应 `Cache-Control: no-store`。
### `POST /api/v1/freight-items/{item_id}/procurement-request`
T-223 创建或重放该商品当前 revision 的采购需求。标题、SKU/规格或数量不合法时返回
`422 FREIGHT_ITEM_NOT_PURCHASABLE`;不调用 VLM 补字段。
### `PUT /api/v1/procurement-requests/{id}/reference-asset`
绑定当前 ADMIN 已上传的 `TASK_REFERENCE` asset。asset 必须尚未属于其他任务/请求,
内容仍走既有解码、像素、规范化和 hash 校验。
### `POST /api/v1/procurement-requests/{id}/purchase-task`
必须带 `Idempotency-Key`。只有 `READY` request 可生成任务;同一 request revision
并发或重试返回同一 task。来源后续更新不修改已生成任务。
## 采购任务 ## 采购任务
### `POST /api/v1/tasks` ### `POST /api/v1/tasks`
+9 -3
View File
@@ -5,7 +5,7 @@
## 当前快照 ## 当前快照
- 日期:2026-07-28 - 日期:2026-07-28
- 阶段:T-219 Admin 待付款提醒与端到端验收已完成 - 阶段:T-220 顺运宝 ERP 字段契约与凭证安全基线已领取
- Git:当前分支为 `main`;T-001 至 T-004、T-101 至 T-104、T-201 至 T-219 - Git:当前分支为 `main`;T-001 至 T-004、T-101 至 T-104、T-201 至 T-219
均按文档提交、实现提交的顺序纳入历史 均按文档提交、实现提交的顺序纳入历史
- 生产代码:`android-buyer/` 已接入 Roubao Android 源码 - 生产代码:`android-buyer/` 已接入 Roubao Android 源码
@@ -151,6 +151,11 @@
| `docs/tasks/T-217.md` | DONE | 重新核对已授权商品并选择 SKU/数量,停在最终提交前 | | `docs/tasks/T-217.md` | DONE | 重新核对已授权商品并选择 SKU/数量,停在最终提交前 |
| `docs/tasks/T-218.md` | DONE | 单次提交围栏、最多一次提交动作和待付款订单唯一对账 | | `docs/tasks/T-218.md` | DONE | 单次提交围栏、最多一次提交动作和待付款订单唯一对账 |
| `docs/tasks/T-219.md` | DONE | Admin 待付款提醒、Roubao 终态和跨端闭环验收 | | `docs/tasks/T-219.md` | DONE | Admin 待付款提醒、Roubao 终态和跨端闭环验收 |
| `docs/tasks/T-220.md` | DOING | 顺运宝 ERP 字段契约与凭证安全基线 |
| `docs/tasks/T-221.md` | TODO | 顺运宝精确单号 Connector |
| `docs/tasks/T-222.md` | TODO | 货运信息存储、API 与 Admin 页面 |
| `docs/tasks/T-223.md` | TODO | 待采购需求提取与任务生成 |
| `docs/tasks/T-224.md` | TODO | ERP 日期增量同步 |
| `docs/design/` | 已确认 | T-202 原型索引、4 个管理页和 7 个 Android 页面 | | `docs/design/` | 已确认 | T-202 原型索引、4 个管理页和 7 个 Android 页面 |
| `deepseek总结.txt` | 已有 | 历史讨论摘要,不是正式需求权威 | | `deepseek总结.txt` | 已有 | 历史讨论摘要,不是正式需求权威 |
| `android-buyer/` | 已有 | Roubao `main` 固定 commit 的 Android 基线 | | `android-buyer/` | 已有 | Roubao `main` 固定 commit 的 Android 基线 |
@@ -162,8 +167,9 @@
## 任务摘要 ## 任务摘要
- 已完成:T-001 至 T-004、T-101 至 T-104、T-201 至 T-219。 - 已完成:T-001 至 T-004、T-101 至 T-104、T-201 至 T-219。
- 进行中:无。 - 进行中:T-220 顺运宝 ERP 字段契约与凭证安全基线。
- 下一步:进入 T-301 P0 UI 完整交互验收。 - 下一步:依次完成 T-221 精确单号 Connector、T-222 货运模块、T-223 采购需求生成
和 T-224 日期增量同步,再进入 T-301 P0 UI 完整交互验收。
## 当前可运行内容 ## 当前可运行内容
+7 -1
View File
@@ -11,9 +11,13 @@ T-202 的离线 P0 页面入口见[原型索引](design/index.html)。原型仅
| `/tasks` | 任务列表 | 查看状态、筛选并进入详情 | US-002 | IX-003 | | `/tasks` | 任务列表 | 查看状态、筛选并进入详情 | US-002 | IX-003 |
| `/tasks/new` | 新建任务 | 提交图片和采购约束 | US-001 | IX-002 | | `/tasks/new` | 新建任务 | 提交图片和采购约束 | US-001 | IX-002 |
| `/tasks/{id}` | 任务详情 | 查看输入/候选/证据、创建下单授权,并展示对账中/人工对账/待人工付款状态 | US-002、US-006、US-010 | IX-003、IX-008、IX-011 | | `/tasks/{id}` | 任务详情 | 查看输入/候选/证据、创建下单授权,并展示对账中/人工对账/待人工付款状态 | US-002、US-006、US-010 | IX-003、IX-008、IX-011 |
| `/freight` | ERP 货运列表 | 按来源单号、同步状态和时间查看已导入货运单 | US-011 | IX-012 |
| `/freight/import` | ERP 货运导入 | 创建精确单号或日期范围同步 | US-011 | IX-012 |
| `/freight/{id}` | ERP 货运详情 | 查看全部商品明细、来源变化、补图和采购任务生成状态 | US-011、US-012 | IX-012、IX-013 |
MVP 登录后默认进入 `/tasks`。未登录访问受保护页面时跳转 `/login` 并携带安全的 MVP 登录后默认进入 `/tasks`。未登录访问受保护页面时跳转 `/login` 并携带安全的
站内返回路径;只接受 `/tasks` 及其本站子路径,拒绝绝对 URL、`//` 和反斜杠。 站内返回路径;只接受 `/tasks`、`/freight` 及其本站子路径,拒绝绝对 URL、`//`
和反斜杠。
不存在和无权限必须使用不同内部原因,但页面均不得泄露任务内容。 不存在和无权限必须使用不同内部原因,但页面均不得泄露任务内容。
## Android 页面 ## Android 页面
@@ -85,6 +89,8 @@ T-207 的 events/candidates/complete/fail 接受原设备对授权内已产生
| `CandidateReview` | Android/Web | 展示候选与硬约束校验,不执行自动化动作 | | `CandidateReview` | Android/Web | 展示候选与硬约束校验,不执行自动化动作 |
| `ExecutionController` | Android | UI 命令入口,委托 workflow,不直接调用 Accessibility | | `ExecutionController` | Android | UI 命令入口,委托 workflow,不直接调用 Accessibility |
| `PendingPaymentSummary` | 管理 Web/App | 只读展示对账订单与人工付款提醒,不提供付款或重提动作 | | `PendingPaymentSummary` | 管理 Web/App | 只读展示对账订单与人工付款提醒,不提供付款或重提动作 |
| `FreightSyncForm` | 管理 Web | 创建精确单号/日期同步记录,不持有 ERP 凭证 |
| `FreightItemReview` | 管理 Web | 显示规范化来源字段、缺失项和采购任务生成操作 |
具体状态反馈以[交互清单](08-interaction-checklist.md)为准,组件命名可在接入真实框架后 具体状态反馈以[交互清单](08-interaction-checklist.md)为准,组件命名可在接入真实框架后
调整并同步本文。 调整并同步本文。
+68
View File
@@ -0,0 +1,68 @@
---
id: T-220
title: 顺运宝 ERP 字段契约与凭证安全基线
phase: 2
deps:
- T-219
status: DOING
created: 2026-07-28
context_ref: 78dc595
work_branch: null
write_paths:
- .gitignore
- shunyunbaoerp_single.py
- docs/integrations/**
- docs/tasks/T-220.md
- docs/current-state.md
---
## 问题 / 背景
采购资料将以顺运宝 ERP 货运单为主要来源。现有单文件脚本证明了验证码登录、
Cookie 会话、按“全部单号”查询、按 stock id 批量读取详情的协议,但运行入口含
明文账号/密码/订单号,并会把完整结果写文件、打印到终端。货运响应包含收件人、
电话、地址、金额和商品信息,不能直接进入 Git、普通日志、VLM 或采购任务。
ERP 详情的 `details[]` 才是商品级来源;一个货运头可能有多个明细。必须先冻结
`stock.id -> detail.id -> details[].id` 的身份和字段映射,再开发导入链路。
## 关联需求与交互
- 功能:F-011、F-012
- 用户故事:US-011、US-012
- 交互:IX-012、IX-013
- 架构/API:ERP Connector、货运来源数据模型和内部安全边界
## 方案
1. 清除单文件脚本中的明文账号、密码和固定订单号,只允许环境变量或交互输入。
2. 查询结果默认只写被忽略的 `.local/`,控制台只输出数量和匿名结果文件位置。
3. 新增顺运宝集成字段契约,记录已由本地 HAR/脱敏结构确认的端点、查询关系和字段,
不复制 HAR、Cookie、JWT、真实订单号或个人信息。
4. 定义最小规范化对象:
- 货运单身份:`source_system + stock.id`
- 商品明细身份:`source_system + stock.id + details[].id`
- 待采购字段:标题、原始规格、`sku/variationSku`、正整数数量、`productThumb`
引用、采购状态和来源内容 hash
5. `productThumb` 当前只确认是 ERP 引用值,不猜测为公开 URL;图片未解析时必须
`NEEDS_IMAGE`,禁止生成采购任务。
6. 私有 HAR、验证码、查询结果、ERP session 和 connector 环境文件进入忽略规则。
## 验收要点
- [ ] Git 跟踪内容不含 ERP 账号、密码、Cookie、JWT、真实单号和货运 PII。
- [ ] 单文件脚本无硬编码凭证/订单号,不再向 stdout 输出完整响应。
- [ ] 字段契约覆盖一货运头多商品、重复同步、缺详情、缺图片和来源更新。
- [ ] 可用静态命令证明脚本可编译,安全扫描和仓库根验证通过;不访问线上 ERP。
## 边界
- 不提交本地 HAR 和 `freight_detail.json`。
- 不在本任务启动 connector、写数据库或创建采购任务。
- 不解释未确认的 ERP 数字状态含义,不自动 OCR 绕过验证码。
- 不因字段缺失猜测标题、SKU、数量或图片。
## 执行记录
- 2026-07-28:在 T-219 `78dc595` 后领取。静态读取本机单文件和独立 ERP 参考工程;
只提取协议结构和字段名,没有执行登录、线上查询或写操作。
+60
View File
@@ -0,0 +1,60 @@
---
id: T-221
title: 顺运宝精确单号 Connector
phase: 2
deps:
- T-220
status: TODO
created: 2026-07-28
context_ref: 78dc595
work_branch: null
write_paths:
- erp-connector/**
- scripts/start-erp-connector.bat
- docs/integrations/**
- docs/tasks/T-221.md
- docs/current-state.md
---
## 问题 / 背景
Go 后端不应在 Gin 请求里启动 Python,也不应保存 ERP 密码、Cookie 或 JWT。需要把
已验证的 Python 客户端收敛为仅监听 loopback、带服务密钥的内部 Connector。首版只
支持完整单号,先验证稳定读取和规范化,不提前做定时同步。
## 关联需求与交互
- 功能:F-011
- 用户故事:US-011
- 交互:IX-012
- 架构/API:ERP Connector 内部 API
## 方案
1. 采用 Python 3.10+、requests 和可选 FastAPI/uvicorn,复用本机已验证客户端结构;
不复制 HAR、真实响应或凭证。
2. Connector 默认 `127.0.0.1`,除健康检查外所有接口要求至少 32 字节服务密钥并
常量时间比较;ERP 密码仅从进程环境读取。
3. 保留人工/受控验证码登录,不承诺无人值守 OCR。读取型列表/详情请求才允许有界
重试;登录不自动重放。
4. `POST /v1/freight/query` 接受完整单号,查询 listTotal/list 和 listByStock,
按 stock id 去重并保留所有 `details[]`。
5. 响应经过规范化和 PII 最小化,只返回后续货运模块所需字段;错误不包含服务端
body、Cookie、JWT、账号、收件人、电话或地址。
## 验收要点
- [ ] 伪 ERP 响应覆盖验证码约束、登录、分页、重试、安全上限、多货运头和多商品。
- [ ] 精确单号响应具有稳定 schema,商品不被 dict 覆盖或错误关联。
- [ ] API Key 缺失/错误、未登录、未找到、ERP 超时和协议异常返回稳定状态。
- [ ] `pytest`/编译和无网络单测通过;启动脚本不包含秘密。
## 边界
- 不支持日期区间查询,属于 T-224。
- 不把 Connector 暴露到局域网,不提供 ERP 密码 Web 表单。
- 不持久化货运数据,不调用 Go 采购任务接口。
## 执行记录
- 2026-07-28:任务合约已冻结,等待 T-220。
+68
View File
@@ -0,0 +1,68 @@
---
id: T-222
title: 货运信息存储 API 与 Admin 页面
phase: 2
deps:
- T-221
status: TODO
created: 2026-07-28
context_ref: 78dc595
work_branch: null
write_paths:
- backend-api/cmd/**
- backend-api/internal/config/**
- backend-api/internal/domain/**
- backend-api/internal/usecase/**
- backend-api/internal/repository/sqlite/**
- backend-api/internal/transport/httpapi/**
- backend-api/internal/transport/webui/**
- backend-api/migrations/**
- docs/api.md
- docs/routes.md
- docs/tasks/T-222.md
- docs/current-state.md
---
## 问题 / 背景
现有 `purchase_tasks.source_ref` 只能防止任务重复创建,无法表示 ERP 同步、货运头、
多商品明细、来源版本和待处理异常。需要独立货运数据层,Admin 先查看来源事实,再
进入采购需求生成。
## 关联需求与交互
- 功能:F-011
- 用户故事:US-011
- 交互:IX-012
- 架构/API:`erp_sync_runs`、`freight_orders`、`freight_order_items`
## 方案
1. 新增 migration,按 creator scope 保存同步记录、货运单和商品明细。
2. 唯一键分别为 `(creator, source_system, external_stock_id)` 和
`(freight_order_id, external_item_id)`;重复响应按 canonical hash 幂等 upsert。
3. 只保存采购和审计必要字段;不保存收件人姓名、电话、详细地址、Cookie/JWT 或
未裁剪原始响应。
4. Admin 创建“按单号导入”同步记录,由后台有界调用 loopback Connector;请求返回
job id,不把验证码/ERP 延迟绑定到浏览器长请求。
5. 新增 `/freight` 列表、`/freight/import` 和 `/freight/{id}` 详情;页面展示来源
单号、店铺、ERP 时间、状态、明细数量、同步状态和可修复异常。
6. 进程重启时遗留 RUNNING job 转稳定失败;失败不写半批货运数据。
## 验收要点
- [ ] migration up/down/up 和降级保护通过。
- [ ] 重复导入不重复货运单/明细,来源变化产生版本/hash 更新和审计时间。
- [ ] 多商品、空详情、重复外部 ID、超限及 connector 失败均有集成测试。
- [ ] Admin API/SSR 鉴权、CSRF、no-store、响应式页面和 PII 缺失断言通过。
- [ ] `go test ./...`、race、vet 和根验证通过。
## 边界
- 不在本任务生成采购任务。
- 不自动下载 `productThumb`,只保存非秘密 ERP 引用。
- 不按 ERP 数字状态自动判断“应采购”,状态枚举确认属于 T-223。
## 执行记录
- 2026-07-28:任务合约已冻结,等待 T-221。
+67
View File
@@ -0,0 +1,67 @@
---
id: T-223
title: 待采购需求提取与任务生成
phase: 2
deps:
- T-222
status: TODO
created: 2026-07-28
context_ref: 78dc595
work_branch: null
write_paths:
- backend-api/internal/domain/**
- backend-api/internal/usecase/**
- backend-api/internal/repository/sqlite/**
- backend-api/internal/transport/httpapi/**
- backend-api/internal/transport/webui/**
- backend-api/migrations/**
- docs/api.md
- docs/routes.md
- docs/tasks/T-223.md
- docs/current-state.md
---
## 问题 / 背景
货运明细是外部可变事实,采购任务是执行时不可变快照。两者之间需要可复核的采购
需求层,避免 ERP 重同步直接修改运行任务,也避免缺图、含糊 SKU 或错误数量进入
Roubao 队列。
## 关联需求与交互
- 功能:F-012
- 用户故事:US-012
- 交互:IX-013
- 架构/API:`procurement_requests`、`purchase_task_sources`
## 方案
1. 每个货运商品明细按来源 revision 生成一条 procurement request,不合并多 SKU。
2. 确定性提取标题、规格/SKU 和正整数数量;优先保留原始 `productSpec`、
`sku/variationSku`,不调用 VLM 改写。
3. `productThumb` 仍无法解析时标记 `NEEDS_IMAGE`;Admin 使用现有受控图片上传并
绑定参考图后才能进入 `READY`。
4. Admin 在详情核对标题、SKU、数量和图片后显式生成 `purchase_task`。使用
procurement request id + revision 作为幂等来源,重复点击返回同一任务。
5. 来源更新不修改已有任务:未生成时追加新 revision;已生成后显示
`SOURCE_CHANGED` 并要求人员决定是否取消旧任务和生成新版本。
6. 被取消、已采购或状态语义未确认的 ERP 明细默认不可生成,允许的状态值必须来自
脱敏样本/人工配置,不根据数字猜测。
## 验收要点
- [ ] 一货运单多商品形成多条独立采购需求。
- [ ] 缺标题/SKU/数量/图片和来源状态不明时不能生成任务。
- [ ] 同一 revision 并发/重试只生成一个采购任务。
- [ ] 来源变化不覆写 PENDING/CLAIMED/RUNNING/终态任务。
- [ ] 生成任务可被现有 Roubao claim,原始字段和参考图 hash 一致。
## 边界
- 不让 VLM 推断或修改 ERP SKU/数量。
- 不自动决定取消旧采购任务。
- 不抓取未经确认的第三方图片 URL。
## 执行记录
- 2026-07-28:任务合约已冻结,等待 T-222。
+66
View File
@@ -0,0 +1,66 @@
---
id: T-224
title: ERP 日期增量同步
phase: 2
deps:
- T-223
status: TODO
created: 2026-07-28
context_ref: 78dc595
work_branch: null
write_paths:
- erp-connector/**
- backend-api/internal/domain/**
- backend-api/internal/usecase/**
- backend-api/internal/repository/sqlite/**
- backend-api/internal/transport/httpapi/**
- backend-api/internal/transport/webui/**
- backend-api/migrations/**
- docs/api.md
- docs/routes.md
- docs/tasks/T-224.md
- docs/current-state.md
---
## 问题 / 背景
精确单号适合第一版人工导入,但日常运营需要按时间发现新货运单。已验证 HAR 使用
`t_stock.created` 日期区间条件;增量同步必须处理分页过程中数据变化、重复窗口、
失败重试和服务端时区,不能简单保存“最后一页”。
## 关联需求与交互
- 功能:F-011、F-012
- 用户故事:US-011、US-012
- 交互:IX-012、IX-013
- 架构/API:日期查询、sync watermark 和重叠窗口
## 方案
1. Connector 增加日期区间请求,严格使用已验证字段:
`colName=created, op=0, type=3, optType=0`,日期使用 Asia/Shanghai。
2. 单次窗口最大 7 天,分页/总数均设上限,按 stock id 去重后批量取详情。
3. 后端保存 last successful watermark;每次从成功水位前回看 10 分钟/至少同一自然日,
依靠外部 ID + hash 去重更新。
4. 只有整批事务成功才推进水位;认证、网络、协议、超限或明细缺失时保留旧水位并
显示可重试错误。
5. Admin 提供手动日期范围和“同步至现在”,不在本任务引入系统级计划任务;定时器
后置到运行稳定后。
## 验收要点
- [ ] 日期 query 与脱敏 HAR 合约一致,时区和闭区间规则有测试。
- [ ] 重叠窗口、重复页、来源更新、空窗口和中途失败不丢单/不重复。
- [ ] 失败不推进 watermark,成功重放得到相同货运与采购需求集合。
- [ ] Admin 可查看范围、状态、计数和匿名错误,不显示 PII/秘密。
- [ ] Python、Go 全量测试、race/vet、根验证和响应式 SSR 验收通过。
## 边界
- 不做无人值守验证码 OCR、cron、消息队列或多 ERP 租户。
- 不承诺逆向页面接口 SLA;正式生产前仍需确认 ERP 开放 API 和数据使用权限。
- 不因时间同步自动领取或执行 Roubao 任务。
## 执行记录
- 2026-07-28:任务合约已冻结,等待 T-223。