Collaborative poker planning web application for agile team estimation using the Fibonacci sequence.
Click to view screenshots
Create a new room to start a planning session.
Share the room code with your team members.
Team members vote anonymously using Fibonacci values.
View vote distribution and average when revealed.
Celebrate when everyone agrees!
- Dynamic rooms with shareable 6-character codes
- Real-time synchronization with SSE (Server-Sent Events)
- Anonymous votes until collective reveal
- Fibonacci sequence for estimation (1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ?, ☕)
- Keyboard shortcuts for quick voting (1-9 keys for first 9 values)
- Automatic statistics (average, vote distribution)
- Confetti celebration when all votes match
- Session persistence via httpOnly cookies (2 hours)
- Auto-cleanup of inactive members (5 minutes)
- Member management - any member can remove others
- Installable on mobile and desktop devices
- App-like experience with standalone display mode
- WCAG compliant with proper ARIA attributes and semantic HTML
- Keyboard navigation throughout the entire application
- Screen reader support with live regions and announcements
- axe-core automated accessibility testing in development
- Preact 10 with TypeScript
- Vite 7 for build and dev server
- Tailwind CSS 4 for styling
- preact-iso for client-side routing
- Hono - Lightweight web framework
- Server-Sent Events for real-time synchronization
- Node.js with TypeScript
- Redis/Valkey - Distributed storage for horizontal scaling
- ioredis - Redis/Valkey client with connection pooling
- Playwright for end-to-end tests
- Vitest for unit tests
- k6 for load and performance testing
- oxlint for fast JavaScript/TypeScript linting
- oxfmt for code formatting
- Node.js 24+
- pnpm 10+
- Redis or Valkey (local or remote instance)
# Clone the repository
git clone <url>
cd poker-planning
# Install dependencies
pnpm install
# Install Playwright browsers (for tests)
pnpm exec playwright install chromium
# Configure environment variables
cp .env.example .env
# Edit .env and set your REDIS_URLFull stack (Redis/Valkey + Application) - Production-like environment:
# Build and start everything
docker-compose up -d
# View logs
docker-compose logs -f
# Stop everything
docker-compose down
# Application available at http://localhost:3001Redis/Valkey only (for local development with hot-reload):
# Start only Redis
docker-compose up -d redis
# Stop Redis
docker-compose down
# Set in .env:
REDIS_URL=redis://localhost:6379
# Then run the dev servers manually:
# Terminal 1: pnpm run dev:server
# Terminal 2: pnpm run devThe application is compatible with both Redis and Valkey (a fully open-source fork of Redis maintained by the Linux Foundation).
Valkey with Docker (recommended for open-source stack):
docker run -d --name poker-valkey -p 6379:6379 valkey/valkey:alpineRedis with Docker:
docker run -d --name poker-redis -p 6379:6379 redis:alpineLocal Valkey installation:
# macOS
brew install valkey
brew services start valkey
# Linux (Ubuntu/Debian)
# Add Valkey repository
curl -fsSL https://packages.valkey.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/valkey-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/valkey-archive-keyring.gpg] https://packages.valkey.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/valkey.list
sudo apt-get update
sudo apt-get install valkey
sudo systemctl start valkeyLocal Redis installation:
# macOS
brew install redis
brew services start redis
# Linux (Ubuntu/Debian)
sudo apt-get install redis-server
sudo systemctl start redisManaged services (for production):
Both Valkey and Redis are protocol-compatible, so you can use managed services:
- Scaleway Managed Database for Redis
- AWS ElastiCache (supports both Redis and Valkey)
- DigitalOcean Managed Redis
- Any Redis-compatible service
Example configuration:
REDIS_URL=redis://username:password@your-instance.cloud:6379The application requires 2 servers running in parallel:
# Terminal 1 - API server
pnpm run dev:server
# Terminal 2 - Vite frontend
pnpm run devThen open:
- Frontend: http://localhost:5173
- API: http://localhost:3001
- Create a room: Click "Create a Room" on the homepage
- Share the link: Copy the room URL to invite team members
- Join: Each member enters their name to join
- Vote: Click a Fibonacci card to vote
- Reveal: Any member can reveal all votes
- Celebrate: Confetti appears when everyone agrees!
- Reset: Start a new estimation round
# Run all E2E tests
pnpm test
# Interactive mode with UI
pnpm test:ui
# With visible browser
pnpm test:headed
# View HTML report
pnpm test:report# Run unit tests
pnpm test:unitLoad testing ensures the application can handle expected traffic and identifies performance bottlenecks.
Prerequisites: Install k6
# Quick validation (1 user, 1 minute)
pnpm run test:load:smoke
# Basic workflow (20 concurrent users, 3.5min)
pnpm run test:load:basic
# Spike test (sudden surge to 100 users)
pnpm run test:load:spikeThese production-ready tests run in a dedicated GitHub Actions workflow to avoid impacting CI performance:
# Stress test (up to 1000 concurrent users, 17min)
pnpm run test:load:stress
# Realistic sessions (500 users across 50-100 rooms, 18min)
pnpm run test:load:realistic
# SSE endurance (1000 concurrent connections for 10+ minutes, 20min)
pnpm run test:load:sse
# Run all heavy tests (~55min total)
pnpm run test:load:allPerformance Thresholds:
- Basic/Spike: <1% error rate, p95 < 500ms
- Stress: <5% error rate at 1000 users, p95 < 2s, p99 < 5s
- Realistic: <2% error rate, >30% consensus rate, p95 < 1s
- SSE: <5% error rate, >800 active connections maintained
GitHub Actions Workflows:
- Standard tests run on all PRs and pushes
- Heavy tests run nightly at 2 AM UTC, manually, or on releases
See tests/load/README.md for detailed documentation.
The application is installable as a Progressive Web App on both mobile and desktop.
Desktop (Chrome/Edge):
- Visit the app URL
- Look for the install icon in the address bar
- Click "Install"
Mobile (iOS/Android):
- Visit the app URL in Safari/Chrome
- Tap the share button
- Select "Add to Home Screen"
The application follows WCAG 2.1 Level AA guidelines.
axe-core runs automatically in development mode:
pnpm run dev
# Open browser console to see accessibility violations- Keyboard navigation: Full keyboard support with arrow keys, Tab, Enter
- Screen readers: ARIA labels, live regions, and semantic HTML
- Skip links: Jump to main content and voting section
- Form labels: All inputs have associated labels (some visually hidden)
- Focus management: Clear focus indicators and logical tab order
- Color contrast: All text meets WCAG AA contrast ratios
# Run linter
pnpm lint
# Format code
pnpm formatpoker-planning/
├── server/ # Hono API server
│ ├── index.ts # API endpoints and SSE handling
│ ├── storage.ts # Redis/Valkey storage layer for rooms
│ └── redis.ts # Redis/Valkey client wrapper
├── src/
│ ├── pages/ # Page components
│ │ ├── Home.tsx # Homepage with room creation
│ │ └── Room.tsx # Room with voting interface
│ ├── hooks/ # Custom hooks
│ │ ├── useRoom.ts # Room state and actions
│ │ └── useConfetti.ts
│ ├── router.tsx # preact-iso router configuration
│ ├── main.tsx
│ └── index.css
├── tests/
│ ├── e2e/ # Playwright E2E tests
│ └── load/ # k6 load tests
│ ├── scenarios/ # Test scenarios
│ └── README.md # Load testing documentation
└── playwright.config.ts
The API is fully documented using OpenAPI 3.0 specification.
- Interactive API Docs (Swagger UI): https://poker.slashgear.dev/api/docs
- OpenAPI JSON: https://poker.slashgear.dev/api/openapi.json
POST /api/rooms- Create a new roomPOST /api/rooms/:code/join- Join a roomGET /api/rooms/:code- Get room infoGET /api/rooms/:code/events- SSE connection for updatesPOST /api/rooms/:code/vote- Submit a votePOST /api/rooms/:code/reveal- Reveal all votesPOST /api/rooms/:code/reset- Reset the sessionDELETE /api/rooms/:code/members/:id- Remove a member
For detailed request/response schemas, authentication, and examples, see the interactive API documentation.
graph TB
subgraph "Scaleway fr-par"
subgraph "GitHub Container Registry"
GHCR["ghcr.io/slashgear/poker-planning<br/>Docker Images"]
end
subgraph "Private Network VPC"
Redis[("Redis Managed Database<br/>rediss://10.x.x.x:6379<br/>TLS Enabled")]
subgraph "Serverless Containers"
Prod["Production Container<br/>Image: v2.x.x<br/>Deploy on git tags"]
end
end
subgraph "CI/CD"
GHA["GitHub Actions<br/>Build • Test • Deploy"]
end
end
GHA -->|1. Build & Push| GHCR
GHA -->|2. Deploy| Prod
GHCR -.->|Pull Image| Prod
Prod -->|rediss://| Redis
style Redis fill:#dc3545
style Prod fill:#28a745
style GHCR fill:#6c757d
style GHA fill:#ffc107
- Redis/Valkey for distributed session storage
- Rooms stored with 2-hour TTL (auto-expiry)
- Supports horizontal scaling across multiple container instances
- Atomic operations for consistency
- Protocol-compatible: works with both Redis and Valkey
- Session data persists across container restarts
- Inactive member cleanup runs every minute
- Rooms are identified by 6-character codes (e.g.,
ABC123) - Members are tracked via session cookies (httpOnly, 2h expiry)
- Inactive members are automatically removed after 5 minutes
- Empty rooms are automatically cleaned up by Redis/Valkey TTL
- Server-Sent Events broadcast room state to all connected clients
- Automatic reconnection on connection loss
- Keep-alive pings every 30 seconds
- SSE clients tracked per container (roomClients Map)
- Room state fetched from Redis/Valkey on each broadcast
pnpm run dev # Start Vite dev server
pnpm run dev:server # Start API server
pnpm run build # Production build
pnpm run preview # Preview build
pnpm lint # Run linter
pnpm format # Format code
pnpm test # Run Playwright tests
pnpm test:ui # Tests in interactive UI mode
pnpm test:headed # Tests with visible browser
pnpm test:report # Show test report
pnpm screenshots # Generate example screenshotsSee CONTRIBUTING.md for contribution guidelines.
MIT License
Copyright (c) 2026 Antoine Caron (@Slashgear)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.




