docs: Ticket-Anlage aus Knoten festgelegt — Proxy, zwei Aktionen, Häkchen-Dialog (D91, #trk.create)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-08-27 14:16:41 +02:00
co-authored by Claude Fable 5
parent e3742feffb
commit 6bbc91e849
3 changed files with 109 additions and 1 deletions
+1
View File
@@ -19,6 +19,7 @@ reverse.
## 2026-08-27 ## 2026-08-27
- Creating Taiga tickets from nodes recorded as planned: a story per node from the node window, sub-packages as tasks picked in a dialog, through a backend proxy — the ticket ref comes back as the node id
- The unassigned pill in the people bar shows each language's short form now — German `N.N.`, English `TBD` — with the long wording in the tooltip - The unassigned pill in the people bar shows each language's short form now — German `N.N.`, English `TBD` — with the long wording in the tooltip
- `pull-doc --open` opens the fetched document in IntelliJ IDEA afterwards — also when nothing changed - `pull-doc --open` opens the fetched document in IntelliJ IDEA afterwards — also when nothing changed
- A dead live session now reconnects by itself — unsent text stays in the editor and goes out as a diff once the server answers again - A dead live session now reconnects by itself — unsent text stays in the editor and goes out as a diff once the server answers again
+67
View File
@@ -7821,3 +7821,70 @@ neben der Langform: **Die Pille zeigt das Kürzel, Tooltip und `aria-label`
die Langform** — ein Kürzel, das nirgends aufgelöst wird, wäre nur ein die Langform** — ein Kürzel, das nirgends aufgelöst wird, wäre nur ein
Rätsel. Nachgemessen im Browser: de-Pille „N.N." mit Tooltip Rätsel. Nachgemessen im Browser: de-Pille „N.N." mit Tooltip
„ohne Zuständigen: 29 % …", en-Pille „TBD" mit „unassigned: 29% …". „ohne Zuständigen: 29 % …", en-Pille „TBD" mit „unassigned: 29% …".
## D91 — Ticket-Anlage aus Knoten: Proxy, zwei Aktionen, Häkchen-Dialog — festgelegt, noch nicht gebaut
Evaluation, wie aus einem Werkbaum-Knoten ein Taiga-Ticket wird; entschieden
als Multiple-Choice-Runde, festgehalten als Plan-Knoten (`#trk.create`),
**bewusst ungebaut** — dieselbe Form wie beim Nutzen-Feature (SPEC §11).
**Der Zuschnitt folgt der Kanban-Ansicht, die tatsächlich benutzt wird:**
Dort sind **Stories die Karten**, Tasks stecken darin — und „storyless
tasks" existieren in Taiga zwar (die API erlaubt Tasks ohne `user_story`),
sind aber nur im Sprint-Taskboard in einer Extra-Sektion sichtbar, im Kanban
gar nicht. Also: **eine Story je Knoten, Tasks nur unter einem Knoten, der
schon eine Story trägt.** Taigas Hierarchie endet bei Epic → Story → Task
(Tasks haben keine Subtasks) — die Abbildung eines beliebig tiefen
Werkbaum-Baums ist damit immer ein Schnitt von höchstens drei Ebenen. Das
ist Arbeitsteilung, kein Verlust: Taiga trackt die grobe Arbeit, Werkbaum
die feine Zerlegung. Ein **Epic-Modus** (Knoten als Epic, Kinder als
Stories, Enkel als Tasks) ist erwogen und **zurückgestellt** — ein zweiter
Modus mit eigener UI-Frage; wer ein Epic braucht, wartet auf eine eigene
Entscheidung.
**Zugang: Backend-Proxy mit schmalen, benannten Endpunkten** (auth,
projects, userstories, tasks) — kein transparenter Durchreich-Proxy: Der
wäre ein offenes Relay auf die Taiga-Instanz und bräche den
API-First-Stil des Backends (D76). Die **Taiga-Basis-URL ist
Server-Konfiguration** (env, wie das Master-Passwort, D77), nie
Request-Parameter — die SSRF-Falle naiver Proxies. Das **Token bleibt im
Browser**, der Proxy reicht nur den Authorization-Header durch; das Backend
speichert nichts und braucht kein Konten-Modell (serverseitige Tokens wären
die Ausbaustufe nach dem Owner-Passwort). Der Auth-Endpunkt sieht das
Passwort einmal im Durchflug — Request-Bodies dort nie loggen.
`/api/v1/info` meldet das Feature (`taiga`), der Knopf erscheint nur, wo
ein konfiguriertes Backend antwortet — dasselbe Muster wie die
Teilen-Lebendprobe (D81-Nachtrag). Verworfen: **direkt aus der App**
(hängt am CORS der Taiga-Instanz — messbar, aber jederzeit durch eine
Server-Einstellung kündbar) und **CLI zuerst** (kann später dieselben
Proxy-Endpunkte nutzen). Nebengewinn des Proxys: Der spätere
Status-Rückweg braucht zwingend eine Server-Seite — Taiga-**Webhooks**
erreichen keinen Browser.
**Zwei Aktionen im Knoten-Fenster:** „Story anlegen" und „Story +
Teilpakete als Tasks". Die zweite zeigt einen **Häkchen-Dialog** über die
direkten Kinder (Nutzer-Entscheidung — maximale Kontrolle statt einer
stillen Regel): **vorbelegt** sind Pflicht- und optionale (`+`) Kinder
sowie die **realisierten** Alternativen einer `|`/`=`-Gruppe (ist nichts
realisiert, ist die Wahl nicht getroffen — nichts vorbelegt); verworfene
(`[-]`) erscheinen gar nicht, **erledigte (`[x]`/`[^]`) starten
abgewählt** — dort ist nichts mehr zu tun, und angelegt wird ohnehin alles
offen (Status-Übernahme ist das spätere Sync-Kapitel, `#trk.write`).
**Das Projekt wird bei jeder Anlage gefragt** (Nutzer-Entscheidung):
Projektliste des eingeloggten Nutzers, nichts gemerkt — kein veralteter
Merker, ein Klick mehr je Ticket. Verworfen: fest im Backend (alle Pläne
in einem Projekt), je Dokument gemerkt, im Notationstext (bräuchte eine
SPEC-Festlegung).
**Die Ticket-Ref wird als Knoten-ID zurückgeschrieben** — undo-fähig über
die vorhandene Maschinerie (D53/D63), für Story und Tasks gleichermaßen
(Taiga vergibt Refs projektweit über alle Typen). Das ist wörtlich die
reservierte Ticket-Referenz aus SPEC §11 („oft ist die Ticket-Kennung die
natürliche Knoten-ID", D34) und zugleich der Idempotenz-Marker: Ein Knoten,
der schon eine Ref trägt, wird nicht erneut angelegt.
**Offen bis zum Bauen:** die zwei Messfragen an die echte Instanz —
Auth-Typ (`normal`/`ldap`, das LDAP-Plugin nutzt einen eigenen `type`) und
das Ref-Muster für die Tracker-Erkennung (`#123` vs. `#US-123`,
D34-Nachtrag). An der Notation ändert sich nichts; `llms.md` bleibt
unberührt.
+41 -1
View File
@@ -199,11 +199,17 @@
| [?] #idea.drift.fixtures: Both parsers test against the same fixtures (S) | [?] #idea.drift.fixtures: Both parsers test against the same fixtures (S)
| [?] #idea.drift.js: Run the one JS parser inside the IDE (M) | [?] #idea.drift.js: Run the one JS parser inside the IDE (M)
- [?] #trk: Tracker integration (XL) %% exactly one of these, hence = - [?] #trk: Tracker integration (XL) %% exactly one of these, hence =
= [?] #trk.taiga: Taiga (L) https://taiga.io = [?] #trk.taiga: Taiga (XL) https://taiga.io
- [ ] #trk.resolve: Resolve "#123" over the REST API (M) - [ ] #trk.resolve: Resolve "#123" over the REST API (M)
- [ ] #trk.resolve.read: Read title, link and status (S) - [ ] #trk.resolve.read: Read title, link and status (S)
- [ ] #trk.resolve.map: Map the workflow onto the states (S) - [ ] #trk.resolve.map: Map the workflow onto the states (S)
- [?] #trk.write: Write the status back (M) :#trk.resolve - [?] #trk.write: Write the status back (M) :#trk.resolve
- [ ] #trk.create: Create tickets from nodes (L)
- [ ] #trk.create.proxy: Backend proxy with named endpoints (M)
- [ ] #trk.create.login: Log in to Taiga, token stays in the browser (S) :#trk.create.proxy
- [ ] #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 ticket ref becomes the node id (S) :#trk.create.story
- [-] #trk.plugin: A plugin inside Taiga itself (L) %% legacy frontend, self-hosted only - [-] #trk.plugin: A plugin inside Taiga itself (L) %% legacy frontend, self-hosted only
= [?] #trk.tenzu: Tenzu, the successor (XXL) https://tenzu.net = [?] #trk.tenzu: Tenzu, the successor (XXL) https://tenzu.net
= [ ] #trk.none: No tracker, plain text is enough (XS) = [ ] #trk.none: No tracker, plain text is enough (XS)
@@ -1144,6 +1150,40 @@
The other direction: change a status in the plan and the ticket follows. The other direction: change a status in the plan and the ticket follows.
Only worth doing once reading it is trustworthy. Only worth doing once reading it is trustworthy.
#trk.create
One click in the node window turns a node into a Taiga ticket. The cut
follows the Kanban view actually in use: stories are the cards and tasks
live inside them — so a story per node, and tasks only under a node that
already carries a story. Decisions in D91.
#trk.create.proxy
A few named endpoints in the Werkbaum backend (auth, projects, user
stories, tasks) relay to the Taiga instance configured server-side. No
CORS trouble and no open relay — the target URL is never a request
parameter — and /api/v1/info announces the feature, so the button only
appears where a backend answers.
#trk.create.login
Taiga's token API behind the proxy: the token lives in the browser and is
only passed through, the backend stores nothing. The password crosses the
proxy once at login and is never logged.
#trk.create.story
"Create story" in the node window: pick the project from your list — asked
on every creation, so nothing stale is remembered — and the story is
created. A node that already carries a ticket ref is left alone.
#trk.create.tasks
The second action also creates the direct sub-packages as tasks under the
story, chosen in a checkbox dialog: preselected are required and optional
children plus the realized alternatives of a |/= group; discarded ones
never appear, finished ones start unchecked.
#trk.create.ref
The returned ref (#123, #US-123) is written back into the line as the node
id, undoable — the reserved ticket reference of SPEC §11, and the marker
that keeps a second click from creating the ticket twice.
#trk.plugin #trk.plugin
Rejected: a plugin inside Taiga means its legacy frontend and works only in Rejected: a plugin inside Taiga means its legacy frontend and works only in
self-hosted installations. A companion application beside it is the better self-hosted installations. A companion application beside it is the better