Sharing without the merge conflict

Product

Notez workspaces used to have exactly one person in them. As of v0.3.0 they can have several: invite someone by email and you share the notes, the tags, the boards, and the AI chat over all of it.

The interesting part is what we left out.

The feature everyone asks for first

"Can two people edit the same note at the same time?"

In the Google Docs sense — two cursors in one paragraph, characters interleaving as they are typed — no. That is a genuinely hard problem, and solving it properly means CRDTs or operational transforms, a persistent connection per open document, and a rewrite of how a note is stored: not a document any more, but a stream of operations you replay.

It is a good feature. It is also most of a product on its own, and it would have delayed sharing by months to serve a case that, for a notes app, is rare. People do not usually write the same paragraph simultaneously. They write different notes, or the same note at different times.

So we built for what actually happens, and made the rare case safe rather than seamless.

What actually happens

Three things, in the order they matter.

You want to know someone else is there. Open a note that a colleague has open and their avatar appears next to the save status. It updates every few seconds and vanishes about a minute after they close the note.

This is deliberately presence, not typing indicators. It answers "is anyone else in here right now?" — the question that makes you either wait or go ahead. It is a Redis hash per note with a 60-second TTL and a poll, no WebSocket, no subscription fan-out. The whole feature is a few dozen lines, and if Redis is briefly unavailable the note still opens and still saves.

You want to know who changed something. The save status now reads Edited by Sam · 4 minutes ago when the last write was not yours, and falls back to a plain timestamp when it was. Combined with the 30 days of version history every note already keeps, "what did this look like before Sam touched it?" is answerable.

Attribution turned out to be the thing people wanted most from collaboration, and it costs two columns.

You do not want to lose work. This is the one that matters.

Refusing the write

The failure mode of naive sharing is silent and total: you open a note, edit for ten minutes, hit save, and your version replaces the one your colleague saved eight minutes ago. Nothing errors. Their work is simply gone, and neither of you finds out until someone notices a missing paragraph next week.

Notez now gives every note a version number. When your editor loads a note it remembers the version it saw, and every save carries that number back. The update runs as:

SQL
UPDATE "Note" SET ... WHERE id = $1 AND "contentVersion" = $2

If somebody saved in the meantime, the version no longer matches, the WHERE clause matches zero rows, and the write does not happen. You get a banner naming who changed it and a Reload button.

The important detail is that the guard lives in the WHERE clause and not in an if statement above it. A check-then-write has a window between the check and the write — small, but two saves landing in the same instant is exactly when you need the guard to hold. Making the version part of the update condition means the database decides, atomically, and the second writer loses.

Losing is the correct outcome. The alternative to refusing a write is guessing how to combine two versions of a paragraph, and a wrong guess is worse than an honest error, because a wrong guess looks like it worked.

What we did not do, on purpose

  • No per-note permissions. Access is per workspace. Everyone invited can read everything in it, including the Bin. Per-note ACLs mean a permission check on every read path, a UI for managing them, and a support burden of people who cannot work out why a note is invisible. If you need a boundary, make a second workspace — they are free and fully isolated.

  • No comments. A comment thread is a small social network. Not now.

  • No live cursors. See above.

  • No seat billing. Members do not need their own plan. Seats come from the owner's: 3 on Free, 10 on Pro, 25 on Ultra, and everything the workspace stores counts against the owner's allowance.

Where the boundary is

Sharing is per workspace, and workspaces were already the isolation boundary in Notez — AI chat only sees the current one, and an MCP key is bound to a single one. That property survives sharing: invite a colleague into Work and they get nothing from Personal, not in search, not through AI, not through a key.

That is enforced on the server, per request, and it is the reason we chose the workspace as the unit of sharing rather than inventing a new one.

If you have been keeping everything in a single workspace and now want to share part of it, move those notes into their own workspace first, then invite.


Details in Sharing a workspace with other people. Everything that shipped: v0.3.0.

Continue reading