All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m54s
- 重构 Worker 启动流程,引入 bootstrap 模块统一管理依赖注入 - 实现套餐流量重置服务(日/月/年周期重置) - 新增套餐激活排队、加油包绑定、囤货待实名激活逻辑 - 新增订单创建幂等性防重(Redis 业务键 + 分布式锁) - 更新 AGENTS.md/CLAUDE.md:新增注释规范、幂等性规范,移除测试要求 - 添加套餐系统升级完整文档(API文档、使用指南、功能总结、运维指南) - 归档 OpenSpec package-system-upgrade 变更,同步 specs 到主目录 - 新增 queue types 抽象和 Redis 常量定义
229 lines
11 KiB
Markdown
229 lines
11 KiB
Markdown
# 共识文档
|
||
|
||
**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. **验证完成** - 确保所有验收标准通过
|
||
|