feat: implement dynamic P2P polling app with real-time synchronization
- 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
This commit is contained in:
280
README.md
280
README.md
@@ -1 +1,279 @@
|
||||
# P2P Poll App
|
||||
# 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
|
||||
|
||||
1. Navigate to server directory:
|
||||
```bash
|
||||
cd server
|
||||
```
|
||||
|
||||
2. Install dependencies:
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
3. Copy environment file:
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
4. Start the development server:
|
||||
```bash
|
||||
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
|
||||
|
||||
1. Navigate to frontend directory:
|
||||
```bash
|
||||
cd frontend
|
||||
```
|
||||
|
||||
2. Install dependencies:
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
3. Copy environment file (optional):
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
4. Start the development server:
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
The frontend will run on `http://localhost:5173`
|
||||
|
||||
## Running the Application
|
||||
|
||||
1. **Start Backend** (Terminal 1):
|
||||
```bash
|
||||
cd server
|
||||
npm run dev
|
||||
```
|
||||
|
||||
2. **Start Frontend** (Terminal 2):
|
||||
```bash
|
||||
cd frontend
|
||||
npm run dev
|
||||
```
|
||||
|
||||
3. **Open Browser:**
|
||||
- Navigate to `http://localhost:5173`
|
||||
- Open multiple tabs/windows to test P2P synchronization
|
||||
|
||||
## 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
|
||||
1. Enter your question in the "Create a New Poll" form at the top
|
||||
2. Click "Create Poll"
|
||||
3. Your poll appears instantly for all connected users
|
||||
|
||||
### Add Answer Options
|
||||
1. Find the poll you want to add an answer to
|
||||
2. Type your answer in the "Add a new option..." field
|
||||
3. Click "Add"
|
||||
4. Your answer appears instantly for all users
|
||||
|
||||
### Vote on Options
|
||||
1. Click the vote button (thumbs up icon) on any option
|
||||
2. You can only vote once per option
|
||||
3. Voted options show a green border and " Voted" indicator
|
||||
4. Vote counts update in real-time across all clients
|
||||
|
||||
### Multi-User Testing
|
||||
1. Open multiple browser tabs/windows
|
||||
2. Create polls from different tabs
|
||||
3. Add answers from different tabs
|
||||
4. Vote from different tabs
|
||||
5. 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 `votedBy` tracking
|
||||
|
||||
## Data Model
|
||||
```typescript
|
||||
{
|
||||
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
|
||||
|
||||
1. Open the app in multiple browser tabs/windows
|
||||
2. **Create polls** from different tabs - they appear everywhere instantly
|
||||
3. **Add answer options** from different tabs to the same poll
|
||||
4. **Vote** from different tabs - watch vote counts update in real-time
|
||||
5. Try voting twice on the same option - it won't let you!
|
||||
6. Check the connection status indicator for peer count
|
||||
7. Verify visual feedback (green border) on options you've voted on
|
||||
|
||||
## Development
|
||||
|
||||
### Backend Scripts
|
||||
- `npm run dev` - Start development server with hot reload
|
||||
- `npm run build` - Build for production
|
||||
- `npm start` - Run production build
|
||||
|
||||
### Frontend Scripts
|
||||
- `npm run dev` - Start Vite dev server
|
||||
- `npm run build` - Build for production
|
||||
- `npm 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 poll
|
||||
- `addOption(pollId, text)` - Add an option to a specific poll
|
||||
- `vote(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
|
||||
Reference in New Issue
Block a user