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:
- 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).
- 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).
- 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ät | Create | Update | Delete (heute) | Status-Enum vorhanden |
|---|---|---|---|---|
| Auftrag (R7) | ✅ auftrag.create | ✅ auftrag.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) |
| Schicht | ✅ | ✅ | Soft (deaktivieren; hart nur unzugewiesen) | SchichtArt |
| Infra-Kostenposten | ✅ | ✅ | Hart + Audit (#200) | — |
| Foto | ✅ registriert | – (immutable) | Hart (R2-Objekt + Metadatum) | — |
| Mitarbeiter | ✅ | ✅ | ✅ Archiv (archiviert-Flag, C1 ✅) | MitarbeiterStatus + archiviert |
| Skill (Katalog) | ✅ | ✅ | ✅ Soft (aktiv-Flag; create reaktiviert) | aktiv |
| Leistung (R3a) | ✅ (C3 ✅) | ✅ update/setProzess | ✅ Soft (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
leistungsnachweisemacht 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).
- (heute) Materialisierung bei Auftragsstart — der Auftrag trägt
- 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:
- Referenz-Guard vor Hard-Delete — referenzierte Entität ⇒ nur archivieren (teils gebaut:
arbeitsplatz.removedeaktiviert statt löschen, wenn Belegung/geplante Schritte existieren, #225). - Materialisierung — laufende Aufträge tragen eigene Instanzen (s. §4), nicht die Live-Vorlage.
- 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).
- Solver-Robustheit —
buildProblem/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-Eventmitarbeiter.archiviert/.reaktiviert) setzen das generischearchiviert-Flag (E-CRUD-1;Archivierbar-Interface +istArchiviert/nurAktiveinserver/src/model/types.ts). Archivierte sind aus aktiver Verwendung genommen (SolverschedulerInput, Zähler, Ausbildungs-/Niveau- Vorschläge, Engpass-Hinweis, Ausfall-Sicht — alle vianurAktive), 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-Testtest: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,createreaktiviert) und Leistung (status=inaktiv, UI dimmt) haben bereits einen funktionierenden Soft-Delete — ein zweitesarchiviert-Flag wäre redundant. Die einzige echte Lücke war Teilschritt (gar kein Flag): dort das generischearchiviert-Flag nachgezogen (Teilschritt extends Archivierbar) +teilschritt.archivieren/reaktivieren(admin-gegated, Auditteilschritt.archiviert/.reaktiviert). Running-process-Schutz (E-CRUD-2): archivierte Vorlagen werden nur am Angebots-Punkt gefiltert (Add-Dropdown der Prozess-Komposition);buildProzessKatalogresolved 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 generischearchiviert. (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; pureerstelleTeilschritt/erstelleLeistunginoperativ/prozess.tsmit sinnvollen Defaults, G-3-konform; Self-Testtest: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 vorsolve): beweist über die purebuildProblem-Fläche (1) Mitarbeiter archiviert →nurAktivenimmt ihn aus dem Solver-Input,buildProblemläuft ohne Crash weiter und plant dieselben Aufträge (nur der Pool fehlt ihn); (2) Teilschritt-Vorlage archiviert (bleibt im Input —schedulerInputfiltert 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. Einheitlicharchiviert: boolean(+archiviertAm, optionalarchiviertVon) ü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/LeistungStatusbleiben für fachliche Zustände wieurlaub/in_wartung;archiviertist 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. Keinegü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, wietest: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)