# @leumas/surveillance-node — Surveillance edge node (data plane)

Leumas Surveillance edge node — the data plane. Runs the SAME camera-manager media/detector/recorder pipelines near the cameras, pulls its assigned cameras from a control plane over HTTP, and...


Runs the Leumas camera-manager pipelines **near the cameras** and publishes only detection **events** to
a control plane (the Leumas API) — never raw video. This is the horizontal-scale half of the
control/data-plane split: each node handles its local cameras; the control plane holds the registry,
rules, metering, and event index.

It is **not a fork** — it imports the identical `@leumas/adapter-surveillance` pipeline services
(`streams`/`media`/`detector`/`recorder`, which are connector-free) and orchestrates them against
cameras it pulls over HTTP. The API's own in-process sidecars are the "built-in node" for a single-box /
EXE install, so small deployments need no separate node at all.

## Run

```bash
SURVEILLANCE_CONTROL_PLANE_URL=https://studio.example.com \
SURVEILLANCE_NODE_TOKEN=<shared node token> \
SURVEILLANCE_INGEST_TOKEN=<shared ingest token> \
SURVEILLANCE_NODE_TENANT=<tenant slug> \
SURVEILLANCE_NODE_ID=lobby-box-1 \
node bin/leumas-surveillance-node.js
```

Assign cameras to a node by setting each camera's `nodeId` to the node's `SURVEILLANCE_NODE_ID`
(cameras with no `nodeId` stay on the control-plane built-in node). The node:

1. **registers** (`POST /api/surveillance/node/register`),
2. **pulls** its assigned cameras (`GET /api/surveillance/node/cameras`),
3. runs `ensureStreams` + `ensureDetections` + `reconcileRecording` locally (the local sidecar posts
   detections to the control plane's `/ingest`), and
4. **heartbeats** (`POST /api/surveillance/node/heartbeat`) — all on a periodic reconcile loop.

## Deploy

Ship it self-contained with `pnpm deploy --filter @leumas/surveillance-node <dir>` (same discipline as
the API EXE). It needs `ffmpeg` + `mediamtx` + the Python detection extras on the box to actually run
detection; without them it registers, pulls, and heartbeats (wiring stays verifiable), and detection is
a clean no-op.

## Auth

Phase 4 uses a shared `SURVEILLANCE_NODE_TOKEN` (loopback-only if unset) — fine for a single-tenant
appliance. Phase 5 upgrades node auth to signed, revocable **per-fleet licenses** (`@leumas/licensing`)
for safe multi-tenant cloud, without changing these routes or this client.


---
Source: shared/services/surveillance-node/README.md
Canonical: https://docs.leumas.tech/p/services/surveillance-node
