Problem Statement / Feature Objective
Field teams operating in remote areas with no cellular connectivity cannot sync their collected meter data and inspection reports back to the central server. A WebRTC-based peer-to-peer mesh network must enable direct device-to-device synchronization without any infrastructure. Devices discover each other via mDNS (local network) or Bluetooth LE (proximity), negotiate a WebRTC connection using a relay signaling server when available (fallback to manual QR code exchange), and sync pending outbox entries using a CRDT-based merge strategy to resolve concurrent edits. The mesh must support up to 50 devices in a single session.
Technical Invariants & Bounds
- Mesh topology: fully connected peer-to-peer (each peer connects to all others). For 50 peers, this is 1,225 connections. Use an upper limit of 20 direct connections; beyond that, route through relay peers (spanning tree).
- Signaling: WebSocket signaling server at wss://signal.utilityprotocol.com. Fallback: manual QR code encoding the SDP offer/answer (max 4 KB per exchange).
- Sync payload: each peer's outbox contains SyncEntry { id, resourceType, action, data, timestamp, peerId, vectorClock }. Entries are batched: max 500 KB per sync message.
- CRDT merge: each peer maintains a Lamport vector clock. Conflicting edits to the same resource are resolved by last-writer-wins (by timestamp) with peerId tiebreaker.
- Data channels: single SCTP data channel per peer connection, ordered and reliable. Channel label: "utility-sync". Max message size: 256 KB (split larger payloads).
- Connection lifecycle: automatic reconnection with exponential backoff up to 30 seconds. If a peer disconnects, its entries remain in the outbox; they are re-sent on reconnection.
Codebase Navigation Guide
- src/services/webrtc/SyncPeer.ts - Represents a single peer connection: manages RTCPeerConnection lifecycle, data channel, and message framing.
- src/services/webrtc/SyncMesh.ts - Mesh manager: tracks connected peers, handles peer discovery, maintains spanning tree for relay.
- src/services/webrtc/SignalingClient.ts - WebSocket-based signaling client for exchanging SDP offers/answers and ICE candidates.
- src/services/webrtc/QRDiscovery.ts - QR code generation/scanning for manual SDP exchange fallback (uses qrcode and jsQR libraries).
- src/hooks/useOfflineSync.ts - React hook providing sync status: connected peers, pending outbox count, last sync timestamp.
- src/store/slices/syncSlice.ts - Redux slice tracking sync state: peer list, outbox queue, vector clock for each peer.
- src/utils/vectorClock.ts - Lamport vector clock implementation for CRDT conflict resolution.
Implementation Blueprint
- Implement VectorClock in src/utils/vectorClock.ts: Map<peerId, number>. Methods: tick(peerId), merge(other), compare(other) returns Before | After | Concurrent.
- Build SyncPeer class: constructor(peerId, config) creates RTCPeerConnection with STUN/TURN servers. createDataChannel('utility-sync', { ordered: true }). On message, parse SyncEntry batch, apply CRDT merge via vector clock, dispatch SYNC_ENTRY_RECEIVED action.
- SyncMesh class manages a Map<peerId, SyncPeer>. Methods: join(peerId, sdp?), broadcast(entries), leave(peerId). For mesh with > 20 peers, compute a spanning tree (minimum spanning tree based on latency estimates) and route entries through the tree.
- SignalingClient connects to wss://signal.utilityprotocol.com, sends { type: 'join', roomId, peerId }, receives peer joined/left events and SDP offers. On receiving offer, create a new SyncPeer and setRemoteDescription.
- QRDiscovery fallback: generate a QR code with the local SDP offer as a data URL, display on screen. Scanning mode uses getUserMedia + jsQR to read another device's QR, extract SDP, and complete the handshake.
- useOfflineSync hook orchestrates: initialize SyncMesh, connect to signaling (or start QR discovery), subscribe to syncSlice for UI state. Exposes { peers, outboxCount, sync(entries), status }.
- syncSlice stores: peers (array of { id, connected, latency, lastSync }), outbox (SyncEntry[]), vectorClocks (Record<peerId, Record<peerId, number>>). On SYNC_ENTRY_RECEIVED, merge into the local resource state via the CRDT logic.
Problem Statement / Feature Objective
Field teams operating in remote areas with no cellular connectivity cannot sync their collected meter data and inspection reports back to the central server. A WebRTC-based peer-to-peer mesh network must enable direct device-to-device synchronization without any infrastructure. Devices discover each other via mDNS (local network) or Bluetooth LE (proximity), negotiate a WebRTC connection using a relay signaling server when available (fallback to manual QR code exchange), and sync pending outbox entries using a CRDT-based merge strategy to resolve concurrent edits. The mesh must support up to 50 devices in a single session.
Technical Invariants & Bounds
Codebase Navigation Guide
Implementation Blueprint