Server Federation
Connect independent GroundWave servers to share data over WAN.
9 min readOverview
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
- Server A's admin generates an inbound key in the Federation tab and securely shares the plaintext with Server B's admin.
- Server B's admin adds Server A as a peer, entering its URL and the shared key as the outbound credential.
- 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:
origin_server_idfield — every federated record carries the UUID of the server where it originated. When an inbound handler receives an event, it checks whetherorigin_server_idmatches the local server UUID. If it does, the event is dropped.- 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. - UID deduplication — each event carries a unique identifier stored in the
federation_eventstable. 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.