diff --git a/CLAUDE.md b/CLAUDE.md index e9df8c9..02aa4db 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -24,6 +24,8 @@ Integrations-Backend. Eintrag begründen, alte Einträge nie löschen. Besonders D13 (Backend-Stack) und D14 (Parser-Hoheit) beachten. - Ziele: docs/ROADMAP.md · Offene Arbeit: docs/TASKS.md (Checkboxen pflegen). +- Pull Requests: jeder PR bekommt ein Dokument unter `docs/prs/` — Konvention + in docs/prs/README.md. - Änderungen: @docs/CHANGELOG.md — **jedes Feature und jeder behobene Fehler bekommt dort eine Zeile**, englisch, ein Satz, unter der Überschrift des Tages (`## JJJJ-MM-TT`). Die Datei speist das Neuigkeiten-Popup im Editor diff --git a/README.de.md b/README.de.md index 236f3a3..5bd69f4 100644 --- a/README.de.md +++ b/README.de.md @@ -57,7 +57,7 @@ einer externen Textdatei beziehen — praktisch zum Teilen eines Plans oder wenn die Quelle in Git oder einem Wiki gepflegt wird: ``` -https://werkbaum.javagil.de/?sourceUrl=https://raw.githubusercontent.com/mhoennig/werkbaum/main/docs/examples/example-plan-0.werkbaum +https://werkbaum.javagil.de/?sourceUrl=https://git.javagil.de/mi/werkbaum/raw/branch/main/docs/examples/example-plan-0.werkbaum ``` Fertige Beispiele in [`docs/examples/`](docs/examples/) — **nacheinander @@ -66,11 +66,11 @@ Editor-Titelzeile zwischen allen umschalten: | Beispiel | Zeigt | |---|---| -| **▶ [0 · Online-Shop-Relaunch](https://werkbaum.javagil.de/?sourceUrl=https://raw.githubusercontent.com/mhoennig/werkbaum/main/docs/examples/example-plan-0.werkbaum)** | ein Softwareprojekt mit allen acht Status | -| **▶ [1 · Neue Küche](https://werkbaum.javagil.de/?sourceUrl=https://raw.githubusercontent.com/mhoennig/werkbaum/main/docs/examples/example-plan-1.werkbaum)** | ein Plan ohne Software, viele Alternativen — gut für den Günstigster-Pfad-Schalter | -| **▶ [2 · Community-Konferenz](https://werkbaum.javagil.de/?sourceUrl=https://raw.githubusercontent.com/mhoennig/werkbaum/main/docs/examples/example-plan-2.werkbaum)** | ein breiter Plan mit vielen Beteiligten; horizontal vs. kompakt vergleichen | -| **▶ [3 · Drei Arbeitsstränge](https://werkbaum.javagil.de/?sourceUrl=https://raw.githubusercontent.com/mhoennig/werkbaum/main/docs/examples/example-plan-3.werkbaum)** | mehrere Wurzeln = mehrere Bäume nebeneinander | -| **▶ [Werkbaum selbst](https://werkbaum.javagil.de/?sourceUrl=https://raw.githubusercontent.com/mhoennig/werkbaum/main/docs/examples/example-werkbaum.werkbaum)** | Bestand und mögliche Weiterentwicklung | +| **▶ [0 · Online-Shop-Relaunch](https://werkbaum.javagil.de/?sourceUrl=https://git.javagil.de/mi/werkbaum/raw/branch/main/docs/examples/example-plan-0.werkbaum)** | ein Softwareprojekt mit allen acht Status | +| **▶ [1 · Neue Küche](https://werkbaum.javagil.de/?sourceUrl=https://git.javagil.de/mi/werkbaum/raw/branch/main/docs/examples/example-plan-1.werkbaum)** | ein Plan ohne Software, viele Alternativen — gut für den Günstigster-Pfad-Schalter | +| **▶ [2 · Community-Konferenz](https://werkbaum.javagil.de/?sourceUrl=https://git.javagil.de/mi/werkbaum/raw/branch/main/docs/examples/example-plan-2.werkbaum)** | ein breiter Plan mit vielen Beteiligten; horizontal vs. kompakt vergleichen | +| **▶ [3 · Drei Arbeitsstränge](https://werkbaum.javagil.de/?sourceUrl=https://git.javagil.de/mi/werkbaum/raw/branch/main/docs/examples/example-plan-3.werkbaum)** | mehrere Wurzeln = mehrere Bäume nebeneinander | +| **▶ [Werkbaum selbst](https://werkbaum.javagil.de/?sourceUrl=https://git.javagil.de/mi/werkbaum/raw/branch/main/docs/examples/werkbaum.werkbaum)** | Bestand und mögliche Weiterentwicklung | Der geladene Text wird als **eigenes Dokument** geführt, dessen **Name die URL** ist — eigene Dokumente bleiben unberührt, und derselbe Link aktualisiert dieses @@ -83,10 +83,10 @@ Notationsdateien tragen die Endung **`.werkbaum`** (UTF-8; siehe `docs/SPEC.md` erreichbare Textdatei, unabhängig von Endung und Content-Type. **Einschränkung — CORS:** Der Browser lädt fremde Hosts nur, wenn sie -`Access-Control-Allow-Origin` senden. `raw.githubusercontent.com` und -GitLab-Raw-Links tun das; ein beliebiger Webserver oft nicht. Scheitert das -Laden, bleibt der bisherige Stand stehen und eine Warnung nennt die Ursache. -Zugelassen sind nur `http`/`https`. +`Access-Control-Allow-Origin` senden. `raw.githubusercontent.com`, +GitLab-Raw-Links und `git.javagil.de` tun das (D96); ein beliebiger Webserver +oft nicht. Scheitert das Laden, bleibt der bisherige Stand stehen und eine +Warnung nennt die Ursache. Zugelassen sind nur `http`/`https`. ### Zusammen an einem Plan arbeiten (`?live=`) @@ -152,11 +152,11 @@ git clone mih09-git@git.javagil.de:mi/werkbaum.git # oder https://git.javag ``` **GitHub bleibt ein Klon.** `main` wird dorthin von Hand gespiegelt -(`scripts/push-github.sh`), denn zwei Dinge hängen daran: die -GitHub-Pages-Instanz (der 🚧 *latest build* ganz oben) und die Beispiel-Links -weiter oben, die ihre Pläne per `?sourceUrl=` von `raw.githubusercontent.com` -laden. Gitea liefert `raw`-Dateien **ohne** `Access-Control-Allow-Origin` aus — -dort blockte der Browser sie (`docs/DECISIONS.md` D23, D95). +(`scripts/push-github.sh`), denn die GitHub-Pages-Instanz hängt daran — der +🚧 *latest build* ganz oben. Die Beispiel-Links waren ein zweiter Grund und sind +es nicht mehr: `git.javagil.de` liefert `raw`-Dateien inzwischen mit +`Access-Control-Allow-Origin`, sie zeigen deshalb auf Gitea +(`docs/DECISIONS.md` D96, revidiert D95). ### Lokal ausführen diff --git a/README.md b/README.md index 070b8ff..b892bef 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ The editor can pull its notation text from an external text file via the Git or a wiki: ``` -https://werkbaum.javagil.de/?sourceUrl=https://raw.githubusercontent.com/mhoennig/werkbaum/main/docs/examples/example-plan-0.werkbaum +https://werkbaum.javagil.de/?sourceUrl=https://git.javagil.de/mi/werkbaum/raw/branch/main/docs/examples/example-plan-0.werkbaum ``` Ready-made examples in [`docs/examples/`](docs/examples/) — **open them one @@ -63,11 +63,11 @@ between all of them in the editor title bar: | Example | Shows | |---|---| -| **▶ [0 · Online shop relaunch](https://werkbaum.javagil.de/?sourceUrl=https://raw.githubusercontent.com/mhoennig/werkbaum/main/docs/examples/example-plan-0.werkbaum)** | a software project with all eight states | -| **▶ [1 · New kitchen](https://werkbaum.javagil.de/?sourceUrl=https://raw.githubusercontent.com/mhoennig/werkbaum/main/docs/examples/example-plan-1.werkbaum)** | a non-software plan, lots of alternatives — good for the cheapest-path toggle | -| **▶ [2 · Community conference](https://werkbaum.javagil.de/?sourceUrl=https://raw.githubusercontent.com/mhoennig/werkbaum/main/docs/examples/example-plan-2.werkbaum)** | a wide plan with many people; compare horizontal vs. compact | -| **▶ [3 · Three workstreams](https://werkbaum.javagil.de/?sourceUrl=https://raw.githubusercontent.com/mhoennig/werkbaum/main/docs/examples/example-plan-3.werkbaum)** | several roots = several trees side by side | -| **▶ [Werkbaum itself](https://werkbaum.javagil.de/?sourceUrl=https://raw.githubusercontent.com/mhoennig/werkbaum/main/docs/examples/example-werkbaum.werkbaum)** | what exists today and where it could go | +| **▶ [0 · Online shop relaunch](https://werkbaum.javagil.de/?sourceUrl=https://git.javagil.de/mi/werkbaum/raw/branch/main/docs/examples/example-plan-0.werkbaum)** | a software project with all eight states | +| **▶ [1 · New kitchen](https://werkbaum.javagil.de/?sourceUrl=https://git.javagil.de/mi/werkbaum/raw/branch/main/docs/examples/example-plan-1.werkbaum)** | a non-software plan, lots of alternatives — good for the cheapest-path toggle | +| **▶ [2 · Community conference](https://werkbaum.javagil.de/?sourceUrl=https://git.javagil.de/mi/werkbaum/raw/branch/main/docs/examples/example-plan-2.werkbaum)** | a wide plan with many people; compare horizontal vs. compact | +| **▶ [3 · Three workstreams](https://werkbaum.javagil.de/?sourceUrl=https://git.javagil.de/mi/werkbaum/raw/branch/main/docs/examples/example-plan-3.werkbaum)** | several roots = several trees side by side | +| **▶ [Werkbaum itself](https://werkbaum.javagil.de/?sourceUrl=https://git.javagil.de/mi/werkbaum/raw/branch/main/docs/examples/werkbaum.werkbaum)** | what exists today and where it could go | The loaded text becomes its own document whose **name is the URL**, so your own documents stay untouched; the same link updates that one document instead of @@ -79,9 +79,10 @@ and D24) — a convention, not a contract: `sourceUrl` reads any text file over http(s) regardless of extension or content type. **Caveat — CORS:** the browser only fetches a foreign host if it sends -`Access-Control-Allow-Origin`. `raw.githubusercontent.com` and GitLab raw links -do; an arbitrary web server often does not. If loading fails the previous -content stays and a warning explains why. Only `http`/`https` are allowed. +`Access-Control-Allow-Origin`. `raw.githubusercontent.com`, GitLab raw links and +`git.javagil.de` do (D96); an arbitrary web server often does not. If loading +fails the previous content stays and a warning explains why. Only `http`/`https` +are allowed. ### Working on one plan together (`?live=`) @@ -146,11 +147,11 @@ git clone mih09-git@git.javagil.de:mi/werkbaum.git # or https://git.javagil ``` **GitHub stays a clone.** `main` is mirrored there by hand -(`scripts/push-github.sh`), because two things hang off it: the GitHub Pages -instance (the 🚧 *latest build* linked at the top) and the example links above, -which load plan files from `raw.githubusercontent.com` via `?sourceUrl=`. Gitea -serves raw files **without** an `Access-Control-Allow-Origin` header, so the -browser would block them there (`docs/DECISIONS.md` D23, D95). +(`scripts/push-github.sh`), because the GitHub Pages instance hangs off it — the +🚧 *latest build* linked at the top. The example links above used to be a second +reason and are not any more: `git.javagil.de` now serves raw files with an +`Access-Control-Allow-Origin` header, so they point at Gitea +(`docs/DECISIONS.md` D96, revising D95). ### Running it locally diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index e616170..bc2e0fd 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -21,6 +21,7 @@ reverse. - The project moved to its own Gitea at git.javagil.de — the footer's repository and version links point there now, and GitHub stays a clone carrying the very same commits - Every push is built by Werkator, the project's own CI, alongside the GitHub Pages build: backend and frontend as two named builds +- The example plan links now load from git.javagil.de instead of the GitHub clone, and the "Werkbaum itself" link works again — it pointed at a file name that does not exist ## 2026-09-02 diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index 5d7f46d..3021bd5 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -635,8 +635,8 @@ mögliche Erweiterung.) **CORS ist die eigentliche Einschränkung.** Der Browser lädt fremde Hosts nur, wenn die Zielseite `Access-Control-Allow-Origin` sendet. Das tun u. a. -`raw.githubusercontent.com` und GitLab-Raw-Links; ein beliebiger Webserver -oft **nicht**. Scheitert das Laden (CORS, 404, Netz), bleibt der bisherige Stand +`raw.githubusercontent.com`, GitLab-Raw-Links und — seit D96 — das eigene +`git.javagil.de`; ein beliebiger Webserver oft **nicht**. Scheitert das Laden (CORS, 404, Netz), bleibt der bisherige Stand stehen und es erscheint eine **Warnung** im Warnbereich (Typ `sourceLoad`, zeilenlos ⇒ zuoberst), die CORS ausdrücklich als wahrscheinliche Ursache nennt. Bewusst kein Proxy-Dienst als Ausweg: das würde fremde Inhalte über einen @@ -9144,3 +9144,62 @@ beobachtete Klon `~/werkbaum` auf mih09 bekommt Gitea als `origin` — sonst sähe der Watcher neue Commits erst nach dem Spiegeln. **Status-Checks werden weiterhin nicht gepostet**, solange auf der Instanz kein Gitea-Token liegt; die Sektion ist bis dahin eine Beschriftung. + +**Nachtrag zu D95 — der CORS-Zwang ist weg (2026-09-03).** Von den zwei +gemessenen Gründen für den Klon hält nur noch einer: `git.javagil.de` liefert +`raw`-Dateien inzwischen mit `Access-Control-Allow-Origin` (D96), die +Beispiel-Links zeigen deshalb auf Gitea. **GitHub Pages bleibt** — der +Actions-Workflow der „latest build“-Instanz (D16) lässt sich nicht mitnehmen, +und daran hängt das Spiegeln weiterhin. + +## D96 — `git.javagil.de` liefert `raw`-Dateien mit `Access-Control-Allow-Origin` (2026-09-03) +D95 hielt fest, dass die Beispiel-Links auf `raw.githubusercontent.com` bleiben +müssen, weil Gitea den CORS-Header nicht sendet. Das war eine +Server-Konfiguration, keine Eigenschaft von Gitea — sie ist jetzt gesetzt, und +die Links zeigen auf `origin`. + +**Gemessen, nicht vermutet.** Giteas eigener `[cors]`-Abschnitt allein reicht +nicht: mit `ENABLED = true` / `ALLOW_DOMAIN = *` / `METHODS = GET,HEAD` in +`app.ini` trägt `/api/v1/repos/mi/werkdock/raw/README.md` den Header, die +**Web**-Route `/mi/werkdock/raw/branch/main/README.md` aber weiterhin nicht — +Gitea 1.27 legt die CORS-Middleware nur auf `/api/v1`. Die Beispiel-Links +benutzen die Web-Route. + +**Also beides, mit klarer Aufteilung.** Der `[cors]`-Abschnitt bleibt für die +API-Route; die Web-Route bekommt den Header im Apache davor, in der +`.htaccess` der Domain: + +```apache +SetEnvIf Request_URI "^/[^/]+/[^/]+/(raw|media)/" GITEA_RAW_CORS +Header always set Access-Control-Allow-Origin "*" env=GITEA_RAW_CORS +``` + +Zwei Fallen, beide beim Umsetzen aufgelaufen: `` ist in einer +`.htaccess` **nicht erlaubt** (nur Server-Config/VHost) — auf einem Managed +Webspace gibt es aber nur `.htaccess`, daher `SetEnvIf`. Und die Regel darf +`/api/v1` **nicht** mitfassen: `Header always` schreibt in `err_headers_out` +und *ergänzt* dort, statt zu ersetzen — zusammen mit Giteas eigenem Header +standen zwei `Access-Control-Allow-Origin: *` in der Antwort, was Browser als +ungültig verwerfen. Gemessen: je genau ein Header auf beiden raw-Routen, keiner +auf gewöhnlichen Repo-Seiten. + +**`*` ohne Credentials ist hier die harmlose Variante.** Unter einem +Wildcard-Ursprung sendet der Browser grundsätzlich keine Cookies; ein fremder +Ursprung liest also nur, was ohnehin anonym abrufbar ist. Private Repositories +brauchen die Sitzung und antworten weiter mit 404/403 (nachgemessen: 404 auf +einen nicht existierenden Pfad). Ausdrücklich **nicht** getan: kein +`Access-Control-Allow-Credentials: true` (damit könnten fremde Seiten private +Repositories im Namen des angemeldeten Benutzers lesen), kein Zurückspiegeln +des `Origin` (dasselbe Risiko, sobald jemand später Credentials ergänzt), und +der Header steht nicht site-weit, sondern nur auf den raw-Pfaden. + +**Kein Preflight nötig.** `OPTIONS` auf die Web-raw-Route antwortet weiterhin +`405`. Das ist folgenlos: der Abruf aus D23 ist ein *simple request* — +schlichtes `GET`, `credentials:'omit'`, keine eigenen Header —, und dafür +schickt der Browser keinen Preflight. + +**Die Konfiguration liegt in keinem Repository.** Sie gehört dem Unix-Benutzer +`mih09-git` auf mih09 (`gitea/custom/conf/app.ini` und +`doms/git.javagil.de/htdocs-ssl/.htaccess`, beide mit Zeitstempel-Sicherung +daneben) — deshalb steht sie hier im Wortlaut, damit sie nach einem Neuaufsetzen +wiederherstellbar ist. diff --git a/docs/prs/2026-09-03-PR#1-gitea-raw-cors.md b/docs/prs/2026-09-03-PR#1-gitea-raw-cors.md new file mode 100644 index 0000000..232e498 --- /dev/null +++ b/docs/prs/2026-09-03-PR#1-gitea-raw-cors.md @@ -0,0 +1,98 @@ +> **Hinweis:** Dieses Dokument beschreibt nur die Änderung dieses PR. +> Es kann veraltet sein, sobald der nächste PR gemergt ist. +> Historische PR-Dokumentation wird nicht nachgepflegt — sie ist eine Momentaufnahme, keine aktuelle Doku. + +## Das Problem + +Die Beispiel-Links beider READMEs laden ihren Plan per `?sourceUrl=` aus einer Textdatei im Netz (D23). +Der Browser holt eine fremde Herkunft nur, wenn die Antwort `Access-Control-Allow-Origin` trägt. +`raw.githubusercontent.com` sendet den Header, `git.javagil.de` sendete ihn nicht. +Deshalb mussten die Links nach dem Umzug nach Gitea (D95) weiterhin auf den GitHub-Klon zeigen, obwohl das Repository dort gar nicht mehr zuhause ist. + +Gemessen am 2026-09-03, mit `Origin:`-Header: HTTP 200, `Access-Control-Expose-Headers: Content-Disposition`, `Content-Type: text/plain; charset=utf-8` — aber kein `Access-Control-Allow-Origin`. +Die Datei selbst war also einwandfrei erreichbar; es fehlte genau ein Header. + +## Nicht das Ziel + +- Der GitHub-Klon verschwindet nicht: die GitHub-Pages-Instanz (D16) hängt weiter daran, sie ist ein Actions-Workflow und lässt sich nicht mitnehmen. +- Kein Proxy-Dienst als Ausweg — D23 verwirft ihn ausdrücklich, weil er fremde Inhalte über einen Dritt-Host leiten würde. +- Keine Änderung am Frontend: `sourceUrl` bleibt, wie es ist; der Fehler lag ausschließlich auf der Serverseite. + +## Die Szenarien + +### Feature: Beispiel-Pläne laden aus dem eigenen Gitea + +#### Hintergrund + +- Die Konfiguration liegt beim Unix-Benutzer `mih09-git` auf mih09 und in **keinem** Repository; sie ist im Wortlaut in D96 festgehalten. +- Giteas eigener `[cors]`-Abschnitt und die `.htaccess` der Domain teilen sich die Arbeit: die API-Route deckt Gitea ab, die Web-Route der Apache davor. + +#### Szenario#1.01: Ein Beispiel-Link öffnet den Plan statt eines CORS-Fehlers + +Damit die Links auf `origin` zeigen können und nicht auf einen Klon. + +- **Gegeben** ein Beispiel-Link mit `?sourceUrl=https://git.javagil.de/mi/werkbaum/raw/branch/main/…` +- **Wenn** der Browser die Datei aus der fremden Herkunft holt +- **Dann** trägt die Antwort `Access-Control-Allow-Origin: *` und der Plan wird geöffnet + +##### Nachgewiesen durch + +- Messung 2026-09-03 auf allen fünf Beispieldateien: je HTTP 200 mit genau einem `Access-Control-Allow-Origin: *`. + +#### Szenario#1.02: Die API-Route trägt den Header genau einmal + +Damit die Antwort gültig bleibt — zwei `Access-Control-Allow-Origin`-Header verwirft der Browser als ungültig. + +- **Gegeben** Gitea setzt den Header auf `/api/v1/…` bereits selbst +- **Wenn** die `.htaccess` diese Route nicht mitfasst +- **Dann** steht in der Antwort genau ein `Access-Control-Allow-Origin: *` + +##### Nachgewiesen durch + +- Messung 2026-09-03: `/api/v1/repos/mi/werkdock/raw/README.md` → ein Header (zuvor, mit der ersten Fassung der `.htaccess`, waren es zwei). + +#### Szenario#1.03: Gewöhnliche Repo-Seiten bleiben unberührt + +Damit der Header nur dort steht, wo er gebraucht wird, und nicht site-weit. + +- **Gegeben** eine gewöhnliche Seite wie `/mi/werkdock` +- **Wenn** sie abgerufen wird +- **Dann** trägt die Antwort keinen `Access-Control-Allow-Origin` + +##### Nachgewiesen durch + +- Messung 2026-09-03: `/mi/werkdock` → HTTP 200, null `Access-Control-Allow-Origin`-Header. + +## Die Lösung + +Auf mih09, beim Benutzer `mih09-git` (Sicherungskopien mit Zeitstempel liegen jeweils daneben): + +- `gitea/custom/conf/app.ini` bekommt einen `[cors]`-Abschnitt (`ENABLED = true`, `ALLOW_DOMAIN = *`, `METHODS = GET,HEAD`); Gitea neu gestartet. +- `doms/git.javagil.de/htdocs-ssl/.htaccess` bekommt `SetEnvIf Request_URI "^/[^/]+/[^/]+/(raw|media)/"` plus `Header always set Access-Control-Allow-Origin "*" env=…`, vor den vorhandenen Proxy-Regeln. + +Im Repository: + +- Die Beispiel-Links beider READMEs zeigen auf `git.javagil.de/mi/werkbaum/raw/branch/main/…`. +- Die CORS-Einschränkung in beiden READMEs und in D23 nennt `git.javagil.de` jetzt unter den Hosts, die den Header senden. +- Der Absatz „GitHub bleibt ein Klon“ nennt nur noch GitHub Pages als Grund; D95 bekommt einen Nachtrag, D96 hält die Konfiguration im Wortlaut fest. + +Warum die Aufteilung auf zwei Stellen: Gitea 1.27 legt die CORS-Middleware nur auf `/api/v1`, nicht auf die Web-raw-Route — und genau die benutzen die Links. +Warum `SetEnvIf` statt ``: Location-Direktiven sind in einer `.htaccess` nicht erlaubt, und auf einem Managed Webspace gibt es nur `.htaccess`. +Warum `*` ohne Credentials: unter einem Wildcard-Ursprung sendet der Browser keine Cookies, ein fremder Ursprung liest also nur, was ohnehin anonym abrufbar ist; private Repositories antworten weiter mit 404/403. + +## Offene Fragen + +- Keine. Beide Fallen (verbotenes ``, doppelter Header) sind beim Umsetzen aufgetreten und behoben; die Messungen decken Web-raw, API-raw und eine gewöhnliche Seite ab. + +## Weitere Änderungen + +- Der Link „Werkbaum selbst“ war schon vorher tot: er zeigte auf `example-werkbaum.werkbaum`, die Datei heißt `werkbaum.werkbaum` — auch auf GitHub lieferte er 404. Beim Umstellen mit korrigiert. +- `docs/prs/` samt Konvention neu eingeführt; `CLAUDE.md` verweist darauf. + +## Vorausgesetzte PRs + +- Keine; setzt den Umzug nach Gitea (D95) voraus, der bereits auf `main` liegt. + +## Folge-PRs + +- Keine geplant. diff --git a/docs/prs/README.md b/docs/prs/README.md new file mode 100644 index 0000000..b82c180 --- /dev/null +++ b/docs/prs/README.md @@ -0,0 +1,34 @@ +# PR-Dokumentation + +Jeder Pull Request bekommt hier **eine** Datei. + +## Dateiname + +`JJJJ-MM-TT-PR#-kurze-beschreibung.md` + +Die Nummer ist die des Gitea-PR auf . +Steht sie noch nicht fest, gilt `PR#000` als Platzhalter — im Dateinamen wie in +den Szenario-IDs — und wird nachgezogen, sobald der PR offen ist. + +## Aufbau + +Die `##`-Abschnitte in genau dieser Reihenfolge, nicht Zutreffendes weglassen: + +1. Das Problem +2. Nicht das Ziel +3. Die Szenarien +4. Die Lösung +5. Offene Fragen +6. Weitere Änderungen +7. Vorausgesetzte PRs +8. Folge-PRs + +## Regeln + +- Deutsch (CLAUDE.md), Markdown, ein Satz je Zeile, kurz halten. +- Das „Warum“ erklären, nicht nur das „Was“. +- Szenarien in Markdown-eigenem Pseudo-Gherkin mit IDs `Szenario#.`, + jedes mit einer Liste `##### Nachgewiesen durch`. +- Ein PR-doc beschreibt den Stand **dieses** PR. Ältere PR-docs werden nicht + nachgepflegt, wenn spätere PRs das Verhalten ändern — dauerhafte Begründungen + gehören nach `docs/DECISIONS.md`.