Skip to content

Kanban: a board shared with three teammates

You share this board with three simulated teammates. Ada, the product owner, writes new cards into the Inbox. Bo, the developer, pulls them through To do and Doing. Cleo, QA, tests what lands in Review and passes it or sends it back. Each of them works through a client of their own, the same way you do, so every pointer, drag and keystroke you see has gone through datadata. Everything runs in this tab on the in-memory engine, with no backend. They wait until you press Start, so you can look around first. Open it full window, which is the better way on a phone.

  • Triage the Inbox. Drag cards into To do. If you leave the Inbox alone, Bo starts pulling from it himself.
  • Watch the cursors. Every pointer sits on the card it’s over, on every screen. A card someone is carrying fades in its column and travels as a ghost under their pointer.
  • Type together. Open a card Ada is writing and you see her caret in the text. She sometimes joins a card you have open, too.
  • Race for a card. Raise your latency and move a card Bo or Cleo is about to move. One move wins; the other snaps back and says who got there first.
  • Add a field. “Card fields” adds Priority, Estimate or a field of your own to every card. Ada starts filling it in.
  • Go offline. Keep moving and editing cards; it all lands when you come back.

The board is one document, with the cards in a record. A move rewrites one card’s column and index, so you and Bo moving different cards touch different paths, and both land. The index is a fractional index, healed per column: when two cards are dropped into the same slot at once, the schema re-spreads them instead of letting them tie.

A move is a guarded write. It holds only if the card is still where the mover last saw it. When two people move the same card at once, the server takes the first and rejects the second, which rolls back on its own optimistic copy. That is the snap-back. See Conflicts.

Descriptions are Yjs. Each card’s description is a Y.Doc referenced from the card, so two people typing in it both keep their words. The carets are Yjs awareness, carried on a presence channel. Deleting a card deletes its description with it.

Pointers are presence. Each person’s pointer, the card they’re carrying and the card they have open are a presence cell on the board. A pointer is anchored to a card or a column rather than to screen pixels, so it lands on the same card whatever your layout. The teammates read the same presence: they don’t pick up a card someone else is holding.

The schema is a document too. Adding a field writes to the board’s schema document, sys:schema:board. Every client runs with dynamic schemas, so it starts validating cards against the new schema the moment the write arrives. Before that, a card carrying the field is rejected as an unknown field.

  • The teammates are bots, in the same tab. Three people in three browsers would need a server; the demo shows the engine, not a deployment.
  • Fields can’t be removed yet. Removing a field is a schema migration; the demo only adds them.
  • One schema per document type. Every board of a type shares its schema, so per-board fields would mean a type per board.