首页 / 业务知识 / 核心领域模型与业务规则

设备归属与绑定

设备归属不能只看单行字段。iot_device.owner_user_id 表示当前归属,但完整绑定过程经过三类记录:

实体/表职责关键约束
iot_bind_session绑定会话:记录一次绑定尝试的中间状态session_key 唯一;设备与会员状态查询有组合索引
iot_binding_task绑定任务:连接设备、订阅 Seat 与支付后的最终执行租户内 task_nopay_order_no 及未完成 session/pre-bind/device guard 唯一,用于幂等和并发防重
iot_device_share设备分享:from_user_id / to_user_id 表示双方,状态和有效期决定是否生效分享状态 + 有效期判定
绑定过程通过 task/session 记录中间状态,不以单行设备归属字段替代完整流程;绑定涉及订阅 Seat 占位与支付时走 Saga(见下)。

订阅-权益-Seat 模型

实体表达的事实
subscription_product / subscription_product_capability可售套餐与套餐包含的能力码
subscription_active当前生效的订阅(权益主体)
subscription_record订阅变更历史(开通/续费/过期/转移)
subscription_seat权益席位占用(设备或成员);对已占用 session/device guard 唯一,释放后恢复
subscription_transfer订阅转移记录

绑定 Saga 事件流(topic entrax-subscription-binding-saga-v1,Tag 即事件类型,统一契约常量避免两模块各自维护字符串):

  1. IoT 发起绑定 → 发布 subscription.seat.reserve.requested(Seat 预占请求)
  2. Subscription 预占 Seat → 回发 subscription.seat.reserved(成功)或 subscription.seat.reserve-failed / subscription.seat.payment-required(需先支付)
  3. 需要支付时走 pay 完成支付 → 发布 subscription.paid.activation.requested → 激活后回发 subscription.paid.activation-completed
  4. IoT 完成绑定 → 回发 iot.binding.completed;任一步失败 → 发布 subscription.seat.release.requestedsubscription.seat.released 补偿释放

消费方:IotBindingSagaListener(RocketMQ,consumerGroup subscription-binding-saga-iot-v1)接收 Seat 结果并调用 IotBindingTaskService.handleSubscriptionResult

权益校验对外暴露为 gRPC SubscriptionEntitlementServiceHasDeviceCapability / BatchHasDeviceCapability / ListDeviceCapabilities / GetRequiredProducts,供 Go 设备网关等外部系统校验设备能力。

支付事实分层

Pay 模块把一次支付拆成多个独立事实,分别落表并各自维护状态机:

事实表/服务说明
支付订单pay_order业务订单,唯一约束:租户订单号、app_id + merchant_order_id
支付尝试pay_payment_attempt与提供商的一次交互;唯一约束:公开 attempt ID、客户端幂等键、提供商幂等键
异步通知通知 + PayNotifyJob提供商回调经校验后驱动状态迁移,失败进重试
对账PayReconciliationCaseJobReconciliationCaseService以提供商流水核对,差异生成 case 处理
未知状态恢复PayUnknownAttemptRecoveryJob订单过期、超时未回调的尝试自动查询并恢复
退款 / 结算PayRefundFactServiceSettlementServicePayTransferSyncJob退款、结算、转账各自独立事实与同步
不能只用 pay_order.status 推断所有提供商状态;对账与未知状态恢复是支付可靠性关键,任何状态推断都必须回到各事实表。

SIM 生命周期

SIM 模块管理卡档案从采购到回收的完整生命周期,涉及与供应商系统的多轮异步交互:

  1. 采购/入库:SimProviderOrderSimImeiPool 管理批次与 IMEI 池
  2. Profile 激活:SimProfile 维护 eSIM profile 档案;SimBinding 绑定到设备
  3. 供应商同步:SimProviderSyncJob + SimSyncController 同步供应商状态,回调 SimCallbackProcessJob 处理并幂等去重
  4. 用量与计费:SimCdr 消费 CDR 生成用量快照,SimSubscription 关联订阅
  5. 告警与回收:SimAlert / SimAlertPolicy 阈值告警;生命周期事件 SimLifecycleEvent 记录状态流转

关键机制:供应商回调幂等、批任务(SimBatchTask)重试、数据保留策略。

告警规则模型

告警能力由 Java alarm(配置面)与 Go alertsvr(执行面)共同构成:

组成职责代码位置
规则 alarm_rule触发器(条件类型/操作符/配置 JSON)+ 过滤器逻辑Java AlarmRuleController;gRPC AlarmRuleService.GetEnabledRulesByDeviceName
过滤器 alarm_rule_filter附加过滤条件,嵌套在规则下gRPC AlarmRuleFilter 消息
模板 alarm_rule_template规则模板,App 端可选规则快速配置AppAlarmRuleTemplateController
记录 alarm_record命中后的告警记录与处理状态AlarmRecordControllerAppAlarmRecordController
执行评估消费设备数据执行 WHEN-THEN 判断Go alertsvr alarmEvaluator.go + ruleIndexCache + stateCache
规则配置(Java)与规则执行(Go)通过 gRPC 契约解耦:Go 启动时拉取设备启用的规则并本地缓存,事件到达后在缓存上评估,避免每次判断都回源 Java。

关键跨模块关系与约束

关系涉及模块约束/原则
设备绑定iot + member + subscription + pay绑定任务幂等(task_no/订单号唯一);Seat 预占 + 支付 + 激活走 Saga
订阅权益校验subscription → Go 网关gRPC 按 deviceName 校验能力;产品/能力码由 subscription 维护
告警规则下发alarm → alertsvrgRPC 查询启用规则,执行侧本地缓存;规则变更需主动失效缓存
轨迹数据Go geosvr/tripsvr → Java prod-gpsGo 高频写 TDengine;Java 只读报表,严禁高频写关系库
用户语义system/member/notify/alarm/gps后台接收人走 system_users,APP 用户走 member_user,查询前必须确认表语义
事件可靠性跨语言消息多副本消费指定 Queue Group;不可丢失消息用 JetStream;消费处理幂等