# NDC Mission Core local telemetry plane Portable local-only telemetry infrastructure for compute contours. One Docker Compose project, `ndc-mission-core-telemetry`, owns three long-running containers and one bounded bootstrap job: - `ndc-mission-core-mqtt-broker` — Eclipse Mosquitto `2.1.2-alpine`; - `ndc-mission-core-telemetry-timescaledb` — TimescaleDB HA OSS `pg16.14-ts2.28.2-all-oss`; - `ndc-mission-core-telemetry-bootstrap` — one-shot database role/bootstrap job; - `ndc-mission-core-telemetry-normalizer` — Mission Core telemetry normalizer. The Telegraf configuration templates cover Windows and Linux, but the agent runs as a host service rather than inside this Compose project. This preserves access to native Windows performance counters, Docker Desktop and NVIDIA telemetry. The normalizer exposes a read-only normalized telemetry adapter on `127.0.0.1:18030`. Mission Core reads this adapter; the browser never receives MQTT or Timescale credentials, and Timescale is not published on a host port. The normalizer uses a separate `missioncore_normalizer` database role with only `SELECT`, `INSERT`, `UPDATE`, and bounded retention `DELETE` on the telemetry hypertable. Raw telemetry older than 30 days is removed at most once per day by the normalizer. This stays compatible with the Apache-licensed Timescale image without depending on the Timescale License retention scheduler. The stack is one deployment contour, not one multi-process container. Keeping broker, normalizer and database in separate containers preserves independent health checks, least-privilege boundaries and rollback while Compose provides one operator lifecycle: ```bash docker compose ps docker compose up -d docker compose down ``` All NODE.DC-owned Docker objects use the lowercase `ndc-` namespace. Docker names are case-sensitive identifiers, so the product prefix is normalized to lowercase while the product name remains NODE.DC in operator-facing copy. This directory does not contain credentials. Copy `.env.example` to `.env`, generate unique passwords and build the ACL/password files before starting the stack. ```bash uv run python prepare.py --initialize --mqtt-bind-address docker compose up -d --build ``` Expected Docker object names: ```text project: ndc-mission-core-telemetry network: ndc-mission-core-telemetry containers: ndc-mission-core-mqtt-broker ndc-mission-core-telemetry-normalizer ndc-mission-core-telemetry-timescaledb volumes: ndc-mission-core-mqtt-data ndc-mission-core-telemetry-timescale-data ``` `prepare.py` passes passwords to `mosquitto_passwd` through stdin. Secrets are not placed in process arguments or committed files. `--initialize` generates `.env` with mode `0600` and refuses to replace existing credentials. The generated `.env` and `runtime/` directory are ignored by Git. The product architecture and topic contract are defined in `docs/adr/0031-local-compute-contour-telemetry-plane.md`. ## Security boundary The current MQTT listener is authenticated and contour-scoped, but intentionally uses plaintext MQTT inside one owner-controlled laboratory LAN. Do not expose port 1883 through a router, cellular WAN, public Wi-Fi, or an Internet-facing host. A remote or shared-network deployment requires a reviewed TLS listener, a private CA distributed to every agent, and credential rotation. Wi-Fi link encryption is not a replacement for MQTT TLS. Each agent credential is bound to one exact `contours//agents//+` prefix. Adding another contour requires issuing another password entry and explicit ACL row; the wildcard contour writer is not permitted. ## Worker agent Worker 006 uses the official Windows Telegraf distribution as the host service `NDC Mission Core Telemetry Agent`. Install or update it with: ```powershell .\telegraf\Install-NdcMissionCoreTelegraf.ps1 .\telegraf\Update-NdcMissionCoreTelegraf.ps1 ``` The update path validates the candidate configuration, backs up the active configuration and rolls back if the service does not return to `Running`. MQTT credentials are scoped to the service environment and must not be passed on a command line or stored in the repository. The stack and agent are intentionally not started by repository tests. Provisioning a machine is a separate, explicit operation.