Files
junhong_cmp_fiber/openspec/changes/archive/2026-02-02-refactor-series-binding-to-series-id/proposal.md
huang 76b539e867
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m22s
chore: 归档 OpenSpec 变更 refactor-series-binding-to-series-id
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-02 12:21:00 +08:00

5.4 KiB
Raw Blame History

Proposal: refactor-series-binding-to-series-id

Why

当前系统中IoT卡和设备通过 series_allocation_id套餐系列分配ID字段绑定到 ShopSeriesAllocation 表,而不是直接绑定到 PackageSeries(套餐系列)。这导致了严重的语义混乱和架构问题:

  1. 语义错误:卡/设备应该表达"只能购买某个系列的套餐",而不是"绑定到某个权限分配"
  2. 职责耦合:资源属性(可购买的套餐范围)与权限配置(返佣规则)混在一起
  3. 查询冗余:每次需要 series_id 时都要通过 allocation 表查询,增加数据库负担
  4. 配置僵化:修改店铺的返佣配置时,需要重新绑定所有卡/设备

这是一个设计失误,需要在开发阶段彻底重构。正确的设计应该是:卡/设备直接绑定 series_id,权限验证和返佣查询时按需通过 (shop_id, series_id) 查询 ShopSeriesAllocation

What Changes

  • 数据库结构:将 tb_iot_cardtb_deviceseries_allocation_id 字段重命名为 series_id,直接关联到 tb_package_series
  • Model 层:修改 IotCardDevice 模型,将 SeriesAllocationID 字段改为 SeriesID
  • DTO 层:更新所有相关 DTO包括查询请求、响应对象、批量设置请求
  • Store 层
    • 更新查询过滤条件(series_allocation_idseries_id
    • 重命名批量更新方法(BatchUpdateSeriesAllocationBatchUpdateSeriesID
    • 重命名列表查询方法(ListBySeriesAllocationIDListBySeriesID
    • 新增 ShopSeriesAllocationStore.GetByShopAndSeries(shopID, seriesID) 方法,用于按需查询返佣配置
    • 新增 PackageSeriesStore(如不存在)及其 GetByID() 方法
  • Service 层:重构核心业务逻辑
    • BatchSetSeriesBinding:验证 series_id 是否存在,检查操作者权限(通过 GetByShopAndSeries 查询)
    • ValidateCardPurchase / ValidateDevicePurchase:直接使用 card.series_id 验证套餐,按需查询返佣配置
    • CalculateOrderCommission:根据 (shop_id, series_id) 查询返佣配置,而不是通过 allocation_id
    • CreateRecharge:同样改为按需查询返佣配置
  • API 文档:更新路由描述,说明参数从 series_allocation_id 改为 series_id
  • 测试:更新约 100+ 个测试用例包括单元测试、集成测试、Store 测试

关键行为变更

  • API /api/admin/iot-cards/series-binding/api/admin/devices/series-binding 的请求参数从 series_allocation_id 改为 series_id
  • 卡/设备列表的查询参数和响应字段同步改为 series_id
  • 内部逻辑从"通过 allocation 获取 series_id"改为"直接使用 series_id按需查询 allocation"

Capabilities

New Capabilities

Modified Capabilities

  • card-series-bindng: 修改 IoT 卡系列绑定的数据模型和验证逻辑,从绑定"分配ID"改为绑定"系列ID"
  • device-series-bindng: 修改设备系列绑定的数据模型和验证逻辑,从绑定"分配ID"改为绑定"系列ID"

Impact

影响范围统计

  • 数据库迁移2 个迁移文件(新增重命名迁移,修改旧迁移注释)
  • Model 层2 个文件(internal/model/iot_card.go, internal/model/device.go
  • DTO 层2 个文件6 个结构体(internal/model/dto/iot_card_dto.go, internal/model/dto/device_dto.go
  • Store 层3 个文件,新增 2 个查询方法(iot_card_store.go, device_store.go, shop_series_allocation_store.go
  • Service 层6 个文件的核心逻辑重构
    • internal/service/iot_card/service.go
    • internal/service/device/service.go
    • internal/service/purchase_validation/service.go(关键)
    • internal/service/commission_calculation/service.go(关键)
    • internal/service/recharge/service.go
    • internal/service/order/service.go
  • Handler/Routes 层2 个文件的路由描述更新
  • 测试层:约 10 个文件100+ 测试用例更新

受影响的 API 端点

  • PATCH /api/admin/iot-cards/series-binding:请求参数 series_allocation_idseries_id
  • PATCH /api/admin/devices/series-binding:请求参数 series_allocation_idseries_id
  • GET /api/admin/iot-cards/standalone:查询参数和响应字段 series_allocation_idseries_id
  • GET /api/admin/devices:查询参数和响应字段 series_allocation_idseries_id

向后兼容性

  • BREAKING CHANGEAPI 请求/响应字段名变更,前端需要同步修改
  • 数据迁移:字段重命名,不需要数据转换(字段含义保持一致,只是重新指向 PackageSeries.ID
  • 业务影响:开发阶段,无生产数据,可直接重构

依赖和约束

  • 依赖现有的 tb_package_series 表和 tb_shop_series_allocation
  • 依赖现有的 PackageSeries 模型
  • 需要创建或完善 PackageSeriesStore(如不存在)
  • 测试需要创建完整的测试数据链路:PackageSeriesShopSeriesAllocationIotCard/Device

性能影响

  • 查询优化:购买验证时减少一次数据库查询(不再需要先查 ShopSeriesAllocation 获取 series_id
  • 返佣查询:增加一次按条件查询 ShopSeriesAllocationWHERE shop_id = ? AND series_id = ?),但有索引支持,性能影响可忽略
  • 整体影响:轻微性能提升(减少了冗余查询)