R2-D2
Dashboard
Node Red
Restreaming
The Force
UpdatedNever
v1.0.0

Overview

Loading…
R2-D2
Dashboard
Node Red
Restreaming
The Force
UpdatedNever
v1.0.0
DDroidspeak / Docs
Operator handbook
Droidspeak
What is R2-D2?
Runtime architectureAuth — Keycloak migration plan
FleetRestreamingGalaxy MapThe RepublicTemple ArchivesSTANAG 4817The Force
Tech StackNext.js 15 + React 19Tailwind v4ZustandTanStack Table + DataViewhls.jsLow-latency playerreagraphoglreact-grid-layoutMonacoScalar API Referencefumadocs
Cluster InfraTrailBaseReductStoreRestreamer (datarhei/core)TBMQKeycloakLonghornkube-vipIngress (Caddy + nginx-ingress + Traefik)Netbird
Operator QA Runbook
Install — RKE2Install — Dokploy
Contributor guideRelease Notes
Cluster Infra

ReductStore

Dedicated time-series blob store for snapshot history and audit binaries.

ReductStore is a time-series blob database. The dashboard uses it for snapshot history — the JPEG-per-feed-per-N-seconds archive that backs the snapshot scrub on every video tile.

It runs as a dedicated cluster (commit 95521d3f separated it from the shared store) so heavy snapshot reads can't starve other dashboard data.

Where it sits

In-cluster URL(set via REDUCTSTORE_URL env on the dashboard)
Chart / valuesr2d2-fleet/k8s/reductstore-snapshots/ in the parent repo
Bucket layoutone bucket per feed, time-indexed
Retention(configured per bucket — typically days, not months)

Reads / writes from the dashboard

DirectionRoute handlerWhat flows
Write/api/restreaming/snapshots (POST)JPEG blob + feed ID + timestamp
Read latest/api/restreaming/snapshots/latest?feedId=…The most recent JPEG for poster fallback
Read range/api/restreaming/snapshots/history?feedId=…&from=…&to=…A list of timestamps + thumbnails for the scrub
Read one/api/restreaming/snapshots/at?feedId=…&ts=…The single JPEG at a timestamp

The TypeScript wrapper lives in src/lib/reductstore.ts.

Why a separate store (and not TrailBase)

  • Blob size. Snapshots are JPEGs in the 50–500KB range; SQLite is the wrong tool for that volume.
  • Time-indexed reads. Snapshot history is "give me everything between T1 and T2" — ReductStore is built for this; SQLite needs a range query + blob join per row.
  • Retention. ReductStore's bucket-level retention drops old blobs automatically; in SQLite we'd build that ourselves.
  • Workload isolation. A long history scrub shouldn't block panel CRUD. Two clusters, two failure domains.

Snapshot capture flow

flowchart LR
  T[Tile mounted, page visible] --> P[Periodic capture trigger]
  P --> F[Fetch from Restreamer snapshot endpoint]
  F --> R[POST /api/restreaming/snapshots]
  R --> RD[ReductStore bucket write]
  T -.->|tile re-render with snapshot| RD

Capture is triggered by the dashboard itself on focus / interval — there's no separate cron. This means an inactive dashboard doesn't accumulate snapshots; if you need guaranteed-rate capture, that's a future change.

Audit binaries

A planned use case beyond snapshots — large audit payloads (full before/after of a panel mutation, request bodies of bulk imports) that we don't want bloating the TrailBase audit table. Not yet wired.

What ReductStore is not used for

  • Structured metadata. That's TrailBase.
  • HLS segments. Restreamer serves HLS directly; we don't archive segments.
  • Logs. Logs go to stdout / cluster log pipeline, not here.

See also

  • Restreaming — primary consumer
  • TrailBase — sibling store for structured data
  • hls.js — snapshots as poster fallback

TrailBase

SQLite-as-API — the dashboard's application data store for everything that isn't a YAML config.

Restreamer (datarhei/core)

The FFmpeg process supervisor that owns live RTSP/RTMP → HLS/RTMP transcoding.

On this page

Where it sitsReads / writes from the dashboardWhy a separate store (and not TrailBase)Snapshot capture flowAudit binariesWhat ReductStore is not used forSee also