1330 lines
42 KiB
Markdown
1330 lines
42 KiB
Markdown
# Gateway Integration 并行执行计划
|
|
|
|
## TL;DR
|
|
|
|
> **快速摘要**: 实现Gateway API统一封装,提供14个物联网卡和设备管理接口的类型安全封装,支持AES-128-ECB加密+MD5签名认证机制。
|
|
>
|
|
> **交付物**:
|
|
> - internal/gateway/ 包(完整的Gateway客户端)
|
|
> - 14个API接口封装(流量卡7个+设备7个)
|
|
> - 配置集成(GatewayConfig+环境变量)
|
|
> - 错误码定义(1110-1119)
|
|
> - 单元测试(覆盖率≥90%)
|
|
> - 集成测试(验证真实Gateway API)
|
|
>
|
|
> **预计工作量**: 120分钟(2小时)
|
|
> **并行执行**: YES - 6个波次,最多4个任务并行
|
|
> **关键路径**: 加密工具 → Client结构 → API封装 → 单元测试 → Service集成 → 集成测试
|
|
|
|
---
|
|
|
|
## 上下文
|
|
|
|
### 原始需求
|
|
实现Gateway API统一封装,解决当前调用逻辑分散、加密签名重复实现的问题,提供类型安全的接口和统一的错误处理。
|
|
|
|
### 背景调研总结
|
|
|
|
#### 1. 项目架构模式(已验证)
|
|
- **Bootstrap模式**: 6步初始化(Stores→Callbacks→Services→Admin→Middlewares→Handlers)
|
|
- **依赖注入**: Dependencies结构 → main.go初始化 → Service构造器
|
|
- **Config管理**: 层级结构 + JUNHONG_前缀环境变量 + 双层验证
|
|
- **Error处理**: 错误码范围(1000-1999/2000-2999) + errors.New/Wrap
|
|
|
|
#### 2. 测试模式(已验证)
|
|
- **核心工具**: NewTestTransaction(自动回滚) + GetTestRedis(全局连接)
|
|
- **集成测试**: NewIntegrationTestEnv(完整环境) + AsSuperAdmin/AsUser
|
|
- **执行方式**: `source .env.local && go test`
|
|
- **覆盖率要求**: Service层≥90%
|
|
|
|
#### 3. AES-ECB加密(已调研)
|
|
- **实现方式**: 手动实现cipher.BlockMode接口(~50行)
|
|
- **参考代码**: TiDB的aes.go实现
|
|
- **PKCS5Padding**: 标准填充算法(验证所有字节)
|
|
- **MD5密钥**: crypto/md5.Sum()返回[16]byte
|
|
- **Base64编码**: encoding/base64.StdEncoding
|
|
|
|
### Metis预审(gap分析)
|
|
无 - 本计划由Prometheus生成,Metis审查在plan生成后进行。
|
|
|
|
---
|
|
|
|
## 工作目标
|
|
|
|
### 核心目标
|
|
封装Gateway API为统一的能力模块,提供类型安全、配置化、可测试的接口调用能力。
|
|
|
|
### 具体交付物
|
|
- [ ] `internal/gateway/client.go` - Gateway客户端主体
|
|
- [ ] `internal/gateway/crypto.go` - 加密/签名工具
|
|
- [ ] `internal/gateway/flow_card.go` - 流量卡7个API
|
|
- [ ] `internal/gateway/device.go` - 设备7个API
|
|
- [ ] `internal/gateway/models.go` - 请求/响应DTO
|
|
- [ ] `internal/gateway/client_test.go` - 单元+集成测试
|
|
- [ ] `pkg/config/config.go` - GatewayConfig集成
|
|
- [ ] `pkg/errors/codes.go` - Gateway错误码(1110-1119)
|
|
- [ ] `internal/bootstrap/bootstrap.go` - Gateway客户端初始化
|
|
- [ ] `docs/gateway-client-usage.md` - 使用文档
|
|
|
|
### 定义完成(Definition of Done)
|
|
- [ ] 所有14个Gateway API接口成功封装
|
|
- [ ] 加密/签名验证通过(与Gateway文档一致)
|
|
- [ ] 错误处理覆盖所有异常场景
|
|
- [ ] 单元测试覆盖率≥90%
|
|
- [ ] 集成测试验证真实Gateway API调用
|
|
- [ ] 配置通过环境变量成功加载
|
|
- [ ] 依赖注入到Service层成功
|
|
- [ ] 文档完整(使用示例、错误码说明)
|
|
|
|
### 必须满足
|
|
- 所有14个API接口封装完成
|
|
- AES-128-ECB加密正确(密钥=MD5(appSecret))
|
|
- MD5签名正确(参数字母序+大写)
|
|
- 配置验证逻辑完整
|
|
- Bootstrap依赖注入正确
|
|
|
|
### 禁止包含(Guardrails)
|
|
- ❌ 跳过tasks.md中的任何任务
|
|
- ❌ 合并或简化任务执行
|
|
- ❌ 使用Java风格的过度抽象
|
|
- ❌ 硬编码配置(必须使用环境变量)
|
|
- ❌ 直接使用fmt.Errorf(必须用errors.New/Wrap)
|
|
- ❌ 参数验证失败返回底层错误详情
|
|
- ❌ 使用非中文注释
|
|
|
|
---
|
|
|
|
## 验证策略
|
|
|
|
### 测试决策
|
|
- **测试基础设施**: ✅ 已存在(testutils + NewIntegrationTestEnv)
|
|
- **测试框架**: bun test(实际使用go test)
|
|
- **测试策略**: TDD(测试先行)
|
|
|
|
### 测试结构
|
|
|
|
#### 单元测试(internal/gateway/client_test.go)
|
|
每个任务遵循TDD流程:
|
|
|
|
**加密/签名测试**:
|
|
1. **RED**: 编写测试用例
|
|
- 测试文件: `internal/gateway/client_test.go`
|
|
- 测试函数: `TestAESEncrypt`, `TestGenerateSign`
|
|
- 预期: FAIL(函数不存在)
|
|
|
|
2. **GREEN**: 实现最小代码
|
|
- 实现: `crypto.go`中的aesEncrypt, generateSign
|
|
- 运行: `go test -v ./internal/gateway -run TestAES`
|
|
- 预期: PASS
|
|
|
|
3. **REFACTOR**: 优化代码
|
|
- 清理重复代码
|
|
- 添加注释
|
|
- 预期: PASS(测试仍然通过)
|
|
|
|
**API接口测试**:
|
|
1. **RED**: 测试QueryCardStatus
|
|
- 测试: 构造mock响应,验证解析逻辑
|
|
- 预期: FAIL
|
|
|
|
2. **GREEN**: 实现QueryCardStatus
|
|
- 实现: flow_card.go
|
|
- 预期: PASS
|
|
|
|
3. **REFACTOR**: 优化
|
|
- 预期: PASS
|
|
|
|
#### 集成测试(client_test.go)
|
|
验证真实Gateway API调用:
|
|
|
|
```go
|
|
func TestIntegration_QueryCardStatus(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("跳过集成测试")
|
|
}
|
|
|
|
// 使用真实配置
|
|
cfg := config.Get()
|
|
client := gateway.NewClient(
|
|
cfg.Gateway.BaseURL,
|
|
cfg.Gateway.AppID,
|
|
cfg.Gateway.AppSecret,
|
|
).WithTimeout(30 * time.Second)
|
|
|
|
// 调用真实API
|
|
resp, err := client.QueryCardStatus(ctx, &gateway.CardStatusReq{
|
|
CardNo: "898608070422D0010269",
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
require.NotNil(t, resp)
|
|
require.NotEmpty(t, resp.ICCID)
|
|
}
|
|
```
|
|
|
|
**验证命令**:
|
|
```bash
|
|
# 单元测试
|
|
source .env.local && go test -v ./internal/gateway -run TestAES
|
|
source .env.local && go test -v ./internal/gateway -run TestGenerate
|
|
|
|
# 集成测试
|
|
source .env.local && go test -v ./internal/gateway -run TestIntegration
|
|
|
|
# 覆盖率
|
|
source .env.local && go test -cover ./internal/gateway
|
|
```
|
|
|
|
---
|
|
|
|
## 执行策略
|
|
|
|
### 并行执行波次
|
|
|
|
系统使用严格的依赖管理,最大化并行执行效率:
|
|
|
|
```
|
|
Wave 1 (立即启动,无依赖):
|
|
├── Task 1.1: 创建目录结构
|
|
├── Task 1.4: DTO定义
|
|
├── Task 3.1: Gateway配置
|
|
└── Task 3.2: Gateway错误码
|
|
|
|
Wave 2 (依赖: Wave 1):
|
|
└── Task 1.2: 加密/签名工具
|
|
|
|
Wave 3 (依赖: Task 1.2):
|
|
└── Task 1.3: Client基础结构
|
|
|
|
Wave 4 (依赖: Task 1.3):
|
|
├── Task 2.1: 流量卡API
|
|
├── Task 2.2: 设备API
|
|
└── Task 4.1: Bootstrap初始化
|
|
|
|
Wave 5 (依赖: Wave 4):
|
|
├── Task 2.3: 单元测试
|
|
└── Task 4.2: Service集成
|
|
|
|
Wave 6 (依赖: Wave 5):
|
|
├── Task 5.1: 集成测试
|
|
└── Task 5.2: 文档更新
|
|
|
|
关键路径: 1.2 → 1.3 → 2.1/2.2 → 2.3 → 4.2 → 5.1
|
|
并行加速: ~40%性能提升(相比顺序执行)
|
|
```
|
|
|
|
### 依赖矩阵
|
|
|
|
| Task | 依赖任务 | 阻塞任务 | 可并行任务 |
|
|
|------|---------|---------|-----------|
|
|
| 1.1 | 无 | 无 | 1.4, 3.1, 3.2 |
|
|
| 1.2 | 1.1 | 1.3 | 1.4, 3.1, 3.2 |
|
|
| 1.3 | 1.2 | 2.1, 2.2, 4.1 | 无 |
|
|
| 1.4 | 无 | 2.1, 2.2 | 1.1, 1.2, 3.1, 3.2 |
|
|
| 2.1 | 1.3, 1.4 | 2.3 | 2.2, 4.1 |
|
|
| 2.2 | 1.3, 1.4 | 2.3 | 2.1, 4.1 |
|
|
| 2.3 | 2.1, 2.2 | 5.1 | 4.2 |
|
|
| 3.1 | 无 | 4.1 | 1.1, 1.2, 1.4, 3.2 |
|
|
| 3.2 | 无 | 无 | 1.1, 1.2, 1.4, 3.1 |
|
|
| 4.1 | 1.3, 3.1 | 4.2 | 2.1, 2.2 |
|
|
| 4.2 | 4.1 | 5.1 | 2.3 |
|
|
| 5.1 | 2.3, 4.2 | 无 | 5.2 |
|
|
| 5.2 | 无 | 无 | 5.1 |
|
|
|
|
### Agent调度建议
|
|
|
|
| Wave | 任务组 | 推荐Category | 推荐Skills |
|
|
|------|--------|-------------|-----------|
|
|
| 1 | 1.1, 1.4, 3.1, 3.2 | quick | 无 |
|
|
| 2 | 1.2 | ultrabrain | 无 |
|
|
| 3 | 1.3 | unspecified-high | 无 |
|
|
| 4 | 2.1, 2.2, 4.1 | unspecified-high | 无 |
|
|
| 5 | 2.3, 4.2 | unspecified-high | 无 |
|
|
| 6 | 5.1, 5.2 | quick | 无 |
|
|
|
|
---
|
|
|
|
## TODOs
|
|
|
|
> 实现+测试=一个任务。每个任务必须包含:推荐Agent Profile + 并行化信息。
|
|
|
|
### Phase 1: 基础结构搭建
|
|
|
|
- [ ] **1.1. 创建Gateway包目录结构**
|
|
|
|
**要做什么**:
|
|
- 创建`internal/gateway/`目录
|
|
- 创建占位文件:`client.go`, `crypto.go`, `models.go`, `flow_card.go`, `device.go`
|
|
- 每个文件添加package声明和基础注释
|
|
|
|
**禁止做什么**:
|
|
- 不要实现任何逻辑(只创建文件骨架)
|
|
- 不要添加import语句(后续任务添加)
|
|
|
|
**推荐Agent Profile**:
|
|
- **Category**: `quick`
|
|
- 理由: 简单的文件创建操作,无复杂逻辑
|
|
- **Skills**: 无
|
|
- 理由: 目录创建是通用操作,不需要专项技能
|
|
- **Skills评估但省略**:
|
|
- `api-routing`: 域不重叠(这是客户端代码,非API路由)
|
|
- `model-standards`: 域不重叠(DTO定义在Task 1.4)
|
|
|
|
**并行化**:
|
|
- **可并行运行**: YES
|
|
- **并行组**: Wave 1(与1.4, 3.1, 3.2并行)
|
|
- **阻塞任务**: 无
|
|
- **被阻塞**: 无(可立即启动)
|
|
|
|
**参考**:
|
|
- 项目结构模式: `/internal/service/account/` (类似的service包结构)
|
|
- Go包命名规范: 小写、单数、无下划线
|
|
|
|
**验收标准**:
|
|
- [ ] 目录`internal/gateway/`创建成功
|
|
- [ ] 5个.go文件创建成功(client, crypto, models, flow_card, device)
|
|
- [ ] 每个文件包含`package gateway`声明
|
|
- [ ] 每个文件包含中文注释说明用途
|
|
- [ ] `go build ./internal/gateway`编译通过(即使是空包)
|
|
|
|
**提交**: NO(与后续任务合并提交)
|
|
|
|
---
|
|
|
|
- [ ] **1.2. 实现加密/签名工具函数**
|
|
|
|
**要做什么**:
|
|
- 在`crypto.go`中实现`aesEncrypt`函数(AES-128-ECB + PKCS5Padding + Base64)
|
|
- 实现`generateSign`函数(MD5签名,大写输出)
|
|
- 添加单元测试验证加密/签名正确性
|
|
|
|
**禁止做什么**:
|
|
- 不要使用第三方加密库(必须用标准库)
|
|
- 不要跳过PKCS5填充验证(必须验证所有字节)
|
|
- 不要使用小写MD5输出(必须大写)
|
|
|
|
**推荐Agent Profile**:
|
|
- **Category**: `ultrabrain`
|
|
- 理由: 加密算法实现需要高精度,涉及字节操作和安全性
|
|
- **Skills**: 无
|
|
- 理由: 加密是通用算法,已有TiDB参考代码
|
|
- **Skills评估但省略**:
|
|
- `api-routing`: 域不重叠(这是工具函数,非API)
|
|
- `dto-standards`: 域不重叠(这是加密,非DTO)
|
|
|
|
**并行化**:
|
|
- **可并行运行**: NO(Wave 1必须先完成)
|
|
- **并行组**: Wave 2(独立任务)
|
|
- **阻塞任务**: 1.3(Client需要加密函数)
|
|
- **被阻塞**: 1.1(需要crypto.go文件存在)
|
|
|
|
**参考**:
|
|
- **加密实现**: TiDB的aes.go(ECB模式实现)
|
|
- **PKCS5Padding**: Lancet库的padding.go
|
|
- **MD5密钥**: `crypto/md5.Sum([]byte(appSecret))`返回`[16]byte`
|
|
- **Base64**: `encoding/base64.StdEncoding.EncodeToString()`
|
|
- **签名格式**: `appId=xxx&data=xxx×tamp=xxx&key=appSecret`
|
|
- **测试模式**: `/internal/service/package/service_test.go`(table-driven tests)
|
|
|
|
**验收标准**:
|
|
|
|
**TDD流程**:
|
|
- [ ] **RED**: 编写`TestAESEncrypt`测试用例
|
|
- 测试文件: `internal/gateway/crypto_test.go`
|
|
- 测试数据: 已知明文+appSecret,验证Base64输出
|
|
- 命令: `go test -v ./internal/gateway -run TestAESEncrypt`
|
|
- 预期: FAIL(函数不存在)
|
|
|
|
- [ ] **GREEN**: 实现`aesEncrypt`函数
|
|
- 步骤1: MD5(appSecret)生成16字节密钥
|
|
- 步骤2: AES-128-ECB加密(手动实现BlockMode)
|
|
- 步骤3: PKCS5填充
|
|
- 步骤4: Base64编码
|
|
- 命令: `go test -v ./internal/gateway -run TestAESEncrypt`
|
|
- 预期: PASS
|
|
|
|
- [ ] **REFACTOR**: 优化代码
|
|
- 添加详细中文注释
|
|
- 提取常量(如BlockSize=16)
|
|
- 命令: `go test -v ./internal/gateway -run TestAESEncrypt`
|
|
- 预期: PASS(测试仍通过)
|
|
|
|
- [ ] **RED**: 编写`TestGenerateSign`测试用例
|
|
- 验证签名格式为32位大写十六进制
|
|
- 验证参数字母序正确
|
|
- 预期: FAIL
|
|
|
|
- [ ] **GREEN**: 实现`generateSign`函数
|
|
- 步骤1: 拼接字符串(appId→data→timestamp)
|
|
- 步骤2: 追加`&key=appSecret`
|
|
- 步骤3: MD5加密
|
|
- 步骤4: 转大写十六进制
|
|
- 预期: PASS
|
|
|
|
- [ ] **REFACTOR**: 优化签名函数
|
|
- 预期: PASS
|
|
|
|
**自动化验证**:
|
|
```bash
|
|
# 编译检查
|
|
go build ./internal/gateway
|
|
# 预期: 成功编译,无错误
|
|
|
|
# 单元测试
|
|
source .env.local && go test -v ./internal/gateway -run TestAES
|
|
# 预期: PASS, 测试覆盖率 ≥ 90%
|
|
|
|
source .env.local && go test -v ./internal/gateway -run TestGenerate
|
|
# 预期: PASS, 签名输出32位大写
|
|
|
|
# 覆盖率检查
|
|
source .env.local && go test -cover ./internal/gateway
|
|
# 预期: 覆盖率 ≥ 90%
|
|
```
|
|
|
|
**提交**: NO(与Phase 1合并提交)
|
|
|
|
---
|
|
|
|
- [ ] **1.3. 实现Gateway客户端基础结构**
|
|
|
|
**要做什么**:
|
|
- 在`client.go`中定义`Client`结构体(baseURL, appID, appSecret, httpClient, timeout)
|
|
- 实现`NewClient`构造函数(配置HTTP Keep-Alive)
|
|
- 实现`WithTimeout`方法(支持链式调用)
|
|
- 实现`doRequest`统一请求方法(加密→签名→HTTP→解密)
|
|
|
|
**禁止做什么**:
|
|
- 不要在doRequest中处理业务逻辑(只处理加密和HTTP)
|
|
- 不要硬编码超时时间(通过WithTimeout配置)
|
|
- 不要忽略Context超时(必须判断ctx.Err())
|
|
|
|
**推荐Agent Profile**:
|
|
- **Category**: `unspecified-high`
|
|
- 理由: 核心架构代码,需要仔细设计并发安全和错误处理
|
|
- **Skills**: 无
|
|
- 理由: HTTP客户端是通用模式,项目中有类似实现
|
|
- **Skills评估但省略**:
|
|
- `api-routing`: 域不重叠(这是HTTP客户端,非路由)
|
|
|
|
**并行化**:
|
|
- **可并行运行**: NO(依赖1.2)
|
|
- **并行组**: Wave 3(独立任务)
|
|
- **阻塞任务**: 2.1, 2.2, 4.1(所有API都依赖Client)
|
|
- **被阻塞**: 1.2(需要加密函数)
|
|
|
|
**参考**:
|
|
- **HTTP客户端**: `net/http.Client`配置Keep-Alive
|
|
- **Context超时**: `http.NewRequestWithContext(ctx, ...)`
|
|
- **JSON序列化**: `sonic.Marshal/Unmarshal`
|
|
- **错误处理**: `pkg/errors/errors.go`(New/Wrap模式)
|
|
- **类似实现**: `/pkg/auth/token.go`(TokenManager的HTTP调用)
|
|
|
|
**验收标准**:
|
|
|
|
**TDD流程**:
|
|
- [ ] **RED**: 编写`TestNewClient`测试
|
|
- 验证Client初始化正确
|
|
- 验证httpClient配置
|
|
- 预期: FAIL
|
|
|
|
- [ ] **GREEN**: 实现NewClient和WithTimeout
|
|
- 配置http.Client(Transport + Timeout)
|
|
- 预期: PASS
|
|
|
|
- [ ] **REFACTOR**: 优化结构
|
|
- 预期: PASS
|
|
|
|
- [ ] **RED**: 编写`TestDoRequest_Success`测试
|
|
- Mock HTTP响应
|
|
- 验证加密→签名→请求流程
|
|
- 预期: FAIL
|
|
|
|
- [ ] **GREEN**: 实现doRequest方法
|
|
- 步骤1: 序列化业务数据(sonic.Marshal)
|
|
- 步骤2: AES加密(调用aesEncrypt)
|
|
- 步骤3: 生成签名(调用generateSign)
|
|
- 步骤4: 构建请求体(appId, data, sign, timestamp)
|
|
- 步骤5: 发送HTTP POST
|
|
- 步骤6: 解析响应(GatewayResponse)
|
|
- 步骤7: 检查业务状态码
|
|
- 预期: PASS
|
|
|
|
- [ ] **REFACTOR**: 错误处理优化
|
|
- 网络错误→CodeGatewayError
|
|
- 超时错误→CodeGatewayTimeout
|
|
- 响应格式错误→CodeGatewayInvalidResp
|
|
- 预期: PASS
|
|
|
|
**自动化验证**:
|
|
```bash
|
|
# 编译检查
|
|
go build ./internal/gateway
|
|
# 预期: 成功编译
|
|
|
|
# 单元测试
|
|
source .env.local && go test -v ./internal/gateway -run TestNewClient
|
|
# 预期: PASS, Client初始化正确
|
|
|
|
source .env.local && go test -v ./internal/gateway -run TestDoRequest
|
|
# 预期: PASS, 请求流程完整
|
|
|
|
# 错误处理测试
|
|
source .env.local && go test -v ./internal/gateway -run TestDoRequest_Error
|
|
# 预期: PASS, 所有错误场景覆盖
|
|
```
|
|
|
|
**提交**: NO(与Phase 1合并提交)
|
|
|
|
---
|
|
|
|
- [ ] **1.4. 定义请求/响应DTO**
|
|
|
|
**要做什么**:
|
|
- 在`models.go`中定义`GatewayResponse`通用响应结构
|
|
- 定义流量卡DTO:`CardStatusReq/Resp`, `FlowQueryReq`, `FlowUsageResp`, `CardOperationReq`
|
|
- 定义设备DTO:`DeviceInfoReq/Resp`, `SpeedLimitReq`, `WiFiReq`, `SwitchCardReq`, `DeviceOperationReq`
|
|
- 添加JSON标签和验证标签
|
|
|
|
**禁止做什么**:
|
|
- 不要省略description注释(每个字段必须有中文说明)
|
|
- 不要使用驼峰JSON字段(必须与Gateway文档一致)
|
|
- 不要省略validate标签(必填字段必须标记)
|
|
|
|
**推荐Agent Profile**:
|
|
- **Category**: `quick`
|
|
- 理由: 结构体定义为机械性工作,遵循DTO规范即可
|
|
- **Skills**: `dto-standards`
|
|
- 理由: 需要遵循项目DTO规范(description标签、验证标签)
|
|
- **Skills评估但省略**:
|
|
- `model-standards`: 域不重叠(这是DTO,非数据库Model)
|
|
- `api-routing`: 域不重叠(这是请求响应结构,非路由)
|
|
|
|
**并行化**:
|
|
- **可并行运行**: YES
|
|
- **并行组**: Wave 1(与1.1, 3.1, 3.2并行)
|
|
- **阻塞任务**: 2.1, 2.2(API方法需要DTO)
|
|
- **被阻塞**: 无(可立即启动)
|
|
|
|
**参考**:
|
|
- **DTO规范**: `docs/dto-standards.md`或`AGENTS.md#DTO规范`
|
|
- **JSON标签**: `json:"cardNo"` (与Gateway文档一致)
|
|
- **验证标签**: `validate:"required"`
|
|
- **示例DTO**: `/internal/model/dto/package.go`
|
|
- **Gateway文档**: design.md中的请求/响应示例
|
|
|
|
**验收标准**:
|
|
- [ ] GatewayResponse定义完整(code, msg, data, trace_id)
|
|
- [ ] 流量卡DTO定义完整(7个API对应的Req/Resp)
|
|
- [ ] 设备DTO定义完整(7个API对应的Req/Resp)
|
|
- [ ] 所有字段包含JSON标签(与Gateway文档一致)
|
|
- [ ] 必填字段包含`validate:"required"`标签
|
|
- [ ] 所有字段包含中文description注释
|
|
- [ ] 可选字段使用`omitempty`标签
|
|
- [ ] 编译通过: `go build ./internal/gateway`
|
|
|
|
**提交**: NO(与Phase 1合并提交)
|
|
|
|
---
|
|
|
|
### Phase 2: API接口封装
|
|
|
|
- [ ] **2.1. 实现流量卡API(7个接口)**
|
|
|
|
**要做什么**:
|
|
- 在`flow_card.go`中实现7个流量卡API方法:
|
|
1. `QueryCardStatus` - 流量卡状态查询
|
|
2. `QueryFlow` - 流量使用查询
|
|
3. `QueryRealnameStatus` - 实名认证状态查询
|
|
4. `StopCard` - 流量卡停机
|
|
5. `StartCard` - 流量卡复机
|
|
6. `GetRealnameLink` - 获取实名认证跳转链接
|
|
7. `BatchQuery` - 批量查询(预留,返回NotImplemented错误)
|
|
|
|
**禁止做什么**:
|
|
- 不要在方法内实现加密逻辑(复用doRequest)
|
|
- 不要硬编码API路径(使用常量)
|
|
- 不要省略错误处理(所有错误必须包装)
|
|
|
|
**推荐Agent Profile**:
|
|
- **Category**: `unspecified-high`
|
|
- 理由: API封装需要准确映射Gateway接口,错误处理要完整
|
|
- **Skills**: 无
|
|
- 理由: API封装是通用模式,复用doRequest即可
|
|
- **Skills评估但省略**:
|
|
- `api-routing`: 域不重叠(这是HTTP客户端,非路由注册)
|
|
|
|
**并行化**:
|
|
- **可并行运行**: YES
|
|
- **并行组**: Wave 4(与2.2, 4.1并行)
|
|
- **阻塞任务**: 2.3(单元测试需要API实现)
|
|
- **被阻塞**: 1.3, 1.4(需要Client和DTO)
|
|
|
|
**参考**:
|
|
- **API路径**: design.md中的接口列表(/flow-card/status等)
|
|
- **请求构造**: `map[string]interface{}{"params": {...}}`
|
|
- **响应解析**: `sonic.Unmarshal(resp, &result)`
|
|
- **错误包装**: `errors.Wrap(errors.CodeGatewayInvalidResp, err, "解析响应失败")`
|
|
- **类似实现**: `/internal/service/auth/service.go`(调用外部API模式)
|
|
|
|
**验收标准**:
|
|
|
|
**TDD流程**(每个API重复):
|
|
- [ ] **RED**: 编写`TestQueryCardStatus`
|
|
- Mock doRequest返回
|
|
- 验证请求参数构造
|
|
- 验证响应解析
|
|
- 预期: FAIL
|
|
|
|
- [ ] **GREEN**: 实现QueryCardStatus
|
|
- 构建businessData
|
|
- 调用doRequest("/flow-card/status", businessData)
|
|
- 解析响应为CardStatusResp
|
|
- 预期: PASS
|
|
|
|
- [ ] **REFACTOR**: 优化代码
|
|
- 预期: PASS
|
|
|
|
- [ ] 重复上述流程实现其他6个API
|
|
|
|
**自动化验证**:
|
|
```bash
|
|
# 编译检查
|
|
go build ./internal/gateway
|
|
# 预期: 成功编译,7个方法定义正确
|
|
|
|
# 单元测试(每个API)
|
|
source .env.local && go test -v ./internal/gateway -run TestQueryCardStatus
|
|
source .env.local && go test -v ./internal/gateway -run TestQueryFlow
|
|
source .env.local && go test -v ./internal/gateway -run TestStopCard
|
|
# 预期: PASS
|
|
|
|
# 覆盖率
|
|
source .env.local && go test -cover ./internal/gateway
|
|
# 预期: 覆盖率 ≥ 90%
|
|
```
|
|
|
|
**提交**: NO(与Phase 2合并提交)
|
|
|
|
---
|
|
|
|
- [ ] **2.2. 实现设备API(7个接口)**
|
|
|
|
**要做什么**:
|
|
- 在`device.go`中实现7个设备API方法:
|
|
1. `GetDeviceInfo` - 获取设备信息
|
|
2. `GetSlotInfo` - 获取设备卡槽信息
|
|
3. `SetSpeedLimit` - 设置设备限速
|
|
4. `SetWiFi` - 设置设备WiFi
|
|
5. `SwitchCard` - 设备切换卡
|
|
6. `ResetDevice` - 设备恢复出厂设置
|
|
7. `RebootDevice` - 设备重启
|
|
|
|
**禁止做什么**:
|
|
- 不要在方法内实现加密逻辑(复用doRequest)
|
|
- 不要硬编码API路径(使用常量)
|
|
- 不要省略参数验证(CardNo和DeviceID二选一)
|
|
|
|
**推荐Agent Profile**:
|
|
- **Category**: `unspecified-high`
|
|
- 理由: 同2.1,API封装需要准确映射
|
|
- **Skills**: 无
|
|
- **Skills评估但省略**:
|
|
- `api-routing`: 域不重叠
|
|
|
|
**并行化**:
|
|
- **可并行运行**: YES
|
|
- **并行组**: Wave 4(与2.1, 4.1并行)
|
|
- **阻塞任务**: 2.3
|
|
- **被阻塞**: 1.3, 1.4
|
|
|
|
**参考**:
|
|
- **API路径**: design.md(/device/info等)
|
|
- **请求构造**: 同2.1
|
|
- **响应解析**: DeviceInfoResp包含多个字段
|
|
- **参数验证**: CardNo和DeviceID至少一个非空
|
|
|
|
**验收标准**:
|
|
|
|
**TDD流程**(每个API重复):
|
|
- [ ] **RED**: 编写TestGetDeviceInfo等测试
|
|
- [ ] **GREEN**: 实现7个设备API
|
|
- [ ] **REFACTOR**: 优化代码
|
|
|
|
**自动化验证**:
|
|
```bash
|
|
go build ./internal/gateway
|
|
source .env.local && go test -v ./internal/gateway -run TestGetDeviceInfo
|
|
source .env.local && go test -v ./internal/gateway -run TestSetWiFi
|
|
source .env.local && go test -cover ./internal/gateway
|
|
```
|
|
|
|
**提交**: NO(与Phase 2合并提交)
|
|
|
|
---
|
|
|
|
- [ ] **2.3. 添加单元测试**
|
|
|
|
**要做什么**:
|
|
- 在`client_test.go`中添加加密/签名单元测试
|
|
- 添加doRequest的mock测试
|
|
- 验证错误处理逻辑(超时、网络错误、响应格式错误)
|
|
- 验证覆盖率≥90%
|
|
|
|
**禁止做什么**:
|
|
- 不要跳过错误场景测试(必须覆盖所有错误码)
|
|
- 不要使用真实Gateway API(单元测试用mock)
|
|
- 不要传递nil绕过依赖(必须mock完整响应)
|
|
|
|
**推荐Agent Profile**:
|
|
- **Category**: `unspecified-high`
|
|
- 理由: 测试覆盖率要求高,需要设计完整的测试用例
|
|
- **Skills**: 无
|
|
- **Skills评估但省略**:
|
|
- `db-validation`: 域不重叠(这是HTTP客户端测试,非数据库)
|
|
|
|
**并行化**:
|
|
- **可并行运行**: YES
|
|
- **并行组**: Wave 5(与4.2并行)
|
|
- **阻塞任务**: 5.1(集成测试依赖单元测试通过)
|
|
- **被阻塞**: 2.1, 2.2(需要API实现完成)
|
|
|
|
**参考**:
|
|
- **测试模式**: `/internal/service/package/service_test.go`
|
|
- **Table-driven tests**: `/tests/unit/shop_store_test.go`
|
|
- **Mock模式**: 不传递nil,构造完整mock响应
|
|
- **覆盖率工具**: `go test -cover`
|
|
|
|
**验收标准**:
|
|
|
|
**测试用例清单**:
|
|
- [ ] TestAESEncrypt_Success - 正常加密
|
|
- [ ] TestAESEncrypt_EmptyData - 空数据加密
|
|
- [ ] TestGenerateSign_Correctness - 签名正确性
|
|
- [ ] TestGenerateSign_Uppercase - 签名大写验证
|
|
- [ ] TestDoRequest_Success - 成功请求
|
|
- [ ] TestDoRequest_NetworkError - 网络错误
|
|
- [ ] TestDoRequest_Timeout - 超时错误
|
|
- [ ] TestDoRequest_InvalidResponse - 响应格式错误
|
|
- [ ] TestDoRequest_BusinessError - Gateway业务错误
|
|
- [ ] TestQueryCardStatus_Success - 卡状态查询成功
|
|
- [ ] TestQueryCardStatus_InvalidCard - 无效卡号
|
|
- [ ] (每个API至少2个测试用例)
|
|
|
|
**自动化验证**:
|
|
```bash
|
|
# 运行所有单元测试
|
|
source .env.local && go test -v ./internal/gateway
|
|
# 预期: PASS, 所有测试通过
|
|
|
|
# 检查覆盖率
|
|
source .env.local && go test -cover ./internal/gateway
|
|
# 预期: 覆盖率 ≥ 90%
|
|
|
|
# 生成覆盖率报告
|
|
source .env.local && go test -coverprofile=coverage.out ./internal/gateway
|
|
go tool cover -html=coverage.out
|
|
# 预期: 可视化报告显示 ≥ 90% 覆盖
|
|
```
|
|
|
|
**提交**: YES - "feat(gateway): 实现Gateway客户端基础功能和API封装"
|
|
- 提交内容: Phase 1 + Phase 2所有代码
|
|
- 验证: `source .env.local && go test -cover ./internal/gateway`
|
|
- 预期: 覆盖率≥90%
|
|
|
|
---
|
|
|
|
### Phase 3: 配置和错误码集成
|
|
|
|
- [ ] **3.1. 添加Gateway配置**
|
|
|
|
**要做什么**:
|
|
- 在`pkg/config/config.go`中添加`GatewayConfig`结构体
|
|
- 在`Config`中添加`Gateway GatewayConfig`字段
|
|
- 在`pkg/config/defaults/config.yaml`中添加gateway配置项
|
|
- 添加配置验证逻辑(必填项检查)
|
|
|
|
**禁止做什么**:
|
|
- 不要省略mapstructure标签(Viper解析需要)
|
|
- 不要硬编码默认值(必须在config.yaml中定义)
|
|
- 不要省略环境变量绑定(loader.go)
|
|
- 不要跳过验证逻辑(Validate方法)
|
|
|
|
**推荐Agent Profile**:
|
|
- **Category**: `quick`
|
|
- 理由: 配置结构定义遵循现有模式即可
|
|
- **Skills**: 无
|
|
- **Skills评估但省略**:
|
|
- `dto-standards`: 域不重叠(这是配置,非DTO)
|
|
|
|
**并行化**:
|
|
- **可并行运行**: YES
|
|
- **并行组**: Wave 1(与1.1, 1.4, 3.2并行)
|
|
- **阻塞任务**: 4.1(Bootstrap需要配置)
|
|
- **被阻塞**: 无
|
|
|
|
**参考**:
|
|
- **配置结构**: `/pkg/config/config.go` lines 14-26(现有Config结构)
|
|
- **配置文件**: `/pkg/config/defaults/config.yaml`(YAML格式)
|
|
- **环境变量**: `/pkg/config/loader.go` lines 49-121(bindEnvVariables)
|
|
- **验证逻辑**: `/pkg/config/config.go` lines 180-274(Validate方法)
|
|
- **类似配置**: StorageConfig(可选配置的验证模式)
|
|
|
|
**验收标准**:
|
|
- [ ] GatewayConfig结构体定义完整
|
|
- BaseURL string `mapstructure:"base_url"`
|
|
- AppID string `mapstructure:"app_id"`
|
|
- AppSecret string `mapstructure:"app_secret"`
|
|
- Timeout int `mapstructure:"timeout"`
|
|
|
|
- [ ] Config结构体添加Gateway字段
|
|
- Gateway GatewayConfig `mapstructure:"gateway"`
|
|
|
|
- [ ] defaults/config.yaml添加gateway节
|
|
```yaml
|
|
gateway:
|
|
base_url: "https://lplan.whjhft.com/openapi"
|
|
app_id: "60bgt1X8i7AvXqkd"
|
|
app_secret: "BZeQttaZQt0i73moF"
|
|
timeout: 30
|
|
```
|
|
|
|
- [ ] loader.go添加环境变量绑定
|
|
- "gateway.base_url"
|
|
- "gateway.app_id"
|
|
- "gateway.app_secret"
|
|
- "gateway.timeout"
|
|
|
|
- [ ] Validate方法添加Gateway验证
|
|
- BaseURL非空
|
|
- BaseURL格式验证(http/https开头)
|
|
- AppID非空
|
|
- AppSecret非空
|
|
- Timeout范围验证(5-300秒)
|
|
|
|
**自动化验证**:
|
|
```bash
|
|
# 设置环境变量测试
|
|
export JUNHONG_GATEWAY_BASE_URL=https://test.example.com
|
|
export JUNHONG_GATEWAY_APP_ID=test_app_id
|
|
export JUNHONG_GATEWAY_APP_SECRET=test_secret
|
|
export JUNHONG_GATEWAY_TIMEOUT=60
|
|
|
|
# 启动应用验证配置加载
|
|
go run cmd/api/main.go
|
|
# 预期: 启动成功,日志显示Gateway配置加载(AppSecret脱敏为***)
|
|
|
|
# 验证配置验证逻辑
|
|
unset JUNHONG_GATEWAY_APP_SECRET
|
|
go run cmd/api/main.go
|
|
# 预期: 启动失败,错误提示"gateway.app_secret不能为空"
|
|
```
|
|
|
|
**提交**: NO(与3.2合并提交)
|
|
|
|
---
|
|
|
|
- [ ] **3.2. 添加Gateway错误码**
|
|
|
|
**要做什么**:
|
|
- 在`pkg/errors/codes.go`中添加Gateway错误码常量(1110-1119)
|
|
- 在`allErrorCodes`数组中注册新错误码
|
|
- 在`errorMessages`映射表中添加中文错误消息
|
|
- 运行错误码验证测试
|
|
|
|
**禁止做什么**:
|
|
- 不要使用已占用的错误码(检查codes.go避免冲突)
|
|
- 不要省略错误消息(必须在errorMessages中定义)
|
|
- 不要省略错误码注册(allErrorCodes数组)
|
|
|
|
**推荐Agent Profile**:
|
|
- **Category**: `quick`
|
|
- 理由: 错误码定义遵循现有模式即可
|
|
- **Skills**: 无
|
|
- **Skills评估但省略**:
|
|
- `dto-standards`: 域不重叠(这是错误码,非DTO)
|
|
|
|
**并行化**:
|
|
- **可并行运行**: YES
|
|
- **并行组**: Wave 1(与1.1, 1.4, 3.1并行)
|
|
- **阻塞任务**: 无(错误码可随时使用)
|
|
- **被阻塞**: 无
|
|
|
|
**参考**:
|
|
- **错误码范围**: `/pkg/errors/codes.go` lines 6-102(现有错误码)
|
|
- **错误消息**: `/pkg/errors/codes.go` lines 193-271(errorMessages)
|
|
- **注册模式**: allErrorCodes数组
|
|
- **测试**: `/pkg/errors/codes_test.go`(错误码验证测试)
|
|
|
|
**验收标准**:
|
|
- [ ] 错误码常量定义(codes.go)
|
|
```go
|
|
// Gateway 相关错误(1110-1119)
|
|
const (
|
|
CodeGatewayError = 1110 // Gateway 通用错误
|
|
CodeGatewayEncryptError = 1111 // 数据加密失败
|
|
CodeGatewaySignError = 1112 // 签名生成失败
|
|
CodeGatewayTimeout = 1113 // 请求超时
|
|
CodeGatewayInvalidResp = 1114 // 响应格式错误
|
|
)
|
|
```
|
|
|
|
- [ ] allErrorCodes数组注册
|
|
```go
|
|
var allErrorCodes = []int{
|
|
// ... 现有错误码
|
|
CodeGatewayError,
|
|
CodeGatewayEncryptError,
|
|
CodeGatewaySignError,
|
|
CodeGatewayTimeout,
|
|
CodeGatewayInvalidResp,
|
|
}
|
|
```
|
|
|
|
- [ ] errorMessages映射表添加
|
|
```go
|
|
var errorMessages = map[int]string{
|
|
// ... 现有消息
|
|
CodeGatewayError: "Gateway 请求失败",
|
|
CodeGatewayEncryptError: "数据加密失败",
|
|
CodeGatewaySignError: "签名生成失败",
|
|
CodeGatewayTimeout: "Gateway 请求超时",
|
|
CodeGatewayInvalidResp: "Gateway 响应格式错误",
|
|
}
|
|
```
|
|
|
|
**自动化验证**:
|
|
```bash
|
|
# 运行错误码测试
|
|
go test -v ./pkg/errors -run TestErrorCodes
|
|
# 预期: PASS, 所有错误码已注册且有消息
|
|
|
|
# 验证错误码使用
|
|
go run -e 'package main; import "pkg/errors"; func main() { println(errors.GetMessage(1110, "zh-CN")) }'
|
|
# 预期: 输出"Gateway 请求失败"
|
|
```
|
|
|
|
**提交**: YES - "feat(errors): 添加Gateway错误码(1110-1119)"
|
|
- 提交内容: Phase 3所有代码(3.1 + 3.2)
|
|
- 验证: `go test -v ./pkg/errors -run TestErrorCodes`
|
|
- 预期: PASS
|
|
|
|
---
|
|
|
|
### Phase 4: 依赖注入和集成
|
|
|
|
- [ ] **4.1. Bootstrap初始化Gateway客户端**
|
|
|
|
**要做什么**:
|
|
- 在`internal/bootstrap/dependencies.go`的`Dependencies`中添加`GatewayClient *gateway.Client`字段
|
|
- 在`cmd/api/main.go`中添加`initGateway`函数
|
|
- 在`Bootstrap`调用中传递`deps.GatewayClient`
|
|
|
|
**禁止做什么**:
|
|
- 不要在Bootstrap函数内初始化Gateway(必须在main.go)
|
|
- 不要忽略配置验证(必须检查必填项)
|
|
- 不要硬编码超时时间(使用config.Gateway.Timeout)
|
|
|
|
**推荐Agent Profile**:
|
|
- **Category**: `unspecified-high`
|
|
- 理由: 依赖注入是核心架构,需要准确遵循现有模式
|
|
- **Skills**: 无
|
|
- **Skills评估但省略**:
|
|
- `api-routing`: 域不重叠(这是依赖注入,非路由)
|
|
|
|
**并行化**:
|
|
- **可并行运行**: YES
|
|
- **并行组**: Wave 4(与2.1, 2.2并行)
|
|
- **阻塞任务**: 4.2(Service需要Gateway客户端)
|
|
- **被阻塞**: 1.3, 3.1(需要Client和Config)
|
|
|
|
**参考**:
|
|
- **Dependencies**: `/internal/bootstrap/dependencies.go` lines 13-24
|
|
- **初始化模式**: `/cmd/api/main.go` lines 299-329(initStorage模式)
|
|
- **Bootstrap调用**: `/cmd/api/main.go` main函数
|
|
- **错误处理**: 配置缺失返回nil(可选服务模式)
|
|
|
|
**验收标准**:
|
|
- [ ] Dependencies添加GatewayClient字段
|
|
```go
|
|
type Dependencies struct {
|
|
// ... 现有字段
|
|
GatewayClient *gateway.Client
|
|
}
|
|
```
|
|
|
|
- [ ] main.go添加initGateway函数
|
|
```go
|
|
func initGateway(cfg *config.Config, logger *zap.Logger) *gateway.Client {
|
|
if cfg.Gateway.BaseURL == "" {
|
|
logger.Info("Gateway未配置,跳过初始化")
|
|
return nil
|
|
}
|
|
|
|
client := gateway.NewClient(
|
|
cfg.Gateway.BaseURL,
|
|
cfg.Gateway.AppID,
|
|
cfg.Gateway.AppSecret,
|
|
).WithTimeout(time.Duration(cfg.Gateway.Timeout) * time.Second)
|
|
|
|
logger.Info("Gateway客户端初始化成功")
|
|
return client
|
|
}
|
|
```
|
|
|
|
- [ ] main函数调用initGateway
|
|
```go
|
|
gatewayClient := initGateway(cfg, appLogger)
|
|
|
|
result, err := bootstrap.Bootstrap(&bootstrap.Dependencies{
|
|
// ... 现有依赖
|
|
GatewayClient: gatewayClient,
|
|
})
|
|
```
|
|
|
|
**自动化验证**:
|
|
```bash
|
|
# 设置环境变量
|
|
export JUNHONG_GATEWAY_BASE_URL=https://lplan.whjhft.com/openapi
|
|
export JUNHONG_GATEWAY_APP_ID=60bgt1X8i7AvXqkd
|
|
export JUNHONG_GATEWAY_APP_SECRET=BZeQttaZQt0i73moF
|
|
|
|
# 启动应用
|
|
source .env.local && go run cmd/api/main.go
|
|
# 预期: 日志显示"Gateway客户端初始化成功"
|
|
|
|
# 测试配置缺失场景
|
|
unset JUNHONG_GATEWAY_BASE_URL
|
|
source .env.local && go run cmd/api/main.go
|
|
# 预期: 日志显示"Gateway未配置,跳过初始化"
|
|
```
|
|
|
|
**提交**: NO(与4.2合并提交)
|
|
|
|
---
|
|
|
|
- [ ] **4.2. Service层集成示例**
|
|
|
|
**要做什么**:
|
|
- 选择一个Service(如`iot_card`)集成Gateway客户端
|
|
- 添加`SyncCardStatus`方法示例
|
|
- 添加错误处理和日志记录
|
|
|
|
**禁止做什么**:
|
|
- 不要在Service中实现加密逻辑(使用Gateway客户端)
|
|
- 不要使用fmt.Errorf(必须用errors.New/Wrap)
|
|
- 不要省略日志记录(调用外部API必须记录)
|
|
|
|
**推荐Agent Profile**:
|
|
- **Category**: `unspecified-high`
|
|
- 理由: Service层集成需要准确的错误处理和日志记录
|
|
- **Skills**: 无
|
|
- **Skills评估但省略**:
|
|
- `api-routing`: 域不重叠(这是Service业务逻辑,非路由)
|
|
|
|
**并行化**:
|
|
- **可并行运行**: YES
|
|
- **并行组**: Wave 5(与2.3并行)
|
|
- **阻塞任务**: 5.1(集成测试需要Service集成)
|
|
- **被阻塞**: 4.1(需要Gateway客户端注入)
|
|
|
|
**参考**:
|
|
- **Service模式**: `/internal/service/auth/service.go` lines 27-43(外部客户端注入)
|
|
- **错误处理**: `/internal/service/account/service.go` lines 36-91(errors.New/Wrap)
|
|
- **日志记录**: zap.Logger使用模式
|
|
- **Store更新**: 调用store.UpdateStatus更新数据库
|
|
|
|
**验收标准**:
|
|
- [ ] Service构造器添加gatewayClient参数
|
|
```go
|
|
type Service struct {
|
|
store *postgres.IotCardStore
|
|
gatewayClient *gateway.Client
|
|
logger *zap.Logger
|
|
}
|
|
|
|
func New(
|
|
store *postgres.IotCardStore,
|
|
gatewayClient *gateway.Client,
|
|
logger *zap.Logger,
|
|
) *Service {
|
|
return &Service{
|
|
store: store,
|
|
gatewayClient: gatewayClient,
|
|
logger: logger,
|
|
}
|
|
}
|
|
```
|
|
|
|
- [ ] 实现SyncCardStatus方法
|
|
```go
|
|
func (s *Service) SyncCardStatus(ctx context.Context, cardNo string) error {
|
|
// 调用Gateway API
|
|
resp, err := s.gatewayClient.QueryCardStatus(ctx, &gateway.CardStatusReq{
|
|
CardNo: cardNo,
|
|
})
|
|
if err != nil {
|
|
s.logger.Error("查询卡状态失败",
|
|
zap.String("cardNo", cardNo),
|
|
zap.Error(err))
|
|
return errors.Wrap(errors.CodeGatewayError, err, "查询卡状态失败")
|
|
}
|
|
|
|
// 更新数据库
|
|
if err := s.store.UpdateStatus(ctx, cardNo, resp.CardStatus); err != nil {
|
|
return errors.Wrap(errors.CodeInternalError, err, "更新卡状态失败")
|
|
}
|
|
|
|
s.logger.Info("同步卡状态成功",
|
|
zap.String("cardNo", cardNo),
|
|
zap.String("status", resp.CardStatus))
|
|
|
|
return nil
|
|
}
|
|
```
|
|
|
|
- [ ] Bootstrap注入Gateway客户端
|
|
```go
|
|
// services.go
|
|
IotCard: iotCardSvc.New(s.IotCard, deps.GatewayClient, deps.Logger),
|
|
```
|
|
|
|
**自动化验证**:
|
|
```bash
|
|
# 编译检查
|
|
go build ./internal/service/iot_card
|
|
# 预期: 成功编译
|
|
|
|
# 单元测试(如果已有)
|
|
source .env.local && go test -v ./internal/service/iot_card -run TestSyncCardStatus
|
|
# 预期: PASS(需要mock Gateway客户端)
|
|
```
|
|
|
|
**提交**: YES - "feat(service): 集成Gateway客户端到Service层"
|
|
- 提交内容: Phase 4所有代码(4.1 + 4.2)
|
|
- 验证: `go build ./...`
|
|
- 预期: 全部编译通过
|
|
|
|
---
|
|
|
|
### Phase 5: 集成测试和文档
|
|
|
|
- [ ] **5.1. 编写集成测试**
|
|
|
|
**要做什么**:
|
|
- 在`client_test.go`中添加集成测试(需要真实Gateway环境)
|
|
- 测试至少2个接口(如`QueryCardStatus`, `StopCard`)
|
|
- 验证加密/签名与Gateway文档一致
|
|
|
|
**禁止做什么**:
|
|
- 不要跳过集成测试(必须验证真实API)
|
|
- 不要使用硬编码测试数据(使用.env.local配置)
|
|
- 不要忽略测试失败(超时=生产超时)
|
|
|
|
**推荐Agent Profile**:
|
|
- **Category**: `quick`
|
|
- 理由: 集成测试调用真实API,验证端到端流程
|
|
- **Skills**: 无
|
|
- **Skills评估但省略**:
|
|
- `db-validation`: 域不重叠(这是HTTP API测试,非数据库)
|
|
|
|
**并行化**:
|
|
- **可并行运行**: YES
|
|
- **并行组**: Wave 6(与5.2并行)
|
|
- **阻塞任务**: 无(最后一波)
|
|
- **被阻塞**: 2.3, 4.2(需要单元测试通过和Service集成)
|
|
|
|
**参考**:
|
|
- **集成测试模式**: `/tests/integration/enterprise_device_h5_test.go`
|
|
- **测试跳过**: `if testing.Short() { t.Skip() }`
|
|
- **配置加载**: `config.Get()`
|
|
- **真实API调用**: 不使用mock,调用真实Gateway
|
|
|
|
**验收标准**:
|
|
|
|
**集成测试用例**:
|
|
- [ ] TestIntegration_QueryCardStatus
|
|
- 使用真实配置(config.Get())
|
|
- 调用真实Gateway API
|
|
- 验证响应完整性
|
|
- 预期: PASS
|
|
|
|
- [ ] TestIntegration_StopCard
|
|
- 调用停机API
|
|
- 验证Gateway返回成功
|
|
- 预期: PASS
|
|
|
|
- [ ] TestIntegration_EncryptionCompatibility
|
|
- 验证加密输出与Gateway文档一致
|
|
- 验证签名可被Gateway验证
|
|
- 预期: PASS
|
|
|
|
**自动化验证**:
|
|
```bash
|
|
# 设置测试环境变量
|
|
source .env.local
|
|
|
|
# 运行集成测试
|
|
go test -v ./internal/gateway -run TestIntegration
|
|
# 预期: PASS, 真实API调用成功
|
|
|
|
# 跳过集成测试(仅单元测试)
|
|
go test -short -v ./internal/gateway
|
|
# 预期: 集成测试被跳过
|
|
```
|
|
|
|
**提交**: NO(与5.2合并提交)
|
|
|
|
---
|
|
|
|
- [ ] **5.2. 更新文档**
|
|
|
|
**要做什么**:
|
|
- 在`docs/`目录下创建`gateway-client-usage.md`
|
|
- 添加Gateway客户端使用示例
|
|
- 添加错误码说明
|
|
- 更新`README.md`添加Gateway模块说明
|
|
|
|
**禁止做什么**:
|
|
- 不要省略代码示例(必须包含完整调用示例)
|
|
- 不要省略错误码说明(所有1110-1119错误码)
|
|
- 不要使用英文(文档必须中文)
|
|
|
|
**推荐Agent Profile**:
|
|
- **Category**: `quick`
|
|
- 理由: 文档编写遵循现有模板即可
|
|
- **Skills**: 无
|
|
- **Skills评估但省略**:
|
|
- `doc-management`: 这是新功能文档,非规范文档
|
|
|
|
**并行化**:
|
|
- **可并行运行**: YES
|
|
- **并行组**: Wave 6(与5.1并行)
|
|
- **阻塞任务**: 无
|
|
- **被阻塞**: 无(文档可随时编写)
|
|
|
|
**参考**:
|
|
- **文档模板**: `/docs/auth-usage-guide.md`(使用指南模板)
|
|
- **API文档**: `/docs/api/auth.md`(API文档模板)
|
|
- **README更新**: `/README.md`(核心功能章节)
|
|
|
|
**验收标准**:
|
|
- [ ] 创建`docs/gateway-client-usage.md`
|
|
- Gateway客户端介绍
|
|
- 配置说明(环境变量)
|
|
- 使用示例(完整代码)
|
|
- 错误处理说明
|
|
- 最佳实践
|
|
|
|
- [ ] 创建`docs/gateway-api-reference.md`
|
|
- 14个API接口列表
|
|
- 每个接口的请求/响应示例
|
|
- 参数说明
|
|
|
|
- [ ] 更新`README.md`
|
|
- 核心功能章节添加Gateway模块
|
|
- 技术栈章节说明
|
|
- 配置示例(环境变量)
|
|
|
|
**自动化验证**:
|
|
```bash
|
|
# 检查文档文件存在
|
|
ls -la docs/gateway-client-usage.md
|
|
ls -la docs/gateway-api-reference.md
|
|
# 预期: 文件存在
|
|
|
|
# 检查README更新
|
|
grep -i "gateway" README.md
|
|
# 预期: 找到Gateway模块说明
|
|
```
|
|
|
|
**提交**: YES - "docs: 添加Gateway客户端使用文档"
|
|
- 提交内容: Phase 5所有代码(5.1 + 5.2)
|
|
- 验证: 文档完整性检查
|
|
- 预期: 所有文档文件存在且内容完整
|
|
|
|
---
|
|
|
|
## 提交策略
|
|
|
|
| 完成阶段 | 提交信息 | 包含文件 | 验证命令 |
|
|
|---------|---------|---------|---------|
|
|
| Phase 2完成 | `feat(gateway): 实现Gateway客户端基础功能和API封装` | Phase 1 + Phase 2 | `source .env.local && go test -cover ./internal/gateway` |
|
|
| Phase 3完成 | `feat(errors): 添加Gateway错误码(1110-1119)` | Phase 3 (3.1 + 3.2) | `go test -v ./pkg/errors -run TestErrorCodes` |
|
|
| Phase 4完成 | `feat(service): 集成Gateway客户端到Service层` | Phase 4 (4.1 + 4.2) | `go build ./...` |
|
|
| Phase 5完成 | `docs: 添加Gateway客户端使用文档` | Phase 5 (5.1 + 5.2) | 文档完整性检查 |
|
|
|
|
---
|
|
|
|
## 成功标准
|
|
|
|
### 验证命令
|
|
|
|
```bash
|
|
# 1. 编译检查
|
|
go build ./internal/gateway
|
|
go build ./...
|
|
|
|
# 2. 单元测试
|
|
source .env.local && go test -v ./internal/gateway
|
|
source .env.local && go test -cover ./internal/gateway
|
|
|
|
# 3. 集成测试
|
|
source .env.local && go test -v ./internal/gateway -run TestIntegration
|
|
|
|
# 4. 错误码验证
|
|
go test -v ./pkg/errors -run TestErrorCodes
|
|
|
|
# 5. 配置验证
|
|
export JUNHONG_GATEWAY_BASE_URL=https://lplan.whjhft.com/openapi
|
|
export JUNHONG_GATEWAY_APP_ID=60bgt1X8i7AvXqkd
|
|
export JUNHONG_GATEWAY_APP_SECRET=BZeQttaZQt0i73moF
|
|
source .env.local && go run cmd/api/main.go
|
|
```
|
|
|
|
### 最终检查清单
|
|
|
|
- [ ] 所有14个Gateway API接口成功封装
|
|
- [ ] 加密/签名验证通过(与Gateway文档一致)
|
|
- [ ] 错误处理覆盖所有异常场景(网络错误、响应格式错误等)
|
|
- [ ] 单元测试覆盖率≥90%
|
|
- [ ] 集成测试验证真实Gateway API调用
|
|
- [ ] 配置通过环境变量成功加载
|
|
- [ ] 依赖注入到Service层成功
|
|
- [ ] 文档完整(使用示例、错误码说明、API参考)
|
|
- [ ] 无LSP错误,编译通过
|
|
- [ ] 符合项目代码规范(中文注释、Go命名规范、errors.New/Wrap)
|
|
|
|
---
|
|
|
|
## 风险与缓解
|
|
|
|
| 风险 | 影响 | 概率 | 缓解措施 |
|
|
|------|------|------|---------|
|
|
| AES-ECB实现错误 | 高(加密失败导致无法调用API) | 中 | 1. 使用TiDB参考代码<br>2. 端到端集成测试验证<br>3. 与Gateway文档示例对比 |
|
|
| 签名算法兼容性 | 高(签名不匹配导致认证失败) | 中 | 1. 严格按字母序拼接<br>2. 大写MD5输出<br>3. 集成测试验证 |
|
|
| Gateway响应格式变更 | 中(解析失败) | 低 | 1. 使用json.RawMessage<br>2. 统一错误处理<br>3. 日志记录原始响应 |
|
|
| 配置验证不完整 | 中(运行时错误) | 低 | 1. 双层验证(Required+Format)<br>2. 启动时验证<br>3. 明确错误提示 |
|
|
| 测试覆盖率不足 | 低(隐藏bug) | 低 | 1. TDD流程<br>2. 覆盖率工具检查<br>3. 集成测试补充 |
|
|
|
|
---
|
|
|
|
## 后续计划
|
|
|
|
本次变更完成后的优化方向:
|
|
|
|
1. **阶段2(未来优化)**:
|
|
- 实现异步模式回调接口
|
|
- 添加批量查询接口
|
|
- 实现请求重试和超时控制
|
|
|
|
2. **阶段3(性能优化)**:
|
|
- 添加响应缓存(Redis)
|
|
- 实现请求限流(防止Gateway过载)
|
|
- 监控和告警集成
|
|
|
|
3. **阶段4(安全增强)**:
|
|
- 替换AES-ECB为更安全的模式(如需Gateway支持)
|
|
- 实现请求签名双向验证
|
|
- 添加API调用审计日志
|