Build the P2P networking layer using PeerJS. This handles connection lifecycle, message passing, and data synchronization between peers. Every poll operates as a "room" where the owner's peer ID is the room identifier.
Design
Connection model: Star topology per poll—owner acts as relay hub; participants connect to owner
Peer ID: Derived from user's public key (deterministic, resumable)
Messages: JSON-based protocol over PeerJS data channels
Reconnection: Auto-reconnect with exponential backoff
Sync: On connect, owner sends full poll state snapshot; subsequent changes are incremental messages
When the poll owner is offline, the poll is unreachable. Participants can view their local cached copy but cannot submit new votes until the owner reconnects.
Outbox & Acknowledgment
Every mutation message includes a commandId (UUID) for deduplication
Sender persists the command in a local IndexedDB outbox before sending
Owner responds with ack { commandId, revision } on success or error { commandId, message } on failure
On reconnect, client resends any unacked commands from the outbox
Owner deduplicates by commandId
UI shows "Pending sync" indicator for unacked mutations
Plan
Create PeerJS service (singleton, manages connection lifecycle)
Implement message send/receive with typed protocol
Add connection state management (connecting, connected, disconnected)
Implement auto-reconnect with backoff
Add "room" concept—join a poll by connecting to owner's peer ID