--- status: planned created: '2026-03-16' tags: - server - infra priority: high created_at: '2026-03-16T07:57:36.544Z' depends_on: - 001-project-setup updated_at: '2026-03-16T09:32:10.798Z' --- # Poll Snapshot Server > **Status**: ๐Ÿ—“๏ธ Planned ยท **Priority**: High ยท **Created**: 2026-03-16 ยท **Tags**: server, infra ## Overview A minimal server that stores poll snapshots for public/offline viewing. This is the only server-side component โ€” intentionally thin. No user accounts, no directory, no auth beyond signature verification. ## Design ### Tech Stack - **Runtime**: Cloudflare Workers (or a simple Bun server if self-hosting) - **Storage**: Cloudflare KV (or SQLite for self-hosted) - **Auth**: Snapshot writes are signed with the poll owner's Ed25519 private key ### API Endpoints - `PUT /api/polls/:id/snapshot` โ€” Store/update snapshot (signed by poll owner) - Body: `{ pollId, ownerId, ownerPeerId, title, description, options[], voteCounts, status, signature }` - `GET /api/polls/:id/snapshot` โ€” Fetch snapshot (public, no auth) ### Security - Write operations require a valid Ed25519 signature - Verify signature against `ownerId` in the request body; bind `pollId โ†’ ownerId` on first write; reject future writes if `ownerId` changes - No sessions, no cookies, no passwords - Rate limiting on writes to prevent abuse ### Data Model ```typescript // KV key: poll:{pollId}:snapshot โ†’ PollSnapshot interface PollSnapshot { pollId: string; ownerId: string; ownerPeerId: string; title: string; description: string; options: { id: string; text: string }[]; voteCounts: Record; status: 'draft' | 'open' | 'closed'; updatedAt: number; } ``` ## Plan - [ ] Set up Cloudflare Workers project (or simple Bun server) - [ ] Implement Ed25519 signature verification middleware - [ ] Implement poll snapshot store/fetch endpoints - [ ] Add rate limiting - [ ] Deploy ## Test - [ ] Snapshot store with valid signature succeeds - [ ] Snapshot store with invalid signature is rejected - [ ] Snapshot fetch returns stored data (public, no auth) - [ ] Second write from different ownerId is rejected - [ ] Rate limiting works ## Notes - The P2P app works without this server โ€” it just loses public sharing and offline snapshot viewing - Future: user directory endpoints can be added here when peer discovery is implemented (see archived spec 007) - Consider a TTL on snapshots (e.g., auto-expire 90 days after last update)