FN-UNS / THE REFERENCE IMPLEMENTATION

The namespace.
Put to work.

fn-uns is a working implementation of a Unified Namespace. It collects machine signals, keeps production history, and makes the results available to dashboards and other applications. Start with simulated machines, then adapt it to your factory.

CAPTURE PROCESS REPORT cnc-01 ACTIVE cnc-02 IDLE cnc-03 ACTIVE cnc-04 ALARM MQTT Broker Valkey Cache uns:data:* · uns:prev:* uns-framework uns-state Go uns-stoppage Node uns-productivity Go uns-log Go uns-input Node PostgreSQL 4 tables uns-kpi Go · HTTP 72% Utilisation 94% Availability 48/hr Throughput 142m MTBF 8.3m MTTR ISA-95 TOPIC HIERARCHY v1.0 / enterprise / site1 / area1 / cnc-01 / status

Capture once. Use it across your factory.

A machine publishes a state change. The pipeline keeps its latest value and records when the change happened. Dashboards, engineering tools, and analysis can work from the same machine identity and timestamps.

01 / OPERATIONS

Know the current state.

A dashboard reads the latest value for CNC-01 from the cache. The timestamp tells you when that value was observed.

Read current values →
02 / ENGINEERING

Reconstruct what happened.

Keep the original signals, state transitions, and operator entries. Follow a change back to its machine and time.

Store the signal history →
03 / ANALYSIS

Assemble the relevant context.

Select a machine and time window. Supply the relevant history and notes to the model alongside the question.

Follow an example below ↓

Give AI the records behind the answer.

A current state tells you what a machine is doing. History and operator notes explain the sequence around it. Here is what that context can look like for one question.

Worked example · Synthetic records and an illustrative response

Context supplied

01—03
Machine
CNC-01 · Site 1 / Area 1
Window
10:00–11:00 UTC, same day
  1. 01

    ACTIVE → IDLE

    CNC-01 stops running.
  2. 02

    “Tool change in progress.”

    An operator records a note for CNC-01.
  3. 03

    IDLE → ACTIVE

    CNC-01 resumes running.

THE QUESTION

What happened on CNC‑01 between 10:00 and 11:00?

EXAMPLE RESPONSE

CNC-01 was idle from 10:14 to 10:32, a period of 18 minutes. 1 3

At 10:16, an operator recorded “Tool change in progress.” 2

The timestamps establish the duration. The operator supplies the note. The model can bring those facts together in a readable account.

IDENTITY

Use the same machine name across signals, history, and manual entries.

TIME

Select a time window and calculate durations from the stored records.

CONTEXT

Include the relevant events and notes with the question sent to the model.

Capture. Process. Report.

Data flows through three stages. Each stage is independent and composable — built from small functions that do one thing well.

STAGE 01

Capture

Machines publish status, program, and tool data to MQTT every 3 seconds. The framework subscribes to the entire namespace and caches every message in Valkey — current value and previous value, for change detection.

uns-simuns-frameworkMQTTValkey
→
STAGE 02

Process

HTTP functions poll the cache, detect changes, and write structured records to PostgreSQL — state durations, stoppage classifications, production runs, and operator input.

uns-stateuns-stoppageuns-productivityuns-loguns-input
→
STAGE 03

Report

KPI functions query all PostgreSQL tables and compute manufacturing metrics on demand — utilisation, availability, throughput, MTBF, MTTR, and stoppage pareto.

uns-kpiuns-cachePostgreSQL

All functions run as Containers on a shared network. External access goes through Caddy (automatic TLS) → fnkit-gateway (auth, routing, rate limiting). Internal communication happens directly between containers. Deployed via git push using fnkit's GitOps workflow.

The core pipeline, component by component.

Each function is a standard Go or Node.js program — its own container, its own repo, its own deploy lifecycle. They compose through shared infrastructure, not through each other.

uns-simNode.js · MQTT
Simulates 4 CNC machines publishing realistic status, program, and tool data every 3 seconds
uns-frameworkGo · MQTT
Subscribes to the entire namespace, caches every message with current/previous value tracking
uns-cacheNode.js · HTTP
Read API for cached topics — returns JSON with change detection and metadata
uns-logGo · HTTP
Logs data snapshots to PostgreSQL whenever a topic value changes
uns-stateGo · HTTP
Tracks machine state transitions and logs precise durations — the foundation for all time-based KPIs
uns-stoppageNode.js · HTTP
Auto-classifies why machines aren't running, with manual operator override for real reasons
uns-productivityGo · HTTP
Tracks production runs — parts completed, target attainment, throughput per hour
uns-inputNode.js · HTTP
Manual operator data entry — scrap counts, quality notes, shift handover information
uns-kpiGo · HTTP
Pure read function — queries all tables and computes manufacturing KPIs on demand via a single API call

These are the core pipeline components. The full reference covers all 12, including the historian, dashboards, and optional AI analysis.

A system your team can maintain.

The implementation keeps processing logic in code and runs components in containers. This gives an engineering team control over changes, while leaving them responsible for deployment, monitoring, backups, and data quality.

How the implementation is built

For the team writing and deploying processing logic: topic structure, messaging, containers, and a code example.

Structured data. Serverless functions. Git push to deploy.

Three ideas come together: an ISA-95 topic hierarchy gives every data point a canonical address, lightweight functions process the data, and MQTT connects everything in real time.

ISA-95 Topic Hierarchy

All data is organised using the ISA-95 international standard — a structured path from enterprise down to individual data points. The hierarchy is self-describing: any consumer can parse the topic path to understand where data comes from without mapping tables or documentation.

Publish / Subscribe Messaging

MQTT decouples producers from consumers. Machines publish to topics, applications subscribe to what they need. The broker handles delivery. Adding a new machine means publishing to a new topic — the entire pipeline picks it up automatically.

Serverless Functions

Each piece of logic is a small, independent function — Go or Node.js. No monolithic platform, no flow builder. Functions read from a shared cache, write to PostgreSQL, and compose through infrastructure rather than through each other.

GitOps Deployment

Every function is version controlled. Deploy with git push. Roll back with git revert. Full audit trail, code review, and CI/CD — the same workflow your software team already uses.

v1.0 / enterprise / site1 / area1 / cnc-01 / status
└─ namespace version
└─ company / business unit
└─ factory / physical site
└─ production area
└─ individual machine
└─ data point

The data flow: Machines publish → MQTT broker distributes → Functions cache in Valkey → Functions detect changes and write to PostgreSQL → KPI functions query and compute on demand.

The deploy flow: Write code → git commit → git push → fnkit builds container → running in production. No manual server management, no UI configuration.

Readable. Testable. Reviewable.

No drag-and-drop flow builders. No visual wiring. No opaque configuration UIs. Just code that any developer can read, review, and extend.

// Read current + previous for every topic
const pipe = rdb.pipeline()

for (const topic of topics) {
  pipe.get(`uns:data:${topic}`)
  pipe.get(`uns:prev:${topic}`)
}

const results = await pipe.exec()

// Did the value change?
const changed = current !== previous

Current value. Previous value. Change detection. One call.

The cache stores two versions of every topic — current and previous. A single pipelined read returns both, plus metadata. The changed flag tells downstream functions whether to act.

This is the pattern that powers the entire pipeline. State tracking, stoppage classification, production logging — they all read from this cache and only write to PostgreSQL when something actually changes.

Standard Node.js. Standard Redis commands. No proprietary SDK, no vendor abstraction layer.

uns-cache/index.js — the complete cache read function

Start with simulated machines.

The quick start brings up the simulator, topic monitor, and cache API. You will see machine values in JSON. The deployment guide then adds stored production records and metrics.