System Architecture Overview¶
Bedrock is a tactical situational-awareness system: operators and devices share position, chat, drawings, and voice over a resilient mesh, with cryptographic identity and classification enforcement. It is 8 independent git repos (no umbrella monorepo).
The repos¶
| Repo | Language | Role |
|---|---|---|
directory |
TypeScript (AdonisJS) | Identity authority — FIDO2 login, signs IdentityToken/ServerToken, issues group keys, publishes the revocation list. The root of trust. |
common |
Rust (waypoint_common) |
Canonical shared crate — AuthEnvelope pack/verify, token protos, SIDC parser, outbox policy. The contract every client/server mirrors. |
server |
Rust (waypoint node) |
Zenoh transport router — relays + stores traffic, federates router↔router (mTLS), enforces the per-message classification gate. |
android |
Kotlin | Tactical client — engine + Zenoh transport + MapLibre map UI. |
web |
TypeScript (AdonisJS + Inertia) | COP / decision-support browser client — Zenoh-over-WSS, server-side recorder tier. Hosts the targeting board, detections, client-side track fusion (server-side fusion deferred), EW/control-measure authoring, planning (estimate/sync matrix/comms-net/versioning/replay export), and the /api/feed/* force-tracking ingest API. |
node |
Rust | Headless GPS / sensor daemon — peer-mesh publisher (position/heartbeat). |
gateway |
Rust | Interop bridge — translates to/from CoT/TAK, ADatP-3, NFFI, etc. |
infrastructure |
Terraform | GCE/KMS provisioning + PKI/TLS for deployments. |
Feed ingestion is handled by an additional component, bedrock-nifi-processors (Apache
NiFi), which is not one of the 8 core repos but produces feed data into web: it normalises
external AIS / ADS-B / GeoJSON feeds and writes them into the track_hits Postgres table via
the least-privilege nifi_ingest role, from where web fans them out to the COP.
How they fit¶
flowchart TB
DIR["<b>directory</b><br/>identity authority"]
COMMON["<b>common</b><br/>canonical contract<br/>(compiled by all)"]
subgraph clients [ ]
direction LR
AND["android"]
WEB["web"]
NODE["node<br/>(GPS daemon)"]
end
R1["<b>server</b><br/>router A"]
R2["<b>server</b><br/>router B"]
GW["gateway"]
EXT["CoT/TAK, ADatP-3,<br/>NFFI … (external)"]
NIFI["<b>NiFi</b><br/>(bedrock-nifi-<br/>processors)"]
FEEDS["AIS / ADS-B /<br/>GeoJSON feeds<br/>(external)"]
PROD["force-tracking<br/>producers (external)"]
DIR -->|"FIDO2 login, tokens,<br/>group key, revocations · HTTPS"| AND
DIR --> WEB
DIR --> NODE
AND <-->|"Zenoh TLS"| R1
WEB <-->|"Zenoh WSS"| R1
NODE <-->|"peer mesh"| R1
R1 <-->|"gossip / mTLS"| R2
R1 --> GW --> EXT
FEEDS -->|"AIS/ADS-B/GeoJSON"| NIFI
NIFI -->|"INSERT track_hits<br/>(nifi_ingest role)"| WEB
PROD -->|"/api/feed/* · JWT"| WEB
COMMON -.->|contract| AND
COMMON -.-> WEB
COMMON -.-> NODE
COMMON -.-> R1
COMMON -.-> R2
COMMON -.-> GW
End-to-end flow¶
- Login (HTTPS → Directory). Operator authenticates with a FIDO2 assertion (devices
use a single-use registration token). The Directory returns a 5×7-day
IdentityTokenbatch and the device's Ed25519 signing key (public half =principal_sign_keyin the token). Seesecurity/pki.md. - Connect (Zenoh). The client opens a server-cert-TLS Zenoh session to a router and
gets thewaypoint/global/auth/**queryable for the router'sServerToken(classification ceiling + coverage cells). Group keys come from/api/group-key. - Send. Each message content is sealed with AES-256-GCM under the deployment group
key (
SealedContent), wrapped in anAuthEnvelope— Ed25519device_signatureover signed-cleartextclassification+owner_principal_idfields plus the sealed payload — andputon a cell-routed key expression (waypoint/<cell>/<topic>/...). Heartbeats remain plaintext. Seeprotocol/wire-protocol.md. - Relay / store. The router verifies the envelope, reads the signed-cleartext
classificationenvelope field for the classification gate (min(sender, server)), stores durable prefixes (chat/drawings as opaque ciphertext), and fans out to subscribers + federated routers. The router never decodes the payload and holds no group key. Late joinersgetthe durable prefix to catch up. - Receive. Every receiver runs the full envelope verify + revocation gate before any
DB write or UI event. See
security/model.md. - Interop. The gateway subscribes to the mesh and translates to/from external
tactical formats. See
protocol/interop-standards/. - Feed ingestion (HTTP, into web). Two seams feed external tracks into the web COP:
external AIS / ADS-B / GeoJSON feeds flow through NiFi, which writes them into the
track_hitsPostgres table (least-privilegenifi_ingestrole); and external force-tracking producers post to/api/feed/*authenticated by a signed HS256 JWT (API credential). Web then fans the tracks out to operators and applies client-side track fusion (server-sidefused_tracksis deferred). Seeprotocol/ingest-api.md.
Where each concern is documented¶
- Identity / authenticity / revocation →
security/model.md - Trust roots, tokens, key issuance →
security/pki.md - Wire format, namespace, handshake →
protocol/wire-protocol.md - Store-and-forward outbox →
protocol/outbox.md - Interop / symbology standards →
protocol/interop-standards/ - Operator workflows (onboard, revoke, create server, rotate keys) →
training/ - Term definitions →
glossary.md
Note: identity is token-only — the Directory's Ed25519 signature over the token, with no per-app X.509 client certificate (see
pki.md). Member content is AES-256-GCM sealed under the deployment group key before it enters the envelope (server-blind E2E confidentiality); the router is payload-blind and group-key-free. This is live and uniform across all clients (android, web, node, gateway) — only heartbeats travel plaintext, and there is no plaintext-content fallback. Seesecurity/model.mdandarchitecture/status-roadmap.md.