Architecture, no magic.
Four containers, two databases, one license check. That's the whole stack.
What's in the box
Every service mlab IR runs, and what it does. Tap a row to expand.
app
Rust + Actix-web. Serves the UI, exposes the REST API, handles auth and RBAC, talks to both databases.
Stateless — restart any time. Healthcheck on /healthz.
executor
Background worker. Runs scheduled jobs: license challenges, observable enrichment, SLA timers, webhook delivery with retries, report generation. Writes analytics to ClickHouse.
MySQL 8
Transactional store: alerts, cases, observables, users, attachments metadata, audit log. Migrations auto-run on app boot.
ClickHouse
Analytics store: high-volume timeline events, metrics rollups, search indices. Optimised for dashboards and queue filters.
License check — mlab.sh
The only outbound call. Once per hour, the executor sends a signed HMAC challenge to
mlab.sh/api/v1/ir/license/validate. Result is cached locally with a 48h grace window.
No telemetry, no usage analytics, no error reporting to a SaaS.
Request to resolution
- Upstream system POSTs to
app:/api/v1/alerts. appvalidates, normalizes, writes to MySQL, emits a timeline event to ClickHouse.- Analyst loads the queue —
appreads MySQL (state) + ClickHouse (filters). - Escalation creates a case, attaches observables, fires webhooks via
executor. - On resolution,
executorgenerates the report and stores it on the uploads volume.
Topology
Single host: all four containers via Docker Compose. Suitable up to several hundred analysts.
Scaled out: MySQL and ClickHouse on dedicated hosts; app and executor stay stateless and scale horizontally behind a reverse proxy.
No Kubernetes operator, no Helm chart maintained as a separate product. If you run K8s you convert the compose file — the service contract is plain.