feat(paket b): Umbenennen erreicht alle — PATCH /title und RENAMED im Feed (D85)

Backend: PATCH /documents/{id}/title mit expectedVersion (409 bei
veralteter Version, 400 bei leerem/zu langem Titel), neuer ChangeType
RENAMED (strukturell, immer Meilenstein), der Feed stellt den neuen Titel
im Klartext zu (ChangeEvent.title). Unter derselben Stripe-Sperre wie die
Inhalts-Patches; Owner-Vormerkung in der API-Beschreibung. Vier neue
Cucumber-Szenarien, zwei Unit-Tests.

Frontend: Der Zeilen-Stift eines Server-Dokuments benennt über den Server
um (optimistisch, 409-Retry, Rücknahme + Warnung bei Fehlschlag); fremde
Umbenennungen kommen als RENAMED über den Feed in Chip und Menü.
URL-Dokumente verlieren den Stift — ihr Name ist die URL.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-08-27 08:13:25 +02:00
co-authored by Claude Fable 5
parent c438a88344
commit fbe9b1fd22
16 changed files with 380 additions and 12 deletions
+2
View File
@@ -19,6 +19,8 @@ reverse.
## 2026-08-27
- Renaming a shared document now renames it for everyone: the pencil patches the server title, and the change feed hands the new name to every open editor
- URL documents lost their pencil — their name is the URL, and a local name would not survive the next load
- If Werkbaum is open in a second browser tab, a warning says so — both tabs write the same document list, and the last one to save wins
- Reloading a URL document no longer asks — a page reload discards local changes silently anyway, so the question promised a protection that did not exist
- Deleting your last document now says that a fresh example will take its place
+41
View File
@@ -7290,3 +7290,44 @@ richtigen Texte, Abbruch lässt alles stehen; und die Tab-Warnung erschien
durch **echtes** Tippen in einem zweiten Tab (kein synthetisches Ereignis —
das storage-Ereignis kommt nur aus fremden Fenstern). 531 Tests, davon 2 neue
für `isDocKey`.
## D85 — Umbenennen erreicht alle: PATCH /title und das RENAMED-Ereignis
Paket B der Ungereimtheiten-Liste (D84). Der Befund: Umbenennen eines
geteilten Dokuments wirkte nur lokal und war flüchtig — der Server-Titel gilt
für alle (D76), und `adoptLive()` überschrieb den lokalen Namen beim nächsten
Laden. Dasselbe bei URL-Dokumenten, deren Name die URL ist (D23). Entschieden
(Multiple-Choice): der in D76 vorgesehene eigene Weg wird gebaut.
**Backend:** `PATCH /documents/{id}/title` mit `expectedVersion`
abweichende Version ⇒ 409, der Client setzt frisch auf; leerer oder zu langer
Titel ⇒ 400 (die Regeln liegen im `LiveEditingService`, unter derselben
Stripe-Sperre wie die Inhalts-Patches: auch der Titel bumpt die Version, und
prüfen und schreiben gehören zusammen). Die Umbenennung ist ein neuer
`ChangeType.RENAMED` — strukturell, also immer Meilenstein — und der
Änderungsfeed stellt den **neuen Titel im Klartext** zu (`ChangeEvent.title`,
nur bei RENAMED gefüllt): Kein Client braucht einen weiteren Abruf. In der
API-Beschreibung steht die Owner-Vormerkung: Die Aktion wird künftig an das
geplante Owner-Passwort gebunden (`#col.live.owner`), die Bindung kommt als
Berechtigungsprüfung dazu, die Signatur bleibt.
**Frontend:** Der Zeilen-Stift eines Server-Dokuments ruft `renameOnServer()`
optimistisch sofort anzeigen, dann GET (Version) + PATCH; bei 409 einmal mit
frischer Version erneut, bei endgültigem Scheitern kommt der alte Name zurück
und eine Warnung sagt warum. Die Version bumpt ohne Inhaltsänderung, die
Schattenkopie bleibt also gültig. Die übrigen Mitschreiber bekommen die
Umbenennung über `applyRenameEvents()` aus dem Feed — Chip und Menü folgen
ohne Neuladen. **URL-Dokumente verlieren den Stift** (wie Mitgelieferte,
D81-Nachtrag 3): Ihr Name ist die URL; ein lokaler Name würde beim nächsten
Laden überschrieben, und ein Server, den man umbenennen könnte, steht dort
nicht dahinter.
**Nachgemessen** Ende-zu-Ende gegen das lokal laufende Backend: Der Stift am
Server-Dokument benennt um (Server-Titel „Team-Plan X", Version 2, keine
Warnung); eine Umbenennung **von außen** (curl) erreicht den offenen Editor
über den Feed — Chip wechselt auf „Von aussen umbenannt", der Inhalt bleibt
unangetastet. Backend: vier neue Cucumber-Szenarien (gilt für alle und lässt
den Inhalt stehen; Feed samt Titel; veraltete Version ⇒ 409; leerer Titel ⇒
400) und zwei Unit-Tests (RENAMED-Meilenstein; Konflikt schreibt nichts),
BUILD SUCCESSFUL samt Coverage. Werkzeuggrenze wie in D76-Nachtrag 7: Der
Automations-Tab meldet sich dauerhaft als verborgen — der Feed lief nur mit
gestellter Sichtbarkeit.
+6
View File
@@ -154,6 +154,7 @@
- [^] #col.live.upload: Share: put a local plan on the server (S) %% a button in the editor title bar, see D81
- [?] #col.live.cursors: Cursors and who else is here (S)
- [ ] #col.live.owner: An owner password guards managing a shared plan (M) %% returned once on creation, admin can reclaim
- [x] #col.live.rename: Renaming reaches everyone (S) %% PATCH /title + RENAMED in the feed, see D85
- [-] #col.live.ws: Transport over a websocket (S) %% plain HTTP turned out to be enough
- [-] #col.live.own: A merge algorithm of our own (XL) %% solved problem, do not reinvent
- [?] #mmd: Mermaid plugin (XL)
@@ -918,6 +919,11 @@
another browser. Management actions bind to it; an admin with the master
password can still reclaim a document.
#col.live.rename
The title is server metadata, so renaming patches it with a version check
and the change feed hands the new title to every client in plain text. URL
documents lost their pencil instead - their name is the URL.
#col.live.cursors
Seeing where the others are. A by-product of the merge layer rather than a
feature in its own right.