Replace minimal README with full project docs (setup, usage, architecture). Remove trivial tests and add meaningful edge case coverage.
92 lines
3.4 KiB
Markdown
92 lines
3.4 KiB
Markdown
# 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](https://demcode.evocracy.org/).
|
|
|
|
## How It Works
|
|
|
|
Data is synchronized directly between peers using [Automerge](https://automerge.org/) 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](https://bun.sh/) (standalone runtime, no Node.js needed)
|
|
|
|
## Getting Started
|
|
|
|
```bash
|
|
bun install # Install dependencies
|
|
bun run dev # Start dev server (http://localhost:3000)
|
|
```
|
|
|
|
## Usage
|
|
|
|
1. **Create a poll** — Enter a title on the home page and click "Create"
|
|
2. **Share it** — Copy the shareable link and send it to others
|
|
3. **Vote** — Click an option to vote; click again to unvote
|
|
4. **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](https://bun.sh/) |
|
|
| Framework | [Waku](https://waku.gg/) (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
|
|
|
|
```bash
|
|
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.ts` are pure functions, used inside Automerge's `changeDoc()` 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](https://claude.ai/code), Anthropic's agentic coding tool.
|
|
|
|
## License
|
|
|
|
MIT
|