Teilen ohne Merge-Konflikt

Product

Früher gehörte ein Notez-Workspace genau einer Person. Seit v0.3.0 können es mehrere sein: Lade jemanden per E-Mail ein, und ihr teilt die Notizen, die Tags, die Boards und den KI-Chat, der auf all das zugreift.

Spannend ist, was ich weggelassen habe.

Die Funktion, nach der alle zuerst fragen

„Können zwei Personen gleichzeitig dieselbe Notiz bearbeiten?“

Im Sinne von Google Docs, mit zwei Cursorn in einem Absatz und Zeichen, die sich beim Tippen ineinanderschieben: nein. Das ist ein wirklich schweres Problem. Es richtig zu lösen bedeutet CRDTs oder Operational Transforms, eine dauerhafte Verbindung pro geöffnetem Dokument und einen Umbau der Art, wie eine Notiz gespeichert wird: nicht mehr als Dokument, sondern als Strom von Operationen, die man nachspielt.

Es ist eine gute Funktion. Sie ist aber auch für sich schon fast ein eigenes Produkt und hätte das Teilen um Monate verzögert, für einen Fall, der in einer Notizen-App selten vorkommt. Menschen schreiben selten gleichzeitig am selben Absatz. Sie schreiben verschiedene Notizen oder dieselbe Notiz zu verschiedenen Zeiten.

Also habe ich für das gebaut, was tatsächlich passiert, und den seltenen Fall sicher gemacht statt nahtlos.

Was tatsächlich passiert

Drei Dinge, aufsteigend nach Wichtigkeit.

Du willst wissen, dass noch jemand da ist. Öffnest du eine Notiz, die eine Kollegin gerade offen hat, erscheint ihr Avatar neben dem Speicherstatus. Er aktualisiert sich alle paar Sekunden und verschwindet etwa eine Minute, nachdem sie die Notiz geschlossen hat.

Das ist bewusst eine Anwesenheitsanzeige und keine Tipp-Anzeige. Sie beantwortet die Frage „Ist gerade noch jemand hier drin?“, nach der du entscheidest, ob du wartest oder loslegst. Technisch ist das ein Redis-Hash pro Notiz mit 60 Sekunden TTL plus Polling, ohne WebSocket und ohne Fan-out an Abonnenten. Die ganze Funktion besteht aus ein paar Dutzend Zeilen, und wenn Redis kurz nicht erreichbar ist, lässt sich die Notiz trotzdem öffnen und speichern.

Du willst wissen, wer etwas geändert hat. Der Speicherstatus zeigt jetzt Bearbeitet von Sam vor 4 Minuten, wenn die letzte Änderung nicht von dir kam, und sonst nur die Zeitangabe. Zusammen mit den 30 Tagen Versionsverlauf, die jede Notiz ohnehin hat, lässt sich die Frage „Wie sah das aus, bevor Sam drangegangen ist?“ beantworten.

Die Angabe, wer bearbeitet hat, war am Ende das, was sich die Leute von der Zusammenarbeit am meisten gewünscht haben, und sie kostet zwei Spalten.

Du willst keine Arbeit verlieren. Darauf kommt es an.

Das Speichern ablehnen

Naives Teilen scheitert leise und vollständig: Du öffnest eine Notiz, bearbeitest sie zehn Minuten lang, speicherst, und deine Fassung ersetzt die, die deine Kollegin vor acht Minuten gespeichert hat. Keine Fehlermeldung. Ihre Arbeit ist einfach weg, und keiner von euch merkt es, bis jemandem in der nächsten Woche ein fehlender Absatz auffällt.

Notez gibt jetzt jeder Notiz eine Versionsnummer. Wenn dein Editor eine Notiz lädt, merkt er sich die Version, die er gesehen hat, und jedes Speichern schickt diese Nummer zurück. Das Update läuft so:

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

Hat in der Zwischenzeit jemand gespeichert, passt die Version nicht mehr, die WHERE-Klausel trifft null Zeilen, und das Schreiben findet nicht statt. Du bekommst ein Banner, das nennt, wer die Notiz geändert hat, und einen Button Neu laden.

Das wichtige Detail: Die Prüfung steckt in der WHERE-Klausel und nicht in einer if-Anweisung davor. Bei „erst prüfen, dann schreiben“ gibt es ein Zeitfenster zwischen Prüfung und Schreiben. Es ist klein, aber genau wenn zwei Speichervorgänge im selben Augenblick ankommen, muss die Prüfung halten. Ist die Version Teil der Update-Bedingung, entscheidet die Datenbank atomar, und wer als Zweiter schreibt, verliert.

Verlieren ist hier das richtige Ergebnis. Die Alternative zum Ablehnen wäre, zu raten, wie man zwei Fassungen eines Absatzes kombiniert, und falsch geraten ist schlimmer als ein ehrlicher Fehler, weil falsch Geratenes so aussieht, als hätte es funktioniert.

Was ich bewusst nicht gebaut habe

  • Keine Berechtigungen pro Notiz. Zugriff gilt pro Workspace. Wer eingeladen ist, kann alles darin lesen, auch den Papierkorb. Berechtigungen pro Notiz bedeuten eine Prüfung auf jedem Lesepfad, eine Oberfläche, um sie zu verwalten, und Supportanfragen von Leuten, die nicht herausfinden, warum eine Notiz unsichtbar ist. Brauchst du eine Grenze, leg einen zweiten Workspace an: Workspaces kosten nichts und sind vollständig voneinander getrennt.

  • Keine Kommentare. Ein Kommentar-Thread ist ein kleines soziales Netzwerk. Nicht jetzt.

  • Keine Live-Cursor. Siehe oben.

  • Keine Abrechnung pro Platz. Mitglieder brauchen keinen eigenen Plan. Die Plätze kommen aus dem Plan des Eigentümers: 3 bei Free, 10 bei Pro, 25 bei Ultra, und alles, was der Workspace speichert, wird auf das Kontingent des Eigentümers angerechnet.

Wo die Grenze verläuft

Geteilt wird pro Workspace, und Workspaces waren in Notez schon vorher die Isolationsgrenze: Der KI-Chat sieht nur den aktuellen, und ein MCP-Schlüssel ist an genau einen gebunden. Das bleibt auch beim Teilen so: Lädst du eine Kollegin in Arbeit ein, bekommt sie nichts aus Privat, nicht in der Suche, nicht über die KI, nicht über einen Schlüssel.

Das setzt der Server bei jeder Anfrage durch, und deshalb habe ich den Workspace als Einheit fürs Teilen gewählt, statt eine neue zu erfinden.

Wenn du bisher alles in einem einzigen Workspace hattest und jetzt einen Teil davon teilen willst, verschieb diese Notizen zuerst in einen eigenen Workspace und lade dann ein.


Details stehen in Einen Workspace mit anderen teilen. Alles, was mit dieser Version erschienen ist: v0.3.0.

Weiterlesen