Skip to content
Serhii Kuznetsov
All projects

06Real-time2026Solo — protocol, worker, interface

Quorum — Planning Poker

Estimation rooms where votes stay hidden on the server until the host reveals them.

Quorum — Planning Poker screenshot

The problem

Nothing in this portfolio showed the hardest thing a front-end developer does: keeping state in step between people. Landing pages and even a full product are, in the end, one browser talking to one server. Planning poker is small enough to finish and rich enough to be interesting — presence, authority, hidden state and reconnection, all in a domain anyone understands in ten seconds.

Decisions

  1. 01

    The server hides the votes, not the interface

    The obvious implementation broadcasts every vote and hides them in the UI — one devtools panel and the round is over. Here the room strips the card value from everyone else's participant until the reveal, so a client that peeks finds nothing. The end-to-end test asserts on the page's HTML rather than on what is visible, because that is the claim being made.

  2. 02

    Presence is the connection, not a list

    Who is in the room comes from the sockets the runtime is actually holding, so there is no join/leave bookkeeping to drift out of step and a closed laptop cannot leave a ghost behind.

  3. 03

    One Durable Object per room

    The room id maps to an object, and that object is the room: no database, no shared table, no locking. Round state lives in its storage and per-person state rides on the socket, so the runtime can hibernate the object between messages and bring it back without dropping anyone.

  4. 04

    Chosen over a managed realtime service

    Free tiers that sleep after a week of inactivity make a poor portfolio demo — a recruiter opening a dead page learns the wrong thing. Durable Objects stay warm on the free plan, and writing the synchronisation myself is the part worth showing; handing it to a library would have removed the project's reason to exist.

  5. 05

    Room codes you can read out on a call

    The alphabet has no vowels, so a generated code cannot accidentally spell something, and none of the characters people confuse when dictating them: no 0/O, no 1/l/I.

  6. 06

    Local green is not green

    Two things passed locally and failed against the deployed worker. The test assumed the host would be whoever connected first — true over loopback, not over the internet, where the join messages arrive in whatever order they arrive. And it reused one room id, while a Durable Object keeps its state, so the second run walked into the first run's revealed round. Both were bugs in the test rather than the server, and only a real deployment surfaced them.

What I measured

2.5 KB

worker, gzipped

the whole synchronisation layer

15

protocol checks

two raw sockets against a real Durable Object

3

two-browser tests

one test driving both sides of the same room

0

cold starts

the room is awake whenever someone opens the link

Before the reveal: your own card is visible, everyone else shows only a tick
The landing page
A room on a phone

Built with

  • Next.js
  • TypeScript
  • Cloudflare Workers
  • Durable Objects
  • Tailwind CSS