forked from quic-issues/427e7578-d7bf-49c8-aee9-2dd999e25316
56 lines
3.2 KiB
Markdown
56 lines
3.2 KiB
Markdown
# P2P Poll App
|
|
|
|
A peer-to-peer polling app built with [Automerge](https://automerge.org/) and Vanilla JS. No backend required — polls sync in real time across browsers using CRDTs and a WebSocket relay.
|
|
|
|
## Features
|
|
|
|
- **Add options** — type an option and press Enter or click "Add Option". Duplicate options (case-insensitive) are rejected with an inline error message.
|
|
- **Vote on options** — click the vote button next to any option. You can vote on multiple options, but only once per option.
|
|
- **Toggle votes** — click your vote again to remove it (the button turns green with a checkmark when you've voted).
|
|
- **Live vote counts** — options are sorted by vote count in descending order and update in real time as votes come in from other users.
|
|
- **2-minute countdown timer** — click "Start 2-min Vote" to begin a shared countdown. Voting is open before and during the countdown. Once the timer expires, all vote buttons are disabled.
|
|
- **Shared timer** — the deadline is stored in the Automerge document, so all peers see the same countdown and voting closes simultaneously for everyone.
|
|
- **Copy URL** — click "Copy URL" to copy the poll link to your clipboard. Share it with others to join the same poll.
|
|
- **P2P sync** — all state (options, votes, timer) syncs across browsers in real time with no central server handling your data.
|
|
|
|
## How it works
|
|
|
|
### Tech stack
|
|
|
|
- **[Automerge](https://automerge.org/)** via `@automerge/vanillajs` — a CRDT library that lets multiple clients concurrently edit shared documents and merge changes without conflicts.
|
|
- **BroadcastChannelNetworkAdapter** — syncs between tabs in the same browser instantly via the browser's BroadcastChannel API.
|
|
- **WebSocketClientAdapter** — syncs across different browsers/devices via a WebSocket relay (`wss://sync.automerge.org`). The relay only forwards CRDT messages; it does not store or interpret your data.
|
|
- **IndexedDBStorageAdapter** — persists the document locally so it survives page refreshes.
|
|
- **Vite** — bundles the app with WebAssembly support (required by Automerge).
|
|
|
|
### Data model
|
|
|
|
The poll is a single Automerge document with three fields:
|
|
|
|
```js
|
|
{
|
|
options: string[], // list of poll options in insertion order
|
|
votes: { [option]: number }, // vote count per option
|
|
deadline: number | null // Unix timestamp (ms) when voting closes, or null
|
|
}
|
|
```
|
|
|
|
### URL-based sharing
|
|
|
|
Each document gets a unique Automerge URL (e.g. `automerge:abc123...`) stored in the page's URL hash. Opening the same URL in any browser loads and syncs the same document. Creating a new poll generates a new document and updates the hash automatically.
|
|
|
|
### Voting rules
|
|
|
|
- Voted options are tracked in `localStorage` (keyed by document URL), so they persist across page refreshes but are isolated per browser.
|
|
- One vote per option per user. Votes can be toggled off and back on until the timer expires.
|
|
- The timer (`doc.deadline`) is set once by whoever clicks "Start 2-min Vote" and is shared via the Automerge document, so all peers use the same deadline.
|
|
|
|
## Running locally
|
|
|
|
```bash
|
|
pnpm install
|
|
pnpm dev
|
|
```
|
|
|
|
Open the printed localhost URL. To test cross-browser sync, copy the URL (including the `#automerge:...` hash) and open it in a different browser.
|