System Configuration & Architecture

Complete overview of MassAI Digital Twin Designer services, ports, and communication flows with PostgreSQL time-series storage.

📝 Quick Reference

Development URLs

Common Commands

docker-compose up -dnpm run dev (Frontend)uvicorn app.main:app --reload (Backend)mosquitto_pub -h localhost -t topic -m "message"psql -h localhost -U massai -d massai
🔌 Services & Ports

Frontend (Next.js)

Port 3000

React application with PrimeReact UI components

URL:http://localhost:3000
Communicates with:
  • Backend API (:8000) via HTTP/REST
Details:
  • Framework: Next.js 15.5.6
  • UI Library: PrimeReact
  • Charts: Chart.js (react-chartjs-2)
  • State: Zustand
  • Auth: Keycloak integration

Backend (FastAPI)

Port 8000

Python REST API with async support

URL:http://localhost:8000
Communicates with:
  • Eclipse Ditto (:8081) via HTTP/REST (via Nginx)
  • PostgreSQL (:5432) via SQL (async via SQLAlchemy)
  • Mosquitto MQTT (:1883) via MQTT
Details:
  • Framework: FastAPI
  • API Docs: http://localhost:8000/docs
  • CORS: Enabled for localhost:3000
  • Timeseries Routes: /api/timeseries/history, /api/timeseries/stats

Eclipse Ditto

Port 8080 (Internal)Internal: Accessed via proxy

Digital Twin platform for IoT devices (internal service)

Communicates with:
  • Nginx Proxy (:8081) via HTTP (proxied)
  • Ditto internal persistence (:27017) via Database protocol
  • Mosquitto MQTT (:1883) via MQTT
Details:
  • Internal API: http://localhost:8080/api/2 (not directly accessible)
  • Access via: Nginx proxy on port 8081
  • Auth: devops:foobar (Basic Auth)
  • Namespace: org.massai
  • Services: gateway, connectivity, policies, things

PostgreSQL

Port 5432

Application database for assets, lines, Metrics, and time-series data

URL:http://localhost:8083 (pgAdmin)
Communicates with:
  • Backend API (:5432) via SQL (asyncpg)
  • MQTT Bridge (:5432) via SQL (psycopg2)
Details:
  • Version: PostgreSQL 16 Alpine
  • pgAdmin UI: http://localhost:8083
  • Database: massai
  • Tables: production_assets, production_lines, metrics, timeseries_data, planning_simulations
  • User: massai
  • Query: Standard SQL (queries PostgreSQL time-series tables)

Ditto Web UI

Port 8082

Web interface for managing Ditto Things and Policies

URL:http://localhost:8082
Communicates with:
  • Nginx Proxy (:8081) via HTTP/REST
Details:
  • UI: http://localhost:8082
  • Connect to API: http://localhost:8081/api/2
  • Auth: devops:foobar
  • Features: Things explorer, Policy editor, Connections

Nginx Proxy

Port 8081

Reverse proxy for Ditto API - REQUIRED ONLY for Ditto UI (not for your application)

URL:http://localhost:8081
Communicates with:
  • Ditto Gateway (internal) (:8080) via HTTP
  • Ditto UI (:8082) via HTTP
Details:
  • API Endpoint: http://localhost:8081/api/2
  • ⚠️ Why it exists: Ditto UI (running in browser) needs CORS to access Ditto
  • 🎯 Your app flow: Frontend → Backend (FastAPI) → Ditto (no Nginx needed)
  • 🖥️ Ditto UI flow: Ditto UI (browser) → Nginx (adds CORS) → Ditto
  • Ditto problem: Does NOT have CORS enabled by default
  • Nginx solution: Adds CORS headers (Access-Control-Allow-Origin, etc.)
  • Auth: Passes through Basic Auth to Ditto (devops:foobar)
  • Note: Your application Backend communicates directly with Ditto (server-to-server, no CORS needed)

Mosquitto MQTT Broker

Port 1883 (MQTT)9001 (WebSocket)

MQTT message broker for IoT communication

URL:mqtt://localhost:1883
Communicates with:
  • Ditto (:1883) via MQTT
  • MQTT Bridge (:1883) via MQTT
  • IoT Devices (:1883) via MQTT
Details:
  • Protocol: MQTT v3.1.1 & v5.0
  • WebSocket: ws://localhost:9001
  • Auth: Anonymous (dev mode)
  • Persistence: Enabled

MQTT-Ditto Bridge

Port 5001 (HTTP Sync)

REQUIRED to synchronize MQTT data with Digital Twins - Bridges real IoT world with the system

Communicates with:
  • Mosquitto (:1883) via MQTT (Subscribe)
  • Ditto (:8081) via HTTP/REST (Update)
  • PostgreSQL (:5432) via SQL (psycopg2)
  • Backend (:5001) via HTTP (Sync trigger)
Details:
  • ⚠️ Why it's needed: Ditto does NOT support MQTT directly as input
  • Problem without Bridge: IoT sensors publish to MQTT but Ditto only understands HTTP/REST
  • Solution: Bridge listens to MQTT and translates to Ditto REST API calls
  • Flow: MQTT Sensor → Mosquitto → Bridge → Ditto (updates Thing current state)
  • Historical persistence: Writes time-series data to PostgreSQL
  • Immediate sync: Backend calls /sync when assets are created (no 5-min wait)
  • HTTP Endpoint: POST http://mqtt-ditto-bridge:5001/sync
  • Auto-discovery: Reads assets from Backend and subscribes to topics dynamically

Ditto internal persistence

Port 27017

NoSQL database used ONLY by Eclipse Ditto for internal persistence

URL:internal Docker service
Communicates with:
  • Ditto (:27017) via Database protocol
Details:
  • Ditto Databases: things, policies, connectivity, search
  • Application data is stored in PostgreSQL; this service is only for Ditto internals
  • Auth: None (dev mode)
  • Persistence: Docker volume

Ditto Persistence UI

Port 8083

Web UI for inspecting Ditto internal persistence

URL:http://localhost:8083
Communicates with:
  • Ditto internal persistence (:27017) via Database protocol
Details:
  • UI: http://localhost:8083
  • Username: admin
  • Password: admin
  • View: All databases (ditto, maasai, system)
  • Features: Browse collections, edit documents, run queries

Keycloak (Optional)

Port 8180

Identity and Access Management

URL:http://localhost:8180
Communicates with:
  • Frontend (:3000) via OIDC/OAuth2
Details:
  • Realm: massai
  • Client: massai-frontend
  • Admin: http://localhost:8180/admin
  • Status: Optional (can be disabled)
📊 PostgreSQL Time-Series Schema
Data Model
Table: timeseries_data
Key Columns (Indexed):
thing_id
Ditto Thing ID (e.g., org.massai:conveyor_belt)
Example: org.massai:conveyor_belt
feature_id
Feature identifier (e.g., speed, temperature)
Example: speed
units
Measurement units (e.g., m/s, °C)
Example: m/s
Value Columns:
valuefloat
Numeric feature value
Example: 22.5
value_strstring
String representation (fallback)
Example: 22.5
Example SQL Queries

Get last 24h of data

SELECT timestamp, value, units
FROM timeseries_data
WHERE thing_id = 'org.massai:conveyor_belt'
  AND feature_id = 'speed'
  AND timestamp >= NOW() - INTERVAL '24 hours'
ORDER BY timestamp ASC;

Get statistics

SELECT
  COUNT(value), MIN(value), MAX(value), AVG(value)
FROM timeseries_data
WHERE thing_id = 'org.massai:conveyor_belt'
  AND feature_id = 'speed'
  AND timestamp >= NOW() - INTERVAL '24 hours';
Backend uses these queries in /api/timeseries/history and /api/timeseries/stats endpoints (backed by PostgreSQL)
🔄 Data Flow Scenarios
Asset Creation Flow
  1. 1. User creates asset in Frontend (port 3000)
  2. 2. Frontend → POST http://localhost:8000/api/assets
  3. 3. Backend receives request
  4. 4. Backend → POST http://localhost:8081/api/2/things
  5. 5. Nginx proxies to Ditto (internal port 8080)
  6. 6. Ditto persists Thing in its internal database
  7. 7. Response back through chain to Frontend
MQTT Feature Update Flow
  1. 1. IoT Device publishes to mqtt://localhost:1883/factory/machine/feature
  2. 2. Mosquitto receives and distributes message
  3. 3. MQTT Bridge subscribes and receives message
  4. 4. Bridge → PATCH http://localhost:8081/api/2/things/{id}/features/{feature}
  5. 5. Bridge → INSERT INTO timeseries_data (PostgreSQL)
  6. 6. Ditto updates Thing feature in its internal database
  7. 7. PostgreSQL stores time-series data point
  8. 8. Frontend can query updated feature history from PostgreSQL
Feature History Query Flow
  1. 1. User opens asset in View mode and clicks history chart
  2. 2. Frontend → GET http://localhost:8000/api/timeseries/history/{thing_id}/{feature_id}?hours=24
  3. 3. Backend queries PostgreSQL timeseries_data table
  4. 4. PostgreSQL returns time-series data points
  5. 5. Backend formats response with timestamps and values
  6. 6. Frontend receives historical data array
  7. 7. Chart.js renders interactive line chart with real data
Live Feature Value Update
  1. 1. User clicks Edit on asset card
  2. 2. Frontend → GET http://localhost:8000/api/assets/ditto/{asset_name}
  3. 3. Backend → GET http://localhost:8081/api/2/things/{thing_id}
  4. 4. Ditto retrieves current Thing state
  5. 5. Backend extracts feature values from Thing
  6. 6. Response with live values to Frontend
  7. 7. Dialog displays real-time feature values
🏗️ Network Architecture Layers

Network Architecture

1

Client Layer

Web Browser → localhost:3000 (Frontend)
2

Application Layer

Frontend (3000) ↔ Backend API (8000)
Backend (8000) ↔ Nginx Proxy (8081)
Backend (8000) ↔ PostgreSQL (5432)
3

Integration Layer

Nginx (8081) ↔ Ditto (8080 internal)
MQTT Bridge ↔ Mosquitto (1883)
MQTT Bridge ↔ Ditto (8081)
MQTT Bridge ↔ PostgreSQL (5432)
4

Data Layer

Ditto ↔ internal persistence (27017) - Thing state
PostgreSQL ↔ timeseries_data - Historical data
Mosquitto ↔ IoT Devices (1883)
⚙️ Environment Variables
Frontend (.env)
NEXT_PUBLIC_BACKEND_URL
http://localhost:8000
Backend API base URL
NEXT_PUBLIC_KEYCLOAK_URL
http://localhost:8180
Keycloak server (optional)
NEXT_PUBLIC_KEYCLOAK_REALM
massai
Keycloak realm
NEXT_PUBLIC_KEYCLOAK_CLIENT_ID
massai-frontend
Keycloak client
Backend (.env)
DITTO_URL
http://localhost:8081
Ditto API via Nginx proxy
DITTO_USERNAME
devops
Ditto basic auth user
DITTO_PASSWORD
foobar
Ditto basic auth password
DATABASE_URL
postgresql+asyncpg://massai:massai_dev@localhost:5432/massai
PostgreSQL connection string
MQTT_BROKER
localhost
Mosquitto broker host
MQTT_PORT
1883
MQTT broker port
MQTT Bridge (.env)
MQTT_BROKER
mosquitto
MQTT broker hostname (Docker)
MQTT_PORT
1883
MQTT broker port
DITTO_URL
http://ditto-nginx:80
Ditto API URL (Docker network)
BACKEND_URL
http://backend:8000
Backend API URL (Docker network)
DATABASE_URL
postgresql://massai:massai_dev@postgres:5432/massai
PostgreSQL connection (Docker)