All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 22m1s
152 lines
5.2 KiB
JavaScript
152 lines
5.2 KiB
JavaScript
/**
|
|
* Recovery-Skript für Zeichnungen (Features) nach Symbol-Verlust
|
|
*
|
|
* Problem: Features verweisen auf gelöschte iconId-UUIDs.
|
|
* Die imageUrl ist "/api/icons/{alte-uuid}/image" → 404.
|
|
*
|
|
* Lösung:
|
|
* Die alte UUID→SVG-Zuordnung ist verloren. ABER:
|
|
* - Alle bestehenden IconAssets wurden per Upsert neu erstellt (gleiche fileKeys)
|
|
* - Jedes Feature hat noch die alte iconId in properties
|
|
* - Die Sidebar liefert jetzt NEUE iconIds
|
|
*
|
|
* Dieses Skript:
|
|
* 1. Listet alle broken Symbol-Features (iconId zeigt auf gelöschtes Icon)
|
|
* 2. Für Features wo imageUrl auf /signaturen/ zeigt: direkt fixbar
|
|
* 3. Für Features mit /api/icons/{uuid}/image: UUID ist verloren → Renderer zeigt ⚠️
|
|
* 4. Zählt und listet betroffene Projekte
|
|
*
|
|
* Der Renderer wurde angepasst (map-view.tsx): broken Symbole zeigen jetzt
|
|
* ein ⚠️-Platzhalter statt nichts. User können das Symbol manuell ersetzen.
|
|
*
|
|
* Ausführung:
|
|
* DATABASE_URL=... node prisma/recover-features.js [--dry-run]
|
|
*/
|
|
|
|
const { PrismaClient } = require('@prisma/client')
|
|
const prisma = new PrismaClient()
|
|
|
|
const DRY_RUN = process.argv.includes('--dry-run')
|
|
|
|
async function main() {
|
|
console.log('🔧 FEATURE RECOVERY — Analyse & Reparatur')
|
|
console.log(` Mode: ${DRY_RUN ? '🔍 DRY RUN' : '⚡ LIVE'}`)
|
|
console.log('')
|
|
|
|
// ─── 1. Lade alle aktuellen IconAssets ───
|
|
const allIcons = await prisma.iconAsset.findMany({
|
|
select: { id: true, name: true, fileKey: true },
|
|
})
|
|
console.log(`📦 ${allIcons.length} IconAssets in der DB`)
|
|
|
|
const iconIdSet = new Set(allIcons.map(i => i.id))
|
|
const fileKeyToIcon = {}
|
|
for (const icon of allIcons) {
|
|
fileKeyToIcon[icon.fileKey] = icon
|
|
}
|
|
|
|
// ─── 2. Lade alle Symbol-Features ───
|
|
const features = await prisma.feature.findMany({
|
|
where: { type: 'symbol' },
|
|
include: { project: { select: { id: true, name: true, tenantId: true } } },
|
|
})
|
|
console.log(`🖼️ ${features.length} Symbol-Features gefunden`)
|
|
console.log('')
|
|
|
|
let ok = 0
|
|
let fixedViaFileKey = 0
|
|
let broken = 0
|
|
const brokenByProject = {}
|
|
|
|
for (const feature of features) {
|
|
const props = feature.properties || {}
|
|
const iconId = props.iconId || ''
|
|
const imageUrl = props.imageUrl || ''
|
|
|
|
// ─── Check 1: iconId still exists? ───
|
|
if (iconId && iconIdSet.has(iconId)) {
|
|
ok++
|
|
continue
|
|
}
|
|
|
|
// ─── Check 2: imageUrl points to static /signaturen/ file? ───
|
|
const sigMatch = imageUrl.match(/\/signaturen\/(.+\.svg)/)
|
|
if (sigMatch) {
|
|
const fileKey = `signaturen/${sigMatch[1]}`
|
|
const matchingIcon = fileKeyToIcon[fileKey]
|
|
if (matchingIcon) {
|
|
// Fix: Update iconId to new valid ID
|
|
const newProps = {
|
|
...props,
|
|
iconId: matchingIcon.id,
|
|
imageUrl: `/api/icons/${matchingIcon.id}/image`,
|
|
_recovered: true,
|
|
_oldIconId: iconId,
|
|
}
|
|
if (!DRY_RUN) {
|
|
await prisma.feature.update({
|
|
where: { id: feature.id },
|
|
data: { properties: newProps },
|
|
})
|
|
}
|
|
fixedViaFileKey++
|
|
console.log(` ✅ ${feature.id} → ${matchingIcon.name} (via fileKey)`)
|
|
continue
|
|
}
|
|
}
|
|
|
|
// ─── Check 3: imageUrl is /api/icons/{uuid}/image? ───
|
|
// The uuid in the URL = old iconId = deleted → can't resolve
|
|
// Mark as broken
|
|
broken++
|
|
const projName = feature.project?.name || feature.projectId
|
|
if (!brokenByProject[projName]) brokenByProject[projName] = []
|
|
brokenByProject[projName].push({
|
|
featureId: feature.id,
|
|
iconId,
|
|
imageUrl,
|
|
})
|
|
}
|
|
|
|
console.log('')
|
|
console.log('═══════════════════════════════════════════')
|
|
console.log(` ✅ OK (iconId existiert): ${ok}`)
|
|
console.log(` 🔧 Gefixt (via fileKey): ${fixedViaFileKey}`)
|
|
console.log(` ❌ Broken (UUID verloren): ${broken}`)
|
|
console.log(` 📊 Total: ${features.length}`)
|
|
console.log('═══════════════════════════════════════════')
|
|
|
|
if (broken > 0) {
|
|
console.log('')
|
|
console.log('❌ BROKEN FEATURES pro Projekt:')
|
|
for (const [projName, items] of Object.entries(brokenByProject)) {
|
|
console.log(` 📄 "${projName}": ${items.length} Symbole`)
|
|
for (const item of items) {
|
|
console.log(` - Feature ${item.featureId} (iconId: ${item.iconId.substring(0, 8)}...)`)
|
|
}
|
|
}
|
|
console.log('')
|
|
console.log('💡 Diese Symbole zeigen jetzt ein ⚠️ auf der Karte.')
|
|
console.log(' User müssen das Symbol manuell löschen und neu platzieren.')
|
|
console.log(' (Select-Mode → Symbol anklicken → DEL → neues Symbol aus Sidebar ziehen)')
|
|
}
|
|
|
|
if (broken === 0 && fixedViaFileKey === 0) {
|
|
console.log('')
|
|
console.log('🎉 Alle Symbol-Features sind OK! Keine Reparatur nötig.')
|
|
}
|
|
|
|
if (DRY_RUN) {
|
|
console.log('')
|
|
console.log('🔍 DRY RUN — Keine Änderungen geschrieben.')
|
|
}
|
|
}
|
|
|
|
main()
|
|
.then(async () => { await prisma.$disconnect() })
|
|
.catch(async (e) => {
|
|
console.error('❌ Fehler:', e)
|
|
await prisma.$disconnect()
|
|
process.exit(1)
|
|
})
|