iotsaas/docs/产品管理模块设计.md
2995840376 0ce191c448 chore: 初始化 iotsaas 版本库基线
纳入范围:
- backend/  Spring Boot 多模块后端(iot-common/device/rule/data/alarm/auth)
- frontend/admin/  Vue3 + Element Plus 管理后台
- Android/   涂鸦原生 APP (com.xhai.iot)
- backend/sql/  Flyway 风格迁移脚本(V2~V21)
- docs/       对接文档与设计文档

排除范围:
- 构建产物: node_modules/ target/ build/ dist/ .gradle/
- 签名密钥: *.jks *.keystore (严禁入库)
- 本机配置: Android/local.properties
- 运行日志: logs/ *.log
- AI 协作本地数据 .codebuddy/ 与第三方 demo tuya-demo/

.gitattributes 统一以 LF 存储, Windows 批处理保留 CRLF
2026-10-27 12:00:41 +08:00

207 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 产品管理模块(Product & TSL & OTA)分析设计
> 状态:分析设计(待评审,先不开发)
> 日期:2026-09-19
> 目标:论证并设计中控屏/IoT 平台所需的"产品管理"能力(产品参数、物模型 TSL、固件 OTA)
---
## 1. 结论先行(建议)
**非常需要,且应尽快立项。** 当前系统是"设备直管"模式,缺少产品(Product)这一层抽象,导致物模型零散、固件无管理、新增设备类型成本高。引入 **产品 → 设备 两级模型**(对标涂鸦/阿里云 IoT 的 Product 概念)是平台标准化的必经之路,并能直接支撑中控屏标准控制 UI、场景、AI 控制、固件升级。
---
## 2. 现状与痛点
### 2.1 现状(代码事实)
- `Device` 实体(`device` 表)字段:`deviceId, deviceName, platform, deviceType, manufacturer, model, firmwareVersion, status, capabilities(JSON), ..., homeId, roomId` —— **无 `productId`**。
- `Device.capabilities`:设备级 JSON,存"设备能力描述",**每个设备重复存静态能力**,无产品级统一定义。
- `AiDeviceProfile`(`ai_device_profile` 表,iot-device 与 iot-rule 两侧都有):**设备级**"指令码档案"(`powerCode/brightnessCode/colorTempCode/temperatureCode/modeCode`…),本质是物模型 DP 雏形,但按 `deviceId` 维度重复存储。
- `Device.firmwareVersion`:仅版本字符串,**无固件库、无升级包、无 OTA 任务、无灰度/回滚**。
- 涂鸦侧 `TuyaDeviceDTO` 有 `productId/productName/category`,但平台未把它沉淀为自有 Product 实体,仅在对接时透传。
### 2.2 痛点
1. **重复定义、难维护**:同类设备(同型号)每个都重复存 `capabilities` / `AiDeviceProfile` 指令码,产品能力变更需逐设备改。
2. **无标准物模型**:控制逻辑(DP 点、属性/事件/服务)散落在设备 JSON 与 `AiDeviceProfile`,AI 控制、场景、中控屏各自解析,易错且无法复用。
3. **固件无管理**:只有版本号,无法上传/发布/下发/灰度/回滚固件,中控屏等设备的固件升级无法支撑。
4. **产品参数无沉淀**:厂商/型号/品类/联网方式/配网/图标等散落,无法以"产品"维度统一管理和展示标准控制 UI。
5. **接入新设备类型成本高**:每接一类设备都要改代码/前端,无法配置化。
---
## 3. 产品管理模块范围
| 能力 | 说明 |
|------|------|
| 产品基础信息 | 名称、品类(category)、厂商(manufacturer)、型号(model)、联网方式(wifi/ble/zigbee/matter)、配网方式、图标、说明、发布状态 |
| 物模型(TSL) | 属性(Property)、事件(Event)、服务(Action) 三类功能点,含 DP 点定义与涂鸦/平台映射 |
| 固件管理(OTA) | 固件版本库、升级包存储(md5)、发布、升级任务、灰度、回滚、设备当前版本追踪 |
| 平台映射 | 本平台 Product ↔ 涂鸦 `productId` 等(`platform` + `platformProductId`) |
| 设备归属 | Device 增加 `productId`,继承产品物模型与固件基线 |
| 接入/配网模板(二期) | 标准化配网流程、设备自动归属产品 |
---
## 4. 与现有概念的关系(迁移策略)
| 现有 | 去向 |
|------|------|
| `Device.manufacturer` / `model` | 提升到 `Product`;Device 改为引用 `productId`(建议移除冗余,或保留只读快照防不一致) |
| `Device.capabilities`(JSON) | 由 Product 物模型(TSL)生成,设备运行时状态另存(`device_data`/status),不再每设备存静态能力 |
| `AiDeviceProfile`(设备级指令码) | **下沉为 Product 物模型的 DP 定义**(powerCode 等即产品的"开关属性");AI 控制/场景直接读产品物模型,设备不再单独存 |
| 涂鸦 `productId` | `Product.platform` + `platformProductId` 字段建立映射(一个平台产品 → 本平台一个 Product) |
| `Device.firmwareVersion` | 保留为设备"当前版本"(运行时上报);新增 `firmware` 表管理"可用版本库",`ota_task` 记录目标版本 |
---
## 5. 数据模型设计
### 5.1 product(产品表)
| 字段 | 说明 |
|------|------|
| id | PK |
| product_key | 业务编码(如 P_LIGHT_001) |
| name | 产品名称 |
| category | 品类(light/switch/ac/security…) |
| manufacturer | 厂商 |
| model | 型号 |
| platform | 接入平台(tuya/local/matter…) |
| platform_product_id | 涂鸦 productId 等映射 |
| connect_type | wifi/ble/zigbee/matter |
| net_config_type | 配网方式 |
| icon | 图标 |
| description | 说明 |
| status | 草稿/已发布 |
| spec_version | 当前物模型版本号 |
| create_time / update_time | — |
### 5.2 物模型(TSL)
推荐**拆表**(便于校验、UI 渲染、DP 映射),顶层用 `spec_version` 关联快照:
- `product_property`(属性):id, product_id, code(如 switch_1), name, access(读/写/上报), type(bool/int/enum/float/string/json), min, max, step, unit, enum_list, dp_id(涂鸦DP映射), default_value, sort
- `product_event`(事件):id, product_id, code, name, type(info/alert/fault), params(JSON)
- `product_action`(服务):id, product_id, code, name, input(JSON), output(JSON)
> 可选:同时存一份 `product.spec_json`(完整 TSL 快照)便于缓存下发。
### 5.3 firmware(固件表)
| 字段 | 说明 |
|------|------|
| id | PK |
| product_id | 所属产品 |
| version | 固件版本 |
| file_url | 升级包地址 |
| file_md5 | 校验 |
| size | 大小 |
| release_note | 更新说明 |
| is_latest | 是否最新 |
| status | 草稿/已发布 |
| create_time | — |
### 5.4 ota_task(升级任务)
| 字段 | 说明 |
|------|------|
| id | PK |
| product_id | 产品 |
| firmware_id | 目标固件 |
| target_version | 目标版本 |
| scope | 全部 / 指定设备 / 灰度% |
| device_ids | 指定设备 |
| status | 进行中/完成/暂停/失败 |
| success_count / fail_count | 统计 |
| create_time | — |
### 5.5 Device 改造
- 新增 `product_id`(FK,关联 product.id)。
- 视情况移除 `model`/`manufacturer` 冗余(或保留只读快照)。
- `firmwareVersion` 保留为设备当前运行版本(上报)。
---
## 6. 接口设计(建议)
### 6.1 管理端(后台/管理员)
- `POST/GET/PUT/DELETE /api/v1/products` —— 产品 CRUD
- `GET /api/v1/products/{id}/spec` —— 物模型查询
- `POST /api/v1/products/{id}/spec/properties` 等 —— DP/事件/服务增删改
- `POST /api/v1/products/{id}/firmware` —— 上传固件
- `GET /api/v1/products/{id}/firmwares` —— 固件列表
- `POST /api/v1/products/{id}/ota` —— 创建升级任务
- `GET /api/v1/ota-tasks/{id}` —— 任务进度
### 6.2 设备/中控屏侧(复用)
- 设备详情返回 `productId` + 物模型(用于渲染**标准控制 UI**,不再依赖零散 capabilities)。
- 控制接口基于物模型 DP(统一语义)。
- 固件查询:设备上报/拉取最新固件版本,触发 OTA。
---
## 7. 固件 OTA 流程
1. 管理员上传固件到 Product → 生成 `firmware` 记录(version, url, md5)。
2. 创建 `ota_task`(目标版本 + 设备范围 / 灰度比例)。
3. 设备定期上报/查询最新固件(或平台主动推送升级指令)→ 下载升级 → 上报新 `firmwareVersion` → 任务统计。
4. 支持回滚(将上一版本 `is_latest=false`,重新下发任务)。
- **中控屏本身也是一类 Product**,可纳入同一套 OTA 管理。
---
## 8. 分阶段实施
- **P0 产品基础**:`product` 表 + `Device.productId` 改造 + 产品 CRUD;按 `model+manufacturer` 自动归并或手动建产品,给存量设备回填 `productId`。
- **P1 物模型**:TSL(property/event/action)建模 + 管理接口;将 `AiDeviceProfile` / `capabilities` **迁移沉淀为产品物模型**,AI 控制/场景改读产品物模型。
- **P2 固件 OTA**:✅ 已实现(2026-09-19)。后端 `FirmwareService/Controller`:固件注册(草稿)/发布(置最新)/最新版查询、升级任务创建(all/designated/gray 物化目标设备)/任务分页/详情/设备上报回调(回写 device.firmware_version、统计完成)/暂停。管理后台「设备管理→产品管理」含固件OTA面板(注册/发布/建任务/进度/暂停)。V13/V14 迁移已在开发库(iot-mysql 3386)执行,8 台涂鸦设备已 reconcile 归类为 8 个产品。
- **P3 标准化控制**:✅ 已实现(2026-09-20)。核心是「标准控制模型」`ControlSchemaService`:`GET /api/v1/products/{id}/control-schema`(产品级)与 `GET /api/v1/devices/{deviceId}/control-schema`(设备级,含 DP 当前值填充)。物模型→控件映射:bool→switch、int/float 有范围→slider、enum→segmented、其余→number/text;主开关自动识别(开关/电源/switch/power 优先,否则唯一可写 bool)。设备无产品时 `available=false`,客户端回退原有渲染。消费端:管理后台「物模型→控制预览」按模型渲染只读控件;Android `DeviceControlActivity` 优先拉后端模型渲染(`ApiService.getDeviceControlSchema`),失败/无模型回退涂鸦 schema(需 Android Studio 编译确认)。
- **P4 高级**:✅ 大部分已实现(2026-09-20)。版本回滚 `POST /products/{id}/ota/rollback`(不指定版本则回退上一个已发布版本);灰度改为**设备ID稳定哈希分组**(同一设备恒在同一组,可配合不同版本做 A/B 对比);统计看板 `GET /ota-tasks/stats?productId=`(任务数/进行中/完成/暂停、成功失败数、成功率、设备固件版本分布),管理后台 OTA 面板顶部为统计卡片 + 版本分布。未做:配网模板。
---
## 9. 风险与注意
- **存量迁移**:设备需回填 `productId`(按 model+manufacturer 归并或人工关联)。
- **兼容性**:保留 `capabilities` 读兼容,逐步切到产品物模型,避免一次性大改。
- **物模型版本**:用 `spec_version` 管理,产品变更不影响已部署设备(设备绑定创建时的 spec 快照)。
- **涂鸦映射一致性**:`platformProductId` 与涂鸦 productId 对齐,DP 映射字段 `dp_id` 准确。
---
## 10. 价值总结
引入产品层可一次性解决当前三大痛点:**① 物模型统一(消除 `capabilities`/`AiDeviceProfile` 设备级重复)② 固件可管理(OTA)③ 设备类型配置化接入**。同时为已规划的中控屏标准控制 UI、场景、AI 语音控制提供统一数据底座,是平台从"能连设备"走向"可运营 IoT 平台"的关键一步。
---
## 11. 已确认决策(2026-09-19 评审)
| 项 | 决策 |
|----|------|
| 存量设备回填 | **两者结合**:系统按 `model+platform` 自动预归类生成建议产品与归属,管理员在后台确认/调整 |
| Device 冗余字段 | **移除** `Device.model` / `manufacturer`,统一从 `product` 取(需同步改所有读写该字段的逻辑:DeviceController.createDevice、DeviceInfo DTO、AiDeviceProfile、前端设备卡片等) |
| 物模型存储 | **拆表**:`product_property` / `product_event` / `product_action`,每行一个 DP 点,含 `dp_id` 涂鸦映射与 `spec_version` |
| 首期范围 | **P0 + P1 全做**:产品基础 + `Device.product_id` + 存量回填 + 物模型(属性/事件/服务)建模与接口,并将 `AiDeviceProfile` / `capabilities` **下沉为产品物模型** |
### 11.1 开发前影响面排查(移除冗余字段必做)
- `Device.model` / `manufacturer` 读写点:`DeviceController`(create/update/query)、`DeviceInfo`/`DeviceData` 等 DTO、SQL 映射、前端设备详情/卡片展示。
- `AiDeviceProfile` 下沉:iot-device 写入、iot-rule 读取(AI 控制翻译)需改为读产品物模型;迁移脚本把存量 deviceId 级指令码归并到所属产品的 property。
- `capabilities` 兼容:保留读兼容,新设备改由产品物模型生成;提供回填/转换脚本。
## 12. 实现进度(2026-09-19,P0+P1 基础)
### 12.1 已完成(可编译,已通过 LSP)
- **SQL** `backend/sql/V13__add_product_module.sql`:新建 `product` / `product_property` / `product_event` / `product_action` / `firmware` / `ota_task` 六表;`device` 表新增 `product_id` 列(保留原 `model/manufacturer` 兼容快照,未物理删除)。
- **实体 + Mapper**:6 个实体与 6 个 `BaseMapper`(纯新增)。
- **ProductService / Impl**:产品 CRUD、物模型查询与增删改、`resolveProductId`(按平台信息解析/自动建产品)、`reconcileDevices`(存量设备按 `model+platform` 自动归类回填 `product_id`)。
- **ProductController** `POST/GET/PUT/DELETE /api/v1/products`、`/products/{id}/spec`、`/properties|events|actions`、`/reconcile`、`/resolve`。
- **Device / DeviceInfo** 增加 `productId`;`TuyaDeviceAdapter.getDeviceInfo` 回填 `productId`(设备详情可返回所属产品)。
### 12.2 未做(高风险,单列计划,未破坏现有功能)
1. **✅ 移除 `Device.model/manufacturer` 冗余(D)**:`V14` 给 `device` 加 `platform_product_id`(承接塞进 `model` 列的涂鸦 productId)、迁移存量、再 `DROP COLUMN model/manufacturer`。`Device` 实体删两字段加 `platformProductId`;`TuyaController` 改设 `platformProductId`;`reconcileDevices` 改按 `platform+platformProductId` 归类;`DeviceInfo` 的 `model/manufacturer` 改为**从 `product` 取**(`TuyaDeviceAdapter` 注入 `ProductMapper`)→ 前端零改动。
2. **✅ `AiDeviceProfile` 下沉产品级(C,向后兼容)**:`ai_device_profile` 加 `product_id`。`iot-device` 探测与 `iot-rule` 解析/保存全部改为**优先读产品级、推断落产品级**;旧设备级作 fallback。`AiDeviceView` 加 `productId`。
3. **✅ 设备同步自动关联(B)**:`TuyaController` 创建/更新涂鸦设备时自动 `resolveProductId` 设 `device.product_id`。
4. **✅ `capabilities` 由物模型生成**:`DeviceServiceImpl.getDeviceInfo` 改为依据设备所属 `product` + `product_property` 动态推导能力描述(`product` 元数据 + 每个功能点 `code/name/type/access/writable/min/max/step/unit/enum/default`),取代各 adapter 硬编码能力(如 `LocalDeviceAdapter` 的 `switch/brightness/color`);`device.capabilities` 列仅保留 `dps` 运行时态;无产品时回退 adapter 自带能力。前端无引用,零改动。
> 验证:后端 `mvn -pl iot-device,iot-rule -am compile` 通过(exitCode 0)。存量设备 productId 回填与产品创建由部署后执行 `POST /api/v1/products/reconcile` 完成(已基于 `platformProductId`)。