Real-time collaborative Planning Poker application with AI-powered story analysis, Jira integration, vote modifiers, and persistent sessions. Built with React, Node.js, WebSocket, and PostgreSQL.
# Quick start (requires PostgreSQL and Node.js 18+)
npm install
cp server/.env.example server/.env
# Configure DATABASE_URL in server/.env
npm run dev
# Open http://localhost:5173Planning Poker is a collaborative estimation tool designed for agile teams to estimate story points in real-time. Teams can create sessions, add multiple stories, vote simultaneously, and receive AI-powered recommendations for story breakdown when estimates are too large.
- Real-time Collaboration: WebSocket-based instant updates across all participants
- Multi-Story Management: Queue multiple stories, focus on one at a time
- Vote Modifiers: Soft up/down adjustments and question markers
- AI Story Analysis: Automatic recommendations to break down complex stories
- Jira Integration: Auto-import ticket titles and descriptions with images
- Rich Text Editor: TipTap-based editor with Markdown/JSON import support
- Persistent Sessions: PostgreSQL-backed storage with automatic user reconnection
- Dark Mode: System-wide dark theme support
- Collapsible Stories: Minimize completed or pending stories for better focus
- React 18 with TypeScript
- Vite for fast development and builds
- React Router for navigation
- TipTap rich text editor with extensions
- WebSocket for real-time communication
- Node.js with Express
- WebSocket (ws) for real-time updates
- PostgreSQL with Prisma ORM
- Axios for HTTP requests
- TypeScript for type safety
- Anthropic Claude (default)
- OpenAI GPT
- AWS Bedrock
- Jira Cloud API for ticket import
- Node.js 18+ and npm
- PostgreSQL 14+ (local or cloud instance)
- (Optional) AI Provider API key (Anthropic, OpenAI, or AWS)
- (Optional) Jira API token for ticket integration
-
Clone the repository
git clone <repository-url> cd planning-poker
-
Install dependencies
npm install
-
Set up the database
cd server cp .env.example .env -
Configure environment variables
Edit
server/.envwith your settings:# Database (REQUIRED) DATABASE_URL="postgresql://user:password@localhost:5432/planning_poker" # AI Provider (OPTIONAL - defaults to 'none') AI_PROVIDER=anthropic ANTHROPIC_API_KEY=your_key_here # Jira Integration (OPTIONAL) JIRA_EMAIL=your-email@company.com JIRA_API_TOKEN=your_token_here JIRA_COMPANY=yourcompany
-
Run database migrations
npx prisma migrate deploy npx prisma generate
-
Start the application
cd .. npm run devThe app will be available at:
- Frontend: http://localhost:5173
- Backend: http://localhost:3001
The application uses PostgreSQL with Prisma ORM. The schema includes:
- Sessions: Planning poker sessions with custom IDs
- Users: Participants with reconnection support
- Stories: Estimation items with focus management
- Votes: Individual user votes with optional modifiers
- AI Recommendations: Cached analysis results
Configure in server/.env:
# Anthropic Claude (Recommended)
AI_PROVIDER=anthropic
ANTHROPIC_API_KEY=sk-ant-...
ANTHROPIC_MODEL=claude-3-5-sonnet-20241022
# OpenAI GPT
AI_PROVIDER=openai
OPENAI_API_KEY=sk-...
OPENAI_MODEL=gpt-4o
# AWS Bedrock
AI_PROVIDER=bedrock
AWS_REGION=us-east-1
BEDROCK_MODEL_ID=anthropic.claude-3-5-sonnet-20241022-v2:0
# Disable AI
AI_PROVIDER=noneSee server/AI_PROVIDER_SETUP.md for detailed setup instructions.
- Generate an API token: https://id.atlassian.com/manage-profile/security/api-tokens
- Configure in
server/.env:JIRA_EMAIL=your-email@company.com JIRA_API_TOKEN=ATATT3xFfGF0... JIRA_COMPANY=yourcompany
- When creating stories, paste a Jira URL and the title/description will auto-populate
- Soft Up (⬆): "I'll defer to the majority if they vote higher"
- Soft Down (⬇): "I'll defer to the majority if they vote lower"
- Question (?): "I have concerns about this story"
Modifiers adjust displayed votes to the consensus (mode) value while preserving original votes in the database.
When votes are revealed with an average > 1 and a description exists:
- AI analyzes the story complexity
- If deemed too large, provides a breakdown recommendation
- Suggests smaller sub-stories
- Results are cached per story
- Focus: Brings a story to the top for all users (⭐ badge)
- Collapse: Minimizes a story card to save space
- Past Stories: Revealed stories move to a separate section when unfocused
The TipTap editor supports:
- Bold, italic, strikethrough, inline code
- Headings (H1, H2, H3)
- Bullet and numbered lists
- Blockquotes, code blocks, horizontal rules
- Import from Markdown or TipTap JSON format
Content is stored as JSON with backward compatibility for legacy HTML.
Users are identified by (sessionId, userName). If a user disconnects and rejoins with the same username:
- Previous votes are preserved
- Story history is maintained
- Session state is restored
planning-poker/
├── client/ # React frontend
│ ├── src/
│ │ ├── components/ # React components
│ │ ├── App.tsx # Main app component
│ │ ├── Session.tsx # Session page
│ │ └── useWebSocket.ts # WebSocket hook
│ └── package.json
├── server/ # Node.js backend
│ ├── src/
│ │ ├── ai/ # AI provider implementations
│ │ ├── jira/ # Jira integration
│ │ ├── index.ts # Express + WebSocket server
│ │ ├── sessionManager.ts # Business logic
│ │ └── types.ts # Shared types
│ ├── prisma/
│ │ └── schema.prisma # Database schema
│ └── package.json
├── package.json # Root package with workspaces
├── Dockerfile # Production container
└── README.md # This file
# Run both frontend and backend with hot reload
npm run dev
# Or run separately:
npm run dev:server # Backend on port 3001
npm run dev:client # Frontend on port 5173cd server
# Create a new migration
npx prisma migrate dev --name migration_name
# Reset database (WARNING: deletes all data)
npx prisma migrate reset
# Open Prisma Studio (database GUI)
npx prisma studio
# Generate Prisma client after schema changes
npx prisma generate# Build both client and server
npm run build
# Start production server
npm start
# Or use Docker (local build)
docker build -t planning-poker .
docker run -p 3001:3001 -e DATABASE_URL="..." planning-poker
# Or use pre-built images from GitHub Container Registry
docker pull ghcr.io/liatrio/planning-poker:latest
docker run -p 80:80 -e DATABASE_URL="..." ghcr.io/liatrio/planning-poker:latestPre-built Docker images are available from GitHub Container Registry:
docker pull ghcr.io/liatrio/planning-poker:latest
docker pull ghcr.io/liatrio/planning-poker:1.0.0Images are tagged with:
latest- Most recent main build<version>- Semantic version (e.g.,1.2.3)<major>.<minor>- Major + minor version (e.g.,1.2)<major>- Major version only (e.g.,1)main-<sha>- Git commit SHA
Images are tagged with:
latest- Most recent build from main branch<version>- Semantic version (e.g.,1.0.0)<major>.<minor>- Partial version (e.g.,1.0)<major>- Major version only (e.g.,1)main-<sha>- Specific commit SHA
Create a new planning poker session.
Request Body:
{
"sessionId": "optional-custom-id"
}Response:
{
"sessionId": "uuid-or-custom-id"
}Health check endpoint.
Response:
{
"status": "healthy",
"timestamp": "2025-01-30T12:00:00.000Z"
}All messages follow the format:
{
type: MessageType,
...payload
}JOIN: Join a sessionCREATE_STORY: Create a new storyEDIT_STORY: Edit an existing storyVOTE: Submit a voteSET_MODIFIER: Set vote modifierREVEAL_VOTES: Reveal votes for a storyRESET_VOTES: Clear votes and reset storySET_FOCUSED_STORY: Focus on a storyUNFOCUS_STORY: Remove focus
SESSION_STATE: Full session stateUSER_JOINED: New user joinedUSER_LEFT: User disconnectedSTORY_CREATED: New story addedSTORY_UPDATED: Story editedVOTE_UPDATE: User votedVOTES_REVEALED: Votes revealed with resultsVOTES_RESET: Votes clearedSTORY_FOCUSED: Story focusedSTORY_UNFOCUSED: Focus removedAI_ANALYSIS_STARTED: AI processing startedAI_RECOMMENDATION: AI results availableERROR: Error occurred
Ensure all required environment variables are set:
DATABASE_URL: PostgreSQL connection stringPORT: (Optional) Server port (default: 3001)- AI provider credentials (if using AI features)
- Jira credentials (if using Jira integration)
docker build -t planning-poker .
docker run -p 3001:3001 \
-e DATABASE_URL="postgresql://..." \
-e ANTHROPIC_API_KEY="..." \
planning-pokerRun migrations before deploying new versions:
cd server
npx prisma migrate deploy- Check firewall rules allow WebSocket connections
- Ensure
ws://orwss://protocol is used correctly - Verify CORS settings in
server/src/index.ts
- Verify
DATABASE_URLis correct - Check PostgreSQL server is running
- Ensure database exists:
createdb planning_poker - Run migrations:
npx prisma migrate deploy
- Verify API keys are valid
- Check account has sufficient credits
- Review provider-specific rate limits
- Check logs for detailed error messages
- Verify Jira credentials are correct
- Ensure Jira URL matches pattern:
https://{JIRA_COMPANY}.atlassian.net/browse/{KEY} - Check API token has required permissions
- Review server logs for API error details
This project uses Semantic Versioning based on Conventional Commits.
Versions are automatically determined from commit messages:
feat:→ MINOR version bump (0.1.0)fix:→ PATCH version bump (0.0.1)BREAKING CHANGE:or!→ MAJOR version bump (1.0.0)
See CHANGELOG.md for release history.
We welcome contributions! Please follow these guidelines:
Use Conventional Commits:
<type>(<scope>): <subject>
Types:
feat:New feature (MINOR version)fix:Bug fix (PATCH version)docs:Documentation changesrefactor:Code refactoringtest:Adding testschore:Maintenance tasks
Examples:
feat(jira): add automatic ticket import
fix(voting): correct soft up/down calculation
docs: update README with Docker instructions- Fork the repository
- Create a feature branch (
git checkout -b feat/amazing-feature) - Commit using conventional commits
- Push to your fork (
git push origin feat/amazing-feature) - Open a Pull Request
For detailed contributing guidelines, see CONTRIBUTING.md.
This project is licensed under the MIT License - see the LICENSE file for details.
For issues, questions, or feature requests, please contact the development team or open an issue in the repository.