How VoteBoard updates board votes in real time
We broke down board voting over WebSocket: instant results, atomic batch handling for legal validity, and a REMOTE mode with a time window.

“If one director votes yes, everyone else should see it immediately.”
From the user’s point of view, it’s very simple: a director opens the meeting, chooses a voting option, and sees the results update without refreshing the page. No need to ask in chat whether the vote went through. No need to wait for someone to compile the table by hand. In VoteBoard, that was the main expectation: board voting should feel like a shared action, even if the participants are in different places.
The engineering part starts where the result gets legal weight. A vote is not a reaction in a messenger app. It can’t be lost, applied halfway, or shown to one participant before the system has recorded the state.
Instant results via WebSocket
For updates, we built a real-time layer on WebSocket. After a vote is accepted, the system sends an event to connected clients, and the interface updates the results immediately. The user does not rely on polling, does not end up with stale state after a refresh, and does not compare numbers with a neighboring tab.
The important point: here, WebSocket is responsible specifically for delivering the current state to the UI. The decision about whether the vote is accepted stays on the server-side voting logic. First, the action has to pass the meeting rules; only then can it be broadcast to the other participants.
Because of that, we had to carefully separate two expectations:
- the user wants an immediate response;
- the system must not show a result that is not yet considered finalized.
The trade-off is straightforward: updates go out quickly, but only after the operation is accepted. For board voting, that matters more than the illusion of instant feedback in the first few milliseconds.
Batch voting without partial states
Another part is batch voting. In the UI, a director can mark several votes and submit them in a single batch request. For a regular form, we could accept some values, highlight others as errors, and ask the user to fix them. Here, that is not acceptable.
Atomicity is critical for legal validity: the batch is either applied in full, or it is not applied as a set of votes at all. Otherwise, you end up with an awkward scenario: some decisions are already counted, some are not, while the user treated the submission as one action.
A real project detail: the discussion was specifically about what should happen when one item in the batch fails. The most UI-friendly option is to return a status for each item. The safest option for the domain is to record nothing if the whole batch does not pass validation. For VoteBoard, we chose the second option, because the user’s action boundary is the entire submission, not an individual row inside it.
After that, WebSocket also becomes easier to reason about: clients receive the result of the accepted state, not a series of intermediate “three votes saved, one rolled back, two more pending” updates.
REMOTE and the time window
Another mode is the remote REMOTE format. It is used when directors are in different time zones and do not have to vote at the same time. Instead of a shared call, the vote has a time window: within that window, a participant can open it and cast a vote whenever it is convenient.
For the user, this reduces friction: there is no need to coordinate one calendar for everyone at once. For the system, it introduces hard boundaries: voting is available only within the defined interval, and the result must update correctly for those who are already in the interface.
Real-time does not disappear in this mode. If one director votes now, another director who opens the meeting during the same window sees the update. If someone joins later, they get the current state, not a history of manual recalculations.
What the architecture ended up with
In VoteBoard, we tied together three requirements that do not work well on their own:
- WebSocket for instant display of results;
- a batch request for submitting a set of votes in one action;
- atomic application of the batch, because this is legally significant voting;
- the
REMOTEmode with a time window for participants in different time zones.
The main engineering boundary here is the moment when the vote is finalized. Before that, the UI can be responsive, but it must not present unconfirmed state as a result. After that, the event is sent to all connected participants, and the numbers on the screen change without a reload.
That way, the user sees something simple: they press a button — the vote is recorded, and the results update. At the same time, the system checks the voting window, accepts the batch as a whole, and only then broadcasts the new state over WebSocket.