Skip to content
NORTH CRESTVENTURES
← Back to our work

Work Management · Live Board

A board that refuses work at the limit

One ordered operation log feeds both the live WebSocket and the catch-up endpoint. Nothing broadcasts from two places.

Book a Demo

The problem

A shared kanban board has two failure modes that look nothing alike but have the same root cause: state that is duplicated instead of derived. If a live board broadcasts changes from more than one place, a client that misses a message has no way to find out what it missed. And WIP limits are usually a suggestion rendered in the UI — a number in a corner of a column that anyone can ignore by dragging anyway, which means the limit teaches a team nothing.

The build

Every mutation funnels through a single emit helper that appends to an append-only operation log with a monotonic per-board sequence, then publishes that one entry over the board's WebSocket room. The same log is what a disconnected client replays from, so live updates and catch-up are the same mechanism rather than two implementations that can disagree. Fan-out prunes dead sockets inline — a socket whose send raises is dropped from the room and the survivors are written back, rather than waiting for a disconnect event that may never arrive. Undo is deliberately a separate mechanism from the op log: a shadowed history table snapshots the before and after of title and column on every change, and undo restores from the newest row then deletes it, so undo is one step and repeatable. WIP limits are enforced as a domain decision, not a UI hint — pulling into a full column is refused with a real 409 at the service layer, and the override is gated on the actor's role. The backend is feature-sliced around a shared kernel, and the Next.js frontend talks to FastAPI through a same-origin /api proxy so the browser never makes a cross-origin call.

  • One append-only op log with a monotonic sequence drives both broadcast and replay
  • WIP limits refused as a domain-layer 409, with a role-gated override path
  • Undo via a before-image history table, separate from the op log and one step deep

The outcome

Live sync and catch-up cannot drift because there is only one log. The WIP refusal is a domain-layer 409 rather than a disabled button, and card edits are recoverable one step at a time. Known gaps, stated plainly: the client does not yet issue the catch-up request on reconnect, the manager override is implemented in the service layer but the router does not yet pass the user through, and the card checklist and comment endpoints exist in the service layer without HTTP routes wired to them.

Next step

See the receptionist, or scope a build.

Book a demonstration of the AI receptionist, or tell us about a custom project. You get a real reply either way.