fastbee/docs/knowledge-base/06-platform-integration-design.md
2026-05-30 12:57:08 +08:00

1179 lines
58 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.

# 平台对接需求与技术设计
## 1. 背景
需求目录 `docs/platform/` 中目前包含 DCP 雨量计、倾角、静力水准、轴力计接口文档。DCP 是当前优先落地的平台,但平台对接能力不能只服务一个平台、一个租户。平台一旦完成接入,后续其他租户应复用同一套平台定义、接口定义、流程编排、适配器和数据交换执行能力;租户只维护自己的第三方账号/用户、项目、设备、字段映射和交换任务。
平台与平台之间的数据交换本质上分三类:
| 方向 | FastBee 角色 | 触发方 | 说明 |
| --------------- | ---------- | ------- | ---------------------------------------- |
| OUTBOUND_PUSH | Producer | FastBee | FastBee 主动把本系统数据推送给第三方。 |
| INBOUND_PULL | Consumer | FastBee | FastBee 主动从第三方拉取数据,但消费方仍是 FastBee。 |
| INBOUND_RECEIVE | Consumer | 第三方 | 第三方主动调用 FastBee 接口或消息入口,FastBee 接收并消费数据。 |
因此本方案不再以“推送”为中心,而是以更普适的 **数据交换 Exchange** 为中心:
```text
平台对接 = 平台模板 + 租户接入 + 资源映射 + 流程编排 + 数据交换任务 + 数据交换记录
```
当前 FastBee 已具备以下基础能力:
- 设备、产品、物模型:设备通过 `iot_device` 管理,物模型通过产品和设备编号查询。
- 设备上报处理:设备数据解析后进入原有入库和规则处理链路。
- 历史数据查询:数据中心接口支持按设备、时间窗口和物模型标识符查询历史数据。
- 数据桥接:现有 `bridge`、`iot_script`、`iot_script_bridge` 支持 HTTP、MQTT、数据库桥接,可作为轻量转发能力保留。
- 定时任务:系统已有 Quartz 任务体系,可复用为 OUTBOUND_PUSH、INBOUND_PULL、RESOURCE_SYNC 等任务触发器。
- 多租户:IoT 主要业务表已有 `tenant_id`、`tenant_name` 约定,平台对接也必须按租户隔离业务映射和交换数据。
## 2. 设计目标
平台对接需要同时满足“平台共用”“租户隔离”“方向清晰”“数据边界清晰”:
- 平台接入人员只维护一次第三方平台模板:认证方式、接口、字段、流程、适配器。
- 多个租户可启用同一个平台模板,不重复配置接口和流程。
- 每个租户维护自己的第三方账号/用户授权、项目映射、设备绑定、字段映射和交换任务。
- 支持三类数据方向:主动推送、主动拉取、被动接收。
- 主动拉取和被动接收都属于 INBOUND,FastBee 是 consumer,最终要落到 FastBee 的设备、物模型、事件、告警、资源映射或业务表。
- 主动推送属于 OUTBOUND,FastBee 是 producer,重点是可靠投递、重试、重推和审计。
- 支持幂等、失败重试、手动重试、补偿、日志追踪。
- DCP 等复杂平台通过专用适配器处理 token、项目、测点、设备、传感器、雨量递增等平台规则。
- DCP 必须遵守 **一个测点对应一个 FastBee 设备**,不能将测点设计为平台级或产品级共享资源。
## 3. 总体架构
平台对接按四层拆分。
```text
平台模板层(全局/系统级,可复用)
-> 平台定义、接口定义、字段定义、流程编排、适配器
租户接入层(租户级,隔离)
-> 租户平台实例、第三方账号/用户、项目映射、资源映射、设备绑定、字段映射
数据交换层(租户级,隔离)
-> 数据交换任务、交换记录、交换尝试、幂等、重试、补偿
业务落点层(FastBee 内部边界)
-> 设备数据、设备日志、物模型值、事件、告警、资源映射、业务表
```
### 3.1 平台模板层
平台模板层由平台管理员维护,配置一次、多租户复用。
包含:
- 第三方平台类型,例如 DCP、通用 HTTP、通用 MQTT、通用数据库。
- 认证方式,例如无认证、固定 Token、Basic、Bearer、OAuth2、自定义 Token 接口。
- 接口定义,例如获取用户、获取项目、创建测点、创建设备、绑定传感器、推送数据、查询数据、接收数据。
- 接口字段定义,用于页面展示和字段映射。
- 流程编排,例如“获取用户 -> 获取项目 -> 确保测点 -> 确保设备 -> 推送数据”。
- 适配器编码,例如 `genericHttp`、`dcp`。
平台模板不保存租户账号、项目、设备和业务数据。
### 3.2 租户接入层
租户接入层由租户管理员或实施人员维护。
包含:
- 租户启用哪个平台模板。
- 租户自己的第三方账号、token、clientId/clientSecret 等授权配置。
- 租户第三方用户和项目映射。
- FastBee 设备与第三方资源的绑定。
- FastBee 物模型字段与第三方接口字段的映射。
- 接收入口密钥、签名配置、白名单等租户级安全配置。
同一个平台模板下,不同租户的数据必须隔离:授权配置、项目、用户、资源映射、设备绑定、交换任务、交换记录都必须带 `tenant_id`。
### 3.3 数据交换层
数据交换层是运行时核心。它不只处理推送,也处理拉取和接收。
```text
OUTBOUND_PUSH
FastBee 内部数据 -> 第三方平台
INBOUND_PULL
第三方平台 -> FastBee 主动拉取 -> FastBee 内部业务落点
INBOUND_RECEIVE
第三方主动提交 -> FastBee 接收入口 -> FastBee 内部业务落点
```
三种方向共用平台模板、租户接入、认证、字段映射、流程编排、资源映射和交换记录,但使用不同触发器和执行器。
### 3.4 业务落点层
INBOUND 数据必须明确落点,避免平台对接层无限扩张。
推荐落点类型:
| sink_type | 说明 |
| ---------------- | ------------------- |
| DEVICE_PROPERTY | 写入设备属性/物模型数据。 |
| DEVICE_EVENT | 写入设备事件。 |
| ALERT_EVENT | 写入告警或告警日志。 |
| RESOURCE_MAPPING | 写入用户、项目、测点、设备等资源映射。 |
| BUSINESS_TABLE | 写入明确的业务表,需要白名单。 |
| RAW_ONLY | 只记录原始数据,不进入业务表。 |
平台对接层负责接入、鉴权、映射、转换、幂等和审计;具体业务落库应通过明确的 sink adapter 完成,不允许任意 SQL 或任意代码写入。
## 4. 三类方向的边界
### 4.1 OUTBOUND_PUSH:推送数据
FastBee 是 producer,第三方平台是 consumer。
```text
设备上报 / 历史补推 / 业务事件
-> 构造标准出站数据 PlatformExchangeMessage
-> 匹配租户平台实例和设备绑定
-> 字段映射和资源补齐
-> 执行 PUSH 流程
-> 调用第三方接口/MQTT/DB
-> 写 exchange_record / exchange_attempt
```
边界:
- 数据来源是 FastBee 内部可信业务数据。
- 失败可重试,可手动重推。
- 需要 outbox,避免阻塞设备上报主链路。
- 幂等 key 应基于本地来源、绑定、时间和 payload hash。
### 4.2 INBOUND_PULL:拉取数据
FastBee 主动发起请求,但 FastBee 仍是 consumer。
```text
Quartz / 手动触发
-> 加载租户平台实例和授权配置
-> 执行 PULL / RESOURCE_SYNC 流程
-> 调第三方查询接口
-> 处理分页、游标、时间窗口
-> 响应字段映射
-> 识别本地租户、项目、设备、资源
-> 写入业务落点
-> 写 exchange_record / exchange_attempt
```
边界:
- 数据来源是第三方平台,必须按外部输入处理。
- 必须有游标、时间窗口或分页边界,禁止无界拉取。
- 必须定义 sink_type,明确拉取结果落到哪里。
- 必须支持幂等,避免同一第三方数据重复入库。
- 拉取状态建议保存在任务游标中,例如 `cursor_json`、`last_success_time`、`last_success_external_id`。
### 4.3 INBOUND_RECEIVE:接收数据
第三方主动调用 FastBee,FastBee 是 consumer。
```text
第三方 HTTP/MQTT 调用 FastBee
-> 接收入口鉴权/签名/限流
-> 匹配租户平台实例和 RECEIVE 流程
-> 提取幂等 key
-> 请求字段映射
-> 识别本地租户、项目、设备、资源
-> 写入业务落点
-> 写 exchange_record / exchange_attempt
-> 返回处理结果
```
边界:
- 数据来源是第三方平台,必须按外部输入处理。
- 接收入口必须具备租户识别、鉴权、签名校验、幂等、限流和日志。
- 同步响应只代表 FastBee 是否接收/处理成功,不代表后续所有异步流程都完成。
- 如果需要异步处理,接收入口应先写 exchange_record,再由 worker 处理。
- 不建议复用旧 `/bridge/**` 作为主入口,可保留旧桥接用于轻量场景。
## 5. 与现有系统功能的关系
| 现有能力 | 复用方式 |
| ----------------- | ----------------------------------------------------------------- |
| 设备管理 `iot_device` | 设备绑定引用 `device_id`、`serial_number`、`product_id`、`tenant_id`。 |
| 产品物模型 | 绑定和字段映射页面通过现有物模型接口展示字段,使用 `identifier`。 |
| 设备实时上报链路 | OUTBOUND_PUSH 可在原有数据处理完成后生成交换记录,不改变协议解析逻辑。 |
| 数据中心历史查询 | OUTBOUND_PUSH 补推可按设备、时间窗口、identifier 取历史数据。 |
| 规则引擎和数据桥接 | 保留给轻量 HTTP/MQTT/DB 转发;平台对接面向多步骤、多租户、可审计场景。 |
| Quartz 定时任务 | INBOUND_PULL、OUTBOUND_PUSH 定时补偿、RESOURCE_SYNC 可复用 sys_job/Quartz。 |
| Redis/Redisson | 缓存 token,资源创建时做并发锁,接收入口可做幂等和限流。 |
| 若依权限体系 | 继续使用菜单、角色、`@PreAuthorize` 权限控制。 |
现有数据桥接仍保留。它适合“固定 URL + 固定模板 + 脚本触发”的轻量转发;平台对接用于第三方平台长期集成,需要多租户账号、项目、设备映射、流程编排、资源幂等、数据落点、失败重试和审计。
## 6. 前端功能设计
一级菜单:**平台对接**,只有 3 个子菜单。
```text
平台对接
平台管理 ← 平台模板 + 接口 + 流程 + 租户接入,全部内嵌
设备接入 ← 设备绑定 + 字段映射 + 交换任务,向导式操作
交换记录 ← 数据交换记录 + 尝试日志 + 重试
```
资源映射不单独作为菜单,在设备接入页面的绑定详情中内嵌查看。
### 6.1 平台管理
平台管理页面采用左右布局:左侧是平台列表,右侧是选中平台的详情,通过 Tab 切换。
**左侧:平台列表**
- 展示所有平台模板(DCP、通用 HTTP 等)。
- 每行显示平台名称、类型、适配器、启用状态。
- 支持新增平台模板。
**右侧 Tab 1:基本信息**
平台模板主要字段:
| 字段 | 说明 |
| ------ | ----------------------------------------- |
| 平台名称 | 用户可读名称,例如 DCP。 |
| 平台编码 | 全局唯一,例如 `DCP`。 |
| 平台类型 | DCP、GENERIC_HTTP、GENERIC_MQTT、GENERIC_DB。 |
| 适配器编码 | dcp、genericHttp 等。 |
| 基础地址模板 | 可作为租户实例默认 baseUrl。 |
| 认证方式 | OAuth2、自定义 Token、固定 Token 等。 |
| 默认请求配置 | 超时、重试、Content-Type 等。 |
| 启用状态 | 启用、停用。 |
**右侧 Tab 2:接口列表**
接口属于平台模板,在此 Tab 内直接管理,不单独作为菜单。
接口按类型分组展示,点击接口行展开查看/编辑接口字段:
| 分组 | 接口类型 | 说明 |
| ------ | ------------------------------------- | ----------------------- |
| 认证接口 | TOKEN | 获取或刷新 token。 |
| 公共接口 | QUERY、RESOURCE_CREATE、RESOURCE_BIND | 查询用户/项目、创建/绑定资源等。 |
| 设备接口 | PUSH、CALLBACK | 按设备类型分组的数据推送接口。 |
| 接收入口 | RECEIVE | FastBee 被动接收第三方数据的入口定义。 |
每个接口展开后显示:请求方法、URL 模板、Header/Query/Body 模板、成功条件、响应变量提取规则、重试策略,以及该接口的 REQUEST/RESPONSE 字段列表(可增删改)。
接口字段用于设备接入时的字段映射,字段路径使用 JSONPath 或表单字段名。
**右侧 Tab 3:流程配置**
流程属于平台模板,在此 Tab 内管理。
流程列表按类型展示(OUTBOUND_PUSH、INBOUND_PULL、INBOUND_RECEIVE、RESOURCE_SYNC),点击流程行展开步骤列表,支持拖拽排序步骤。
步骤类型:API(引用接口)、ADAPTER(适配器方法)、CONDITION(条件判断)、TRANSFORM(数据转换)、SINK(写入业务落点)。
**右侧 Tab 4:租户接入**
租户接入表示当前租户启用该平台模板,在此 Tab 内配置,不单独作为菜单。
主要字段:
| 字段 | 说明 |
| ------- | -------------------------------- |
| 实例名称 | 租户内展示名。 |
| baseUrl | 可覆盖模板默认地址。 |
| 授权配置 | 租户自己的账号、clientId、secret、token 等。 |
| 默认第三方用户 | DCP userId 或其他平台用户。 |
| 默认项目 | DCP projectId 或其他平台项目。 |
| 接收安全配置 | webhook token、签名密钥、IP 白名单等。 |
| 启用状态 | 启用、停用。 |
租户接入配置完成后,才能在设备接入页面选择该平台实例。
### 6.2 设备接入
设备接入页面是租户操作的核心入口,采用列表 + 抽屉向导的方式。
**列表视图**
展示当前租户所有设备绑定,列显示:平台实例、设备类型、FastBee 设备名/编号、交换模式、状态、最近成功时间。
支持按平台实例、设备类型、状态筛选。
操作列:编辑映射、启用/停用、初始化资源、查看资源映射、查看交换记录、解绑。
**新增绑定:向导式抽屉(3步)**
**第 1 步:选择平台与设备类型**
- 下拉选择平台实例(从当前租户已启用的租户接入中加载,不是写死的枚举)。
- 选择平台实例后,动态加载该平台模板下的设备接口分组,作为设备类型选项(例如 DCP 加载后显示:雨量计、倾角仪、静力水准、轴力计)。
- 设备类型对应平台模板中的 PUSH 接口分组,由平台模板定义,不在前端硬编码。
**第 2 步:选择 FastBee 设备**
- 选择产品(下拉)。
- 选择设备(从该产品下的设备列表选,支持搜索设备名/编号)。
- 展示设备基本信息和物模型字段列表(供下一步参考)。
- 可选:填写绑定级第三方用户 id、项目 id(留空则使用租户接入的默认值)。
**第 3 步:字段映射**
左右分栏:
- 左侧:FastBee 物模型字段列表(identifier、字段名、数据类型),以及系统字段(serialNumber、deviceName、reportTime)。
- 右侧:第 1 步选定的设备接口的 REQUEST 字段列表(字段路径、字段名、是否必填)。
- 中间:映射关系,每行对应一个目标字段,来源可选:物模型字段、系统字段、常量、资源映射(pointId 等)、JSONPath 表达式。
- 支持从平台模板复制默认映射(如果平台模板预置了默认映射规则)。
字段映射同时支持 OUTBOUND(FastBee → 第三方)和 INBOUND(第三方 → FastBee),通过方向 Tab 切换。
**绑定详情:资源映射内嵌**
点击列表行的"查看资源映射",在侧边抽屉中展示该绑定下的资源映射记录(USER、PROJECT、POINT、DEVICE、SENSOR 等),不单独作为菜单。
**交换任务**
在设备接入列表页顶部提供"交换任务"入口(或作为 Tab),管理当前租户的定时推送、主动拉取、资源同步任务。
任务配置:选择平台实例、选择流程、设置 Cron 表达式、时间窗口类型、批次大小、最大重试次数。
任务与绑定的关联在任务详情中配置(选择哪些设备绑定参与该任务)。
### 6.3 交换记录
交换记录是运维监控视图,展示所有数据交换的执行状态。
筛选条件:平台实例、方向(OUTBOUND_PUSH/INBOUND_PULL/INBOUND_RECEIVE)、设备编号、状态、时间范围。
列表列:方向、平台实例、设备名/编号、数据时间、状态、重试次数、最近错误、创建时间。
操作:
- 点击行展开查看:原始输入、标准消息、最终 payload、幂等 key、请求响应详情、错误信息。
- 失败记录:单条重试、批量重试。
- 成功记录:强制重放(新建 REPLAY 记录,幂等 key 追加批次号)。
- 点击"尝试日志"查看每次请求的 URL、请求头(脱敏)、请求体、响应状态、响应内容、耗时。
## 7. 标准数据模型
平台对接内部统一使用标准数据交换消息,避免直接依赖原始 MQTT/HTTP payload 或第三方响应结构。
```json
{
"direction": "OUTBOUND_PUSH",
"tenantId": 1,
"tenantChannelId": 10,
"flowId": 100,
"bindingId": 1001,
"sourceType": "DEVICE_PROPERTY",
"sourceRefId": "device_log_id_or_external_message_id",
"eventTime": "2026-05-27 10:00:00",
"device": {
"productId": 10,
"deviceId": 1001,
"serialNumber": "ABC001",
"deviceName": "雨量计-001"
},
"values": {
"rainfall": {
"value": 12.3,
"unit": "mm",
"ts": "2026-05-27 10:00:00"
}
},
"resources": {
"projectId": "P001",
"pointId": "PT001",
"externalDeviceId": "D001"
},
"rawPayload": {}
}
```
说明:
- OUTBOUND 的 `rawPayload` 通常是 FastBee 原始上报或业务事件。
- INBOUND 的 `rawPayload` 是第三方原始请求或响应。
- `values` 的 key 优先使用 FastBee 物模型 `identifier`。
- `resources` 来自租户级资源映射。
- INBOUND 处理完成后必须进入明确的 `sink_type`,不能停留在平台对接层。
## 8. DCP 适配设计
DCP 通过平台模板 + 流程编排 + 专用适配器落地。DCP 当前主要覆盖 OUTBOUND_PUSH 和 RESOURCE_SYNC,也可以扩展 INBOUND_PULL 同步项目、测点或历史数据。
### 8.1 DCP 平台模板
DCP 平台模板包含:
- token 接口:`POST /connect/token`。
- 用户接口:获取 userId。
- 项目接口:按 userId 获取项目。
- 资源接口:创建测点、创建设备、创建/绑定传感器等。
- 数据接口:雨量、倾角、静力水准、轴力计数据推送;如 DCP 提供查询接口,也可配置为 INBOUND_PULL。
- DCP 专用适配器:处理 token 缓存、资源幂等、payload 构造、特殊规则。
这些配置由系统维护一次,所有租户复用。
### 8.2 DCP 租户映射
每个租户需要维护自己的 DCP 映射:
```text
租户
-> DCP 租户平台实例
-> DCP 账号/用户 userId
-> DCP 项目 projectId
-> FastBee 设备绑定 DCP 测点 pointId
-> FastBee 设备绑定 DCP 设备 dcpDeviceId
-> 设备附属 sensor/module/virtual
```
同一个 DCP 平台模板下,不同租户可以使用不同 DCP 账号、用户和项目。资源映射必须按 `tenant_id` 隔离。
### 8.3 DCP 一测点一设备约束
DCP 资源映射必须按“一测点一设备”建模:
```text
FastBee Device(serialNumber)
-> DCP Project(projectId)
-> DCP Point(pointId)
-> DCP Device(dcpDeviceId)
-> DCP Sensor/Module/Virtual(按设备类型可选)
```
规则:
- `PROJECT` 可以是租户平台实例级默认资源,也可以绑定级覆盖。
- `USER`、`PROJECT` 是租户级或绑定级映射,不是全局共享。
- `POINT` 必须是设备级资源,一个 FastBee 设备对应一个 DCP 测点。
- `DEVICE` 必须是设备级资源,一个 FastBee 设备对应一个 DCP 设备资源。
- `SENSOR`、`MODULE`、`VIRTUAL` 是设备附属资源,按绑定保存。
- 静力水准 payload 中可包含多条 `sensorData`,但仍归属同一个 FastBee 设备对应的 DCP 测点和 DCP 设备下。
### 8.4 DCP OUTBOUND_PUSH 流程
```text
设备上报或补推任务
-> 匹配租户 DCP 设备绑定
-> 加载租户 DCP 授权配置
-> 获取/刷新 token
-> 加载 userId/projectId 映射
-> 加载 pointId/dcpDeviceId/sensor 映射
-> 资源缺失时按流程懒加载或手动初始化
-> 构造对应设备类型 payload
-> 调用 DCP 数据接口
-> 写 exchange_record 和 exchange_attempt
```
资源创建必须幂等。并发上报同一设备时,使用 Redis/Redisson 锁:
```text
platform:dcp:resource:{tenantId}:{tenantChannelId}:{serialNumber}
```
### 8.5 DCP 特殊规则
- 雨量 `value` 为累计降雨量,DCP 要求新值大于历史值。系统使用绑定的 `last_success_value` 或资源扩展字段记录最近成功值;不满足时记录为 `SKIPPED`,不反复重试。
- 倾角需要同一时间的 x、y、z 和温度,必须按一次设备快照组包,不能拆成多个单字段推送。
- 静力水准的 `sensorData` 可包含多条传感器数据,但这些数据属于同一个 FastBee 设备对应的 DCP 设备资源。
- 轴力计按独立设备类型处理,字段映射和 payload 由 `DcpPlatformAdapter` 中对应 builder 负责。
- DCP token 缓存在 Redis,key 建议:`platform:dcp:token:{tenantId}:{tenantChannelId}`。
- 401 或 token 过期时刷新 token 后重试一次,再失败则记录错误。
## 9. 表设计
表名前缀使用 `iot_platform_`,避免和现有 `iot_social_platform` 混淆。
### 9.1 表清单
| 表名 | 层级 | 说明 |
| ------------------------------- | ----- | ------------------------- |
| `iot_platform_template` | 平台模板层 | 平台模板,全局可复用。 |
| `iot_platform_api` | 平台模板层 | 第三方接口定义,含调用接口和接收入口。 |
| `iot_platform_api_field` | 平台模板层 | 接口字段定义。 |
| `iot_platform_flow` | 平台模板层 | 流程模板。 |
| `iot_platform_flow_step` | 平台模板层 | 流程步骤。 |
| `iot_platform_tenant_channel` | 租户接入层 | 租户启用的平台实例、授权和接收安全配置。 |
| `iot_platform_resource_mapping` | 租户接入层 | 用户、项目、测点、设备、传感器等资源映射。 |
| `iot_platform_binding` | 租户接入层 | FastBee 设备与平台流程/项目/资源绑定。 |
| `iot_platform_field_mapping` | 租户接入层 | 绑定级字段映射。 |
| `iot_platform_exchange_task` | 数据交换层 | 定时推送、主动拉取、资源同步任务。 |
| `iot_platform_task_binding` | 数据交换层 | 交换任务与绑定关系。 |
| `iot_platform_exchange_record` | 数据交换层 | 数据交换记录,兼 outbox/inbox 审计。 |
| `iot_platform_exchange_attempt` | 数据交换层 | 每次交换尝试日志。 |
### 9.2 iot_platform_template
平台模板,全局可复用。
| 字段 | 类型 | 说明 |
| ----------------- | ------------ | ---------------------------------------- |
| id | bigint | 主键 |
| platform_code | varchar(64) | 平台编码,全局唯一 |
| platform_name | varchar(128) | 平台名称 |
| platform_type | varchar(32) | DCP、GENERIC_HTTP、GENERIC_MQTT、GENERIC_DB |
| adapter_code | varchar(64) | dcp、genericHttp 等 |
| base_url_template | varchar(512) | 默认基础地址模板 |
| auth_type | varchar(32) | 认证类型 |
| auth_schema | json | 授权配置字段定义,用于租户填写 |
| request_config | json | 默认超时、重试、TLS 等 |
| status | tinyint | 0停用,1启用 |
| create_time | datetime | 创建时间 |
| update_time | datetime | 更新时间 |
| remark | varchar(500) | 备注 |
建议索引:
```text
uk_platform_code(platform_code)
idx_platform_type(platform_type)
```
### 9.3 iot_platform_api
第三方接口定义,属于平台模板。对 OUTBOUND/PULL 是要调用的第三方接口;对 RECEIVE 是 FastBee 暴露的接收入口定义。
| 字段 | 类型 | 说明 |
| ------------------ | ------------ | --------------------------------------------------------------- |
| id | bigint | 主键 |
| template_id | bigint | 平台模板 id |
| api_code | varchar(64) | 接口编码 |
| api_name | varchar(128) | 接口名称 |
| api_type | varchar(32) | TOKEN、QUERY、RECEIVE、PUSH、RESOURCE_CREATE、RESOURCE_BIND、CALLBACK |
| method | varchar(16) | GET、POST、PUT、DELETE |
| path_template | varchar(512) | URL 路径模板或接收入口路径模板 |
| content_type | varchar(64) | application/json、form-urlencoded |
| header_template | json | Header 模板 |
| query_template | json | Query 模板 |
| body_template | json | Body 模板 |
| auth_config | json | 接口级认证或接收校验配置 |
| idempotency_config | json | 幂等 key 提取规则 |
| success_condition | json | 成功条件 |
| response_mapping | json | 响应变量提取规则 |
| retry_policy | json | 接口级重试策略 |
| timeout_ms | int | 超时时间 |
| status | tinyint | 0停用,1启用 |
| create_time | datetime | 创建时间 |
| update_time | datetime | 更新时间 |
建议索引:
```text
uk_template_api_code(template_id, api_code)
idx_template_api_type(template_id, api_type)
```
### 9.4 iot_platform_api_field
接口字段定义,用于页面展示和字段映射。
| 字段 | 类型 | 说明 |
| ------------- | ------------ | ---------------------------------- |
| id | bigint | 主键 |
| api_id | bigint | 接口 id |
| direction | varchar(16) | REQUEST、RESPONSE |
| field_path | varchar(256) | JSONPath 或表单字段名 |
| field_name | varchar(128) | 字段名称 |
| data_type | varchar(32) | string、number、boolean、array、object |
| required | tinyint | 是否必填 |
| default_value | varchar(512) | 默认值 |
| example_value | varchar(512) | 示例值 |
| description | varchar(500) | 说明 |
| sort_order | int | 排序 |
建议索引:
```text
idx_api_direction(api_id, direction)
```
### 9.5 iot_platform_flow
流程模板,属于平台模板。
| 字段 | 类型 | 说明 |
| ------------ | ------------ | ----------------------------------------------------------------- |
| id | bigint | 主键 |
| template_id | bigint | 平台模板 id |
| flow_code | varchar(64) | 流程编码 |
| flow_name | varchar(128) | 流程名称 |
| flow_type | varchar(32) | OUTBOUND_PUSH、INBOUND_PULL、INBOUND_RECEIVE、RESOURCE_SYNC、CALLBACK |
| adapter_code | varchar(64) | 可覆盖平台适配器 |
| sink_type | varchar(32) | INBOUND 数据落点类型,OUTBOUND 可为空 |
| status | tinyint | 0停用,1启用 |
| create_time | datetime | 创建时间 |
| update_time | datetime | 更新时间 |
| remark | varchar(500) | 备注 |
建议索引:
```text
uk_template_flow_code(template_id, flow_code)
idx_template_flow_type(template_id, flow_type)
```
### 9.6 iot_platform_flow_step
流程步骤。
| 字段 | 类型 | 说明 |
| -------------- | ------------ | ------------------------------------ |
| id | bigint | 主键 |
| flow_id | bigint | 流程 id |
| step_code | varchar(64) | 步骤编码 |
| step_name | varchar(128) | 步骤名称 |
| step_type | varchar(32) | API、ADAPTER、CONDITION、TRANSFORM、SINK |
| api_id | bigint | API 步骤引用接口 id |
| adapter_method | varchar(128) | 适配器方法,例如 ensurePoint |
| input_mapping | json | 步骤入参映射 |
| output_mapping | json | 步骤输出变量映射 |
| condition_expr | varchar(512) | 执行条件 |
| on_fail | varchar(32) | STOP、SKIP、RETRY |
| sort_order | int | 执行顺序 |
| status | tinyint | 0停用,1启用 |
建议索引:
```text
idx_flow_sort(flow_id, sort_order)
```
### 9.7 iot_platform_tenant_channel
租户启用平台模板后的平台实例。授权配置、baseUrl、默认用户/项目、接收安全配置属于租户级。
| 字段 | 类型 | 说明 |
| ------------------ | ------------ | ------------------------- |
| id | bigint | 主键 |
| tenant_id | bigint | 租户 id |
| tenant_name | varchar(64) | 租户名称 |
| template_id | bigint | 平台模板 id |
| channel_code | varchar(64) | 租户内平台实例编码 |
| channel_name | varchar(128) | 租户内平台实例名称 |
| base_url | varchar(512) | 实际基础地址 |
| auth_config | json | 租户授权配置,敏感值加密 |
| receive_config | json | 接收安全配置,token、签名密钥、IP 白名单等 |
| default_user_id | varchar(128) | 默认第三方用户 id |
| default_project_id | varchar(128) | 默认第三方项目 id |
| config_json | json | 租户级扩展配置 |
| status | tinyint | 0停用,1启用 |
| del_flag | char(1) | 0正常,2删除 |
| create_by | varchar(64) | 创建者 |
| create_time | datetime | 创建时间 |
| update_by | varchar(64) | 更新者 |
| update_time | datetime | 更新时间 |
| remark | varchar(500) | 备注 |
建议索引:
```text
uk_tenant_channel_code(tenant_id, channel_code, del_flag)
idx_tenant_template(tenant_id, template_id)
```
### 9.8 iot_platform_resource_mapping
外部资源映射,租户级隔离。
| 字段 | 类型 | 说明 |
| ----------------- | ------------ | ------------------------------------------------------ |
| id | bigint | 主键 |
| tenant_id | bigint | 租户 id |
| tenant_channel_id | bigint | 租户平台实例 id |
| binding_id | bigint | 绑定 id,用户/项目可为空 |
| resource_scope | varchar(32) | TENANT、PROJECT、DEVICE、BINDING |
| resource_type | varchar(64) | USER、PROJECT、POINT、DEVICE、SENSOR、MODULE、VIRTUAL、CUSTOM |
| local_key | varchar(128) | 本地唯一键,设备级使用 serialNumber |
| external_id | varchar(128) | 外部资源 id |
| external_code | varchar(128) | 外部资源编码 |
| external_name | varchar(128) | 外部资源名称 |
| resource_payload | json | 外部资源详情 |
| status | tinyint | 0失效,1有效 |
| create_time | datetime | 创建时间 |
| update_time | datetime | 更新时间 |
建议索引:
```text
uk_resource(tenant_channel_id, binding_id, resource_type, local_key)
idx_resource_tenant_type(tenant_id, tenant_channel_id, resource_type)
idx_external_id(tenant_channel_id, resource_type, external_id)
```
### 9.9 iot_platform_binding
设备绑定,租户级配置。
| 字段 | 类型 | 说明 |
| -------------------- | ------------ | ----------------------------------------------- |
| id | bigint | 主键 |
| tenant_id | bigint | 租户 id |
| tenant_channel_id | bigint | 租户平台实例 id |
| flow_id | bigint | 平台流程 id |
| product_id | bigint | 产品 id |
| product_name | varchar(128) | 产品名称冗余 |
| device_id | bigint | FastBee 设备 id |
| device_name | varchar(128) | FastBee 设备名称 |
| serial_number | varchar(64) | FastBee 设备编号 |
| external_user_id | varchar(128) | 绑定级第三方用户 id,可为空 |
| external_project_id | varchar(128) | 绑定级第三方项目 id,可为空 |
| external_device_type | varchar(32) | 第三方设备类型,例如 DCP RAIN、INCLINO |
| binding_name | varchar(128) | 绑定名称 |
| exchange_mode | varchar(32) | OUTBOUND_PUSH、INBOUND_PULL、INBOUND_RECEIVE、BOTH |
| config_json | json | 绑定级配置 |
| last_success_time | datetime | 最近成功交换时间 |
| last_success_value | varchar(128) | 最近成功值,雨量递增等场景使用 |
| status | tinyint | 0停用,1启用 |
| del_flag | char(1) | 0正常,2删除 |
| create_time | datetime | 创建时间 |
| update_time | datetime | 更新时间 |
建议索引:
```text
idx_binding_device(tenant_id, product_id, serial_number)
idx_binding_channel_flow(tenant_channel_id, flow_id)
uk_binding(tenant_channel_id, flow_id, serial_number, del_flag)
```
### 9.10 iot_platform_field_mapping
字段映射,按绑定维护。
| 字段 | 类型 | 说明 |
| ---------------- | ------------ | --------------------------------------------------------------------- |
| id | bigint | 主键 |
| tenant_id | bigint | 租户 id |
| binding_id | bigint | 绑定 id |
| direction | varchar(32) | OUTBOUND、INBOUND |
| target_path | varchar(256) | 目标字段路径 |
| target_name | varchar(128) | 目标字段名称 |
| source_type | varchar(32) | THING_MODEL、SYSTEM、CONSTANT、JSONPATH、EXPRESSION、RESOURCE |
| source_key | varchar(256) | 物模型 identifier、系统字段、表达式等 |
| source_name | varchar(128) | 来源字段名称 |
| transform_type | varchar(32) | DIRECT、DATE_FORMAT、UNIT_CONVERT、ENUM、NUMBER_SCALE、TEMPLATE、EXPRESSION |
| transform_config | json | 转换配置 |
| default_value | varchar(512) | 默认值 |
| required | tinyint | 是否必填 |
| sort_order | int | 排序 |
| status | tinyint | 0停用,1启用 |
建议索引:
```text
idx_mapping_binding(binding_id, direction)
```
### 9.11 iot_platform_exchange_task
数据交换任务,租户级。用于定时推送、主动拉取、资源同步。
| 字段 | 类型 | 说明 |
| ----------------- | ------------ | ----------------------------------------- |
| id | bigint | 主键 |
| tenant_id | bigint | 租户 id |
| tenant_channel_id | bigint | 租户平台实例 id |
| flow_id | bigint | 流程 id |
| task_name | varchar(128) | 任务名称 |
| task_type | varchar(32) | OUTBOUND_PUSH、INBOUND_PULL、RESOURCE_SYNC |
| cron_expression | varchar(128) | Cron 表达式 |
| window_type | varchar(32) | LAST_SUCCESS、RECENT_MINUTES、CUSTOM、CURSOR |
| window_config | json | 时间窗口配置 |
| cursor_json | json | 拉取游标、分页位置、最近外部 id 等 |
| sink_type | varchar(32) | INBOUND 数据落点类型 |
| batch_size | int | 批次大小 |
| max_retry | int | 最大重试次数 |
| status | tinyint | 0停用,1启用 |
| last_run_time | datetime | 最近执行时间 |
| next_run_time | datetime | 下次执行时间 |
| create_time | datetime | 创建时间 |
| update_time | datetime | 更新时间 |
### 9.12 iot_platform_task_binding
交换任务与设备绑定关系。
| 字段 | 类型 | 说明 |
| ---------- | ------- | ------- |
| id | bigint | 主键 |
| task_id | bigint | 任务 id |
| binding_id | bigint | 绑定 id |
| status | tinyint | 0停用,1启用 |
建议索引:
```text
uk_task_binding(task_id, binding_id)
```
### 9.13 iot_platform_exchange_record
数据交换记录。OUTBOUND 时是 outbox;INBOUND 时是 inbox/消费审计。
| 字段 | 类型 | 说明 |
| ------------------- | ------------- | --------------------------------------------------------------------------------- |
| id | bigint | 主键 |
| tenant_id | bigint | 租户 id |
| tenant_channel_id | bigint | 租户平台实例 id |
| flow_id | bigint | 流程 id |
| binding_id | bigint | 绑定 id,可为空 |
| task_id | bigint | 任务 id,接收入口可为空 |
| direction | varchar(32) | OUTBOUND_PUSH、INBOUND_PULL、INBOUND_RECEIVE |
| source_type | varchar(32) | DEVICE_PROPERTY、DEVICE_EVENT、ALERT_EVENT、RESOURCE、RAW 等 |
| sink_type | varchar(32) | DEVICE_PROPERTY、DEVICE_EVENT、ALERT_EVENT、RESOURCE_MAPPING、BUSINESS_TABLE、RAW_ONLY |
| source_device_id | bigint | FastBee 设备 id,可为空 |
| serial_number | varchar(64) | FastBee 设备编号,可为空 |
| external_message_id | varchar(128) | 第三方消息 id,可为空 |
| source_ref_id | varchar(128) | 本地来源或外部来源 id |
| source_time | datetime | 数据时间 |
| time_window_start | datetime | 批量窗口开始 |
| time_window_end | datetime | 批量窗口结束 |
| raw_payload | json | 原始输入或原始响应 |
| standard_payload | json | 标准数据交换消息 |
| request_payload | json | 最终请求 payload,OUTBOUND 使用 |
| response_payload | json | 响应或处理结果 |
| payload_hash | varchar(64) | payload 哈希 |
| idempotency_key | varchar(128) | 幂等 key |
| status | varchar(32) | PENDING、PROCESSING、SUCCESS、FAILED、RETRY_WAIT、SKIPPED、CANCELLED |
| retry_count | int | 已重试次数 |
| max_retry | int | 最大重试次数 |
| next_retry_time | datetime | 下次重试时间 |
| last_error | varchar(1000) | 最近错误 |
| locked_by | varchar(64) | worker 锁 |
| locked_time | datetime | 锁定时间 |
| success_time | datetime | 成功时间 |
| create_time | datetime | 创建时间 |
| update_time | datetime | 更新时间 |
建议索引:
```text
uk_idempotency(idempotency_key)
idx_record_poll(status, next_retry_time)
idx_record_direction(tenant_channel_id, direction, source_time)
idx_record_device(tenant_channel_id, serial_number, source_time)
idx_record_binding(binding_id, source_time)
```
### 9.14 iot_platform_exchange_attempt
数据交换尝试日志。
| 字段 | 类型 | 说明 |
| --------------- | ------------- | ------------------------------------------ |
| id | bigint | 主键 |
| tenant_id | bigint | 租户 id |
| record_id | bigint | 交换记录 id |
| attempt_no | int | 第几次尝试 |
| direction | varchar(32) | OUTBOUND_PUSH、INBOUND_PULL、INBOUND_RECEIVE |
| request_url | varchar(1024) | 请求地址或接收入口 |
| request_headers | json | 请求头,敏感信息脱敏 |
| request_payload | json | 请求体 |
| response_status | int | HTTP 状态码或处理状态码 |
| response_body | mediumtext | 响应内容 |
| success | tinyint | 是否成功 |
| error_msg | varchar(1000) | 错误信息 |
| duration_ms | int | 耗时 |
| create_time | datetime | 创建时间 |
建议索引:
```text
idx_attempt_record(record_id, attempt_no)
idx_attempt_tenant(tenant_id, create_time)
```
## 10. 技术实现建议
### 10.1 模块与包
后端先放在现有 IoT 服务和 open-api 中:
```text
fastbee-open-api/src/main/java/com/fastbee/controller/platform
fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/platform
fastbee-service/fastbee-iot-service/src/main/resources/mapper/iot/platform
```
前端目录:
```text
yack-web/src/views/iot/platformConnect
yack-web/src/api/iot/platformConnect.js
```
权限前缀建议使用 `iot:platformConnect`,避免和现有第三方登录 `iot:platform` 混淆。
### 10.2 核心接口
```java
public interface PlatformAdapter {
String adapterCode();
void beforeExecute(PlatformContext context);
void ensureResources(PlatformContext context);
Object transform(PlatformContext context);
ExchangeResult execute(PlatformContext context, Object payload);
}
```
```java
public interface PlatformFlowExecutor {
ExchangeResult execute(Long tenantChannelId, Long flowId, PlatformExchangeMessage message, Long bindingId);
}
```
```java
public interface PlatformExchangeRecordService {
void createOutboundRecords(PlatformExchangeMessage message);
void createPullRecords(Long taskId, Date beginTime, Date endTime);
void createReceiveRecord(Long tenantChannelId, Long flowId, Object rawPayload);
void retry(Long recordId, boolean force);
void retryBatch(List<Long> recordIds, boolean force);
}
```
### 10.3 OUTBOUND_PUSH 接入点
设备上报原流程保持不变,在设备数据入库或规则处理附近增加平台交换事件:
```text
设备数据解析
-> 原有设备日志/历史数据处理
-> 构造 PlatformExchangeMessage(direction=OUTBOUND_PUSH)
-> PlatformExchangeRecordService.createOutboundRecords(message)
-> 匹配 tenant_id + device_id 的启用绑定
-> 生成 PENDING 交换记录
-> worker 异步执行流程
```
### 10.4 INBOUND_PULL 调度
优先复用 Quartz/sys_job:
```text
Quartz 触发
-> 读取 iot_platform_exchange_task
-> direction=INBOUND_PULL 或 RESOURCE_SYNC
-> 根据 window_type/cursor_json 计算拉取范围
-> 调第三方查询接口
-> 分页/游标处理
-> 生成或直接处理 exchange_record
-> 写入 sink_type 对应业务落点
-> 更新 cursor_json
```
### 10.5 INBOUND_RECEIVE 接收入口
建议新增统一接收入口,不把旧 `/bridge/**` 作为平台对接主入口。
```text
POST /platform/receive/{tenantChannelCode}/{flowCode}
```
处理流程:
```text
解析 tenantChannelCode + flowCode
-> 加载租户平台实例和 RECEIVE 流程
-> 校验 token/签名/IP 白名单
-> 提取幂等 key
-> 创建 INBOUND_RECEIVE exchange_record
-> 同步处理或交给 worker 异步处理
-> 返回接收结果
```
### 10.6 worker 处理
worker 轮询:
```text
status in (PENDING, RETRY_WAIT)
and next_retry_time <= now
```
抢占记录时使用数据库乐观更新,避免多实例重复消费:
```sql
UPDATE iot_platform_exchange_record
SET status = 'PROCESSING', locked_by = ?, locked_time = NOW()
WHERE id = ?
AND status IN ('PENDING', 'RETRY_WAIT')
```
处理结果:成功写 `SUCCESS`,可重试失败写 `RETRY_WAIT`,超过次数写 `FAILED`,业务跳过写 `SKIPPED`。
## 11. 幂等、游标与重试
### 11.1 OUTBOUND_PUSH 幂等
实时数据优先使用原始日志 id:
```text
tenantChannelId + flowId + bindingId + OUTBOUND_PUSH + sourceRefId + payloadHash
```
没有 `sourceRefId` 时使用:
```text
tenantChannelId + flowId + bindingId + OUTBOUND_PUSH + sourceTime + payloadHash
```
### 11.2 INBOUND_PULL 幂等
优先使用第三方数据 id:
```text
tenantChannelId + flowId + INBOUND_PULL + externalMessageId
```
没有第三方 id 时使用:
```text
tenantChannelId + flowId + INBOUND_PULL + sourceTime + payloadHash
```
拉取任务必须维护 `cursor_json` 或时间窗口,避免重复和无界拉取。
### 11.3 INBOUND_RECEIVE 幂等
优先从第三方请求中提取 messageId、eventId、deviceCode + time 等业务幂等键:
```text
tenantChannelId + flowId + INBOUND_RECEIVE + externalMessageId
```
如果第三方没有幂等字段,可使用请求体 hash,但需要注意同一业务重复发送和相同 payload 的边界。
### 11.4 外部资源幂等
资源创建前先查 `iot_platform_resource_mapping`。
DCP 设备级资源必须按 `tenantChannelId + bindingId + serialNumber + resourceType` 唯一。
```text
查 mapping
-> 存在则复用
-> 不存在则加 Redis 锁
-> 再查一次
-> 调第三方创建接口或适配器方法
-> 保存 mapping
```
DCP 锁 key:
```text
platform:dcp:resource:{tenantId}:{tenantChannelId}:{serialNumber}
```
### 11.5 重试和重放
- OUTBOUND_PUSH:失败可自动重试和手动重推。
- INBOUND_PULL:失败可重试当前窗口;成功后再推进游标。
- INBOUND_RECEIVE:同步处理失败由第三方重试;异步处理失败可由 FastBee 内部重试。
- 成功记录强制重放:新建 MANUAL/REPLAY 记录,幂等 key 追加手动批次号。
## 12. 权限建议
权限前缀:`iot:platformConnect`。
```text
iot:platformConnect:template:list/query/add/edit/remove
iot:platformConnect:api:list/add/edit/remove
iot:platformConnect:flow:list/add/edit/remove
iot:platformConnect:tenantChannel:list/query/add/edit/remove
iot:platformConnect:resource:list/query/sync
iot:platformConnect:binding:list/query/add/edit/unbind/initResource
iot:platformConnect:task:list/add/edit/remove/run
iot:platformConnect:record:list/query/retry/replay
```
平台模板、接口、流程建议仅平台管理员可维护;租户管理员主要维护租户接入、资源映射、设备绑定、交换任务和交换记录。
## 13. 实施计划
### 阶段一:平台模板与租户接入骨架
- 新增平台模板、接口、字段、流程、流程步骤表。
- 新增租户平台实例表。
- 建立 DCP 平台模板和 DCP OUTBOUND_PUSH/RESOURCE_SYNC 基础流程。
- 实现租户级授权配置、接收安全配置、默认用户/项目映射。
### 阶段二:资源映射、设备绑定与字段映射
- 新增资源映射、设备绑定、字段映射页面和接口。
- 实现 DCP 一设备一测点、一设备一 DCP 设备资源建模。
- 实现 DCP token、userId、projectId、pointId、dcpDeviceId、sensor/module/virtual 资源初始化。
### 阶段三:OUTBOUND_PUSH 数据交换闭环
- 新增 exchange_task、exchange_record、exchange_attempt。
- 实现设备上报生成 OUTBOUND_PUSH 交换记录。
- 实现 worker、重试、幂等和手动重放。
- 支持雨量计实时推送闭环。
### 阶段四:INBOUND_PULL 和 RESOURCE_SYNC
- 实现平台交换任务的定时拉取。
- 支持分页、游标、时间窗口。
- 支持用户、项目、设备、测点等资源同步。
- 支持拉取数据写入明确 sink_type。
### 阶段五:INBOUND_RECEIVE 接收能力
- 新增统一接收入口。
- 支持 token、签名、IP 白名单、幂等 key 提取。
- 支持同步处理和异步 exchange_record 处理。
- 支持接收数据写入设备属性、事件、告警、资源映射或 RAW_ONLY。
### 阶段六:通用平台增强
- 通用 HTTP 平台模板。
- 接口调试。
- 模板导入导出。
- MQTT/DB 适配器按需扩展。
- 日志归档和敏感信息脱敏策略。
## 14. 风险与约束
- 平台模板是共享基础能力,租户授权、项目、资源、设备绑定、交换记录必须按 `tenant_id` 隔离。
- INBOUND_PULL 和 INBOUND_RECEIVE 都是外部输入,必须做鉴权、校验、幂等和明确落点。
- DCP 一测点一设备是核心建模约束,不能把测点设计成产品级或平台级共享资源。
- OUTBOUND_PUSH 必须异步,不影响设备上报吞吐。
- token、密码、请求头、签名密钥等敏感信息需要加密保存和脱敏展示。
- 交换日志增长较快,需要后续增加归档或清理策略。
- 字段映射表达式必须受限,不能执行任意代码。
- INBOUND 写业务表必须通过白名单 sink adapter,不能开放任意 SQL。
- 定时拉取和补推要限制窗口、批次大小和并发数,避免压垮第三方平台或本系统。
- 雨量累计值不递增时应跳过并记录原因,不应无限重试。
## 15. 结论
平台对接应定位为可复用的数据交换/iPaaS Connector 能力,而不是单个平台或单一“推送”能力。
推荐模型:
```text
平台模板(共享)
-> 接口配置(共享)
-> 流程编排(共享)
-> 适配器(共享)
-> 租户平台实例(租户级)
-> 用户/项目/资源映射(租户级)
-> 设备绑定和字段映射(租户级)
-> 数据交换任务(租户级)
-> 数据交换记录和尝试日志(租户级)
```
其中数据方向明确分为:
```text
OUTBOUND_PUSH:FastBee 作为 producer 推送数据
INBOUND_PULL:FastBee 主动拉取,但作为 consumer 消费第三方数据
INBOUND_RECEIVE:FastBee 被动接收,并作为 consumer 消费第三方数据
```
DCP 是第一批落地模板和适配器,必须保留“一测点一设备”的资源约束;其他租户复用 DCP 平台模板后,只需配置自己的 DCP 账号、用户、项目、设备绑定、字段映射和数据交换策略。