Doc-Review-Workflows: Submit / Approve / Reject mit immutabler Versionierung
Wikis lösten das Problem, Dokumente gemeinsam zu schreiben. Sie lösten nicht das Problem, sie zu governen. Sobald Ihre Dokumentation eine:n Auditor:in zufriedenstellen muss, oder im Incident verlässlich sein muss, bricht das Wiki-Modell. So sieht eine review-first Wissens-Plattform darunter aus: ETag-Locks, Pflicht-Reject-with-Reason, semantische Diffs und eine Append-Only-Historie, die niemand still umschreiben kann.

TL;DR: Wiki-artige Plattformen, optimiert für kollaboratives Editieren, trafen eine Annahme, die in regulierten oder Incident-Response-Kontexten nicht hält: dass die neueste Version die autoritative ist. Trägt ein Dokument operatives Gewicht (Runbook, Policy, Threat-Model, Change-Prozedur), hört "jede:r darf editieren, latest wins" auf, ein Workflow zu sein, und wird zur Belastung. Dieser Beitrag geht durch die Mechanik, die eine Wissensbasis in ein audit-grade Artefakt verwandelt: explizite Submit-/Approve-/Reject-Zustände, ETag-basiertes Optimistic-Locking, Pflicht-Reject-Begründungen, semantische Diffs und eine immutable Versions-Historie.
Das Standardmodell für kollaborative Dokumentation ist das Wiki. Jede:r darf editieren, der jüngste Edit gewinnt, und die Historie ist eine lineare Revisions-Kette, die man inspizieren kann, falls man es will. Für seinen ursprünglichen Zweck (ein Team dazu bringen, Dinge aufzuschreiben, ohne einen Word-Dokument-per-Mail-Bottleneck) ist das Modell exzellent.
Das Modell bricht in dem Moment, in dem die Dokumentation operatives Gewicht trägt. Ein Runbook, dem die:der On-Call-Engineer um 3 Uhr morgens folgt. Eine Response-Prozedur, die das SOC während eines Incidents ausführt. Eine Security-Policy, die die:der Auditor:in nächsten Monat reviewt. Ein Threat-Model, auf das sich das Architektur-Team für das nächste Release verlässt. In diesen Kontexten ist die Frage nicht "was sagt das Dokument jetzt", sondern "was sagte das Dokument, als diese Entscheidung getroffen wurde, wer hat die Änderung genehmigt, auf welcher Basis".
Wiki-Tools wurden nicht gebaut, diese Fragen zu beantworten, und die meisten Nachrüst-Versuche produzieren Zeremonie ohne Substanz.
Dieser Beitrag geht durch das Modell, das in Krasper Thot verwendet wird, einem Knowledge-Hub, der review-first statt edit-first gebaut ist. Die Mechanik ist unglamourös: ETag-Locks, explizite Zustände, Pflicht-Reject-Begründungen, semantische Diffs, eine Append-Only-Historie. Das Ergebnis ist eine Wissensbasis, die unter Audit hält, sich unter Concurrent-Editing vorhersehbar verhält und "was wurde wann genehmigt" zu einer One-Query-Antwort macht statt zu einer forensischen Untersuchung.
Inhalt
- Warum Wikis das falsche Substrat für governte Dokumentation sind
- Das Drei-Zustands-Dokument-Modell
- ETag-Optimistic-Locking: Concurrent-Editing ohne Last-Write-Wins-Falle
- Pflicht-Reject-with-Reason: das Formular ist die Policy
- Diff-Viewer: semantischer Vergleich statt textuellem Noise
- Immutable-Versionierung: Append-Only-Historie, Punkt
- Der Audit-Record, der als Nebenprodukt aus dem Workflow fällt
- Was man eine Wissens-Plattform fragen sollte, bevor man auf sie setzt
1. Warum Wikis das falsche Substrat für governte Dokumentation sind
Das Wiki-Modell ruht auf drei Annahmen, und governte Dokumentation bricht sie alle.
Die erste: Die neueste Version sei die autoritative. In einem Wiki wird der jüngste Edit zur aktuellen Wahrheit, was für ein Team, das Meeting-Notes schreibt, passt und für ein Policy-Dokument, das vor Inkrafttreten reviewt werden muss, genau falsch ist. Der Akt des Editierens sollte nicht für sich allein ändern, was die Organisation als autoritativ betrachtet.
Eine zweite: Historie sei eine Kuriosität statt eines Vertrags. Wikis halten zwar Revisions-Historie, behandeln sie aber als Debugging-Hilfe: nichts hindert einen daran, sie zu löschen, es gibt keinen signierten Audit-Trail und keine Garantie, dass das, was man in der Historie sieht, das ist, was historisch angezeigt wurde.
Die dritte: Edit-Konflikte seien selten und Last-Write-Wins gut genug. Auf einer Low-Traffic-Page mag das stimmen. In einem Runbook, das zwei Engineers während eines Incidents gleichzeitig editieren, sind stille Overwrites genau der Weg, auf dem kritische Fixes verlorengehen.
Einige Tools der Kategorie, Confluence eingeschlossen, haben Approval-Features auf das Wiki-Substrat draufgesetzt. Sie funktionieren für leichtes Gating, aber die zugrundeliegenden Annahmen bleiben. Der Review-Schritt ist aufgelegt, nicht eingebacken; die Historie ist veränderbar; das Edit-Modell ist weiterhin Last-Write-Wins.
Eine Review-First-Plattform invertiert jede dieser Annahmen. Der jüngste Edit ist nicht autoritativ; die jüngste genehmigte Version ist es. Historie ist Append-Only und kryptographisch verankert. Concurrent-Edits werden erkannt und als Konflikte sichtbar gemacht statt still aufgelöst. Der Rest dieses Beitrags geht darum, wie das in der Praxis aussieht.
2. Das Drei-Zustands-Dokument-Modell
Jedes Dokument in einem Review-First-System lebt zu jedem Zeitpunkt in einem von drei Zuständen:
- Draft: wird von einer:einem oder mehreren Autor:innen editiert, für allgemeine Leser:innen nicht sichtbar, nicht Teil des kanonischen Records.
- Submitted: für Review eingefroren, für designierte Reviewer:innen sichtbar, wartet auf Approve- oder Reject-Entscheidung.
- Approved: die aktuelle kanonische Version, für alle Leser:innen sichtbar, immutable bis eine neue Version genehmigt wird.
┌───────────────────────────────┐
│ │
author edits │ │
──────────▶ [Draft] │
│ │
│ submit │
▼ │
[Submitted] │
│ │
┌─────────┴─────────┐ │
│ │ │
approve reject │
│ │ │
▼ ▼ │
[Approved] back to Draft │
│ with reason ────────────────┘
│
new draft for next version starts from here
Die Übergänge sind gegated. Nur Autor:innen können ein Dokument nach Submitted bewegen. Nur designierte Reviewer:innen (nicht die:der Autor:in) können es aus Submitted herausbewegen. Das System erzwingt das auf API-Ebene, nicht im UI. Kein Client-Side-Bypass kann einen Zustand ändern, ohne dass das Backend Akteur und Entscheidung loggt.
Approval ist nicht das Ende des Dokument-Lebens. Es ist das Ende dieser Version. Ein neues Draft für die nächste Version startet sofort, gebrancht vom Approved-Zustand, und der Zyklus wiederholt sich. Die Versions-Historie wächst linear durch genehmigte Versionen; Drafts und abgelehnte Submissions werden festgehalten, werden aber nie Teil der kanonischen Kette.
3. ETag-Optimistic-Locking: Concurrent-Editing ohne Last-Write-Wins-Falle
In operativen Kontexten kommt es oft genug vor, dass zwei Engineers dasselbe Dokument gleichzeitig editieren, dass man direkt dafür designen muss. Eine Review-First-Plattform handlet das mit Optimistic-Locking auf Basis von ETags.
Jedes Read eines Dokuments gibt einen ETag zurück, einen starken, versions-gekeyten Fingerprint des Dokument-States im Moment des Reads. Jedes Write muss den ETag enthalten, gegen den die:der Editor:in gearbeitet hat. Hat sich das Dokument zwischenzeitlich geändert, matcht der ETag den aktuellen State nicht mehr, und das Write wird mit einem Konflikt abgelehnt.
┌─────────────────────────────────────────────────┐ │ Editor A Server Editor B │ │ │ │ │ │ │ │ GET doc │ │ │ │ │◀───────── etag:v7 ─────────────│ │ │ │ │ │ GET doc │ │ │ │◀────────── etag:v7 ──────│ │ │ │ │ │ │ │ PUT etag:v7 │ │ │ │ │──────▶ (accepted, now v8) │ │ │ │ │ PUT etag:v7 │ │ │ │ │◀──── 409 Conflict ───────│ │ │ │ │ │ │ │ │ B re-reads, sees v8, │ │ │ │ resolves, retries │ └─────────────────────────────────────────────────┘
Die Konflikt-Response lehnt das Write nicht nur ab: sie gibt den aktuellen Dokument-State plus einen strukturierten Diff zwischen der veralteten Version der:des Editor:in und der aktuellen zurück. Editor:in B sieht, was Editor:in A geändert hat, kann den Konflikt explizit auflösen und mit dem aktualisierten ETag retryen.
Das ist mehr Reibung als Last-Write-Wins, und das mit Absicht: ein wenig Widerstand im richtigen Moment ist genau das, was Datenverlust verhindert. In der Praxis kostet es einen zusätzlichen Round-Trip, wenn ein Konflikt tatsächlich auftritt, und im Gegenzug verschwindet kein Edit je still.
ETag-Locking gilt für Drafts. Submitted-Dokumente sind eingefroren, keine Edits während Review. Approved-Dokumente sind immutable, überhaupt keine Edits; die nächste Version ist ein neues Draft, gebrancht vom Approved-State.
4. Pflicht-Reject-with-Reason: das Formular ist die Policy
Ein Review-Workflow ist nur so nützlich wie seine Reject-Mechanik. Ist "Reject" ein einzelner Button ohne Pflicht-Input, hören Reviewer:innen entweder auf abzulehnen (weil es Autor:innen ohne Signal lässt) oder lehnen ohne Erklärung ab (was Autor:innen trainiert, Rejections zu ignorieren). Keines produziert bessere Dokumente.
Die Lösung ist strukturell: Reject verlangt einen Grund. Die API weigert sich, ein Reject ohne nicht-leere Begründung zu speichern. Das UI exponiert das Reason-Feld als primäre Aktion des Reject-Affordance, nicht als Nachgedanken.
┌──────────────────────────────────────────────┐ │ Reject submission │ │ │ │ Document: incident-response-runbook v8 │ │ │ │ Category: ▼ [Required] │ │ ○ Incorrect technical detail │ │ ○ Missing required section │ │ ○ Conflicts with existing policy │ │ ○ Not aligned with current release │ │ ○ Other (requires explanation) │ │ │ │ Specific feedback: [Required] │ │ ┌─────────────────────────────────────────┐ │ │ │ Step 4 references the old isolation API. │ │ │ │ Update to use the unified action API per │ │ │ │ ARCH-2026-014. │ │ │ └─────────────────────────────────────────┘ │ │ │ │ References (optional): [link to spec/ticket] │ │ │ │ [Cancel] [Reject submission]│ └──────────────────────────────────────────────┘
Zwei Design-Entscheidungen in diesem Formular zählen über das Offensichtliche hinaus.
Erstens: Kategorien sind strukturiert, aber erweiterbar. Reporting auf "warum werden in diesem Team in diesem Quartal Dokumente abgelehnt" ist eine einzelne Aggregations-Query. Muster werden sichtbar: sind 60 % der Rejections in einem Quartal "Missing required section", braucht das Template Arbeit, nicht die Autor:innen.
Zweitens: Die Rejection selbst wird Teil der Dokument-Historie. Zukünftige Autor:innen, die den nächsten Draft editieren, sehen vorherige Rejections und ihre Gründe inline. Institutionelles Gedächtnis akkumuliert mit dem Dokument statt in einem Chat-Channel zu verschwinden.
5. Diff-Viewer: semantischer Vergleich statt textuellem Noise
Ein Diff zwischen zwei Dokument-Versionen ist das, worauf Reviewer:innen ihr Aufmerksamkeits-Budget verwenden. Textuelle Diffs (zeilenweise, der Default jedes Revision-Control-Tools) sind für Prosa-Dokumente noisy. Eine Absatz-Umformatierung produziert hunderte geänderte Zeilen, die keine semantische Änderung enthalten.
Ein Diff-Viewer für governte Dokumente muss auf Block-Ebene operieren: Wurde diese Überschrift hinzugefügt? Dieser Absatz umgeschrieben? Diese Liste umsortiert? Diese Tabelle modifiziert? Reviewer:innen können in textuelle Diffs hineinexpandieren, wo sie genau inspizieren wollen, aber die Default-Ansicht zeigt die Änderungen in der Granularität, die für Approval-Entscheidungen zählt.
┌────────────────────────────────────────────────────────┐ │ Diff: runbook v7 → v8 (submitted) │ │ │ │ ▼ Section 3.2 "Initial Triage" - modified │ │ Paragraph 2 rewritten [expand] │ │ │ │ ▼ Section 4 "Containment" - modified │ │ Step 4: old "call /isolate endpoint" │ │ new "submit isolate action" │ │ │ │ ▶ Section 5 "Notification" - unchanged │ │ ▶ Section 6 "Audit" - unchanged │ │ │ │ + Section 7 "Post-incident review" - added │ │ │ │ [Approve] [Reject with reason] │ └────────────────────────────────────────────────────────┘
Die Ansicht zeigt auch Edits an Metadaten: Owner-Change, Tag-Change, Klassifizierungs-Change. Die sind oft konsequenter als Content-Änderungen (ein "Public"-Dokument still zu "Internal" reklassifiziert kann Downstream-Automatisierung brechen), und sollten für Reviewer:innen nie unsichtbar sein.
6. Immutable-Versionierung: Append-Only-Historie, Punkt
Jede genehmigte Version wird als immutable Record gespeichert. Die Storage-Schicht ist auf der API Append-Only; es gibt keine "edit a previous version"-Operation, kein Admin-Override, kein "ersetze diese Version durch eine korrigierte"-Affordance.
Stellt sich eine zuvor genehmigte Version als falsch heraus, ist der Fix, eine neue Version zu autoren, sie durch Review zu führen und zu approven. Die falsche Version bleibt in der Historie als Record dessen, was zu jener Zeit genehmigt war. Das ist für manche Organisationen unbequem und tragend für den Rest des System-Werts: können vorherige Versionen still umgeschrieben werden, ist die Historie kein Beweis.
Die Immutability wird auf zwei Wegen erzwungen. Auf Daten-Ebene ist jede genehmigte Version inhalts-adressiert durch einen Hash ihres Contents plus Metadata. Auf Storage-Ebene sind die Records Write-Once. Ein Modifikations-Versuch produziert einen neuen Record mit neuem Hash; der vorherige Record bleibt unverändert.
Die Versions-Kette selbst ist vorwärts gehasht: der Record jeder Version enthält den Hash der vorherigen genehmigten Version. Die Kette kann zu jeder Zeit end-to-end verifiziert werden. Manipulation einer einzelnen Version bricht die Kette, und der Bruch ist detektierbar.
7. Der Audit-Record, der als Nebenprodukt aus dem Workflow fällt
Die Kombination aus expliziten Zuständen, Pflicht-Reject-Begründungen, ETag-gelockten Edits und immutabler Versionierung produziert einen Audit-Record als Nebeneffekt statt als separates Anliegen.
Für jedes Dokument, zu jedem vergangenen Zeitpunkt, kann das System beantworten:
- Was war am Datum X die genehmigte Version dieses Dokuments?
- Wer hat Version N wann submitted?
- Wer hat sie wann mit welcher Entscheidung reviewt?
- Falls rejected, was war der kategorisierte Grund und das spezifische Feedback?
- Welche Metadaten-Felder haben sich in dieser Version gegenüber der vorherigen geändert?
- Verifiziert die Versions-Kette sauber?
Das sind die Fragen, die ein:e Auditor:in stellt. Es sind auch die Fragen, die ein:e Incident-Responder:in stellt ("was sagte das Runbook, als dieser Incident begann?") und die Fragen, die ein:e Release-Manager:in stellt ("welche Policy war in Kraft, als diese Change genehmigt wurde?").
Derselbe Record erfüllt alle drei. Es gibt keinen separaten "Compliance-Export", der gegen das Live-System abgeglichen werden muss; der Workflow ist der Audit-Trail.
8. Was man eine Wissens-Plattform fragen sollte, bevor man auf sie setzt
Wer eine Knowledge-Management-Plattform für governte Dokumentation evaluiert, sollte folgende Fragen stellen.
Ist die genehmigte Version ein vom jüngsten Edit verschiedener Zustand, oder sind sie dasselbe? Wenn sie dasselbe sind, ist die Plattform ein Wiki mit Kommentar-Feld, keine Review-Plattform.
Wenn zwei Reviewer:innen gleichzeitig verschiedene submitted Versionen desselben Dokuments genehmigen, was passiert? Die ehrliche Antwort beinhaltet ETag-Locking auch auf Submissions, nicht nur auf Edits.
Kann eine Rejection ohne Grund gespeichert werden? Wenn ja, ist der Rejection-Record dekorativ.
Kann eine zuvor genehmigte Version modifiziert oder gelöscht werden? Wenn ja, ist die Historie nicht audit-grade.
Zeigen Sie mir die Chain-Verifikation. Gibt es keine Chain-Verifikation, gibt es keinen kryptographischen Anker; Manipulation ist nicht detektierbar.
Wie eine Plattform mit diesen Fragen umgeht, zeigt, ob sie die Governance-Arbeit tatsächlich geleistet oder nur die Wiki-Arbeit gemacht und sie Governance genannt hat.
Abschluss
Governte Dokumentation muss von Anfang an für die Anforderung designt sein, nicht nachträglich auf ein Wiki geschraubt. Das heißt: explizite Zustände, gelockte Edits, Pflicht-Reject-Rationale, semantische Diffs, immutable Versionen und eine verifizierbare Kette.
Die obige Mechanik ist nicht exotisch. Sie sind nüchterne Anwendungen gut verstandener Muster: Optimistic-Concurrency, Append-Only-Storage, hash-gekettete Verifikation, strukturierte Formulare als Policy-Durchsetzung. Die Investition liegt darin, sie über die gesamte Plattform einzufordern, nicht darin, etwas Neues zu erfinden.
Der nächste Beitrag dieser Serie steigt in die Code-Analyse-Seite von Thot ein: SAST-Ergebnisse, die bei jedem Commit eintreffen und unter derselben Governance-Disziplin wie die obigen Dokumente reviewt, suppressed oder gefixt werden müssen.
Weiterlesen
- RFC 7232, HTTP Conditional Requests (die kanonische ETag-Spec)
- ISO/IEC 27001:2022, Anhang A.5 (Documented information)
- Martin Kleppmann, Designing Data-Intensive Applications, Kapitel zu Concurrency Control
Unternehmensinfrastruktur abzusichern?
Vereinbaren Sie ein technisches Briefing. Kein Sales-Pitch, nur Architekten und Ihr Team.