Files
427e7578-d7bf-49c8-aee9-2dd…/PLAN.md
2026-04-15 01:23:33 +02:00

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.json with dependencies: yjs, y-webrtc, y-indexeddb, vite, typescript
  • Create tsconfig.json (strict, ES2022, bundler resolution)
  • Create index.html entry point
  • Create vite.config.ts if 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 1
  • sync.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 components
  • main.ts: minimal entry that calls initApp

Step 4: Components

  • PollTitle.ts: port collaborative Y.Text editing from project 1, add TypeScript types
  • AddOption.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 TypeScript
  • PollList.ts: port diff-rendering from project 1, add TypeScript
  • StatusBar.ts: merge project 1 (peer count) + project 3 (online/offline status)
  • ShareSection.ts: port from project 1, add TypeScript
  • DeadlineTimer.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