All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 22m1s
140 lines
5.2 KiB
Markdown
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)
|