Replace minimal README with full project docs (setup, usage, architecture). Remove trivial tests and add meaningful edge case coverage.
3.4 KiB
P2P Poll App
A peer-to-peer polling application where users can create polls, add options, and vote — all without a central server. Built for the Evocracy democratic coding research experiment.
How It Works
Data is synchronized directly between peers using Automerge CRDTs (Conflict-free Replicated Data Types). There is no backend database — every client holds a full copy of the poll document and changes merge automatically, even when made offline or concurrently.
Sync layers:
- WebSocket (
wss://sync.automerge.org) — cross-device sync via a public relay - BroadcastChannel — instant cross-tab sync within the same browser
- IndexedDB — local persistence across page reloads and offline use
Requirements
- Bun (standalone runtime, no Node.js needed)
Getting Started
bun install # Install dependencies
bun run dev # Start dev server (http://localhost:3000)
Usage
- Create a poll — Enter a title on the home page and click "Create"
- Share it — Copy the shareable link and send it to others
- Vote — Click an option to vote; click again to unvote
- Add options — Anyone with the link can add new poll options
Each browser gets a stable peer ID (stored in localStorage) so votes are tracked per-device and double-voting is prevented.
Tech Stack
| Layer | Technology |
|---|---|
| Runtime | Bun |
| Framework | Waku (React Server Components) |
| Styling | Tailwind CSS v4 |
| P2P sync | Automerge + automerge-repo |
| Storage | IndexedDB (client-side) |
Project Structure
src/
├── pages/ # Waku page router
│ ├── _root.tsx # HTML document shell
│ ├── _layout.tsx # Root layout + Providers
│ ├── index.tsx # Home page (create/join polls)
│ └── poll/[id].tsx # Poll view page
├── components/
│ ├── Providers.tsx # Automerge Repo initialization
│ ├── HomeClient.tsx # Create/join poll UI
│ ├── PollPageClient.tsx # Poll ID validation
│ ├── PollView.tsx # Poll display, voting, options
│ └── ConnectionStatus.tsx # P2P connection indicator
├── lib/
│ ├── types.ts # Poll & PollOption interfaces
│ ├── repo.ts # Automerge Repo singleton
│ ├── poll.ts # Pure poll mutation functions
│ ├── peer.ts # Peer ID management
│ └── __tests__/ # Unit tests
└── styles/
└── global.css # Tailwind CSS
Testing
bun test
Covers poll creation, voting/unvoting, double-vote prevention, option management, and peer ID persistence.
Architecture Notes
- Pure business logic — Poll mutations in
src/lib/poll.tsare pure functions, used inside Automerge'schangeDoc()for CRDT-safe updates - No server state — The WebSocket relay only forwards sync messages; it never stores or processes poll data
- Offline-first — The app works fully offline; changes sync when connectivity resumes
- Conflict-free — Concurrent edits (e.g., two users voting at the same time) merge automatically without conflicts
Built With
This project was built in collaboration with Claude Code, Anthropic's agentic coding tool.
License
MIT