The shape rules and patterns applied end to end. One app reached three ways over shared services, and the same requirement built with and without seams — so you can see what the seams buy you.
One app, three surfaces
An HTTP API, a dashboard and MQTT over one shared Tables pool; each surface ends at its own sink.
Node-RED · Data-Driven App — three surfaces, one shared pool
Surfaces · each beginning its own path
MQTT in
devices
http in
services
dashboard
people · reuses HTTP
link call
Shared services
Tables pool
one pool · link call
results return
Sinks · one per surface
MQTT out
publish
http res
respond
call / return
One app reached three ways over shared services.
The pieces
Surfaces — a dashboard for people, an HTTP API for services, an MQTT feed for devices and events. Each beginning is its own path, so a device path never runs through a browser path.
Shared services — one Tables pool and one external service call, both invoked with link call. One pool serves all three surfaces without mixing them.
Single sink — each surface converges on one sink through a labeled link, an http response or an MQTT publish. It only sends; the HTTP path responds exactly once, the MQTT path just publishes.
People reuse HTTP — the dashboard is a ui-template that fetches the HTTP API, so it adds no new backend paths of its own.
Same requirement, with vs without seams
Draw the boundary on purpose and define the contract; spaghetti has nowhere to accumulate.
One tab, everything — versus four named tabs
One tab, everything
Node-RED
one flow, everything tangled
Four named tabs
Config
Ingestion
Processing
Presentation
The same requirement built with and without seams.
The pieces
The bad version — one tab, everything on it. Tags and thresholds frozen in Function nodes, a template that holds logic and pulls its own data, the full object threaded node to node. A second line means copy, paste, edit.
{
"The good version — four tabs with clear boundaries": "Config, Ingestion, Processing, Presentation. Config lives in a persistent store the operator edits, the template only renders a view-model, and state lives in a namespaced context key."
}
Why it wins — named seams you can read one at a time, runtime config with no redeploy, a clean UI boundary, and a Threshold Evaluator subflow, so a second line is configuration rather than copy-paste.
The architecture, in one sentence
A Software: Data-Driven App backed by a Relational DB, reached three ways over one shared Tables pool and one external service call, each surface ending at its own sink. Draw the boundary on purpose and define the contract across it, and there is nowhere for spaghetti to accumulate.