Eleven services, explicit responsibilities
Docker packages each service independently. Typed messages carry camera, stream, and sequence identity through the live pipeline.
What each stage does
A container can be inspected or updated independently. Isolation separates responsibilities, but services on the same device still share CPU, memory, disk, and network capacity.
| Service | Input → output |
|---|---|
| Camera | Camera source → original frames; handles opening and reconnecting. |
| Inference | Frames → detections and annotated frames; model can serve multiple cameras. |
| Tracking | Detections, plus frames when required → detections with stable track IDs. |
| Enrichment | Tracked/untracked detections → events with geometry and camera context. |
| Rules | Enriched events → accepted events and notification alerts. |
| Row builder | Events, alerts, and monitor health → structured database rows. |
| Buffer | Rows → durable pending records and status; provides ingest claim/ack operations. |
| Ingest | Claimed buffer records → HTTP backend delivery and acknowledgements. |
| Notifier | Alerts → configured log, webhook, or SMTP delivery attempts. |
| Monitor | Freshness of health snapshots → device health metadata. |
| Collector | Original frames + matching detections → clean JPEGs and YOLO labels. |
Local connections and remote endpoints
Live services communicate using ZeroMQ TCP endpoints. Inside Compose, receivers use service DNS names and container ports. Published host ports are a separate mapping and default to localhost.
Annotated frames are not a browser stream
Inference can publish annotated frame messages. They are not RTSP or WebRTC, and a browser cannot consume raw ZeroMQ directly. A separate streaming gateway is planned; the detection feed widget currently displays structured detection data.