frontend: ?etherpad= — Echtzeit-Zusammenarbeit über ein geliehenes Pad

Werkbaum hat kein Backend, und das eigentlich Schwere an gemeinsamem
Bearbeiten ist das Zusammenführen gleichzeitiger Änderungen — im Plan als
`[!] Merging simultaneous edits` markiert. Etherpad hat das gelöst. Also
geliehen statt nachgebaut: das Pad ist die Schreibfläche, Werkbaum die
Ansicht.

Nachgemessen an pad.hostsharing.net, bevor irgendwas gebaut wurde:
- der Klartext-Export sendet `Access-Control-Allow-Origin: *`,
- das kanonische Beispiel (SPEC §10) kommt byte-identisch zurück,
- der HTML-Export zeigt kein Listen-Markup — Etherpad deutet `-` nicht zur
  Aufzählung um und behält die führenden Leerzeichen.
Das war das Risiko, das die Idee hätte erledigen können. Nicht geprüft ist
das Tippen im Etherpad-Editor selbst (Tab-Einrückung, mögliches
Auto-Bullet); dafür braucht es einen echten Browser.

Eigener Parameter statt `?sourceUrl=`: Die URL, die ein Mensch in der Hand
hat, ist die Pad-URL — `/export/txt` hängt Werkbaum selbst an. Vor allem
aber lizenziert der eigene Parameter das andere Verhalten, sodass D23
unangetastet bleibt: `sourceUrl` heißt weiter „statische Datei, einmal pro
Laden geholt", bestehende Links bekommen kein Polling. Name und id sind die
vollständige Pad-URL (Pad-Namen sind nur pro Instanz eindeutig).

Textfeld schreibgeschützt, Knopf öffnet das Pad: ohne das verschwände
getippter Text beim nächsten Abruf. Schrift bleibt Tinte statt grau — hier
wird gelesen, der Plantext ist der Hauptinhalt.

Drei Riegel im Takt, jeder aus einem echten Fehler:
- `padBusy` — im Netzwerk-Mitschnitt stapelten sich die Abrufe, weil die
  Gegenseite langsamer war als der Takt; eine spät eintreffende alte
  Antwort hätte neueren Text überschrieben,
- Abbruch nach 10 s — sonst bliebe der Riegel bei hängender Gegenseite für
  immer zu,
- `visibilityState` + `visibilitychange` — nicht im Hintergrund abrufen,
  aber bei Rückkehr sofort.
Der Stabilitätstakt übernimmt erst beim zweiten gleichen Abruf, sonst sieht
man die anderen mitten im Tippen.

Die Normalisierung der Pad-Adresse liegt headless in `remote.js`, damit sie
testbar ist (23 neue Tests, 60 -> 83). Im Vorschau-Browser meldet
`visibilityState` „hidden" und HMR lädt bei jeder Quelländerung neu — ein
Reload sieht wie eine geglückte Übernahme aus; nachgewiesen wurde die
Übernahme deshalb mit einem Marker auf `window`, der einen Reload nicht
überlebt.

SPEC §9 zuerst, dann D31, dann Code. Der Plan bekommt den Knoten nach D30
mit `[x]`, nicht `[^]`.
This commit is contained in:
mhoennig
2026-07-30 12:04:22 +02:00
parent cfbbfab54b
commit 3310cab7be
11 changed files with 478 additions and 31 deletions
+26
View File
@@ -91,6 +91,32 @@ GitLab-Raw-Links tun das; ein beliebiger Webserver oft nicht. Scheitert das
Laden, bleibt der bisherige Stand stehen und eine Warnung nennt die Ursache.
Zugelassen sind nur `http`/`https`.
### Zusammen an einem Plan arbeiten (Etherpad)
Für Zusammenarbeit in Echtzeit braucht Werkbaum kein eigenes Backend — es leiht
sich ein **Etherpad**. Angegeben wird die Pad-Adresse, wie sie im Browser steht
(ohne Export-Pfad, den hängt Werkbaum selbst an):
```
https://werkbaum.javagil.de/?etherpad=https://pad.hostsharing.net/p/mein-plan
```
Alle bearbeiten den Notationstext **im Pad**, jeder Betrachter sieht das Diagramm
mitwachsen (Abruf alle 2,5 s; nicht, während der Tab im Hintergrund liegt). Das
Zusammenführen gleichzeitiger Änderungen macht Etherpad — genau darum geht es.
Weil das Pad die Schreibfläche ist, ist das Textfeld hier **schreibgeschützt**;
ein Knopf in der Editor-Titelzeile öffnet das Pad im neuen Tab. Ohne den Schutz
verschwände getippter Text beim nächsten Abruf.
Getestet gegen Etherpad: Der Klartext-Export sendet
`Access-Control-Allow-Origin: *`, und die Notation kommt **byte-identisch**
zurück — führende Leerzeichen, `-`/`+`/`|`, Statusboxen und `%%` überleben
Etherpads Speichermodell, das `-` wird nicht zur Aufzählung umgedeutet.
**Bedenke:** Der Plantext liegt damit auf fremder Infrastruktur, und ein Pad ist
für jeden lesbar, der die Adresse kennt. Siehe `docs/DECISIONS.md` D31.
### Lokal ausführen
Die Editor-Quelle liegt jetzt als ES-Module unter `frontend/src/`, gebündelt mit