Skip to main content

PLATFORM · SCALE & PERFORMANCE

Built to stay fast when the deployment gets large.

Sentinel is engineered for scale from the data model up: a distributed multi-agent architecture, covering indexes that answer the heaviest queries in a single scan, and bounded queries that keep the console responsive as event counts climb into the millions.

Cameras management page at scale — 1,000+ cameras organised in a materialised-path group tree with online/offline status badges, search, sort, and pagination controlsClick to enlarge

Thousands of cameras · Millions of events · Sub-50 ms core queries at 1.2 M events (tested) · Distributed multi-agent

1.2 M
Events tested
cctv_event rows on the benchmark dataset
< 50 ms
Core queries
persons · watchlist · Command Center · heatmap (tested)
5,000
Cameras
designed and paginated for a single deployment
100+
Agents
distributed processing nodes, one console
BUILT FOR SCALE

One console over thousands of cameras and millions of events.

The same console runs a single entrance camera or a five-thousand-camera estate without a different code path — designed and tested for the full range, with search, sort, and pagination on every surface.

  • Designed and tested for 1 to 5,000 cameras per deployment — no UI degradation
  • Event data in purpose-built tables engineered for tens of millions of rows — never bolted onto backup tables
  • Distributed by design — processing pushed to edge agents; the console never pulls raw video to do its job
  • No unbounded surfaces — every list has search, sort, and pagination throughout
  • The same product at every size — no enterprise-edition fork
Camera group tree expanded several levels deep showing Site, Building, Floor, Corridor hierarchy with camera counts per node and a scoped-permission badgeClick to enlarge

Five thousand cameras is unusable as a flat list — the tree makes it navigable.

DISTRIBUTED PROCESSING

One dashboard. 100+ agents. Work pushed to the edge.

Each agent pulls and decodes video locally, runs the AI close to the cameras, and reports compact events to the console — adding capacity is as simple as adding an agent, coordinated by lightweight version-string heartbeats.

  • 100+ agents per console — each handles a subnet; events, alerts, and status aggregated in real time
  • Edge processing — video decoded and analysed where the cameras are, eliminating cross-network video traffic
  • Lightweight heartbeats — version strings and queued commands only; no full config payloads on every tick
  • Zero-downtime scaling — add or remove agents without affecting the rest of the deployment
  • FOR UPDATE SKIP LOCKED worker queue — multiple workers share load with no Redis or etcd dependency
Agent fleet view showing multiple agents with per-agent camera counts and health status, total rolled up at the topClick to enlarge

One console coordinates the whole fleet; raw video never needs to cross the network.

BENCHMARKED PERFORMANCE

Measured at 1.2 M events, not promised.

On a benchmark dataset of 1.2 million event rows and a million audit-log rows — the kind of history a busy estate accumulates — the queries an operator hits most stay under 50 milliseconds. Every one of these surfaces has a specific index or query pattern engineered to make it fast at that scale.

Persons query (tested)< 50 ms — at 1.2 M events on the benchmark dataset
Watchlist query (tested)< 50 ms — at 1.2 M events
Command Center (tested)< 50 ms — at 1.2 M events
Heatmap aggregation (tested)< 50 ms — single covering-index scan at 1.2 M events
Audit dashboard (tested)< 100 ms — raw SQL + covering indexes at 1 M audit rows
Persons list + enrichment (tested)< 200 ms — 1,000 persons with full enrichment
Last measured2026-03-19, benchmark dataset (tested results / design targets, not customer counts)

THE ENGINEERING BEHIND IT

Fast is a property you build in, on purpose.

Covering indexes

The heaviest queries are answered from the index alone, no row fetch. Composite covering indexes on the event table handle per-camera timelines, global recent events, type-filtered queries, watchlist feeds, and the live ticker.

pgvector IVFFlat for face kNN

Face search runs against a 512-dimension embedding store with an IVFFlat cosine index — sub-second nearest-neighbour lookups across hundreds of thousands of faces, powering search, watchlist, and auto-clustering.

Anchor caps on heavy joins

The co-occurrence self-join is bounded to a subject's most recent 2,000 events inside a sub-query, so its cost is fixed regardless of lifetime activity. The multi-tenant guard is enforced inside the join.

Parallel top-N + roll-up queries

The location distribution runs two queries in parallel: a top-N camera bucket list and a single-row roll-up for the totals, with the long tail sized arithmetically instead of materialising every camera.

Soft-fail per enrichment

Each non-essential sub-query is wrapped in its own try/catch. If pgvector is briefly unreachable, the MySQL counts still return. A partial outage degrades one field, never the whole page.

Bounded everywhere

take/limit on every query, batch lookups instead of N+1, no COUNT(*) over 100K+ rows, and parameterised IN lists so a batch sparkline for 200 entities is one round-trip, not 200.

HOW IT WORKS

From camera to query result, kept fast at every hop.

1

Process at the edge

Agents close to the cameras decode video and run the full AI vision pipeline locally. What travels to the console is a compact event, not a video stream — so network cost scales with events, not pixels.

2

Write to purpose-built tables

Events land in dedicated tables engineered for tens of millions of rows — deliberately separate from file-backup tables. Face embeddings go to pgvector; everything else to MySQL.

3

Index for the questions operators actually ask

Each heavy read has an index or query pattern built for it: composite covering indexes, an IVFFlat cosine index for face kNN, and daily roll-up tables for audit counters so no widget ever runs a full-table scan.

4

Answer with bounded, defensive queries

Every list paginates; every join is capped; heavy reporting uses raw parameterised SQL to hit a covering index cleanly. Each enrichment soft-fails independently so one slow dependency degrades a single field, not the page.

5

Serve the console from a warm cluster

The dashboard runs as a multi-instance cluster with reload-not-restart deploys, so traffic spreads across workers and a deploy never drops requests.

SPECIFICATIONS

Full technical specifications

Cameras (designed / paginated for)1 to 5,000 per deployment
Agents100+ distributed processing nodes per console
Events tested1.2 M cctv_event rows + 1 M cctv_audit_log rows — benchmark dataset
Event storeMySQL — purpose-built tables (cctv_event, cctv_video, …), separate from file-backup tables
Event indexingComposite covering indexes: (cameraId, startTime), (organizationId, startTime), (organizationId, eventType, startTime), watchlist + live-ticker indexes, and a dedicated heatmap covering index
Face embedding storePostgreSQL pgvector — 512-dimension ArcFace embeddings
Face kNN indexIVFFlat with cosine distance — sub-second nearest-neighbour over hundreds of thousands of embeddings
Heavy-join strategyAnchor caps (recent-N sub-query), tenant guard inside join, SELECT DISTINCT de-dup
Reporting-query strategyParallel top-N + single-row roll-up via Promise.all; arithmetic long-tail sizing
Resilience patternSoft-fail per enrichment — own try/catch → null on failure, WARN-logged, page still renders
PaginationEvery list endpoint; take/limit on every query; default 50, max 200
HeartbeatVersion strings + queued commands only; agent refetches config on version change; 10–30 s cadence
Worker coordinationFOR UPDATE SKIP LOCKED queue — no Redis/etcd dependency
Front-end resilienceAbortController cancels stale in-flight requests on prop change / unmount
Storage tiersHot (instant) · Cold (6-mo min, 3–5 h restore) · Deep Freeze (12-mo min, 12–48 h restore)
Camera organisationMaterialised-path group tree, unlimited depth, sub-tree resolvable in one query
Console runtimeMulti-instance cluster (4 Next.js instances), reload-not-restart deploys
Deployment targetsCloud, on-premise, or air-gapped — identical platform at every scale

All benchmark numbers describe tested results and design targets on a benchmark dataset (last measured 2026-03-19) — not customer counts. You can reproduce them on live data in a demo.

See the numbers on live data.

Request demo access and we’ll send you a private, pre-loaded environment running against a large dataset. Open a person profile, run a face search, pull a heatmap, and watch the response times yourself.