Case study 3 · Multi-tenant IoT platform

IOT-EE

Enterprise capabilities for ThingsBoard CE operators, a safe path off an existing deployment, and no fork they can never upgrade.

Implemented and tested locally · not yet deployed

The problem

IoT operators on ThingsBoard CE need enterprise capabilities such as tenancy, entitlements, audit, firmware management and disaster recovery. They also need to avoid a fork they can never upgrade, and to move off an existing deployment without losing the rule logic and history their business runs on.

The platform

  • 01
    Stack: Java 17, Spring Boot 3 and Spring Cloud, with ThingsBoard CE kept unforked behind a replaceable, upgradeable adapter boundary.
  • 02
    Domain coverage: tenants, devices, assets and their hierarchy, telemetry, alarms, commands, reports and firmware. The first use case is tank monitoring, and the model is general to any asset fleet.
  • 03
    Architecture rules that are tested, not just documented: hexagonal architecture, with boundaries enforced by ArchUnit tests. Pooled tenants are isolated with PostgreSQL row-level security.
  • 04
    Executable specification. A reference implementation covers milestones M0 to M8, and every real-backend item is explicitly marked as blocked until it can be verified.
flowchart LR
  W["Browser"] -->|"HTTPS"| GW["APISIX<br/>gateway"] --> BFF["Backend<br/>for frontend"] --> SV["Spring Boot services<br/>domain · ports · adapters<br/>gRPC between services"]
  SV -->|"domain events"| KF["Kafka"]
  SV --> PG["PostgreSQL<br/>pooled tenants + RLS"]
  SV --> TB["ThingsBoard CE<br/>unforked, behind an adapter"]
  D["Devices"] -->|"MQTT"| TB
  CT["Contracts<br/>.proto · OpenAPI · JSON Schema"] -.-> SV
Communication direction and tenancy, from the repository's architecture conventions. · Source: repository

The Migration Manager

Migration Studio brings an existing ThingsBoard deployment across: rule chains with their node configurations and custom code, exported as JSON through an approved path, plus the entities and the database history. It treats rules asreviewed executable logic, not data. Copying a rule chain blindly could run one tenant's logic against another tenant's data.

  • 01
    Control plane and data plane are separate. The Studio versions sources, tenant and field mappings and secret references, and runs validate, dry-run preview, approve, start, pause and resume. Read-only connector adapters do the extraction. The browser never holds replication credentials.
  • 02
    Rules migrate per tenant. Every chain and node is mapped to exactly one target tenant. Orphan nodes and cross-tenant edges go to quarantine. Each rebuilt node stays disabled until golden inputs, outputs and alarm effects match the legacy system for that tenant. It is then activated in a controlled ring, with the prior version kept for rollback.
  • 03
    Snapshot and change capture form one ordered run. A consistent snapshot boundary is followed by CDC from the same position (Debezium is a candidate, only after a source-specific proof). Changes apply idempotently with checkpoints, and anything ambiguous is quarantined, never guessed.
  • 04
    Reconciliation you can filter. Results are filterable by tenant, device and UTC period. Visible dashboard and report parity is checked separately from database counts, because matching row counts don't prove matching behaviour.
  • 05
    Evidence is the release gate. Each run produces a manifest: source authorisation, snapshot and CDC continuity, mapping hashes, quarantine reasons, rule-graph hashes, golden parity results and approvers. An unexplained difference blocks cutover.
  • 06
    Safety rules. No password hashes, tokens or device credentials are copied. Nothing writes to ThingsBoard's internal tables. Source access stays read-only. Shadow data can never drive commands, alarms or billing before the cutover gate.
flowchart LR
  TBX["Existing ThingsBoard CE<br/>rule chains · node configs<br/>custom code · entities<br/>(JSON export / API)"] --> AD["Connector adapters<br/>read-only"]
  LPG["Legacy PostgreSQL<br/>telemetry history"] -->|"snapshot + CDC<br/>after a source proof"| AD
  MQ["Mosquitto"] -->|"live delta"| SH
  AD --> MS["Migration Studio · control plane<br/>map tenant and entity IDs<br/>validate · preview (dry run)<br/>approve · run · evidence"]
  MS --> QU["Quarantine<br/>orphans · cross-tenant edges<br/>schema drift · missing keys"]
  MS --> SH["Isolated shadow data<br/>parity checks only"]
  MS -->|"golden parity + approval<br/>(cutover gate)"| TG["IOT-EE services<br/>tenant-scoped rules and data"]
Migration flow, from the legacy migration execution plan and the proposed Migration Studio CDC decision record. · Source: repository docs

Status, stated honestly

The platform is implemented and tested locally, but not yet deployed (the README says so). In the Migration Manager, the control foundation is built in the reference specification: source registration, approval gates, evidence records, secrets held only as vault references, and validate and preview steps that tests prove change nothing.

Live connectors, rule-node mapping against real exports, change capture, shadow comparison and the final cutover are designed and documented. They need access to a real legacy deployment, and the change-capture design is still a proposed decision.Repository →