Files
junhong_cmp_fiber/openspec/changes/archive/2026-02-12-package-system-upgrade/consensus.md
huang c665f32976
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m54s
feat: 套餐系统升级 - Worker 重构、流量重置、文档与规范更新
- 重构 Worker 启动流程,引入 bootstrap 模块统一管理依赖注入
- 实现套餐流量重置服务(日/月/年周期重置)
- 新增套餐激活排队、加油包绑定、囤货待实名激活逻辑
- 新增订单创建幂等性防重(Redis 业务键 + 分布式锁)
- 更新 AGENTS.md/CLAUDE.md:新增注释规范、幂等性规范,移除测试要求
- 添加套餐系统升级完整文档(API文档、使用指南、功能总结、运维指南)
- 归档 OpenSpec package-system-upgrade 变更,同步 specs 到主目录
- 新增 queue types 抽象和 Redis 常量定义
2026-02-12 14:24:15 +08:00

229 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 共识文档
**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. **验证完成** - 确保所有验收标准通过