feat(t225): freeze Go ERP protocol contract

This commit is contained in:
QiuSW
2026-07-29 09:21:32 +08:00
parent 11e480773a
commit c2f340d067
13 changed files with 836 additions and 31 deletions
+6 -3
View File
@@ -21,7 +21,7 @@
| 数据访问 | 标准库 `database/sql` | MVP 已定 | 领域层通过仓储接口访问,避免先引入 ORM 和代码生成复杂度。 |
| 数据迁移 | 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 工程,模板和静态资源随服务构建。 |
| ERP Connector | Python 3.10+、requests 2.31+;可选 FastAPI/uvicorn 内部服务 | T-220 至 T-222 已实现,T-224 扩展 | 复用已验证顺运宝协议客户端;只监听 loopback、服务密钥鉴权,ERP 凭证不进入 Go 后端。 |
| ERP 直连适配 | Go 标准库 `net/http`、`net/http/cookiejar` | T-225 契约已冻结,尚未切换运行时 | Go 侧固定顺运宝请求、分页、详情批量和最小字段归一化;当前 Python loopback Connector 仅在 T-228 前临时保留。 |
| 数据库 | SQLite | MVP 已定 | 单服务、单设备验证足够;多实例或并发提升前迁移 PostgreSQL。 |
| 图片/截图 | 后端受控本地文件目录 + `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。 |
@@ -167,5 +167,8 @@ T-205 已在该分层上增加独立 `LifecycleService` 与 SQLite immediate tra
PowerShell 等价环境变量,确保依赖没有暗中要求更高 Go 版本。
- handler 不直接写 SQL,repository 不依赖 Gin,domain/usecase 不导入具体数据库驱动。
- 密钥和设备令牌通过环境变量或本地忽略配置注入,不进入 Git。
- ERP 账号、密码、Cookie、JWT 和 Connector 服务密钥只通过环境变量/受控秘密注入;
Go 后端不保存 ERP 会话,Connector 不把完整响应或 PII 写普通日志。
- T-225 后 Go `internal/platform/shunyunbao` 固定同一套脱敏协议契约;T-226 以前不装配
直接会话,运行时仍使用临时 Connector。T-226 的会话只在进程内,不引入 Redis。
- ERP 账号、密码、Cookie、JWT、验证码和 Connector 服务密钥只通过环境变量/受控秘密
注入;不得进入 SQLite、浏览器、VLM、fixture 或普通日志。Go 适配器不得记录完整
响应或 PII。
+7 -1
View File
@@ -132,7 +132,7 @@ App 支持两个显式模式:
- `MANUAL_FIRST`:从原始标题/SKU 产生有界搜索词,由人员判断候选,不要求 VLM。
- `AI_ASSISTED`:使用 App 本地配置的 OpenAI 兼容 provider 做需求提取和候选评估。
### 2.4 顺运宝 ERP Connector
### 2.4 顺运宝 ERP 适配层
Connector 是外部系统防腐层,不属于采购任务状态机:
@@ -155,6 +155,12 @@ Admin 创建 sync run
- ERP 接口由页面协议观察得到,正式生产前需确认开放 API、服务账号、调用频率、
缓存和个人信息处理权限。
T-225 已在 `internal/platform/shunyunbao` 冻结直接 Go 实现的协议常量、请求 header、
完整单号/日期范围条件、分页、详情批量和 allowlist 归一化;它尚未接入运行时。货运
用例只识别来源中立的“未配置、会话失效、未找到、协议异常、暂时不可用”错误,不依赖
Connector 包。T-226 负责单进程内受锁保护的验证码会话,T-227 才将异步 sync worker
从 loopback Connector 切换到 Go source,T-228 删除旧 Python 进程和服务密钥。
模式在 execution 开始时固定并写入结果;AI 失败后只能由人员明确切换,不能静默降级。
App 同时固定 provider ID、model、prompt/schema version 和证据 SHA-256,作为非秘密
provenance 回传。Key、Authorization、完整 endpoint 和供应商原始响应正文不回传。
+5
View File
@@ -113,6 +113,9 @@
recovery 不得把 Authorization、Cookie、panic 或请求正文写普通日志。
- SQLite 数据文件必须位于被忽略目录,启用 foreign keys、有限 busy timeout 和
WAL;连接由进程入口显式关闭,migration 使用固定版本和受控 SQL 文件。
- ERP adapter 只能把版本化 allowlist 归一化对象交给 `FreightSource`;收件人、电话、
地址、完整响应、Cookie、JWT、账号、密码和验证码不得进入领域对象、错误、日志、
fixture、SQLite、浏览器或 VLM。验证码必须由人员输入,禁止 OCR、猜测或重放。
## 7. 安全与隐私
@@ -128,6 +131,8 @@
`private-fixtures/` 等被忽略目录;测试使用脱敏 fixture。
- 普通日志不得输出完整蝦皮订单号、店铺名或本机原图绝对路径。
- 日志默认脱敏,不记录 Authorization、Cookie、密码、设备令牌或完整地址。
- ERP 外部 URL 必须在配置层限制为完整 HTTPS origin;仅离线 `httptest` 可使用 HTTP。
Cookie jar 和 token 只能停留在受锁保护的进程内会话,进程重启后要求人工重新登录。
- 上传文件限制媒体类型、大小和解码结果,随机化服务端文件名。
- 不绕过第三方平台限制、验证码、风控或系统权限。
- 不可逆动作必须由明确需求、服务端授权、App 确认和幂等保护共同允许。
+12 -7
View File
@@ -4,8 +4,8 @@
## 当前快照
- 日期:2026-07-28
- 阶段:T-220 至 T-224 ERP 货运接入闭环已完成
- 日期:2026-07-29
- 阶段:T-225 Go 直连 ERP 协议与安全边界已完成;运行时切换待 T-226 至 T-228
- Git:当前分支为 `main`;T-001 至 T-004、T-101 至 T-104、T-201 至 T-219
均按文档提交、实现提交的顺序纳入历史
- 生产代码:`android-buyer/` 已接入 Roubao Android 源码
@@ -17,6 +17,10 @@
- ERP 货运:Go 后端通过仅限 loopback、服务密钥鉴权的 Python Connector 异步按
完整单号同步;v12 保存同步记录、货运头和全部明细,canonical hash 控制 revision,
Admin 已有 `/freight`、`/freight/import`、`/freight/{id}` 与对应 JSON API。
- ERP Go 迁移:T-225 已用脱敏 fixture 固定 `internal/platform/shunyunbao` 的 header、
单号/日期查询、分页、详情批量和字段 allowlist,并使货运用例依赖来源中立错误;尚未
发起真实 ERP 请求,也未切换 Python Connector 运行时。T-226 将加入单进程人工验证码
会话,T-227 才切换异步货运 source,T-228 删除旧 Connector。
- ERP 增量同步:v14 支持 Asia/Shanghai 创建日期闭区间和“同步至现在”,Connector
单窗最多 7 天,后端对较长水位范围切窗并从成功水位前 10 分钟所在自然日回看。
货运落库、同步成功和水位推进同事务完成;失败与较旧范围成功不推进水位。Admin
@@ -28,7 +32,8 @@
- Android Studio:未安装;`winget` 静默安装卡住后已终止,不阻塞命令行构建
- 测试:T-219 Android Debug/Release 单元测试与构建和根 `init.ps1` 通过;
Debug APK `1.4.16 (21)` 已覆盖安装到 PKG110
- 后端测试:T-224 运行 `go test ./...`、`go test -race ./...`、`go vet ./...`;
- 后端测试:T-225 运行 `go test ./...`、`go test -race ./...`、`go vet ./...` 和三个 Go
入口构建;
覆盖 v14 上下迁移、7 天切窗、水位重叠、中途失败、空窗口、重复页、来源 revision、
水位事务/不回退、Admin API/SSR 和 Connector 严格响应窗口;Python 22 项伪响应
测试通过,未访问真实 ERP
@@ -183,11 +188,11 @@
## 任务摘要
- 已完成:T-001 至 T-004、T-101 至 T-104、T-201 至 T-219。
- 已完成:另含 T-220 至 T-224 ERP 契约、Connector、货运存储、采购需求生成和
日期增量同步。
- 已完成:另含 T-220 至 T-225 ERP 契约、Connector、货运存储、采购需求生成、日期
增量同步和 Go 直连协议安全边界。
- 进行中:无。
- 下一步:T-225 至 T-228 将把顺运宝 Python Connector 收敛到 Go 后端;真实 ERP
上线前仍需确认开放 API、数据使用权限并由人员完成验证码登录。
- 下一步:T-226 建立 Go 后端内存会话和 Admin 人工验证码登录;真实 ERP 上线前仍需
确认开放 API、数据使用权限并由人员完成验证码登录。
## 当前可运行内容
+19
View File
@@ -21,6 +21,25 @@
接口来自 ERP 页面协议,不是已确认的开放 API。生产使用前必须确认厂商授权、请求
频率、服务账号和个人信息处理规则。
## Go 直连迁移契约(T-225)
T-225 在 `backend-api/internal/platform/shunyunbao` 用脱敏 fixture 固定以下内容,尚未
改变当前 Python Connector 运行时路径:
- 基础请求 header 固定 `Accept`、`Origin`、`Referer`、`User-Agent` 和
`X-Requested-With`;base URL 必须是无 userinfo、query、fragment 或路径的 origin。
- 单号条件为 `t_stock.allcode`、`op=6`、`type=0`、`optType=1`;日期范围为
`t_stock.created`、`op=0`、`type=3`、`optType=0`,单个 ERP 窗口最多 7 个自然日。
- `listTotal`、`list` 共享 `history=0`、`length`、`start`、`pageIndex`、`store=false`、
已验证 columns 和单一 `queries`;每页最多 500 条。
- `listByStock?hist=0` 每批最多 100 个去重后的正整数 stock id,详情 `id` 必须与列表
`stock.id` 一致。
- 所有结果必须经 Go allowlist 归一化;fixture 专门含收件信息、Cookie/JWT 标记值,
测试断言它们不会出现在输出或错误里。
Go 直连的验证码、登录和 Cookie jar 属于 T-226。不得用本地 OCR 或 Redis 取代人工
验证码流程;真实线上请求不属于自动化测试。
## 身份和规范字段
### 货运单
+15 -5
View File
@@ -4,7 +4,7 @@ title: 冻结 Go 直连 ERP 协议与安全边界
phase: 2
deps:
- T-224
status: TODO
status: DONE
created: 2026-07-29
context_ref: d62a4af
work_branch: null
@@ -14,6 +14,9 @@ write_paths:
- docs/04-architecture.md
- docs/05-coding-rules.md
- docs/integrations/shunyunbao-contract.md
- docs/current-state.md
- backend-api/internal/domain/freight_source_errors.go
- backend-api/internal/usecase/freight_service.go
- backend-api/internal/platform/shunyunbao/**
- backend-api/internal/platform/erpconnector/**
---
@@ -47,10 +50,10 @@ Python 环境、loopback 端口和与 Go 后端相同的服务密钥。当前 `E
## 验收要点
- [ ] Go fixture 测试固定请求 header、查询条件、分页、详情批量和 allowlist 归一化。
- [ ] 负向测试证明 PII、Cookie、JWT、账号、密码和验证码不会出现在输出或错误中。
- [ ] 取消 OCR、Redis 和 Python HTTP 服务作为 Go 第一版运行时依赖的设计。
- [ ] 不访问线上 ERP;现有 Python Connector 仍可继续运行,货运导入行为不改变。
- [x] Go fixture 测试固定请求 header、查询条件、分页、详情批量和 allowlist 归一化。
- [x] 负向测试证明 PII、Cookie、JWT、账号、密码和验证码不会出现在输出或错误中。
- [x] 第一版 Go 设计不依赖 OCR、Redis 或 Python HTTP 服务。
- [x] 未访问线上 ERP;现有 Python Connector 仍可继续运行,货运导入行为不改变。
## 边界
@@ -61,3 +64,10 @@ Python 环境、loopback 端口和与 Go 后端相同的服务密钥。当前 `E
## 执行记录
- 2026-07-29:由 `d62a4af` 创建,等待 T-224 后开始。
- 2026-07-29:开始实施;已核对现有脱敏 Python 契约和 T-224 异步导入边界,未访问线上 ERP。
- 2026-07-29:新增 Go 协议常量、header/payload 构造、脱敏 fixture 归一化与来源中立错误;
运行时仍装配 Python Connector,未改 Admin 页面、schema 或同步异步边界。
- 验证:在 `backend-api/` 执行 `$env:GOTOOLCHAIN='local'; go test ./...; go test -race ./...;`
`go vet ./...; go build ./cmd/api; go build ./cmd/migrate; go build ./cmd/authctl`,全部通过;
未访问线上 ERP。
- 未验证项:真实顺运宝登录和查询有意留给 T-226/T-227,并需要人员配置凭证和完成验证码。