A modern, real-time collaborative retrospective tool built with SvelteKit 5 and SQLite.
- Real-time Collaboration - SSE-powered real-time synchronization for 40+ concurrent users
- Board Series Management - Organize retrospectives in series with role-based access control
- Multi-phase Workflow - Structured meeting phases with facilitator controls
- Card Management - Create, edit, group, and vote on retrospective cards
- Smart Voting System - Configurable vote allocation with facilitator dashboard
- Scene Management - Control meeting phases with customizable permissions
- Comments & Agreements - Add comments to cards with agreement tracking
- Presence Tracking - See who's actively participating in real-time
- Timer System - Meeting timers with extension voting capabilities
- Board Templates - Pre-configured templates (KAFE, Sailboat, Mad Sad Glad, etc.)
- Action Item Tracking - Track and rollover action items between boards
- Password Authentication - Email/password authentication with secure sessions
- WebAuthn/Passkey Support - Passwordless authentication with biometrics or security keys
- Admin System - Admin-only access controls for sensitive features
- Rate Limiting - Server-side rate limiting for auth and resource endpoints
- Scorecard System - Create reusable data collection templates with formulas
- RPN Formula Evaluation - Advanced formula system for scorecard calculations
- Data Source Management - Configure multiple data sources per scorecard
- Scene-based Scorecards - Run scorecards during specific meeting phases
- Results Tracking - Flag and track scorecard results over time
- Performance Monitoring - Real-time performance metrics and analytics dashboard
- Time Series Charts - Visual performance data with historical tracking
- Slow Query Detection - Automatic detection of database performance issues
- Health Checks - System health monitoring endpoint
- Frontend: SvelteKit 5 with custom design system (LESS)
- Backend: SvelteKit API routes with TypeScript
- Database: SQLite or PostgreSQL with Drizzle ORM
- Real-time: Server-Side Events (same port as HTTP)
- Authentication: Session-based with secure cookies
# Install dependencies
npm install
# Generate and apply SQLite schema
npm run db:push:sqlite
# Start development server
npm run devThe application will be available at http://localhost:5173
# Install dependencies
npm install
# Set DATABASE_URL for PostgreSQL
export DATABASE_URL="postgresql://user:password@localhost/teambeat"
# Generate and apply PostgreSQL schema
npm run db:push:postgres
# Start development server with PostgreSQL
npm run devThe database type is automatically detected from DATABASE_URL:
- Starts with
postgres://orpostgresql://→ PostgreSQL - Otherwise → SQLite (default:
./teambeat.db)
Use the provided docker-compose.yml for easy deployment:
# Build and start the application
docker-compose up --build
# Run in background
docker-compose up -d --buildThe application will be available at http://localhost:3000 with the database persisted in ./db/teambeat.db.
# Build the Docker image
docker build -t teambeat .
# Create database directory
mkdir -p ./db
# Run the container
docker run -d \
--name teambeat \
-p 3000:3000 \
-v $(pwd)/db:/db \
-e DATABASE_URL=/db/teambeat.db \
teambeatThe Dockerfile uses a multi-stage build:
- Stage 1: Install dependencies
- Stage 2: Build the application
- Stage 3: Create optimized runtime image with Node.js
Key features:
- SQLite database mounted at
/dbdirectory - Non-root user for security
- Health checks for container monitoring
- Automatic database migration on startup
- Port 3000 exposed by default
DATABASE_URL: Path to SQLite database file (default:/db/teambeat.db)PORT: Application port (default:3000)NODE_ENV: Environment mode (set toproductionin container)
/db: Database directory (required for data persistence)/app/logs: Application logs (optional)
# Generate SQLite migration from schema changes
npm run db:generate:sqlite
# Apply SQLite schema to database
npm run db:push:sqlite
# Open database studio
npm run db:studio# Generate PostgreSQL migration from schema changes
DATABASE_URL="postgresql://localhost/teambeat" npm run db:generate:postgres
# Apply PostgreSQL schema to database
DATABASE_URL="postgresql://user:pass@host/db" npm run db:push:postgres
# Open database studio
DATABASE_URL="postgresql://user:pass@host/db" npm run db:studioBoth databases use the same schema with automatic type adaptation:
- Booleans: Native
booleanin PostgreSQL,integerin SQLite - Timestamps: ISO 8601 text strings in both databases
- Transactions: Async transactions work with both backends
src/
├── lib/
│ ├── server/
│ │ ├── db/ # Database schema and connection
│ │ ├── repositories/ # Data access layer
│ │ ├── sse/ # Server-Side Events handling
│ │ ├── auth/ # Authentication, sessions & WebAuthn
│ │ ├── performance/ # Performance tracking & persistence
│ │ ├── middleware/ # Request middleware (presence, etc.)
│ │ └── utils/ # Shared server utilities
│ ├── components/ # Reusable UI components
│ │ └── ui/ # Base UI components
│ ├── stores/ # Client-side state management
│ ├── utils/ # Shared utilities (RPN, data parsing)
│ ├── styles/ # LESS styles and mixins
│ ├── data/ # Static data (column presets)
│ └── types/ # TypeScript type definitions
├── routes/
│ ├── api/ # REST API endpoints
│ │ ├── auth/ # Authentication endpoints
│ │ ├── boards/ # Board management
│ │ ├── cards/ # Card operations
│ │ ├── comments/ # Comments & agreements
│ │ ├── series/ # Series management
│ │ ├── scenes/ # Scene configuration
│ │ ├── scorecards/ # Scorecard management
│ │ ├── admin/ # Admin-only endpoints
│ │ └── sse/ # Real-time events
│ ├── board/[id]/ # Board interface
│ ├── series/[id]/ # Series management pages
│ ├── admin/ # Admin pages
│ ├── login/ # Authentication pages
│ ├── register/
│ └── profile/
├── app.html # Root HTML template
└── hooks.server.ts # Server-side hooks
POST /api/auth/register- Create accountPOST /api/auth/login- Sign in with passwordPOST /api/auth/logout- Sign outGET /api/auth/me- Get current userPUT /api/auth/profile- Update user profilePUT /api/auth/change-password- Change passwordDELETE /api/auth/delete-account- Delete user accountPOST /api/auth/dev-login- Development login (dev only)
POST /api/auth/webauthn/register/begin- Start passkey registrationPOST /api/auth/webauthn/register/complete- Complete passkey registrationPOST /api/auth/webauthn/authenticate/begin- Start passkey authenticationPOST /api/auth/webauthn/authenticate/complete- Complete passkey authenticationGET /api/auth/webauthn/passkeys- List user's passkeysDELETE /api/auth/webauthn/passkeys/[id]- Delete a passkey
GET /api/series- List user's seriesPOST /api/series- Create new seriesGET /api/series/[id]- Get series detailsPUT /api/series/[id]- Update seriesDELETE /api/series/[id]- Delete seriesGET /api/series/[id]/users- Get series usersPOST /api/series/[id]/users- Add user to seriesGET /api/series/[seriesId]/columns- Get series column presetsGET /api/series/[seriesId]/scorecards- List series scorecardsPOST /api/series/[seriesId]/scorecards- Create series scorecardPUT /api/series/[seriesId]/scorecards/[id]- Update scorecardDELETE /api/series/[seriesId]/scorecards/[id]- Delete scorecard
GET /api/boards- List user's recent boardsPOST /api/boards- Create new boardGET /api/boards/[id]- Get board detailsPUT /api/boards/[id]- Update boardDELETE /api/boards/[id]- Delete boardPOST /api/boards/[id]/clone- Clone boardGET /api/boards/[id]/clone-sources- Get available boards to clone fromPUT /api/boards/[id]/scene- Change current scenePUT /api/boards/[id]/setup-template- Setup board templateGET /api/boards/[id]/present-data- Get present mode dataGET /api/boards/[id]/user-votes- Get user's vote dataGET /api/boards/[id]/user-status- Get voting status infoPUT /api/boards/[id]/share- Update board sharing settings
GET /api/boards/[id]/scenes- Get board scenesPOST /api/boards/[id]/scenes- Create sceneGET /api/boards/[id]/scenes/[sceneId]- Get scene detailsPUT /api/boards/[id]/scenes/[sceneId]- Update sceneDELETE /api/boards/[id]/scenes/[sceneId]- Delete scenePUT /api/boards/[id]/scenes/reorder- Reorder scenesGET /api/boards/[id]/scenes/[sceneId]/columns- Get scene columnsGET /api/scenes/[id]/select-card- Select presentation cardGET /api/boards/[id]/columns- Get board columnsPOST /api/boards/[id]/columns- Create columnPUT /api/boards/[id]/columns/[columnId]- Update columnDELETE /api/boards/[id]/columns/[columnId]- Delete columnPUT /api/boards/[id]/columns/reorder- Reorder columns
GET /api/boards/[id]/cards- Get all cards for boardPOST /api/boards/[id]/cards- Create new cardPOST /api/boards/[id]/cards/group- Group multiple cardsGET /api/cards/[id]- Get card detailsPUT /api/cards/[id]- Update card contentDELETE /api/cards/[id]- Delete cardPUT /api/cards/[id]/move- Move card between columnsPUT /api/cards/[id]/group- Group cards togetherPUT /api/cards/[id]/group-onto- Group card onto anotherPOST /api/cards/[id]/vote- Toggle vote on cardGET /api/boards/[id]/voting-stats- Facilitator voting dashboardPOST /api/boards/[id]/votes/clear- Clear all votesPOST /api/boards/[id]/votes/increase-allocation- Increase vote allocation
GET /api/boards/[id]/comments- Get board commentsPOST /api/cards/[id]/comments- Add comment to cardGET /api/comments/[id]- Get comment detailsPUT /api/comments/[id]- Update commentDELETE /api/comments/[id]- Delete commentPOST /api/comments/[id]/toggle-agreement- Toggle agreement on commentPOST /api/comments/[id]/complete- Mark comment as completePOST /api/comments/[id]/copy-to-card- Convert comment to cardGET /api/boards/[id]/agreements- Get board agreementsGET /api/agreements/[id]- Get agreement detailsPUT /api/agreements/[id]- Update agreementDELETE /api/agreements/[id]- Delete agreementPOST /api/agreements/[id]/complete- Mark agreement as completePOST /api/agreements/[id]/copy-to-card- Convert agreement to card
GET /api/cards/[id]/notes- Get card notesPUT /api/cards/[id]/notes- Update card notesPOST /api/cards/[id]/notes/lock- Lock/unlock notes editing
GET /api/scorecards/[scorecardId]/datasources- List scorecard data sourcesPOST /api/scorecards/[scorecardId]/datasources- Create data sourcePUT /api/scorecards/[scorecardId]/datasources/[id]- Update data sourceDELETE /api/scorecards/[scorecardId]/datasources/[id]- Delete data sourcePUT /api/scorecards/[scorecardId]/datasources/reorder- Reorder data sources
GET /api/scenes/[sceneId]/scorecards- List scene scorecardsPOST /api/scenes/[sceneId]/scorecards- Add scorecard to sceneGET /api/scene-scorecards/[id]- Get scene scorecard detailsPUT /api/scene-scorecards/[id]- Update scene scorecardDELETE /api/scene-scorecards/[id]- Remove scorecard from scenePOST /api/scene-scorecards/[id]/collect-data- Trigger data collectionGET /api/scene-scorecards/[id]/results- Get scorecard resultsPOST /api/scene-scorecard-results/[resultId]/flag- Flag a result
GET /api/sse- Server-Side Events endpointPUT /api/boards/[id]/presence- Update user presencePOST /api/boards/[id]/timer- Start/vote on timerDELETE /api/boards/[id]/timer- Stop timerPOST /api/timer/vote- Vote on timer extension
GET /api/admin/performance- Get performance metrics (admin only)POST /api/admin/performance- Reset performance metrics (admin only)GET /api/admin/performance/history- Get historical performance data (admin only)GET /api/admin/performance/timeseries- Get time series data (admin only)
GET /api/health- Health check endpointGET /api/templates- Get available board templates
The application uses Server-Side Events streamed on the same port as the web application for real-time updates:
card_created- New card added to boardcard_updated- Card content or properties changedcard_deleted- Card removed from boardcard_moved- Card moved between columnscards_grouped- Multiple cards grouped together
vote_changed- Vote count updated on cardcomment_added- New comment added to cardcomment_updated- Comment content changedcomment_deleted- Comment removedagreement_toggled- Agreement status changed on commentvoting_stats_updated- Facilitator voting statistics changed
scene_changed- Meeting phase changedboard_updated- Board settings or metadata changedcolumns_updated- Column configuration changedupdate_presentation- Present mode display updated
user_joined- User joined boarduser_left- User left boardpresence_update- User activity changed (includes presence_data)presence_ping- Server ping to maintain presence
timer_update- Timer status changedtimer_started- Timer startedtimer_stopped- Timer stoppedtimer_vote- Vote cast on timer extension
scorecard_data_collected- Scorecard data collection completedscorecard_result_added- New scorecard result available
Core Retrospective:
- Authentication (password + WebAuthn/passkey)
- Board series organization with role-based access
- Real-time card creation, editing, and voting
- Multi-phase meeting workflow with scene management
- Card grouping and organization
- Comments and agreements on cards
- Facilitator controls and voting dashboard
- SSE-powered real-time collaboration
- Timer system with extension voting
- Presence tracking with ping/pong
- Action item tracking with rollover
- Board cloning and templates
- Card notes with locking
Data Collection & Analysis:
- Scorecard system with RPN formula evaluation
- Scene-based scorecard execution
- Multi-source data collection
- Results tracking and flagging
- Time series visualization
Administration:
- Performance monitoring dashboard
- Real-time metrics tracking
- Slow query detection
- Historical data retention (7 days)
- Rate limiting for auth/resource endpoints
Infrastructure:
- SQLite and PostgreSQL support
- Database migration system
- Docker deployment
- Digital Ocean App Platform support
- Health check endpoints
- Automated PostgreSQL migrations via drizzle-kit push (use generate + migrate instead)
- Template scene option values not fully populated
- Direct navigation to linked board after registration
User Experience:
- Scene-based tutorial popups
- Enhanced responsive design for mobile
- Rich text editor for card content
- Drag-and-drop card reordering within columns
- Keyboard shortcuts
Features:
- Anonymous/guest user board access
- AI-powered card grouping suggestions
- Action item assignment to specific users
- Export board data (PDF, CSV, JSON)
- Board archiving and search
Security & Integration:
- CSRF protection
- SSO/OAuth integration
- Two-factor authentication (TOTP)
- Audit logging
- API rate limiting per user
Performance:
- Redis for session storage (horizontal scaling)
- CDN integration for static assets
- Database query optimization
- Connection pooling for PostgreSQL
Built according to CLAUDE.md development guidelines emphasizing explicit over implicit code, libraries over custom solutions, and human-maintainable architecture.
MIT License. See LICENSE file for details.
The DiceBear avatar style Adventurer is a remix of: Adventurer by Lisa Wischofsky, licensed under CC BY 4.0.