feat: Add Directus setup scripts for collections, fields, and relations
- Created setup-directus-collections.js to automate the creation of tech stack collections, fields, and relations in Directus. - Created setup-directus-hobbies.js for setting up hobbies collection with translations. - Created setup-directus-projects.js for establishing projects collection with comprehensive fields and translations. - Added setup-tech-stack-directus.js to populate tech_stack_items with predefined data.
This commit is contained in:
240
scripts/migrate-tech-stack-to-directus.js
Normal file
240
scripts/migrate-tech-stack-to-directus.js
Normal file
@@ -0,0 +1,240 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Directus Tech Stack Migration Script
|
||||
*
|
||||
* Migriert bestehende Tech Stack Daten aus messages/en.json und messages/de.json
|
||||
* nach Directus Collections.
|
||||
*
|
||||
* Usage:
|
||||
* npm install node-fetch@2 dotenv
|
||||
* node scripts/migrate-tech-stack-to-directus.js
|
||||
*/
|
||||
|
||||
const fetch = require('node-fetch');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
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);
|
||||
}
|
||||
|
||||
// Lade aktuelle Tech Stack Daten aus messages files
|
||||
const messagesEn = JSON.parse(
|
||||
fs.readFileSync(path.join(__dirname, '../messages/en.json'), 'utf-8')
|
||||
);
|
||||
const messagesDe = JSON.parse(
|
||||
fs.readFileSync(path.join(__dirname, '../messages/de.json'), 'utf-8')
|
||||
);
|
||||
|
||||
const techStackEn = messagesEn.home.about.techStack;
|
||||
const techStackDe = messagesDe.home.about.techStack;
|
||||
|
||||
// Tech Stack Struktur aus About.tsx
|
||||
const TECH_STACK_DATA = [
|
||||
{
|
||||
key: 'frontend',
|
||||
icon: 'Globe',
|
||||
nameEn: techStackEn.categories.frontendMobile,
|
||||
nameDe: techStackDe.categories.frontendMobile,
|
||||
items: ['Next.js', 'Tailwind CSS', 'Flutter']
|
||||
},
|
||||
{
|
||||
key: 'backend',
|
||||
icon: 'Server',
|
||||
nameEn: techStackEn.categories.backendDevops,
|
||||
nameDe: techStackDe.categories.backendDevops,
|
||||
items: ['Docker', 'PostgreSQL', 'Redis', 'Traefik']
|
||||
},
|
||||
{
|
||||
key: 'tools',
|
||||
icon: 'Wrench',
|
||||
nameEn: techStackEn.categories.toolsAutomation,
|
||||
nameDe: techStackDe.categories.toolsAutomation,
|
||||
items: ['Git', 'CI/CD', 'n8n', techStackEn.items.selfHostedServices]
|
||||
},
|
||||
{
|
||||
key: 'security',
|
||||
icon: 'Shield',
|
||||
nameEn: techStackEn.categories.securityAdmin,
|
||||
nameDe: techStackDe.categories.securityAdmin,
|
||||
items: ['CrowdSec', 'Suricata', 'Proxmox']
|
||||
}
|
||||
];
|
||||
|
||||
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 ensureLanguagesExist() {
|
||||
console.log('\n🌍 Checking Languages...');
|
||||
|
||||
try {
|
||||
const { data: languages } = await directusRequest('items/languages');
|
||||
const hasEnUS = languages.some(l => l.code === 'en-US');
|
||||
const hasDeDE = languages.some(l => l.code === 'de-DE');
|
||||
|
||||
if (!hasEnUS) {
|
||||
console.log(' Creating en-US language...');
|
||||
await directusRequest('items/languages', 'POST', {
|
||||
code: 'en-US',
|
||||
name: 'English (United States)'
|
||||
});
|
||||
}
|
||||
|
||||
if (!hasDeDE) {
|
||||
console.log(' Creating de-DE language...');
|
||||
await directusRequest('items/languages', 'POST', {
|
||||
code: 'de-DE',
|
||||
name: 'German (Germany)'
|
||||
});
|
||||
}
|
||||
|
||||
console.log(' ✅ Languages ready');
|
||||
} catch (error) {
|
||||
console.log(' ⚠️ Languages collection might not exist yet');
|
||||
}
|
||||
}
|
||||
|
||||
async function migrateTechStack() {
|
||||
console.log('\n📦 Migrating Tech Stack to Directus...\n');
|
||||
|
||||
await ensureLanguagesExist();
|
||||
|
||||
for (const category of TECH_STACK_DATA) {
|
||||
console.log(`\n📁 Category: ${category.key}`);
|
||||
|
||||
try {
|
||||
// 1. Create Category
|
||||
console.log(' Creating category...');
|
||||
const categoryData = {
|
||||
key: category.key,
|
||||
icon: category.icon,
|
||||
status: 'published',
|
||||
sort: TECH_STACK_DATA.indexOf(category) + 1
|
||||
};
|
||||
|
||||
const { data: createdCategory } = await directusRequest(
|
||||
'items/tech_stack_categories',
|
||||
'POST',
|
||||
categoryData
|
||||
);
|
||||
|
||||
console.log(` ✅ Category created with ID: ${createdCategory.id}`);
|
||||
|
||||
// 2. Create Translations
|
||||
console.log(' Creating translations...');
|
||||
|
||||
// English Translation
|
||||
await directusRequest(
|
||||
'items/tech_stack_categories_translations',
|
||||
'POST',
|
||||
{
|
||||
tech_stack_categories_id: createdCategory.id,
|
||||
languages_code: 'en-US',
|
||||
name: category.nameEn
|
||||
}
|
||||
);
|
||||
|
||||
// German Translation
|
||||
await directusRequest(
|
||||
'items/tech_stack_categories_translations',
|
||||
'POST',
|
||||
{
|
||||
tech_stack_categories_id: createdCategory.id,
|
||||
languages_code: 'de-DE',
|
||||
name: category.nameDe
|
||||
}
|
||||
);
|
||||
|
||||
console.log(' ✅ Translations created (en-US, de-DE)');
|
||||
|
||||
// 3. Create Items
|
||||
console.log(` Creating ${category.items.length} items...`);
|
||||
|
||||
for (let i = 0; i < category.items.length; i++) {
|
||||
const itemName = category.items[i];
|
||||
await directusRequest(
|
||||
'items/tech_stack_items',
|
||||
'POST',
|
||||
{
|
||||
category: createdCategory.id,
|
||||
name: itemName,
|
||||
sort: i + 1
|
||||
}
|
||||
);
|
||||
console.log(` ✅ ${itemName}`);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error(` ❌ Error migrating ${category.key}:`, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n✨ Migration complete!\n');
|
||||
}
|
||||
|
||||
async function verifyMigration() {
|
||||
console.log('\n🔍 Verifying Migration...\n');
|
||||
|
||||
try {
|
||||
const { data: categories } = await directusRequest(
|
||||
'items/tech_stack_categories?fields=*,translations.*,items.*'
|
||||
);
|
||||
|
||||
console.log(`✅ Found ${categories.length} categories:`);
|
||||
categories.forEach(cat => {
|
||||
const enTranslation = cat.translations?.find(t => t.languages_code === 'en-US');
|
||||
const itemCount = cat.items?.length || 0;
|
||||
console.log(` - ${cat.key}: "${enTranslation?.name}" (${itemCount} items)`);
|
||||
});
|
||||
|
||||
console.log('\n🎉 All data migrated successfully!\n');
|
||||
console.log('Next steps:');
|
||||
console.log(' 1. Visit https://cms.dk0.dev/admin/content/tech_stack_categories');
|
||||
console.log(' 2. Verify data looks correct');
|
||||
console.log(' 3. Run: npm run dev:directus (to test GraphQL queries)');
|
||||
console.log(' 4. Update About.tsx to use Directus data\n');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Verification failed:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Main execution
|
||||
(async () => {
|
||||
try {
|
||||
await migrateTechStack();
|
||||
await verifyMigration();
|
||||
} catch (error) {
|
||||
console.error('\n❌ Migration failed:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user