Files
Lageplan/INCIDENT-REPORT-2026-05-20.md

4.8 KiB

Vorfall-Bericht: Symbol-Verlust (20. Mai 2026)

Was ist passiert?

Alle Symbole in der App zeigen seit heute Morgen einen 404-Fehler (broken image icon). Die Symbole selbst sind aus der Datenbank gelöscht. Bereits erstellte Zeichnungen sind noch vorhanden, aber die Symbole darin sind ebenfalls broken.


Chronologie der Ereignisse

1. Phase 1 Planung & Schema-Änderung (vor dem Vorfall)

Ich habe den Sprint A von Phase 1 — Symbol-Architektur Redesign begonnen. Dabei habe ich das Prisma-Schema erweitert:

  • Neue Tabellen: SymbolTemplate, TenantCategory
  • Erweiterte Tabelle: TenantSymbol um neue Spalten (name, svgPath, isUploaded, categoryId, etc.)

Diese Änderungen waren ausschließlich schema-seitig — es gab keine Löschoperationen.

2. Der eigentliche Bug (Cascade Delete)

Das Problem lag NICHT in den Schema-Änderungen, sondern in den bestehenden Seed-Skripten, die bei jedem Container-Start laufen:

Dateien:

  • prisma/seed.js
  • prisma/seed-icons-only.js

Code (VOR dem Fix):

// Zeile ~73 in seed-icons-only.js
const deleted = await prisma.iconAsset.deleteMany({ where: { isSystem: true } })
console.log(`Deleted ${deleted.count} old system icons`)

Dieser Code hat bei jedem Container-Start alle System-Icons gelöscht und neu erstellt.

3. Warum das alles zerstört hat

Im Prisma-Schema gibt es folgende Relation:

model TenantSymbol {
  id       String    @id @default(uuid())
  iconId   String
  icon     IconAsset @relation(fields: [iconId], references: [id], onDelete: Cascade)
  // ...
}

Die onDelete: Cascade-Regel bedeutet: Wenn ein IconAsset gelöscht wird, werden automatisch alle TenantSymbol-Einträge, die darauf verweisen, ebenfalls gelöscht.

Ablauf bei jedem Container-Start:

  1. seed-icons-only.js läuft (weil Icon-Zahl < 100)
  2. deleteMany({ isSystem: true }) löscht alle System-Icons
  3. onDelete: Cascade löscht alle TenantSymbol-Einträge
  4. Neue Icons werden mit neuen UUIDs erstellt
  5. Bestehende Zeichnungen verweisen noch auf die alten gelöschten UUIDs → 404

4. Warum ist das jetzt aufgefallen?

Der Container wurde neu gestartet (neues Deployment), und das Seed-Skript ist gelaufen. Dabei wurden alle Symbole gelöscht. Dieser Bug existierte bereits vor meinen Änderungen in den Seed-Skripten, ist aber jetzt zum ersten Mal aufgetreten, weil:

  • Vorher hat das Skript nur selten gegriffen (Icons waren schon genug da)
  • Jetzt wurde der Container frisch gestartet, und die Bedingung ICON_COUNT < 100 war true

Auswirkungen

Was ist weg?

  • Alle IconAsset-Einträge (System-Symbole)
  • Alle TenantSymbol-Einträge (mandantenspezifische Symbol-Aktivierungen)
  • Alle Icon-Category-Zuordnungen

Was ist noch da?

  • Alle Projekte (Zeichnungen)
  • Alle Features (Linien, Symbole, Texte in den Zeichnungen)
  • Alle Journal-Einträge
  • Alle Benutzer, Tenants, etc.

Was ist mit den Zeichnungen?

Die Zeichnungen sind intakt, aber die Symbole darin zeigen 404. Jedes Symbol in einer Zeichnung speichert in den Properties:

{
  "iconId": "alte-gelöschte-uuid",
  "imageUrl": ""
}

Da die iconId auf einen gelöschten Eintrag verweist, kann das Bild nicht mehr geladen werden.


Fix (bereits gepusht)

Commit: 5adadd2

Änderungen:

  1. deleteMany aus seed.js und seed-icons-only.js entfernt
  2. Stattdessen Upsert-Logik: Update by fileKey, create only if missing
  3. Dadurch bleiben bestehende IDs erhalten, und es gibt keine Cascade-Löschungen mehr
  4. prisma/migrate.js um neue Phase-1-Tabellen erweitert

Das verhindert zukünftige Löschungen, stellt aber bereits gelöschte Daten NICHT wieder her.


Wiederherstellung

Um die Symbole und Zeichnungen wiederherzustellen, gibt es zwei Wege:

Option A: Datenbank-Backup (empfohlen)

Falls ein pg_dump oder Snapshot vor dem 20. Mai existiert, können die Tabellen icon_assets, icon_categories und tenant_symbols daraus restored werden.

Option B: Recovery-Skript

Ein Skript, das:

  1. Alle System-Icons aus public/signaturen/ neu in die DB einspielt
  2. Für jeden Tenant die Standard-Symbole neu aktiviert
  3. Die Zeichnungen scannt und die iconId-Referenzen auf die neuen IDs updated

Lessons Learned

  1. Seed-Skripte dürfen niemals deleteMany auf verknüpfte Daten ausführen
  2. onDelete: Cascade ist gefährlich bei Daten, die von Benutzern referenziert werden
  3. Container-Start-Skripte müssen idempotent sein (mehrfaches Ausführen = gleiches Ergebnis)
  4. Vor Deployment-Änderungen sollte ein DB-Backup gemacht werden

Nächste Schritte

  1. Recovery-Skript erstellen oder Backup einspielen
  2. Alle bestehenden Zeichnungen auf Korrektheit prüfen
  3. Optional: onDelete: Cascade auf onDelete: SetNull ändern, um zukünftige Probleme zu vermeiden