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 check
the only outbound call · 7 days offline

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.

RAM 2 GB
Disk 10 GB
Host
Any Linux / VPS
Migrations
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 check to mlab.sh (license key, instance id, version). No telemetry, no usage analytics, no data exfiltration.
7 days offline
mlab.sh returns a signed license that the instance verifies itself and keeps: if mlab.sh is unreachable it keeps working for 7 days before locking, so 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.

Record Relates to
  contracts↔ providers
  assessments↔ providers
  incidents↔ providers
  exit plans↔ providers
  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.

$ docker composeup -d
apprunning
mysqlbusiness data
clickhouseanalytics
migrationsV1..V15 applied
licensevalid
listening:8080