# 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 文档生成以及迁移向上、单步向下、重新向上验证。
