Zum Hauptinhalt springen

Entitäten-Lebenszyklus: CRUD · Versionierung · Archiv statt Löschen (OP-CRUD-1)

Status: entschieden & umgesetzt — alle Entscheidungen E-CRUD-1…4 ✅ (Sign-off Auftraggeber 2026-06-27, §7), Slices C1–C4 ✅ gebaut (v0.19.0–0.22.0, §6) · Bezug: OP-CRUD-1 (Owning) · OP-AUDIT-1 (Versionierung) · OP-SEED-1/OP-BACKUP-1 (Retention) · OP-R3-1/3 (Prozess-Katalog) · Zielgruppe: IT-Dev/Architektur (Policy + Mechanik) · Business/Management (§3-Begründung „warum nie hart löschen") · True North: nur indirekt — saubere Lebenszyklen halten Referenzen, Statistiken und Audit intakt, auf denen die Antworten der drei Leitfragen rechnen

Kernaussage. Eine einheitliche Lebenszyklus-Politik je Entität (Wo fehlt CRUD? Was wird versioniert? Was wird beim „Löschen" archiviert statt hart gelöscht? Wie bleiben laufende Prozesse unversehrt?) — drei Festlegungen:

  1. Hart löschen ist die Ausnahme, nicht die Regel. Jede Entität mit Referenzen oder Historie wird archiviert/deaktiviert (Soft-Delete), nicht physisch entfernt — sonst entstehen verwaiste Verweise, kaputte Statistiken und Lücken im revisionssicheren Audit. Hart löschen nur bei referenzfreien, nicht-historischen Daten (und auch dann mit Audit-Event).
  2. Versionierung = das append-only Audit-Log (OP-AUDIT-1). Jede Mutation jeder Stammdaten-Entität erzeugt ein Audit-Event (wer·wann·vorher→nachher). Eine zweite, feld-eigene Versionierung braucht nur der Prozess-Katalog (Leistung/Teilschritt) — wegen der Wirkung auf laufende Aufträge (§4).
  3. Laufende Prozesse schützt das Prinzip „Materialisierung bei Auftragsstart" + Referenz-Guards. Ein laufender Auftrag trägt eigene Teilschritt-Instanzen (TeilschrittInstanz), nicht die Live- Katalog-Vorlage; Stammdaten-Archivierung entzieht einem laufenden Prozess nie die Grundlage, sondern wirkt nur vorwärts (keine neue Verwendung). Das war anfangs teils gebaut, teils Lücke (§5) — inzwischen sind die Slices C1–C4 ✅ umgesetzt (§6).

1. CRUD-Ist-Zustand je Entität

„Read" ist überall gegeben (State-Broadcast). C/U/D = Message-Handler in server/party/leitstand.ts.

EntitätCreateUpdateDelete (heute)Status-Enum vorhanden
Auftrag (R7)auftrag.createauftrag.aktion/…Archiv (Lifecycle→archiviert)AuftragStatus (Lifecycle)
Arbeitsplatz (R2)Soft (remove deaktiviert bei Referenz)ArbeitsplatzKonfigStatus (aktiv/in_wartung/gesperrt)
Taxonomie (G-1)Soft (deaktivieren; hart nur unreferenziert)— (über taxonomieInUse)
SchichtSoft (deaktivieren; hart nur unzugewiesen)SchichtArt
Infra-KostenpostenHart + Audit (#200)
Fotoregistriert– (immutable)Hart (R2-Objekt + Metadatum)
MitarbeiterArchiv (archiviert-Flag, C1 ✅)MitarbeiterStatus + archiviert
Skill (Katalog)Soft (aktiv-Flag; create reaktiviert)aktiv
Leistung (R3a)✅ (C3 ✅)update/setProzessSoft (status=inaktiv, UI dimmt)LeistungStatus (aktiv/inaktiv)
Teilschritt (R3b)✅ (C3 ✅)update/…Archiv (archiviert-Flag, C2 ✅)archiviert

Append-only (kein CRUD gewollt — OP-AUDIT-1): abwesenheitHistorie, befoerderungsHistorie, leistungsnachweise. Korrektur = kompensierender Eintrag, nie Update/Delete.

2. Lösch-Politik: drei Klassen

  • Klasse A — Archivieren/Soft-deaktivieren (Regel für Stammdaten mit Referenzen oder Historie): Mitarbeiter · Arbeitsplatz · Skill · Leistung · Teilschritt · Taxonomie · Schicht. „Löschen" setzt einen archiviert/inaktiv-Status → unsichtbar für neue Verwendung, aber referenzstabil. Reaktivierbar.
  • Klasse B — Lifecycle-Archiv (genau Auftrag): kein separates Delete, der Status-Lifecycle endet in archiviert (autoArchiviere). Revisions-/Auswertungs-relevant → bleibt erhalten.
  • Klasse C — Hart löschen + Audit (nur referenzfrei, nicht-historisch): Infra-Kostenposten · Foto. Physisches Entfernen, aber immer mit Audit-Event (wer·wann·was). Der einzige Massen-Destruktiv-Pfad bleibt der Purge (admin.purge, OP-SEED-1, owner-gegated).

Konsistenz-Notiz: Heute ist die Soft-Delete-Mechanik uneinheitlich (mal inaktiv, mal gesperrt, mal „deaktivieren bei …InUse"). E-CRUD-1 ✅ entschieden: vereinheitlichen über ein generisches archiviert-Flag (orthogonal zu den fachlichen Status-Enums; s. §7).

3. Warum nie hart löschen? (Business-Sicht)

  • Verwaiste Verweise brechen Auswertungen: ein gelöschter Mitarbeiter mit leistungsnachweise macht die Erfahrungs-/Auslastungs-Statistik unzuverlässig (True-North-Frage 1 „Auslastung").
  • Revisionssicherheit (DE/AT/CH, OP-COMPLIANCE-1): das Audit-Log verweist auf resource_ids — verschwindet die Entität, ist die Historie nicht mehr auflösbar („nicht reverse-engineerbar" bleibt, aber lesbar muss es sein).
  • Recht auf Vergessen (DSGVO) ist der bewusste Gegenfall → gezielter Purge/Anonymisierung statt beiläufigem Delete; gehört zu OP-SEED-1/OP-BACKUP-1-Retention, nicht in den CRUD-Alltag. ⮕ proaktiv geflaggt.

4. Versionierung: was braucht Änderungs-Historie?

  • Generisch über OP-AUDIT-1: jede Stammdaten-Mutation → Audit-Event. Das deckt „wer hat wann was geändert" für alle Entitäten ab — keine zweite Historie nötig für Mitarbeiter/Arbeitsplatz/Skill/Taxonomie/Schicht.
  • Eigene Versionierung nötig — Prozess-Katalog (Leistung/Teilschritt): Ändert sich die Vorlage, dürfen laufende Aufträge sich nicht rückwirkend ändern. Zwei Wege:
    • (heute) Materialisierung bei Auftragsstart — der Auftrag trägt TeilschrittInstanz-Kopien; Katalog- Änderungen wirken nur auf neue Aufträge. Einfach, robust, schon teilweise gebaut.
    • (Option) Katalog-Versionierung mit gültigAb — Vorlagen-Versionen explizit; Aufträge referenzieren die Version. Mächtiger (Nachvollziehbarkeit „welche Vorlage galt"), aber mehr Modell-Aufwand.
    • E-CRUD-2 ✅ entschieden: Materialisierung-bei-Start bestätigt; keine gültigAb-Versionierung jetzt (s. §7).
  • Bewusst kein Versionieren: infraKostenPosten (Korrektur = Audit-Event genügt), fotos (immutable).

5. Laufende Prozesse schützen (der Kern der Anforderung)

Invariante: Eine Stammdaten-Änderung/Archivierung darf einen laufenden Prozess nie in einen inkonsistenten oder gestoppten Zustand zwingen — sie wirkt nur vorwärts. Bausteine:

  1. Referenz-Guard vor Hard-Delete — referenzierte Entität ⇒ nur archivieren (teils gebaut: arbeitsplatz.remove deaktiviert statt löschen, wenn Belegung/geplante Schritte existieren, #225).
  2. Materialisierung — laufende Aufträge tragen eigene Instanzen (s. §4), nicht die Live-Vorlage.
  3. Geordnete Übergabe statt Entzug bei aktiven Bindungen:
    • Mitarbeiter inaktiv setzen, der gerade an einem Teilschritt arbeitet → der laufende Schritt wird pausiert/zur Neuzuweisung markiert (Klärfall-Prozess, Lastenheft §5.1), nicht hart entkoppelt.
    • Arbeitsplatz sperren, der belegt ist → Belegung erst sauber umziehen/freigeben, dann sperren.
    • Skill deaktivieren, der eine laufende Eignung trägt → Eignungsberechnung muss tolerant sein (fehlender/inaktiver Skill ⇒ kein Crash, nur keine neue Eignung).
  4. Solver-RobustheitbuildProblem/Scheduler dürfen bei inaktiven/archivierten Stammdaten nicht brechen (sie filtern auf „aktiv", behalten aber gepinnte/laufende Zuweisungen). E-CRUD-3 ✅ macht die Testmatrix dafür zum blockierenden Gate (§7).

6. Lücken & Slices (Vorschlag)

Echte CRUD-Lücken aus §1. Entschiedene Reihenfolge (E-CRUD-3, §7): C1 ✅ → C2 → C4 → C3.

  • C1 · Mitarbeiter-Archivierung. ✅ gebaut (0.19.0). employee.archivieren/employee.reaktivieren (admin-gegated, Audit-Event mitarbeiter.archiviert/.reaktiviert) setzen das generische archiviert-Flag (E-CRUD-1; Archivierbar-Interface + istArchiviert/nurAktive in server/src/model/types.ts). Archivierte sind aus aktiver Verwendung genommen (Solver schedulerInput, Zähler, Ausbildungs-/Niveau- Vorschläge, Engpass-Hinweis, Ausfall-Sicht — alle via nurAktive), bleiben aber referenzstabil (Leistungsnachweise/Historie/Audit auflösbar) und reaktivierbar. Laufende Bindung: der Live-Task wird gelöst (Schritt fällt zur Neuzuweisung an, wie bei Verfügbarkeit≠aktiv) — geordnete Übergabe statt Entzug. UI: „Archivieren"-Button (mit Rückfrage) + eigener Archiviert-Abschnitt mit „Reaktivieren". Self-Test test:archiv. Kein Migrationsbedarf (archiviert? optional, undefiniert = aktiv). Schließt die wichtigste Lücke (Personal kommt/geht), revisionssicher.
  • C2 · Soft-Delete vereinheitlichen. ✅ gebaut (0.20.0). Bei der Umsetzung zeigte sich: Skill (aktiv, create reaktiviert) und Leistung (status=inaktiv, UI dimmt) haben bereits einen funktionierenden Soft-Delete — ein zweites archiviert-Flag wäre redundant. Die einzige echte Lücke war Teilschritt (gar kein Flag): dort das generische archiviert-Flag nachgezogen (Teilschritt extends Archivierbar) + teilschritt.archivieren/reaktivieren (admin-gegated, Audit teilschritt.archiviert/.reaktiviert). Running-process-Schutz (E-CRUD-2): archivierte Vorlagen werden nur am Angebots-Punkt gefiltert (Add-Dropdown der Prozess-Komposition); buildProzessKatalog resolved sie weiter (bestehende Leistungs-Prozesse + materialisierte Auftrags-Instanzen bleiben intakt). UI (processes.component): Archivieren/Reaktivieren-Button + dimmt archivierte Vorlagen. Ergebnis: alle Klasse-A-Entitäten haben jetzt „archiv statt löschen" — Skill/Leistung über ihr fachliches Flag, Mitarbeiter/Teilschritt über das generische archiviert. (Eine kosmetische Voll-Vereinheitlichung Skill/Leistung → generisches Flag ist niedrig-prioritärer Folgeschritt, kein Mehrwert/Risiko jetzt.)
  • C3 · Prozess-Katalog Create. ✅ gebaut (0.22.0). Neue Teilschritt-Vorlagen und Leistungen im Katalog anlegen (teilschritt.create/leistung.create, admin-gegated + Audit *.erstellt; pure erstelleTeilschritt/erstelleLeistung in operativ/prozess.ts mit sinnvollen Defaults, G-3-konform; Self-Test test:prozess). Delete ist bereits abgedeckt (Teilschritt = Archiv C2, Leistung = status-Soft). Damit ist der Prozess-Katalog voll editierbar. Client (processes.component): „+ Neuer Teilschritt"/ „+ Neue Leistung". Running-process-Sicherheit ist durch E-CRUD-2 (Materialisierung) + C4-Gate abgedeckt.
  • C4 · Running-process-Testmatrix. ✅ gebaut (0.21.0) (E-CRUD-3, blockierender CI-Gate). Self-Test test:running-process (server/src/operativ/running-process-demo.ts, im Server-CI-Job vor solve): beweist über die pure buildProblem-Fläche (1) Mitarbeiter archiviert → nurAktive nimmt ihn aus dem Solver-Input, buildProblem läuft ohne Crash weiter und plant dieselben Aufträge (nur der Pool fehlt ihn); (2) Teilschritt-Vorlage archiviert (bleibt im Input — schedulerInput filtert Vorlagen nicht) → die Aufträge behalten alle Schritte (Resolve/Materialisierung schützt Laufendes, E-CRUD-2). Damit ist die Schutz-Invariante „laufende Prozesse bleiben heil" maschinell gegen Regressionen gesichert.

7. Entscheidungen

  • E-CRUD-1 — Soft-Delete-Mechanik → ✅ ENTSCHIEDEN 2026-06-27: (A) generisches archiviert-Flag. Einheitlich archiviert: boolean (+ archiviertAm, optional archiviertVon) über alle Klasse-A-Entitäten, statt je Entität ein eigenes Status-Enum. Begründung des Auftraggebers: uniforme, leicht prüfbare Semantik (ein Coverage-/Filter-Muster für alle). Folge für die Umsetzung: das Flag wird additiv neben den bestehenden fachlichen Status-Enums geführt (MitarbeiterStatus/ArbeitsplatzKonfigStatus/LeistungStatus bleiben für fachliche Zustände wie urlaub/in_wartung; archiviert ist die orthogonale Lebenszyklus- Dimension „aus dem aktiven Bestand genommen"). Solver/Anzeige filtern generisch auf !archiviert.
  • E-CRUD-2 — Prozess-Katalog-Schutz → ✅ ENTSCHIEDEN 2026-06-27: Materialisierung-bei-Start bestätigt. Laufende Aufträge tragen TeilschrittInstanz-Kopien; Katalog-Änderungen wirken nur vorwärts. Keine gültigAb-Versionierung jetzt — erst bei nachweisbarem Bedarf (dann eigener OP). Die Umsetzung muss die Materialisierung explizit absichern (C4-Testmatrix).
  • E-CRUD-3 — Slice-Reihenfolge & Testmatrix-Gate → ✅ ENTSCHIEDEN 2026-06-27. Reihenfolge nach C1 ✅: C2 → C4 → C3 — erst das generische archiviert-Flag über die restlichen Klasse-A-Entitäten (Skill/Leistung/Teilschritt; Arbeitsplatz/Taxonomie/Schicht haben bereits Soft-Delete) breit vereinheitlichen (C2), dann die Running-process-Testmatrix als blockierenden CI-Gate festzurren (C4), zuletzt der Prozess-Katalog Create/Delete (C3). Die Testmatrix ist ein blockierender Gate (Server- CI-Job, wie test:archiv): „archiviere/ändere ein Stammdatum während laufendem Prozess → der Prozess läuft/ pausiert sauber, kein Crash/Datenverlust" muss grün sein, sonst rot. Begründung: Konsistenz vor neuer Fläche; die Schutz-Invariante (laufende Prozesse bleiben heil) ist billige, dauerhafte Versicherung.
  • E-CRUD-4 — Klasse-C-Hart-Delete → ✅ ENTSCHIEDEN 2026-06-27: (A) Hart-Delete für Infra-Kosten/Foto beibehalten. Die einzigen referenzfreien, nicht-historischen Entitäten bleiben physisch löschbar (infraKosten.entfernen, foto.entfernen) — mit Audit-Event (OP-AUDIT-1). Begründung: kein Schutzgewinn durch ein zweites Soft-Delete-Modell (keine verwaisten Referenzen, das Audit hält den Vorgang fest); bei Fotos spricht DSGVO/„Recht auf Vergessen" sogar für echtes Löschen statt dauerhaftes Liegenlassen im R2-Speicher. Damit ist OP-CRUD-1 vollständig entschieden und umgesetzt (Slices C1–C4 ✅).

8. Bezüge

OP-AUDIT-1 (Versionierungs-Substrat), OP-SEED-1 (Purge = der bewusste Destruktiv-Pfad), OP-DATA-1 (Persistenz/Migrationen der betroffenen Felder), OP-BACKUP-1 (Retention/Recht-auf-Vergessen), OP-COMPLIANCE-1 (Revisionssicherheit DE/AT/CH), OP-R3-1/3 (Prozess-Katalog), Lastenheft §5.1 (Klärfall-Prozess = geordnete Unterbrechung). Tracking: HANDOFF §4 (OP-CRUD-1).


↩ Zurück zur Doku-Landkarte · Lesepfade · Register (alle OPs)