Architecture
How all the pieces fit together — from machine data to KPI APIs.
System Overview
Internet
│
▼
┌──────────────────────────────────────────────────────┐
│ Caddy (TLS termination, reverse proxy) │
└──────────────────────┬───────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────┐
│ fnkit-gateway (authentication, routing, rate limit) │
└──────────────────────┬───────────────────────────────┘
│
┌────────────┼────────────────────┐
│ │ │
▼ ▼ ▼
HTTP Functions MQTT Functions Shared Services
(uns-cache, (uns-sim, (fnkit-cache,
uns-log, uns-framework) fnkit-postgres,
uns-state, MQTT broker)
uns-stoppage,
uns-productivity,
uns-input,
uns-kpi)
All containers run on a shared Docker network (fnkit-network). External access goes through Caddy → gateway. Internal communication happens directly between containers.
Data Flow
The system processes data in three stages: capture, process, and report.
Stage 1: Capture
| Component | Role |
|---|---|
| uns-sim | Publishes machine data (status, program, tool) to MQTT every 3 seconds |
| MQTT Broker | Distributes messages to all subscribers |
| uns-framework | Subscribes to v1.0/# and caches every message to Valkey |
For each message: current value → uns:data:<topic>, previous value → uns:prev:<topic>
Stage 2: Process
Processing functions read from Valkey and write to PostgreSQL:
| Function | Reads | Writes |
|---|---|---|
| uns-state | /status topics from Valkey | State durations → uns_state table |
| uns-stoppage | uns_state table | Classified stoppages → uns_stoppage table |
| uns-productivity | /program topics from Valkey | Production runs → uns_productivity table |
| uns-input | HTTP POST body | Manual entries → uns_input table |
| uns-log | Any topics from Valkey | Change snapshots → uns_log table |
| uns-cache | Any topics from Valkey | JSON response (no DB write) |
Stage 3: Report
uns-kpi is a pure read function. It queries all 4 PostgreSQL tables and computes manufacturing KPIs on demand — utilisation, availability, throughput, MTBF/MTTR, stoppage pareto, and scrap.
Infrastructure Components
fnkit-network
A Docker bridge network that all containers join. Functions communicate by container name:
fnkit-cache:6379 → Valkey (Redis-compatible cache) fnkit-postgres:5432 → PostgreSQL database mqtt-broker:1883 → MQTT broker (internal) mqtt-broker:8883 → MQTT broker (TLS)
fnkit-cache (Valkey)
Valkey — an open-source Redis-compatible cache. Used for:
| Purpose | Key Pattern |
|---|---|
| UNS topic data — current and previous values | uns:data:*, uns:prev:* |
| Topic registry — set of all discovered topics | uns:topics |
| Function config — runtime configuration | fnkit:config:* |
| Metadata — message counts, timestamps | uns:meta:* |
fnkit-postgres (PostgreSQL)
Stores all persistent data. All tables are auto-created on first run:
| Table | Written by | Purpose |
|---|---|---|
| uns_log | uns-log | Change snapshots with full hierarchy |
| uns_state | uns-state | Machine state durations |
| uns_stoppage | uns-stoppage | Classified stoppage reasons |
| uns_productivity | uns-productivity | Production run metrics |
| uns_input | uns-input | Manual operator entries |
fnkit-gateway
The API gateway handles authentication (Bearer token), routing (URL paths → function containers), and rate limiting.
GET /uns-cache → uns-cache container POST /uns-log → uns-log container GET /uns-kpi?hours=8 → uns-kpi container POST /uns-input → uns-input container
Caddy
Provides automatic TLS (Let's Encrypt), reverse proxy, and HTTP/2 support.
Function Types
| Type | Scaffold Command | Trigger | Used by |
|---|---|---|---|
| Go HTTP | fnkit go | HTTP request | uns-log, uns-state, uns-productivity, uns-kpi |
| Node.js HTTP | fnkit node | HTTP request | uns-cache, uns-stoppage, uns-input |
| Go MQTT | fnkit go-mqtt | MQTT message | uns-framework |
| Node.js MQTT | fnkit node-mqtt | MQTT message | uns-sim |
Configuration Pattern
All runtime configuration is stored in Valkey, not in environment files:
fnkit:config:uns-log → {"table":"uns_log","topics":[...]}
fnkit:config:uns-state → {"table":"uns_state","topics":[...]}
fnkit:config:uns-productivity → {"table":"uns_productivity","topics":[...]}
Each function reads its config using FUNCTION_TARGET as the key. Config is cached in-memory for 30 seconds. You can change what topics a function monitors without redeploying the container.
Deployment Model
# Local development docker compose up -d curl http://localhost:8080/ # Remote deployment (GitOps) fnkit deploy remote --host root@server git push deploy main
Each function is independently deployable. Updating uns-kpi doesn't affect uns-state. Rolling back uns-stoppage doesn't touch uns-productivity.