4.7 KiB
4.7 KiB
Plan: Combined P2P Polling App
Overview
Merge the three subfolder projects into a single TypeScript + Yjs + Vite application at the repo root, combining the best features from each.
Technology Choices
- Language: TypeScript (from project 3) with strict mode
- CRDT: Yjs + y-webrtc + y-indexeddb (from projects 1 & 3)
- Build: Vite (shared by all)
- Package manager: npm
Feature Superset
From project 1 (group-efa16e66):
- Collaborative title editing via Y.Text (real-time character-level sync)
- Delete options
- Diff-rendering for poll list (reuse DOM elements)
- Peer count display via awareness
- Share section with copy-to-clipboard
From project 2 (proposal-8835ffc9):
- Deadline/timer system (2-minute voting window with countdown)
- Duplicate detection (case-insensitive)
From project 3 (proposal-88461784):
- TypeScript types & strict mode
- Modular architecture (state, sync, render, identity, app layers)
- IndexedDB persistence (offline support)
- Online/offline connection tracking
- Input validation (max lengths, empty checks)
- HTML escaping for XSS prevention
- ViewModel pattern for clean render layer
Data Model (Yjs)
Y.Doc
├── poll-meta (Y.Map<string>)
│ └── title → Y.Text (collaborative editing from project 1)
├── poll-options (Y.Map<OptionRecord>)
│ └── [optionId] → { id, label, createdAt, createdBy }
├── poll-votes (Y.Map<string>)
│ └── [userId] → optionId (single vote per user)
└── poll-deadline (Y.Map<any>)
└── deadline → number | null (timestamp, from project 2)
Architecture & File Structure
/
├── index.html
├── package.json
├── tsconfig.json
├── vite.config.ts (if needed for any plugins)
├── src/
│ ├── main.ts (entry: mount app)
│ ├── app.ts (orchestrator: init sync, bind events, manage state)
│ ├── identity.ts (getUserId with localStorage persistence)
│ ├── state.ts (types, pure functions, ViewModel creation)
│ ├── sync.ts (Yjs doc, WebRTC provider, IndexedDB, connection status)
│ ├── render.ts (DOM rendering with escapeHtml, diff-rendering for options)
│ ├── components/
│ │ ├── PollTitle.ts (collaborative title input bound to Y.Text)
│ │ ├── PollList.ts (diff-rendered option list with sorting)
│ │ ├── PollOption.ts (single option: vote bar, vote/delete buttons)
│ │ ├── AddOption.ts (input + submit with validation & duplicate check)
│ │ ├── StatusBar.ts (connection status + peer count)
│ │ ├── ShareSection.ts (copy URL to clipboard)
│ │ └── DeadlineTimer.ts (set deadline + countdown display, from project 2)
│ └── styles.css (merged: project 1's design tokens + project 3's glassmorphism)
Implementation Steps
Step 1: Scaffold root project
- Create
package.jsonwith dependencies: yjs, y-webrtc, y-indexeddb, vite, typescript - Create
tsconfig.json(strict, ES2022, bundler resolution) - Create
index.htmlentry point - Create
vite.config.tsif needed
Step 2: Core layer — identity.ts, state.ts, sync.ts
identity.ts: port from project 3 (getUserId)state.ts: port types from project 3, add deadline types, add ViewModel with deadline/timer info, add vote percentage calculation from project 1sync.ts: port from project 3, add Y.Text for title (from project 1), add poll-deadline map, add awareness tracking for peer count (from project 1)
Step 3: App orchestrator — app.ts, main.ts
app.ts: port from project 3, add deadline handlers, add delete option handler, wire up all componentsmain.ts: minimal entry that calls initApp
Step 4: Components
PollTitle.ts: port collaborative Y.Text editing from project 1, add TypeScript typesAddOption.ts: merge project 1 (UI/animation) + project 2 (duplicate detection) + project 3 (validation)PollOption.ts: port from project 1 (vote bar, percentage, delete button), add TypeScriptPollList.ts: port diff-rendering from project 1, add TypeScriptStatusBar.ts: merge project 1 (peer count) + project 3 (online/offline status)ShareSection.ts: port from project 1, add TypeScriptDeadlineTimer.ts: new component porting project 2's deadline/countdown logic to Yjs
Step 5: Styling
- Merge CSS: use project 1's design tokens and typography as base, incorporate project 3's glassmorphism panel effects, add timer-specific styles from project 2
Step 6: Cleanup
- Remove three subfolders (after confirming with user)
- Update root README.md