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:
243
directus-schema/README.md
Normal file
243
directus-schema/README.md
Normal 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
|
||||
404
directus-schema/tech-stack-schema.json
Normal file
404
directus-schema/tech-stack-schema.json
Normal 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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user