# 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.