Skip to content

System Architecture Overview

Bedrock is a tactical situational-awareness system: operators and devices share position, chat, drawings, and voice over a resilient routed data plane, 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) Content-blind Zenoh Relay + Storage — routes LIVE traffic under a closed ACL and validates retained ingest/replay under Directory authority.
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 — position/heartbeat publisher through one configured TLS/QUIC router.
gateway Rust Interop bridge — translates to/from CoT/TAK, ADatP-3, NFFI, etc.
infrastructure Ansible On-prem rack provisioning + PKI/TLS for deployments.

The PETRA 1.0 Server is a statically provisioned, content-blind Relay + Storage role. See the normative Zenoh and DDIL data-plane contract for its degraded topologies, opaque addressing, and recovery boundary, and the status roadmap for release evidence.

Expendable does not mean storage-free

The Manifesto's component table calls Server “stateless” as shorthand for having no Core authority or application source of truth. Its longer trust rule requires bounded durable store-and-forward. A Server may be rebuilt or replaced, but while running it persists authorized opaque values only within the offline horizon and remains content-blind, group-key-free, and unable to mint authority.

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 <-->|"configured Zenoh TLS/QUIC"| R1
    R1 <-->|"gossip / private-CA TLS"| 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

  1. Login (HTTPS → Directory). Operator authenticates with a FIDO2 assertion (devices use a single-use registration token). The Directory returns a 5×7-day IdentityToken batch and the device's Ed25519 signing key (public half = principal_sign_key in the token). See security/pki.md.
  2. Connect (Zenoh). The client opens a configured TLS or QUIC Zenoh session, obtains the endpoint-local Directory-signed ServerToken from the closed router-token control family, and binds that token to the selected endpoint before any application publish, subscription, or retained query. The token carries the router identity, classification ceiling, coverage cells, and replay-receipt public key. Group keys come from /api/group-key and are never delivered by a router.
  3. Send. Each message content is sealed with AES-256-GCM under the deployment group key (SealedContent), wrapped in an AuthEnvelope — Ed25519 device_signature over signed-cleartext classification + owner_principal_id fields plus the sealed payload — and put on a cell-routed key expression (waypoint/<cell>/<topic>/...). Heartbeats remain plaintext. See protocol/wire-protocol.md.
  4. Relay / store. The router applies the required default-deny peer/action/key policy and verifies the generic publication or query authorization. It reads only signed-cleartext metadata needed for the classification and storage gates, durably buffers eligible opaque ciphertext within the offline horizon, and fans it out to subscribers and federated routers. It never decodes application payloads, holds a group key, or interprets ORBAT, membership, ownership, drawing, target, plan, or report semantics.
  5. Receive. Every receiver runs the full envelope verify + revocation gate before any DB write or UI event. See security/model.md.
  6. Interop. The gateway subscribes to the mesh and translates to/from external tactical formats. See protocol/interop-standards/.
  7. 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_hits Postgres table (least-privilege nifi_ingest role); 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-side fused_tracks is deferred). See protocol/ingest-api.md.

Where each concern is documented

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. See security/model.md and architecture/status-roadmap.md.