#!/usr/bin/env node /** * Migrate Projects from PostgreSQL to Directus * * Migriert ALLE bestehenden Projects aus deiner PostgreSQL Datenbank nach Directus * inklusive aller Felder und Translations. * * Usage: * node scripts/migrate-projects-to-directus.js */ const fetch = require('node-fetch'); const { PrismaClient } = require('@prisma/client'); require('dotenv').config(); const DIRECTUS_URL = process.env.DIRECTUS_URL || 'https://cms.dk0.dev'; const DIRECTUS_TOKEN = process.env.DIRECTUS_STATIC_TOKEN; if (!DIRECTUS_TOKEN) { console.error('❌ Error: DIRECTUS_STATIC_TOKEN not found in .env'); process.exit(1); } const prisma = new PrismaClient(); async function directusRequest(endpoint, method = 'GET', body = null) { const url = `${DIRECTUS_URL}/${endpoint}`; const options = { method, headers: { 'Authorization': `Bearer ${DIRECTUS_TOKEN}`, 'Content-Type': 'application/json' } }; if (body) { options.body = JSON.stringify(body); } try { const response = await fetch(url, options); if (!response.ok) { const text = await response.text(); throw new Error(`HTTP ${response.status}: ${text}`); } return await response.json(); } catch (error) { console.error(`Error calling ${method} ${endpoint}:`, error.message); throw error; } } async function migrateProjects() { console.log('\nπŸ“¦ Migrating Projects from PostgreSQL to Directus...\n'); // Load all published projects from PostgreSQL const projects = await prisma.project.findMany({ where: { published: true }, include: { translations: true }, orderBy: { createdAt: 'desc' } }); console.log(`Found ${projects.length} published projects in PostgreSQL\n`); let successCount = 0; let errorCount = 0; for (const project of projects) { console.log(`\nπŸ“ Migrating: ${project.title}`); try { // 1. Create project in Directus console.log(' Creating project...'); const projectData = { slug: project.slug, status: 'published', featured: project.featured, category: project.category, difficulty: project.difficulty, date: project.date, time_to_complete: project.timeToComplete, github: project.github, live: project.live, image_url: project.imageUrl, demo_video: project.demoVideo, color_scheme: project.colorScheme, accessibility: project.accessibility, tags: project.tags, technologies: project.technologies, challenges: project.challenges, lessons_learned: project.lessonsLearned, future_improvements: project.futureImprovements, screenshots: project.screenshots, performance: project.performance }; const { data: createdProject } = await directusRequest( 'items/projects', 'POST', projectData ); console.log(` βœ… Project created with ID: ${createdProject.id}`); // 2. Create Translations console.log(' Creating translations...'); // Default locale translation (from main project fields) await directusRequest( 'items/projects_translations', 'POST', { projects_id: createdProject.id, languages_code: project.defaultLocale === 'en' ? 'en-US' : 'de-DE', title: project.title, description: project.description, content: project.content, meta_description: project.metaDescription, keywords: project.keywords } ); // Additional translations from ProjectTranslation table for (const translation of project.translations) { // Skip if it's the same as default locale (already created above) if (translation.locale === project.defaultLocale) { continue; } await directusRequest( 'items/projects_translations', 'POST', { projects_id: createdProject.id, languages_code: translation.locale === 'en' ? 'en-US' : 'de-DE', title: translation.title, description: translation.description, content: translation.content ? JSON.stringify(translation.content) : null, meta_description: translation.metaDescription, keywords: translation.keywords } ); } console.log(` βœ… Translations created (${project.translations.length + 1} locales)`); successCount++; } catch (error) { console.error(` ❌ Error migrating ${project.title}:`, error.message); errorCount++; } } console.log('\n╔════════════════════════════════════════╗'); console.log(`β•‘ Migration Complete! β•‘`); console.log('β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\n'); console.log(`βœ… Successfully migrated: ${successCount} projects`); console.log(`❌ Failed: ${errorCount} projects\n`); if (successCount > 0) { console.log('πŸŽ‰ Projects are now in Directus!\n'); console.log('Next steps:'); console.log(' 1. Visit: https://cms.dk0.dev/admin/content/projects'); console.log(' 2. Verify all projects are visible'); console.log(' 3. Update lib/directus.ts with getProjects() function'); console.log(' 4. Update components to use Directus API\n'); } } async function verifyMigration() { console.log('\nπŸ” Verifying Migration...\n'); try { const { data: projects } = await directusRequest( 'items/projects?fields=slug,status,translations.title,translations.languages_code' ); console.log(`βœ… Found ${projects.length} projects in Directus:`); projects.slice(0, 5).forEach(p => { const enTitle = p.translations?.find(t => t.languages_code === 'en-US')?.title; console.log(` - ${p.slug}: "${enTitle || 'No title'}"`); }); if (projects.length > 5) { console.log(` ... and ${projects.length - 5} more`); } } catch (error) { console.error('❌ Verification failed:', error.message); } } async function main() { console.log('\n╔════════════════════════════════════════╗'); console.log('β•‘ Project Migration: PostgreSQL β†’ Directus β•‘'); console.log('β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\n'); try { // Test database connection first console.log('πŸ” Testing database connection...'); await prisma.$connect(); console.log('βœ… Database connected\n'); await migrateProjects(); await verifyMigration(); } catch (error) { if (error.message?.includes("Can't reach database")) { console.error('\n❌ PostgreSQL ist nicht erreichbar!'); console.error('\nπŸ’‘ LΓΆsungen:'); console.error(' 1. Starte PostgreSQL: npm run dev'); console.error(' 2. Oder nutze Docker: docker-compose up -d postgres'); console.error(' 3. Oder skip diesen Schritt - Projects Collection existiert bereits in Directus\n'); console.error('Du kannst Projects spΓ€ter manuell in Directus erstellen oder die Migration erneut ausfΓΌhren.\n'); process.exit(0); // Graceful exit } console.error('\n❌ Migration failed:', error); process.exit(1); } finally { await prisma.$disconnect(); } } main();