Flux Board is a full-stack collaborative canvas app with real-time multi-user editing, Clerk authentication, and MongoDB persistence.
This repository contains both:
- Backend API + Socket.IO server
- Frontend React application
- React 19
- Vite
- React Router
- Clerk (client auth)
- React Flow
- Zustand
- Socket.IO client
- Tailwind CSS
- Node.js + Express
- Socket.IO
- Clerk (server auth)
- MongoDB + Mongoose
- Helmet + rate limiting + CORS hardening
- Cloudinary (thumbnail uploads)
- backend: Express API, Socket.IO, MongoDB models/controllers/routes
- frontend: React app and canvas UI
- Node.js 18+ (recommended 20+)
- npm 9+
- MongoDB Atlas (or compatible MongoDB)
- Clerk app (publishable + secret keys)
- Cloudinary account (for production thumbnail storage)
Backend:
cd backend
npm installFrontend:
cd frontend
npm installBackend:
cd backend
cp .env.example .envFrontend:
cd frontend
cp .env.example .envIf you are on Windows PowerShell and cp is not available:
Copy-Item .env.example .envBackend required values:
- MONGODB_URI
- CLERK_SECRET_KEY
- CLOUDINARY_CLOUD_NAME
- CLOUDINARY_API_KEY
- CLOUDINARY_API_SECRET
Frontend required values:
- VITE_API_BASE_URL
- VITE_CLERK_PUBLISHABLE_KEY
Run backend in terminal 1:
cd backend
npm run devRun frontend in terminal 2:
cd frontend
npm run devOpen:
- Frontend: http://localhost:5173
- Backend health: http://localhost:5000/api/health
- npm run dev: start with nodemon
- npm start: production start
- npm run dev: start Vite dev server
- npm run build: production build
- npm run preview: preview built app
- npm run lint: run ESLint
All routes are under /api and require auth unless dev bypass is enabled in development.
- GET /api/health
- POST /api/users
- GET /api/users/me
- GET /api/users/search
- GET /api/users/:userId
- PUT /api/users/:userId
- DELETE /api/users/:userId
- POST /api/boards
- GET /api/boards/user/all
- GET /api/boards/shared/:collaborationId
- GET /api/boards/:boardId
- PUT /api/boards/:boardId
- DELETE /api/boards/:boardId
- PUT /api/boards/:boardId/thumbnail
- POST /api/boards/collaborator/add
- POST /api/boards/collaborator/remove
- GET /api/collaboration/:boardId/sessions
- PUT /api/collaboration/:sessionId/end
- GET /api/activity/:boardId
- POST /api/activity
Socket server runs on the backend host.
- Client authenticates socket with Clerk token (or guarded dev bypass headers in development).
- Client emits
join_board. - Backend verifies board access and creates/updates active collaboration session.
- Presence is emitted with
presence_updated. - Canvas/cursor events are broadcast to other collaborators in the same board room.
Client emits:
- join_board
- leave_board
- canvas_state_updated
- cursor_moved
- node_added, node_updated, node_deleted, node_moved
- edge_added, edge_deleted
Server emits:
- presence_updated
- canvas_state_updated
- collaborator_cursor
- user_joined
- user_left
- collaboration_error
Runtime:
- NODE_ENV (development or production)
- PORT
- HOST
- PUBLIC_BASE_URL
Database:
- MONGODB_URI
- DB_NAME
- DNS_FALLBACK_SERVERS
Security and network:
- CORS_ORIGINS
- SOCKET_CORS_ORIGINS
- TRUST_PROXY
- JSON_BODY_LIMIT
- RATE_LIMIT_WINDOW_MS
- RATE_LIMIT_MAX_REQUESTS
Clerk:
- CLERK_SECRET_KEY
- CLERK_PUBLISHABLE_KEY
- CLERK_JWT_KEY (optional)
- CLERK_AUTHORIZED_PARTIES (recommended in production)
Cloudinary:
- CLOUDINARY_CLOUD_NAME
- CLOUDINARY_API_KEY
- CLOUDINARY_API_SECRET
Development-only bypass:
- ALLOW_DEV_AUTH_BYPASS
- DEV_AUTH_SHARED_SECRET
- VITE_API_BASE_URL (must include
/api) - VITE_SOCKET_URL (optional if same origin as API)
- VITE_CLERK_PUBLISHABLE_KEY
Development-only bypass:
- VITE_USE_DEV_AUTH_BYPASS
- VITE_DEV_CLERK_ID
- VITE_DEV_EMAIL
- VITE_DEV_NAME
- VITE_DEV_AVATAR
- VITE_DEV_AUTH_SHARED_SECRET
- Set NODE_ENV=production on backend.
- Keep ALLOW_DEV_AUTH_BYPASS=false in production.
- Set strict CORS_ORIGINS and SOCKET_CORS_ORIGINS to your real frontend domain.
- Configure CLERK_AUTHORIZED_PARTIES to your frontend origin.
- Use HTTPS for both frontend and backend.
- Enable TRUST_PROXY if behind reverse proxy/load balancer.
- Provide production Cloudinary credentials.
- Build frontend with
npm run buildand deploy static output. - Start backend with
npm start. - Verify:
- /api/health
- login flow
- board CRUD
- realtime presence and cursor sync
Another process is already using the port. Stop stale node processes and restart backend.
- Verify backend is running and socket auth is successful.
- Ensure both tabs are on the same board.
- Ensure Clerk session is valid and not expired.
- Check backend logs for
Socket authentication failedmessages.
Refresh the client session (hard refresh/sign in again). The client now requests fresh tokens at connection time.
Confirm CORS_ORIGINS and SOCKET_CORS_ORIGINS include the exact frontend origin.
Port 5173 is already in use; this is normal Vite behavior. Use the printed local URL.
- Dev auth bypass is for local development only.
- Never expose dev bypass env variables in production.
- Keep Clerk and Cloudinary secrets server-side only.
- Do not commit
.envfiles.
ISC