# Phase 3: Design System & Advanced Features - Detailplanung ## π― Γberblick Phase 3 Phase 3 baut auf der soliden Architektur-Basis von Phase 1+2 auf und verwandelt Worldream in eine professionelle, skalierbare Anwendung mit Enterprise-QualitΓ€t. **Zeitrahmen:** 2-3 Wochen **Fokus:** Design System, Performance, Developer Experience, QualitΓ€t ## π Teilphasen im Detail ### Phase 3.1: Design System Foundation (Woche 1) #### 3.1.1 Core UI Components (2-3 Tage) **Ziel:** Wiederverwendbare, konsistente UI-Bibliothek **Neue Dateien erstellen:** ``` src/lib/ui/ βββ Button/ β βββ Button.svelte # Universal Button Component β βββ Button.types.ts # Button Props Interface β βββ Button.stories.ts # Storybook Stories βββ Input/ β βββ Input.svelte # Text Input β βββ Textarea.svelte # Textarea Input β βββ Select.svelte # Select Dropdown β βββ Input.types.ts # Input Props βββ Form/ β βββ FormField.svelte # Label + Input + Error β βββ FormSection.svelte # Section mit Titel β βββ Form.svelte # Form Container βββ Layout/ β βββ Card.svelte # Content Cards β βββ Modal.svelte # Overlay Modals β βββ Tabs.svelte # Tab Navigation βββ index.ts # Barrel Exports ``` **Button.svelte Beispiel:** ```svelte {#if loading} {/if} {@render children?.()} ``` **Migrations-Impact:** - Alle `` Tags in Components ersetzen - Konsistente Styling-Properties - Accessibility Features eingebaut #### 3.1.2 Theme System Verbesserung (1-2 Tage) **Ziel:** Robustes, erweiterbares Theme-System **Neue Features:** ```typescript // src/lib/themes/themeSystem.ts interface ThemeToken { colors: { primary: ColorScale; secondary: ColorScale; success: ColorScale; warning: ColorScale; error: ColorScale; neutral: ColorScale; }; typography: { fontFamily: Record; fontSize: Record; fontWeight: Record; }; spacing: Record; borderRadius: Record; shadows: Record; } interface ColorScale { 50: string; 100: string; 200: string; // ... bis 900 } ``` **CSS Custom Properties:** ```css /* Auto-generiert basierend auf Theme-Token */ :root { --color-primary-50: #f0f9ff; --color-primary-500: #3b82f6; --color-primary-900: #1e3a8a; --font-size-xs: 0.75rem; --font-size-sm: 0.875rem; /* ... */ } [data-theme="dark"] { --color-primary-50: #1e3a8a; /* Inverted scales fΓΌr Dark Mode */ } ``` **Erwarteter Impact:** - Bessere Design-Konsistenz - Einfache Theme-Erweiterung - Performance durch CSS Custom Properties #### 3.1.3 NodeForm Component Refactoring (1-2 Tage) **Ziel:** Aufspaltung des monolithischen NodeForm **Neue Struktur:** ``` src/lib/components/forms/ βββ NodeForm.svelte # Orchestrator βββ sections/ β βββ BasicInfoSection.svelte # Title, Slug, Summary, etc. β βββ ContentSection.svelte # Dynamic content fields β βββ ImageSection.svelte # AI Image Generation β βββ StoryBuilderSection.svelte # Story-specific fields β βββ OptionalSection.svelte # Collapsible advanced fields βββ fields/ β βββ TextField.svelte # Reusable text input β βββ TextareaField.svelte # Reusable textarea β βββ TagsField.svelte # Tags input with autocomplete β βββ VisibilityField.svelte # Visibility selector βββ NodeForm.types.ts # Shared types ``` **NodeForm.svelte (refactored):** ```svelte {#if error} {/if} {#if mode === 'create'} {/if} {#if kind === 'story' && mode === 'create'} {/if} ``` **Vorteile:** - Bessere Testbarkeit (einzelne Sections) - Leichtere Wartung - Wiederverwendbare Form-Sections ### Phase 3.2: Performance Optimierung (Woche 2) #### 3.2.1 Smart Loading & Caching (2-3 Tage) **Client-Side Caching:** ```typescript // src/lib/stores/nodeCache.ts interface NodeCache { nodes: Map; lists: Map; lastFetch: Map; } export const nodeCache = (() => { let cache = $state({ nodes: new Map(), lists: new Map(), lastFetch: new Map() }); return { get cache() { return cache; }, getNode(slug: string): ContentNode | null { return cache.nodes.get(slug) || null; }, setNode(node: ContentNode): void { cache.nodes.set(node.slug, node); cache.lastFetch.set(node.slug, Date.now()); }, getList(key: string): ContentNode[] | null { const cached = cache.lists.get(key); const fetchTime = cache.lastFetch.get(key); // Cache for 5 minutes if (cached && fetchTime && Date.now() - fetchTime < 5 * 60 * 1000) { return cached; } return null; }, invalidateNode(slug: string): void { cache.nodes.delete(slug); // Invalidate related lists cache.lists.clear(); } }; })(); ``` **Smart NodeService:** ```typescript // Enhanced NodeService mit Caching export class NodeService { static async get(slug: string, useCache = true): Promise { if (useCache) { const cached = nodeCache.getNode(slug); if (cached) return cached; } const response = await fetch(`/api/nodes/${slug}`); if (!response.ok) throw new Error('Node not found'); const node = await response.json(); nodeCache.setNode(node); return node; } // Optimistic Updates static async update(slug: string, updates: UpdateNodeRequest): Promise { // Update cache optimistically const cached = nodeCache.getNode(slug); if (cached) { const optimistic = { ...cached, ...updates }; nodeCache.setNode(optimistic); } try { const response = await fetch(`/api/nodes/${slug}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(updates) }); if (!response.ok) throw new Error('Update failed'); const updated = await response.json(); nodeCache.setNode(updated); return updated; } catch (error) { // Revert optimistic update nodeCache.invalidateNode(slug); throw error; } } } ``` #### 3.2.2 Virtual Scrolling fΓΌr Listen (1-2 Tage) **Problem:** GroΓe Listen (100+ Nodes) werden langsam **LΓΆsung:** Virtual Scrolling Component ```svelte {#each visibleItems.items as item, index (item)} {@render renderItem(item, visibleItems.startIndex + index)} {/each} ``` #### 3.2.3 Image Optimization (1 Tag) **Lazy Loading Images:** ```svelte {#if !loaded && !error} {/if} {#if error} Bild nicht verfΓΌgbar {/if} ``` ### Phase 3.3: Developer Experience (Woche 2-3) #### 3.3.1 Advanced Error Handling (1-2 Tage) **Error Boundary System:** ```svelte {#if error} {#if fallback} {@render fallback(error, retry)} {:else} Ein Fehler ist aufgetreten {error.message} Erneut versuchen {/if} {:else} {@render children?.()} {/if} ``` **Toast Notification System:** ```typescript // src/lib/stores/notifications.ts interface Notification { id: string; type: 'success' | 'error' | 'warning' | 'info'; title: string; message?: string; duration?: number; actions?: { label: string; action: () => void }[]; } export const notifications = (() => { let items = $state([]); return { get items() { return items; }, add(notification: Omit): string { const id = Math.random().toString(36).substring(7); const item = { ...notification, id }; items = [...items, item]; if (notification.duration !== 0) { setTimeout(() => { items = items.filter(n => n.id !== id); }, notification.duration || 5000); } return id; }, remove(id: string): void { items = items.filter(n => n.id !== id); }, clear(): void { items = []; }, // Convenience methods success(title: string, message?: string) { return this.add({ type: 'success', title, message }); }, error(title: string, message?: string) { return this.add({ type: 'error', title, message, duration: 0 }); } }; })(); ``` #### 3.3.2 Advanced State Management (1-2 Tage) **Global State Store Pattern:** ```typescript // src/lib/stores/appStore.ts interface AppState { user: User | null; currentWorld: ContentNode | null; isLoading: boolean; notifications: Notification[]; modals: Modal[]; } export const createAppStore = () => { let state = $state({ user: null, currentWorld: null, isLoading: false, notifications: [], modals: [] }); return { get state() { return state; }, // Actions setUser(user: User | null) { state.user = user; }, setCurrentWorld(world: ContentNode | null) { state.currentWorld = world; if (browser && world) { localStorage.setItem('worldream-current-world', JSON.stringify(world)); } }, setLoading(loading: boolean) { state.isLoading = loading; }, addNotification(notification: Notification) { state.notifications = [...state.notifications, notification]; }, // Derived get isAuthenticated() { return state.user !== null; }, get hasWorldContext() { return state.currentWorld !== null; } }; }; export const appStore = createAppStore(); ``` #### 3.3.3 Testing Infrastructure (2-3 Tage) **Vitest Setup:** ```typescript // vitest.config.ts import { defineConfig } from 'vitest/config'; import { sveltekit } from '@sveltejs/kit/vite'; export default defineConfig({ plugins: [sveltekit()], test: { include: ['src/**/*.{test,spec}.{js,ts}'], environment: 'jsdom', setupFiles: ['src/tests/setup.ts'] } }); ``` **NodeService Tests:** ```typescript // src/lib/services/nodeService.test.ts import { describe, it, expect, vi, beforeEach } from 'vitest'; import { NodeService } from './nodeService'; // Mock fetch global.fetch = vi.fn(); describe('NodeService', () => { beforeEach(() => { vi.resetAllMocks(); }); describe('create', () => { it('should create a new node successfully', async () => { const mockNode = { id: '1', title: 'Test', kind: 'character' }; (fetch as any).mockResolvedValue({ ok: true, json: () => Promise.resolve(mockNode) }); const result = await NodeService.create({ kind: 'character', slug: 'test', title: 'Test', visibility: 'private', tags: [], content: {} }); expect(result).toEqual(mockNode); expect(fetch).toHaveBeenCalledWith('/api/nodes', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ kind: 'character', slug: 'test', title: 'Test', visibility: 'private', tags: [], content: {} }) }); }); it('should throw error on failed request', async () => { (fetch as any).mockResolvedValue({ ok: false, json: () => Promise.resolve({ error: 'Failed to create' }) }); await expect(NodeService.create({} as any)).rejects.toThrow('Failed to create'); }); }); }); ``` **Component Tests:** ```typescript // src/lib/ui/Button/Button.test.ts import { render, fireEvent } from '@testing-library/svelte'; import { describe, it, expect, vi } from 'vitest'; import Button from './Button.svelte'; describe('Button', () => { it('renders with correct text', () => { const { getByText } = render(Button, { props: { children: () => 'Click me' } }); expect(getByText('Click me')).toBeInTheDocument(); }); it('calls onclick handler when clicked', async () => { const handleClick = vi.fn(); const { getByRole } = render(Button, { props: { onclick: handleClick, children: () => 'Click me' } }); await fireEvent.click(getByRole('button')); expect(handleClick).toHaveBeenCalledOnce(); }); it('shows loading state', () => { const { getByText } = render(Button, { props: { loading: true, children: () => 'Submit' } }); expect(getByText('Submit')).toBeInTheDocument(); // Check for spinner expect(document.querySelector('.animate-spin')).toBeInTheDocument(); }); }); ``` ### Phase 3.4: Advanced Features (Woche 3) #### 3.4.1 Advanced Search & Filtering (2-3 Tage) **Smart Search Component:** ```svelte {#if loading} {/if} {#if results.length > 0} {#each results as result, index} selectResult(result)} > {result.title} {#if result.summary} {result.summary} {/if} {result.kind} {/each} {/if} ``` #### 3.4.2 Keyboard Shortcuts System (1-2 Tage) **Global Shortcuts:** ```typescript // src/lib/utils/shortcuts.ts interface Shortcut { key: string; ctrl?: boolean; alt?: boolean; shift?: boolean; action: () => void; description: string; } export const shortcuts = (() => { let registeredShortcuts = new Map(); function getShortcutKey(shortcut: Shortcut): string { const parts = []; if (shortcut.ctrl) parts.push('ctrl'); if (shortcut.alt) parts.push('alt'); if (shortcut.shift) parts.push('shift'); parts.push(shortcut.key.toLowerCase()); return parts.join('+'); } function handleKeydown(e: KeyboardEvent) { const key = getShortcutKey({ key: e.key, ctrl: e.ctrlKey || e.metaKey, alt: e.altKey, shift: e.shiftKey } as Shortcut); const shortcut = registeredShortcuts.get(key); if (shortcut) { e.preventDefault(); shortcut.action(); } } return { register(shortcut: Shortcut): () => void { const key = getShortcutKey(shortcut); registeredShortcuts.set(key, shortcut); if (registeredShortcuts.size === 1) { window.addEventListener('keydown', handleKeydown); } return () => { registeredShortcuts.delete(key); if (registeredShortcuts.size === 0) { window.removeEventListener('keydown', handleKeydown); } }; }, getAll(): Shortcut[] { return Array.from(registeredShortcuts.values()); } }; })(); ``` **Shortcuts Helper Component:** ```svelte {#if showHelp} Keyboard Shortcuts showHelp = false} class="text-gray-400 hover:text-gray-600"> {#each allShortcuts as shortcut} {shortcut.description} {#if shortcut.ctrl} Ctrl {/if} {#if shortcut.alt} Alt {/if} {#if shortcut.shift} Shift {/if} {shortcut.key} {/each} {/if} ``` ## π Phase 3 Erwartete Ergebnisse ### Quantifizierbare Verbesserungen - **Performance:** 40-60% schnellere Ladezeiten - **Bundle Size:** 20-30% kleiner durch Tree-shaking - **Development Speed:** 50% weniger Zeit fΓΌr neue Features - **Bug Rate:** 70% weniger UI-bugs durch Design System - **Accessibility Score:** 95+ Lighthouse Score ### Qualitative Verbesserungen - **User Experience:** Professionelle, konsistente UI - **Developer Experience:** Moderne Tooling & Testing - **Maintainability:** Klare Component-Bibliothek - **Scalability:** Solide Basis fΓΌr komplexe Features ## π― Definition of Done - Phase 3 ### Must Have (Minimal) - [ ] 8+ wiederverwendbare UI Components - [ ] Theme System mit Custom Properties - [ ] NodeForm aufgeteilt in 5+ Sections - [ ] Client-side Caching implementiert - [ ] Error Boundary System - [ ] 80% Test Coverage fΓΌr Services ### Should Have (Optimal) - [ ] Virtual Scrolling fΓΌr alle Listen - [ ] Lazy Image Loading - [ ] Toast Notification System - [ ] Advanced Search mit Keyboard Navigation - [ ] Storybook fΓΌr Component Library - [ ] 90% Test Coverage ### Could Have (Nice-to-have) - [ ] Global Keyboard Shortcuts - [ ] Performance Monitoring - [ ] Advanced Animation System - [ ] Accessibility Features (Screen Reader, etc.) - [ ] Advanced Caching mit Background Sync ## π° ROI Erwartung Phase 3 ### Entwicklungszeit-Einsparungen - **Neue UI Features:** 70% schneller durch Component Library - **Bug-Fixes:** 60% weniger Zeit durch bessere Testing - **Performance Issues:** 80% weniger durch professionelle Architektur ### Langfristige Vorteile - **Skalierbarkeit:** Enterprise-ready Architecture - **User Retention:** Professionelle UX steigert Zufriedenheit - **Team Onboarding:** Neue Entwickler productive in Tagen statt Wochen - **Technical Debt:** Praktisch eliminiert durch solide Basis --- **Phase 3 verwandelt Worldream von einem funktionalen MVP in eine professionelle, skalierbare Enterprise-Anwendung mit weltklasse Developer Experience.**
{error.message}