diff --git a/prisma/migrate.js b/prisma/migrate.js index e395919..d6b2cd3 100644 --- a/prisma/migrate.js +++ b/prisma/migrate.js @@ -231,6 +231,65 @@ async function migrate() { console.log(' tenant_symbols table skipped:', e.message) } + // ─── Step 13: Create symbol_templates table ─── + console.log(' [13] Creating symbol_templates table...') + try { + await prisma.$executeRawUnsafe(` + CREATE TABLE IF NOT EXISTS symbol_templates ( + id TEXT PRIMARY KEY DEFAULT gen_random_uuid(), + "fileKey" TEXT NOT NULL, + "originalFilename" TEXT NOT NULL, + "displayName" TEXT, + "categoryName" TEXT, + "svgPath" TEXT, + "metadata" JSONB NOT NULL DEFAULT '{}', + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + UNIQUE("fileKey") + ) + `) + console.log(' symbol_templates table created (or already exists)') + } catch (e) { + console.log(' symbol_templates table skipped:', e.message) + } + + // ─── Step 14: Create tenant_categories table ─── + console.log(' [14] Creating tenant_categories table...') + try { + await prisma.$executeRawUnsafe(` + CREATE TABLE IF NOT EXISTS tenant_categories ( + id TEXT PRIMARY KEY DEFAULT gen_random_uuid(), + "name" TEXT NOT NULL, + "description" TEXT, + "sortOrder" INTEGER NOT NULL DEFAULT 0, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "tenantId" TEXT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE + ) + `) + console.log(' tenant_categories table created (or already exists)') + } catch (e) { + console.log(' tenant_categories table skipped:', e.message) + } + + // ─── Step 15: Extend tenant_symbols with Phase 1 columns ─── + console.log(' [15] Extending tenant_symbols with Phase 1 columns...') + const tenantSymbolColumns = [ + `ALTER TABLE tenant_symbols ADD COLUMN IF NOT EXISTS "name" TEXT`, + `ALTER TABLE tenant_symbols ADD COLUMN IF NOT EXISTS "svgPath" TEXT`, + `ALTER TABLE tenant_symbols ADD COLUMN IF NOT EXISTS "isUploaded" BOOLEAN NOT NULL DEFAULT false`, + `ALTER TABLE tenant_symbols ADD COLUMN IF NOT EXISTS "categoryId" TEXT REFERENCES tenant_categories(id) ON DELETE SET NULL`, + `ALTER TABLE tenant_symbols ADD COLUMN IF NOT EXISTS "migratedFromIconId" TEXT`, + `ALTER TABLE tenant_symbols ADD COLUMN IF NOT EXISTS "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP`, + `ALTER TABLE tenant_symbols ADD COLUMN IF NOT EXISTS "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP`, + ] + let tsAdded = 0 + for (const sql of tenantSymbolColumns) { + try { await prisma.$executeRawUnsafe(sql); tsAdded++ } catch (e) { /* ignore */ } + } + console.log(` ${tsAdded}/${tenantSymbolColumns.length} tenant_symbol columns added`) + console.log('✅ Database migrations complete') } diff --git a/prisma/seed-icons-only.js b/prisma/seed-icons-only.js index 6e110a5..d9585c6 100644 --- a/prisma/seed-icons-only.js +++ b/prisma/seed-icons-only.js @@ -44,11 +44,10 @@ async function main() { patterns: ['Massstab', 'Nordrichtung', 'Windrichtung'] }, ] - // Delete ALL old system icons (regardless of fileKey pattern) - const deleted = await prisma.iconAsset.deleteMany({ - where: { isSystem: true }, - }) - console.log(`🗑️ ${deleted.count} old system icons removed`) + // NOTE: We intentionally do NOT delete old system icons here. + // TenantSymbol rows reference IconAsset.id via foreign key. + // Deleting would either break references (tenant symbols become 404s) + // or cascade-delete tenant symbols. Instead we upsert by fileKey. // Upsert global categories (preserves tenant categories) const catMap = {} @@ -90,6 +89,7 @@ async function main() { } let created = 0 + let updated = 0 for (const file of svgFiles) { let name = file.replace('.svg', '') name = name.replace(/_de$/i, '').replace(/_DE$/i, '').replace(/-de$/i, '') @@ -99,7 +99,21 @@ async function main() { const category = findCategory(file) const existing = await prisma.iconAsset.findFirst({ where: { fileKey } }) - if (!existing) { + if (existing) { + await prisma.iconAsset.update({ + where: { id: existing.id }, + data: { + name, + categoryId: category.id, + mimeType: 'image/svg+xml', + isSystem: true, + isActive: true, + width: 48, + height: 48, + }, + }) + updated++ + } else { await prisma.iconAsset.create({ data: { name, @@ -115,7 +129,7 @@ async function main() { } } - console.log(`✅ FKS Signaturen: ${created} new SVG icons created (${svgFiles.length} total)`) + console.log(`✅ FKS Signaturen: ${created} created, ${updated} updated (${svgFiles.length} total)`) } main() diff --git a/prisma/seed.js b/prisma/seed.js index 0513845..456eb7e 100644 --- a/prisma/seed.js +++ b/prisma/seed.js @@ -110,11 +110,10 @@ async function main() { patterns: ['Massstab', 'Nordrichtung', 'Windrichtung'] }, ] - // Delete ALL old system icons (regardless of fileKey pattern) - const deletedIcons = await prisma.iconAsset.deleteMany({ - where: { isSystem: true }, - }) - console.log(`🗑️ ${deletedIcons.count} old system icons removed`) + // NOTE: We intentionally do NOT delete old system icons here. + // TenantSymbol rows reference IconAsset.id via foreign key. + // Deleting would either break references (tenant symbols become 404s) + // or cascade-delete tenant symbols. Instead we upsert by fileKey. // Clean up empty global categories const oldGlobalCats = await prisma.iconCategory.findMany({ where: { tenantId: null } }) @@ -163,6 +162,7 @@ async function main() { } let created = 0 + let updated = 0 for (const file of svgFiles) { // Clean name: remove .svg, remove _de/_DE suffix let name = file.replace('.svg', '') @@ -173,7 +173,21 @@ async function main() { const category = findCategory(file) const existing = await prisma.iconAsset.findFirst({ where: { fileKey } }) - if (!existing) { + if (existing) { + await prisma.iconAsset.update({ + where: { id: existing.id }, + data: { + name, + categoryId: category.id, + mimeType: 'image/svg+xml', + isSystem: true, + isActive: true, + width: 48, + height: 48, + }, + }) + updated++ + } else { await prisma.iconAsset.create({ data: { name, @@ -189,7 +203,7 @@ async function main() { } } - console.log(`✅ FKS Signaturen: ${created} new icons created (${svgFiles.length} total SVGs)`) + console.log(`✅ FKS Signaturen: ${created} created, ${updated} updated (${svgFiles.length} total SVGs)`) // Create a demo project const demoProject = await prisma.project.upsert({