All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m55s
5.0 KiB
5.0 KiB
Context
当前套餐价格在多个链路里被直接读取,后台配置、C 端展示、订单创建、自动购包和代理授权都在用同一批字段,但它们需要的其实不是同一种值。与此同时,赠送套餐已经被业务明确为独立语义,既不是普通可售套餐的别名,也不能靠 package_type 或数值 0 去推断。这个变更会同时影响 Handler、Service、Store、Model 和迁移脚本,必须先把语义拆开,再改各条链路。
Goals / Non-Goals
Goals:
- 建立普通可售套餐的原始价与生效价分层。
- 在建议零售价未配置时,统一回退到成本价。
- 普通可售套餐不能显式配置 0 作为售卖价,0 只保留给赠送语义。
- 把赠送套餐做成独立语义,平台专属,禁止代理分配和 C 端自购。
- 保留原始配置值,避免把回退后的值写回配置页。
- 完成历史数据与存量记录的迁移回填,并输出人工复核清单。
Non-Goals:
- 不重做套餐类型体系,也不把 gift 语义塞进
package_type。 - 不新增外部依赖,不改用新的队列或存储组件。
- 不在本次变更里重构整个套餐管理域,只处理价格与赠送政策相关路径。
Decisions
1. 价格状态与价格数值分开存
采用独立的价格配置状态来区分“未配置”“赠送 0”“已配置为非 0”,原始建议零售价继续保留,生效售价由服务层计算。
原因:普通可售套餐不能显式卖 0,但赠送套餐仍可能使用 0,不能再用数值 0 当哨兵值。
备选方案:
- 继续用 0 代表未配置,最简单,但会把合法 0 价和未配置混在一起,不能接受。
- 直接覆盖原始字段为生效价,查询简单,但配置页会丢失真实原值。
2. 赠送语义独立于价格和套餐类型
新增独立的赠送语义标记,平台专属限制和价格规则彼此独立。
原因:平台-only、不可分配给代理、不可自购,这些都是业务权限问题,不是价格问题。
备选方案:
- 仅靠
package_type=formal/addon推断,已经被明确否决。 - 仅靠价格为 0 推断,无法区分合法 0 价与未配置。
3. 生效价格在 Service 层统一计算
Handler 只接收和返回值,不做价格推导。Store 只取原始数据,Service 统一计算生效价并下发给下游。
原因:价格规则会同时影响 C 端列表、下单、自动购包和授权链路,放在 Service 层更容易复用,也更符合分层职责。
备选方案:
- 在 Handler 里临时计算,容易散落和重复。
- 在 Store 里拼接业务规则,会把数据访问和业务逻辑混在一起。
4. 迁移采用“先加字段,再回填,再切流”的顺序
先把新语义字段和状态字段上线,再用迁移脚本回填历史数据,最后让读链路切到生效价。
原因:这样可以避免一次性改动过大导致历史数据无法解释,也方便回滚。
备选方案:
- 直接替换旧字段,风险太高,历史记录会失真。
- 先切读后补数据,会出现短时间内的口径不一致。
5. 不引入价格缓存
价格计算只依赖单条套餐和分配记录,属于 O(1) 读取,不新增 Redis 缓存层。
原因:这次变更的核心是语义和一致性,不是性能瓶颈。现有分页与查询边界已经足够。
备选方案:
- 引入缓存可以做,但会增加失效和回填复杂度,不适合作为首版方案。
Risks / Trade-offs
- [历史数据无法准确判断是否为赠送 0 价] → 迁移脚本优先读取历史发放记录和配置快照,只有能明确识别为赠送 0 的记录才保留为赠送 0,其余旧 0 一律转为未配置并输出待人工核验清单。
- [赠送语义改动会影响多条购买链路] → 先在 Service 层统一封装判定函数,再逐步替换各入口的直接读取。
- [价格展示口径切换后前端可能误解返回值] → 接口文档明确区分原始值、生效值和赠送语义,前后端一起切换。
- [存量分配记录字段回填出错] → 迁移前后保留回滚脚本,按批次执行并校验记录数。
Migration Plan
- 增加价格状态字段、赠送语义字段和平台专属标记,保持原始价格字段不变。
- 回填存量套餐的价格状态和生效价,优先使用历史配置与发放记录判断。只有能明确识别为赠送 0 的记录才保留为赠送 0,其余旧 0 一律转为未配置,并输出人工复核清单。
- 回填分配记录、历史订单和自动购包相关快照,让展示链路能读取生效价。
- 切换 Service 层统一价格解析与赠送校验,再切换 Handler 输出。
- 验证完成后,清理旧的直接读取路径,保留原始值用于配置页和审计。
Implementation Notes
- 人工复核清单只负责承接无法正向识别的旧 0 数据,不回写为赠送语义。
- 赠送套餐历史识别优先以后台发放记录为准,补录清单只作为迁移输入,不改变判定标准。