Files
Laufzettel/docs/issues/009-vorlagen-versionierung.md
florian.wilde d8d5444e9f
Prüfung / pruefung (push) Canceled after 0s
Prüfung / e2e (push) Canceled after 0s
feat(vorlagen): Versionierung, Unveraenderlichkeit und JSON-Austausch (#23)
2026-09-25 06:10:01 +00:00

5.5 KiB
Raw Permalink Blame History

#009 M4 – Vorlagen-Versionierung im Service

Status: erledigt Meilenstein: v0.1.0 Labels: phase-1, backend Geschätzt: 6 h Tatsächlich: 1 h 20 min

Ziel

Die harte Regel der Anwendung: eine veröffentlichte Version ist für immer unveränderlich, damit ein Archiv-Lauf für immer nachvollziehbar bleibt. Diese Regel sitzt in der Service-Schicht, nicht in der Oberfläche.

Aufgaben

  • Services für Vorlage, VorlagenVersion, VorlagenAbschnitt, VorlagenSchritt, VorlagenVariable
  • versionVeroeffentlichen: setzt status = VEROEFFENTLICHT, veroeffentlichtAm, veroeffentlichtVonId, Änderungsnotiz, Protokoll-Eintrag
  • entwurfHolenOderErzeugen: tiefe Kopie der letzten veröffentlichten Version als neuer Entwurf mit fortlaufender version; kopiert Variablen, Abschnitte und Schritte samt konfig
  • Höchstens ein Entwurf je Vorlage — durchgesetzt vom partiellen Eindeutigkeitsindex VorlagenVersion_ein_entwurf, der zweite gleichzeitige Aufruf bekommt denselben Entwurf
  • Jede Schreiboperation auf einer veröffentlichten Version wirft; zentral in versionMussEntwurfSein() — und zusätzlich in der Datenbank per Trigger
  • Läufe verweisen ausschließlich auf veröffentlichte Versionen — veroeffentlichteVersionPruefen() für #013
  • vorlageDuplizieren: neue Vorlage mit Entwurf als Kopie
  • JSON-Export und -Import mit Zod-Schema, Format in docs/vorlagen-format.md dokumentiert (Version des Formats, Abschnitte, Schritte, Variablen, konfig)
  • Rechte: REDAKTEUR und ADMIN dürfen anlegen, bearbeiten, veröffentlichen; TECHNIKER und LESER nicht

Akzeptanzkriterien

  • Test: nach dem Veröffentlichen schlägt jede Änderung an Version, Abschnitten, Schritten und Variablen fehl
  • Test: „Bearbeiten“ erzeugt eine tiefe Kopie — Änderungen am Entwurf lassen die veröffentlichte Version unberührt, auch in verschachtelten konfig-Feldern
  • Test: ein zweiter Entwurf wird abgelehnt
  • Test: ein Lauf auf Version 1 bleibt nach Veröffentlichen von Version 2 unverändert und zeigt weiter die Schritte aus Version 1
  • Test: Export und anschließender Import ergeben eine inhaltsgleiche Vorlage
  • Test: TECHNIKER darf nicht veröffentlichen
  • Test: Veröffentlichen schreibt einen Protokoll-Eintrag

Beim Bauen aufgefallen

  • Die Lesemodelle haben die Mandantengrenze verloren, sobald jemand suchte. Der Suchfilter brachte einen zweiten OR-Schlüssel in dasselbe Objekt; in JavaScript gewinnt der letzte, also ersetzte er die Kundenbedingung. Ein einzelner Buchstabe im Suchfeld gab einem gebundenen Techniker alle Vorlagen aller Kunden. versionsHistorie und versionMitAufbau haben überhaupt nicht gefiltert — damit lagen Abschnittstitel, Schritte und PowerShell-Befehle fremder Kunden offen. Ursache ist banal: zu src/server/queries/vorlagen.ts gab es keinen einzigen Test. Es gibt jetzt tests/vorlagen-sicht.test.ts, und die Kundenbedingung steht in einem AND-Eintrag, wo kein weiterer Filter sie überschreiben kann.
  • Die Unveränderlichkeit hing allein am Service. Migrationen, psql, ein Seed-Skript und ab Phase 4 die Connectoren schreiben daran vorbei — und genau diese Regel ist der Grund, warum ein Archiv-Lauf in zehn Jahren noch etwas wert ist. Vier Trigger setzen sie jetzt in der Datenbank durch, einer davon verbietet den Rückweg VEROEFFENTLICHT → ENTWURF, der sonst alles andere ausgehebelt hätte.
  • Prisma will handgeschriebene Datenbankobjekte löschen. prisma migrate dev erzeugte für die neue Migration sieben DROP-Anweisungen gegen Trigger, zusammengesetzte Fremdschlüssel und Trigramm-Indizes — aus Prismas Sicht sind sie Abweichungen von der Vorgabe. Wer sie einmal übersieht, entfernt stillschweigend die Mandantengrenze. tests/datenbankregeln.test.ts zählt diese Objekte jetzt namentlich auf und macht jeden Verlust laut.
  • Die Trigger haben schlechte Test-Fixtures entlarvt. Mehrere legten eine Version als VEROEFFENTLICHT an und füllten sie danach — also genau das, was die Regel verbietet. Der Service hatte das nie gesehen, weil die Fixtures direkt über Prisma schrieben.
  • Zwei Redakteure am selben Entwurf überschrieben sich spurlos. Entwürfe werden bewusst nicht protokolliert, die Arbeit wäre also auch nicht wiederherstellbar gewesen. entwurfSpeichern nimmt jetzt den erwarteten Stand (geaendertAm) und weist ein Speichern auf einem überholten Stand ab.
  • Zod war achtmal einzeln eingebunden, die deutschen Meldungen hingen davon ab, dass jede Datei daran denkt. Jetzt gibt es src/lib/validierung.ts als einzige Quelle, und eine ESLint-Regel weist einen direkten zod-Import ab.
  • Der Doku-Link eines Schritts nahm jedes Schema an, auch javascript:alert(1). Er landet in der Abarbeitungsansicht als href — über eine importierte Datei wäre das fremder Code im Browser des Technikers. Erlaubt sind jetzt nur http und https.
  • Der Export verwarf bei jeder Beanstandung das ganze konfig. Ein shell: "zsh" aus einer späteren Fassung kostete lautlos auch den befehl — in genau der Datei, die jemand zum Umzug braucht. Exportiert wird jetzt der rohe Inhalt; abgewiesen wird beim Import, laut und mit Pfad.
  • Zwei gleichzeitige Testläufe gegen dieselbe Datenbank (mein Lauf und der des Review-Agenten) ergaben 62 falsche Fehlschläge, weil TRUNCATE dem anderen die Daten unter den Füßen wegzieht. Das war mein Fehler im Auftrag an den Agenten; CLAUDE.md nennt jetzt den Befehl für eine eigene Review-Datenbank.