5.3 KiB
5.3 KiB
MQTT contract
The MQTT topic schema is the inter-process contract of the platform. All publishers and subscribers must respect this schema. Versioned in packages/proto-mqtt/ of the future code repo as JSON Schema files.
See ADR-0003 for why MQTT is the spine.
Naming conventions
- Lowercase, slash-separated.
- Site prefix only when bridged to hub:
sites/<site_id>/.... - Local topics (within a site) don't include the site prefix.
- Underscore prefix (
_registry,_cmd,_bridge) marks system-level topics, distinct from device topics. +is single-level wildcard,#is multi-level (MQTT standard).
Topic catalog
Device events
hai/<cam_id>/events/<event_type>
event_type∈person | car | truck | motorcycle | bicycle | animal | package | license-plate | custom.- Payload (JSON):
{ "id": "evt-8a2f", "label": "person", "conf": 0.92, "zone": "entrance", "ts": "2026-05-09T19:34:22.142Z", "ts_nts": "2026-05-09T19:34:22.142Z", "sha_clip": "a1f7...", "sha_keyframe": "b2c8..." } - QoS: 1.
- Retained: no.
- Bridged: yes, with prefix
sites/<site_id>/.
Device state
hai/<cam_id>/state/<key>
key∈online | fps | npu_pct | last_keepalive | error.- Retained: yes.
- Bridged: yes (status info needed at hub).
Snapshots
hai/<cam_id>/snapshots/<n>
- Binary JPEG, ~50-100KB.
- Retained: yes (last frame).
- Never bridged (sovereignty rule, see ADR-0005).
Telemetry (raw)
hai/<cam_id>/telemetry/<key>
key∈fps | bitrate | latency | drops.- High-frequency, low-value individually.
- Retained: no.
- Never bridged raw — aggregated and republished by
healthd.
Service registry
hai/_registry/announce
- Published by Cell containers and other discoverable services.
- Payload:
{ "type": "frigate | enricher | re-id | healthd | hai-console", "id": "cell-01", "host": "192.168.20.10", "port": 5000, "caps": ["frigate", "reid"], "version": "0.4.2", "started_at": "2026-04-25T14:18:00Z" } - Retained: yes.
- Bridged: yes (hub needs to know what's deployed where).
hai/_registry/heartbeat/<id>
- Published every 30s by each registered service.
- Retained: no.
- Bridged: no (hub uses bridge state for liveness).
Health reports
hai/healthd/health
- Aggregated selftest result, published every 5min.
- Payload: structured object with results per test.
- Retained: yes.
- Bridged: yes (hub needs health for fleet view).
Bridge status
hai/_bridge/status
- Published by router to indicate bridge health.
- Payload:
{ "connected": true, "queue": 0, "rtt_ms": 38, "last_disconnect": "..." }. - Retained: yes.
- Special: this topic is published locally by the router about its own bridge state. Operators see it in the MQTT panel.
Commands (incoming from hub)
_cmd/<command>
- Published by the hub, consumed by router or Cell services.
- Payload includes
requested_by,ts,correlation_id. - Bridged inbound: yes, with hub-side topic
sites/<site_id>/_cmd/<command>mapped to local_cmd/<command>.
Configuration changes (incoming from hub)
_config/<resource>
- Used by hub to push GitOps-equivalent config updates.
- In practice, GitOps does most of this; this topic is reserved for low-latency overrides.
- Retained: yes.
- Bridged inbound: yes.
Evidence chain (post-MVP, see ADR-0007)
hai/_evidence/manifest
- Published whenever a clip is finalized with its signed manifest.
- Bridged: yes (hub keeps a second copy for hash-chain verification).
QoS guidelines
- QoS 0: telemetry, snapshots, frequent low-value data.
- QoS 1: events, state, registry, health, commands. Default for anything that should not be lost.
- QoS 2: not used. Cost not justified for our use cases.
ACL guidelines
- Cell containers can
pub/subonlyhai/<their_id>/...andhai/_registry/announce. - Router can
pub/subeverything locally. - Bridge writes only to remapped namespaces, can't pub locally.
- Operator console (read-only) can subscribe to
hai/#but not publish. - Future: per-operator ACLs based on Keycloak roles.
Bridge policy (sovereignty matrix)
What goes UP (site → hub):
hai/+/events/# → sites/<site_id>/hai/+/events/# QoS 1
hai/+/state/# → sites/<site_id>/hai/+/state/# QoS 1, retained
hai/_registry/announce → sites/<site_id>/_registry/announce QoS 1, retained
hai/+/health → sites/<site_id>/health/+ QoS 0
hai/_bridge/status → sites/<site_id>/_bridge/status QoS 1, retained
hai/_evidence/manifest → sites/<site_id>/_evidence/manifest QoS 1
What goes DOWN (hub → site):
sites/<site_id>/_cmd/# → _cmd/# QoS 1
sites/<site_id>/_config/# → _config/# QoS 1, retained
What is never bridged:
hai/+/snapshots/# (binary JPEGs, sovereignty)
hai/+/telemetry/# (raw, aggregated only)
$SYS/# (broker internals)
This policy lives in /etc/mosquitto/conf.d/bridge.conf on the router, version-controlled in the site-config repo. The MQTT panel in the console renders it from the live config.