Skip to content

OpsWeave — Soft-Delete-Strategie

AUDIT-FIX: L-09 — Dokumentiert, welche Entitaeten Soft-Delete vs. Hard-Delete verwenden.


Prinzip

Entitaeten, die Audit Trails erfordern oder von historischen Datensaetzen referenziert werden koennten, sollten Soft-Delete nutzen (is_active = 0). Junction-Tabellen, Konfigurationsdaten und kurzlebige Datensaetze duerfen Hard-Delete mit referentiellen Integritaetspruefungen verwenden.


Aktueller Stand

Soft-Delete (is_active = 0)

EntitaetTabelleLoeschansatzHinweise
Kundencustomersis_active = 0Prueft auf offene Tickets vor Deaktivierung. Bestehende Tickets behalten die Kundenreferenz.

Hard-Delete (Zeile entfernen)

EntitaetTabelleReferenzpruefungHinweise
Benutzer-Mitgliedschafttenant_user_membershipsSelbstloeschung verhindertEntfernt Benutzer aus Mandant
Gruppen-Mitgliedschaftuser_group_membershipsKeineJunction-Tabelle
Zuweisungsgruppenassignee_groupsKaskadierend (Mitglieder zuerst)Entfernt Gruppe + Mitgliedschaften
AssetsassetsPrueft verknuepfte TicketsCMDB-Elemente — Soft-Delete empfohlen
Asset-Beziehungenasset_relationsKeineDAG-Kanten
Ticket-Kategorienticket_categories409 falls Tickets zugewiesenHard-Delete nur wenn unbenutzt
Workflow-Vorlagenworkflow_templatesPrueft aktive InstanzenHat is_active-Spalte, loescht aber hart
KB-Artikelkb_articlesEntfernt Verknuepfungen zuerstNutzt status-Feld, nicht is_active

Empfehlung

Entitaeten, die in einem kuenftigen Release auf Soft-Delete migriert werden sollten:

EntitaetGrund
AssetsCMDB-Elemente werden von Tickets, SLA-Ketten, Compliance-Flags referenziert. Hard-Delete zerstoert historischen Kontext.
Workflow-VorlagenAbgeschlossene Workflow-Instanzen referenzieren die Vorlage. Soft-Delete bewahrt Audit Trail.
KB-ArtikelHat bereits status: 'archived' — das statt Hard-Delete nutzen.
SLA-DefinitionenHistorische Tickets referenzieren SLA-Stufen. Deaktivierung ist sicherer als Loeschung.
E-Mail-KonfigurationenEmpfangene Nachrichten referenzieren die Konfiguration. Deaktivierung bewahrt Nachrichtenverlauf.

Migrationsmuster

typescript
// Statt:
await db.delete(entity).where(eq(entity.id, id));

// Verwende:
await db.update(entity).set({ is_active: 0, updated_at: now }).where(eq(entity.id, id));

Stelle sicher, dass alle Listen-Queries standardmaessig WHERE is_active = 1 filtern, mit einem optionalen include_inactive-Parameter fuer Admin-Ansichten.

Veröffentlicht unter der AGPL-3.0 Lizenz.