Files
junhong_cmp_fiber/openspec/specs/package-management/spec.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

10 KiB
Raw Blame History

Requirements

Requirement: 创建套餐

系统 SHALL 允许平台管理员创建套餐,包含套餐编码、套餐名称、所属系列、套餐类型、时长、周期类型calendar_type、流量重置周期data_reset_cycle、是否需要实名激活enable_realname_activation、流量配置、价格和建议价格。套餐编码 MUST 全局唯一(排除已删除记录)。新创建的套餐默认为启用状态(1)和下架状态(2)。

Scenario: 成功创建自然月套餐

  • GIVEN 管理员提供套餐信息calendar_type=natural_monthduration_months=1
  • WHEN 提交创建请求
  • THEN 系统创建套餐,状态=1上架状态=2calendar_type=natural_month

Scenario: 成功创建按天套餐

  • GIVEN 管理员提供套餐信息calendar_type=by_dayduration_days=30
  • WHEN 提交创建请求
  • THEN 系统创建套餐calendar_type=by_dayduration_days=30

Scenario: 套餐编码重复

  • GIVEN 数据库中存在套餐编码为 "PKG001" 的套餐(未删除)
  • WHEN 管理员创建套餐,编码为 "PKG001"
  • THEN 系统返回错误 "套餐编码已存在"

Scenario: 关联不存在的套餐系列

  • GIVEN 管理员指定 series_id=999但系列不存在
  • WHEN 提交创建请求
  • THEN 系统返回错误 "套餐系列不存在"

Scenario: 缺少必填字段

  • GIVEN 管理员未提供套餐编码
  • WHEN 提交创建请求
  • THEN 系统返回参数验证错误 "套餐编码为必填项"

Scenario: 创建自然月套餐时必须提供 duration_months

  • GIVEN 管理员创建套餐calendar_type=natural_month但未提供 duration_months
  • WHEN 提交创建请求
  • THEN 系统返回错误 "自然月套餐必须指定 duration_months"

Scenario: 创建按天套餐时必须提供 duration_days

  • GIVEN 管理员创建套餐calendar_type=by_day但未提供 duration_days
  • WHEN 提交创建请求
  • THEN 系统返回错误 "按天套餐必须指定 duration_days"

Scenario: 默认 data_reset_cycle 为 monthly

  • GIVEN 管理员创建主套餐,未指定 data_reset_cycle
  • WHEN 提交创建请求
  • THEN 系统自动设置 data_reset_cycle=monthly

Scenario: 默认 enable_realname_activation 为 true

  • GIVEN 管理员创建主套餐,未指定 enable_realname_activation
  • WHEN 提交创建请求
  • THEN 系统自动设置 enable_realname_activation=true

Requirement: 查询套餐列表

系统 SHALL 提供套餐列表查询功能,支持按套餐名称模糊搜索、按系列 ID 筛选、按状态筛选、按上架状态筛选、按套餐类型筛选。结果 MUST 分页返回,按创建时间倒序排列。

Scenario: 查询所有套餐

  • WHEN 管理员请求套餐列表,不带筛选条件
  • THEN 系统返回所有未删除的套餐,分页显示

Scenario: 按系列筛选

  • WHEN 管理员指定套餐系列 ID
  • THEN 系统只返回属于该系列的套餐

Scenario: 按名称搜索

  • WHEN 管理员提供套餐名称关键字
  • THEN 系统返回名称包含该关键字的套餐

Scenario: 按状态筛选

  • WHEN 管理员指定启用状态
  • THEN 系统只返回匹配启用状态的套餐

Scenario: 按上架状态筛选

  • WHEN 管理员指定上架状态
  • THEN 系统只返回匹配上架状态的套餐

Scenario: 按套餐类型筛选

  • WHEN 管理员指定套餐类型formal/addon
  • THEN 系统只返回匹配类型的套餐

Requirement: 查询套餐详情

系统 SHALL 允许管理员查询单个套餐的详细信息,响应包含新增字段calendar_type, data_reset_cycle, enable_realname_activation

Scenario: 查询存在的套餐

  • GIVEN 数据库中存在套餐 ID=1
  • WHEN 管理员请求套餐详情
  • THEN 系统返回该套餐的完整信息,包含所有新增字段

Scenario: 查询不存在的套餐

  • GIVEN 管理员请求套餐 ID=999但套餐不存在
  • WHEN 提交查询请求
  • THEN 系统返回 "套餐不存在" 错误

Scenario: 响应包含周期类型信息

  • GIVEN 套餐 calendar_type=natural_monthduration_months=1
  • WHEN 管理员查询套餐详情
  • THEN 响应包含 calendar_type=natural_monthduration_months=1

Scenario: 响应包含流量重置周期信息

  • GIVEN 套餐 data_reset_cycle=monthly
  • WHEN 管理员查询套餐详情
  • THEN 响应包含 data_reset_cycle=monthly

Scenario: 响应包含实名激活配置

  • GIVEN 套餐 enable_realname_activation=true
  • WHEN 管理员查询套餐详情
  • THEN 响应包含 enable_realname_activation=true

Requirement: 更新套餐

系统 SHALL 允许管理员更新套餐的基本信息,包括周期类型、流量重置周期、实名激活配置等新增字段。套餐编码创建后 MUST NOT 允许修改。

Scenario: 成功更新套餐基本信息

  • GIVEN 管理员更新套餐名称和价格
  • WHEN 提交更新请求
  • THEN 系统更新套餐记录,返回更新后的详情

Scenario: 尝试修改套餐编码

  • GIVEN 管理员尝试修改套餐编码
  • WHEN 提交更新请求
  • THEN 系统忽略套餐编码字段,不进行修改

Scenario: 更新不存在的套餐

  • GIVEN 管理员更新套餐 ID=999但套餐不存在
  • WHEN 提交更新请求
  • THEN 系统返回 "套餐不存在" 错误

Scenario: 关联不存在的套餐系列

  • GIVEN 管理员将套餐的 series_id 改为 999但系列不存在
  • WHEN 提交更新请求
  • THEN 系统返回错误 "套餐系列不存在"

Scenario: 更新套餐周期类型(从自然月改为按天)

  • GIVEN 套餐当前 calendar_type=natural_monthduration_months=1
  • WHEN 管理员更新 calendar_type=by_dayduration_days=30
  • THEN 系统更新成功calendar_type=by_dayduration_days=30

Scenario: 更新套餐周期类型(从按天改为自然月)

  • GIVEN 套餐当前 calendar_type=by_dayduration_days=30
  • WHEN 管理员更新 calendar_type=natural_monthduration_months=1
  • THEN 系统更新成功calendar_type=natural_monthduration_months=1

Scenario: 更新周期类型但未提供对应时长字段

  • GIVEN 套餐当前 calendar_type=by_day
  • WHEN 管理员更新 calendar_type=natural_month但未提供 duration_months
  • THEN 系统返回错误 "自然月套餐必须指定 duration_months"

Scenario: 更新 data_reset_cycle

  • GIVEN 套餐当前 data_reset_cycle=monthly
  • WHEN 管理员更新 data_reset_cycle=daily
  • THEN 系统更新成功data_reset_cycle=daily

Scenario: 更新 enable_realname_activation

  • GIVEN 套餐当前 enable_realname_activation=true
  • WHEN 管理员更新 enable_realname_activation=false
  • THEN 系统更新成功enable_realname_activation=false

Requirement: 删除套餐

系统 SHALL 允许管理员删除套餐(软删除)。

Scenario: 成功删除套餐

  • WHEN 管理员删除指定的套餐
  • THEN 系统软删除该记录,后续查询不再返回

Scenario: 删除不存在的套餐

  • WHEN 管理员删除不存在的套餐
  • THEN 系统返回 "套餐不存在" 错误

Requirement: 启用/禁用套餐

系统 SHALL 允许管理员切换套餐的启用状态。禁用套餐时 MUST 同时将上架状态设置为下架。

Scenario: 启用套餐

  • WHEN 管理员将禁用的套餐设置为启用
  • THEN 系统更新状态为启用(1),上架状态保持不变

Scenario: 禁用套餐

  • WHEN 管理员将启用的套餐设置为禁用
  • THEN 系统更新状态为禁用(2),同时将上架状态设置为下架(2)

Scenario: 禁用已上架的套餐

  • WHEN 管理员禁用一个当前已上架的套餐
  • THEN 系统更新状态为禁用(2),上架状态强制设置为下架(2)

Requirement: 上架/下架套餐

系统 SHALL 允许管理员切换套餐的上架状态。只有启用状态的套餐才能上架。

Scenario: 上架启用的套餐

  • WHEN 管理员将启用且下架的套餐设置为上架
  • THEN 系统更新上架状态为上架(1)

Scenario: 尝试上架禁用的套餐

  • WHEN 管理员尝试上架一个禁用的套餐
  • THEN 系统返回错误 "禁用的套餐不能上架,请先启用"

Scenario: 下架套餐

  • WHEN 管理员将上架的套餐设置为下架
  • THEN 系统更新上架状态为下架(2)

Scenario: 状态未变化

  • WHEN 管理员设置的上架状态与当前状态相同
  • THEN 系统正常返回成功,不产生错误

Requirement: Package 模型新增字段

系统 MUST 在 Package 模型中新增以下字段:

  • suggested_cost_price:建议成本价(分为单位),默认 0
  • suggested_retail_price:建议售价(分为单位),默认 0
  • shelf_status上架状态1-上架 2-下架,默认 2

Scenario: 创建套餐时设置建议价格

  • WHEN 管理员创建套餐并设置建议成本价和建议售价
  • THEN 系统保存这些价格信息

Scenario: 查询套餐时返回建议价格

  • WHEN 管理员查询套餐详情或列表
  • THEN 响应中包含 suggested_cost_price、suggested_retail_price、shelf_status 字段

Requirement: 清理废弃模型

系统 MUST 删除以下废弃的分佣相关模型和对应的数据库表:

  • AgentHierarchy (tb_agent_hierarchy)
  • CommissionRule (tb_commission_rule)
  • CommissionLadder (tb_commission_ladder)
  • CommissionCombinedCondition (tb_commission_combined_condition)
  • CommissionApproval (tb_commission_approval)
  • CommissionTemplate (tb_commission_template)
  • CarrierSettlement (tb_carrier_settlement)
  • AgentPackageAllocation (tb_agent_package_allocation)

Scenario: 迁移后废弃表不存在

  • WHEN 执行数据库迁移后
  • THEN 上述 8 个表在数据库中不再存在

Scenario: 代码中无废弃模型引用

  • WHEN 删除模型定义后
  • THEN 项目能够正常编译,无编译错误