# 微信公众号能力规格说明

## ADDED Requirements

### Requirement: 系统必须支持微信 OAuth 2.0 授权登录

系统 SHALL 实现微信公众号 OAuth 2.0 授权流程，允许个人客户通过微信授权获取用户身份信息。

#### Scenario: 用户首次通过微信授权码登录成功
- **WHEN** 用户在前端完成微信授权，后端接收到有效的授权码（code）
- **THEN** 系统调用微信 API 获取用户 OpenID、UnionID 和基本信息（昵称、头像）
- **THEN** 系统在数据库中创建新的个人客户记录，保存微信 OpenID 和 UnionID
- **THEN** 系统生成 JWT Token 并返回给客户端

#### Scenario: 已存在的微信用户再次登录
- **WHEN** 用户通过微信授权码登录，且该 OpenID 已存在于数据库
- **THEN** 系统查询到现有客户记录
- **THEN** 系统更新客户的昵称和头像信息（保持最新）
- **THEN** 系统生成 JWT Token 并返回给客户端

#### Scenario: 微信授权码无效或过期
- **WHEN** 用户提交的授权码无效、过期或已被使用
- **THEN** 系统调用微信 API 失败
- **THEN** 系统返回错误码 1040（微信 OAuth 授权失败）和中文错误消息"微信授权失败，请重试"

#### Scenario: 微信 API 服务不可用
- **WHEN** 调用微信 API 时发生网络超时或微信服务异常
- **THEN** 系统记录详细的错误日志（包含 Request ID）
- **THEN** 系统返回错误码 1040（微信 OAuth 授权失败）和用户友好的中文错误消息

### Requirement: 系统必须支持已有账号绑定微信

系统 SHALL 允许已注册的个人客户（通过手机号登录）绑定微信账号。

#### Scenario: 用户成功绑定微信账号
- **WHEN** 已登录用户提交有效的微信授权码，且该用户尚未绑定微信
- **THEN** 系统调用微信 API 获取 OpenID 和 UnionID
- **THEN** 系统验证该 OpenID 未被其他用户绑定
- **THEN** 系统更新该用户的 wx_open_id 和 wx_union_id 字段
- **THEN** 系统返回成功响应和更新后的用户信息

#### Scenario: 尝试绑定已被使用的微信账号
- **WHEN** 用户提交的微信授权码对应的 OpenID 已被其他用户绑定
- **THEN** 系统返回错误码 1036（微信账号已被绑定）和中文错误消息"该微信账号已绑定其他用户"

#### Scenario: 用户已绑定微信后再次绑定
- **WHEN** 已绑定微信的用户再次提交微信授权码
- **THEN** 系统更新用户的昵称和头像信息
- **THEN** 系统返回成功响应（允许更新信息，不报错）

### Requirement: 系统必须支持通过 OpenID/UnionID 查询用户

系统 MUST 提供通过微信 OpenID 或 UnionID 查询个人客户的能力。

#### Scenario: 通过 OpenID 查询到用户
- **WHEN** 调用 Store 层的 GetByWxOpenID 方法，传入有效的 OpenID
- **THEN** 系统返回对应的个人客户记录

#### Scenario: 通过 OpenID 查询不到用户
- **WHEN** 调用 Store 层的 GetByWxOpenID 方法，传入不存在的 OpenID
- **THEN** 系统返回 nil（无错误，表示用户不存在）

#### Scenario: 通过 UnionID 查询到用户
- **WHEN** 调用 Store 层的 GetByWxUnionID 方法，传入有效的 UnionID
- **THEN** 系统返回对应的个人客户记录

### Requirement: 系统必须实现 Access Token 中控

系统 MUST 使用 Redis 缓存微信 Access Token，支持多实例共享，避免重复获取导致超出每日限额。

#### Scenario: 首次获取 Access Token
- **WHEN** 系统首次调用微信 API 需要 Access Token
- **THEN** 系统调用微信 API 获取 Access Token
- **THEN** 系统将 Token 存储到 Redis（Key: `powerwechat.access_token.{MD5(appid+secret)}`，TTL: 7200秒）
- **THEN** 系统使用该 Token 完成 API 调用

#### Scenario: 从 Redis 缓存获取 Token
- **WHEN** 系统调用微信 API，Redis 中存在有效的 Access Token
- **THEN** 系统直接使用缓存的 Token，不调用微信 API 获取新 Token

#### Scenario: Access Token 过期后自动刷新
- **WHEN** 系统使用缓存的 Token 调用微信 API 返回 Token 过期错误
- **THEN** 系统自动重新获取 Access Token
- **THEN** 系统更新 Redis 缓存
- **THEN** 系统重试原 API 调用

### Requirement: API 必须遵循统一响应格式

所有微信相关 API MUST 返回统一的 JSON 响应格式。

#### Scenario: 成功响应格式
- **WHEN** API 调用成功
- **THEN** 系统返回 HTTP 200 和以下 JSON 格式：
  ```json
  {
    "code": 0,
    "message": "success",
    "data": { /* 业务数据 */ },
    "timestamp": 1706789012345
  }
  ```

#### Scenario: 失败响应格式
- **WHEN** API 调用失败（参数错误、业务逻辑错误、微信 API 错误）
- **THEN** 系统返回对应的 HTTP 状态码（400/401/500）和以下 JSON 格式：
  ```json
  {
    "code": 1040,
    "message": "微信授权失败，请重试",
    "data": null,
    "timestamp": 1706789012345
  }
  ```

### Requirement: 系统必须记录完整的日志

所有微信 API 调用 MUST 记录完整的日志，便于排查问题。

#### Scenario: 记录微信 API 请求日志
- **WHEN** 系统调用微信 API
- **THEN** 系统记录 INFO 级别日志，包含：Request ID、API 端点、请求参数（脱敏）

#### Scenario: 记录微信 API 响应日志
- **WHEN** 系统收到微信 API 响应
- **THEN** 系统记录 INFO 级别日志，包含：Request ID、响应状态、响应时间、关键字段

#### Scenario: 记录微信 API 错误日志
- **WHEN** 微信 API 调用失败
- **THEN** 系统记录 ERROR 级别日志，包含：Request ID、错误码、错误消息、完整的错误详情

### Requirement: 系统必须支持配置管理

微信公众号相关配置 MUST 通过 Viper + 环境变量管理。

#### Scenario: 从环境变量读取配置
- **WHEN** 系统启动时
- **THEN** 系统从环境变量读取以下配置：
  - `JUNHONG_WECHAT_OFFICIAL_ACCOUNT_APP_ID`（公众号 AppID）
  - `JUNHONG_WECHAT_OFFICIAL_ACCOUNT_APP_SECRET`（公众号 AppSecret）
  - `JUNHONG_WECHAT_OFFICIAL_ACCOUNT_TOKEN`（回调 Token）
  - `JUNHONG_WECHAT_OFFICIAL_ACCOUNT_AES_KEY`（回调加密密钥）
  - `JUNHONG_WECHAT_OFFICIAL_ACCOUNT_OAUTH_REDIRECT_URL`（OAuth 回调地址）

#### Scenario: 配置缺失时启动失败
- **WHEN** 必填配置项（AppID、AppSecret）缺失
- **THEN** 系统记录 FATAL 级别日志
- **THEN** 系统启动失败并退出
