Projects

Work I'm proud of

A selection of what I build — where industrial control meets modern software.

In-house SaaS product · live demo

OnboardForge

OnboardForge is a multi-tenant SaaS platform for personal, role-based onboarding and knowledge management. Instead of one generic handbook, the platform assembles a journey per employee automatically: a content-assembly engine combines reusable modules based on segments (role, department, team, location), so generic and role-specific information sit side by side — without duplication.

Content is type-driven: documents with PDF and image attachments, visual workflows (flowcharts), checkable checklists, contact cards, videos and links. A journey runs on a month·week·day schedule; employees tick off steps, give a version-bound 'read and understood' sign-off and take knowledge checks. HR and managers see progress live.

OnboardForge is a sellable product by Haan Software Solutions: each client is its own tenant with its own accounts, roles and branding (accent colour, brand name), and the entire interface is bilingual (NL/EN). Under the hood it shares EdgeForge's proven architecture — FastAPI with a role-based permission model and an append-only audit trail. The public demo logs you in automatically as an employee and resets every hour.

Multi-tenant SaaSRBACAudittrailPythonFastAPISQLiteJWTReactTypeScriptViteTanStack QueryZustandReact FlowDockerCloudflareRaspberry Pi 5

View the live demo

01

The challenge

New employees often get one thick, generic onboarding document in which most of it doesn't apply to their role. At the same time an organisation needs to prove that — and which version — someone has read; hard with loose PDFs and emails.

02

The approach

One engine that assembles a personal, phased journey per profile from reusable, published modules — with personalisation variables in the text. Sign-offs are recorded version-bound; if the content changes, the platform automatically asks for a fresh sign-off.

03

The result

Demonstrable, personal onboarding that scales across multiple clients: every employee sees exactly what's relevant to them, HR keeps control through reporting and a complete audit trail, and the same platform serves every tenant with its own branding and language.

Under the hood

Technical highlights

  • Content-assembly engine: segment targeting (role/department/team/location) automatically composes a personal, phased journey — generic and role-specific without duplication
  • Type-driven, version-bound content (JSON): documents with attachments, visual flowcharts (React Flow), checklists, contact cards, video and links, each with its own authoring and rendering
  • Compliance audit trail: append-only sign-offs with timestamp and IP; on republication the platform automatically requests a fresh sign-off
  • Per-module knowledge checks with a pass threshold; questions go to the browser without the correct answers and the server grades them — a step is only done once both the sign-off and the quiz are passed
  • Interactive checklists and month·week·day scheduling, derived from a per-step offset instead of fixed phases
  • Multi-tenant with role-based permissions (platform admin > org admin/HR > manager > employee) and a rank rule: you only manage roles strictly below your own
  • Per-tenant branding (accent colour and brand name, applied live) and a fully bilingual interface (NL/EN), down to bilingual modules, quizzes and journey names
  • Secure file uploads (PDF and images) with a MIME allowlist; the SPA fetches files as an authenticated blob and shows them inline
  • Architecture modelled on EdgeForge: FastAPI + SQLite with numbered migrations and a repository pattern (ready for Postgres), React + TanStack Query + Zustand
  • Deployment as a single Docker image (Node build → Python serves the API and SPA) on a Raspberry Pi, exposed via a Cloudflare Tunnel, with automatic deploys

In-house platform · live demo

TwinForge

A digital twin of an industrial process, entirely in the browser. TwinForge simulates a batch mixing/heating tank with real control: two PID loops (level and temperature), a batch sequence with interlocks and a SCADA-style operator interface. Move the setpoints, start the batch and inject faults — and watch the control system react live.

TwinForge is the missing link in the Forge family: where EdgeForge collects data and InsightForge analyses it, TwinForge shows the control side — exactly where my industrial background (PLC, control engineering, HMI/SCADA) meets modern software. The same tags the simulator produces are also published over a built-in OPC UA server, ready to be ingested by EdgeForge. The whole chain becomes visible: simulate → collect → analyse.

The server runs a fixed-scan control loop (like a PLC) and streams the process values to the browser over a WebSocket. It runs as a separate FastAPI backend with a React frontend — hosted 24/7 on a Raspberry Pi 5 with Docker and a Cloudflare Tunnel.

PID-regelingBatchsequentieOPC UAPythonFastAPIWebSocketReactTypeScriptViteZustandEChartsDockerCloudflareRaspberry Pi 5

View the live demo

01

The challenge

Control and regulation are hard to show: normally you need a machine, a PLC and an HMI. For a client or in a portfolio, that side therefore stays invisible.

02

The approach

Rebuild both the process and the control in software: a fixed-scan control loop with PID loops and a batch state machine, operated through a live SCADA interface in the browser — with the process values exposed over OPC UA.

03

The result

Anyone can play with a real control system — shift setpoints, run a batch, inject faults — and watch the chain flow on to EdgeForge and InsightForge. Control, data collection and analysis in one story.

Under the hood

Technical highlights

  • Fixed-scan control loop (10 Hz) like a PLC, with two PID controllers (level and temperature) including clamping and anti-windup
  • Batch sequence as a state machine (fill → heat → mix → drain) with interlocks, combining analog and discrete control in one model
  • Physics simulation of level and temperature (flow balance and heat balance), stable at the scan interval
  • Inject faults (sensor stuck, valve jammed, pump tripped, heater fault) with an immediately visible effect and alarming
  • Live SCADA HMI: animated tank mimic (SVG), dual-axis trend chart (ECharts) and controls with setpoints and auto/manual mode
  • Real-time over WebSocket: the server pushes process snapshots, the browser reconnects automatically on outage
  • Built-in OPC UA server (asyncua) publishing the same tags — the bridge to EdgeForge, so the Forge chain works end to end
  • Demo-friendly: controls are rate-limited against abuse and the simulation resets itself automatically when idle
  • Extensible via a process registry: a new process is one self-registering module; engine, OPC UA and frontend stay generic
  • Bilingual interface (NL/EN) and deployment without a public IP: FastAPI backend in Docker on a Raspberry Pi 5, exposed via a Cloudflare Tunnel

In-house platform · live demo

EdgeForge

An industrial edge data platform that collects real-time data from a wide range of machines and protocols, stores it in a time-series database and shows it in live dashboards — with crash-safe storage so no measurement data is lost during network or server outages.

Designed and built entirely from scratch: from the protocol drivers and storage pipeline to the web interface with dashboards, data viewer, alarming, user management and backups. A single Docker command and the whole platform runs — on an industrial PC, a server or in the cloud.

Operators and engineers work together in a single web interface: live dashboards with real-time tiles, an interactive data viewer to analyse history, node analytics with statistics and limit violations, and a system monitor that watches the entire data flow — from machine to database — in real time.

Reliability comes first: every connection recovers automatically after an outage, measurements are buffered locally until the time-series database is reachable again, and role-based access separates viewing from configuring. Backups of both configuration and measurement data run on a schedule, so an installation can keep running unattended for a long time.

OPC UAEtherNet/IPSiemens S7-1500Modbus TCPMQTTREST APIInfluxDBSQLitePythonReactEChartsDockernginx

View the live demo

01

The challenge

Industrial data is scattered across machines, each speaking its own protocol. A single, reliable overview is often missing — and no measurement data may be lost during outages.

02

The approach

Read multiple protocols simultaneously with persistent connections and automatic reconnect; write each value to InfluxDB at its own interval; buffer locally during outages.

03

The result

No measurement data is lost during outages anymore. Operators see everything in live dashboards with alarming — one overview instead of separate machines — analyse and export history, and run the whole platform with a single Docker command.

Under the hood

Technical highlights

  • Multi-protocol acquisition (OPC UA, EtherNet/IP, S7-1500, Modbus TCP, MQTT, REST) with per-server reconnect backoff
  • Crash-safe store-and-forward — SQLite buffer absorbs writes during InfluxDB outages and flushes automatically
  • Live dashboards with real-time tiles and a full-screen data viewer (ECharts): line/area/bar/scatter/histogram/heatmap, multiple axes, limit lines and annotations
  • Node analytics: statistics (average, min/max, standard deviation, trend), limit violations, time-of-day breakdown and node comparison — with CSV/Excel/JSON export
  • Alarm engine with high/low limits, deadband and lifecycle (triggered → acknowledged → cleared), including notification channels and rules
  • Hierarchical organisation into locations and groups, plus reusable machine templates for fast rollout
  • Authentication & RBAC: viewer/engineer/admin roles, JWT, bcrypt, audit log
  • Security: CSP headers, rate limiting, and PLC credentials encrypted at rest (Fernet + PBKDF2)
  • Backup & restore of both configuration and time-series data, with scheduled daily backups
  • Full deployment with Docker Compose (platform + nginx + InfluxDB) and a deploy wizard for on-site installation

In-house platform · live demo

SignalForge

An ML layer on top of the OT data EdgeForge collects: robust anomaly detection, forecasting and one explainable asset-health score per asset. SignalForge is the closing piece of the chain — simulate (TwinForge) → collect (EdgeForge) → analyse (SignalForge).

Under the hood an ensemble of detectors runs on detrended residuals, complemented by heavy models (STL residual, CUSUM, multivariate Isolation Forest) that only run on a periodic refit. On top of that: correlation and lead-lag analysis for root cause, and forecasting with a time-to-threshold. Everything rolls up into one understandable health score (0–100) with a per-factor explanation.

The demo runs live on the real EdgeForge data (InfluxDB), with a curated scenario showcase alongside so there's always something to see. The analysis is purely statistical; an optional, off-by-default AI layer can explain an anomaly or health score in plain language.

Runs as a separate FastAPI backend with a React frontend — hosted 24/7 on a Raspberry Pi 5 with Docker and a Cloudflare Tunnel, alongside EdgeForge and TwinForge on the same machine.

Anomaly detectionForecastingHolt-WintersSTLCUSUMIsolation ForestCorrelationnumpypandasscipyscikit-learnstatsmodelsFastAPIWebSocketReactEChartsInfluxDBDockerCloudflareRaspberry Pi 5

View the live demo

01

The challenge

Raw OT data is rarely truly analysed. Creeping drift, unusual signal combinations and approaching limit crossings stay invisible until there's a fault or downtime.

02

The approach

An ML layer on top of EdgeForge: cheap detectors every cycle, heavy models on the refit, correlation/lead-lag and forecasting — rolled up into one explainable health score instead of a pile of separate charts.

03

The result

Per asset one understandable score (0–100) with an explanation, a live anomaly feed, forecasting with a time-to-threshold and root-cause hints — running on the real EdgeForge data, with curated scenarios alongside.

Under the hood

Technical highlights

  • Three cheap detectors (robust z-score/MAD, EWMA control chart, IQR/Hampel) on detrended residuals, with an ensemble merge so the same event isn't double-counted
  • Three heavy detectors (STL residual, CUSUM change-point, multivariate Isolation Forest) that only run on the periodic refit — keeping the hot loop light on the Pi
  • Explainable asset-health score (0–100) from five weighted factors (anomaly rate, baseline deviation, trend, limit proximity, signal coupling), each with an NL/EN explanation and history
  • Forecasting (Holt-Winters with a linear-trend fallback) with a confidence band and time-to-threshold: when a signal is projected to cross its alarm limit
  • Correlation & root cause: a Pearson heatmap plus lead-lag cross-correlation ("X leads Y by N s"); coupling drift feeds the signal-coupling factor of the health score
  • A refresh worker pulls each window → detects → scores → broadcasts a compact snapshot over WebSocket; on-demand endpoints (forecast/correlation) are cached and never run in the hot loop
  • Data-source adapter with three backends behind one interface (InfluxDB-direct, EdgeForge REST, synthetic with planted anomalies) with graceful fallback; a live overlay shows a curated scenario showcase alongside the real assets
  • Curated fault scenarios (spike, drift, ramp-to-limit, seasonal break, correlation break) with auto-rotation and idle revert, keeping the demo lively 24/7
  • Optional, off-by-default AI explanation layer (a small Claude model) that explains an anomaly or health score in NL/EN — the public demo stays purely statistical
  • Bilingual (NL/EN), light/dark and in the house style; FastAPI + React/Vite/TypeScript in Docker on a Raspberry Pi 5, exposed via a Cloudflare Tunnel

In-house platform · live demo

InsightForge

Ask your data a question in plain language and get an answer plus the right chart back. InsightForge is an AI layer on top of time-series and tabular data — no query language required. A language model of your choice — Claude or an open model (Qwen, DeepSeek, Llama) — translates your question into a safe, read-only query through tool use, runs it against the selected data source and picks fitting charts to go with it.

InsightForge belongs to the Forge family alongside EdgeForge: the same industrial domain knowledge, now aimed at unlocking data. You pick the data source in the demo itself — from demo data (DuckDB/CSV) and SQLite to industrial time-series in InfluxDB (1.x, 2.x and 3) — and the AI first explores the source's structure on its own before writing the query. Beyond the question box, InsightForge also produces a daily AI summary per source: in the demo you generate it on demand, self-hosted it runs on a timer. The next step open-sources the core. The end goal: an open-core product that lets SMEs get insight from their own data without any data skills.

Everything stays transparent: the demo shows live which query the model writes, streams the answer word by word and renders the charts in the house style. It runs as a separate FastAPI backend with a React frontend — hosted 24/7 on a Raspberry Pi 5 with Docker and a Cloudflare Tunnel, auto-updating itself from the repository.

Claude APIOpenRouterTool useFastAPIDuckDBSQLiteInfluxDBReactTypeScriptViteTanStack QueryEChartsDockerCloudflareRaspberry Pi 5

View the live demo

01

The challenge

Valuable data sits in databases and CSVs, but the insights are locked behind query languages and dashboards you have to build first. Non-technical users can't get to them.

02

The approach

A language model as a safe intermediate layer: it translates a plain-language question into a read-only, parameterized query (via tool use — no free-form SQL in text), runs it, and proposes fitting charts to go with it.

03

The result

Anyone can ask their data a question and immediately get a substantiated answer with a chart — bilingual (NL/EN), with the executed query visible for anyone who wants to check.

Under the hood

Technical highlights

  • Question → query via tool use: read-only, parameterized queries (no free-form SQL) with a read-only validator per data source and query language
  • Streaming experience: live progress (translate → run → chart → write) and the answer word by word via Server-Sent Events
  • Automatic chart selection: the model proposes one or more charts (line/area/bar/scatter/pie/heatmap, dual axes and combinations), rendered with ECharts
  • Multiple data sources with an in-UI source picker: DuckDB (CSV/Parquet), SQLite and InfluxDB in three flavors — 2.x (Flux), 1.x (InfluxQL) and 3 (SQL); a new source is one adapter + registry entry
  • Self-discovering AI: the model gets an auto-built catalog of the source and may explore read-only first before writing the final query — how the database is structured no longer matters
  • Daily AI summary per source (“Daily insight” card): a short summary of the notable recent changes with a chart — generated on demand in the demo (metered on the same free quota), on a daily timer when self-hosted
  • Conversation with context: a follow-up question is answered with the previous question-and-answer turns in context, so you can drill down on an earlier result
  • Export: every result downloads as CSV and every chart as a PNG image
  • Bilingual interface (NL/EN) and answers in the language of the question
  • In-UI model choice: Claude (Haiku, Sonnet, Opus) or cheap open models (Qwen3-Coder, DeepSeek, Llama 4) via OpenRouter — the tool-use loop is provider-agnostic
  • Bring-your-own-key: a shared free quota in credits, weighted by model price (per IP + daily cap), or paste your own Anthropic or OpenRouter key — it stays in the browser and goes straight to the provider
  • Transparent: the executed queries and the raw data are always visible next to the answer
  • Deployment without a public IP: FastAPI backend in Docker on a Raspberry Pi 5 (24/7, low-power), exposed via a Cloudflare Tunnel and auto-updated from the repository; frontend as a Cloudflare Worker (static assets)
  • Test suite and CI: pytest and vitest cover the validator, rate limiter, tool-use loop and chart builder; GitHub Actions runs all checks on every push
  • Open-core on the roadmap: an open-source core (MIT) and a paid hosted/Pro tier

Custom application

PlannerTool

A complete planning and capacity tool for an engineering department, replacing an ageing Excel/Access system. Engineers, tasks and projects come together in a single overview that automatically calculates the available hours per person per week — taking leave, public holidays and internal work into account.

Designed and built entirely from scratch: a Python backend with a React frontend, bundled into a single Windows installer. Multiple PCs collaborate in real time on one shared database — without a central server or IT administration. Planning is visual: drag-and-drop scheduling, task dependencies, critical-path analysis and ready-made reports.

PythonFastAPISQLAlchemyAlembicSQLiteReactTypeScriptViteAnt DesignChart.jsPlaywrightPyInstallerNSIS
01

The challenge

Planning for an engineering department lived in fragile Excel and Access files: error-prone, hard to share and with no real insight into who actually has capacity left.

02

The approach

A single application that calculates capacity per engineer automatically and lets you plan tasks visually, with dependencies and templates — built as a modern web interface, but bundled as an ordinary desktop app on a shared database.

03

The result

The whole team plans in real time in the same overview, immediately sees over- and under-capacity, and pulls out reports, PDFs and Excel exports on demand — without a central server or IT administration.

Under the hood

Technical highlights

  • Capacity-weighted hour distribution: task hours are spread across the weeks in proportion to net availability, so leave weeks are skipped automatically
  • Interactive planning grid: drag to reschedule, resize duration with live load preview, and multi-select for bulk actions
  • Task dependencies (FS/SS/FF/SF) with automatic propagation and critical-path analysis (CPM)
  • Reusable project templates: roll out entire sequences of tasks with dependencies onto a project in one go
  • Reports and analytics with interactive charts (capacity, reliability, KPIs) and snapshots to compare plans over time
  • Shared SQLite database (WAL) on a network drive: multiple concurrent users, with retry logic against lock conflicts
  • Export to PDF (server-side rendered with Playwright) and Excel (openpyxl), preserving formatting and colour coding
  • Type-safe end to end: Pydantic schemas in the backend mirrored by TypeScript types in the frontend
  • One-click distribution: the whole app (Python runtime, server and web interface) bundled into a single Windows installer with PyInstaller and NSIS — installable without admin rights
  • Database migrations run automatically on startup, so all users always share the same schema

Need something similar?

From control to dashboard — in one pair of hands.

A machine that needs reading out, data that needs to come together somewhere, or a custom application? Let's look at the best approach.

Book a free intro call