# Gateway API 集成工作计划

## TL;DR

> **Quick Summary**: 封装 Gateway API 为统一的能力模块，提供类型安全的接口、统一的错误处理、配置管理和自动重试机制
> 
> **Deliverables**: 
> - Gateway 客户端封装（`internal/gateway/` 包）
> - 14 个 API 接口（流量卡 7 个 + 设备 7 个）
> - AES-128-ECB 加密 + MD5 签名机制
> - 配置集成（GatewayConfig）
> - 错误码定义（1110-1119）
> - 依赖注入（Bootstrap）
> - 完整测试覆盖（单元测试 + 集成测试）
> 
> **Estimated Effort**: Medium（预计 2-3 小时）
> **Parallel Execution**: YES - 5 waves
> **Critical Path**: Phase 1 → Phase 2 → Phase 3 → Phase 4 → Phase 5

---

## Context

### Original Request
用户需要实施 gateway-integration 提案，该提案包含 61 个任务，分为 5 个 Phase。核心目标是封装 Gateway API 为统一的能力模块，提供类型安全的接口、统一的错误处理和配置管理。

### Interview Summary
**Key Discussions**:
- **Gateway 测试环境配置**: 已提供 BaseURL、AppID、AppSecret、测试 ICCID
- **加密/签名算法**: 基于 Apifox 文档（AES-128-ECB + MD5，遗留系统）
- **Service 集成范围**: 仅 iot_card Service，新增 SyncCardStatus 方法作为示例
- **批量查询接口**: 完全不需要（删除 Task 20）
- **错误处理策略**: 需要自动重试（3 次，指数退避：1s, 2s, 4s）

**Research Findings**:
- **项目现有模式**: SMS 客户端（pkg/sms/）可作为参考（接口 + 依赖注入）
- **测试模式**: testutils（全局单例 DB/Redis + 事务回滚）
- **错误处理**: 统一错误码系统（pkg/errors/）
- **配置管理**: Viper 加载，支持环境变量覆盖（JUNHONG_ 前缀）
- **安全警告**: ⚠️ AES-128-ECB 和 MD5 存在密码学漏洞（遗留系统，需添加注释警告）

### 自我审查
**识别的潜在风险**:
1. **加密算法实现风险**: AES-128-ECB + PKCS5Padding 实现容易出错
   - **缓解措施**: 使用 Apifox 文档中的 Go 示例代码，添加单元测试验证加密/解密
2. **签名计算风险**: 参数排序和拼接逻辑可能与 Gateway 不一致
   - **缓解措施**: 严格按照 Apifox 文档实现，集成测试验证真实签名
3. **重试逻辑风险**: 不当重试可能导致重复操作（如停机/复机）
   - **缓解措施**: 只重试网络错误和 5xx 错误，业务错误（4xx）不重试
4. **测试覆盖风险**: 设备 API 无法真实测试
   - **缓解措施**: 设备 API 只实现方法签名，集成测试跳过

**明确的边界和约束**:
- ✅ **必须包含**: 流量卡 7 个接口完整实现和测试
- ❌ **必须排除**: 批量查询接口（BatchQuery）
- ⚠️ **可选实现**: 设备 API 只需方法签名（测试跳过）
- 🔒 **不可变更**: 加密/签名算法（遗留系统约束）

---

## Work Objectives

### Core Objective
封装 Gateway API 为统一的能力模块，提供类型安全的接口、统一的错误处理、配置管理和自动重试机制，支持流量卡和设备管理的 14 个 API 接口。

### Concrete Deliverables
- `internal/gateway/client.go` - Gateway 客户端核心实现
- `internal/gateway/crypto.go` - AES-128-ECB 加密 + MD5 签名工具
- `internal/gateway/models.go` - 请求/响应 DTO 定义
- `internal/gateway/flow_card.go` - 流量卡 API（7 个接口）
- `internal/gateway/device.go` - 设备 API（7 个接口）
- `internal/gateway/client_test.go` - 单元测试 + 集成测试
- `pkg/config/config.go` - GatewayConfig 配置结构
- `pkg/errors/codes.go` - Gateway 错误码（1110-1119）
- `internal/bootstrap/bootstrap.go` - Bootstrap 初始化 Gateway 客户端
- `internal/service/iot_card/service.go` - SyncCardStatus 集成示例
- `docs/gateway-client-usage.md` - 使用文档

### Definition of Done
- [ ] 所有 14 个 Gateway API 接口成功封装（流量卡 7 个 + 设备 7 个）
- [ ] 加密/签名通过单元测试验证（与 Apifox 文档一致）
- [ ] 集成测试验证真实 Gateway API 调用（测试 ICCID: `8986062580006141710`）
- [ ] 重试逻辑测试通过（3 次重试，指数退避）
- [ ] 配置通过环境变量成功加载（JUNHONG_GATEWAY_*）
- [ ] 依赖注入到 iot_card Service 成功（SyncCardStatus 方法）
- [ ] 单元测试覆盖率 ≥ 90%（核心逻辑）
- [ ] 无 LSP 错误，编译通过
- [ ] 符合项目代码规范（中文注释、Go 命名规范）
- [ ] 文档完整（使用示例、错误码说明）

### Must Have
- AES-128-ECB 加密（PKCS5Padding + Base64）
- MD5 签名（大写输出）
- 自动重试逻辑（3 次，指数退避：1s, 2s, 4s）
- 流量卡 7 个 API 完整实现
- 真实 Gateway 环境集成测试
- 错误码定义（1110-1119）
- 配置环境变量支持

### Must NOT Have (Guardrails)
- ❌ 批量查询接口（BatchQuery）- 用户明确不需要
- ❌ 设备 API 的真实测试 - 无测试环境，只需方法签名
- ❌ 使用第三方重试库 - 项目无依赖，使用简单循环
- ❌ 降级策略 - 用户不需要，失败直接返回错误
- ❌ 使用 AES-GCM 或 HMAC-SHA256 - 遗留系统约束，必须使用 ECB + MD5
- ❌ AI-Slop 模式：
  - 过度抽象（不需要工厂模式、策略模式）
  - 过度验证（不需要 15 个参数校验）
  - 过度文档（不需要 JSDoc everywhere）

---

## Verification Strategy

### Test Decision
- **Infrastructure exists**: YES（项目已有 testutils）
- **User wants tests**: TDD（测试驱动开发）
- **Framework**: Go 标准库（testing + httptest）

### TDD Workflow

每个 TODO 遵循 **RED-GREEN-REFACTOR**：

**Task Structure:**
1. **RED**: 编写失败测试
   - 测试文件: `internal/gateway/*_test.go`
   - 测试命令: `go test -v ./internal/gateway/...`
   - 预期: FAIL（测试存在，实现不存在）
2. **GREEN**: 最小实现使测试通过
   - 实现代码: `internal/gateway/*.go`
   - 测试命令: `go test -v ./internal/gateway/...`
   - 预期: PASS
3. **REFACTOR**: 优化代码保持绿色
   - 重构: 提取常量、优化逻辑、添加注释
   - 测试命令: `go test -v ./internal/gateway/...`
   - 预期: PASS（仍然通过）

### 集成测试环境

**真实 Gateway 配置**:
```bash
export JUNHONG_GATEWAY_BASEURL="https://lplan.whjhft.com/openapi"
export JUNHONG_GATEWAY_APPID="60bgt1X8i7AvXqkd"
export JUNHONG_GATEWAY_APPSECRET="BZeQttaZQt0i73moF"
```

**测试数据**:
- 测试 ICCID: `8986062580006141710`
- 设备测试: 跳过（无测试环境）

**集成测试验证**:
```bash
# 运行集成测试（需先加载环境变量）
source .env.local && go test -v ./internal/gateway/... -run TestIntegration
```

---

## Execution Strategy

### Parallel Execution Waves

```
Wave 1 (Start Immediately - 基础结构):
├── Task 1.1: 创建 Gateway 包目录结构
└── Task 3.1: 添加 Gateway 配置结构

Wave 2 (After Wave 1 - 加密和模型):
├── Task 1.2: 实现加密/签名工具函数（crypto.go）
├── Task 1.3: 定义 DTO 结构（models.go）
└── Task 3.2: 添加 Gateway 错误码

Wave 3 (After Wave 2 - 客户端核心):
├── Task 1.4: 实现 Gateway 客户端基础结构（client.go）
└── Task 1.5: 实现 HTTP 重试逻辑（doRequest 方法）

Wave 4 (After Wave 3 - API 接口实现):
├── Task 2.1: 实现流量卡 API（flow_card.go，7 个接口）
└── Task 2.2: 实现设备 API（device.go，7 个接口签名）

Wave 5 (After Wave 4 - 集成和测试):
├── Task 2.3: 添加单元测试（client_test.go）
├── Task 4.1: Bootstrap 初始化 Gateway 客户端
├── Task 4.2: Service 层集成示例（SyncCardStatus）
├── Task 5.1: 编写集成测试
└── Task 5.2: 更新文档

Critical Path: Wave 1 → Wave 2 → Wave 3 → Wave 4 → Wave 5
Parallel Speedup: ~30% faster than sequential
```

### Dependency Matrix

| Task | Depends On | Blocks | Can Parallelize With |
|------|------------|--------|---------------------|
| 1.1 | None | All | 3.1 |
| 1.2 | 1.1 | 1.4, 2.1, 2.2 | 1.3, 3.2 |
| 1.3 | 1.1 | 2.1, 2.2 | 1.2, 3.2 |
| 1.4 | 1.1, 1.2, 1.3 | 1.5, 2.1, 2.2 | None |
| 1.5 | 1.4 | 2.1, 2.2 | None |
| 2.1 | 1.4, 1.5, 1.2, 1.3 | 2.3, 5.1 | 2.2 |
| 2.2 | 1.4, 1.5, 1.2, 1.3 | 2.3, 5.1 | 2.1 |
| 2.3 | 2.1, 2.2 | None | 4.1, 4.2 |
| 3.1 | None | 4.1 | 1.1 |
| 3.2 | 1.1 | 4.1 | 1.2, 1.3 |
| 4.1 | 1.4, 3.1, 3.2 | 4.2 | 2.3 |
| 4.2 | 4.1 | None | 2.3, 5.1 |
| 5.1 | 2.1, 2.2, 4.1 | None | 2.3, 4.2, 5.2 |
| 5.2 | All | None | 5.1 |

---

## TODOs

### Phase 1: 基础结构搭建

- [ ] **1.1 创建 Gateway 包目录结构**

  **What to do**:
  - 创建目录 `internal/gateway/`
  - 创建占位文件:
    - `client.go` - Gateway 客户端核心实现
    - `crypto.go` - 加密/签名工具
    - `models.go` - 请求/响应 DTO
    - `flow_card.go` - 流量卡 API
    - `device.go` - 设备 API
    - `client_test.go` - 测试文件
  - 每个文件添加 package 声明和中文注释说明用途

  **Must NOT do**:
  - 不添加任何实现代码（只创建文件结构）
  - 不创建 batch_query.go（批量查询不需要）

  **Recommended Agent Profile**:
  - **Category**: `quick`
    - Reason: 简单的目录和文件创建任务，无复杂逻辑
  - **Skills**: 无
    - Reason: 不涉及特定规范，只是文件结构创建

  **Parallelization**:
  - **Can Run In Parallel**: YES
  - **Parallel Group**: Wave 1（与 Task 3.1 并行）
  - **Blocks**: 所有后续任务（目录结构是基础）
  - **Blocked By**: None（可立即开始）

  **References**:
  - `pkg/sms/client.go` - 参考 SMS 客户端的包结构模式
  - `pkg/sms/http_client.go` - 参考 HTTP 客户端文件组织方式
  - `internal/service/iot_card/service.go` - 参考 Service 包的文件组织

  **Acceptance Criteria**:
  - [ ] 目录存在: `internal/gateway/`
  - [ ] 文件存在: `client.go`, `crypto.go`, `models.go`, `flow_card.go`, `device.go`, `client_test.go`
  - [ ] 每个文件包含 `package gateway` 声明
  - [ ] 每个文件顶部有中文注释说明用途
  - [ ] 验证命令: `ls -la internal/gateway/` → 显示所有文件
  - [ ] 编译通过: `go build ./internal/gateway/...` → 无错误

  **Commit**: YES
  - Message: `feat(gateway): 创建 Gateway 包目录结构`
  - Files: `internal/gateway/*.go`
  - Pre-commit: `go build ./internal/gateway/...`

---

- [ ] **1.2 实现加密/签名工具函数**

  **What to do**:
  - 在 `internal/gateway/crypto.go` 中实现加密函数:
    - `aesEncrypt(plaintext, appSecret string) (string, error)` - AES-128-ECB + PKCS5Padding + Base64
    - 步骤: MD5(appSecret) → 16字节密钥 → PKCS5填充 → ECB加密 → Base64编码
  - 实现签名函数:
    - `generateSign(params map[string]interface{}, appSecret string) string` - MD5签名（大写）
    - 步骤: 排序参数键 → 拼接 key=value&... → 追加 &key=appSecret → MD5 → 转大写
  - 实现解密函数（用于测试验证）:
    - `aesDecrypt(ciphertext, appSecret string) (string, error)` - 解密验证
  - 添加详细中文注释和安全警告:
    ```go
    // ⚠️ 安全警告: AES-128-ECB 模式已被证明存在密码学漏洞（相同明文产生相同密文，泄漏模式）
    // 仅用于对接遗留系统的 Gateway API，不应用于新系统设计
    // 推荐替代方案: AES-256-GCM（提供认证加密）
    ```

  **Must NOT do**:
  - 不使用第三方加密库（使用标准库 crypto/aes）
  - 不实现 AES-GCM 或其他模式（遗留系统约束）
  - 不跳过安全警告注释

  **Recommended Agent Profile**:
  - **Category**: `ultrabrain`
    - Reason: 加密算法实现需要精确逻辑，容易出错
  - **Skills**: 无
    - Reason: 加密实现不涉及项目特定规范

  **Parallelization**:
  - **Can Run In Parallel**: YES
  - **Parallel Group**: Wave 2（与 Task 1.3, 3.2 并行）
  - **Blocks**: Task 1.4, 2.1, 2.2（客户端和 API 依赖加密）
  - **Blocked By**: Task 1.1（需要文件结构存在）

  **References**:
  - **Apifox 文档**: `https://omp5mq28pq.apifox.cn/7819761m0` - 官方 Go 语言加密/签名示例
  - **Librarian 研究**: AES-128-ECB 实现模式（手动 ECB 循环，因为标准库无 ECB）
  - `crypto/aes` - AES 加密标准库
  - `crypto/md5` - MD5 哈希标准库
  - `encoding/base64` - Base64 编码标准库

  **Acceptance Criteria**:
  
  **TDD - RED Phase**:
  - [ ] 测试文件创建: `internal/gateway/crypto_test.go`
  - [ ] 编写失败测试:
    ```go
    func TestAESEncrypt(t *testing.T) {
        plaintext := "test"
        appSecret := "BZeQttaZQt0i73moF"
        encrypted, err := aesEncrypt(plaintext, appSecret)
        require.NoError(t, err)
        assert.NotEmpty(t, encrypted)
        
        // 验证可解密
        decrypted, err := aesDecrypt(encrypted, appSecret)
        require.NoError(t, err)
        assert.Equal(t, plaintext, decrypted)
    }
    
    func TestGenerateSign(t *testing.T) {
        params := map[string]interface{}{
            "appId": "60bgt1X8i7AvXqkd",
            "timestamp": 1704067200,
            "data": "encrypted_data",
        }
        appSecret := "BZeQttaZQt0i73moF"
        sign := generateSign(params, appSecret)
        assert.NotEmpty(t, sign)
        assert.Regexp(t, "^[A-F0-9]{32}$", sign) // 32位大写MD5
    }
    ```
  - [ ] 运行测试: `go test -v ./internal/gateway/ -run TestAES` → FAIL（未实现）
  
  **TDD - GREEN Phase**:
  - [ ] 实现 `aesEncrypt` 函数（参考 Apifox 文档示例）
  - [ ] 实现 `aesDecrypt` 函数（用于测试验证）
  - [ ] 实现 `generateSign` 函数（参考 Apifox 文档示例）
  - [ ] 运行测试: `go test -v ./internal/gateway/ -run TestAES` → PASS
  
  **TDD - REFACTOR Phase**:
  - [ ] 添加详细中文注释和安全警告
  - [ ] 提取 PKCS5 填充逻辑为独立函数
  - [ ] 运行测试: `go test -v ./internal/gateway/ -run TestAES` → PASS（仍然通过）

  **Commit**: YES
  - Message: `feat(gateway): 实现 AES-128-ECB 加密和 MD5 签名工具`
  - Files: `internal/gateway/crypto.go`, `internal/gateway/crypto_test.go`
  - Pre-commit: `go test -v ./internal/gateway/ -run TestAES`

---

- [ ] **1.3 定义请求/响应 DTO 结构**

  **What to do**:
  - 在 `internal/gateway/models.go` 中定义:
  - **通用请求/响应结构**:
    ```go
    // GatewayRequest Gateway API 统一请求结构
    type GatewayRequest struct {
        AppID     string `json:"appId"`     // 应用ID
        Data      string `json:"data"`      // AES加密后的Base64字符串
        Sign      string `json:"sign"`      // MD5签名（大写）
        Timestamp int64  `json:"timestamp"` // 时间戳（秒）
    }
    
    // GatewayResponse Gateway API 统一响应结构
    type GatewayResponse struct {
        Code int         `json:"code"` // 响应码（200=成功）
        Msg  string      `json:"msg"`  // 响应消息
        Data interface{} `json:"data"` // 业务数据（需解密）
    }
    ```
  - **流量卡相关 DTO**（7 个接口）:
    - `CardStatusReq` - 卡状态查询请求
    - `CardStatusResp` - 卡状态查询响应
    - `FlowQueryReq` - 流量查询请求
    - `FlowUsageResp` - 流量使用响应
    - `RealnameStatusReq` - 实名认证状态请求
    - `RealnameStatusResp` - 实名认证状态响应
    - `CardOperationReq` - 停机/复机请求（通用）
    - `RealmnameLinkResp` - 实名认证链接响应
  - **设备相关 DTO**（7 个接口）:
    - `DeviceInfoReq` - 设备信息请求
    - `DeviceInfoResp` - 设备信息响应
    - `SlotInfoReq` - 卡槽信息请求
    - `SlotInfoResp` - 卡槽信息响应
    - `SpeedLimitReq` - 限速设置请求
    - `WiFiConfigReq` - WiFi 配置请求
    - `CardSwitchReq` - 切换卡请求
    - `DeviceOperationReq` - 设备操作请求（重启/恢复出厂）
  - 每个结构体添加:
    - JSON 标签（使用 sonic 序列化）
    - 中文注释（description）
    - 验证标签（validate，如 `required`）

  **Must NOT do**:
  - 不定义 BatchQuery 相关 DTO（不需要）
  - 不过度抽象（不需要接口或泛型）
  - 不添加 Getter/Setter（Go 惯用法直接访问字段）

  **Recommended Agent Profile**:
  - **Category**: `quick`
    - Reason: DTO 定义是结构化任务，无复杂逻辑
  - **Skills**: [`dto-standards`]
    - `dto-standards`: DTO 规范（description 标签、枚举字段、验证标签）
    - Reason: 定义 DTO 结构需要遵循项目规范

  **Parallelization**:
  - **Can Run In Parallel**: YES
  - **Parallel Group**: Wave 2（与 Task 1.2, 3.2 并行）
  - **Blocks**: Task 2.1, 2.2（API 实现依赖 DTO）
  - **Blocked By**: Task 1.1（需要文件结构存在）

  **References**:
  - **Apifox 文档**: `https://omp5mq28pq.apifox.cn/7819761m0` - 完整的请求/响应结构定义
  - `internal/model/dto/` - 参考现有 DTO 定义模式
  - `docs/dto-standards.md` - DTO 规范（description 标签、验证标签）
  - **Validator 库**: `github.com/go-playground/validator/v10` - 验证标签语法

  **Acceptance Criteria**:
  
  **TDD - RED Phase**:
  - [ ] 测试文件创建: `internal/gateway/models_test.go`
  - [ ] 编写失败测试:
    ```go
    func TestGatewayRequestJSON(t *testing.T) {
        req := GatewayRequest{
            AppID: "test",
            Data: "encrypted",
            Sign: "ABC123",
            Timestamp: 1704067200,
        }
        data, err := json.Marshal(req)
        require.NoError(t, err)
        assert.Contains(t, string(data), "appId")
    }
    ```
  - [ ] 运行测试: `go test -v ./internal/gateway/ -run TestGatewayRequest` → FAIL
  
  **TDD - GREEN Phase**:
  - [ ] 定义所有 DTO 结构体（参考 Apifox 文档）
  - [ ] 运行测试: `go test -v ./internal/gateway/ -run TestGatewayRequest` → PASS
  
  **TDD - REFACTOR Phase**:
  - [ ] 添加中文注释（每个字段说明用途）
  - [ ] 添加验证标签（required, min, max 等）
  - [ ] 运行测试: `go test -v ./internal/gateway/ -run TestGatewayRequest` → PASS

  **Commit**: YES
  - Message: `feat(gateway): 定义 Gateway API 请求/响应 DTO 结构`
  - Files: `internal/gateway/models.go`, `internal/gateway/models_test.go`
  - Pre-commit: `go test -v ./internal/gateway/ -run TestGatewayRequest`

---

- [ ] **1.4 实现 Gateway 客户端基础结构**

  **What to do**:
  - 在 `internal/gateway/client.go` 中定义客户端接口和结构:
    ```go
    // Client Gateway API 客户端接口（用于 mock 测试）
    type Client interface {
        // 流量卡相关接口
        QueryCardStatus(ctx context.Context, iccid string) (*CardStatusResp, error)
        QueryFlow(ctx context.Context, iccid string) (*FlowUsageResp, error)
        // ... 其他接口声明
    }
    
    // GatewayClient Gateway API 客户端实现
    type GatewayClient struct {
        baseURL    string       // Gateway API 地址
        appID      string       // 应用ID
        appSecret  string       // 应用密钥
        httpClient *http.Client // HTTP 客户端
        logger     *zap.Logger  // 日志记录器
    }
    ```
  - 实现构造函数:
    ```go
    func NewClient(baseURL, appID, appSecret string, logger *zap.Logger) *GatewayClient
    ```
  - 实现配置方法:
    ```go
    func (c *GatewayClient) WithTimeout(timeout time.Duration) *GatewayClient
    ```
  - **不实现 doRequest 方法**（留给 Task 1.5）

  **Must NOT do**:
  - 不实现具体的 API 方法（留给 Task 2.1, 2.2）
  - 不实现重试逻辑（留给 Task 1.5）
  - 不使用 Getter/Setter 模式（Go 惯用法）

  **Recommended Agent Profile**:
  - **Category**: `ultrabrain`
    - Reason: 客户端架构设计需要考虑接口设计、依赖注入
  - **Skills**: 无
    - Reason: 不涉及项目特定规范，是通用的客户端设计

  **Parallelization**:
  - **Can Run In Parallel**: NO
  - **Parallel Group**: Wave 3（顺序执行）
  - **Blocks**: Task 1.5, 2.1, 2.2（API 实现依赖客户端结构）
  - **Blocked By**: Task 1.1, 1.2, 1.3（需要目录、加密、DTO）

  **References**:
  - `pkg/sms/client.go` - 参考 SMS 客户端的接口 + 结构体模式
  - `pkg/sms/http_client.go` - 参考 HTTP 客户端的依赖注入模式
  - **Librarian 研究**: API 客户端设计模式（接口 + 依赖注入）

  **Acceptance Criteria**:
  
  **TDD - RED Phase**:
  - [ ] 测试文件更新: `internal/gateway/client_test.go`
  - [ ] 编写失败测试:
    ```go
    func TestNewClient(t *testing.T) {
        client := NewClient("https://api.example.com", "appid", "secret", zap.NewNop())
        assert.NotNil(t, client)
        assert.Equal(t, "https://api.example.com", client.baseURL)
    }
    
    func TestWithTimeout(t *testing.T) {
        client := NewClient("https://api.example.com", "appid", "secret", zap.NewNop())
        client = client.WithTimeout(5 * time.Second)
        assert.Equal(t, 5*time.Second, client.httpClient.Timeout)
    }
    ```
  - [ ] 运行测试: `go test -v ./internal/gateway/ -run TestNewClient` → FAIL
  
  **TDD - GREEN Phase**:
  - [ ] 定义 Client 接口（所有方法签名）
  - [ ] 定义 GatewayClient 结构体
  - [ ] 实现 NewClient 构造函数
  - [ ] 实现 WithTimeout 方法
  - [ ] 运行测试: `go test -v ./internal/gateway/ -run TestNewClient` → PASS
  
  **TDD - REFACTOR Phase**:
  - [ ] 添加详细中文注释
  - [ ] 配置默认 HTTP 客户端（参考 librarian 研究的超时配置）
  - [ ] 运行测试: `go test -v ./internal/gateway/ -run TestNewClient` → PASS

  **Commit**: YES
  - Message: `feat(gateway): 实现 Gateway 客户端基础结构`
  - Files: `internal/gateway/client.go`, `internal/gateway/client_test.go`
  - Pre-commit: `go test -v ./internal/gateway/ -run TestNewClient`

---

- [ ] **1.5 实现 HTTP 重试逻辑（doRequest 方法）**

  **What to do**:
  - 在 `internal/gateway/client.go` 中实现统一请求方法:
    ```go
    func (c *GatewayClient) doRequest(ctx context.Context, endpoint string, reqData interface{}) (*GatewayResponse, error)
    ```
  - 请求流程:
    1. 序列化请求数据（sonic）
    2. AES 加密请求数据
    3. 构建 GatewayRequest（appId, data, timestamp, sign）
    4. **重试循环**（最多 3 次）:
       - 发送 HTTP POST 请求
       - 解析响应
       - **网络错误或 5xx → 重试**（指数退避：1s, 2s, 4s）
       - **4xx 业务错误 → 不重试**（直接返回错误）
       - **超时错误 → 不重试**（context.DeadlineExceeded）
    5. AES 解密响应数据
    6. 返回 GatewayResponse
  - 错误处理:
    - 网络错误: 返回 `errors.Wrap(errors.CodeGatewayNetworkError, err)`
    - 超时错误: 返回 `errors.New(errors.CodeGatewayTimeout)`
    - 业务错误: 返回 `errors.New(errors.CodeGatewayBusinessError, resp.Msg)`

  **Must NOT do**:
  - 不使用第三方重试库（项目无依赖）
  - 不重试业务错误（4xx）
  - 不重试超时错误（避免雪崩）

  **Recommended Agent Profile**:
  - **Category**: `ultrabrain`
    - Reason: 重试逻辑复杂，需要精确的错误分类和退避算法
  - **Skills**: 无
    - Reason: HTTP 重试是通用逻辑，不涉及项目特定规范

  **Parallelization**:
  - **Can Run In Parallel**: NO
  - **Parallel Group**: Wave 3（顺序执行，依赖 Task 1.4）
  - **Blocks**: Task 2.1, 2.2（API 实现依赖 doRequest）
  - **Blocked By**: Task 1.4（需要客户端结构存在）

  **References**:
  - **Librarian 研究**: HTTP 重试最佳实践（指数退避、错误分类）
  - `pkg/sms/http_client.go` - 参考 HTTP 请求模式（无重试，需自行实现）
  - `pkg/constants/constants.go` - 参考 DefaultRetryMax（Asynq 任务重试次数 5）
  - **Sonic 库**: `github.com/bytedance/sonic` - JSON 序列化

  **Acceptance Criteria**:
  
  **TDD - RED Phase**:
  - [ ] 测试文件更新: `internal/gateway/client_test.go`
  - [ ] 编写失败测试:
    ```go
    func TestDoRequest_Success(t *testing.T) {
        // 使用 httptest.Server 模拟成功响应
        server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            w.WriteHeader(http.StatusOK)
            json.NewEncoder(w).Encode(GatewayResponse{Code: 200, Msg: "success"})
        }))
        defer server.Close()
        
        client := NewClient(server.URL, "appid", "secret", zap.NewNop())
        resp, err := client.doRequest(context.Background(), "/test", map[string]string{"iccid": "test"})
        require.NoError(t, err)
        assert.Equal(t, 200, resp.Code)
    }
    
    func TestDoRequest_Retry(t *testing.T) {
        // 模拟前 2 次失败，第 3 次成功
        attempts := 0
        server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            attempts++
            if attempts < 3 {
                w.WriteHeader(http.StatusInternalServerError)
                return
            }
            w.WriteHeader(http.StatusOK)
            json.NewEncoder(w).Encode(GatewayResponse{Code: 200, Msg: "success"})
        }))
        defer server.Close()
        
        client := NewClient(server.URL, "appid", "secret", zap.NewNop())
        resp, err := client.doRequest(context.Background(), "/test", map[string]string{"iccid": "test"})
        require.NoError(t, err)
        assert.Equal(t, 200, resp.Code)
        assert.Equal(t, 3, attempts) // 验证重试了 2 次
    }
    
    func TestDoRequest_NoRetryOn4xx(t *testing.T) {
        // 4xx 错误不重试
        attempts := 0
        server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            attempts++
            w.WriteHeader(http.StatusBadRequest)
        }))
        defer server.Close()
        
        client := NewClient(server.URL, "appid", "secret", zap.NewNop())
        _, err := client.doRequest(context.Background(), "/test", map[string]string{"iccid": "test"})
        require.Error(t, err)
        assert.Equal(t, 1, attempts) // 验证没有重试
    }
    ```
  - [ ] 运行测试: `go test -v ./internal/gateway/ -run TestDoRequest` → FAIL
  
  **TDD - GREEN Phase**:
  - [ ] 实现 doRequest 方法（加密、重试、解密）
  - [ ] 实现重试逻辑（指数退避：1s, 2s, 4s）
  - [ ] 实现错误分类（网络/超时/业务）
  - [ ] 运行测试: `go test -v ./internal/gateway/ -run TestDoRequest` → PASS
  
  **TDD - REFACTOR Phase**:
  - [ ] 提取重试配置为常量（maxRetries, baseDelay）
  - [ ] 添加详细日志（每次重试记录日志）
  - [ ] 运行测试: `go test -v ./internal/gateway/ -run TestDoRequest` → PASS

  **Commit**: YES
  - Message: `feat(gateway): 实现 HTTP 重试逻辑（3 次重试，指数退避）`
  - Files: `internal/gateway/client.go`, `internal/gateway/client_test.go`
  - Pre-commit: `go test -v ./internal/gateway/ -run TestDoRequest`

---

### Phase 2: API 接口封装

- [ ] **2.1 实现流量卡 API（7 个接口）**

  **What to do**:
  - 在 `internal/gateway/flow_card.go` 中实现 7 个流量卡 API:
    1. **QueryCardStatus** - 查询流量卡状态（在线/离线）
       - 参数: iccid
       - 返回: 卡状态、运营商、信号强度等
    2. **QueryFlow** - 查询流量使用情况
       - 参数: iccid
       - 返回: 已用流量、剩余流量、套餐流量等
    3. **QueryRealnameStatus** - 查询实名认证状态
       - 参数: iccid
       - 返回: 是否已实名、实名信息等
    4. **StopCard** - 停机（暂停流量卡）
       - 参数: iccid
       - 返回: 操作结果
    5. **StartCard** - 复机（恢复流量卡）
       - 参数: iccid
       - 返回: 操作结果
    6. **GetRealnameLink** - 获取实名认证跳转链接
       - 参数: iccid
       - 返回: H5 认证链接
    7. **~~BatchQuery~~** - ❌ 删除（用户明确不需要）
  - 每个方法:
    - 接收 `context.Context` 参数
    - 调用 `doRequest` 统一请求方法
    - 解析响应数据到对应的 Resp 结构体
    - 返回 `(*XxxResp, error)`
  - 添加详细中文注释

  **Must NOT do**:
  - 不实现 BatchQuery（删除）
  - 不在方法内重复加密/签名逻辑（使用 doRequest）
  - 不忽略错误处理

  **Recommended Agent Profile**:
  - **Category**: `ultrabrain`
    - Reason: API 实现需要精确的请求/响应映射和错误处理
  - **Skills**: 无
    - Reason: API 实现是标准流程，不涉及项目特定规范

  **Parallelization**:
  - **Can Run In Parallel**: YES
  - **Parallel Group**: Wave 4（与 Task 2.2 并行）
  - **Blocks**: Task 2.3, 5.1（测试依赖 API 实现）
  - **Blocked By**: Task 1.4, 1.5, 1.2, 1.3（需要客户端、重试、加密、DTO）

  **References**:
  - **Apifox 文档**: `https://omp5mq28pq.apifox.cn/7819761m0` - 流量卡接口文档（endpoint、请求/响应格式）
  - `internal/gateway/client.go` - doRequest 方法（统一请求入口）
  - `internal/gateway/models.go` - DTO 定义（CardStatusReq, CardStatusResp 等）
  - `internal/gateway/crypto.go` - 加密/签名工具（已在 doRequest 中使用）

  **Acceptance Criteria**:
  
  **TDD - RED Phase**:
  - [ ] 测试文件更新: `internal/gateway/flow_card_test.go`
  - [ ] 编写失败测试（每个接口一个测试）:
    ```go
    func TestQueryCardStatus(t *testing.T) {
        server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            // 模拟 Gateway 响应
            w.WriteHeader(http.StatusOK)
            json.NewEncoder(w).Encode(GatewayResponse{
                Code: 200,
                Msg: "success",
                Data: CardStatusResp{Status: "online", Operator: "移动"},
            })
        }))
        defer server.Close()
        
        client := NewClient(server.URL, "appid", "secret", zap.NewNop())
        resp, err := client.QueryCardStatus(context.Background(), "8986062580006141710")
        require.NoError(t, err)
        assert.Equal(t, "online", resp.Status)
    }
    ```
  - [ ] 运行测试: `go test -v ./internal/gateway/ -run TestQuery` → FAIL
  
  **TDD - GREEN Phase**:
  - [ ] 实现 QueryCardStatus 方法
  - [ ] 实现 QueryFlow 方法
  - [ ] 实现 QueryRealnameStatus 方法
  - [ ] 实现 StopCard 方法
  - [ ] 实现 StartCard 方法
  - [ ] 实现 GetRealnameLink 方法
  - [ ] 运行测试: `go test -v ./internal/gateway/ -run TestQuery` → PASS
  
  **TDD - REFACTOR Phase**:
  - [ ] 添加详细中文注释（每个方法说明用途和参数）
  - [ ] 提取公共逻辑（如错误码映射）
  - [ ] 运行测试: `go test -v ./internal/gateway/ -run TestQuery` → PASS

  **Commit**: YES
  - Message: `feat(gateway): 实现流量卡 API（6 个接口）`
  - Files: `internal/gateway/flow_card.go`, `internal/gateway/flow_card_test.go`
  - Pre-commit: `go test -v ./internal/gateway/ -run TestQuery`

---

- [ ] **2.2 实现设备 API（7 个接口签名）**

  **What to do**:
  - 在 `internal/gateway/device.go` 中实现 7 个设备 API **方法签名**:
    1. **GetDeviceInfo** - 获取设备信息
    2. **GetSlotInfo** - 获取设备卡槽信息
    3. **SetSpeedLimit** - 设置设备限速
    4. **SetWiFi** - 设置设备 WiFi
    5. **SwitchCard** - 设备切换卡
    6. **ResetDevice** - 设备恢复出厂设置
    7. **RebootDevice** - 设备重启
  - 每个方法:
    - 接收 `context.Context` 和相应参数
    - **暂时返回 "未实现" 错误**:
      ```go
      return nil, errors.New(errors.CodeGatewayNotImplemented, "设备 API 暂未实现（无测试环境）")
      ```
    - 添加 TODO 注释说明未来需实现
  - 保留完整的方法签名和 DTO 定义

  **Must NOT do**:
  - 不实现真实的 HTTP 请求（无测试环境）
  - 不删除这些方法（保留接口定义）
  - 不在集成测试中测试设备 API

  **Recommended Agent Profile**:
  - **Category**: `quick`
    - Reason: 只实现方法签名，无复杂逻辑
  - **Skills**: 无
    - Reason: 简单的方法签名定义

  **Parallelization**:
  - **Can Run In Parallel**: YES
  - **Parallel Group**: Wave 4（与 Task 2.1 并行）
  - **Blocks**: Task 2.3, 5.1（测试需要所有方法存在）
  - **Blocked By**: Task 1.4, 1.5, 1.2, 1.3（需要客户端、重试、加密、DTO）

  **References**:
  - **Apifox 文档**: `https://omp5mq28pq.apifox.cn/7819761m0` - 设备接口文档（了解参数和返回值）
  - `internal/gateway/flow_card.go` - 参考流量卡 API 的方法签名模式
  - `internal/gateway/models.go` - 设备相关 DTO

  **Acceptance Criteria**:
  
  **TDD - RED Phase**:
  - [ ] 测试文件创建: `internal/gateway/device_test.go`
  - [ ] 编写失败测试（验证方法存在且返回未实现错误）:
    ```go
    func TestGetDeviceInfo_NotImplemented(t *testing.T) {
        client := NewClient("https://api.example.com", "appid", "secret", zap.NewNop())
        _, err := client.GetDeviceInfo(context.Background(), "device-123")
        require.Error(t, err)
        assert.Contains(t, err.Error(), "未实现")
    }
    ```
  - [ ] 运行测试: `go test -v ./internal/gateway/ -run TestGetDevice` → FAIL
  
  **TDD - GREEN Phase**:
  - [ ] 定义所有 7 个设备 API 方法签名
  - [ ] 每个方法返回 "未实现" 错误
  - [ ] 运行测试: `go test -v ./internal/gateway/ -run TestGetDevice` → PASS
  
  **TDD - REFACTOR Phase**:
  - [ ] 添加 TODO 注释（说明未来需实现）
  - [ ] 添加详细中文注释（每个方法说明用途）
  - [ ] 运行测试: `go test -v ./internal/gateway/ -run TestGetDevice` → PASS

  **Commit**: YES
  - Message: `feat(gateway): 实现设备 API 方法签名（7 个接口，暂未实现）`
  - Files: `internal/gateway/device.go`, `internal/gateway/device_test.go`
  - Pre-commit: `go test -v ./internal/gateway/ -run TestGetDevice`

---

- [ ] **2.3 添加单元测试（覆盖率 ≥ 90%）**

  **What to do**:
  - 在 `internal/gateway/client_test.go` 中补充完整单元测试:
    - **加密/签名测试**（已在 Task 1.2 完成）
    - **doRequest 测试**（已在 Task 1.5 完成）
    - **流量卡 API 测试**（已在 Task 2.1 完成）
    - **设备 API 测试**（已在 Task 2.2 完成）
  - 新增测试覆盖:
    - **边界条件测试**: 空字符串、nil 参数、超长字符串
    - **错误处理测试**: 网络错误、超时、业务错误
    - **并发安全测试**: 多 goroutine 同时调用客户端
  - 使用 **table-driven tests** 模式
  - 运行覆盖率检查:
    ```bash
    go test -v ./internal/gateway/... -cover -coverprofile=coverage.out
    go tool cover -func=coverage.out
    ```
  - 确保核心逻辑覆盖率 ≥ 90%

  **Must NOT do**:
  - 不测试设备 API 的真实调用（无环境）
  - 不过度测试（不需要 100% 覆盖率）
  - 不跳过错误场景测试

  **Recommended Agent Profile**:
  - **Category**: `ultrabrain`
    - Reason: 测试覆盖率需要全面考虑边界条件和错误场景
  - **Skills**: 无
    - Reason: 单元测试是通用技能

  **Parallelization**:
  - **Can Run In Parallel**: YES
  - **Parallel Group**: Wave 5（与 Task 4.1, 4.2 并行）
  - **Blocks**: None（测试不阻塞其他任务）
  - **Blocked By**: Task 2.1, 2.2（需要 API 实现存在）

  **References**:
  - `tests/unit/shop_store_test.go` - 参考项目的 table-driven tests 模式
  - **Go 测试文档**: `testing` 标准库（t.Run, subtests）
  - **httptest 文档**: `net/http/httptest` - 模拟 HTTP 服务器

  **Acceptance Criteria**:
  
  **测试覆盖验证**:
  - [ ] 运行覆盖率检查: `go test -v ./internal/gateway/... -cover -coverprofile=coverage.out`
  - [ ] 查看覆盖率报告: `go tool cover -func=coverage.out | grep total`
  - [ ] 核心逻辑覆盖率 ≥ 90%:
    - `crypto.go` ≥ 90%
    - `client.go` ≥ 90%
    - `flow_card.go` ≥ 90%
    - `device.go` = 100%（只返回错误，简单）
  - [ ] 所有测试通过: `go test -v ./internal/gateway/...` → PASS

  **测试场景覆盖**:
  - [ ] 加密/签名正确性测试（加密 → 解密 → 验证）
  - [ ] 重试逻辑测试（5xx 重试、4xx 不重试、超时不重试）
  - [ ] 错误分类测试（网络/超时/业务错误）
  - [ ] 边界条件测试（空参数、nil、超长字符串）
  - [ ] 并发安全测试（多 goroutine 调用）

  **Commit**: YES
  - Message: `test(gateway): 补充单元测试覆盖率（≥ 90%）`
  - Files: `internal/gateway/*_test.go`
  - Pre-commit: `go test -v ./internal/gateway/... -cover`

---

### Phase 3: 配置和错误码集成

- [ ] **3.1 添加 Gateway 配置结构**

  **What to do**:
  - 在 `pkg/config/config.go` 中添加 `GatewayConfig` 结构体:
    ```go
    // GatewayConfig Gateway API 配置
    type GatewayConfig struct {
        BaseURL   string        `mapstructure:"base_url" validate:"required,url"` // Gateway API 地址
        AppID     string        `mapstructure:"app_id" validate:"required"`       // 应用ID
        AppSecret string        `mapstructure:"app_secret" validate:"required"`   // 应用密钥
        Timeout   time.Duration `mapstructure:"timeout" validate:"min=1s"`        // 请求超时时间（默认 30s）
    }
    ```
  - 在 `Config` 结构体中添加字段:
    ```go
    type Config struct {
        // ... 现有字段
        Gateway GatewayConfig `mapstructure:"gateway"`
    }
    ```
  - 在 `pkg/config/defaults/config.yaml` 中添加默认配置:
    ```yaml
    gateway:
      base_url: "https://lplan.whjhft.com/openapi"
      app_id: ""
      app_secret: ""
      timeout: 30s
    ```
  - 在 `pkg/config/loader.go` 中绑定环境变量:
    ```go
    viper.BindEnv("gateway.base_url", "JUNHONG_GATEWAY_BASEURL")
    viper.BindEnv("gateway.app_id", "JUNHONG_GATEWAY_APPID")
    viper.BindEnv("gateway.app_secret", "JUNHONG_GATEWAY_APPSECRET")
    viper.BindEnv("gateway.timeout", "JUNHONG_GATEWAY_TIMEOUT")
    ```
  - 添加配置验证（必填项检查）

  **Must NOT do**:
  - 不在配置文件中硬编码 AppID/AppSecret（使用环境变量）
  - 不跳过验证逻辑

  **Recommended Agent Profile**:
  - **Category**: `quick`
    - Reason: 配置结构定义是标准化任务
  - **Skills**: 无
    - Reason: 配置管理遵循现有模式，无需特殊规范

  **Parallelization**:
  - **Can Run In Parallel**: YES
  - **Parallel Group**: Wave 1（与 Task 1.1 并行）
  - **Blocks**: Task 4.1（Bootstrap 初始化依赖配置）
  - **Blocked By**: None（可立即开始）

  **References**:
  - `pkg/config/config.go` - 参考现有配置结构（SMSConfig, JWTConfig）
  - `pkg/config/defaults/config.yaml` - 参考默认配置格式
  - `pkg/config/loader.go` - 参考环境变量绑定模式（viper.BindEnv）

  **Acceptance Criteria**:
  
  **配置加载验证**:
  - [ ] 配置结构定义完成: `GatewayConfig` 在 `pkg/config/config.go`
  - [ ] 默认配置存在: `pkg/config/defaults/config.yaml` 包含 gateway 配置
  - [ ] 环境变量绑定: `pkg/config/loader.go` 绑定 JUNHONG_GATEWAY_* 变量
  - [ ] 配置验证通过:
    ```bash
    export JUNHONG_GATEWAY_BASEURL="https://lplan.whjhft.com/openapi"
    export JUNHONG_GATEWAY_APPID="60bgt1X8i7AvXqkd"
    export JUNHONG_GATEWAY_APPSECRET="BZeQttaZQt0i73moF"
    go run cmd/api/main.go --help  # 验证配置加载无错误
    ```
  - [ ] 编译通过: `go build ./pkg/config/...` → 无错误

  **Commit**: YES
  - Message: `feat(config): 添加 Gateway API 配置结构`
  - Files: `pkg/config/config.go`, `pkg/config/defaults/config.yaml`, `pkg/config/loader.go`
  - Pre-commit: `go build ./pkg/config/...`

---

- [ ] **3.2 添加 Gateway 错误码（1110-1119）**

  **What to do**:
  - 在 `pkg/errors/codes.go` 中添加 Gateway 错误码常量:
    ```go
    // Gateway 相关错误 (1110-1119)
    CodeGatewayNetworkError       = 1110 // Gateway 网络错误
    CodeGatewayTimeout            = 1111 // Gateway 请求超时
    CodeGatewayBusinessError      = 1112 // Gateway 业务错误
    CodeGatewayEncryptionError    = 1113 // Gateway 加密错误
    CodeGatewayDecryptionError    = 1114 // Gateway 解密错误
    CodeGatewaySignatureError     = 1115 // Gateway 签名错误
    CodeGatewayInvalidResponse    = 1116 // Gateway 响应格式错误
    CodeGatewayNotImplemented     = 1117 // Gateway 接口未实现
    // 预留 1118-1119 供未来扩展
    ```
  - 在 `allErrorCodes` 数组中注册新错误码
  - 在 `errorMessages` 映射表中添加中文错误消息:
    ```go
    1110: "Gateway 网络错误",
    1111: "Gateway 请求超时",
    1112: "Gateway 业务错误",
    1113: "Gateway 加密失败",
    1114: "Gateway 解密失败",
    1115: "Gateway 签名错误",
    1116: "Gateway 响应格式错误",
    1117: "Gateway 接口未实现",
    ```
  - 运行错误码验证测试: `go test -v ./pkg/errors/...`

  **Must NOT do**:
  - 不使用其他范围的错误码（严格使用 1110-1119）
  - 不跳过错误码验证测试

  **Recommended Agent Profile**:
  - **Category**: `quick`
    - Reason: 错误码定义是标准化任务
  - **Skills**: 无
    - Reason: 错误码遵循现有模式

  **Parallelization**:
  - **Can Run In Parallel**: YES
  - **Parallel Group**: Wave 2（与 Task 1.2, 1.3 并行）
  - **Blocks**: Task 4.1（Bootstrap 初始化可能需要错误码）
  - **Blocked By**: Task 1.1（目录结构需先存在）

  **References**:
  - `pkg/errors/codes.go` - 参考现有错误码定义模式
  - `pkg/errors/errors_test.go` - 参考错误码验证测试

  **Acceptance Criteria**:
  
  **错误码验证**:
  - [ ] 错误码常量定义完成: `CodeGatewayNetworkError` 等在 `pkg/errors/codes.go`
  - [ ] 错误码注册完成: `allErrorCodes` 包含 1110-1119
  - [ ] 错误消息定义完成: `errorMessages` 包含中文消息
  - [ ] 错误码验证测试通过: `go test -v ./pkg/errors/...` → PASS
  - [ ] 编译通过: `go build ./pkg/errors/...` → 无错误

  **Commit**: YES
  - Message: `feat(errors): 添加 Gateway 错误码（1110-1119）`
  - Files: `pkg/errors/codes.go`
  - Pre-commit: `go test -v ./pkg/errors/...`

---

### Phase 4: 依赖注入和集成

- [ ] **4.1 Bootstrap 初始化 Gateway 客户端**

  **What to do**:
  - 在 `internal/bootstrap/dependencies.go` 的 `Dependencies` 结构体中添加字段:
    ```go
    type Dependencies struct {
        // ... 现有字段
        GatewayClient *gateway.Client // Gateway API 客户端
    }
    ```
  - 在 `internal/bootstrap/bootstrap.go` 的 `Bootstrap` 函数中初始化 Gateway 客户端:
    ```go
    // 初始化 Gateway 客户端
    gatewayClient := gateway.NewClient(
        cfg.Gateway.BaseURL,
        cfg.Gateway.AppID,
        cfg.Gateway.AppSecret,
        deps.Logger,
    ).WithTimeout(cfg.Gateway.Timeout)
    deps.GatewayClient = gatewayClient
    
    deps.Logger.Info("Gateway 客户端初始化成功",
        zap.String("base_url", cfg.Gateway.BaseURL),
        zap.Duration("timeout", cfg.Gateway.Timeout),
    )
    ```
  - 确保初始化顺序正确（在 Service 初始化之前）

  **Must NOT do**:
  - 不在 Bootstrap 中调用 Gateway API（只初始化客户端）
  - 不跳过日志记录

  **Recommended Agent Profile**:
  - **Category**: `quick`
    - Reason: 依赖注入是标准流程
  - **Skills**: 无
    - Reason: Bootstrap 模式遵循现有模式

  **Parallelization**:
  - **Can Run In Parallel**: YES
  - **Parallel Group**: Wave 5（与 Task 2.3 并行）
  - **Blocks**: Task 4.2（Service 集成依赖 Bootstrap）
  - **Blocked By**: Task 1.4, 3.1, 3.2（需要客户端、配置、错误码）

  **References**:
  - `internal/bootstrap/bootstrap.go` - 参考现有依赖初始化模式（SMS、Storage）
  - `internal/bootstrap/dependencies.go` - 参考 Dependencies 结构体定义
  - `internal/gateway/client.go` - Gateway 客户端构造函数

  **Acceptance Criteria**:
  
  **Bootstrap 验证**:
  - [ ] Dependencies 字段添加: `GatewayClient *gateway.Client`
  - [ ] Bootstrap 初始化代码完成（在 Service 初始化之前）
  - [ ] 编译通过: `go build ./cmd/api/...` → 无错误
  - [ ] 启动验证:
    ```bash
    source .env.local && go run cmd/api/main.go
    # 查看日志: "Gateway 客户端初始化成功"
    ```

  **Commit**: YES
  - Message: `feat(bootstrap): 初始化 Gateway 客户端`
  - Files: `internal/bootstrap/dependencies.go`, `internal/bootstrap/bootstrap.go`
  - Pre-commit: `go build ./cmd/api/...`

---

- [ ] **4.2 Service 层集成示例（SyncCardStatus）**

  **What to do**:
  - 在 `internal/service/iot_card/service.go` 的 `Service` 结构体中添加字段:
    ```go
    type Service struct {
        // ... 现有字段
        gatewayClient *gateway.Client // Gateway API 客户端
    }
    ```
  - 更新构造函数 `New` 添加参数:
    ```go
    func New(
        // ... 现有参数
        gatewayClient *gateway.Client,
    ) *Service {
        return &Service{
            // ... 现有字段
            gatewayClient: gatewayClient,
        }
    }
    ```
  - 新增方法 `SyncCardStatus`（从 Gateway 同步卡状态到数据库）:
    ```go
    // SyncCardStatus 从 Gateway 同步流量卡状态到数据库
    func (s *Service) SyncCardStatus(ctx context.Context, iccid string) error {
        // 1. 调用 Gateway API 查询卡状态
        resp, err := s.gatewayClient.QueryCardStatus(ctx, iccid)
        if err != nil {
            s.logger.Error("查询 Gateway 卡状态失败",
                zap.String("iccid", iccid),
                zap.Error(err),
            )
            return errors.Wrap(errors.CodeGatewayBusinessError, err, "同步卡状态失败")
        }
        
        // 2. 更新数据库中的卡状态
        err = s.iotCardStore.UpdateStatus(ctx, iccid, resp.Status)
        if err != nil {
            return errors.Wrap(errors.CodeDatabaseError, err, "更新卡状态失败")
        }
        
        s.logger.Info("同步卡状态成功",
            zap.String("iccid", iccid),
            zap.String("status", resp.Status),
        )
        return nil
    }
    ```
  - 在 `internal/bootstrap/services.go` 中更新 iot_card Service 初始化:
    ```go
    IotCard: iot_card.New(
        // ... 现有参数
        deps.GatewayClient,
    ),
    ```

  **Must NOT do**:
  - 不暴露 Gateway 响应结构给 Handler 层（封装在 Service 内）
  - 不跳过错误处理和日志记录

  **Recommended Agent Profile**:
  - **Category**: `ultrabrain`
    - Reason: Service 集成需要考虑错误处理、日志记录、数据库更新
  - **Skills**: 无
    - Reason: Service 集成是标准流程

  **Parallelization**:
  - **Can Run In Parallel**: YES
  - **Parallel Group**: Wave 5（与 Task 2.3, 5.1, 5.2 并行）
  - **Blocks**: None（集成示例不阻塞其他任务）
  - **Blocked By**: Task 4.1（需要 Bootstrap 初始化完成）

  **References**:
  - `internal/service/iot_card/service.go` - 现有 Service 结构和方法
  - `internal/bootstrap/services.go` - Service 初始化模式
  - `internal/gateway/flow_card.go` - QueryCardStatus 方法

  **Acceptance Criteria**:
  
  **集成验证**:
  - [ ] Service 字段添加: `gatewayClient *gateway.Client`
  - [ ] 构造函数更新: `New` 函数添加 gatewayClient 参数
  - [ ] SyncCardStatus 方法实现完成
  - [ ] Bootstrap 更新: `services.go` 传递 GatewayClient
  - [ ] 编译通过: `go build ./internal/service/iot_card/...` → 无错误
  - [ ] 启动验证: `source .env.local && go run cmd/api/main.go` → 无错误

  **Commit**: YES
  - Message: `feat(service): 集成 Gateway 客户端到 iot_card Service（SyncCardStatus 示例）`
  - Files: `internal/service/iot_card/service.go`, `internal/bootstrap/services.go`
  - Pre-commit: `go build ./internal/service/iot_card/...`

---

### Phase 5: 集成测试和文档

- [ ] **5.1 编写集成测试（真实 Gateway 环境）**

  **What to do**:
  - 在 `internal/gateway/integration_test.go` 中编写集成测试:
    - 使用真实 Gateway 配置（BaseURL, AppID, AppSecret）
    - 使用测试 ICCID: `8986062580006141710`
    - 测试至少 2 个流量卡接口:
      1. `QueryCardStatus` - 查询卡状态
      2. `QueryFlow` - 查询流量使用
    - **不测试设备 API**（无测试环境）
  - 集成测试结构:
    ```go
    // +build integration
    
    package gateway_test
    
    import (
        "context"
        "os"
        "testing"
        "time"
        
        "github.com/stretchr/testify/assert"
        "github.com/stretchr/testify/require"
        "go.uber.org/zap"
        
        "junhong_cmp_fiber/internal/gateway"
    )
    
    func TestIntegration_QueryCardStatus(t *testing.T) {
        if os.Getenv("JUNHONG_GATEWAY_APPID") == "" {
            t.Skip("跳过集成测试：未配置 Gateway 环境变量")
        }
        
        client := gateway.NewClient(
            os.Getenv("JUNHONG_GATEWAY_BASEURL"),
            os.Getenv("JUNHONG_GATEWAY_APPID"),
            os.Getenv("JUNHONG_GATEWAY_APPSECRET"),
            zap.NewNop(),
        ).WithTimeout(30 * time.Second)
        
        ctx := context.Background()
        resp, err := client.QueryCardStatus(ctx, "8986062580006141710")
        
        require.NoError(t, err)
        assert.NotNil(t, resp)
        assert.NotEmpty(t, resp.Status)
        
        t.Logf("卡状态查询成功: %+v", resp)
    }
    ```
  - 运行集成测试:
    ```bash
    source .env.local && go test -v ./internal/gateway/... -tags=integration -run TestIntegration
    ```

  **Must NOT do**:
  - 不在 CI/CD 中自动运行集成测试（需手动触发）
  - 不测试设备 API（无环境）
  - 不硬编码配置（使用环境变量）

  **Recommended Agent Profile**:
  - **Category**: `ultrabrain`
    - Reason: 集成测试需要处理真实 API 响应和错误场景
  - **Skills**: 无
    - Reason: 集成测试是通用技能

  **Parallelization**:
  - **Can Run In Parallel**: YES
  - **Parallel Group**: Wave 5（与 Task 2.3, 4.2, 5.2 并行）
  - **Blocks**: None（测试不阻塞其他任务）
  - **Blocked By**: Task 2.1, 2.2, 4.1（需要 API 实现和 Bootstrap）

  **References**:
  - **测试配置**: BaseURL, AppID, AppSecret, 测试 ICCID（用户提供）
  - `tests/integration/` - 参考项目的集成测试模式
  - **Go build tags**: `// +build integration` - 条件编译标记

  **Acceptance Criteria**:
  
  **集成测试验证**:
  - [ ] 集成测试文件创建: `internal/gateway/integration_test.go`
  - [ ] 测试使用 build tag: `// +build integration`
  - [ ] 测试使用环境变量（不硬编码配置）
  - [ ] 测试至少 2 个接口: QueryCardStatus, QueryFlow
  - [ ] 运行集成测试:
    ```bash
    source .env.local && go test -v ./internal/gateway/... -tags=integration -run TestIntegration
    ```
  - [ ] 集成测试通过（验证真实 Gateway API）
  - [ ] 日志输出完整（包含请求/响应详情）

  **Commit**: YES
  - Message: `test(gateway): 添加集成测试（真实 Gateway 环境）`
  - Files: `internal/gateway/integration_test.go`
  - Pre-commit: `source .env.local && go test -v ./internal/gateway/... -tags=integration -run TestIntegration`

---

- [ ] **5.2 更新文档**

  **What to do**:
  - 创建 `docs/gateway-client-usage.md` 使用文档:
    - **概述**: Gateway 客户端功能和用途
    - **配置说明**: 环境变量配置示例
    - **使用示例**: 代码示例（QueryCardStatus, QueryFlow 等）
    - **错误码说明**: Gateway 错误码（1110-1119）和处理方式
    - **重试机制**: 重试策略说明（3 次，指数退避）
    - **安全警告**: AES-128-ECB 和 MD5 的安全风险说明
    - **最佳实践**: 超时设置、错误处理、日志记录
  - 更新 `README.md`:
    - 在 "功能模块" 部分添加 Gateway 集成模块
    - 在 "配置说明" 部分添加 Gateway 环境变量说明
  - 确保所有文档使用中文

  **Must NOT do**:
  - 不过度详细（不需要 API 文档级别的详情）
  - 不添加英文文档（项目要求中文）

  **Recommended Agent Profile**:
  - **Category**: `writing`
    - Reason: 文档编写任务
  - **Skills**: [`doc-management`]
    - `doc-management`: 规范文档管理流程
    - Reason: 文档更新需要遵循项目文档规范

  **Parallelization**:
  - **Can Run In Parallel**: YES
  - **Parallel Group**: Wave 5（与 Task 2.3, 4.2, 5.1 并行）
  - **Blocks**: None（文档不阻塞其他任务）
  - **Blocked By**: All（文档需要完整功能才能编写）

  **References**:
  - `docs/` - 参考现有文档结构和风格
  - `README.md` - 参考现有 README 格式
  - **Apifox 文档**: `https://omp5mq28pq.apifox.cn/7819761m0` - Gateway API 文档（参考）
  - `internal/gateway/client.go` - Gateway 客户端实现（提取使用示例）

  **Acceptance Criteria**:
  
  **文档验证**:
  - [ ] 文档创建: `docs/gateway-client-usage.md`
  - [ ] 文档包含以下部分:
    - [ ] 概述
    - [ ] 配置说明（环境变量）
    - [ ] 使用示例（至少 2 个接口）
    - [ ] 错误码说明（1110-1119）
    - [ ] 重试机制说明
    - [ ] 安全警告（ECB + MD5）
    - [ ] 最佳实践
  - [ ] README.md 更新:
    - [ ] "功能模块" 部分添加 Gateway 集成
    - [ ] "配置说明" 部分添加 Gateway 环境变量
  - [ ] 所有文档使用中文
  - [ ] 代码示例可编译（复制到项目中能运行）

  **Commit**: YES
  - Message: `docs(gateway): 添加 Gateway 客户端使用文档`
  - Files: `docs/gateway-client-usage.md`, `README.md`
  - Pre-commit: 无（文档无需测试）

---

## Commit Strategy

| After Task | Message | Files | Verification |
|------------|---------|-------|--------------|
| 1.1 | `feat(gateway): 创建 Gateway 包目录结构` | `internal/gateway/*.go` | `go build ./internal/gateway/...` |
| 1.2 | `feat(gateway): 实现 AES-128-ECB 加密和 MD5 签名工具` | `internal/gateway/crypto.go`, `crypto_test.go` | `go test -v ./internal/gateway/ -run TestAES` |
| 1.3 | `feat(gateway): 定义 Gateway API 请求/响应 DTO 结构` | `internal/gateway/models.go`, `models_test.go` | `go test -v ./internal/gateway/ -run TestGatewayRequest` |
| 1.4 | `feat(gateway): 实现 Gateway 客户端基础结构` | `internal/gateway/client.go`, `client_test.go` | `go test -v ./internal/gateway/ -run TestNewClient` |
| 1.5 | `feat(gateway): 实现 HTTP 重试逻辑（3 次重试，指数退避）` | `internal/gateway/client.go`, `client_test.go` | `go test -v ./internal/gateway/ -run TestDoRequest` |
| 2.1 | `feat(gateway): 实现流量卡 API（6 个接口）` | `internal/gateway/flow_card.go`, `flow_card_test.go` | `go test -v ./internal/gateway/ -run TestQuery` |
| 2.2 | `feat(gateway): 实现设备 API 方法签名（7 个接口，暂未实现）` | `internal/gateway/device.go`, `device_test.go` | `go test -v ./internal/gateway/ -run TestGetDevice` |
| 2.3 | `test(gateway): 补充单元测试覆盖率（≥ 90%）` | `internal/gateway/*_test.go` | `go test -v ./internal/gateway/... -cover` |
| 3.1 | `feat(config): 添加 Gateway API 配置结构` | `pkg/config/config.go`, `defaults/config.yaml`, `loader.go` | `go build ./pkg/config/...` |
| 3.2 | `feat(errors): 添加 Gateway 错误码（1110-1119）` | `pkg/errors/codes.go` | `go test -v ./pkg/errors/...` |
| 4.1 | `feat(bootstrap): 初始化 Gateway 客户端` | `internal/bootstrap/dependencies.go`, `bootstrap.go` | `go build ./cmd/api/...` |
| 4.2 | `feat(service): 集成 Gateway 客户端到 iot_card Service（SyncCardStatus 示例）` | `internal/service/iot_card/service.go`, `bootstrap/services.go` | `go build ./internal/service/iot_card/...` |
| 5.1 | `test(gateway): 添加集成测试（真实 Gateway 环境）` | `internal/gateway/integration_test.go` | `source .env.local && go test -v ./internal/gateway/... -tags=integration` |
| 5.2 | `docs(gateway): 添加 Gateway 客户端使用文档` | `docs/gateway-client-usage.md`, `README.md` | 无 |

---

## Success Criteria

### Verification Commands
```bash
# 1. 编译检查
go build ./internal/gateway/...
go build ./cmd/api/...

# 2. 单元测试（覆盖率 ≥ 90%）
go test -v ./internal/gateway/... -cover -coverprofile=coverage.out
go tool cover -func=coverage.out | grep total

# 3. 集成测试（需先配置环境变量）
source .env.local
go test -v ./internal/gateway/... -tags=integration -run TestIntegration

# 4. LSP 错误检查
gopls check ./internal/gateway/...

# 5. 启动服务验证
source .env.local && go run cmd/api/main.go
# 查看日志: "Gateway 客户端初始化成功"
```

### Final Checklist
- [ ] 所有 14 个 Gateway API 接口成功封装（流量卡 6 个 + 设备 7 个签名）
- [ ] 加密/签名通过单元测试验证（与 Apifox 文档一致）
- [ ] 集成测试验证真实 Gateway API 调用（测试 ICCID: `8986062580006141710`）
- [ ] 重试逻辑测试通过（3 次重试，指数退避）
- [ ] 配置通过环境变量成功加载（JUNHONG_GATEWAY_*）
- [ ] 依赖注入到 iot_card Service 成功（SyncCardStatus 方法）
- [ ] 单元测试覆盖率 ≥ 90%（核心逻辑）
- [ ] 无 LSP 错误，编译通过
- [ ] 符合项目代码规范（中文注释、Go 命名规范）
- [ ] 文档完整（使用示例、错误码说明）
- [ ] 所有 "Must NOT Have" 约束遵守（无批量查询、无设备真实测试、无第三方重试库）
