# UR#55 套餐分配生效条件覆盖与购买快照 ## 实现范围 - 系列首次授权、系列追加授权和批量套餐分配必须显式提交 `expiry_base_override`,支持 `null`、`from_purchase`、`from_activation`。 - 套餐分配响应返回套餐默认值、分配覆盖值和最终有效值及其中文名称。 - 新增单条分配覆盖修改接口:`PATCH /api/admin/shop-package-allocations/{id}/expiry-base`,显式 `null` 恢复跟随默认,重复提交保持幂等。 - 同步购买和自动购包创建主套餐或加油包时,在同一事务写入生效条件、周期类型、月数和天数快照。 - 实名激活、指定激活、排队接续和退款后的下一套餐接续优先读取购买快照;仅四字段全部为空或零的历史记录允许告警回退套餐当前配置,部分缺失或非法快照直接拒绝。 ## 数据库变更 - `tb_shop_package_allocation.expiry_base_override`:可空字符串,`NULL` 表示跟随套餐默认值。 - `tb_package_usage`:新增 `expiry_base_snapshot`、`calendar_type_snapshot`、`duration_months_snapshot`、`duration_days_snapshot`。 - 历史套餐使用记录不回填,保留空值和零值作为历史未快照标记。 ## 发布与回滚 发布时先部署兼容读取快照和历史回退的应用,再执行 162、163 迁移,并在同一维护窗口切换所有写入路径。回滚迁移只删除本需求新增字段和约束,不修改套餐使用状态或历史业务数据。 ## 验证 - 领域测试覆盖覆盖值解析、自然月/按天快照、快照优先、历史回退和异常快照拒绝。 - 已执行全仓 `go test ./...`、OpenAPI 文档生成以及迁移向上、单步向下、重新向上验证。