Under the hood

Self-hosted, private, yours.

A Rust backend, two databases and one license check. Your DORA compliance data never leaves your infrastructure — no SaaS, no vendor lock-in.

What's in the box

A small, boring, dependable stack. Nothing exotic to operate.

Backend — Rust / Actix-web 4

Serves the UI, exposes the REST API, handles auth and RBAC, and talks to both databases. Fast, memory-safe and single-binary.

MySQL — business data

Transactional store for providers, contracts, assessments, incidents, exit plans, users and the full register. The system of record.

ClickHouse — analytics

High-volume analytics and activity logging. Powers the advanced reporting dashboards and the recent-activity feed.

Docker + Compose

The whole platform ships as containers, orchestrated by a single Docker Compose file. One command to a running instance.

CI/CD — GitHub Actions

Builds and publishes images to GHCR (GitHub Container Registry). You pull versioned, reproducible images — no building required.

Versioned migrations

A versioned SQL migration system (V1 → V15) runs automatically on startup. Every write surfaces SQL errors to the UI — no silent false “success”.

The whole picture, on one host

Your browser and API clients reach the Rust app; the app owns both databases; one hourly call goes out.

Browser (UI) REST API client
Your infrastructure · one Docker host
app — Rust / Actix-web
UI · REST API · auth · RBAC
MySQL
business data
ClickHouse
analytics / activity
 mlab.sh — hourly license HMAC
the only outbound call · 48h grace window

One command, minimal box

A single docker compose up brings up the app and both databases. Migrations run automatically on startup — there is no separate install step.

2 GB RAM 10 GB disk Any Linux / VPS Auto-migrations on boot
docker-compose.yml
services: app: image: ghcr.io/mlab-sh/tprm:latest ports: ["8080:8080"] environment: DATABASE_URL: mysql://tprm@mysql/tprm CLICKHOUSE_URL: http://clickhouse:8123 LICENSE_KEY: ${TPRM_LICENSE_KEY} depends_on: [mysql, clickhouse] mysql: image: mysql:8 # business data clickhouse: image: clickhouse/clickhouse-server # analytics $ docker compose up -d migrations V1..V15 applied · listening :8080

Your compliance data stays put

DORA is about resilience. Sending your third-party register to someone else's SaaS would undermine the point.

Never leaves your infra

Providers, contracts, assessments, incidents and the register live entirely in your own MySQL and ClickHouse. We never see them.

One outbound call

The only thing that leaves the box is an hourly license-validation HMAC to mlab.sh — no telemetry, no usage analytics, no data exfiltration.

48-hour grace

If the license server is unreachable, the instance keeps working for a 48-hour grace period before locking — transient outages don't stop you.

No lock-in

No SaaS, no proprietary datastore. It's your databases, your containers and your standard CSV / xBRL-CSV exports. Walk away any time.

RBAC, 12-bit permissions

A role-based access control system built on a 12-bit permission set. Grant exactly what each role needs — nothing more.

  • Admin — super-user, implicit full access
  • Email verified — confirmed email account
  • Manage team — invite/remove users, manage roles
  • Manage providers — CRUD third-party providers
  • Manage assessments — CRUD risk assessments
  • Manage contracts — CRUD contracts
  • Manage exit strategies — CRUD exit plans
  • Manage incidents — CRUD third-party incidents
  • View risk dashboard — concentration analysis
  • View analytics — advanced reporting
  • Manage settings — organisation configuration
  • Manage register/compliance — DORA register, functions, due diligence, audits, Art. 30, entity, scope, branches, intra-group, definitions, EBA export

Sessions, tokens & headers

Secure sessions

HTTP-only, secure session cookies. Email/password login with code verification and token-based password reset.

API token auth

API keys (mlab_ prefix) sent as Authorization: token <api_key>. GET-only on Free, full CRUD on Licensed.

Security headers

HSTS, X-Frame-Options DENY, X-Content-Type-Options, a strict Referrer-Policy and Permissions-Policy on every response.

Everything relates back to the provider

A connected model — not a pile of spreadsheets. The provider is the hub; contracts, assessments, incidents and exit plans hang off it, and business functions map across.

contracts providers assessments
incidents exit plans functions ↔ providers

All typed register fields use DORA 4.0 controlled vocabularies: eba_CT, eba_TA, eba_qCO, eba_GA, eba_CU, eba_ZZ, eba_CO, eba_BT, eba_RP.

Run it on your own box, today.

One docker compose up. 2 GB RAM. Your data, your infrastructure.