Real-time collaborative whiteboard with AI-assisted sticky note organization.
Whiteboard Collab combines a modern canvas UI, low-latency multi-user synchronization, and an ML microservice that groups sticky notes by semantic similarity.
Teams need a fast way to brainstorm together without losing structure. This project provides:
- Real-time board collaboration with live presence and cursor sharing
- Role-based board access and collaborator management
- Undo/redo history with Redis-backed snapshots
- AI Auto-Organize for sticky notes (semantic clustering)
- Docker-first local and production workflows
- Create, update, delete, and share boards
- Public board read endpoints for view-only access
- Real-time element create, update, delete, and bulk update events
- Active users list and live cursor positions
- Keyboard-friendly interactions (undo/redo, selection, delete)
- Board clear action restricted to privileged roles
- Auto-Organize sticky notes by semantic similarity
- Configurable layout mode (preserve proximity or aggressive organize)
- Backend caching of cluster results in Redis
- Circuit-breaker and graceful degraded fallback when ML is unavailable
- Request validation and strict rate limiting for AI endpoints
- API and socket event rate limits
- Role checks on board operations
- Strict payload validation with Zod and Pydantic
- Health and readiness probes for service monitoring
- CI checks with path-based job filtering
The system uses a service-oriented architecture:
- Frontend: Next.js app with Fabric.js canvas, Zustand state, and Socket.IO client
- Backend: Express + Socket.IO gateway, Prisma ORM, Redis integration, board/auth/AI APIs
- ML service: FastAPI service for semantic clustering using sentence-transformers + scikit-learn
- Data layer: MySQL for persistence, Redis for caching, presence, and history stacks
- Edge: Nginx reverse proxy for HTTPS, API routing, and WebSocket upgrade
- User performs an action in the canvas.
- Frontend emits socket events and/or calls REST APIs.
- Backend authenticates, validates, checks permissions, and persists state.
- Backend broadcasts real-time updates to board room participants.
- AI requests are proxied by backend to ML service with service-token auth.
- Frontend: Next.js 16, React 19, TypeScript, Fabric.js, Zustand, Vitest
- Backend: Node.js, Express 5, TypeScript, Socket.IO, Prisma, Jest, Supertest
- ML service: Python 3.11, FastAPI, sentence-transformers, scikit-learn, pytest
- Infrastructure: Docker Compose, Nginx, GitHub Actions, AWS EC2 deployment
.
├── backend/
│ ├── prisma/
│ ├── src/
│ └── tests/
├── frontend/
│ ├── app/
│ ├── components/
│ ├── hooks/
│ └── store/
├── ml-service/
│ ├── app/
│ └── tests/
├── docker/
├── nginx/
├── docker-compose.yml
├── .env.example
├── dev.sh
├── run-tests.sh
└── stop.sh
cp .env.example .envOpen .env and set secure values for at least:
MYSQL_ROOT_PASSWORDMYSQL_PASSWORDJWT_SECRETML_SERVICE_KEYNEXT_PUBLIC_API_URLNEXT_PUBLIC_WS_URL
docker compose up --build -dcurl http://localhost:4000/health
curl http://localhost:5000/ready- Application:
http://localhost
This mode is useful when iterating quickly on one service.
- Node.js 20+
- npm
- Python 3.10+ (3.11 recommended)
- MySQL 8
- Redis 7
cd backend
cp .env.example .env
npm ci
npx prisma generate
npx prisma migrate deploy
npm run devcd frontend
cp .env.local.example .env.local
npm ci
npm run devcd ml-service
python -m venv venv
./venv/bin/pip install -r requirements-dev.txt
./venv/bin/uvicorn app.main:app --host 0.0.0.0 --port 5000 --log-level info./dev.shRoot .env (for Docker Compose) contains the most important runtime settings.
MYSQL_ROOT_PASSWORDMYSQL_USERMYSQL_PASSWORDJWT_SECRETJWT_EXPIRES_INFRONTEND_URLML_ENABLEDML_TIMEOUT_MSML_SERVICE_KEYNEXT_PUBLIC_API_URLNEXT_PUBLIC_WS_URL
AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYAWS_REGIONS3_BUCKET
Important: NEXT_PUBLIC_* values are compiled into the frontend bundle at build time.
POST /api/auth/registerPOST /api/auth/loginPOST /api/auth/logoutGET /api/auth/profilePATCH /api/auth/profile
GET /api/boardsGET /api/boards/:idGET /api/boards/:id/elementsPOST /api/boardsPATCH /api/boards/:idDELETE /api/boards/:idPOST /api/boards/:id/collaborators
GET /api/public/boards/:idGET /api/public/boards/:id/elements
POST /api/boards/:id/ai/cluster
GET /health
board:joinboard:leavecursor:moveelement:createelement:updateelements:bulk_updateelement:deleteelement:undoelement:redoboard:clear
room:usersuser:joineduser:leftcursor:updateelement:createdelement:updatedelement:deletedelement:snapshotboard:clearedhistory:stateerror
- Frontend collects sticky notes from board state.
- Backend verifies board permission (editor/admin), validates payload, applies AI rate limit.
- Backend checks Redis cache for prior clustering result.
- On cache miss, backend calls ML service with
ML_SERVICE_KEY. - ML service creates embeddings and computes K-Means clusters.
- Backend returns suggestions to frontend preview modal.
- User accepts or rejects suggested layout.
Failure mode:
- If ML is slow/unavailable, backend returns degraded response that preserves current positions.
Run all tests from project root:
./run-tests.shRun service-specific tests:
cd backend && npm test
cd frontend && npm test
cd ml-service && ./venv/bin/python -m pytest tests- GitHub Actions workflow runs on push/PR
- Path filter skips unaffected jobs
- Backend: type check, lint, tests, Prisma migrate deploy
- Frontend: type check, tests, production build
- ML service: targeted pytest suites
- Deploy workflow triggers after successful CI on
main - SSH deploy to AWS EC2
- Builds images, applies Prisma migrations, starts services with Docker Compose
- Performs health checks and attempts rollback on failure
- Ensure
NEXT_PUBLIC_API_URLandNEXT_PUBLIC_WS_URLare correct in.env - Rebuild frontend image after changing these values
- Check
ML_ENABLED=true - Verify
ML_SERVICE_KEYmatches in backend and ml-service - Check ML readiness endpoint:
GET /ready
- Confirm Nginx includes WebSocket upgrade for
/socket.io/
- Verify
DATABASE_URLand MySQL credentials - Run migrations in backend container or local backend
- Never commit secrets or private keys
- Use strong random values for
JWT_SECRETandML_SERVICE_KEY - Keep TLS certificates secure in production environments
- Restrict destructive board actions to trusted roles
- Create a feature branch
- Implement and test changes
- Run service tests locally
- Open a pull request with a clear description
See LICENSE if present in this repository.