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.
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
- 01Stack: Java 17, Spring Boot 3 and Spring Cloud, with ThingsBoard CE kept unforked behind a replaceable, upgradeable adapter boundary.
- 02Domain 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.
- 03Architecture rules that are tested, not just documented: hexagonal architecture, with boundaries enforced by ArchUnit tests. Pooled tenants are isolated with PostgreSQL row-level security.
- 04Executable 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
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.
- 01Control 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.
- 02Rules 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.
- 03Snapshot 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.
- 04Reconciliation 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.
- 05Evidence 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.
- 06Safety 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"]
Status, stated honestly
The platform is implemented and tested locally, but not yet deployed. 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 →