projects / 08
drawx
real-time collaborative whiteboard
A real-time collaborative whiteboard. Users sign in with Google, create or join rooms by slug, and draw rectangles, circles, lines, arrows, text and freehand strokes together while chatting. Rooms and strokes persist in Postgres, so anyone can rejoin a board later.
- ws ticket lifetime
- 5min
- ws ticket lifetime
- msg limit per conn
- 50/s
- msg limit per conn
- heartbeat
- 25s
- heartbeat
how it works
- 01
Sign in and join
Users sign in with Google through NextAuth and create or join a room by slug. Opening /room/[slug] checks that the room exists.
- 02
Get a ticket
The page asks /api/ws-token for a ticket: an HS256 JWT valid for 5 minutes that binds the user, the room and their role, with the admin role looked up in the database.
- 03
Connect
The WebSocket server verifies the ticket and the origin before accepting the socket, then tells the room who is connected.
- 04
Draw and chat
Shapes (rect, circle, line, arrow, text, pencil), erases and chat messages are validated and relayed to everyone in the room. Chat sender identity is stamped by the server.
- 05
Persist
Whoever draws or erases a stroke saves it through a debounced, batched queue that retries server errors and flushes when the tab closes, so the board doesn't depend on the admin being online.
design decisions
Short-lived tickets for sockets
The WebSocket server is a separate service. A signed 5-minute ticket lets it trust identity and room access without sharing the web app's session store.
Writers persist their own strokes
Saving from the client that made the change means no single participant has to stay online for the board to be saved.
Limits on both sides
1 MiB per message, 50 messages per second per connection, and shape validation on both the socket and the save API keep one client from flooding a room.
highlights
- 5-minute signed tickets bind user, room and admin role before a socket is accepted
- Reconnects with a fresh ticket and backoff, re-syncs missed strokes, blocks drawing while offline
- 1 MiB message cap and 50 msg/s per connection, shapes validated on both the socket and save API
stack
- next.js
- ws
- postgres
- prisma
- nextauth
- turborepo