# 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
