# 共识文档

**Change**: package-system-upgrade (套餐系统升级-支持自然月按天套餐与多套餐管理)
**确认时间**: 2026-02-10
**确认人**: 用户

---

## 1. 要做什么

- [x] **套餐类型扩展**：新增「自然月套餐」和「按天套餐」两种类型（已确认）
  - 自然月套餐：按自然月边界计算有效期（如1月15日生效→1月31日失效）
  - 按天套餐：按天数计算有效期（如1月15日+30天→2月13日失效）

- [x] **流量重置周期**：支持套餐流量按「日/月/年/不重置」四种周期重置（已确认）
  - 独立于套餐有效期
  - 例如：12个月套餐可配置为按月重置或按年重置

- [x] **首次实名激活机制**（后台囤货场景）（已确认）
  - 支持未实名状态购买套餐（仅后台管理）
  - 载体（设备/卡）首次实名时自动激活套餐
  - 有效期从实名时刻开始计算
  - 设备绑定多卡场景：任意一张卡首次实名即触发

- [x] **主套餐排队生效**（已确认）
  - 同时只能有1个生效中的主套餐
  - 后续购买的主套餐按购买顺序排队
  - 当前主套餐到期后自动激活下一个

- [x] **加油包生命周期管理**（已确认）
  - 加油包必须在有主套餐时才能购买
  - 支持「独立有效期」和「跟随主套餐」两种模式
  - 主套餐过期时，其关联加油包自动失效（即使流量未用完）

- [x] **流量扣减优先级**（已确认）
  - 先扣加油包流量（按购买顺序）
  - 最后扣主套餐流量

- [x] **停机条件调整**（已确认）
  - 主套餐 + 所有加油包流量都用完才停机

- [x] **三套流量统计系统**（已确认）
  - 系统A（客户视图）：主套餐和加油包分开展示，含总计
  - 系统B（卡流量详单）：按日统计卡总流量，与套餐无关
  - 系统C（套餐流量详单）：按套餐维度记录每日增量流量

- [x] **上游流量适配**（已确认）
  - 适配运营商周期（联通27号重置/其他1号重置）
  - 每日增量 = 当前查询用量 - 昨日记录用量

- [x] **现有API改造**（已确认）
  - 套餐管理API：支持新增字段（套餐类型、重置周期等）
  - 订单API：支持主套餐排队逻辑、加油包购买限制
  - 流量查询API：支持三套统计系统的数据展示

## 2. 不做什么

- [x] **不支持旧加油包继承**（已确认）
  - 旧主套餐过期时，其加油包不会继承到新主套餐
  - 新主套餐需要重新购买加油包

- [x] **不支持多主套餐并行生效**（已确认）
  - 不允许同时有多个主套餐处于生效中状态
  - 必须按排队顺序逐个生效

- [x] **不支持客户端未实名购买**（已确认）
  - 首次实名激活机制仅限后台管理端
  - 客户端购买套餐必须已实名

- [x] **不支持流量跨套餐转移**（已确认）
  - 套餐过期后，剩余流量不能转移到新套餐
  - 每个套餐独立计算流量

- [x] **不支持手动指定主套餐生效时间**（已确认）
  - 主套餐生效时间由系统自动管理（按排队顺序）
  - 不允许用户指定"下个月生效"等特定时间

- [x] **不支持加油包独立存在**（已确认）
  - 加油包必须依附于主套餐
  - 没有主套餐时不能单独使用加油包

**注**: 因处于开发阶段，可以完全重构，不受历史数据限制

## 3. 关键约束

- [x] **技术栈约束**（已确认）
  - 必须使用 GORM 修改数据模型，禁止直接使用 database/sql
  - 套餐生效调度使用现有轮询系统（Scheduler + PollingHandler）
  - 使用 Asynq 处理异步任务（实名回调、套餐激活等）

- [x] **数据库设计约束**（已确认）
  - 禁止建立外键约束
  - 禁止使用 GORM 关联关系标签（foreignKey, hasMany, belongsTo）
  - 关联通过 ID 字段手动维护，在代码层面显式查询

- [x] **架构分层约束**（已确认）
  - 必须遵循 Handler → Service → Store → Model 分层
  - Handler 层只处理 HTTP 请求/响应，不包含业务逻辑
  - Service 层包含所有业务逻辑，支持事务管理

- [x] **错误处理约束**（已确认）
  - 所有错误必须在 pkg/errors/ 中定义
  - Service 层禁止使用 fmt.Errorf，必须返回 errors.New/errors.Wrap
  - Handler 层禁止直接拼接底层错误信息给客户端

- [x] **并发安全约束**（已确认）
  - 套餐激活逻辑必须支持并发安全（乐观锁/事务）
  - 流量扣减逻辑必须使用数据库事务
  - 主套餐排队逻辑必须防止竞态条件

- [x] **性能约束**（已确认）
  - 轮询系统必须支持千万级卡规模（现有能力）
  - 流量查询 API P95 < 200ms, P99 < 500ms
  - 套餐激活调度延迟 < 1分钟

- [x] **测试约束**（已确认）
  - 核心业务逻辑测试覆盖率 ≥ 90%
  - 必须编写验收测试（基于 Spec Scenarios）
  - 禁止绕过核心逻辑的测试（例如传递 nil 跳过依赖）

- [x] **文档约束**（已确认）
  - 所有注释必须使用中文
  - 新增 API 必须更新 OpenAPI 文档生成器
  - 必须更新 CLAUDE.md 中的相关规范

## 4. 验收标准

### 数据库层
- [x] 1. Package 表包含 calendar_type, data_reset_cycle, enable_realname_activation 字段（已确认）
- [x] 2. PackageUsage 表 status 支持 0-待生效, 1-生效中, 2-已用完, 3-已过期, 4-已失效（已确认）
- [x] 3. 新表 PackageUsageDailyRecord 存在且有正确索引（package_usage_id + date）（已确认）
- [x] 4. 数据库迁移脚本执行成功，无数据丢失（已确认）

### 套餐购买逻辑
- [x] 5. 后台管理端可为未实名载体购买套餐，状态为"待生效"（已确认）
- [x] 6. 客户端未实名时购买套餐返回错误提示（已确认）
- [x] 7. 购买第2个主套餐时，priority 自动递增，状态为"待生效"（已确认）
- [x] 8. 购买加油包时，无主套餐返回错误"必须有主套餐才能购买加油包"（已确认）

### 实名激活逻辑
- [x] 9. 设备第1张卡实名后，待生效套餐自动变为"生效中"（已确认）
- [x] 10. 设备第2、第3张卡实名后，套餐状态不变（已确认）
- [x] 11. 实名激活的套餐，activated_at = 实名时刻，expires_at 按套餐类型计算（已确认）

### 主套餐排队逻辑
- [x] 12. 当前主套餐过期后，1分钟内 priority 最小的待生效主套餐自动激活（已确认）
- [x] 13. 自然月套餐激活时，expires_at 为当月最后一天 23:59:59（已确认）
- [x] 14. 按天套餐激活时，expires_at = activated_at + duration_days（已确认）

### 加油包生命周期
- [x] 15. 主套餐过期时，其关联加油包状态变为"已失效"（已确认）
- [x] 16. 独立有效期的加油包过期时，状态变为"已过期"（已确认）

### 流量扣减逻辑
- [x] 17. 新增流量时，优先扣减 priority 最小的加油包（已确认）
- [x] 18. 所有加油包用完后，才开始扣减主套餐流量（已确认）
- [x] 19. 主套餐 + 所有加油包流量都用完时，轮询系统触发停机（已确认）

### 流量统计系统
- [x] 20. 客户视图 API 返回：主套餐、每个加油包、总计（三个数据）（已确认）
- [x] 21. 卡流量详单 API 按日返回，包含 date, daily_increase_mb, total_mb（已确认）
- [x] 22. 套餐流量详单 API 按套餐维度，按日返回，包含 date, daily_usage_mb, cumulative_mb（已确认）

### 流量重置逻辑
- [x] 23. reset_cycle=daily 的套餐，每天0点重置 data_usage_mb 为 0（已确认）
- [x] 24. reset_cycle=monthly 的套餐，每月1号0点重置（或根据运营商配置）（已确认）
- [x] 25. reset_cycle=yearly 的套餐，每年1月1号0点重置（已确认）

### API 改造
- [x] 26. POST /api/admin/packages 支持新增字段创建套餐（已确认）
- [x] 27. GET /api/admin/packages/:id 返回包含新增字段（已确认）
- [x] 28. POST /api/admin/orders 支持主套餐排队逻辑（已确认）
- [x] 29. 新增 GET /api/h5/packages/my-usage 返回客户视图数据（已确认）
- [x] 30. 新增 GET /api/admin/package-usage/:id/daily-records 返回套餐流量详单（已确认）

### 性能指标
- [x] 31. 流量查询 API 响应时间 P95 < 200ms（已确认）
- [x] 32. 套餐激活调度延迟 < 1分钟（已确认）
- [x] 33. 轮询系统支持千万级卡规模（现有能力不退化）（已确认）

### 测试覆盖
- [x] 34. 核心业务逻辑单元测试覆盖率 ≥ 90%（已确认）
- [x] 35. 所有 Spec Scenarios 有对应的验收测试（已确认）
- [x] 36. 所有验收测试在实现前生成且预期 FAIL（已确认）

---

## 讨论背景

在探索阶段，用户提出了需求方补充的套餐系统需求，核心问题包括：

1. **套餐类型多样化**：现有系统只有按月计算的简单套餐，需要支持自然月和按天两种计算方式
2. **囤货场景支持**：代理商需要提前为未实名设备囤货（低价采购），等待首次实名时自动激活
3. **多套餐管理复杂度**：需要支持主套餐排队、加油包生命周期管理、流量扣减优先级等复杂逻辑
4. **流量统计精细化**：需要三套独立的流量统计系统分别服务于客户视图、卡维度统计、套餐维度统计

通过详细讨论，澄清了以下关键点：
- 套餐周期类型（自然月/按天）独立于流量重置周期（日/月/年/不重置）
- 首次实名激活仅限后台管理端，客户端必须已实名才能购买
- 主套餐同时只能有一个生效，后续购买自动排队
- 加油包完全依附于主套餐，主套餐过期时加油包也失效
- 流量扣减优先级：加油包 > 主套餐

## 关键决策记录

| 决策点 | 选择 | 原因 |
|--------|------|------|
| 套餐类型与重置周期 | 分为两个独立维度 | 灵活性更高，支持"自然月年套餐按年重置"等复杂场景 |
| 首次实名激活权限 | 仅限后台管理端 | 防止客户端恶意囤货，保证正常业务流程 |
| 主套餐并发控制 | 同时只能有1个生效 | 简化业务逻辑，符合运营商套餐习惯 |
| 加油包继承机制 | 不继承，跟随主套餐失效 | 避免复杂的跨套餐关联，符合运营商逻辑 |
| 流量扣减优先级 | 加油包优先 | 鼓励用户购买加油包，提升营收 |
| 历史数据处理 | 可完全重构 | 开发阶段，无需兼容历史数据 |
| 流量统计系统 | 三套独立系统 | 满足不同场景需求（客户视图、数据统计、套餐分析）|

---

**签字确认**: 用户已通过 Question_tool 逐条确认以上内容

## 后续步骤

1. **生成 Proposal** - 使用 `/opsx:continue` 创建提案，定义 Capabilities
2. **设计数据模型** - 创建 Design artifact，详细设计数据库结构和业务流程
3. **编写 Spec** - 定义详细的 API 规范和业务场景
4. **生成验收测试** - 从 Spec Scenarios 自动生成测试骨架
5. **实现功能** - 按照 Tasks 逐步实现
6. **验证完成** - 确保所有验收标准通过

