Files
Lageplan/INCIDENT-REPORT-2026-05-20.md
Pepe Ziberi a53f77c97c
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 22m1s
fix(db): comprehensive symbol recovery + safety fixes
2026-05-20 15:05:44 +02:00

140 lines
5.2 KiB
Markdown

# 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):**
```javascript
// 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:
```prisma
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:
```json
{
"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. [x] Recovery-Skript erstellt: `prisma/recover-symbols.js` (Sidebar/Admin)
2. [x] Recovery-Skript erstellt: `prisma/recover-features.js` (Zeichnungen)
3. [x] Renderer resilient gemacht: broken Symbole zeigen ⚠️ statt leeres Nichts
4. [x] `onDelete: Cascade``onDelete: SetNull` auf TenantSymbol.icon geändert
5. [x] Seed-Skripte auf Upsert umgestellt (Commit 5adadd2)
6. [ ] `recover-symbols.js` auf Server ausführen
7. [ ] `recover-features.js --dry-run` auf Server ausführen zur Analyse
8. [ ] Falls broken Features: User informieren (Symbole manuell neu platzieren)