Server Federation

Connect independent GroundWave servers to share data over WAN.

9 min read

Overview

Federation allows two or more independent GroundWave servers to exchange operational data in real time when they can reach each other over a WAN link — for example, when separate field teams each operate a local GroundWave server but have satellite, cellular, or radio-backed IP connectivity between sites.

Federation is an opt-in feature. It is disabled by default and must be explicitly included in the FEATURES_ENABLED environment variable. Adding federation to that list activates the feature at both the REST API and Socket.IO layers and makes the Federation tab visible in the Admin Dashboard.

Critically, federation runs in-process inside the existing groundwave-app container. No additional container, service, or port is required. The federation subsystem consists of three cooperating components: an outbound Socket.IO client that connects to remote servers, an inbound handler that authenticates arriving peers and injects their data, and a lifecycle manager that coordinates all connections and routes events through an internal event bus.

Federation requires a stable WAN connection between peers. GroundWave's core situational awareness features — maps, position tracking, chat, markers — continue working locally on each server whether or not the federation link is up.

Trust Model

Federation uses a pre-shared API key model. No central certificate authority or PKI infrastructure is needed — two servers trust each other because an administrator on each side has manually exchanged a secret key.

Keys must be at least 32 characters long. The system generates 48-character base64-encoded keys by default, providing approximately 288 bits of entropy. Keys are stored as argon2id hashes in the database — the plaintext key is only visible at the time of generation and is never stored in recoverable form.

Key Exchange Process

  1. Server A's admin generates an inbound key in the Federation tab and securely shares the plaintext with Server B's admin.
  2. Server B's admin adds Server A as a peer, entering its URL and the shared key as the outbound credential.
  3. When Server B connects outbound to Server A, it presents the key. Server A hashes it and compares against the stored inbound key hash. On match, the connection is authenticated and data sharing begins.

All federation connections must use TLS (wss://). Plaintext WebSocket federation is rejected to prevent API key exposure over untrusted network paths.

Data Types

Each peer relationship has independent inbound and outbound data type filters, configured per peer in the Admin Dashboard. This lets you share positions with all peers while restricting chat or markers to specific trusted servers.

Data Type What is shared
Positions Real-time GPS position reports from connected users, including callsign, coordinates, speed, heading, accuracy, and battery level. Position updates are relayed as they arrive — no historical track data is sent on connection establishment.
Markers Map features (points, lines, polygons) including geometry, marker type, name, category, color, label, and creator callsign. Create, update, and delete operations are all propagated. Photo attachments are not transferred across federation links.
Chat Messages from public channels only. Direct messages and private group channels are never federated. The sender's callsign and server identity are preserved in the message attribution.

Server Identity

Each GroundWave server has a persistent UUID stored in the server_config table. This UUID is generated once on first run and never changes. It serves as the authoritative identifier for that server in all federation protocol messages — it is used in echo prevention, conflict resolution, and event deduplication regardless of whether the server's URL or name changes.

A human-readable name is assigned via the SERVER_NAME environment variable (default: GroundWave). This name is used to prefix federated user callsigns so that operators on any server can tell where a user originates:

ServerName::Callsign

For example, if the remote server is named Alpha and a user there has the callsign WOLF-1, they appear as Alpha::WOLF-1 on all other federated servers. Choose a short, memorable SERVER_NAME for clarity in the field.

Connection Architecture

Federation uses Socket.IO WebSocket connections as the wire transport, reusing the same library already deployed for client-server communication. The federation subsystem establishes separate Socket.IO connections on a dedicated namespace (/federation) so that federation traffic is isolated from client traffic.

Outbound Client

For each configured peer with status active, the lifecycle manager spawns a Socket.IO client that connects to the remote server's federation namespace. The client authenticates by presenting the pre-shared API key in the handshake. On successful authentication, the outbound client begins forwarding locally-generated events that match the peer's outbound data type filter.

Connections include automatic reconnection with exponential backoff. A peer that temporarily loses WAN connectivity resumes data sharing automatically when the link is restored, without administrator intervention.

Inbound Handler

The inbound handler listens on the /federation namespace for incoming peer connections. On connection, it validates the presented API key against all stored inbound key hashes. Connections with invalid or missing keys are immediately rejected.

Authenticated inbound data is written to the local PostgreSQL database with origin_server_id set to the remote server's UUID, then broadcast to locally connected clients via the main Socket.IO namespace. This makes remote data appear live on local maps and panels without any client-side awareness of the federation layer.

Conflict Resolution

When the same marker is edited on two different servers before their changes sync, a conflict occurs. GroundWave uses a Last-Write-Wins (LWW) strategy: the record with the highest updated_at timestamp takes precedence. This is simple, deterministic, and appropriate for the relatively low update frequency of field operational data.

Echo Prevention

Without echo prevention, a data item could loop endlessly between servers: Server A sends it to Server B, Server B rebroadcasts it back to Server A, and so on. GroundWave uses three independent layers to prevent this:

  1. origin_server_id field — every federated record carries the UUID of the server where it originated. When an inbound handler receives an event, it checks whether origin_server_id matches the local server UUID. If it does, the event is dropped.
  2. Source tag — the outbound client tags all events it emits with a source: "federation" marker. The inbound handler on the receiving side uses this tag to distinguish federated events from client-originated events and prevent double-counting.
  3. UID deduplication — each event carries a unique identifier stored in the federation_events table. The inbound handler rejects any event whose UID it has already processed, covering edge cases where two servers have a mutual peer relationship and both route the same event.

Admin Management

Federation is configured entirely through the Admin Dashboard's Federation tab. No manual configuration file editing or container restarts are required to add, modify, or remove peers.

The Federation tab provides:

  • Peer management — add a new outbound peer by entering its URL, display name, API key, and data type filters. Pause or resume individual peers without removing them. Remove peers to permanently terminate the connection and delete the stored key hash.
  • Inbound key management — generate new inbound API keys to share with remote servers. Revoke keys to immediately refuse future connections from any peer using that key.
  • Real-time connection status — each peer shows its current connection state (connected, connecting, paused, error) updated live via Socket.IO.
  • Audit event log — a timestamped log of federation events: connections established, data received, authentication failures, and key revocations. Useful for diagnosing WAN link issues.

All federation endpoints are admin-only. Operators and observers cannot view or modify federation configuration.

Federated User Display

Federated users — those whose position data arrived via a federation link rather than a direct local connection — are visually distinguished from local users in both the map view and the User Roster panel:

  • Map markers use an orange color instead of the standard blue, making remote users immediately identifiable at a glance.
  • A "Fed" badge is displayed next to the user entry in the Roster panel, along with the originating server name.
  • The callsign is shown in its full prefixed form (ServerName::Callsign) in all panels, tooltips, and chat attribution.

Federated users do not appear in the local user count or connected-clients tally in the System Status admin panel, as they are not consuming a local WebSocket connection.