# 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_card` 和 `tb_device` 的 `series_allocation_id` 字段重命名为 `series_id`,直接关联到 `tb_package_series` - **Model 层**:修改 `IotCard` 和 `Device` 模型,将 `SeriesAllocationID` 字段改为 `SeriesID` - **DTO 层**:更新所有相关 DTO,包括查询请求、响应对象、批量设置请求 - **Store 层**: - 更新查询过滤条件(`series_allocation_id` → `series_id`) - 重命名批量更新方法(`BatchUpdateSeriesAllocation` → `BatchUpdateSeriesID`) - 重命名列表查询方法(`ListBySeriesAllocationID` → `ListBySeriesID`) - **新增** `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_id` → `series_id` - `PATCH /api/admin/devices/series-binding`:请求参数 `series_allocation_id` → `series_id` - `GET /api/admin/iot-cards/standalone`:查询参数和响应字段 `series_allocation_id` → `series_id` - `GET /api/admin/devices`:查询参数和响应字段 `series_allocation_id` → `series_id` ### 向后兼容性 - **BREAKING CHANGE**:API 请求/响应字段名变更,前端需要同步修改 - **数据迁移**:字段重命名,不需要数据转换(字段含义保持一致,只是重新指向 `PackageSeries.ID`) - **业务影响**:开发阶段,无生产数据,可直接重构 ### 依赖和约束 - 依赖现有的 `tb_package_series` 表和 `tb_shop_series_allocation` 表 - 依赖现有的 `PackageSeries` 模型 - 需要创建或完善 `PackageSeriesStore`(如不存在) - 测试需要创建完整的测试数据链路:`PackageSeries` → `ShopSeriesAllocation` → `IotCard/Device` ### 性能影响 - **查询优化**:购买验证时减少一次数据库查询(不再需要先查 `ShopSeriesAllocation` 获取 `series_id`) - **返佣查询**:增加一次按条件查询 `ShopSeriesAllocation`(`WHERE shop_id = ? AND series_id = ?`),但有索引支持,性能影响可忽略 - **整体影响**:轻微性能提升(减少了冗余查询)