5.2 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:
TenantSymbolum 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.jsprisma/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:
seed-icons-only.jsläuft (weil Icon-Zahl < 100)deleteMany({ isSystem: true })löscht alle System-IconsonDelete: Cascadelöscht alleTenantSymbol-Einträge- Neue Icons werden mit neuen UUIDs erstellt
- 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 < 100war 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:
deleteManyausseed.jsundseed-icons-only.jsentfernt- Stattdessen Upsert-Logik: Update by
fileKey, create only if missing - Dadurch bleiben bestehende IDs erhalten, und es gibt keine Cascade-Löschungen mehr
prisma/migrate.jsum 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:
- Alle System-Icons aus
public/signaturen/neu in die DB einspielt - Für jeden Tenant die Standard-Symbole neu aktiviert
- Die Zeichnungen scannt und die
iconId-Referenzen auf die neuen IDs updated
Lessons Learned
- Seed-Skripte dürfen niemals
deleteManyauf verknüpfte Daten ausführen onDelete: Cascadeist gefährlich bei Daten, die von Benutzern referenziert werden- Container-Start-Skripte müssen idempotent sein (mehrfaches Ausführen = gleiches Ergebnis)
- Vor Deployment-Änderungen sollte ein DB-Backup gemacht werden
Nächste Schritte
- Recovery-Skript erstellt:
prisma/recover-symbols.js(Sidebar/Admin) - Recovery-Skript erstellt:
prisma/recover-features.js(Zeichnungen) - Renderer resilient gemacht: broken Symbole zeigen ⚠️ statt leeres Nichts
onDelete: Cascade→onDelete: SetNullauf TenantSymbol.icon geändert- Seed-Skripte auf Upsert umgestellt (Commit
5adadd2) recover-symbols.jsauf Server ausführenrecover-features.js --dry-runauf Server ausführen zur Analyse- Falls broken Features: User informieren (Symbole manuell neu platzieren)