feat: Etherpad-Anbindung ausgebaut (D78)
D31 lieh sich fuer die Echtzeit-Zusammenarbeit ein Etherpad: Das Pad war die Schreibflaeche, Werkbaum die Ansicht. Richtig fuer den Zeitpunkt - die schwere Arbeit war dort getan, und Werkbaum hatte kein Backend. Jetzt hat es eins (D76), das dasselbe besser und im Editor selbst kann. D31 bleibt stehen: Was dort gemessen wurde, ist der Grund, warum die Anbindung nie gut wurde - Export-Drosselung (10 je 90 s), SameSite=Lax beim Autoren-Cookie, abgelehnter Socket-Upgrade. Uebrig blieb ein Neu-laden-Knopf und ein schreibgeschuetztes Textfeld. Ein alter ?etherpad=-Link meldet sich, statt still nichts zu tun: Der Parameter bleibt erkannt und ergibt die zeilenlose Warnung padGone, die auf ?live= zeigt (neun Sprachen). Geholt wird nichts - nachgemessen geht keine Anfrage mehr an den Pad-Host. Vorhandene Pad-Dokumente bleiben liegen und werden dabei besser: ohne Schreibschutz sind sie bearbeitbar und sammeln fruehere Staende. Mit ausgebaut, weil sie nur der Anbindung dienten: remote.js samt Tests, der Ansichts-Waehler und sein Splitter, der Neu-laden-Knopf samt Drosselungs-Zaehler, die Warnungen sourceTimeout/padRateLimit, elf i18n- Schluessel x 9 Sprachen - und src.readOnly ganz, denn nur Pad-Dokumente haben es gesetzt (mit ihm updateSnapBtn und sieben tote Waechter). Auch #srcArea faellt weg: den Kasten gab es nur, damit Pad-Rahmen und Spiegel sich einen Bereich teilen. ?sourceUrl= bleibt unangetastet - beide teilten sich einen Fetch-Pfad, das war die Stelle, an der nichts verrutschen durfte. Im Plan wird aus dem #col.pad-Zweig (14 Knoten samt der ganzen "Update by itself"-Gruppe) ein verworfener Knoten mit Begruendung; der gemeinsame Zeigefinger wandert als #col.point heraus, denn !!! gilt jedem geteilten Dokument. 196 Knoten, 0 Warnungen. Nebengewinn: Der README bekommt endlich den Abschnitt zu ?live= - den gab es nie, die Einstiegs-Beschreibung stand weiter beim Pad. Nachgemessen im Browser: ?etherpad= zeigt die Warnung ohne Netz-Anfrage, ?sourceUrl= laedt unveraendert und ist beschreibbar, Textfeld und Zahlenstreifen liegen buendig, Legenden-Splitter teilt wie zuvor (954+10+300), Falten und Staende funktionieren. 501 Tests, 946 Zeilen weniger.
This commit is contained in:
@@ -19,6 +19,7 @@ reverse.
|
||||
|
||||
## 2026-08-26
|
||||
|
||||
- The Etherpad integration is gone: collaboration now runs through a Werkbaum backend, and an old `?etherpad=` link says so instead of doing nothing
|
||||
- Plans can live on a Werkbaum backend now: open `?live=<document URL>` and everyone edits the same text, seeing each other's changes without reloading
|
||||
- When two people change the same lines, a bar asks whose version should win — everything else the server merges by itself
|
||||
- The caret stays where you put it when someone else inserts lines above you
|
||||
|
||||
@@ -6660,3 +6660,87 @@ Version), `frontend info` (1.1.162, Commit = HEAD), `backend status`,
|
||||
`backend restart`, `backend backup` samt lokalem Wiederanlauf,
|
||||
`frontend preview` (nichts geschrieben, HEAD unverändert) und die
|
||||
Fehlerpfade (Exit-Code 2 bei unbekanntem Ziel und fehlender Aktion).
|
||||
|
||||
## D78 — Die Etherpad-Anbindung ist ausgebaut
|
||||
D31 lieh sich für die Echtzeit-Zusammenarbeit ein **Etherpad**: Das Pad war die
|
||||
Schreibfläche, Werkbaum die Ansicht. Das war die richtige Entscheidung für den
|
||||
Zeitpunkt — die schwere Arbeit (gleichzeitige Änderungen zusammenführen) war
|
||||
dort seit Jahren getan, und Werkbaum hatte kein Backend. **Jetzt hat es eins**
|
||||
(D76), und das kann dasselbe besser und im Editor selbst. Also raus damit,
|
||||
statt zwei Wege zur selben Sache zu pflegen.
|
||||
|
||||
**D31 bleibt stehen** — Entscheidungen werden nicht gelöscht, sondern
|
||||
fortgeschrieben. Was dort gemessen wurde, gilt weiter und ist der Grund, warum
|
||||
die Anbindung nie gut wurde: Etherpad **drosselt den Export** (serienmäßig 10
|
||||
Abrufe je 90 s und IP), ein Hintergrund-Takt erzeugt die Drosselung, statt sie
|
||||
zu umgehen; das Autoren-Cookie ist `SameSite=Lax` und kommt im eingebetteten
|
||||
Rahmen nicht an, also ist man bei jedem Laden ein neuer Autor; und ein eigener
|
||||
Socket zum Pad wurde von der Gegenseite abgelehnt (D31-Nachtrag, Code 1006).
|
||||
Übrig blieb ein Neu-laden-Knopf und ein schreibgeschütztes Textfeld — die
|
||||
Rückmeldung „funktioniert sowieso nicht gut" ist die ehrliche Zusammenfassung.
|
||||
|
||||
**Was `?live=` besser macht**, in derselben Reihenfolge: Es wird **im Editor
|
||||
geschrieben** statt in einem fremden Rahmen; die Gegenrichtung ist ein offener
|
||||
Abruf statt eines Takts gegen ein fremdes Limit; der Konflikt wird benannt
|
||||
statt versteckt; und der Plantext liegt auf **eigener** Infrastruktur statt auf
|
||||
einem Pad, das jeder lesen kann, der die Adresse kennt.
|
||||
|
||||
**Ein alter Link meldet sich, statt still nichts zu tun.** `?etherpad=` bleibt
|
||||
als **erkannter** Parameter stehen und ergibt die zeilenlose Warnung `padGone`,
|
||||
die auf `?live=` zeigt — in allen neun Sprachen. Der Parameter war geteilt: Wer
|
||||
ihn irgendwo stehen hat (in einer Mail, einem Wiki, einem Lesezeichen), bekäme
|
||||
sonst ein leeres Werkbaum ohne Erklärung. Genau der stille Fehler, den dieses
|
||||
Projekt sonst überall ablehnt (SPEC §4, D59). Es ist bewusst **kein**
|
||||
Rest-Feature: Geholt wird nichts, der Pad-Host sieht keine Anfrage mehr
|
||||
(nachgemessen).
|
||||
|
||||
**Vorhandene Pad-Dokumente bleiben liegen — und werden dabei besser.** Sie sind
|
||||
im localStorage gewöhnliche Dokumente (`{id, name, text, source}`); ohne den
|
||||
Schreibschutz sind sie ab jetzt **bearbeitbar**, sammeln frühere Stände (D54)
|
||||
und lassen sich falten. Ihr Text ist der zuletzt geholte. Nichts wird gelöscht,
|
||||
niemand verliert seinen Plan.
|
||||
|
||||
**Der Schreibschutz verschwindet ganz, nicht nur seine Ursache.** `src.readOnly`
|
||||
wurde ausschließlich von Pad-Dokumenten gesetzt; danach hätten sieben Wächter
|
||||
in Falten, Kurz-IDs, Autovervollständigung und Ständen auf eine Bedingung
|
||||
geprüft, die nie mehr wahr wird — mit Kommentaren, die auf D31 zeigen. Tote
|
||||
Wächter mit veralteter Begründung sind schlechter als keine; ein künftiger
|
||||
Lesemodus braucht ohnehin seine eigene Entscheidung. Mit ihm fällt
|
||||
`updateSnapBtn()` weg: Der Knopf ist jetzt immer da.
|
||||
|
||||
**Eine Layout-Ebene weniger.** `#srcArea` gab es nur, damit Pad-Rahmen und
|
||||
Textspiegel sich einen Bereich teilen konnten, ohne die Legenden-Aufteilung
|
||||
(D26) anzufassen. Ohne Rahmen ist es ein Kasten mit einem Kind. Nachgemessen
|
||||
nach dem Entfernen: `.editor-body` trägt jetzt direkt `srcWrap` · `hintGutter` ·
|
||||
`agenda`, und die drei kacheln die Breite exakt (954 + 10 + 300 px) — der
|
||||
Legenden-Splitter arbeitet unverändert.
|
||||
|
||||
**Mit ausgebaut**, weil sie nur der Anbindung dienten: `remote.js` samt seinen
|
||||
Tests (die Pad-Adressen normalisieren), der Ansichts-Wähler und sein Splitter
|
||||
(`--pcol`/`--prow`), der Neu-laden-Knopf samt Drosselungs-Zähler, die Warnungen
|
||||
`sourceTimeout` und `padRateLimit`, elf i18n-Schlüssel × 9 Sprachen und der
|
||||
Timeout-Parameter von `fetchRemote()`. **`?sourceUrl=` bleibt unangetastet**
|
||||
(D23) — beide teilten sich einen Fetch-Pfad, und das war die eine Stelle, an der
|
||||
beim Schneiden nichts verrutschen durfte.
|
||||
|
||||
**Der Plan sagt es auch.** Im mitgelieferten `werkbaum.werkbaum` wird aus dem
|
||||
`#col.pad`-Zweig (14 Knoten samt der ganzen „Update by itself"-Gruppe, die nur
|
||||
Etherpads Grenze umgehen wollte) **ein** verworfener Knoten `[-] #col.pad` mit
|
||||
Begründung — dieselbe Form, in der dort schon `#bld.ghpages` und `#not.store`
|
||||
stehen. Der eine Knoten, der weiterlebt, wandert heraus: `#col.pad.point` wird
|
||||
`#col.point`, denn der gemeinsame Zeigefinger `!!!` gilt jedem geteilten
|
||||
Dokument, nicht nur einem Pad. Danach 196 Knoten, 0 Warnungen.
|
||||
|
||||
**Nebengewinn: Der README bekommt endlich den Abschnitt zu `?live=`.** Den gab
|
||||
es nie — D76 ist gebaut und dokumentiert (SPEC §9, DECISIONS), aber die
|
||||
Einstiegs-Beschreibung stand weiter beim Pad. Das Ausbauen hätte sonst ein Loch
|
||||
hinterlassen; jetzt steht dort in beiden Sprachen, wie man ein Server-Dokument
|
||||
anlegt, teilt und was bei einem Konflikt passiert.
|
||||
|
||||
**Nachgemessen** im Browser: `?etherpad=…` zeigt die Warnung, und im
|
||||
Netzwerk-Mitschnitt geht **keine** Anfrage an den Pad-Host; `?sourceUrl=` lädt
|
||||
unverändert und das Dokument ist beschreibbar (früher: schreibgeschützt); das
|
||||
Textfeld liegt mit dem Zahlenstreifen bündig (1151 + 20 px), die Zeilennummern
|
||||
sitzen auf ihren Höhen, Pfad und Stationen werden gezeichnet; der
|
||||
Legenden-Splitter teilt wie zuvor. 501 Tests (die 24 Pad-Adress-Tests sind mit
|
||||
`remote.js` gegangen, `padGone` ist dazugekommen).
|
||||
|
||||
+1
-1
@@ -112,7 +112,7 @@ Tastendruck ein Commit); und wer bei einem Backend eigentlich was darf
|
||||
Zu klären ist das Zusammenspiel mit der Update-Anzeige (D45): Sitzt ein
|
||||
Worker vor der Seite, entscheidet **er**, was ausgeliefert wird — „der
|
||||
laufende Build gegen den, den der Server schickt" ist dann nicht mehr
|
||||
dasselbe. Dokumente aus `?sourceUrl=`/`?etherpad=` bleiben naturgemäß
|
||||
dasselbe. Dokumente aus `?sourceUrl=`/`?live=` bleiben naturgemäß
|
||||
online. Im Plan: `#bld.pwa`.
|
||||
- Schlagworte `&tag` mit einer Filter-/Hervorheben-Linse im Diagramm: Der Baum
|
||||
ist genau eine Zerlegung — ein Tag benennt eine Menge von Knoten quer dazu
|
||||
|
||||
+17
-61
@@ -155,7 +155,7 @@ ab, auch außerhalb seines eigenen Teilbaums.
|
||||
|
||||
**Fokusmarke `!!!`** — „schau hier hin": Der Knoten wird im Diagramm
|
||||
hervorgehoben und ins Bild geholt (§9). Gedacht für das gemeinsame Arbeiten an
|
||||
einem Pad (§9, `?etherpad=`): Weil dort niemand den Cursor der anderen sieht,
|
||||
einem Dokument (§9, `?live=`): Weil dort niemand den Cursor der anderen sieht,
|
||||
ist eine Marke **im Text** der einzige Weg, auf eine Stelle zu zeigen — und sie
|
||||
hat etwas, das ein Cursor nicht hat: **alle** sehen dieselbe Stelle.
|
||||
|
||||
@@ -770,59 +770,18 @@ Scheitert das Laden (häufigster Fall: das Ziel sendet keinen
|
||||
`Access-Control-Allow-Origin`-Header, außerdem 404/Netzfehler), bleibt der
|
||||
bisherige Stand stehen und es erscheint eine **Warnung**. Siehe D23.
|
||||
|
||||
### Gemeinsam an einem Pad arbeiten (`?etherpad=`)
|
||||
Für Zusammenarbeit in Echtzeit nimmt der Editor die Adresse eines
|
||||
**Etherpad-Pads** — die Adresse, die im Browser steht, ohne Export-Pfad:
|
||||
`…?etherpad=https://pad.example.org/p/mein-plan`. Werkbaum hängt den
|
||||
Klartext-Export (`/export/txt`) selbst an; ein versehentlich mitgegebener
|
||||
Export- oder `/timeslider`-Pfad wird abgeschnitten.
|
||||
|
||||
- **Das Pad ist die Schreibfläche, Werkbaum die Ansicht.** Alle bearbeiten den
|
||||
Notationstext im Pad, jeder Betrachter sieht das Diagramm mitwachsen. Das
|
||||
Zusammenführen gleichzeitiger Änderungen macht Etherpad; Werkbaum tut es
|
||||
nicht.
|
||||
- Deshalb ist das Textfeld für ein solches Dokument **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.
|
||||
- Das Pad kann **im Editor-Panel eingebettet** werden. Ein Wähler in der
|
||||
Titelzeile schaltet reihum zwischen drei Ansichten: **Pad und Text** (beide,
|
||||
durch einen eigenen **Splitter** frei geteilt — Doppelklick setzt zurück),
|
||||
**nur Pad** und **nur Text**. Die Aufteilung wird für nebeneinander und
|
||||
gestapelt getrennt gehalten und bleibt erhalten.
|
||||
- Der schmal gezogene Textspiegel behält seinen Zweck: Der Sprung zwischen
|
||||
Diagramm und Text (§9) arbeitet auf ihm. In „nur Pad" ist er ausgeblendet —
|
||||
ein Sprung holt ihn dann selbst zurück, so wie er ein zugeklapptes
|
||||
Editor-Panel aufklappt.
|
||||
- Der Rahmen wird **nur geladen, wenn er sichtbar ist**. Ein geladenes Pad
|
||||
verbindet sich und zeigt dich in dessen Anwesenden-Liste; „nur Text" ist
|
||||
damit die Ansicht, die nichts von dir verrät.
|
||||
- Geholt wird **auf Knopfdruck**, nicht selbsttätig: Ein Neu-laden-Knopf neben
|
||||
dem Pad-Knopf holt den aktuellen Stand. Etherpad **drosselt** den Export
|
||||
(serienmäßig 10 Abrufe je 90 s und IP); ein Hintergrund-Takt läuft dagegen an
|
||||
und bekommt am Ende gar nichts mehr. Läuft ein Abruf, dreht das Symbol — bei
|
||||
gedrosselter Gegenseite kann das bis zum Abbruch (20 s) dauern.
|
||||
- Der Knopf greift gut mit „Was ist neu?" (§9) zusammen: drücken, und was seither
|
||||
in Produktion ging, leuchtet auf.
|
||||
- **Name ist die vollständige Pad-URL** (nicht der bloße Pad-Name — zwei Pads
|
||||
gleichen Namens auf verschiedenen Hosts wären sonst nicht zu unterscheiden),
|
||||
wie bei `?sourceUrl=`. Identität und Name leiten sich von der **Pad**-Adresse
|
||||
ab, nicht von der Export-Adresse — derselbe Pad ergibt damit genau ein
|
||||
Dokument, gleich in welcher Schreibweise der Link kam.
|
||||
- `?sourceUrl=` bleibt unverändert: statische Datei, einmal pro Laden geholt.
|
||||
Der eigene Parameter trägt gerade den Unterschied.
|
||||
- Fehler (CORS, 404, Netz) melden sich wie bei `?sourceUrl=`. Ein **Abbruch**
|
||||
wegen Zeitablauf bekommt eine eigene Meldung, die die Drosselung benennt —
|
||||
die `?sourceUrl=`-Meldung zeigt auf CORS und schickte hier auf die falsche
|
||||
Fährte. Scheitert schon der erste Abruf, bleibt der Neu-laden-Knopf sichtbar
|
||||
und holt es nach; ein Neuladen der Seite ist nicht nötig.
|
||||
|
||||
Siehe D31.
|
||||
### Kein Etherpad mehr (`?etherpad=`, entfallen)
|
||||
Der Editor konnte den Notationstext aus einem **Etherpad-Pad** beziehen: Alle
|
||||
schrieben im Pad, Werkbaum zeigte das Diagramm dazu. Das ist **ausgebaut** —
|
||||
`?live=` (unten) kann dasselbe besser, und zwar im Editor selbst. Ein alter
|
||||
`?etherpad=`-Link ergibt heute eine **Warnung**, die auf `?live=` zeigt, statt
|
||||
still nichts zu tun. Siehe D78; die frühere Ausführung steht in D31.
|
||||
|
||||
### Gemeinsam an einem Server-Dokument arbeiten (`?live=`)
|
||||
Liegt der Plan auf einem Werkbaum-Backend, nimmt der Editor dessen
|
||||
Dokument-Adresse: `…?live=https://example.org/api/v1/documents/<uuid>`.
|
||||
Anders als beim Pad (`?etherpad=`) wird hier **im Editor selbst geschrieben**,
|
||||
und alle sehen die Änderungen der anderen, ohne neu zu laden.
|
||||
Geschrieben wird **im Editor selbst**, und alle sehen die Änderungen der
|
||||
anderen, ohne neu zu laden.
|
||||
|
||||
- **Das Textfeld bleibt beschreibbar.** Nach kurzer Ruhe (1,5 s) schickt der
|
||||
Editor die Änderung als Zeilen-Diff; ein offener Abruf hält die Gegenrichtung
|
||||
@@ -852,8 +811,7 @@ Ausrichtungen getrennt erhalten. Die Legende belegt höchstens 85 % des Panels,
|
||||
damit das Textfeld nie ganz verschwindet. Siehe D26.
|
||||
|
||||
### Was ist neu? (Dokumente von außen)
|
||||
Bei Dokumenten, die von außen kommen (mitgeliefert, per `?sourceUrl=` oder
|
||||
`?etherpad=`), wird
|
||||
Bei Dokumenten, die von außen kommen (mitgeliefert oder per `?sourceUrl=`), wird
|
||||
gezeigt, was sich seit dem letzten Besuch getan hat. **„Neu" heißt: neu in
|
||||
Produktion** — ein Knoten trägt jetzt `[^]` und tat es in der zuletzt gesehenen
|
||||
Fassung nicht. Solche Knoten bekommen einen **gelben Strahlenkranz** nach außen
|
||||
@@ -1018,8 +976,7 @@ eigene ID der Zeile.
|
||||
weiter: Sie fängt keine Taste ab, solange sie nichts anzeigt, und Tab rückt
|
||||
bei geschlossener Liste unverändert ein.
|
||||
- **Kein Vorschlag** bei bloßem `#` (das *definiert* eine ID), im Kommentar
|
||||
(`%%`), im Beschreibungsteil hinter `---` und in schreibgeschützten
|
||||
Pad-Dokumenten (§9).
|
||||
(`%%`) und im Beschreibungsteil hinter `---`.
|
||||
- Der Parser sieht nie etwas davon; `llms.md` (§13) bleibt unberührt. Für
|
||||
Screenreader meldet eine höfliche Live-Region die Trefferzahl und den
|
||||
gewählten Eintrag; das Popup selbst ist `aria-hidden`, normales Tippen
|
||||
@@ -1099,13 +1056,12 @@ fokussierten Knoten (WAI-ARIA-Baum-Idiom).
|
||||
angefasst, solange die übrigen Marken den Zustand noch richtig beschreiben —
|
||||
ein von Hand gesetztes `<` bleibt also stehen. Trifft es nicht mehr zu, werden
|
||||
alle Marken neu gesetzt und das `<` dabei aufgelöst.
|
||||
- Wo der Text **nicht beschreibbar** ist — bei einem Pad-Dokument (§9) —, gilt
|
||||
der Eingriff **je Knoten** (Identität = Label-Pfad, wie bei „Was ist neu?“)
|
||||
und **nur für die Sitzung**; ein Dokumentwechsel setzt ihn zurück. Dasselbe
|
||||
gilt für einen Zustand, der sich in Marken gar nicht ausdrücken lässt (etwa
|
||||
weil eine Fokusmarke `!!!` ihren Knoten immer wieder hervorholt): Dann wird
|
||||
lieber nichts geschrieben, als einen Text zu hinterlassen, der etwas anderes
|
||||
sagt als das Bild.
|
||||
- Lässt sich ein Zustand in Marken **gar nicht ausdrücken** (etwa weil eine
|
||||
Fokusmarke `!!!` ihren Knoten immer wieder hervorholt), wird lieber nichts
|
||||
geschrieben, als einen Text zu hinterlassen, der etwas anderes sagt als das
|
||||
Bild. Der Eingriff gilt dann **je Knoten** (Identität = Label-Pfad, wie bei
|
||||
„Was ist neu?“) und **nur für die Sitzung**; ein Dokumentwechsel setzt ihn
|
||||
zurück.
|
||||
- **Für den ganzen Baum** gibt es im Diagramm-Kopf einen **Durchschalter**:
|
||||
Jeder Druck stellt die **nächste** von vier Voreinstellungen her, reihum —
|
||||
1. **ab Größe M abwärts zugeklappt**: jeder Knoten mit Kindern, dessen
|
||||
|
||||
+16
-115
@@ -131,30 +131,10 @@
|
||||
| [?] #be.auth.token: Single user, one token (S)
|
||||
| [?] #be.auth.oidc: Log in with OIDC (L)
|
||||
- [~] #col: Collaborating on a Diagram (XXL)
|
||||
" The pad merges concurrent edits, Werkbaum renders the plan.
|
||||
- [^] #col.pad: Watch a shared Etherpad — it merges, we render (L)
|
||||
- [^] #col.pad.export: Load the pad's plain-text export (XS)
|
||||
- [^] #col.pad.reload: Reload on demand (XS) %% a timer only trips Etherpad's rate limit
|
||||
- [^] #col.pad.embed: Embed the pad, keep the text mirror beside it (M)
|
||||
- [^] #col.pad.views: Three views: pad and text, pad only, text only (S)
|
||||
- [^] #col.pad.split: Splitter between pad and mirror (XS)
|
||||
- [?] #col.pad.cookie: Editing in the frame stops after a while (S) %% SameSite=Lax, see D31
|
||||
| [?] #col.pad.samesite: Ask the admin for cookie.sameSite = None (XS)
|
||||
| [ ] #col.pad.owntab: Live with it: edit in the pad's own tab (XS)
|
||||
- [^] #col.pad.point: A shared pointer: !!! focuses a node for everyone (XS)
|
||||
- [?] > #col.auto: Update by itself, within about 2 s (M)
|
||||
| [?] #col.own: Our own Etherpad beside Werkbaum (L) %% then every setting below is ours
|
||||
- [ ] #col.own.db: Node and a real database in userland (S) %% the flatfile store is not for production
|
||||
- [ ] #col.own.ram: Book the RAM quota for an own daemon (XS)
|
||||
- [ ] #col.own.proxy: Reverse proxy in .htaccess, websockets included (S) %% Mattermost does it, wiki shows how
|
||||
- [ ] #col.own.unit: systemd user unit so it survives a reboot (XS)
|
||||
- [!] #col.own.patch: Keeping a public service patched (S) %% indefinitely, that is the real cost
|
||||
| [?] #col.auto.limit: Admin raises the export rate limit (XS) %% default is 10 per 90 s
|
||||
| [?] #col.auto.plugin: Admin installs a plugin that pushes the text (S) %% postMessage to the page
|
||||
| [?] #col.auto.relay: Our own backend holds one socket and fans out (XXL) :#be.scaffold
|
||||
| [ ] #col.auto.poll: Poll inside the budget, at best every 9 s (S) %% legal, but not 2 s
|
||||
| [-] #col.auto.socket: Our own socket straight to the pad (L) %% measured: upgrade refused
|
||||
| [-] #col.auto.html: Read the pad's HTML instead of the export (M) %% measured: no CORS header
|
||||
" Reading together is solved, changing together too — typing together at the
|
||||
" same instant is the expensive one.
|
||||
- [^] #col.point: A shared pointer: !!! focuses a node for everyone (XS)
|
||||
- [-] #col.pad: Borrow an Etherpad — it merges, we render (L) %% built, then removed, see D78
|
||||
- [ ] #col.git: Git as the shared store (L)
|
||||
| [ ] #col.git.pr: A file in a repository, changed by pull request (S) %% works today, no code
|
||||
| [?] #col.git.auto: The backend commits every change (L) :#be.scaffold
|
||||
@@ -714,8 +694,8 @@
|
||||
#bld.pwa.sw
|
||||
A worker lets the editor start without a network. It is deliberately dumb:
|
||||
navigations go network-first, and the cache only keeps the last version it
|
||||
has seen of the one self-contained file for the offline case. Texts pulled from a URL
|
||||
or a pad pass through untouched and stay online by their nature.
|
||||
has seen of the one self-contained file for the offline case. Texts pulled from
|
||||
a URL or a server pass through untouched and stay online by their nature.
|
||||
|
||||
#bld.pwa.update
|
||||
The feared migration turned out unnecessary: because the worker only
|
||||
@@ -838,96 +818,17 @@
|
||||
machinery. Reading together is solved, changing together mostly is, and
|
||||
typing together at the same instant is the expensive one.
|
||||
|
||||
#col.point
|
||||
Nobody sees anyone else's caret, so a mark in the text is the only way to
|
||||
point at a place — and it has something a caret has not: everyone sees the
|
||||
same spot.
|
||||
|
||||
#col.pad
|
||||
Let an Etherpad do the hard part: it merges concurrent edits, and Werkbaum
|
||||
only renders the result. Borrowed rather than rebuilt.
|
||||
|
||||
#col.pad.export
|
||||
Every pad offers its content as plain text, with the header that lets a
|
||||
foreign page read it. That one endpoint is the entire integration.
|
||||
|
||||
#col.pad.reload
|
||||
Fetching happens on a button press, not on a timer. The export is rate
|
||||
limited, and a timer does nothing but trip it.
|
||||
|
||||
#col.pad.embed
|
||||
The pad in a frame inside the editor, with our own text mirror beside it.
|
||||
The mirror keeps the jumps between diagram and text working, because a
|
||||
foreign frame gives up no access to its content.
|
||||
|
||||
#col.pad.views
|
||||
Pad and text, pad only, text only. Text only is the view that tells the pad
|
||||
nothing about you — a loaded pad announces you in its list of people.
|
||||
|
||||
#col.pad.split
|
||||
A splitter of its own between frame and mirror, remembered separately for
|
||||
side by side and stacked.
|
||||
|
||||
#col.pad.cookie
|
||||
In a foreign frame the pad's author cookie is not sent, so a session can
|
||||
turn read-only after a while. Not fixable from this side.
|
||||
|
||||
#col.pad.samesite
|
||||
One server setting resolves it. Presumes somebody who can change that
|
||||
setting.
|
||||
|
||||
#col.pad.owntab
|
||||
Or live with it: read along in the frame, and write in the pad's own tab
|
||||
where the cookie works.
|
||||
|
||||
#col.pad.point
|
||||
Nobody sees anybody else's cursor across two applications, so a mark in the
|
||||
text is the only way to point at something. It has one thing a cursor
|
||||
hasn't: everyone sees the same spot.
|
||||
|
||||
#col.auto
|
||||
The view should follow the pad by itself, within a couple of seconds. Every
|
||||
route below was measured rather than guessed at.
|
||||
|
||||
#col.own
|
||||
Running the pad ourselves makes every setting below it ours. It also makes
|
||||
every one of them our job.
|
||||
|
||||
#col.own.db
|
||||
The default file store is not meant for production, so a real database and a
|
||||
runtime to host it are the price of admission.
|
||||
|
||||
#col.own.ram
|
||||
A daemon of one's own needs memory booked for it.
|
||||
|
||||
#col.own.proxy
|
||||
Reaching it needs a reverse proxy that passes websockets through as well.
|
||||
|
||||
#col.own.unit
|
||||
And something that starts it again after a reboot.
|
||||
|
||||
#col.own.patch
|
||||
The real cost is not the setup but keeping a public service patched,
|
||||
indefinitely.
|
||||
|
||||
#col.auto.limit
|
||||
The cheapest effective change: raise the export limit on the pad server. Ten
|
||||
fetches per ninety seconds is the default, and the reason a timer fails.
|
||||
|
||||
#col.auto.plugin
|
||||
A pad plugin can push the text to the embedding page. Live, no polling, no
|
||||
limit touched — and nothing to install on our side.
|
||||
|
||||
#col.auto.relay
|
||||
Our own backend holds one connection to the pad and fans out to every
|
||||
viewer. Solves it for everybody at once, and costs a backend.
|
||||
|
||||
#col.auto.poll
|
||||
Staying inside the budget means one fetch every nine seconds at best, shared
|
||||
by everyone behind the same address. Legal, but not two seconds.
|
||||
|
||||
#col.auto.socket
|
||||
Measured and rejected: the pad server refuses the websocket upgrade when it
|
||||
comes from another origin.
|
||||
|
||||
#col.auto.html
|
||||
Measured and rejected: the pad page carries the full text, but sends no
|
||||
header that would let a foreign page read it.
|
||||
Removed. An Etherpad did the hard part for a while: it merged concurrent
|
||||
edits and Werkbaum only rendered the result, borrowed rather than rebuilt.
|
||||
The borrowing is what it cost — a rate-limited export, no writing from here,
|
||||
and an author cookie that a foreign frame never gets. The backend does it
|
||||
better and in our own editor, so this went out again.
|
||||
|
||||
#col.git
|
||||
Keep the plan in a repository. Because it is text, diff, blame, review and
|
||||
|
||||
Reference in New Issue
Block a user