CADENCE — Deployment (Docker / Compose)

Status: DRAFTED, partially verified. The container runtime model is verified; the Docker build/run itself is not (this CI has no Docker daemon). Read "Verification status" below before relying on these artifacts.

TL;DR

cd products/cadence
docker compose up --build          # → http://localhost:3000  (self-contained demo dashboard)

The Feed Builder CLI ships in the same image:

docker run --rm --entrypoint feed-builder cadence-client lint --feed /app/feed-sample

What’s in the image

A multi-stage build (Dockerfile):

  • build stage (rust:1-slim-bookworm) — cargo build --release -p cadence-client -p feed-builder. No system -dev packages are needed: rustls (no OpenSSL), bundled libsqlite3, bundled webpki roots.

  • runtime stage (debian:bookworm-slim) — the two binaries, the feed-sample/ + examples/ demo assets, ca-certificates (TLS roots for SMTP delivery) and curl (only for the healthcheck).

Key env baked in (override at run time — see .env.example for everything):

Var Image default Why

CADENCE_BIND

0.0.0.0:3000

listen on all interfaces inside the container

CADENCE_DEMO_FEED_DIR

/app/feed-sample

demo assets live here, not the (absent) build tree

CADENCE_DEMO_INVENTORY

/app/examples/inventory.yaml

"

CADENCE_STATE_DB

/data/cadence-state.db

reminder + notify + audit state on the volume

CADENCE_FEED_CACHE

/data/feed-cache

the air-gap feed mirror on the volume

/data is a named volume (cadence-state) so the audit trail, notify-on-change baseline, and feed mirror survive restarts — set the state DB in production (an in-memory restart re-sends every active alert once).

Going live (real feed)

Demo mode is the default. For a real deployment, provide live config (compose environment: or an env_file):

  • CADENCE_FEED_URL + CADENCE_FEED_PUBKEY (the one trusted signing key),

  • an inventory source — CADENCE_ADAPTER=proxmox|netbox|nextcloud|apt (+ its config) or a mounted CADENCE_INVENTORY=<file>,

  • usually CADENCE_REFRESH_INTERVAL=6h (run as a daemon, notify only on change),

  • CADENCE_BASIC_AUTH=user:pass (the dashboard and /decisions.json carry customer data),

  • a notify channel: CADENCE_NOTIFY_WEBHOOK_URL and/or CADENCE_SMTP_*.

The feed signature — not TLS — is the trust anchor, so the image can pull from an internal HTTP mirror safely.

Verification status (honest)

  • Runtime model verified (no Docker needed). The release cadence-client binary, run from a clean directory containing only the copied feed-sample/ + examples/ and container-style env (CADENCE_BIND, CADENCE_DEMO_*, CADENCE_STATE_DB on a separate dir), served /, /healthz, and /decisions.json (all HTTP 200) and wrote cadence-state.db to the "volume" dir. This is the part most likely to break in a container (binary + assets + paths), and it works.

  • ⚠️ docker build / docker compose up NOT run here (no Docker daemon in CI). The unproven layer is base-image specifics: that rust:1-slim-bookworm builds the workspace and that debian:bookworm-slim + ca-certificates satisfies rustls/lettre at runtime. Verify in a Docker-capable env before relying on it. If the build pins the wrong toolchain, bump the FROM.

  • 🔭 Hardening options (later): distroless runtime (drop curl/shell — move the healthcheck to the orchestrator), a non-root USER, and read-only rootfs with only /data writable.