## Context

当前代理充值线下确认接口（`OfflinePay`）通过将 `operation_password` 与操作人自己的登录密码（`account.Password`）做 bcrypt 对比来实现操作密码验证。这个机制存在两个问题：

1. **缺乏独立性**：操作密码与登录密码耦合，修改登录密码即等于修改操作密码，无法独立管控。
2. **安全边界不清**：需要操作密码的敏感操作（如确认大额资金流转）应由超级管理员统一管控，而非各操作人分散管理。

设计决策：操作密码存 Redis，不开新表。原因：操作密码是全局单一配置，没有历史版本需求，Redis 的 SET/GET 完全满足需求，避免引入新表的维护成本。

## Goals / Non-Goals

**Goals:**
- 超级管理员可以设置/修改全局操作密码（存 Redis，bcrypt 哈希）
- 提供查询接口返回操作密码是否已设置（不暴露密码本身）
- `OfflinePay` 的操作密码验证从"当前用户登录密码"改为"全局操作密码"
- 封装 `VerifyOperationPassword` 工具函数，供后续接口统一复用

**Non-Goals:**
- 不做操作密码的过期机制（非当前需求）
- 不做操作密码历史记录
- 不修改除 `agent_recharge.OfflinePay` 以外的其他接口（其他接口暂无此需求）

## Decisions

### 决策1：存储介质选 Redis 而非数据库新表

**选择**：Redis `SET system:operation_password <bcrypt_hash>` 永久存储（无 TTL）。

**理由**：全局单一配置，无历史记录需求，Redis 的简单 KV 足够。Key 命名遵循项目规范，定义在 `pkg/constants/redis.go`。

**备选**：新建 `tb_system_config` 表 → 引入表管理、迁移、GORM 操作，过度设计。

### 决策2：新接口归属路径

**选择**：`POST /api/admin/super-admin/operation-password`（设置/修改）和 `GET /api/admin/super-admin/operation-password/status`（查询状态）。

**理由**：`/super-admin/` 路径前缀清晰表达"仅超级管理员"语义，与现有路由命名惯例一致。Handler 层检查 `userType == UserTypeSuperAdmin`，非超级管理员返回 403。

### 决策3：Service 层封装独立的 OperationPassword 服务

**选择**：新建 `internal/service/operation_password/service.go`，提供 `Set(ctx, password)` 和 `Verify(ctx, inputPassword) error` 两个方法。

**理由**：将操作密码逻辑从 `agent_recharge` Service 中解耦，后续接口可直接注入复用，避免逻辑散落多处。

### 决策4：未设置时的行为

**选择**：操作密码未设置时，`Verify` 返回"操作密码未设置，请联系超级管理员"错误，拒绝操作。

**理由**：不降级为登录密码（安全边界清晰）。初次上线前超级管理员需先设置操作密码。

### 决策5：bcrypt 哈希存 Redis

**选择**：Set 时用 `bcrypt.GenerateFromPassword` 哈希后存储，Verify 时用 `bcrypt.CompareHashAndPassword` 对比。

**理由**：即使 Redis 被访问，也无法还原明文密码。与现有登录密码处理方式一致。

## Risks / Trade-offs

**[风险] 初次上线前操作密码未设置**
→ `OfflinePay` 接口会返回"操作密码未设置"错误。需在上线前由超级管理员设置初始操作密码。

**[风险] Redis 数据丢失**
→ 如 Redis 数据被清空，操作密码丢失，所有需要操作密码的接口将拒绝服务。
→ 缓解：Redis 持久化（AOF/RDB）已在生产环境启用；超级管理员可随时重设。

**[风险] bcrypt 计算开销**
→ bcrypt 默认 cost=10，约 100ms/次。此接口调用频率极低（管理操作），不影响系统整体性能。

## Migration Plan

1. 部署代码变更（新接口 + Redis 验证逻辑）
2. 超级管理员登录后台，调用 `POST /api/admin/super-admin/operation-password` 设置初始操作密码
3. 验证 `GET /api/admin/super-admin/operation-password/status` 返回已设置
4. 验证 `OfflinePay` 接口使用新操作密码可正常通过
