Address
Utrecht, Veenendaal

Work Hours
Monday to Friday: 9am to 5pm
Weekend: 10am to 5pm

A personal project: a shared digital board where cards, text, images and video stay in sync across everyone looking at it, with an event sourced Node.js backend and a Vue.js application layer on top.

  • TypePersonal project
  • Period2021
  • RoleSolo full stack build
  • DeliveredRealtime collaborative board
  • Every change lands on every other screen as it is made, not on refresh.
  • Two people can edit the same card at the same time and neither loses work.
  • The board is a stream of what happened rather than a row that gets overwritten, so its state can always be rebuilt and never lands half written.

Context

Teams collect their thinking in the same few shapes: a card, a note, an image, a clip. What they usually lose is not the content but the moment, because the board only updates when somebody reloads it. I built a board where that gap does not exist.

The challenge

The interesting problem is not drawing cards, it is two people touching the same card in the same second. Last write wins throws away work somebody just did, and locking makes the board feel dead. On top of that a board that pushes every keystroke to every client gets expensive fast, in queries and in memory, on both ends of the connection.

What I did

  • Modelled the board as events, rather than as rows to overwrite. Every change is an appended fact, so current state is derived and two edits are two facts rather than a collision.
  • Synchronised over sockets, so a change made anywhere is applied everywhere as it happens, with no polling and no reload.
  • Made concurrent editing safe, by resolving simultaneous edits on one card into a single agreed result instead of letting the last one through.
  • Built the Node.js services underneath, and tuned them for the traffic shape this creates: many small writes and many more reads, held so that neither client nor server pays for every keystroke.
  • Layered a modular Vue.js application over them, structured so a new card type is an addition and not a rewrite. Text, images and video went in that way.

The outcome

  • A board that stays live for everyone on it, including under concurrent edits.
  • An application layer that takes new content types without being reopened.
  • A backend where state is rebuildable from its own history, which is the same property I later built into production event stores.

Technologies used

  • Node.js: The services behind the board and the socket connections into them.
  • Event sourcing: Board state derived from an appended stream of changes.
  • JavaScript: The realtime sync layer shared between client and server.
  • Vue.js: The modular application layer over the services.

If you are weighing event sourcing for something that has to stay live under concurrent use, it is a conversation I enjoy.