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

11 KiB
Raw Blame History

共识文档

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

通过详细讨论,澄清了以下关键点:

  • 套餐周期类型(自然月/按天)独立于流量重置周期(日/月/年/不重置)
  • 首次实名激活仅限后台管理端,客户端必须已实名才能购买
  • 主套餐同时只能有一个生效,后续购买自动排队
  • 加油包完全依附于主套餐,主套餐过期时加油包也失效
  • 流量扣减优先级:加油包 > 主套餐

关键决策记录

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

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

后续步骤

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