nodela.

Domain-agnostic IoT platform

A real-time IoT backbone.
On your own servers.

nodela turns the raw MQTT packet into a canonical event, runs the rules you write in TypeScript on the stream with state, and writes the result to a live map, to alerts and to your time series. Not SaaS — one Helm chart installs it into your own cluster, and the data never leaves it.

livepipeline
inbound · MQTTin/cbor/dev-8842
{ 1: 41.0182, 2: 29.0117, 3: 128,
  9: 1751030400, 21: "34ABC123" }

binary, integer key table

canonical · Redpandaiot.acme.fleet.telemetry
{
  "device_id": "dev-8842",
  "lat": 41.0182, "lon": 29.0117,
  "speed": 128, "ignition": true,
  "plate": "34 ABC 123",
  "driver": "M. Yılmaz"
}

slot aliases resolved

rule(event.speed ?? 0) > 120→ true
alertSpeeding · 34 ABC 123 · 128 km/h
≤ 5 s
save a rule, the running pipeline picks it up — no deploy
3 codecs
JSON · CBOR · MessagePack, one canonical event
One chart
broker to console, the whole stack via Helm

How it works

From raw packet to decision, five stops

Every stop is a contract. Replace anything in between; the envelope stays the same.

  1. 01

    Ingress

    Devices publish straight to MQTT; JSON, CBOR and MessagePack channels are native. Teltonika TCP and HTTP get a decoding shim at the edge. A packet that cannot be decoded is not lost — it lands in the DLQ.

    in/{codec}/{device_id}

  2. 02

    Stream

    Every event is written durably to Redpanda. Ordering is guaranteed by processing_key: events from the same device — or the same asset — always land on the same partition, always in order.

    iot.{tenant}.{vertical}.raw

  3. 03

    Enrichment

    The raw bag flattens into a canonical event. Slot aliases become real field names (t1 → plate) and reference data is joined in from cache. With no enrichment defined, the event passes through untouched.

    enrich-manager

  4. 04

    Rules & processors

    Your rules run keyed and stateful on Flink. A rule returning true raises an alert; processors keep state, set timers and emit events of their own.

    rule-manager · processor-manager

  5. 05

    Output

    Alerts, current device state, time series and integration outputs. The console updates the map live over SignalR — no page refresh.

    .alerts · device.state · timescale

Rule editor

Writing a rule is as simple as writing a function

You write TypeScript in the browser. Types are generated for your tenant: if you defined an alias you write event.plate and never see a field called t1. On save the code is type-checked and errors come back line by line; if it passes, the running pipeline picks up the new version within five seconds. No restart, no deploy, no JAR.

1export default function evaluate(event: IAcmeFleet): boolean {
2 // Aliased fields are real TypeScript properties:
3 // plate = t1, driver = t2 — the slot name is not on the interface.
4 if (!event.ignition) return false;
5
6 return (event.speed ?? 0) > 120;
7}
  • Monaco in the browser, with your tenant's types
  • Full type check before anything is saved
  • Hot reload: live within 5s of saving

Console

The screens themselves

Not mockups — screenshots taken from a running installation.

nodela.io/verticals/fleet/rules/speed-threshold
The rule editor. Monaco in the browser, typed for your tenant. The rule returns a severity that scales with speed rather than a fixed threshold; the green badge means the code passed its type check.
The rule editor. Monaco in the browser, typed for your tenant. The rule returns a severity that scales with speed rather than a fixed threshold; the green badge means the code passed its type check.
nodela.io/verticals/fleet/map
Live tracking. device_state holds the current picture and changes arrive over SignalR — position and timestamp update without a page refresh.
Live tracking. device_state holds the current picture and changes arrive over SignalR — position and timestamp update without a page refresh.

Platform

What a backbone needs, already built

The layer you rewrite on every project is finished here.

Canonical event model

One envelope: tenant, time, identifiers, processing_key and a versioned payload. After telemetry there is no such thing as a device type — everything is the same interface.

Aliased custom fields

Five text and five numeric slots inline, the rest in JSONB. You give them aliases, codegen writes the TypeScript interface for your tenant. A real type, not documentation.

Stateful processors

Keyed state, timers you set and cancel, the watchdog pattern. Rules like 'no signal for ten minutes' do not fit into SQL; they fit here.

Live map

device_state holds the current picture and SignalR pushes changes to the console. The debounce threshold is a setting — the map is not drowned in redundant updates.

Alert handling

A rule can return a dynamic severity, not just a fixed threshold. Repeating alerts are deduplicated, so an operator does not see the same event a hundred times.

Time series

TimescaleDB with continuous aggregates. You do not hand-write a rollup table for an eight-hour report, and you do not chase its refresh either.

Commands & downlink

Send a command to a device over MQTT, SMS or BLE; template-based and channel-agnostic. Firmware binaries and configuration are managed separately.

Multi-tenant

Topics per tenant, types per tenant, rules per tenant. One installation, many customers — and one customer's rule never sees another's.

Verticals

A vertical is a UI and rule bundle

A device is not locked to a vertical. It shows up on the screens that match the IO it produces; opening a new vertical is not standing up a new platform.

Fleet management

IFleet

Position, speed, ignition, odometer, satellite count. Speeding, idling, trip start/end and geofence rules.

  • trips
  • speeding
  • idling

Cold chain

IColdChain

Temperature and humidity thresholds, door state, chain breaks. Escalating alerts based on how long and how often a threshold is breached.

  • thresholds
  • door
  • chain break

Asset tracking

IAssetTracking

Geofence entry and exit, movement and dwell, asset-to-device binding — including several devices on a single asset.

  • geofence
  • dwell
  • binding

Architecture

Every component, one picture

The flow above is the summary. Below is the whole system: from broker to console, from the managers to external integrations — what each box does and which topic runs between them.

Install

Your infrastructure, one chart

Kubernetes, k3s or a single machine — it does not matter. The whole stack, from broker to console, is one Helm chart with a values file per target. The difference between the dev cluster on your laptop and production is that file.

The data stays with you
Not SaaS. Neither telemetry nor rules leave your servers; it runs on an air-gapped network just as well.
White label
Ship it to your own customers under your own brand. The console and its copy are yours.
No vendor lock-in
Standard components underneath: MQTT, Redpanda, Flink, PostgreSQL. If you want out tomorrow, your data is already in a standard shape.
bash
$ helm install nodela deploy/helm/nodela -f values-prod.yaml
broker · redpanda · flink · postgres/timescale · api · console
 
$ ./scripts/smoke.sh
32/32 ✓

Running underneath

  • Mosquitto
  • Redpanda
  • Apache Flink
  • PostgreSQL
  • TimescaleDB
  • GraalVM
  • Rust
  • .NET
  • TypeScript
  • Next.js
  • Kubernetes
  • Helm

FAQ

Probably the three questions on your mind

Can I connect my own devices?

Any device that speaks MQTT connects directly; JSON, CBOR and MessagePack channels are ready. There is a parser for Teltonika's TCP protocol. For anything else you write a small shim at the edge: decoding happens outside, and a single canonical shape stays inside the platform.

Do I need to know Flink or Java to write rules?

No. Rules, enrichments and processors are all TypeScript. Keyed state, ordering guarantees and timers are carried by Flink underneath; you just write a function.

How does it talk to my existing systems?

Alerts and telemetry can be streamed out over webhooks and integration channels, and your own application pulls data through the query gateway. nodela does not replace your application — it puts a backbone under it.

Contact

See it live in thirty minutes

Let us walk you through the install, the rule editor and the map with real data. Tell us briefly what you are trying to do and we will get back to you.

info@nodela.io

Your details are used only to get back to you and are never shared with third parties.