Files
427e7578-d7bf-49c8-aee9-2dd…/specs/002-p2p-networking/README.md
2026-03-16 22:44:21 +13:00

82 lines
3.0 KiB
Markdown

---
status: planned
created: '2026-03-16'
tags:
- p2p
- core
priority: high
created_at: '2026-03-16T07:51:47.888Z'
depends_on:
- 001-project-setup
updated_at: '2026-03-16T07:52:03.104Z'
---
# P2P Networking Layer
> **Status**: 🗓️ Planned · **Priority**: High · **Created**: 2026-03-16 · **Tags**: p2p, core
## Overview
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
### Message Protocol
```typescript
type Message =
| { type: 'poll:state'; payload: Poll }
| { type: 'poll:vote'; payload: Vote }
| { type: 'poll:option:add'; payload: Option }
| { type: 'poll:role:update'; payload: RoleUpdate }
| { type: 'user:profile'; payload: UserProfile }
| { type: 'peer:discovery'; payload: PeerInfo[] }
| { type: 'ack'; payload: { commandId: string; revision: number } }
| { type: 'error'; payload: { commandId: string; message: string } }
| { type: 'sync:request'; payload: { pollId: string } }
```
### Offline Behavior
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
- [ ] Handle peer disconnect/cleanup
- [ ] Implement outbox (IndexedDB-backed pending command queue)
- [ ] Implement ack/error response handling
- [ ] Implement resend-on-reconnect for unacked commands
## Test
- [ ] Two browser tabs can establish a PeerJS connection
- [ ] Messages round-trip correctly
- [ ] Reconnection works after simulated disconnect
- [ ] Unacked commands are resent after reconnect
- [ ] Owner deduplicates commands by commandId
## Notes
- Star topology keeps it simple—owner must be online for live interaction
- Could explore gossip/mesh topology later for resilience, but adds complexity