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 常量定义
11 KiB
11 KiB
共识文档
Change: package-system-upgrade (套餐系统升级-支持自然月按天套餐与多套餐管理) 确认时间: 2026-02-10 确认人: 用户
1. 要做什么
-
套餐类型扩展:新增「自然月套餐」和「按天套餐」两种类型(已确认)
- 自然月套餐:按自然月边界计算有效期(如1月15日生效→1月31日失效)
- 按天套餐:按天数计算有效期(如1月15日+30天→2月13日失效)
-
流量重置周期:支持套餐流量按「日/月/年/不重置」四种周期重置(已确认)
- 独立于套餐有效期
- 例如:12个月套餐可配置为按月重置或按年重置
-
首次实名激活机制(后台囤货场景)(已确认)
- 支持未实名状态购买套餐(仅后台管理)
- 载体(设备/卡)首次实名时自动激活套餐
- 有效期从实名时刻开始计算
- 设备绑定多卡场景:任意一张卡首次实名即触发
-
主套餐排队生效(已确认)
- 同时只能有1个生效中的主套餐
- 后续购买的主套餐按购买顺序排队
- 当前主套餐到期后自动激活下一个
-
加油包生命周期管理(已确认)
- 加油包必须在有主套餐时才能购买
- 支持「独立有效期」和「跟随主套餐」两种模式
- 主套餐过期时,其关联加油包自动失效(即使流量未用完)
-
流量扣减优先级(已确认)
- 先扣加油包流量(按购买顺序)
- 最后扣主套餐流量
-
停机条件调整(已确认)
- 主套餐 + 所有加油包流量都用完才停机
-
三套流量统计系统(已确认)
- 系统A(客户视图):主套餐和加油包分开展示,含总计
- 系统B(卡流量详单):按日统计卡总流量,与套餐无关
- 系统C(套餐流量详单):按套餐维度记录每日增量流量
-
上游流量适配(已确认)
- 适配运营商周期(联通27号重置/其他1号重置)
- 每日增量 = 当前查询用量 - 昨日记录用量
-
现有API改造(已确认)
- 套餐管理API:支持新增字段(套餐类型、重置周期等)
- 订单API:支持主套餐排队逻辑、加油包购买限制
- 流量查询API:支持三套统计系统的数据展示
2. 不做什么
-
不支持旧加油包继承(已确认)
- 旧主套餐过期时,其加油包不会继承到新主套餐
- 新主套餐需要重新购买加油包
-
不支持多主套餐并行生效(已确认)
- 不允许同时有多个主套餐处于生效中状态
- 必须按排队顺序逐个生效
-
不支持客户端未实名购买(已确认)
- 首次实名激活机制仅限后台管理端
- 客户端购买套餐必须已实名
-
不支持流量跨套餐转移(已确认)
- 套餐过期后,剩余流量不能转移到新套餐
- 每个套餐独立计算流量
-
不支持手动指定主套餐生效时间(已确认)
- 主套餐生效时间由系统自动管理(按排队顺序)
- 不允许用户指定"下个月生效"等特定时间
-
不支持加油包独立存在(已确认)
- 加油包必须依附于主套餐
- 没有主套餐时不能单独使用加油包
注: 因处于开发阶段,可以完全重构,不受历史数据限制
3. 关键约束
-
技术栈约束(已确认)
- 必须使用 GORM 修改数据模型,禁止直接使用 database/sql
- 套餐生效调度使用现有轮询系统(Scheduler + PollingHandler)
- 使用 Asynq 处理异步任务(实名回调、套餐激活等)
-
数据库设计约束(已确认)
- 禁止建立外键约束
- 禁止使用 GORM 关联关系标签(foreignKey, hasMany, belongsTo)
- 关联通过 ID 字段手动维护,在代码层面显式查询
-
架构分层约束(已确认)
- 必须遵循 Handler → Service → Store → Model 分层
- Handler 层只处理 HTTP 请求/响应,不包含业务逻辑
- Service 层包含所有业务逻辑,支持事务管理
-
错误处理约束(已确认)
- 所有错误必须在 pkg/errors/ 中定义
- Service 层禁止使用 fmt.Errorf,必须返回 errors.New/errors.Wrap
- Handler 层禁止直接拼接底层错误信息给客户端
-
并发安全约束(已确认)
- 套餐激活逻辑必须支持并发安全(乐观锁/事务)
- 流量扣减逻辑必须使用数据库事务
- 主套餐排队逻辑必须防止竞态条件
-
性能约束(已确认)
- 轮询系统必须支持千万级卡规模(现有能力)
- 流量查询 API P95 < 200ms, P99 < 500ms
- 套餐激活调度延迟 < 1分钟
-
测试约束(已确认)
- 核心业务逻辑测试覆盖率 ≥ 90%
- 必须编写验收测试(基于 Spec Scenarios)
- 禁止绕过核心逻辑的测试(例如传递 nil 跳过依赖)
-
文档约束(已确认)
- 所有注释必须使用中文
- 新增 API 必须更新 OpenAPI 文档生成器
- 必须更新 CLAUDE.md 中的相关规范
4. 验收标准
数据库层
- 1. Package 表包含 calendar_type, data_reset_cycle, enable_realname_activation 字段(已确认)
- 2. PackageUsage 表 status 支持 0-待生效, 1-生效中, 2-已用完, 3-已过期, 4-已失效(已确认)
- 3. 新表 PackageUsageDailyRecord 存在且有正确索引(package_usage_id + date)(已确认)
- 4. 数据库迁移脚本执行成功,无数据丢失(已确认)
套餐购买逻辑
- 5. 后台管理端可为未实名载体购买套餐,状态为"待生效"(已确认)
- 6. 客户端未实名时购买套餐返回错误提示(已确认)
- 7. 购买第2个主套餐时,priority 自动递增,状态为"待生效"(已确认)
- 8. 购买加油包时,无主套餐返回错误"必须有主套餐才能购买加油包"(已确认)
实名激活逻辑
- 9. 设备第1张卡实名后,待生效套餐自动变为"生效中"(已确认)
- 10. 设备第2、第3张卡实名后,套餐状态不变(已确认)
- 11. 实名激活的套餐,activated_at = 实名时刻,expires_at 按套餐类型计算(已确认)
主套餐排队逻辑
- 12. 当前主套餐过期后,1分钟内 priority 最小的待生效主套餐自动激活(已确认)
- 13. 自然月套餐激活时,expires_at 为当月最后一天 23:59:59(已确认)
- 14. 按天套餐激活时,expires_at = activated_at + duration_days(已确认)
加油包生命周期
- 15. 主套餐过期时,其关联加油包状态变为"已失效"(已确认)
- 16. 独立有效期的加油包过期时,状态变为"已过期"(已确认)
流量扣减逻辑
- 17. 新增流量时,优先扣减 priority 最小的加油包(已确认)
- 18. 所有加油包用完后,才开始扣减主套餐流量(已确认)
- 19. 主套餐 + 所有加油包流量都用完时,轮询系统触发停机(已确认)
流量统计系统
- 20. 客户视图 API 返回:主套餐、每个加油包、总计(三个数据)(已确认)
- 21. 卡流量详单 API 按日返回,包含 date, daily_increase_mb, total_mb(已确认)
- 22. 套餐流量详单 API 按套餐维度,按日返回,包含 date, daily_usage_mb, cumulative_mb(已确认)
流量重置逻辑
- 23. reset_cycle=daily 的套餐,每天0点重置 data_usage_mb 为 0(已确认)
- 24. reset_cycle=monthly 的套餐,每月1号0点重置(或根据运营商配置)(已确认)
- 25. reset_cycle=yearly 的套餐,每年1月1号0点重置(已确认)
API 改造
- 26. POST /api/admin/packages 支持新增字段创建套餐(已确认)
- 27. GET /api/admin/packages/:id 返回包含新增字段(已确认)
- 28. POST /api/admin/orders 支持主套餐排队逻辑(已确认)
- 29. 新增 GET /api/h5/packages/my-usage 返回客户视图数据(已确认)
- 30. 新增 GET /api/admin/package-usage/:id/daily-records 返回套餐流量详单(已确认)
性能指标
- 31. 流量查询 API 响应时间 P95 < 200ms(已确认)
- 32. 套餐激活调度延迟 < 1分钟(已确认)
- 33. 轮询系统支持千万级卡规模(现有能力不退化)(已确认)
测试覆盖
- 34. 核心业务逻辑单元测试覆盖率 ≥ 90%(已确认)
- 35. 所有 Spec Scenarios 有对应的验收测试(已确认)
- 36. 所有验收测试在实现前生成且预期 FAIL(已确认)
讨论背景
在探索阶段,用户提出了需求方补充的套餐系统需求,核心问题包括:
- 套餐类型多样化:现有系统只有按月计算的简单套餐,需要支持自然月和按天两种计算方式
- 囤货场景支持:代理商需要提前为未实名设备囤货(低价采购),等待首次实名时自动激活
- 多套餐管理复杂度:需要支持主套餐排队、加油包生命周期管理、流量扣减优先级等复杂逻辑
- 流量统计精细化:需要三套独立的流量统计系统分别服务于客户视图、卡维度统计、套餐维度统计
通过详细讨论,澄清了以下关键点:
- 套餐周期类型(自然月/按天)独立于流量重置周期(日/月/年/不重置)
- 首次实名激活仅限后台管理端,客户端必须已实名才能购买
- 主套餐同时只能有一个生效,后续购买自动排队
- 加油包完全依附于主套餐,主套餐过期时加油包也失效
- 流量扣减优先级:加油包 > 主套餐
关键决策记录
| 决策点 | 选择 | 原因 |
|---|---|---|
| 套餐类型与重置周期 | 分为两个独立维度 | 灵活性更高,支持"自然月年套餐按年重置"等复杂场景 |
| 首次实名激活权限 | 仅限后台管理端 | 防止客户端恶意囤货,保证正常业务流程 |
| 主套餐并发控制 | 同时只能有1个生效 | 简化业务逻辑,符合运营商套餐习惯 |
| 加油包继承机制 | 不继承,跟随主套餐失效 | 避免复杂的跨套餐关联,符合运营商逻辑 |
| 流量扣减优先级 | 加油包优先 | 鼓励用户购买加油包,提升营收 |
| 历史数据处理 | 可完全重构 | 开发阶段,无需兼容历史数据 |
| 流量统计系统 | 三套独立系统 | 满足不同场景需求(客户视图、数据统计、套餐分析) |
签字确认: 用户已通过 Question_tool 逐条确认以上内容
后续步骤
- 生成 Proposal - 使用
/opsx:continue创建提案,定义 Capabilities - 设计数据模型 - 创建 Design artifact,详细设计数据库结构和业务流程
- 编写 Spec - 定义详细的 API 规范和业务场景
- 生成验收测试 - 从 Spec Scenarios 自动生成测试骨架
- 实现功能 - 按照 Tasks 逐步实现
- 验证完成 - 确保所有验收标准通过