forked from quic-issues/427e7578-d7bf-49c8-aee9-2dd999e25316
e14bb6d425713db2d6254b321a0408fb5eace9d0
- Add complete P2P polling application with React + TypeScript frontend - Implement Node.js backend with Yjs WebSocket and WebRTC signaling - Support dynamic poll creation, answer management, and voting - Add CRDT-based state synchronization using Yjs for conflict-free merging - Implement user tracking and vote prevention (one vote per user per option) - Create modern UI with Tailwind CSS and visual feedback - Add comprehensive documentation and setup instructions Features: - Users can create polls with custom questions - Anyone can add answer options to any poll - Real-time voting with instant cross-client synchronization - Smart vote tracking with visual feedback for voted options - User attribution showing who created polls and options - Connection status indicators for WebSocket and P2P connections Technical: - Hybrid P2P architecture (WebSocket + WebRTC) - CRDT-based state management with Yjs
P2P Poll App
A peer-to-peer polling application built with React, TypeScript, Tailwind CSS, Node.js, Yjs, and WebSocket for real-time collaborative voting.
Users can create polls, add answers, and vote in real-time with automatic P2P synchronization across all connected clients.
Architecture
Hybrid P2P Approach:
- Backend serves as both a Yjs WebSocket provider (for state synchronization) and signaling server (for WebRTC peer discovery)
- Clients sync poll data via Yjs CRDT for conflict-free merging
- Direct P2P connections via WebRTC for real-time updates when possible
- Server fallback ensures reliability when P2P fails
Tech Stack
Backend:
- Node.js + TypeScript
- Express.js
- WebSocket (ws)
- y-websocket (Yjs WebSocket provider)
- CORS support
Frontend:
- React 18 + TypeScript
- Vite (build tool)
- Tailwind CSS
- Yjs (CRDT library)
- y-websocket (server sync)
- y-webrtc (P2P sync)
- lucide-react (icons)
Project Structure
quicgroup/
├── server/ # Backend Node.js server
│ ├── src/
│ │ ├── index.ts # Main server entry
│ │ ├── yjs-server.ts # Yjs WebSocket provider
│ │ ├── signaling-server.ts # WebRTC signaling
│ │ ├── types/ # TypeScript types
│ │ └── utils/ # Utilities
│ ├── package.json
│ └── tsconfig.json
│
└── frontend/ # React frontend
├── src/
│ ├── components/ # React components
│ ├── hooks/ # Custom React hooks
│ ├── lib/ # Yjs setup and utilities
│ ├── types/ # TypeScript types
│ └── styles/ # CSS styles
├── package.json
└── vite.config.ts
Setup Instructions
Prerequisites
- Node.js 18+ and npm
Backend Setup
- Navigate to server directory:
cd server
- Install dependencies:
npm install
- Copy environment file:
cp .env.example .env
- Start the development server:
npm run dev
The server will run on http://localhost:3000 with:
- Yjs WebSocket:
ws://localhost:3000/yjs - Signaling WebSocket:
ws://localhost:3000/signal
Frontend Setup
- Navigate to frontend directory:
cd frontend
- Install dependencies:
npm install
- Copy environment file (optional):
cp .env.example .env
- Start the development server:
npm run dev
The frontend will run on http://localhost:5173
Running the Application
- Start Backend (Terminal 1):
cd server
npm run dev
- Start Frontend (Terminal 2):
cd frontend
npm run dev
- Open Browser:
- Navigate to
http://localhost:5173 - Open multiple tabs/windows to test P2P synchronization
- Navigate to
Features
Dynamic Poll Creation
- Create Polls - Any user can create new polls with custom questions
- Add Answers - Anyone can add answer options to any poll
- Real-time Voting - Vote on options with instant updates across all clients
- Smart Vote Tracking - One vote per user per option (prevents duplicate voting)
- Visual Feedback - Green border and " Voted" indicator on voted options
- User Attribution - See who created each poll and option
- Live Vote Counts - See vote percentages and counts update in real-time
- P2P Synchronization - Uses Yjs CRDT for conflict-free state merging
- Connection Status - Visual indicator showing WebSocket and peer connections
- Hybrid Architecture - Combines WebSocket server sync with WebRTC P2P
- Beautiful UI - Modern gradient design with Tailwind CSS
How to Use
Create a Poll
- Enter your question in the "Create a New Poll" form at the top
- Click "Create Poll"
- Your poll appears instantly for all connected users
Add Answer Options
- Find the poll you want to add an answer to
- Type your answer in the "Add a new option..." field
- Click "Add"
- Your answer appears instantly for all users
Vote on Options
- Click the vote button (thumbs up icon) on any option
- You can only vote once per option
- Voted options show a green border and " Voted" indicator
- Vote counts update in real-time across all clients
Multi-User Testing
- Open multiple browser tabs/windows
- Create polls from different tabs
- Add answers from different tabs
- Vote from different tabs
- Watch real-time synchronization in action!
How It Works
CRDT Synchronization
The app uses Yjs (a CRDT library) to ensure all clients converge to the same state without conflicts:
- Each client maintains a local Yjs document
- Changes are automatically synced via WebSocket to the server
- WebRTC provides direct P2P connections between clients
- Yjs handles merge conflicts automatically
- One vote per user per option is enforced via
votedBytracking
Data Model
{
polls: Array<{
id: string,
question: string,
createdBy: string,
timestamp: number,
options: Array<{
id: string,
text: string,
votes: number,
votedBy: string[], // Tracks which users have voted
createdBy: string,
timestamp: number
}>
}>
}
Testing P2P Functionality
- Open the app in multiple browser tabs/windows
- Create polls from different tabs - they appear everywhere instantly
- Add answer options from different tabs to the same poll
- Vote from different tabs - watch vote counts update in real-time
- Try voting twice on the same option - it won't let you!
- Check the connection status indicator for peer count
- Verify visual feedback (green border) on options you've voted on
Development
Backend Scripts
npm run dev- Start development server with hot reloadnpm run build- Build for productionnpm start- Run production build
Frontend Scripts
npm run dev- Start Vite dev servernpm run build- Build for productionnpm run preview- Preview production build
Environment Variables
Backend (.env)
PORT=3000
YJS_WS_PORT=1234
NODE_ENV=development
CORS_ORIGIN=http://localhost:5173
Frontend (.env)
VITE_WS_URL=ws://localhost:3000
Components
Frontend Components
- PollView - Main view showing all polls and create poll form
- CreatePoll - Form to create new polls
- PollCard - Individual poll display with metadata
- OptionList - List of answer options with vote tracking
- AddOption - Form to add new answer options
- VoteButton - Vote button with disabled state for voted options
- ConnectionStatus - Shows WebSocket and P2P connection status
Key Functions
createPoll(question)- Create a new polladdOption(pollId, text)- Add an option to a specific pollvote(pollId, optionId)- Vote on an option (one vote per user)hasVoted(option)- Check if current user has voted on an option
User Tracking
Each user gets a unique ID stored in localStorage:
- Format:
user-xxxxxxxxx - Used to track poll/option creators
- Used to prevent duplicate voting
- Persists across browser sessions
Future Enhancements
- Edit/delete polls and options
- User nicknames instead of IDs
- Poll expiration/closing
- Vote history and analytics
- Export poll results
- Persistent storage (database)
- Dark mode toggle
- Mobile responsive improvements
- Poll categories/tags
- Search/filter polls
License
MIT
Description