- Integrate worldream (text-first world-building platform) into games/ - Configure as @worldream/web workspace package - Remove standalone git repo, now part of monorepo 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
9.3 KiB
Custom Fields Implementation
Überblick
Das Custom Fields System wurde als erste Phase der flexiblen Mechaniken-Erweiterung für Worldream implementiert. Es ermöglicht Nutzern, eigene strukturierte Datenfelder zu beliebigen Content Nodes (Charaktere, Objekte, Orte, Geschichten) hinzuzufügen.
Architektur
Datenbankstruktur
Die Implementierung nutzt PostgreSQL's JSONB-Felder für maximale Flexibilität:
-- In content_nodes Tabelle
custom_schema JSONB -- Feld-Definitionen
custom_data JSONB -- Tatsächliche Werte
schema_version INTEGER -- Versionierung für Migrationen
-- Separate Tabelle für Templates
custom_field_templates -- Wiederverwendbare Feld-Konfigurationen
Designentscheidung: JSONB wurde gewählt, da es:
- Flexible Schema-Evolution ohne Migrationen ermöglicht
- Effiziente Queries und Indexierung unterstützt
- Type-Safety auf Anwendungsebene erlaubt
- Einfaches Backup und Export ermöglicht
Type System
Das TypeScript Type System (/src/lib/types/customFields.ts) definiert 11 Feldtypen:
- text - Ein- oder mehrzeiliger Text mit optionaler Längen-Validierung
- number - Numerische Werte mit Min/Max und Einheiten
- range - Slider für Werte in einem bestimmten Bereich
- select - Dropdown mit vordefinierten Optionen
- multiselect - Mehrfachauswahl aus Optionen
- boolean - Ja/Nein Checkbox
- date - Datumseingabe
- formula - Berechnete Felder basierend auf anderen Feldern
- reference - Verweise auf andere Nodes (@slug)
- list - Dynamische Listen von Elementen
- json - Strukturierte JSON-Daten für komplexe Konfigurationen
Komponenten-Architektur
CustomFieldsManager.svelte (Haupt-Container)
├── Tab: Daten
│ └── CustomDataForm.svelte (Formular-Rendering)
├── Tab: Schema
│ └── FieldDefinitionEditor.svelte (Feld-Editor)
└── Tab: Templates
└── Template-Auswahl und -Anwendung
CustomFieldsDisplay.svelte (Read-Only Anzeige)
└── Kategorisierte Feld-Darstellung mit speziellen Visualisierungen
Implementierungsdetails
1. Schema-Definition
Jedes Feld wird durch eine CustomFieldDefinition beschrieben:
interface CustomFieldDefinition {
id: string; // Eindeutige ID
key: string; // Technischer Schlüssel (z.B. "health_points")
label: string; // Anzeigename (z.B. "Lebenspunkte")
type: FieldType; // Feldtyp
description?: string; // Hilfetext
category?: string; // Gruppierung (z.B. "Kampfwerte")
required?: boolean; // Pflichtfeld
config: FieldConfig; // Typ-spezifische Konfiguration
}
2. Dynamisches Form-Rendering
CustomDataForm.svelte generiert zur Laufzeit Formulare basierend auf dem Schema:
// Für jedes Feld im Schema
for (const field of schema.fields) {
// Rendere passendes Input-Element basierend auf field.type
switch(field.type) {
case 'text': renderTextField(field, value);
case 'number': renderNumberField(field, value);
// ... weitere Typen
}
}
Besonderheiten:
- Echtzeit-Validierung basierend auf Feld-Konfiguration
- Abhängigkeits-Tracking für Formula-Felder
- Kategorisierte Darstellung für bessere UX
3. Template-System
Templates lösen das "Cold Start" Problem:
interface CustomFieldTemplate {
id: string;
name: string;
description: string;
applicable_to: string[]; // ['character', 'object', etc.]
fields: CustomFieldDefinition[];
tags: string[];
is_public: boolean;
usage_count: number;
}
Mitgelieferte Templates:
- Basic Stats: Grundlegende Attribute (Stärke, Geschicklichkeit, etc.)
- Inventory: Item-Verwaltung mit Gewicht und Anzahl
- Relationships: Beziehungs-Tracking mit Vertrauen und Notizen
4. API-Endpoints
PUT /api/nodes/[slug]/schema
- Speichert/Aktualisiert Schema
- Validiert Feld-Definitionen
- Erhöht Schema-Version
PUT /api/nodes/[slug]/custom-data
- Speichert Feld-Daten
- Validiert gegen Schema
- Berechnet Formula-Felder
GET /api/templates
- Listet verfügbare Templates
- Filtert nach applicable_to
5. Sicherheit
- Row-Level Security (RLS): Nur Besitzer können Schema/Daten ändern
- Validierungsfunktionen: PostgreSQL-seitige Schema-Validierung
- Permission Checks: API prüft Besitz vor Änderungen
Verwendung
Als Nutzer
-
Felder hinzufügen:
- Navigiere zu einem Node (z.B. Charakter)
- Klicke auf "Bearbeiten"
- Wechsle zum Tab "Benutzerdefinierte Felder"
- Tab "Felder verwalten" → "Neues Feld"
-
Template anwenden:
- Tab "Vorlagen"
- Wähle passendes Template
- Klicke "Anwenden"
-
Daten eingeben:
- Tab "Daten"
- Fülle Felder aus
- Speichern
Als Entwickler
// Schema abrufen
const response = await fetch(`/api/nodes/${slug}/schema`);
const { schema } = await response.json();
// Daten speichern
await fetch(`/api/nodes/${slug}/custom-data`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
data: {
health_points: 100,
strength: 15
}
})
});
Technische Entscheidungen
Warum JSONB statt separate Tabellen?
Vorteile:
- Keine Schema-Migrationen bei neuen Feldtypen
- Einfacher Import/Export
- Flexible Struktur-Evolution
- Atomare Updates
Nachteile (und Lösungen):
- Keine SQL-Constraints → Anwendungs-Validierung
- Komplexere Queries → PostgreSQL JSON-Funktionen
- Type-Safety → TypeScript + Validierung
Warum Svelte 5 Runes?
<!-- Alte Syntax -->
<script>
let value = '';
$: validated = validateField(value);
</script>
<!-- Neue Syntax mit Runes -->
<script lang="ts">
let value = $state('');
let validated = $derived(validateField(value));
</script>
Vorteile:
- Bessere TypeScript-Integration
- Klarere Reaktivitäts-Semantik
- Zukunftssicher für Svelte 5+
Warum keine Formula-Evaluation im Frontend?
Sicherheit: Formula-Evaluation erfolgt später serverseitig Performance: Verhindert DoS durch komplexe Formeln Konsistenz: Zentrale Berechnung vermeidet Inkonsistenzen
Performance-Optimierungen
- Lazy Loading: Templates werden nur bei Bedarf geladen
- Debounced Saves: Auto-Save mit 500ms Verzögerung
- Field Grouping: Kategorien reduzieren visuelle Komplexität
- Selective Rendering: Nur sichtbare Tabs werden gerendert
Erweiterungsmöglichkeiten
Kurzfristig (Phase 2)
- Formula-Evaluation implementieren
- Erweiterte Validierungs-Regeln
- Bulk-Operations für mehrere Nodes
- Import/Export von Schemas
Mittelfristig (Phase 3-4)
- Visuelle Schema-Designer
- Abhängige Felder (Conditional Logic)
- Berechnete Aggregationen
- Schema-Vererbung
Langfristig
- KI-generierte Schemas basierend auf Beschreibungen
- Cross-Node Formeln
- Versionierte Daten-Historie
- GraphQL-API für Custom Fields
Bekannte Einschränkungen
- Formula-Felder: Noch nicht funktional (Platzhalter)
- Reference-Felder: Einfache Text-Eingabe statt Node-Picker
- Schema-Migration: Manuelle Daten-Anpassung bei Schema-Änderungen
- Performance: Bei >100 Feldern merkbare Verzögerung
- Mobile UX: Tabs nicht optimal auf kleinen Bildschirmen
Testing
Unit Tests (geplant)
// Validierung
expect(validateFieldKey('health_points')).toBe(true);
expect(validateFieldKey('Health Points')).toBe(false);
// Schema-Erstellung
const schema = createEmptySchema();
expect(schema.fields).toHaveLength(0);
expect(schema.version).toBe(1);
Integration Tests (geplant)
- Schema-Speicherung und -Abruf
- Daten-Validierung gegen Schema
- Template-Anwendung
- Permission-Checks
Migration von Legacy-Daten
Falls zukünftig Daten aus anderen Systemen importiert werden:
// Migration Helper (Beispiel)
function migrateToCustomFields(legacyData: any): CustomFieldData {
return {
// Map alte Felder zu neuen Keys
health_points: legacyData.hp || 100,
strength: legacyData.str || 10,
// ...
};
}
Troubleshooting
"Cannot apply unknown utility class"
Problem: Tailwind-Theme-Klassen nicht gefunden
Lösung: Verwende korrekte Theme-Präfixe (bg-theme-bg-surface statt bg-theme-surface)
Schema wird nicht gespeichert
Mögliche Ursachen:
- Fehlende Authentifizierung
- RLS-Policy blockiert
- Ungültiges Schema-Format
Debug:
// Prüfe Response
const response = await fetch(...);
if (!response.ok) {
const error = await response.json();
console.error('Schema save failed:', error);
}
Felder werden nicht angezeigt
Checkliste:
- Schema erfolgreich geladen?
- Daten vorhanden?
- Kategorien korrekt zugeordnet?
- Komponente korrekt importiert?
Zusammenfassung
Das Custom Fields System bietet eine solide Grundlage für flexible, nutzerdefinierte Mechaniken in Worldream. Die JSONB-basierte Architektur ermöglicht schnelle Iteration und Erweiterung ohne Datenbankmigrationen. Mit 11 Feldtypen und einem Template-System können Nutzer sofort produktiv werden.
Die nächsten Schritte fokussieren sich auf:
- Formula-Evaluation
- Verbesserte Reference-Felder
- Mobile Optimierung
- Performance bei großen Schemas
Das System ist bewusst einfach gehalten, um schnelles Feedback zu ermöglichen und die Richtung basierend auf Nutzer-Bedürfnissen anzupassen.