/** * Recovery-Skript für gelöschte Symbole * * ACHTUNG: Dieses Skript kann die Symbole in der Sidebar wiederherstellen, * aber BESTEHENDE ZEICHNUNGEN (Features) bleiben broken, weil die alten * iconId-UUIDs in den Feature-Properties für immer verloren sind. * * Ausführung: * node prisma/recover-symbols.js * * Umgebung: * DATABASE_URL muss gesetzt sein (oder .env.docker geladen werden) */ const { PrismaClient } = require('@prisma/client') const fs = require('fs') const path = require('path') const prisma = new PrismaClient() const SVG_DIR = path.join(__dirname, '..', 'public', 'signaturen') // Kategorie-Definitionen (wie im Original-Seed) const catDefs = [ { name: 'Wasser', description: 'Wasser, Hydranten, Leitungen', sortOrder: 2, patterns: ['Wasser', 'Hydrant', 'Reservoir', 'Druckleitung', 'Druckleistung', 'Transportleitung', 'Oberflurhydrant', 'Unterflurhydrant', 'Innenhydrant', 'Wasserloeschposten', 'Wasserversorgung', 'Moeglicher_Wasserbezugsort', 'Stehendes_Gewaesser', 'Schieber'], }, { name: 'Feuer', description: 'Brand, Feuerwehr, Entwicklung', sortOrder: 3, patterns: ['Feuer', 'Brandherd', 'Entwicklungsgrenze', 'Horizontale_Entwicklung', 'Vertikale'], }, { name: 'Gefahr / Stoffe', description: 'Chemie, Gas, Biologie, Strom', sortOrder: 4, patterns: ['Chemie', 'Chemikalien', 'Biologische', 'Gas', 'Elektrizitaet', 'Gefaehrliche', 'Explosion', 'Gefahr_durch_Loeschen'], }, { name: 'Technik / Gebäude', description: 'Lifte, Türen, Treppen, Tableaus', sortOrder: 5, patterns: ['Lift', 'Treppe', 'Eingang', 'Tableau', 'Entrauchung', 'Sprinkler', 'Kamin', 'Brandmeldezentrale', 'Brandschutztueren', 'Elektrotableau', 'Fernsignaltableau', 'Luefter', 'Decke_eingestuerzt', 'AnzahlGeschosse'], }, { name: 'Gebäude / Schäden', description: 'Gebäude, Zerstörung, Schäden', sortOrder: 6, patterns: ['Beschaedigung', 'Teilzerstoerung', 'Totalzerstoerung', 'Bruecke'], }, { name: 'Einsatzführung', description: 'Führung, Organisation, Kommunikation', sortOrder: 7, patterns: ['Einsatzleiter', 'ADL', 'KP_', 'Kontrollstelle', 'Informationszentrum', 'Medienkontaktstelle', 'Sanitaet', 'Sanitaetshilfsstelle', 'Totensammelstelle', 'Materialdepot', 'Schluesseldepot', 'Sammelstelle', 'Sammelplatz', 'Beobachtungsposten'], }, { name: 'Fahrzeuge / Geräte', description: 'Feuerwehrfahrzeuge, Leitern, Geräte', sortOrder: 8, patterns: ['TLF', 'HRF', 'Anhaengeleiter', 'Leiter', 'Sprungretter', 'Kleinloeschgeraet', 'SWHP', 'MS_de'], }, { name: 'Kommunikation / Sonstiges', description: 'Funk, Wind, Massstab, etc.', sortOrder: 9, patterns: ['Funk', 'Windrichtung', 'Nordrichtung', 'Massstab', 'Helikopter', 'Armee', 'Zivilschutz', 'Rettungen', 'Unfall', 'Rutschgebiet', 'Ueberschwemmung', 'Abschnitt', 'Absperrung', 'Achtung', 'Anmarsch'], }, ] function findCategory(filename) { const base = filename.replace(/\.svg$/i, '') for (const cat of catDefs) { for (const p of cat.patterns) { if (base.toLowerCase().includes(p.toLowerCase())) return cat.name } } return 'Sonstiges' } async function recover() { console.log('🚨 SYMBOL RECOVERY STARTED') console.log('') console.log('⚠️ WARNUNG: Bestehende Zeichnungen bleiben broken!') console.log(' Die alten iconId-UUIDs in den Feature-Properties sind verloren.') console.log(' Benutzer müssen Symbole in Zeichnungen manuell neu setzen.') console.log('') // ─── 1. Lade SVG-Dateien ─── if (!fs.existsSync(SVG_DIR)) { console.error('❌ SVG-Verzeichnis nicht gefunden:', SVG_DIR) process.exit(1) } const files = fs.readdirSync(SVG_DIR).filter(f => f.endsWith('.svg')) console.log(`📁 ${files.length} SVG-Dateien gefunden`) // ─── 2. Erstelle Icon-Categories ─── console.log('\n📂 Erstelle Icon-Categories...') const categoryMap = {} for (const def of catDefs) { const cat = await prisma.iconCategory.upsert({ where: { name: def.name }, update: {}, create: { name: def.name, description: def.description, sortOrder: def.sortOrder, isGlobal: true, }, }) categoryMap[def.name] = cat.id console.log(` ✅ ${cat.name}`) } // Sonstiges-Kategorie const sonstiges = await prisma.iconCategory.upsert({ where: { name: 'Sonstiges' }, update: {}, create: { name: 'Sonstiges', sortOrder: 99, isGlobal: true }, }) categoryMap['Sonstiges'] = sonstiges.id // ─── 3. Erstelle IconAssets ─── console.log('\n🖼️ Erstelle IconAssets...') const iconMap = {} // fileKey -> icon.id for (const file of files) { const filePath = path.join(SVG_DIR, file) const stats = fs.statSync(filePath) const fileKey = `lageplan-icons/symbols/${file}` const name = file.replace(/\.svg$/i, '').replace(/_/g, ' ') const catName = findCategory(file) const categoryId = categoryMap[catName] const icon = await prisma.iconAsset.upsert({ where: { fileKey }, update: { name, mimeType: 'image/svg+xml', isSystem: true, isActive: true, iconType: 'STANDARD', categoryId, }, create: { name, fileKey, mimeType: 'image/svg+xml', isSystem: true, isActive: true, iconType: 'STANDARD', categoryId, }, }) iconMap[fileKey] = icon.id } console.log(` ✅ ${files.length} IconAssets erstellt/aktualisiert`) // ─── 4. Aktiviere alle Icons für alle Tenants ─── console.log('\n🏢 Aktiviere Symbole für alle Tenants...') const tenants = await prisma.tenant.findMany({ select: { id: true, name: true } }) let tsCount = 0 for (const tenant of tenants) { for (const [fileKey, iconId] of Object.entries(iconMap)) { await prisma.tenantSymbol.upsert({ where: { tenantId_iconId: { tenantId: tenant.id, iconId: iconId, }, }, update: { isActive: true }, create: { tenantId: tenant.id, iconId: iconId, isActive: true, }, }) tsCount++ } console.log(` ✅ ${tenant.name}: ${Object.keys(iconMap).length} Symbole aktiviert`) } // ─── 5. Zeichnungen (Features) — Hinweis ─── console.log('\n⚠️ FEATURES / ZEICHNUNGEN:') const featureCount = await prisma.feature.count({ where: { type: 'symbol' } }) console.log(` ${featureCount} Symbol-Features in der Datenbank gefunden.`) console.log(` Diese zeigen auf GELÖSCHTE iconId-UUIDs und bleiben BROKEN.`) console.log(` Es gibt KEINE Möglichkeit, die alten UUIDs wiederherzustellen.`) console.log(` Benutzer müssen Symbole in ihren Zeichnungen manuell neu setzen.`) console.log('\n✅ RECOVERY ABGESCHLOSSEN') console.log(' - Symbole sind jetzt in der Sidebar verfügbar') console.log(' - Admin → Symbol-Manager zeigt alle Symbole an') console.log(' - Zeichnungen müssen manuell repariert werden') } recover() .then(async () => { await prisma.$disconnect() }) .catch(async (e) => { console.error('Recovery error:', e) await prisma.$disconnect() process.exit(1) })