Surveillance Module

CCTV integration, motion detection, clip recording, and evidence linking — server-side FFmpeg detection, browser overlay, and Nextcloud storage.

Last updated: 2025-02-18

Surveillance Module

The Surveillance module connects CCTV cameras to the evidence chain: live streams, motion-triggered clip recording, optional browser-based object detection, and automatic linking to WHMS events and the Time Machine.

Camera Grid Overview

The 2x3 surveillance grid provides at-a-glance monitoring of all warehouse cameras. Click any feed to expand and view detailed metadata.

certexi.com/app/surveillance/grid
Loading interactive demo...

6 camera feeds with recording status, motion detection indicators, and zone assignments.

Architecture

Loading diagram…

Design principles

  • Server-side first: Motion detection and clip extraction run in FFmpeg; the browser shows streams and controls.
  • Evidence-linked: Clips are uploaded to Nextcloud with metadata (camera, time, duration) and can be attached to WHMS placement events.
  • Optional browser detection: TensorFlow.js COCO-SSD runs in the browser for object boxes only; no frames leave the device.

Component inventory

All surveillance-related components and their roles.

Motion detection & control

ComponentPathDescription
MotionClipControl@/components/iot/motion-clip-controlStart/stop detection per camera, sensitivity, pre/post record
DetectionControlPanel@/components/iot/detection-control-panelMulti-camera detection toggles and settings
DetectionConfigPanel@/components/iot/detection-config-panelRules and taxonomy for detection
DetectionDashboard@/components/iot/detection-dashboardOverview of all cameras and motion state
DetectionToast@/components/iot/detection-toastIn-app toast when motion is detected

Streams & playback

ComponentPathDescription
CameraGrid@/components/iot/camera-gridGrid of live camera streams (HLS)
EnhancedStreamPlayer@/components/iot/enhanced-stream-playerSingle stream with controls and overlay
EnhancedMotionViewer@/components/iot/enhanced-motion-viewerStream + motion controls + optional TF overlay
StreamPreview@/components/iot/stream-previewSmall preview tile
CctvStreamField@/components/iot/cctv-stream-fieldTable/form field for selecting and showing a stream

Browser detection overlay

ComponentPathDescription
BrowserDetectionOverlay@/components/iot/browser-detection-overlayTensorFlow.js COCO-SSD overlay on video
DetectionOverlay@/components/iot/detection-overlayWrapper for detection overlay
BoundingBoxOverlay@/components/iot/bounding-box-overlayDraws bounding boxes and labels

Clips & recordings

ComponentPathDescription
ClipRecorder@/components/iot/clip-recorderRecords from stream to blob/clip
ClipExportDialog@/components/iot/clip-export-dialogExport clip to Nextcloud or download
SaveClipDialog@/components/iot/save-clip-dialogSave clip with metadata
RecordingsList@/components/iot/recordings-listList of saved clips with playback
SurveillanceTimeline@/components/iot/surveillance-timelineTimeline of motion events and clips

WHMS integration

ComponentPathDescription
ZoneCCTVTab@/components/whms/ZoneCCTVTabCCTV feeds for a WHMS zone
CCTVTab@/components/whms/CCTVTabCamera list and status in WHMS context
CCTVWidget@/components/workflow/widgets/CCTVWidgetWorkflow widget for camera stream
SurveillanceWidget@/components/dashboard/SurveillanceWidgetDashboard widget for surveillance

Configuration & modals

ComponentPathDescription
CameraQuickSettings@/components/iot/camera-quick-settingsQuick settings for a camera
CameraSettingsModal@/components/iot/camera-settings-modalFull camera configuration
IotCameraSelector@/components/iot/IotCameraSelectorPick a camera from list
EventViewer@/components/iot/event-viewerView detection events
EventDetailModal@/components/iot/event-detail-modalSingle event details and clip

Fields & deck

ComponentPathDescription
CCTVField@/components/fields/CCTVFieldField renderer for CCTV reference
IotEvidenceField@/components/fields/IotEvidenceFieldIoT evidence attachment
DeckIntegrationPanel@/components/iot/deck-integration-panelLink detection to Deck cards
SessionToRecordDialog@/components/iot/session-to-record-dialogAttach session to table record

UI patterns (sandboxes)

These sandboxes show the UI building blocks used in the surveillance UI. Real components use the same primitives plus video elements and API state.

Camera status card

Single camera in a grid or list: status badge, name, and actions.

Camera status card
<Card className="max-w-xs">
  <CardHeader className="pb-2 flex flex-row items-center justify-between">
    <CardTitle className="text-sm font-medium">Loading dock — Cam 3</CardTitle>
    <Badge variant="secondary">Live</Badge>
  </CardHeader>
  <CardContent className="space-y-3">
    <div className="aspect-video rounded-md bg-muted flex items-center justify-center text-xs text-muted-foreground">
      Stream preview
    </div>
    <div className="flex gap-2">
      <Button size="sm" variant="outline">Motion on</Button>
      <Button size="sm" variant="ghost">Settings</Button>
    </div>
  </CardContent>
</Card>

Motion control strip

Start/stop detection and sensitivity (mirrors MotionClipControl).

Motion control strip
<Card className="max-w-md">
  <CardHeader className="pb-2">
    <CardTitle className="text-base">Motion detection</CardTitle>
    <CardDescription>Camera 3 — Loading dock</CardDescription>
  </CardHeader>
  <CardContent className="space-y-4">
    <div className="flex items-center justify-between">
      <span className="text-sm">Status</span>
      <Badge variant="destructive">Recording</Badge>
    </div>
    <div className="flex gap-2">
      <Button size="sm">Stop</Button>
      <Button size="sm" variant="outline">Sensitivity</Button>
      <Button size="sm" variant="outline">Clip buffer</Button>
    </div>
    <Alert>
      <AlertTitle>Motion detected</AlertTitle>
      <AlertDescription>Last event 30s ago. Clip saved.</AlertDescription>
    </Alert>
  </CardContent>
</Card>

Clip list row

One row in the recordings list: thumbnail, time, duration, actions.

Clip list row
<div className="flex items-center gap-4 rounded-lg border p-3 max-w-lg">
  <div className="w-24 h-14 rounded bg-muted flex-shrink-0 flex items-center justify-center text-xs text-muted-foreground">
    Thumb
  </div>
  <div className="flex-1 min-w-0">
    <p className="text-sm font-medium">Cam 3 — Loading dock</p>
    <p className="text-xs text-muted-foreground">14:32:05 · 12s</p>
  </div>
  <div className="flex gap-1">
    <Button size="sm" variant="ghost">Play</Button>
    <Button size="sm" variant="ghost">Export</Button>
  </div>
</div>

Detection alert panel

In-app alert when motion is detected (DetectionToast style).

Motion alert panel
<Alert variant="default" className="max-w-md">
  <AlertTitle>Motion detected — Cam 2</AlertTitle>
  <AlertDescription>
    Staging area. Clip recorded and linked to evidence. Open to view.
  </AlertDescription>
  <div className="mt-2 flex gap-2">
    <Button size="sm">View clip</Button>
    <Button size="sm" variant="outline">Dismiss</Button>
  </div>
</Alert>

Camera grid placeholder

Grid of camera placeholders (real grid uses HLS players).

Camera grid (placeholders)
<div className="grid grid-cols-2 gap-2 max-w-md">
  <div className="aspect-video rounded-lg border bg-muted flex items-center justify-center text-xs text-muted-foreground">Cam 1</div>
  <div className="aspect-video rounded-lg border bg-muted flex items-center justify-center text-xs text-muted-foreground">Cam 2</div>
  <div className="aspect-video rounded-lg border bg-muted flex items-center justify-center text-xs text-muted-foreground">Cam 3</div>
  <div className="aspect-video rounded-lg border bg-muted flex items-center justify-center text-xs text-muted-foreground">Cam 4</div>
</div>

Surveillance dashboard strip

Summary strip: cameras online, motion active, recent clips (SurveillanceWidget style).

Surveillance summary strip
<div className="flex flex-wrap gap-4 rounded-lg border p-4 max-w-lg">
  <div>
    <p className="text-2xl font-semibold">4</p>
    <p className="text-xs text-muted-foreground">Cameras online</p>
  </div>
  <div>
    <p className="text-2xl font-semibold">2</p>
    <p className="text-xs text-muted-foreground">Motion active</p>
  </div>
  <div>
    <p className="text-2xl font-semibold">12</p>
    <p className="text-xs text-muted-foreground">Clips today</p>
  </div>
  <Button size="sm">Open surveillance</Button>
</div>

API summary

EndpointMethodDescription
/api/iot/cctvGETList cameras (filtered by ownership)
/api/iot/detection/motion-streamPOSTStart/stop motion detection, set options
/api/iot/detection/motion-stream?cctvId=NGETStatus and stats for camera N
/api/iot/detection-eventsGETList motion events with optional filters
/api/iot/buffer/[cctvId]/clipGETGet clip from buffer (by time range)

For full request/response shapes and webhooks, see REST API and Motion Detection.