Der Unterschied war nirgends aufgeschrieben, und am type ist er auch nicht ablesbar: Der kennt nur bug und feature_request, also muss ein Roadmap-Vorhaben sich als Wunsch ausgeben. Unterschieden wird am Themenbereich. Ein feature_request ist ein Vorschlag an ein FREMDES Projekt - etwas, das dort gebaut werden muesste, damit die Zusammenarbeit besser wird. Das Beispiel steht jetzt in der Agent-Vorlage, weil es genau so vorgekommen ist: Ein Agent an IBKRTrader brauchte die Besitzerart seines Tokens, das Deploymentcenter gab sie nirgends heraus, also schlug er einen Endpunkt vor (#282 - inzwischen gebaut). ROADMAP_MIGRATION.md warnt zusaetzlich, dass Schritt 3 und 4 zusammengehoeren. Bei der ersten Uebernahme ist das gutgegangen - 217 von 229 Eintraegen haben ihren Themenbereich bekommen. Auffaellig wurde etwas anderes: Die Bugliste zeigte Roadmap-Eintraege mit an, und die zwoelf echten Vorschlaege lagen unter der Planung begraben. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
349 lines
13 KiB
Markdown
349 lines
13 KiB
Markdown
# Roadmap ins Deploymentcenter übernehmen
|
||
|
||
**Für Agenten und Entwickler in den angebundenen Projekten.** Diese Anleitung
|
||
beschreibt, wie eine vorhandene `ROADMAP.md`, `TODO.md`, `PLAN.md` oder eine
|
||
Sammlung von Entwurfsdokumenten in das Roadmap-System des Deploymentcenters
|
||
überführt wird — einmalig, pro Projekt.
|
||
|
||
Verfügbar ab **2.7.0**. Voraussetzung: Migration `016_roadmap.sql` ist auf dem
|
||
Server gelaufen.
|
||
|
||
---
|
||
|
||
## Warum überhaupt
|
||
|
||
Vorhaben lagen bisher in Markdown-Dateien: Status, Reihenfolge und
|
||
Zuständigkeit von Hand gepflegt, neben einem Bugtracker, der genau diese drei
|
||
Dinge bereits führt. Zwei Pfleger für dasselbe Feld — Drift war keine
|
||
Möglichkeit, sondern eine Frage der Zeit.
|
||
|
||
Konkret ging dabei verloren:
|
||
|
||
- Ein Punkt stand als offen in der Datei, obwohl der Code ihn längst erledigt
|
||
hatte. Wer die Datei las, arbeitete an etwas Fertigem.
|
||
- Zwei Agenten nahmen sich dasselbe Vorhaben vor, weil die Datei nicht sagen
|
||
kann, dass jemand daran sitzt.
|
||
- Ein verworfener Vorschlag kam nach drei Monaten wieder, weil die Begründung
|
||
in einem Entwurfsdokument stand, das niemand mehr aufschlug.
|
||
|
||
## Die Arbeitsteilung
|
||
|
||
**Kein Feld hat zwei Pfleger.** Das ist die ganze Regel; alles Weitere folgt
|
||
daraus.
|
||
|
||
| | Wahrheit | Die andere Seite hält |
|
||
|---|---|---|
|
||
| Status, Reihenfolge, Zielfassung, Bearbeiter | **Deploymentcenter** | eine maschinell erzeugte Kopie zwischen Markern |
|
||
| Begründung, Auslöser, Verworfenes, Herleitung | **Die Datei** | nur einen Verweis (`doc_anchor`) |
|
||
|
||
Die Datei verschwindet also **nicht**. Sie verliert nur die Hälfte, die sie
|
||
ohnehin nie zuverlässig getragen hat.
|
||
|
||
## Die Kennung
|
||
|
||
Handvergebene Kennungen (`A12`, `TODO-7`) sind der Grund für die schlimmste
|
||
Fehlerart: Beide Seiten sind für sich stimmig und meinen Verschiedenes, weil
|
||
die Kennung nach einer Löschung neu vergeben wurde. Niemand bemerkt das.
|
||
|
||
Deshalb ist die Kennung die **Item-ID** aus dem Deploymentcenter.
|
||
AUTO_INCREMENT vergibt nie zweimal dieselbe Nummer; eine gelöschte Zeile
|
||
hinterlässt eine hängende Referenz, und die *meldet* der Abgleich, statt sie
|
||
stillschweigend umzudeuten.
|
||
|
||
Der Themenbuchstabe bleibt — aber nur als Gruppe:
|
||
|
||
```markdown
|
||
### [A] #142 — Symbol-Upload und dc_symbolicate
|
||
```
|
||
|
||
---
|
||
|
||
## Übernahme in sechs Schritten
|
||
|
||
### 1. Bestandsaufnahme
|
||
|
||
Sortiere jeden Eintrag deiner Datei in genau eine der vier Kisten:
|
||
|
||
| Kiste | Kennzeichen | Wohin |
|
||
|---|---|---|
|
||
| **Vorhaben** | hat einen Zustand, jemand könnte es übernehmen | Item im DC |
|
||
| **Zurückgestellt** | bewusst nicht jetzt, mit benanntem Anlass | Item (`deferred`) + Absatz |
|
||
| **Verworfen** | geprüft und abgelehnt, mit Begründung | Item (`rejected`) + Absatz |
|
||
| **Erledigt** | schon ausgeliefert | Item (`resolved`) — oder ersatzlos streichen |
|
||
|
||
Was in keine Kiste passt, ist meist ein Gedanke und kein Vorhaben. Der gehört
|
||
in die Prosa, nicht in die Datenbank. **Faustregel:** Wenn niemand es
|
||
übernehmen kann, ist es kein Item.
|
||
|
||
### 2. Themenbereiche anlegen
|
||
|
||
Die Abschnitte deiner Datei werden Themenbereiche. Kurzes Kürzel, sprechender
|
||
Titel:
|
||
|
||
```bash
|
||
curl -X POST "https://dc.mhdf.de/api/bugtracker/v1/roadmap.php?action=epic" \
|
||
-H "Authorization: Bearer $DC_TOKEN" -H "Content-Type: application/json" \
|
||
-d '{"project_slug":"meinprojekt","epic":"A","title":"Handelslogik","sort_order":10}'
|
||
```
|
||
|
||
Oder im WebUI unter **Roadmap → Themenbereiche**.
|
||
|
||
Halte die Zahl klein. Fünf bis zehn Bereiche sind übersichtlich, zwanzig sind
|
||
eine zweite Ablage, die selbst wieder sortiert werden will.
|
||
|
||
### Abkürzung: Schritte 2–4 als Skript
|
||
|
||
Für eine Datei im Format dieses Projekts — Bereichstabellen mit
|
||
`| A4 | Titel | 📋 |`, Auslöser als `**Auslöser:** …` — nimmt
|
||
[scripts/roadmap_import.py](../scripts/roadmap_import.py) die drei Schritte ab:
|
||
|
||
```bash
|
||
python scripts/roadmap_import.py --lesen
|
||
```
|
||
|
||
Zeigt, was es gefunden hat, ohne etwas zu senden. **Immer zuerst.** Dabei fällt
|
||
auf, was die Datei falsch behauptet — bei der Übernahme hier waren drei
|
||
Einträge längst erledigt und einer doppelt vergeben.
|
||
|
||
```bash
|
||
python scripts/roadmap_import.py --uebernehmen
|
||
```
|
||
|
||
`DC_TOKEN` muss dabei ein Werkbank-Token des Projekts sein. Das Skript legt die
|
||
Themenbereiche mit an, ist über `client_ref` wiederholbar und wartet bei
|
||
Drosselung, statt abzubrechen: `/report` lässt 60 Meldungen je Minute zu, und
|
||
eine Roadmap mit mehr Einträgen liegt darüber.
|
||
|
||
Die Prioritätsreihenfolge liest es aus dem Abschnitt „Als Nächstes" der Datei —
|
||
solange die Datei die Quelle ist, soll auch die Priorität von dort kommen und
|
||
nicht aus einer zweiten Liste daneben.
|
||
|
||
Für eine Datei in anderem Format ist das Skript die Vorlage, nicht das
|
||
Werkzeug: Die Auswertung steht in `auswerten()` und ist auf etwa achtzig Zeilen
|
||
angepasst.
|
||
|
||
### 3. Vorhaben anlegen
|
||
|
||
Jedes Vorhaben wird ein Item. Mit MCP-Adapter:
|
||
|
||
> ⚠️ **`type: "feature_request"` ist hier ein Behelf, keine Aussage.** `type`
|
||
> kennt nur `bug` und `feature_request` — ein Vorhaben muss sich deshalb als
|
||
> Wunsch ausgeben, obwohl es die eigene Planung ist und kein Vorschlag an
|
||
> jemanden. Entscheidend ist Schritt 4: **Erst der Themenbereich macht das Item
|
||
> zum Roadmap-Eintrag**, und erst dann verschwindet es aus der Bugliste und
|
||
> erscheint im Roadmap-Modul.
|
||
>
|
||
> Wer die Übernahme nach Schritt 3 abbricht, hinterlässt Dutzende
|
||
> vermeintlicher Feature Requests im Eingang des Projekts — **Schritt 3 und 4
|
||
> gehören zusammen.**
|
||
>
|
||
> Bei der ersten Übernahme (August 2026, vier Projekte) ist das gutgegangen:
|
||
> 217 von 229 Einträgen haben ihren Themenbereich bekommen. Auffällig wurde
|
||
> trotzdem etwas anderes — die Bugliste zeigte Roadmap-Einträge damals noch
|
||
> mit an, und die zwölf echten Vorschläge lagen unter der Planung begraben.
|
||
> Seit 2.7.1 blendet die Bugliste sie ab Werk aus.
|
||
>
|
||
> Dass der `type` zu eng ist, ist als Item #285 gemeldet.
|
||
|
||
```
|
||
dc_report(title: "Symbol-Upload und dc_symbolicate",
|
||
type: "feature_request",
|
||
description: "…",
|
||
client_ref: "roadmap-a4")
|
||
```
|
||
|
||
`client_ref` immer setzen: Ein wiederholter Lauf legt dann kein Duplikat an —
|
||
und bei einer Übernahme von zwanzig Einträgen läuft irgendetwas immer zweimal.
|
||
|
||
Ohne MCP:
|
||
|
||
```bash
|
||
curl -X POST "https://dc.mhdf.de/api/bugtracker/v1/report" \
|
||
-H "Authorization: Bearer $DC_TOKEN" -H "Content-Type: application/json" \
|
||
-d '{"project_slug":"meinprojekt","type":"feature_request",
|
||
"title":"…","description":"…","client_ref":"roadmap-a4"}'
|
||
```
|
||
|
||
### 4. Auf die Roadmap heben
|
||
|
||
Ein Vorhaben steht auf der Roadmap, **sobald es einen Themenbereich hat**. Das
|
||
ist das einzige Kennzeichen — ein zweites Flag daneben gäbe es zwei Angaben,
|
||
die dasselbe behaupten und auseinanderlaufen können.
|
||
|
||
```
|
||
dc_roadmap_set(id: 142, epic: "A", roadmap_rank: 10, target_build: "2.7.0",
|
||
doc_anchor: "docs/ROADMAP.md#142-symbol-upload")
|
||
```
|
||
|
||
Zur Reihenfolge: **Zehnerschritte.** Die Lücken sind Absicht — ein Eintrag
|
||
lässt sich später auf Rang 15 dazwischenschieben, ohne dass alle folgenden neu
|
||
nummeriert werden müssen.
|
||
|
||
Zurückgestelltes braucht den Auslöser, sonst wird der Aufruf abgelehnt:
|
||
|
||
```
|
||
dc_roadmap_set(id: 147, epic: "A", status: "deferred",
|
||
defer_trigger: "sobald Logauszüge strukturiert hereinkommen")
|
||
```
|
||
|
||
Ohne benannten Anlass ist ein Vorhaben nicht zurückgestellt, sondern vergessen.
|
||
Genau deshalb ist das Feld Pflicht und nicht bloß empfohlen.
|
||
|
||
### 5. Die Datei umbauen
|
||
|
||
Drei Änderungen:
|
||
|
||
**a) Zustandstabellen raus.** Jede von Hand gepflegte Tabelle mit Status-Spalte
|
||
wird ersatzlos gelöscht. Sie kommt gleich erzeugt zurück.
|
||
|
||
**b) Überschriften auf Item-IDs umstellen.**
|
||
|
||
```markdown
|
||
### [A] #142 — Symbol-Upload und dc_symbolicate
|
||
|
||
Der Packager lädt beim `publish` die PDB mit hoch, verknüpft mit `commit_sha`.
|
||
Ausgeliefert wird ein gestripptes Binary. …
|
||
```
|
||
|
||
Kein Status in der Überschrift, kein Häkchen, keine Zielfassung — das steht
|
||
alles im erzeugten Block und wäre hier eine zweite Wahrheit.
|
||
|
||
**c) Den Block einsetzen.** Beim ersten Lauf wird er ans Dateiende gehängt;
|
||
verschiebe ihn samt Markern dorthin, wo er stehen soll. Künftige Läufe finden
|
||
ihn dort wieder.
|
||
|
||
```bash
|
||
php cli/roadmap.php --write --project=meinprojekt --file=/pfad/zu/ROADMAP.md
|
||
```
|
||
|
||
Liegt das Projekt auf einer anderen Maschine als das Deploymentcenter, holst du
|
||
den Block über die API:
|
||
|
||
```bash
|
||
curl -s "https://dc.mhdf.de/api/bugtracker/v1/roadmap.php?action=render&project_slug=meinprojekt" \
|
||
-H "Authorization: Bearer $DC_TOKEN" | jq -r .markdown
|
||
```
|
||
|
||
### 6. Abgleich einrichten
|
||
|
||
```bash
|
||
php cli/roadmap.php --check --project=meinprojekt --file=/pfad/zu/ROADMAP.md
|
||
```
|
||
|
||
Was geprüft wird — nur die **Prosa**, denn der erzeugte Block kann nicht
|
||
abweichen:
|
||
|
||
| Befund | Bedeutung | Grad |
|
||
|---|---|---|
|
||
| `unknown_item` | Absatz nennt `#142`, das Item gibt es nicht | Fehler |
|
||
| `foreign_item` | `#142` gehört einem anderen Projekt | Fehler |
|
||
| `not_on_roadmap` | Absatz vorhanden, aber kein Themenbereich gesetzt | Warnung |
|
||
| `title_drift` | Überschrift und Item-Titel haben nichts mehr gemeinsam | Warnung |
|
||
| `decision_undocumented` | zurückgestellt/verworfen, aber keine Begründung in der Datei | Warnung |
|
||
|
||
Rückgabewert 0 heißt in Ordnung (Warnungen erlaubt), 1 heißt Fehler. Damit
|
||
lässt sich der Aufruf in einen Deploy-Schritt oder Pre-Commit-Hook hängen.
|
||
|
||
Ein Item **ohne** Absatz ist bewusst kein Befund: Nicht jedes Vorhaben braucht
|
||
eine Herleitung, die meisten sind eine Zeile wert und mehr nicht.
|
||
|
||
---
|
||
|
||
## Nach der Übernahme: die Regeln im Alltag
|
||
|
||
**Ein Vorhaben entsteht immer im DC, nie in der Datei.** `dc_report` legt das
|
||
Item an → `--write` schreibt die Zeile → *danach* schreibst du die Begründung
|
||
darunter. So kann ein Eintrag, der nur in der Datei steht, gar nicht erst
|
||
entstehen — und damit auch kein offener Punkt, den niemand angeht.
|
||
|
||
**Die Arbeitsschlange ist die Wahrheit über Arbeit.** Was nicht über
|
||
`?action=next` ausgegeben wird, macht niemand — unabhängig davon, wie es in
|
||
einer Datei markiert ist. Ein Eintrag, der etwas werden soll, muss ein Item
|
||
sein.
|
||
|
||
**Vor dem Anfangen `dc_roadmap` aufrufen.** Es beantwortet „was ist als
|
||
Nächstes dran" und „arbeitet schon jemand daran". Beides, bevor du beginnst.
|
||
|
||
**Vor dem Wiedervorschlagen die Begründung lesen.** Steht ein Vorhaben auf
|
||
`rejected` oder `deferred`, führt `doc_anchor` zu dem Absatz, der sagt warum.
|
||
Ein erneuter Vorschlag braucht ein Argument, das dort noch nicht steht.
|
||
|
||
**Der erzeugte Block darf altern.** Er ist eine Kopie, und Kopien altern. Der
|
||
Live-Stand kommt aus `dc_roadmap`; der Block ist für Menschen, die die Datei
|
||
aufschlagen. `--check` weist auf einen Block hin, der älter als ein Tag ist.
|
||
|
||
---
|
||
|
||
## Was nicht ins DC gehört
|
||
|
||
Der Umzug ist keine Einladung, alles in die Datenbank zu kippen.
|
||
|
||
- **Architekturentscheidungen mit Herleitung** bleiben in der Datei. Ein
|
||
Absatz, der eine Abwägung erklärt, überlebt keine Tabellenzelle.
|
||
- **Verworfenes mit Begründung** bleibt in der Datei. Der Wert des Eintrags ist
|
||
die Begründung, nicht die Ablehnung. Im DC steht nur der Status daneben.
|
||
- **Lose Gedanken** gehören weder hierhin noch dorthin. Wenn niemand sie
|
||
übernehmen kann, sind sie kein Vorhaben — im Zweifel als Notiz ins Archiv.
|
||
- **Alte Entwurfsdokumente** nach `docs/archiv/` verschieben, nicht löschen.
|
||
Sie enthalten die ausführliche Begründung, aber keinen gültigen Stand mehr.
|
||
Ein Hinweis darauf gehört an den Kopf der Roadmap-Datei.
|
||
|
||
---
|
||
|
||
## Werkzeuge im Überblick
|
||
|
||
| Werkzeug | Wofür |
|
||
|---|---|
|
||
| `dc_roadmap` | lesen: was ist dran, wer sitzt dran (MCP) |
|
||
| `dc_roadmap_set` | Bereich, Rang, Zielfassung, Anker setzen (MCP) |
|
||
| `GET /api/bugtracker/v1/roadmap.php?action=list` | dasselbe über REST |
|
||
| `?action=render` | den Markdown-Block holen |
|
||
| `?action=check` | Abgleich mit mitgeschickter Datei (`content`) |
|
||
| `php cli/roadmap.php --write\|--check\|--list` | von der DC-Maschine aus |
|
||
| WebUI → **Roadmap** | Übersicht, Filter, Reihenfolge, Aufnahmeliste |
|
||
|
||
Token braucht `bugtracker:read` zum Lesen und `bugtracker:manage` zum
|
||
Schreiben. Ein Werkbank-Token (`dev_agent`) hat beides.
|
||
|
||
---
|
||
|
||
## Beispiel: eine Datei vorher und nachher
|
||
|
||
**Vorher** — Zustand und Begründung durcheinander, beides von Hand:
|
||
|
||
```markdown
|
||
## A — Supervisor
|
||
|
||
| | Vorhaben | Stand |
|
||
|---|---|---|
|
||
| A4 | Symbol-Upload | 📋 geplant für 2.7.0 |
|
||
| A5 | Logzeilen-Schablonen | 🧊 später |
|
||
|
||
### A4 — Symbol-Upload
|
||
Der Packager lädt die PDB mit hoch…
|
||
```
|
||
|
||
**Nachher** — Zustand erzeugt, Begründung von Hand, verbunden über die ID:
|
||
|
||
```markdown
|
||
<!-- dc:roadmap stand=2026-08-29T14:02Z items=7 projekt=deploymentcenter -->
|
||
|
||
### A — Supervisor und Befunde
|
||
|
||
| | Vorhaben | Stand | Ziel |
|
||
|---|---|---|---|
|
||
| #142 | Symbol-Upload und dc_symbolicate | 📋 Offen | `2.7.0` |
|
||
| #143 | novel.log_template | 🧊 Zurückgestellt — Auslöser: sobald Logauszüge strukturiert hereinkommen | — |
|
||
|
||
<!-- /dc:roadmap -->
|
||
|
||
## Begründungen
|
||
|
||
### [A] #142 — Symbol-Upload
|
||
Der Packager lädt die PDB mit hoch, verknüpft mit `commit_sha`. Ausgeliefert
|
||
wird ein gestripptes Binary. Der Kunde bekommt `at 0x4a2f`, du bekommst
|
||
`UserAuthService.cs:42` — ohne dass Quelltext das Haus verlässt.
|
||
```
|
||
|
||
Die Statuszeile stimmt jetzt, weil sie niemand mehr pflegt.
|