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:
2026-01-23 02:53:31 +01:00
parent 7604e00e0f
commit e431ff50fc
28 changed files with 5253 additions and 23 deletions

243
directus-schema/README.md Normal file
View File

@@ -0,0 +1,243 @@
# Directus Schema Import - Anleitung
## 📦 Verfügbare Schemas
- `tech-stack-schema.json` - Tech Stack Categories + Items mit Translations
- `projects-schema.json` - Projects Collection (Coming Soon)
- `hobbies-schema.json` - Hobbies Collection (Coming Soon)
---
## 🚀 Methode 1: Import via Directus UI (Einfachste Methode)
### Voraussetzungen:
- Directus 10.x installiert
- Admin-Zugriff auf https://cms.dk0.dev
### Schritte:
1. **Gehe zu Directus Admin Panel:**
```
https://cms.dk0.dev
```
2. **Öffne Settings:**
- Klicke auf das **Zahnrad-Icon** (⚙️) unten links
- Navigiere zu **Data Model** → **Schema**
3. **Import Schema:**
- Klicke auf **"Import Schema"** Button
- Wähle die Datei: `tech-stack-schema.json`
- ✅ Confirm Import
4. **Überprüfen:**
- Gehe zu **Data Model**
- Du solltest jetzt sehen:
- `tech_stack_categories`
- `tech_stack_categories_translations`
- `tech_stack_items`
---
## ⚡ Methode 2: Import via Directus CLI (Fortgeschritten)
### Voraussetzungen:
- Direkter Zugriff auf Directus Server
- Directus CLI installiert
### Schritte:
1. **Schema-Datei auf Server kopieren:**
```bash
# Via scp oder in deinem Docker Container
scp tech-stack-schema.json user@server:/path/to/directus/
```
2. **Schema anwenden:**
```bash
cd /path/to/directus
npx directus schema apply ./tech-stack-schema.json
```
3. **Verify:**
```bash
npx directus database inspect
```
---
## 🔧 Methode 3: Import via REST API (Automatisch)
Falls du ein Script bevorzugst:
```typescript
// scripts/import-directus-schema.ts
import fetch from 'node-fetch';
import fs from 'fs';
const DIRECTUS_URL = process.env.DIRECTUS_URL || 'https://cms.dk0.dev';
const DIRECTUS_TOKEN = process.env.DIRECTUS_STATIC_TOKEN;
async function importSchema(schemaPath: string) {
const schema = JSON.parse(fs.readFileSync(schemaPath, 'utf-8'));
// Import Collections
for (const collection of schema.collections) {
await fetch(`${DIRECTUS_URL}/collections`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${DIRECTUS_TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(collection)
});
}
// Import Relations
for (const relation of schema.relations) {
await fetch(`${DIRECTUS_URL}/relations`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${DIRECTUS_TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(relation)
});
}
console.log('✅ Schema imported successfully!');
}
importSchema('./directus-schema/tech-stack-schema.json');
```
**Ausführen:**
```bash
npm install node-fetch @types/node-fetch
npx tsx scripts/import-directus-schema.ts
```
---
## 📝 Nach dem Import: Languages konfigurieren
Directus benötigt die Languages Collection:
### Option A: Manuell in Directus UI
1. Gehe zu **Settings** → **Project Settings** → **Languages**
2. Füge hinzu:
- **English (United States)** - Code: `en-US`
- **German (Germany)** - Code: `de-DE`
### Option B: Via API
```bash
curl -X POST "https://cms.dk0.dev/languages" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"code": "en-US", "name": "English (United States)"}'
curl -X POST "https://cms.dk0.dev/languages" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"code": "de-DE", "name": "German (Germany)"}'
```
---
## 🎨 Nach dem Import: Daten befüllen
### Manuell in Directus UI:
1. **Tech Stack Categories erstellen:**
- Gehe zu **Content** → **Tech Stack Categories**
- Klicke **"Create Item"**
- Fülle aus:
- Key: `frontend`
- Icon: `Globe`
- Status: `published`
- Translations:
- EN: "Frontend & Mobile"
- DE: "Frontend & Mobile"
2. **Tech Stack Items hinzufügen:**
- Gehe zu **Content** → **Tech Stack Items**
- Klicke **"Create Item"**
- Fülle aus:
- Category: `frontend` (Select)
- Name: `Next.js`
- URL: `https://nextjs.org` (optional)
### Oder: Migrations-Script verwenden
```bash
# Coming Soon
npm run migrate:tech-stack
```
---
## ✅ Checklist
- [ ] Schema importiert in Directus
- [ ] Languages konfiguriert (en-US, de-DE)
- [ ] Tech Stack Categories angelegt (4 Kategorien)
- [ ] Tech Stack Items hinzugefügt (~20 Items)
- [ ] Status auf "published" gesetzt
- [ ] GraphQL Query getestet:
```graphql
query {
tech_stack_categories(filter: {status: {_eq: "published"}}) {
key
icon
translations {
name
languages_code { code }
}
items {
name
url
}
}
}
```
---
## 🐛 Troubleshooting
### Error: "Collection already exists"
→ Schema wurde bereits importiert. Lösung:
```bash
# Via Directus UI: Data Model → Delete Collection
# Oder via API:
curl -X DELETE "https://cms.dk0.dev/collections/tech_stack_categories" \
-H "Authorization: Bearer YOUR_TOKEN"
```
### Error: "Language not found"
→ Stelle sicher dass `en-US` und `de-DE` in Languages existieren
### Error: "Unauthorized"
→ Überprüfe `DIRECTUS_STATIC_TOKEN` in .env
---
## 📚 Nächste Schritte
Nach erfolgreichem Import:
1. ✅ **Test GraphQL Query** in Directus
2. ✅ **Erweitere lib/directus.ts** mit `getTechStack()`
3.**Update About.tsx** Component
4.**Deploy & Test** auf Production
---
## 💡 Pro-Tipps
- **Backups:** Exportiere Schema regelmäßig via Directus UI
- **Version Control:** Committe Schema-Files ins Git
- **Automation:** Nutze Directus Webhooks für Auto-Deployment
- **Testing:** Teste Queries im Directus GraphQL Playground

View File

@@ -0,0 +1,404 @@
{
"version": 1,
"directus": "10.x",
"collections": [
{
"collection": "tech_stack_categories",
"meta": {
"icon": "layers",
"display_template": "{{translations.name}}",
"hidden": false,
"singleton": false,
"translations": [
{
"language": "en-US",
"translation": "Tech Stack Categories"
},
{
"language": "de-DE",
"translation": "Tech Stack Kategorien"
}
],
"sort_field": "sort"
},
"schema": {
"name": "tech_stack_categories"
},
"fields": [
{
"field": "id",
"type": "uuid",
"meta": {
"hidden": true,
"readonly": true,
"interface": "input",
"special": ["uuid"]
},
"schema": {
"is_primary_key": true,
"has_auto_increment": false
}
},
{
"field": "status",
"type": "string",
"meta": {
"width": "full",
"options": {
"choices": [
{ "text": "Published", "value": "published" },
{ "text": "Draft", "value": "draft" },
{ "text": "Archived", "value": "archived" }
]
},
"interface": "select-dropdown",
"display": "labels",
"display_options": {
"choices": [
{
"text": "Published",
"value": "published",
"foreground": "#FFFFFF",
"background": "#00C897"
},
{
"text": "Draft",
"value": "draft",
"foreground": "#18222F",
"background": "#D3DAE4"
},
{
"text": "Archived",
"value": "archived",
"foreground": "#FFFFFF",
"background": "#F7971C"
}
]
}
},
"schema": {
"default_value": "draft",
"is_nullable": false
}
},
{
"field": "sort",
"type": "integer",
"meta": {
"interface": "input",
"hidden": true
},
"schema": {}
},
{
"field": "key",
"type": "string",
"meta": {
"interface": "input",
"width": "half",
"options": {
"placeholder": "e.g. frontend, backend, devops"
},
"note": "Unique identifier for the category (no spaces, lowercase)"
},
"schema": {
"is_unique": true,
"is_nullable": false
}
},
{
"field": "icon",
"type": "string",
"meta": {
"interface": "select-dropdown",
"width": "half",
"options": {
"choices": [
{ "text": "Globe (Frontend)", "value": "Globe" },
{ "text": "Server (Backend)", "value": "Server" },
{ "text": "Wrench (Tools)", "value": "Wrench" },
{ "text": "Shield (Security)", "value": "Shield" },
{ "text": "Code", "value": "Code" },
{ "text": "Database", "value": "Database" },
{ "text": "Cloud", "value": "Cloud" }
]
},
"note": "Icon from lucide-react library"
},
"schema": {
"default_value": "Code"
}
},
{
"field": "date_created",
"type": "timestamp",
"meta": {
"special": ["date-created"],
"interface": "datetime",
"readonly": true,
"hidden": true,
"width": "half",
"display": "datetime",
"display_options": {
"relative": true
}
},
"schema": {}
},
{
"field": "date_updated",
"type": "timestamp",
"meta": {
"special": ["date-updated"],
"interface": "datetime",
"readonly": true,
"hidden": true,
"width": "half",
"display": "datetime",
"display_options": {
"relative": true
}
},
"schema": {}
},
{
"field": "translations",
"type": "alias",
"meta": {
"special": ["translations"],
"interface": "translations",
"options": {
"languageField": "languages_code"
}
}
}
]
},
{
"collection": "tech_stack_categories_translations",
"meta": {
"hidden": true,
"icon": "import_export",
"translations": [
{
"language": "en-US",
"translation": "Tech Stack Categories Translations"
}
]
},
"schema": {
"name": "tech_stack_categories_translations"
},
"fields": [
{
"field": "id",
"type": "integer",
"meta": {
"hidden": true
},
"schema": {
"is_primary_key": true,
"has_auto_increment": true
}
},
{
"field": "tech_stack_categories_id",
"type": "uuid",
"meta": {
"hidden": true
},
"schema": {}
},
{
"field": "languages_code",
"type": "string",
"meta": {
"width": "half",
"interface": "select-dropdown-m2o",
"options": {
"template": "{{name}}"
}
},
"schema": {}
},
{
"field": "name",
"type": "string",
"meta": {
"interface": "input",
"options": {
"placeholder": "e.g. Frontend & Mobile"
},
"note": "Translated category name"
},
"schema": {}
}
]
},
{
"collection": "tech_stack_items",
"meta": {
"icon": "code",
"display_template": "{{name}} ({{category.translations.name}})",
"hidden": false,
"singleton": false,
"translations": [
{
"language": "en-US",
"translation": "Tech Stack Items"
},
{
"language": "de-DE",
"translation": "Tech Stack Items"
}
],
"sort_field": "sort"
},
"schema": {
"name": "tech_stack_items"
},
"fields": [
{
"field": "id",
"type": "uuid",
"meta": {
"hidden": true,
"readonly": true,
"interface": "input",
"special": ["uuid"]
},
"schema": {
"is_primary_key": true,
"has_auto_increment": false
}
},
{
"field": "sort",
"type": "integer",
"meta": {
"interface": "input",
"hidden": true
},
"schema": {}
},
{
"field": "category",
"type": "uuid",
"meta": {
"interface": "select-dropdown-m2o",
"width": "half",
"display": "related-values",
"display_options": {
"template": "{{translations.name}}"
}
},
"schema": {}
},
{
"field": "name",
"type": "string",
"meta": {
"interface": "input",
"width": "half",
"options": {
"placeholder": "e.g. Next.js, Docker, Tailwind CSS"
},
"note": "Technology name (same in all languages)"
},
"schema": {
"is_nullable": false
}
},
{
"field": "url",
"type": "string",
"meta": {
"interface": "input",
"width": "half",
"options": {
"placeholder": "https://nextjs.org"
},
"note": "Official website (optional)"
},
"schema": {}
},
{
"field": "icon_url",
"type": "string",
"meta": {
"interface": "input",
"width": "half",
"options": {
"placeholder": "https://..."
},
"note": "Custom icon/logo URL (optional)"
},
"schema": {}
},
{
"field": "date_created",
"type": "timestamp",
"meta": {
"special": ["date-created"],
"interface": "datetime",
"readonly": true,
"hidden": true
},
"schema": {}
},
{
"field": "date_updated",
"type": "timestamp",
"meta": {
"special": ["date-updated"],
"interface": "datetime",
"readonly": true,
"hidden": true
},
"schema": {}
}
]
}
],
"relations": [
{
"collection": "tech_stack_categories_translations",
"field": "tech_stack_categories_id",
"related_collection": "tech_stack_categories",
"meta": {
"one_field": "translations",
"sort_field": null,
"one_deselect_action": "delete"
},
"schema": {
"on_delete": "CASCADE"
}
},
{
"collection": "tech_stack_categories_translations",
"field": "languages_code",
"related_collection": "languages",
"meta": {
"one_field": null,
"sort_field": null,
"one_deselect_action": "nullify"
},
"schema": {
"on_delete": "SET NULL"
}
},
{
"collection": "tech_stack_items",
"field": "category",
"related_collection": "tech_stack_categories",
"meta": {
"one_field": "items",
"sort_field": "sort",
"one_deselect_action": "nullify"
},
"schema": {
"on_delete": "SET NULL"
}
}
]
}