Der Hintergrund-Takt aus dem letzten Commit funktionierte in der Praxis nicht:
im Netzwerk-Mitschnitt stapelten sich Anfragen und wurden abgebrochen
("cancelled"). Die Ursache ist nicht Langsamkeit, sondern ein Rate Limit —
Etherpads `importExportRateLimiting` ist serienmäßig an und lässt 10 Abrufe je
90 s und IP zu; der Takt wollte 36. Jenseits davon antwortet die Gegenseite
nicht mit 429, sondern hält die Verbindung ohne Antwort offen. Nachgemessen:
12:48:12 Abbruch nach 25 s (0 Bytes)
Abbruch nach 25 s (0 Bytes)
12:50:23 HTTP 200 nach 0,436 s <- nach ~40 s Pause
Zwei Minuten totgestellt, dann sofort in 0,4 s da. Gegen eine Drosselung kann
ein Takt nicht gewinnen, er erzeugt sie. Also ein Knopf. Damit entfallen
Stabilitätstakt, Sichtbarkeits-Wächter, Anti-Stapel-Riegel und Wiederanlauf.
Der Knopf greift zudem gut mit "Was ist neu?" (D28) zusammen: drücken, und was
seither in Produktion ging, leuchtet auf.
Verhindern UND melden, beides:
- Mindestabstand 10 s zwischen zwei Abrufen. Das ergibt höchstens 9 je 90 s und
bleibt damit beweisbar unter Etherpads Budget — die Drosselung wird gar nicht
erst ausgelöst. Nach einem Abbruch sind wir schon drüber: dann das ganze
Fenster (90 s) abwarten statt weiter dagegen zu rennen.
- Der Knopf bleibt in der Sperre **klickbar** (nur `aria-disabled`, nicht
`disabled`): Ein Klick meldet den Grund und nennt die Grenze samt Restzeit.
Die Meldung landet in `#warn`, das eine Live-Region ist, wird also angesagt.
Ein `disabled` erklärt nichts.
- Eigener Warnungstyp `sourceTimeout` für den Abbruch: `sourceLoad` zeigt auf
CORS und schickte hier auf die falsche Fährte.
- `setPadBusy()` dreht das Symbol während des Abrufs — das können bis zu 20 s
sein, und ohne Zeichen wirkt der Knopf kaputt.
Zwei Fehler des Vorgänger-Commits fielen dabei auf:
- `padSource` und der Takt standen HINTER dem `await` des ersten Abrufs. Ein
einziger Fehlschlag — bei dieser Gegenseite der Normalfall — ließ das Dokument
tot liegen, ohne Knopf und ohne Wiederversuch, bis zum Neuladen der Seite.
Genau das war die vom Nutzer gemeldete Fehlermeldung.
- Kein Erfolg räumte die Warnung des ersten Versuchs weg; sie hätte gestanden,
während der Text längst da war.
Dazu: `deleteDoc()` beendet die Pad-Quelle, sonst legte ein späterer Abruf das
gelöschte Dokument wieder an und aktivierte es auch gleich.
Nebenbefunde, beide nachgemessen und in D31 festgehalten:
- Das *Tippen* im Etherpad-Editor war der letzte offene Punkt. Der Nutzer hat
` - [ ] Layout` eingerückt eingetippt; der Export gibt es zeichengenau
zurück (vier echte Leerzeichen, kein Tab, kein Listen-Markup).
- Einbetten verweigert der Server nicht: kein `X-Frame-Options`, keine CSP mit
`frame-ancestors`, und im Versuch baute das Pad in einem fremdstämmigen Rahmen
seine Editorframes auf. Preis ist `SameSite=Lax` am Autoren-Cookie (jedes
Laden ein neuer Autor; nur serverseitig zu beheben) und der Verlust beider
Richtungen von D25, falls das Textpanel ersetzt wird.
86 Tests (85 -> 86); Schreibschutz zeigt den Text jetzt in Tinte statt grau —
hier wird gelesen, der Plantext ist der Hauptinhalt.
105 lines
4.6 KiB
Plaintext
105 lines
4.6 KiB
Plaintext
%% Werkbaum, planned with Werkbaum — what exists today and where it could go.
|
|
%% Distilled from docs/ROADMAP.md, docs/TASKS.md and docs/DECISIONS.md.
|
|
|
|
[~] Werkbaum (XXL) https://github.com/mhoennig/werkbaum
|
|
- [^] Notation (L)
|
|
- [^] Line format (M)
|
|
- [^] Status box, eight states (S)
|
|
- [^] T-shirt size and the "decompose from M" rule (S)
|
|
- [^] People tags, bare URLs, %% comments (XS)
|
|
- [^] And/or decomposition (S)
|
|
- [x] Optional nodes — neither required nor an alternative (S)
|
|
- [-] A separate storage format for the structure (L) %% the text is the format
|
|
- [ ] Ticket references #123 (S)
|
|
- [?] Benefit per node, not only cost (M)
|
|
| [?] Another sigil next to the size (S)
|
|
| [?] Story points behind the T-shirt sizes (M)
|
|
- [~] Editor (XL) https://werkbaum.javagil.de
|
|
- [^] Live diagram from text (M)
|
|
- [^] Parser (S)
|
|
- [^] Renderer, three layout modes (M)
|
|
- [^] Horizontal fan (S)
|
|
- [^] Vertical, transposed (S)
|
|
- [^] Compact (S)
|
|
- [^] Cheapest path (M)
|
|
- [^] Cost model, missing size counts as M (S)
|
|
- [^] Metro-map line through the leaves (S)
|
|
- [^] Export (M)
|
|
- [^] SVG and PNG download (S)
|
|
- [^] PNG to the clipboard (S)
|
|
+ [^] Print stylesheet (XS)
|
|
- [^] Nine interface languages (M)
|
|
- [^] Translations (S)
|
|
- [^] Default taken from the browser (XS)
|
|
- [^] Accessibility: aria labels, focus order (S)
|
|
- [^] Works on a phone (S)
|
|
- [^] Several documents in one editor (M)
|
|
- [^] Switcher in the editor title bar (S)
|
|
- [^] Load a document from ?sourceUrl= (S)
|
|
- [^] Jump between diagram and text (S)
|
|
- [ ] Open and save .werkbaum files (S)
|
|
+ [x] Show what is new since your last visit (S)
|
|
+ [?] A pastel colour per person (S)
|
|
- [?] Dates and milestones (M)
|
|
| [?] An attribute in the line (S)
|
|
| [?] A separate timeline view (L)
|
|
- [^] Build and delivery (M)
|
|
- [^] One self-contained file, bundled by Vite (S)
|
|
- [^] Unit tests (S)
|
|
- [^] Published on every push (S)
|
|
- [-] Deploy through a gh-pages branch (S) %% GitHub Actions instead
|
|
- [-] Fonts from Google (XS) %% self-hosted, no third-party request
|
|
- [ ] Backend (XL)
|
|
- [ ] Kotlin and Spring Boot scaffold (M)
|
|
- [ ] Gradle Kotlin DSL, JDK 21 (S)
|
|
- [ ] Health endpoint and CI (S)
|
|
- [ ] Documents on the server (L)
|
|
- [ ] Text plus metadata, no structure format (M)
|
|
- [ ] REST endpoints (S)
|
|
- [ ] Persistence (S)
|
|
- [ ] Share by link (S)
|
|
- [?] Accounts and permissions (L)
|
|
| [?] Single user, one token (S)
|
|
| [?] Log in with OIDC (L)
|
|
- [~] Working together on one plan (XL)
|
|
- [x] Watch a shared Etherpad — it merges, we render (S)
|
|
- [x] Load the pad's plain-text export (XS)
|
|
- [x] Reload on demand (XS) %% a timer only trips Etherpad's rate limit
|
|
+ [?] Embed the pad beside the diagram (M) %% costs the jump to the line
|
|
- [ ] Git as the shared store (L)
|
|
| [ ] A file in a repository, changed by pull request (S) %% works today, no code
|
|
| [?] The backend commits every change (L)
|
|
- [?] History and restore (M)
|
|
- [?] Diff between two versions (S)
|
|
- [?] Who changed this line (S)
|
|
- [?] A branch per scenario (S)
|
|
- [?] Live editing, several people at once (XL)
|
|
- [ ] Transport over a websocket (S) %% the easy half
|
|
- [!] Merging simultaneous edits (L) %% the actual work
|
|
| [?] Text CRDT — the plan is plain text, so it fits (L)
|
|
| [?] Operational transformation (XL)
|
|
- [?] Cursors and who else is here (S)
|
|
- [-] A merge algorithm of our own (XL) %% solved problem, do not reinvent
|
|
- [?] Mermaid plugin (XL)
|
|
- [!] A layout engine of its own (XL) %% measure, place, route — the real work
|
|
- [ ] Measure node sizes (M)
|
|
- [ ] Text metrics without a browser (S)
|
|
- [ ] Badges and tags inside the box (S)
|
|
- [ ] Place nodes and route connectors (L)
|
|
- [ ] All-of fan (M)
|
|
- [ ] Horizontal (S)
|
|
- [ ] Transposed (S)
|
|
- [ ] Any-of rail (S)
|
|
- [?] Registration with Mermaid (M)
|
|
| [?] External diagram, self-hosted pages only (M)
|
|
| [?] Pull request into Mermaid itself (L)
|
|
- [?] Tracker integration (XL)
|
|
| [?] Taiga (L) https://taiga.io
|
|
- [ ] Resolve #123 over the REST API (M)
|
|
- [ ] Read title, link and status (S)
|
|
- [ ] Map the workflow onto the states (S)
|
|
- [?] Write the status back (M)
|
|
- [-] A plugin inside Taiga itself (L) %% legacy frontend, self-hosted only
|
|
| [?] Tenzu, the successor (XXL) https://tenzu.net
|
|
| [ ] No tracker, plain text is enough (XS)
|