Commit Graph
397 Commits
Author SHA1 Message Date
mhoennigandClaude Opus 5 063d2c947b docs(scripts): push-github.sh nennt nicht mehr CORS als Grund für den Klon (D96)
Deploy to GitHub Pages / build (push) Canceled after 0s
Deploy to GitHub Pages / deploy (push) Canceled after 0s
Der Kopfkommentar behauptete noch, Gitea sende kein
Access-Control-Allow-Origin. Seit D96 tut es das; übrig bleibt GitHub Pages.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 19:23:04 +02:00
mhoennigandClaude Opus 5 3cafc92d49 docs: Beispiel-Links laden aus dem eigenen Gitea (D96)
Deploy to GitHub Pages / build (push) Canceled after 0s
Deploy to GitHub Pages / deploy (push) Canceled after 0s
git.javagil.de sendete auf raw-Dateien kein Access-Control-Allow-Origin,
weshalb die ?sourceUrl=-Beispiel-Links nach dem Umzug (D95) auf dem
GitHub-Klon bleiben mussten. Der Header ist jetzt auf mih09 gesetzt:
Giteas [cors]-Abschnitt deckt nur /api/v1 ab, die Web-raw-Route bekommt
ihn im Apache davor. Die Links zeigen nun auf origin.

Nebenbei: "Werkbaum selbst" war schon vorher tot (example-werkbaum.werkbaum
existiert nicht, die Datei heisst werkbaum.werkbaum) und ist mit korrigiert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 18:31:37 +02:00
mhoennigandClaude Opus 5 29a217f892 chore(repo): Umzug nach Gitea — GitHub bleibt Klon, main von Hand gespiegelt (D95)
Deploy to GitHub Pages / build (push) Canceled after 0s
Deploy to GitHub Pages / deploy (push) Canceled after 0s
Zuhause ist künftig git.javagil.de/mi/werkbaum (origin); GitHub bleibt unter
dem Remote `github` ein Klon, den scripts/push-github.sh mit `main` versorgt —
nur vorwärts, nie erzwungen.

Der Klon bleibt aus zwei gemessenen Gründen: Gitea sendet auf raw-Dateien kein
Access-Control-Allow-Origin (nachgemessen an mi/werkdock), die
?sourceUrl=-Beispiellinks der READMEs müssen also auf raw.githubusercontent.com
zeigen; und der Pages-Workflow lässt sich nicht mitnehmen.

Footer, llms.txt und llms.md zeigen jetzt auf Gitea (Repo-Seite ohne Anmeldung
lesbar, HTTP 200 geprüft); beide COMMIT_URL-Stellen (deploy-prod.sh und der
Pages-Workflow) ziehen mit. deploy-prod.sh prüft origin und github getrennt und
erinnert an das Spiegeln, statt selbst zu pushen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 17:26:15 +02:00
mhoennigandClaude Fable 5.1 736e9c1d88 docs(rfc): RFC 003 — Knoten im Text verschieben, als Bauanleitung für einen Coding-Agenten
Zwei Knöpfe in der Editor-Titelzeile und Alt+↑/↓ verschieben den Block des
Knotens der Cursor-Zeile (Zeile, \-Fortsetzungen, "-Beschreibungen,
Teilbaum) vor den vorherigen bzw. hinter den nächsten Geschwisterknoten —
als reine Text→Text-Regel neben setFoldMark/expandShortIds, ein Undo-Schritt
über writeAt, ohne neue Editor-Komponente. Das RFC legt Blockgrenzen,
Nachbarsuche, Zusammensetzen, Verdrahtung, i18n, 15 Testfälle samt
Mutations-Gegenproben, Browser-Nachmessung und die nachzuziehenden Dokumente
(SPEC §9, CHANGELOG, D95, Plan-Knoten #ed.move) fest. Nichts gebaut.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 16:12:31 +02:00
mhoennigandClaude Opus 5 5e72cd873f build(ci): Gradle-Wrapper ins Repo — ohne ihn baut kein frischer Klon das Backend
`.gitignore` schloss `backend/gradlew`, `gradlew.bat` und `gradle/wrapper/`
aus (40db415). Lokal fiel das nie auf, weil die Dateien unversioniert im
Arbeitsverzeichnis liegen — auf der Werkator-Instanz scheiterte der erste
Build sofort mit `/bin/sh: 1: ./gradlew: not found`.

Der Wrapper ist der vereinbarte Weg, eine Gradle-Version festzuschreiben
(9.1.0); die Sandbox hat kein eigenes Gradle, und `!gradle-wrapper.jar`
stand in derselben Datei bereits als Ausnahme zur `*.jar`-Regel — die drei
Ignore-Zeilen widersprachen ihr.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 14:12:54 +02:00
Michael Hönnig 828d961a8b Merge pull request #2 from mhoennig/werkator-ci
Werkator CI
2026-09-03 13:02:51 +02:00
mhoennig ac4a06bd18 Merge remote-tracking branch 'origin/main' into werkator-ci 2026-09-03 12:56:45 +02:00
mhoennigandClaude Opus 5 3ccff12cfd ci(werkator): .werkator.yml — Werkbaum wird zusätzlich von Werkator gebaut
Werkator ist ein deklaratives CI (https://werkator.javagil.de): Die Datei im
Repo-Root beschreibt die Builds, der Watcher der Instanz baut jeden Push auf
jedem Branch. Zwei Builds, wie die beiden Teile des Monorepos: `backend`
(Gradle-Tests, Artefakt sind die Berichte unter backend/build/reports) und
`frontend` (npm ci, Vitest, Vite-Bundle als frontend/dist). Das `default`
trägt bewusst keinen Trigger — es ist nur die Einstellungsbasis, damit nichts
doppelt läuft.

Beide Befehle laufen wörtlich so, wie sie in der Datei stehen, lokal durch:
Backend BUILD SUCCESSFUL in 1m35s mit 180 Testfällen (jacoco- und
Test-Berichte liegen im deklarierten Artefakt-Verzeichnis), Frontend npm ci +
628 Tests + Vite-Bundle nach frontend/dist/index.html (761 kB).

Die Sandbox hat Node 20.19, lokal läuft 22.17 — deshalb zusätzlich die
`engines`-Angaben aller installierten Pakete geprüft: Keines schließt 20.19
aus; die schärfsten Schranken sind vite 8.1.5 (^20.19.0 || >=22.12.0) und
jsdom 29.1.1 (^20.19.0 || ^22.13.0 || >=24). 20.19.0 ist damit exakt die
Untergrenze — wer eine Abhängigkeit aufnimmt, die darüber liegt, bricht den
CI-Build (Anleitung).

Werkator baut und testet nur; deployt wird weiterhin über scripts/deploy-*.sh
bzw. tools/remote (D77), und der GitHub-Pages-Workflow bleibt unberührt —
beide CI laufen parallel, bis das Repo nach Gitea umzieht. Die Footer-Version
setzt nur der Pages-Workflow (D16), das Werkator-Artefakt trägt sie nicht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 11:54:18 +02:00
Michael Hönnig 04cc154567 Merge pull request #1 from mhoennig/rfc-002-mehrfenster
RFC-002 verbesserte Mehrfenster Absicherung
2026-09-03 11:49:07 +02:00
mhoennigandClaude Opus 5 2d78baf407 fix(editor): „nur ansehen" gilt jetzt dem Dokument, nicht nur dem Textfeld — auch das Diagramm faltet dort nicht mehr
Nutzer-Einwand, folgerichtig aus dem Vorgänger-Commit: Wenn Falten eine
Änderung ist, muss der Nur-Ansehen-Modus auch das Diagramm stillstellen —
im haltenden Fenster natürlich weiter nicht.

Es war schlimmer als eine fehlende Sperre: `readonly` hielt gar nichts auf.
`replaceTextUndoable` fällt auf `src.value = neu` zurück, wenn `execCommand`
scheitert, und eine Zuweisung an `value` schreibt auch in ein
schreibgeschütztes Feld. Nachgemessen: Ein Klick auf das Falt-Zeichen im
Nur-Ansehen-Fenster setzte `- > Ast A (M)` in Textfeld UND Speicher — der
Modus war nur eine Beschriftung.

Gesperrt wird jetzt an der Schreibstelle: eine Zeile in
`replaceTextUndoable` weist jeden programmatischen Schreibzugriff ab
(Falten, Durchschalter, „aus Taiga übernehmen", früherer Stand,
ID-Kurzform). Dazu ruhen die Gesten selbst, damit nichts still ins Leere
geht — toggleFold und der Durchschalter kehren früh um, Falt-Zeichen und
Knopf treten zurück und nehmen keinen Klick an (body.viewonly), und im
Knoten-Fenster entfallen die Aktionen, die in die Zeile schreiben.
„Nach Taiga schreiben" bleibt: Es fasst den Plan nicht an. Ansicht bleibt
Ansicht — Zoom, Modus, Pfad, Export, Sprünge unverändert bedienbar.

Nachgemessen mit zwei Fenstern: Chip, Tastatur und Durchschalter lassen im
Nur-Ansehen-Fenster Text und Speicher unangetastet; im haltenden Fenster
faltet dieselbe Geste weiter; verlässt es das Dokument, wird das andere von
selbst wieder beschreibbar und faltbar. SPEC §9, D94-Nachtrag 3 und
CHANGELOG nachgezogen; 666 Tests grün.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 20:28:20 +02:00
mhoennigandClaude Opus 5 2a58951138 fix(i18n): die Zwei-Fenster-Warnung nennt die zuletzt gespeicherte Änderung, nicht den letzten Tastendruck
Nutzer-Rückfrage: „Was für ein letzter Tastendruck?" — die Formulierung
liest sich, als zähle nur Tippen. Tut es nicht: Umklappen im Diagramm
schreibt die Faltmarke in den Text (D38-Nachtrag 2) und damit in den
Speicher, nimmt also am selben Wettlauf teil. Nachgemessen mit zwei
Fenstern: A klappt zu, im Speicher steht `- > Ast A (M)`, B's Editor und
Diagramm bleiben unverändert — und B's nächster Tastendruck überschreibt
den Speicher, A's Faltung ist weg.

Beide Texte in allen neun Sprachen umformuliert (tabConflictWarn,
docLockText); der Dialogtext nennt das Falten ausdrücklich. SPEC §9 sagt
jetzt dazu, dass das andere Fenster nichts nachzieht und dass ein
Dokumentwechsel dort nicht mitwandert — `werkbaum-active` entscheidet erst
wieder, was ein Neustart öffnet (auch das eine Nutzer-Rückfrage,
nachgemessen). D94-Nachtrag 2 und CHANGELOG nachgezogen.

Benannt, nicht behoben: Wer „trotzdem hier bearbeiten" gewählt hat, behält
die Warnung, auch wenn das andere Fenster das Dokument längst verlassen
hat — dieser Ausweg fordert die Sperre bewusst nicht mehr an.

666 Tests grün; die neuen Texte im laufenden Editor nachgesehen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 20:21:29 +02:00
mhoennigandClaude Opus 5 7f4c2a3e6a fix(editor): der Sperr-Dialog wählt das andere Dokument im Aufklapp-Feld — die Knopfliste quetschte ihre Beschriftungen ineinander
Gemeldet aus der produktiven Instanz: „die Buttons mit den anderen
Dokumenten überlappen sich und sind unleserlich". Ursache ist eine
Flexbox-Falle, nicht die Zahl der Dokumente: Die Liste war ein
flex-Spaltenkasten mit max-height 9rem, und ihre Knöpfe tragen serienmäßig
flex-shrink 1 — statt zu scrollen, schrumpfte der Kasten sie unter ihre
eigene Textzeile. Nachgemessen bei acht Dokumenten: 14,5 px Kastenhöhe
gegen 32 px Inhalt, 17,5 px Überstand je Knopf bei 4 px Abstand.

Statt der naheliegenden Reparatur (flex-shrink 0, dann scrollt die Liste)
das vom Nutzer gewählte Aufklapp-Feld: eine Zeile hoch, unabhängig von der
Anzahl — der Dialog steckt im Editor-Panel und ist dort ohnehin knapp. Die
Kopfzeile ist jetzt ein echtes <label for>, der Platzhalter ein Strich,
die Auswahl schaltet sofort um (dieselbe Ein-Klick-Geste wie der Knopf).
Kein neuer i18n-Schlüssel.

Nachgemessen: Feld 36 px, kein Überstand, Karte 364 -> 256 px; Auswahl
schaltet um, Dialog schließt, Textfeld wird beschreibbar. D94-Nachtrag und
CHANGELOG nachgezogen; 666 Tests grün.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 20:16:58 +02:00
mhoennig 4bb9b768b0 docs: Werkbaum-Plan — 5 Knoten in Produktion
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):

- #ed.docs.windows: Two windows on one storage: app and tab side by side (M)  %% docs/rfc/002-mehrfenster.md, D94
- #ed.docs.windows.keys: Every document owns its keys — text, meta, states; the index never deletes
- #ed.docs.windows.sync: The storage event keeps the list, names and tombstones current in every window
- #ed.docs.windows.lock: A per-document lock via the Web Locks API finds the one real loss case (S) :#ed.docs.windows.keys
- #ed.docs.windows.dialog: Three exits instead of continue anyway: open another, view only, edit anyway (XS) :#ed.docs.windows.lock
2026-09-02 20:10:20 +02:00
mhoennigandClaude Opus 5 e411927695 VERSION 1.2 — die Dokument-Ablage hat ein neues Format
Bewusster Bump-Commit nach D16. Anlass ist nicht die Zahl der Commits,
sondern dass sich das Format geändert hat, in dem der Editor Dokumente im
Browser hält (Schema v3, RFC 002 / D94): Text, Name und frühere Stände
liegen je Dokument unter eigenen Schlüsseln, der Index ist nur noch
Reihenfolge-Hinweis und löscht nie, Löschungen hinterlassen einen
Tombstone. Die Migration läuft einmalig beim Laden und ist idempotent;
ein Rückbau auf einen älteren Build findet die Dokumente über den Index.

Sichtbar wird das als Mehr-Fenster-Betrieb: installierte App und
Browser-Tab arbeiten nebeneinander, ohne sich gegenseitig Dokumente zu
löschen, und der modale Zwei-Fenster-Dialog (D89) ist einer Sperre je
Dokument gewichen.

Die Micro-Stelle beginnt damit wieder bei 0 (D16).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 20:09:51 +02:00
mhoennigandClaude Opus 5 94ee0f20e5 docs(spec): §9 — der Zeilenumbruch trennte live: von seinem Bindestrich
Der Absatz zum Mehr-Fenster-Betrieb brach nach dem Code-Span um, sodass
"`live:`\n-Dokumente" gerendert als „live: -Dokumente" dastand — der
Bindestrich sah aus wie ein Gedankenstrich am Zeilenanfang. Nur neu
umbrochen, kein Wort geändert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 20:08:17 +02:00
mhoennigandClaude Opus 5 da872f795c docs(changelog): die Planungszeile zum Mehr-Fenster-Betrieb entfällt — sie stand neben dem gebauten Ergebnis
Der 2026-09-02 trug beide Aussagen zur selben Sache: die vier Zeilen „geht
jetzt" und darunter noch „recorded as planned … before it is built" aus dem
RFC-Commit desselben Tages. Im Neuigkeiten-Popup (D58) liest sich das
widersprüchlich — der Leser sieht ein Feature, das zugleich fertig und
geplant ist. Die Planungszeile geht, weil das Gebaute mehr sagt; die
MCP-Planungszeile daneben bleibt stehen, die ist wirklich noch ungebaut.

Ein Test liest die ausgelieferte Datei (news.test.js), 666 Tests grün.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 20:07:42 +02:00
mhoennigandClaude Opus 5 caaf7c15e1 feat(editor): Mehr-Fenster-Betrieb gebaut — Ablageschema v3, Tombstones, docsync, Sperre je Dokument (RFC 002, D94)
Kein Fenster schreibt mehr den Schlüssel eines anderen: Text, Meta und
frühere Stände liegen je Dokument unter eigenen Schlüsseln, der Index ist
nur noch Reihenfolge-Hinweis und löscht nie, Löschungen hinterlassen einen
Tombstone (7 Tage). Der Voll-Flush weicht dem Dirty-Flush. Damit sind
Befund 2 und 3 des RFC weg — verschiedene Dokumente in zwei Fenstern
kollidieren gar nicht mehr. docsync.js zieht Liste, Namen, Tombstones und
den Stände-Cache aus dem storage-Ereignis nach; am aktiven Dokument die
drei Fälle umbenannt / anderswo gelöscht (behalten, bis getippt wird) /
fremd geschrieben. Der modale D89-Dialog samt Präsenz-Kanal ist ersatzlos
raus; den einen Verlustfall — dasselbe nicht-`live:`-Dokument in beiden
Fenstern vorn — findet eine Sperre per Web Locks, und das zweite Fenster
bekommt drei Auswege statt „trotzdem fortfahren".

Im Browser mit zwei echten Tabs nachgemessen (RFC §10): Fälle 1–8 grün,
Fall 1 im Vor-v3-Build gegengeprüft und dort nachweislich rot. Fall 9
deckte auf, dass reviveGoneDoc() den Index-Hinweis nicht mitschrieb — ein
durch Tippen wiederbelebtes Dokument hing bis zum nächsten Flush allein an
seinen eigenen Schlüsseln und wäre bei einem Rückbau auf einen Build vor
v3 still verlorengegangen; behoben, Gegenprobe per Mutation gezogen.
Headless 666 Tests grün. Offen bleibt die Handarbeit: PWA neben Tab,
Firefox, Safari, ein Browser ohne Locks-API.

SPEC §9, D94, D89-Nachtrag, RFC (Status, §10, Revisionsgeschichte),
CHANGELOG und Plan-Knoten #ed.docs.windows nachgezogen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 20:07:20 +02:00
mhoennigandClaude Fable 5.1 112ada4e58 docs(rfc): Mehr-Fenster-Betrieb (PWA + Tab) — RFC 002, Plan-Knoten #ed.docs.windows, D94 (revidiert D89)
Der modale Zwei-Fenster-Dialog (D89) verbietet den Fall, der funktioniert
(dasselbe geteilte Dokument in App und Tab), und schützt nicht vor dem,
wovor er warnt: Der Voll-Flush löscht Dokumente und Stände des anderen
Fensters. Entschieden: je Dokument eigene Schlüssel, Tombstones, Sperre je
Dokument per Web Locks, Dialog mit drei Auswegen. Nichts gebaut.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 12:57:22 +02:00
mhoennigandClaude Fable 5 1f186eddce docs(rfc): MCP-Server nur im Backend, kein Node als Laufzeit — dritte Runde; Hausregel: neue Technologie braucht ausdrückliche Zustimmung
Nutzer-FYI: Node.js einzuführen ist eine Dimension schwerer als eine
Backend-Abhängigkeit und muss dem Entwickler deutlich gemacht werden —
als Regel in CLAUDE.md. Aus den nachgefragten Beweggründen folgt: kein
lokaler Prozess. Der MCP-Server lebt im Backend (Streamable HTTP,
Bearer-Token), führt die Frontend-Module per GraalJS aus, jedes Werkzeug
hat eine text- und eine document-Form; das Node-Paket ist verworfen,
seine Tool-Schicht lebt als frontend/src/inspect.js, guard.js, edit.js.
Backend-Abhängigkeiten GraalJS + Spring-AI-Starter zugestimmt; der
GraalJS-Spike steht vor allem anderen. RFC neu geschrieben (§12 hält die
drei Runden fest), Plan-Teilbaum #ai.mcp neu, D93-Nachtrag.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-02 10:04:11 +02:00
mhoennigandClaude Fable 5 62807b91a1 docs(rfc): MCP-Server — zweite Runde: Urheber im Spiegel-Commit, Streamable HTTP im Backend per GraalJS (Spike vorbehalten), Bearer-Token, nur Dokumente
Der erste Entwurf nahm an, MCP erzwinge Node; tatsächlich erzwang es nur
der Parser. Das Backend darf den HTTP-Transport tragen, wenn es die
JS-Module per GraalJS ausführt (dieselbe Technik wie #idea.drift.js) —
Kotlin ist Transport und Zugang, die Logik bleibt einmal vorhanden;
Rückfall ist der Node-Dienst hinter Apache. Urheber im Git-Spiegel:
Historie im Rumpf plus Trailer statt git --author, damit blame nicht lügt.
Entscheidungen in RFC §11 und D93 (zweite Runde).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-02 09:39:06 +02:00
mhoennigandClaude Fable 5 1e9cc93cb9 docs(rfc): MCP-Server für KI-Agenten — RFC 001, Plan-Knoten #ai.mcp, D93 (festgelegt, nichts gebaut)
Ein Node-Paket, das die headless-Module des Frontends unverändert
importiert (kein zweiter Parser, D14), den Plan als Ressource und Tools
anbietet (Baum, Warnungen, günstigster Pfad, Knoten-Verben) und
Änderungen als Zeilen-Diff mit Basisversion schreibt (D76); Leitplanken:
keine beschädigte Notation, kein [^] von einem Agenten. Geteiltes Dokument
und Git zugleich: nach jedem Agenten-Zug committet der Server über
pull-doc --git-commit (D88). Entscheidungen der Multiple-Choice-Runde in
RFC §11 und D93.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-02 09:25:02 +02:00
mhoennigandClaude Fable 5 aa6ca85bdf fix(diagram): umgeklappter Knoten behält seine Position im Bild — Scrollstand zieht nach (D38-Nachtrag 5)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 20:21:03 +02:00
mhoennigandClaude Fable 5 0fe4c07851 feat(diagram): Knoten-Fenster öffnet nur noch auf Klick, nicht mehr bei Hover (D92, SPEC §6/§9)
Der einfache Klick toggelt das Fenster überall — wie der Tipp auf Touch
(D52); der Link eines Knotens ist damit auch am Zeiger der ↗-Knopf im
Fenster, Enter und Strg+Klick öffnen die URL weiterhin direkt. Tastatur-
fokus öffnet nur noch echten (:focus-visible), focusout schließt nicht in
das Fenster hinein, und die Fokus-Rückgabe nach dem Falten ruft das
Fenster ausdrücklich nie.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 16:43:01 +02:00
mhoennigandClaude Opus 5 a223e6af57 fix(taiga): Knoten-Fenster-Knöpfe in einer Zeile — tipwide, Öffnen-Knopf in der Aktions-Zeile (D91-Nachtrag 12)
Eine gemeinsame flex-wrap-Aktions-Zeile für Schreiben/Übernehmen/Öffnen in
der Ticket-Box; mit Taiga-Knöpfen wird das Fenster auf 31rem breiter
(gemessen an den deutschen Labels), umgebrochen wird nur bei echtem
Platzmangel. Der Öffnen-Knopf heißt nur noch «{ref} öffnen» — «in Taiga»
sagen die Nachbarknöpfe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 13:01:25 +02:00
mhoennig 3984e91106 docs: Werkbaum-Plan — 1 Knoten in Produktion
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):

- #trk.link: Link an existing ticket to a node (S) :#trk.resolve.read
2026-08-28 12:48:41 +02:00
mhoennigandClaude Opus 5 1a33ebdac8 feat(taiga): Ticket verknüpfen — URL/Ref-Feld mit Betreff-Bestätigung (D91-Nachtrag 11)
Ein Knopf im Knoten-Fenster bindet ein bestehendes Taiga-Ticket an den
Knoten: Die eingefügte Ticket-URL trägt Slug, Typ und Nummer selbst; eine
nackte Nummer wird per Probe Story-dann-Task aufgelöst. Verknüpft wird erst
nach Anzeige des Betreffs; geschrieben werden Ref-Token und ggf.
&taiga.<slug> in einem Undo-Schritt, der geholte Stand füllt den
Ticket-Cache. Eine URL einer fremden Instanz wird benannt statt verknüpft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 12:48:32 +02:00
mhoennig ce657e74c1 docs: Werkbaum-Plan — 3 Knoten in Produktion
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):

- #trk.bulk: Diverging tickets show up in the diagram (M) :#trk.resolve.read
- #trk.bulk.proxy: One request fans out into by_ref queries server-side
- #trk.bulk.mark: A diverging ref turns amber on its node
2026-08-28 11:44:42 +02:00
mhoennigandClaude Opus 5 a1e4a3bbab feat(taiga): Bulk-Abfrage und Abweichungs-Marke — das Diagramm zeigt, wo Ticket und Plan auseinanderlaufen (D91-Nachtrag 10, SPEC §9)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 11:44:33 +02:00
mhoennig e77a4d1ce4 docs: Werkbaum-Plan — 1 Knoten in Produktion
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):

- #trk.create.task: A dialog-free "create task" under a story ancestor (S) :#trk.create.tasks,#trk.resolve.read
2026-08-28 11:08:26 +02:00
mhoennigandClaude Opus 5 0ed30e9eae feat(taiga): Anlage-Knöpfe neu geschnitten — ein Story-Knopf mit Dialog, dialogfreie Task unter einem Story-Vorfahren (D91-Nachtrag 9)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 11:08:13 +02:00
mhoennig 4f6d45045a docs: Werkbaum-Plan — 1 Knoten in Produktion
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):

- #trk.write: Write the status back (M) :#trk.resolve
2026-08-27 22:20:45 +02:00
mhoennigandClaude Fable 5 323e8fe0ba feat(taiga): Status zurückschreiben — zwei Knöpfe, niemand gewinnt von selbst (D91-Nachtrag 8, SPEC §9)
Weicht der Ticket-Status von der Statusbox ab, markiert das Knoten-Fenster
die Abweichung und bietet beide Richtungen ausdrücklich an.

- „nach Taiga schreiben": Spalte des Projekts suchen (Taiga schreibt nach Id,
  die Namen sind je Projekt frei) und mit der zuletzt GELESENEN `version`
  patchen — hat jemand dazwischen geändert, lehnt Taiga ab und der Text steht
  im Fenster, statt dass etwas überschrieben wird.
- „aus Taiga übernehmen": `setStatusBox()` schreibt die Box in die Textzeile,
  undo-fähig wie jede andere Änderung.
- Schreibbar sind nur die fünf abgebildeten Zustände; `[?]`, `[!]`, `[-]` und
  der neutrale Knoten lassen das Ticket unangetastet — mit Begründung im
  Fenster.
- Proxy: zwei Spaltenlisten (`/taiga/{userstory,task}-statuses?slug=`) und
  zwei Schreib-Endpunkte (`PATCH …/{ref}/status?slug=`); die Zielspalte wählt
  der Editor, das Backend parst die Notation nicht (D14).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 22:18:52 +02:00
mhoennigandClaude Fable 5 4e6f98bbee docs: Status-Rückschreiben festgelegt — zwei Knöpfe statt einer Richtung, nur die fünf abgebildeten Zustände (D91-Nachtrag 7, SPEC §11)
Die offene Frage von #trk.write ist entschieden, gebaut ist nichts: Weicht
der Ticket-Status von der Statusbox ab, wird die Abweichung markiert und mit
zwei ausdrücklichen Aktionen angeboten — nichts geschieht von selbst.
Verworfen sind „der Text gewinnt" (schreibt selbsttätig in ein fremdes,
geteiltes System) und „Taiga gewinnt" (schriebe fortlaufend im Notationstext,
gegen D14); „Zeitstempel entscheidet" ist ohne erfundene Metadaten gar nicht
baubar.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 22:00:20 +02:00
mhoennig 990632ddcf docs: Werkbaum-Plan — 1 Knoten in Produktion
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):

- #trk.resolve.read: Read title, link and status
2026-08-27 20:43:09 +02:00
mhoennigandClaude Fable 5 842e89795a feat(taiga): Ticket-Stand im Knoten-Fenster — gelesen, nie geschrieben (D91-Nachtrag 6, SPEC §9)
Wo eine Ref steht und ein `&taiga.<slug>` gilt, zeigt das Knoten-Fenster
Betreff, Status und Zuständigen des Tickets; Taigas Statusname steht neben
der Statusbox der Notation (`In progress → [~]`).

- Proxy: zwei benannte Lese-Endpunkte (`GET /taiga/userstories/{ref}` und
  `…/tasks/{ref}`, je `?slug=`) — das Präfix der Ref trägt den Typ, Taiga
  hat getrennte `by_ref`-Endpunkte. Erst `/projects/by_slug`, dann `by_ref`
  (eine Ref ist nur je Projekt eindeutig); der Slug wird kodiert angehängt.
- Die Abbildung Status → Statusbox liegt im Editor (`mapTaigaStatus`,
  headless): Statuscodes sind Notation, das Backend parst sie nicht (D14).
  Unbekannte Namen bleiben unabgebildet — Raten hieße, dem Knoten eine
  Aussage zu geben, die niemand gemacht hat.
- Geholt wird erst nach 400 ms Verweilen und je Ticket einmal je Sitzung
  (↻ holt neu); ohne Anmeldung gar nicht — der Knopf meldet erst an.
- Nichts wird geschrieben: kein Text, keine Statusbox (das bleibt
  `#trk.write`).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 20:41:21 +02:00
mhoennig e58f71bf90 docs: Werkbaum-Plan — 2 Knoten in Produktion
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):

- #trk.create: Create tickets from nodes
- #trk.open: Open a ticket ref in Taiga (S) :#trk.create.ref,#not.tag.project
2026-08-27 17:30:33 +02:00
mhoennigandClaude Fable 5 eae2ff1ef0 docs: D91-Nachtrag 5 — Ref-Umbruch und Strg+Klick-Öffnen festgehalten; #trk.create bestanden, #trk.open im Plan
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 17:28:36 +02:00
mhoennigandClaude Fable 5 a22c320909 feat(editor): Strg+Klick öffnet eine Ticket-Ref in Taiga (D91, SPEC §9)
Im Text (freistehendes #US-123/#T-1234, D67-Ausschlüsse) wie auf dem
Knoten; das Knoten-Fenster trägt an Refs einen Öffnen-Knopf — der Weg
auf Touch. Adresse aus taigaWeb (/info) + &taiga.slug-Vererbung; in
einem :#…-Token gewinnt weiter der Abhängigkeits-Sprung.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 17:24:20 +02:00
mhoennigandClaude Fable 5 55cade1a65 feat(backend): /info meldet die Taiga-Web-Basis für Ticket-Links (D91)
WERKBAUM_TAIGA_WEB_URL (das Taiga-Frontend, nicht aus der API-URL
ableitbar) kommt als taigaWeb in GET /api/v1/info — ohne Schrägstrich am
Ende, fehlt unkonfiguriert. deploy-backend.sh zieht die Zeile aus der
lokalen .env idempotent in die Server-Umgebung nach.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 17:19:02 +02:00
mhoennigandClaude Fable 5 83eb6ff77f fix(diagram): Ticket-Refs im Label brechen nicht mehr am Bindestrich um (SPEC §9)
Der Browser bricht eine zu breit geratene Zeile an jedem Bindestrich —
aus #US-123 wurde #US-/123 über zwei Zeilen. Eine tref-Spanne mit
white-space:nowrap hält das Token zusammen; labelLines() (Export) misst
ihre Textknoten unverändert mit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 17:14:27 +02:00
mhoennig 3f336db680 docs: Werkbaum-Plan — 7 Knoten in Produktion
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):

- #not.tag.project: (&taiga.slug) assigns the Taiga project, inherited
- #trk.create.proxy: Backend proxy with named endpoints
- #trk.create.login: Log in to Taiga, token stays in the browser (S) :#trk.create.proxy
- #trk.create.project: The project comes from the inherited tag (S) :#not.tag.project
- #trk.create.story: A "create story" action in the node window (S) :#trk.create.login
- #trk.create.tasks: Sub-packages become tasks, picked in a dialog (M) :#trk.create.story
- #trk.create.ref: The ref lands in the line beside the id (S) :#trk.create.story
2026-08-27 16:54:26 +02:00
mhoennigandClaude Fable 5 3ab931d50e docs: D91-Nachtrag 4 — Bau-Entscheidungen der Taiga-Anlage festgehalten
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 16:51:55 +02:00
mhoennigandClaude Fable 5 d1de8758b1 feat(editor): Taiga-Story und -Tasks aus dem Knoten-Fenster anlegen (D91, #trk.create)
Zwei Aktionen im Knoten-Fenster, nur wo GET /info das Feature meldet
(Lebendprobe-Muster, je Basis einmal gecacht) und nur an Knoten ohne
Ticket-Referenz — die Ref an der Zeile ist der Idempotenz-Marker.
Login-Dialog (type=password, kein window.prompt; nur das Token landet
im Browser, 401 fragt neu), Projekt-Dialog vorbelegt aus dem geerbten
&taiga.<slug>, Häkchen-Dialog nach der D91-Vorbelegung; Refs und ggf.
das Projekt-Schlagwort gehen undo-fähig als Tokens an die Zeilen
(appendToken: vor %% und vor der Fortsetzungsmarke). Regeln headless in
taiga.js (15 neue Tests); Deploy zieht TAIGA_API_URL aus der .env als
WERKBAUM_TAIGA_API_URL in die Server-Umgebung nach (Nutzerwunsch).

E2E im Browser gegen Backend + Taiga-Stub gemessen: Buttons nur ohne
Ref, Vorbelegung Kundenprojekt aus geerbtem Tag, Refs #US-/#T- an den
richtigen Zeilen, Erledigtes uebersprungen, abweichende Projektwahl
schreibt &taiga.mi-intern zurueck, Undo/Redo je Schreibzug, falsches
Passwort bleibt als Taiga-Fehlertext im Dialog.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 16:51:10 +02:00
mhoennigandClaude Fable 5 fd0e730656 feat(backend): Taiga-Proxy — vier schmale Endpunkte, Ziel-URL aus der Server-Konfiguration (D91, #trk.create.proxy)
API First: /taiga/auth, /taiga/projects, /taiga/userstories, /taiga/tasks
in der OpenAPI-Spec; TaigaClient/TaigaProperties in
de.werkbaum.integration.taiga. Die API-URL kommt aus
WERKBAUM_TAIGA_API_URL (nie Request-Parameter — SSRF), das Token je
Aufruf im Header X-Taiga-Token (Authorization muessen OpenAPI-Werkzeuge
als Header-Parameter ignorieren) und geht als Bearer hinaus; der Server
speichert nichts und loggt keine Request-Bodies. Taiga-4xx werden samt
_error_message durchgereicht, 5xx/Netz sind 502, unkonfiguriert 503 —
und GET /info meldet das Feature (taiga). Tests gegen aufgezeichnete
Antwortformen auf einem JDK-HttpServer-Stub (statt WireMock: keine neue
Test-Abhaengigkeit, dieselbe Zusicherung); Gegenprobe: ohne den
type-Durchreich faellt genau der benannte Test. check gruen, 93 %
Coverage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 16:33:35 +02:00
mhoennigandClaude Fable 5 5a18505571 feat(notation): Schlagworte &tag gebaut — taiga.<slug> benennt das Projekt je Teilbaum, vererbt (SPEC §1, D91)
SPEC zuerst: §1 Schritt 5b samt Block und Referenz-Regex, §11 auf
'umgesetzt' umgestellt; llms.md nachgezogen. Parser extrahiert
alleinstehende &-Token als node.marks (Zitier-Konvention gilt),
taigaSlugs() in model.js vererbt das taiga.*-Schlagwort wie die
@-Tags beim Engpass. Sichtbar im Tooltip und aria-label (a11yMarks,
9 Sprachen). Plan-Labels mit &-Erwähnungen eingeklammert; 12 neue
Tests, Gegenprobe: ohne Alleinstehend-Anker fallen genau die zwei
Zitier-Tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 16:20:03 +02:00
mhoennigandClaude Fable 5 c712e81970 docs: Mehrprojekt-Pläne — &taiga.slug erbt je Teilbaum, erster &tag-Konsument (D91-Nachtrag 3, SPEC §11)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 14:48:03 +02:00
mhoennigandClaude Fable 5 4c98ec6603 docs: Ticket-Ref zusätzlich zur Knoten-ID, Präfixe US-/T- festgelegt (D91-Nachtrag 2, SPEC §11)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 14:37:08 +02:00
mhoennigandClaude Fable 5 ac484f8104 docs: Taiga-Zielinstanz vermessen — API-Host, ldap-Auth, offenes CORS, OIDC-Vormerker (D91-Nachtrag)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 14:31:49 +02:00
mhoennigandClaude Fable 5 6bbc91e849 docs: Ticket-Anlage aus Knoten festgelegt — Proxy, zwei Aktionen, Häkchen-Dialog (D91, #trk.create)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 14:16:41 +02:00
mhoennigandClaude Fable 5 e3742feffb feat(diagram): Unassigned-Pille zeigt das Sprach-Kürzel — de N.N., en TBD; Langform im Tooltip (D87-Nachtrag)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 13:52:39 +02:00