Zum Inhalt

XyNaP.crm — WYSIWYG Page-Designer, Theming & UI Components

Status: Konzept v1.0 (2026-03-06) Abhaengigkeit: modulares-produktsystem.md (Phase 2: CRM Core) Ziel: CRM mit echtem WYSIWYG In-Page-Designer — direkt auf der Live-Seite designen, Preview und Publish


1. Vision

Der XyNaP.crm Designer ist kein separater Editor — er IST die Seite. Der Nutzer arbeitet direkt auf der Live-Ansicht, kann Widgets hinzufuegen, verschieben, konfigurieren und sieht sofort das Ergebnis. Aendern. Sehen. Publishen.

┌──────────────────────────────────────────────────────────────────┐
│                    WYSIWYG Page-Designer                          │
│                                                                   │
│  ┌─ Toolbar ──────────────────────────────────────────────────┐  │
│  │ [Bearbeiten] [Vorschau] [Publish]  💻 📱  [Undo] [Redo]   │  │
│  └────────────────────────────────────────────────────────────┘  │
│                                                                   │
│  ┌─ Live-Page (WYSIWYG) ─────────────────────────────────────┐  │
│  │                                                             │  │
│  │   Design direkt auf der Seite.                              │  │
│  │   Klicke auf ein Widget → Inline-Config erscheint.          │  │
│  │   Ziehe neue Widgets aus dem [+] Panel.                     │  │
│  │   Verschiebe per Drag & Drop.                               │  │
│  │   Resize per Edge-Handles.                                  │  │
│  │                                                             │  │
│  │   Was du siehst = was publisht wird.                        │  │
│  │                                                             │  │
│  └─────────────────────────────────────────────────────────────┘  │
│                                                                   │
│  ┌─ Context Panel (rechts, ausklappbar) ──────────────────────┐  │
│  │ Widget-Einstellungen │ Theme │ Seiten-Settings              │  │
│  └────────────────────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────────────────────┘

Kern-Prinzipien:

  1. In-Place Editing — Kein separater "Designer-Modus". Die Live-Seite wird direkt bearbeitet.
  2. Preview = Reality — Was im Designer zu sehen ist, ist exakt das Published-Ergebnis.
  3. Publish-Workflow — Aenderungen sind erst nach explizitem "Publish" fuer alle sichtbar (Draft/Published).
  4. Responsive Live — Zwischen Desktop/Tablet/Mobile umschalten — direkt im Designer.
  5. Zero Code — Kein HTML/CSS/JS noetig. Alles visuell.

2. Page-Architektur

2.1 Seitentypen

Typ Beschreibung Beispiele
dashboard Uebersichtsseiten mit KPIs, Charts, Listen Sales Dashboard, Support Dashboard, CEO View
detail Entity-Detail mit dynamischen Feldern Kontakt-Seite, Deal-Seite, Ticket-Seite
list Gefilterte Listen/Tabellen Offene Deals, Meine Aufgaben, Alle Kontakte
report Auswertungen mit Datenquellen + Filter MRR Report, Pipeline Report, Team Performance
form Formulare (intern + extern) Lead-Erfassung, Kontakt-Formular, Umfrage
custom Freie Seiten Onboarding-Wizard, Willkommens-Seite

2.2 Page-Datenmodell

interface Page {
  id: string
  tenant_id: string
  name: string                        // "Sales Dashboard"
  slug: string                        // "sales-dashboard"
  type: PageType
  icon?: string                       // Lucide Icon fuer Navigation
  entity_type?: string                // Fuer detail/list: "deal", "contact", "ticket"

  // Versioning
  draft: PageContent                  // Aktueller Entwurf (wird im Designer bearbeitet)
  published: PageContent | null       // Veroeffentlichte Version (null = noch nie publisht)
  published_at: string | null
  published_by: string | null

  // Meta
  is_system: boolean                  // System-Seiten (nicht loeschbar)
  is_default: boolean                 // Standard-Seite fuer diesen Typ
  is_public: boolean                  // Fuer alle Tenant-User sichtbar
  owner_id: string
  permissions: string[]               // Welche Rollen diese Seite sehen
  sort_order: number                  // Position in der Navigation

  // Navigation
  nav_section?: string                // "crm", "support", "reports", null (versteckt)
  nav_parent_id?: string              // Fuer verschachtelte Navigation

  created_at: string
  updated_at: string
}

interface PageContent {
  version: number
  rows: Row[]
  settings: PageSettings
  theme_overrides?: Partial<ThemeOverrides>  // Seitenspezifische Theme-Anpassungen
}

interface PageSettings {
  max_width: string                   // "1440px" | "100%" | "1200px"
  padding: string                     // "24px"
  row_gap: string                     // "24px"
  background?: string                 // Seiten-Hintergrund (ueberschreibt Theme)
  auto_refresh?: number               // Sekunden (0 = aus)
  filters?: PageFilter[]              // Globale Seitenfilter (Zeitraum, Team, etc.)
}

interface PageFilter {
  id: string
  label: string
  type: 'date_range' | 'select' | 'user' | 'pipeline' | 'custom'
  options?: any
  default_value?: any
  affects_widgets: string[]           // Widget-IDs die auf diesen Filter reagieren
}

2.3 Row & Cell Modell

interface Row {
  id: string
  order: number
  cells: Cell[]

  // Layout
  columns: number                     // Spaltenanzahl: 1-12 (CSS Grid)
  gap: string                         // "16px"
  align_items: 'stretch' | 'start' | 'center' | 'end'
  min_height?: string
  max_height?: string

  // Optik
  background?: string
  padding?: string
  margin_top?: string
  border_bottom?: boolean

  // Responsive
  responsive: {
    desktop: { columns: number; visible: boolean }
    tablet:  { columns: number; visible: boolean }
    mobile:  { columns: number; visible: boolean }
  }

  // Bedingung (optional)
  visible_condition?: {
    field: string                     // "user.role", "page.filter.period"
    operator: 'eq' | 'neq' | 'in' | 'gt' | 'lt'
    value: any
  }
}

interface Cell {
  id: string
  order: number

  // Was wird angezeigt
  widget_type: string                 // "kpi-number", "deal-kanban", "chart-bar", etc.
  widget_config: Record<string, any>  // Widget-spezifische Konfiguration

  // Grid-Position (responsive)
  span: {
    desktop: number                   // 1-12 Spalten
    tablet: number
    mobile: number
  }
  offset?: {
    desktop: number                   // 0-11 Spalten Einrueckung
    tablet: number
    mobile: number
  }

  // Optik
  title?: string
  show_title: boolean
  card_style: 'elevated' | 'outlined' | 'flat' | 'none'
  padding?: string
  min_height?: string
  max_height?: string
  overflow: 'visible' | 'scroll' | 'hidden'

  // Verhalten
  collapsible: boolean                // Einklappbar
  collapsed_default: boolean
  loading_skeleton: boolean           // Skeleton-Loader waehrend Daten laden
  refresh_interval?: number           // Widget-spezifischer Refresh (Sekunden)

  // Bedingung
  visible_condition?: {
    field: string
    operator: string
    value: any
  }
}

3. WYSIWYG Designer — UX im Detail

3.1 Modi

┌─────────────────────────────────────────────────────────────────┐
│                                                                  │
│   [Bearbeiten]     [Vorschau]      [Publish ▾]                  │
│   ═══════════                                                    │
│   Aktiver Modus                                                  │
│                                                                  │
│   Bearbeiten:  Widgets auswaehlen, konfigurieren, verschieben    │
│                Inline-Toolbar bei Hover, Drag-Handles sichtbar   │
│                Click → Config-Panel oeffnet rechts               │
│                                                                  │
│   Vorschau:    Exakt wie fuer Endnutzer (keine Handles/Toolbar)  │
│                Responsive-Toggle aktiv (Desktop/Tablet/Mobile)   │
│                                                                  │
│   Publish:     ▾ Dropdown:                                       │
│                  - "Jetzt veroeffentlichen"                      │
│                  - "Zeitgesteuert" (Datum/Uhrzeit)               │
│                  - "Entwurf speichern"                           │
│                  - "Aenderungen verwerfen"                       │
│                  - "Versionshistorie"                            │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

3.2 In-Page Editing Flow

  User oeffnet CRM-Seite (z.B. "Sales Dashboard")
  ┌─ Normal-Ansicht (Published) ────────────────────────┐
  │                                                      │
  │  Seite wird gerendert wie fuer alle User.            │
  │  Oben rechts: kleiner [✏ Bearbeiten] Button          │
  │  (nur fuer User mit "page.edit" Permission)          │
  │                                                      │
  └──────────────────────────────────────────────────────┘
          │ Klick auf "Bearbeiten"
  ┌─ Edit-Modus (WYSIWYG) ─────────────────────────────┐
  │                                                      │
  │  ┌─ Floating Toolbar (oben) ──────────────────────┐ │
  │  │ [+ Widget]  [Undo] [Redo]  💻 📱  [Vorschau]   │ │
  │  │ [Speichern] [Publish] [✕ Schliessen]           │ │
  │  └────────────────────────────────────────────────┘ │
  │                                                      │
  │  Jedes Widget bekommt bei Hover:                     │
  │  ┌────────────────────────────────────┐              │
  │  │ ↕ Drag-Handle  │  ⚙ Config  │  ✕  │ ← Inline    │
  │  ├────────────────────────────────────┤              │
  │  │                                    │              │
  │  │     Widget-Inhalt (LIVE Daten)     │              │
  │  │                                    │              │
  │  ├────────────────────────────────────┤              │
  │  │ ←─────── Resize Handle ──────────→ │ ← Breite    │
  │  └────────────────────────────────────┘              │
  │                                                      │
  │  Zwischen Rows: [+ Row hier einfuegen] Linie         │
  │                                                      │
  │  Klick auf Widget → Config-Panel klappt rechts auf:  │
  │                     ┌──────────────────┐             │
  │                     │ Widget-Settings   │             │
  │                     │ Datenquelle       │             │
  │                     │ Darstellung       │             │
  │                     │ Responsive        │             │
  │                     │ Bedingungen       │             │
  │                     └──────────────────┘             │
  │                                                      │
  └──────────────────────────────────────────────────────┘
          │ Klick auf "Publish"
  ┌─ Publish-Dialog ────────────────────────────────────┐
  │                                                      │
  │  Aenderungen seit letztem Publish:                   │
  │  - 2 Widgets hinzugefuegt                            │
  │  - 1 Widget verschoben                               │
  │  - Theme-Farbe geaendert                             │
  │                                                      │
  │  [Jetzt veroeffentlichen]  [Abbrechen]              │
  │                                                      │
  └──────────────────────────────────────────────────────┘

3.3 Widget hinzufuegen (+ Panel)

Klick auf [+ Widget] oeffnet ein Overlay-Panel (kein separater Screen):

┌─ Widget hinzufuegen ────────────────────────────────────┐
│                                                          │
│ 🔍 [Suche...]                                           │
│                                                          │
│ ── Kennzahlen (KPIs) ─────────────────────────────────  │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐                    │
│ │  #   │ │  ↗   │ │ ±    │ │  ○   │                    │
│ │ Zahl │ │Trend │ │Vgl.  │ │Gauge │                    │
│ └──────┘ └──────┘ └──────┘ └──────┘                    │
│                                                          │
│ ── Pipeline & Deals ──────────────────────────────────  │
│ ┌──────┐ ┌──────┐ ┌──────┐                              │
│ │ ▯▯▯  │ │  ▽   │ │  ☰   │                              │
│ │Kanban│ │Funnel│ │Deals │                              │
│ └──────┘ └──────┘ └──────┘                              │
│                                                          │
│ ── Listen & Tabellen ─────────────────────────────────  │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐          │
│ │  ☰   │ │  ☰   │ │  ☰   │ │  ▤   │ │  ✓   │          │
│ │Kont. │ │Ticket│ │Aktiv.│ │Recent│ │Tasks │          │
│ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘          │
│                                                          │
│ ── Diagramme ─────────────────────────────────────────  │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐                    │
│ │ ▌▌▌  │ │  ╱   │ │  ◔   │ │  📊  │                    │
│ │ Bar  │ │ Line │ │Donut │ │Fore- │                    │
│ │      │ │      │ │      │ │cast  │                    │
│ └──────┘ └──────┘ └──────┘ └──────┘                    │
│                                                          │
│ ── Detail-Felder ─────────────────────────────────────  │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐                    │
│ │  👤  │ │  ▦   │ │  🔗  │ │  📝  │                    │
│ │Header│ │Felder│ │Relat.│ │Notes │                    │
│ └──────┘ └──────┘ └──────┘ └──────┘                    │
│                                                          │
│ ── Sonstiges ─────────────────────────────────────────  │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐          │
│ │  ⚡  │ │  🏆  │ │  📅  │ │  </> │ │  ─   │          │
│ │Quick │ │Leader│ │Kalen.│ │HTML  │ │Spacer│          │
│ │Act.  │ │board │ │      │ │      │ │      │          │
│ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘          │
│                                                          │
│ Klicke oder ziehe ein Widget auf die Seite.             │
└─────────────────────────────────────────────────────────┘

Workflow: Widget anklicken → wird an Ende der Seite eingefuegt → sofort per Drag an gewuenschte Position ziehen → Config-Panel oeffnet sich automatisch.

3.4 Inline-Konfiguration

Statt eines separaten Config-Screens oeffnet sich ein Slide-Over Panel rechts:

┌─ Widget-Einstellungen ────── [✕] ──┐
│                                      │
│ ┌─ Tabs ──────────────────────────┐ │
│ │ [Daten] [Darstellung] [Erweit.] │ │
│ └─────────────────────────────────┘ │
│                                      │
│ ── Tab: Daten ────────────────────  │
│                                      │
│ Datenquelle                          │
│ [Pipeline: Sales ▾]                  │
│                                      │
│ Filter                               │
│ Status: [● Offen  ○ Gewonnen  ○ Alle]│
│ Zeitraum: [🔗 Seitenfilter ▾]       │
│                                      │
│ Sortierung                           │
│ [Wert ▾]  [Absteigend ▾]           │
│                                      │
│ Limit: [20]                          │
│                                      │
│ ── Tab: Darstellung ──────────────  │
│                                      │
│ Titel: [Pipeline-Uebersicht]        │
│ Titel anzeigen: [✓]                 │
│                                      │
│ Card-Stil:                           │
│ [● Erhoeht  ○ Umrandet  ○ Flach]    │
│                                      │
│ Breite:                              │
│ 💻 Desktop: [═══════8═══════]  8/12  │
│ 📱 Tablet:  [═══════════12══] 12/12  │
│ 📱 Mobile:  [═══════════12══] 12/12  │
│                                      │
│ Hoehe: [Auto ▾]                     │
│ Padding: [16px]                      │
│                                      │
│ ── Tab: Erweitert ────────────────  │
│                                      │
│ Einklappbar: [✓]                    │
│ Eingeklappt bei Start: [ ]          │
│ Auto-Refresh: [30s ▾]              │
│ Skeleton-Loader: [✓]               │
│                                      │
│ Sichtbarkeit:                        │
│ [Immer ▾]                           │
│ Oder: Bedingung definieren...        │
│                                      │
└──────────────────────────────────────┘

3.5 Responsive Design im Designer

┌─ Toolbar ─────────────────────────────────────────────┐
│                                                        │
│  Viewport:  [💻 Desktop]  [📱 Tablet]  [📱 Mobile]    │
│              ═══════════                                │
│                                                        │
│  Bei Viewport-Wechsel:                                 │
│  - Canvas-Breite aendert sich (1440 → 768 → 375px)    │
│  - Grid passt sich an (span-Werte pro Breakpoint)      │
│  - Versteckte Rows/Cells werden ausgegraut             │
│  - Aenderungen gelten NUR fuer den aktiven Breakpoint  │
│                                                        │
└────────────────────────────────────────────────────────┘

Desktop (1440px):
┌──3──┐ ┌──3──┐ ┌──3──┐ ┌──3──┐
│ KPI │ │ KPI │ │ KPI │ │ KPI │
└─────┘ └─────┘ └─────┘ └─────┘
┌──────────8──────────┐ ┌──4──┐
│     Kanban           │ │Feed │
└─────────────────────┘ └─────┘

Tablet (768px):
┌──────6──────┐ ┌──────6──────┐
│    KPI      │ │    KPI      │
└─────────────┘ └─────────────┘
┌──────6──────┐ ┌──────6──────┐
│    KPI      │ │    KPI      │
└─────────────┘ └─────────────┘
┌────────────12────────────────┐
│          Kanban               │
└──────────────────────────────┘
┌────────────12────────────────┐
│           Feed                │
└──────────────────────────────┘

Mobile (375px):
┌────────────12────────────────┐
│            KPI                │ × 4
└──────────────────────────────┘
┌────────────12────────────────┐
│          Kanban               │
└──────────────────────────────┘

4. Theming-Engine

4.1 Theme-Architektur

Themes werden pro Tenant gespeichert und ueber CSS Custom Properties live angewendet. Der Theme-Editor ist Teil des WYSIWYG Designers.

interface TenantTheme {
  id: string
  tenant_id: string
  name: string                        // "Corporate Blue"
  is_active: boolean

  colors: {
    primary: string                   // Hauptfarbe
    primary_hover: string
    secondary: string
    accent: string
    success: string
    warning: string
    danger: string
    info: string
    surface: string                   // Card/Widget-Hintergrund
    background: string                // Seiten-Hintergrund
    text: string
    text_muted: string
    border: string
    neutral: Record<string, string>   // 50-950 Graustufen
  }

  typography: {
    font_family: string
    font_family_mono: string
    font_size_base: string
    line_height: string
    heading_weight: string
  }

  layout: {
    border_radius: string
    border_radius_sm: string
    border_radius_lg: string
    spacing_unit: string
    sidebar_width: string
  }

  branding: {
    logo_url: string | null
    favicon_url: string | null
    login_background_url: string | null
    login_message: string | null
  }

  mode: 'light' | 'dark' | 'auto'
  dark_overrides: Partial<TenantTheme['colors']>
}

4.2 Theme-Editor (im Designer integriert)

Der Theme-Editor ist ein Tab im Config-Panel des Designers — NICHT eine separate Seite:

┌─ Config Panel: Theme ────── [✕] ──┐
│                                     │
│ Aktives Theme: [Corporate Blue ▾]   │
│ [Neues Theme]  [Duplizieren]        │
│                                     │
│ ── Schnellauswahl ────────────────  │
│ ┌────┐┌────┐┌────┐┌────┐┌────┐    │
│ │Blue││Grn ││Purp││Org ││Slat│    │
│ └────┘└────┘└────┘└────┘└────┘    │
│ (10 Preset-Themes als Kacheln)      │
│                                     │
│ ── Farben ────────────────────────  │
│ Primary:   [■ #2563eb] [🎨]        │
│ Secondary: [■ #64748b] [🎨]        │
│ Accent:    [■ #f59e0b] [🎨]        │
│ Success:   [■ #10b981]             │
│ Warning:   [■ #f59e0b]             │
│ Danger:    [■ #ef4444]             │
│ Background:[■ #f8fafc]             │
│ Surface:   [■ #ffffff]             │
│ Text:      [■ #0f172a]             │
│                                     │
│ ── Typografie ────────────────────  │
│ Font: [Inter ▾]                    │
│ Groesse: [16px ▾]                  │
│ Heading-Gewicht: [600 ▾]          │
│                                     │
│ ── Layout ────────────────────────  │
│ Ecken-Radius: [═══8px═══]          │
│ (Slider: 0 → 20px)                 │
│                                     │
│ ── Branding ──────────────────────  │
│ Logo:    [📁 Hochladen]            │
│ Favicon: [📁 Hochladen]            │
│                                     │
│ ── Modus ─────────────────────────  │
│ [● Auto  ○ Hell  ○ Dunkel]         │
│                                     │
│ [Aenderungen live — Publish noetig] │
└─────────────────────────────────────┘

Theme-Aenderungen werden sofort auf der Live-Seite sichtbar (WYSIWYG), aber erst nach "Publish" fuer alle Nutzer aktiv.

4.3 Preset-Themes

Theme Primary Stil
XyNaP Default #2563eb Modern, Clean
Corporate #1e40af Serioes, Business
Startup #059669 Frisch, Dynamisch
Creative #7c3aed Kreativ
Warm #ea580c Einladend
Minimal #18181b Reduziert
Ocean #0891b2 Professionell
Rose #e11d48 Auffaellig
Forest #166534 Vertrauensvoll
Slate #475569 Zeitlos

4.4 CSS Custom Properties (Runtime)

:root {
  --x-primary: #2563eb;
  --x-primary-hover: #1d4ed8;
  --x-secondary: #64748b;
  --x-accent: #f59e0b;
  --x-success: #10b981;
  --x-warning: #f59e0b;
  --x-danger: #ef4444;
  --x-info: #3b82f6;
  --x-surface: #ffffff;
  --x-bg: #f8fafc;
  --x-text: #0f172a;
  --x-text-muted: #64748b;
  --x-border: #e2e8f0;
  --x-radius: 8px;
  --x-radius-sm: 4px;
  --x-radius-lg: 12px;
  --x-font: 'Inter', system-ui, sans-serif;
  --x-font-mono: 'JetBrains Mono', monospace;
}

[data-theme="dark"] {
  --x-surface: #1e293b;
  --x-bg: #0f172a;
  --x-text: #f1f5f9;
  --x-text-muted: #94a3b8;
  --x-border: #334155;
}

5. UI Components (Widget-Bibliothek)

5.1 Architektur

Jedes Widget ist eine selbststaendige Vue-Komponente die: - Ihre eigenen Daten per API laedt - Ueber widget_config konfiguriert wird - Theme-CSS-Variablen nutzt (kein Hardcoding) - Im WYSIWYG Designer platzierbar ist - Einen Edit-Overlay fuer den Designer bereitstellt - Einen Config-Schema fuer das Config-Panel liefert

interface WidgetMeta {
  type: string                        // Eindeutiger Bezeichner
  name: string                        // Anzeigename (i18n key)
  icon: string                        // Lucide Icon
  category: 'kpi' | 'pipeline' | 'list' | 'chart' | 'detail' | 'misc'
  description: string
  default_span: { desktop: number; tablet: number; mobile: number }
  min_span: number
  config_schema: JSONSchema7          // Fuer automatische Config-UI-Generierung
  default_config: Record<string, any>
  supports_page_filters: boolean      // Reagiert auf globale Seitenfilter
}

5.2 Widget-Katalog

Kennzahlen (KPIs)

Widget Beschreibung Default Span
kpi-number Einzelne grosse Zahl mit Label, Icon, Trend-Pfeil 3
kpi-trend Zahl + Sparkline (7d/30d/90d) 3
kpi-comparison Aktuell vs. Vorperiode mit Delta 3
kpi-gauge Kreisfoermiger Fortschrittsbalken (0-100%) 3
kpi-group 2-4 KPIs in einer kompakten Card 6

Pipeline & Deals

Widget Beschreibung Default Span
pipeline-kanban Kanban-Board mit Drag & Drop zwischen Phasen 8
pipeline-funnel Trichter-Visualisierung mit Conversion-Raten 6
deal-table Sortierbare, filterbare Deal-Tabelle 12
deal-summary Kompakte Deal-Karte (fuer Detail-Pages) 4

Listen & Tabellen

Widget Beschreibung Default Span
contact-table Kontakt-Liste mit Suche, Filter, Inline-Actions 12
ticket-table Ticket-Liste mit Status-Badges, SLA-Countdown 12
activity-timeline Chronologischer Feed (E-Mails, Anrufe, Notizen) 4
task-list Aufgaben mit Checkbox, Faelligkeit, Prioritaet 4
recent-items Zuletzt bearbeitete Entities (Deals, Kontakte, ...) 4

Diagramme

Widget Beschreibung Default Span
chart-bar Balkendiagramm (vertikal/horizontal) 6
chart-line Liniendiagramm mit optionalem Area-Fill 6
chart-donut Donut/Pie mit optionalem Center-Total 4
chart-forecast CRM-Forecast (gewichtet, historisch + Projektion) 6
chart-stacked-bar Gestapelte Balken (z.B. Deals pro Phase pro Monat) 6

Detail-Felder (fuer Entity-Pages)

Widget Beschreibung Default Span
entity-header Kopfbereich: Avatar, Name, Tags, Status, Actions 12
entity-fields Editierbare Feldergruppe (Grid oder Liste) 6
entity-relations Verknuepfte Entities (Deals, Tickets, Files, ...) 6
notes-panel Notizen mit Pinned, Add, Timeline 4
files-panel Angehaengte Dateien mit Upload 4

Sonstiges

Widget Beschreibung Default Span
quick-actions Button-Leiste (Neuer Deal, Neuer Kontakt, ...) 12
team-leaderboard Ranking nach Metrik (Deals, Umsatz, Tickets) 4
calendar-mini Mini-Kalender mit CRM-Events 4
html-embed Freier HTML-Block (sanitized) 6
spacer Leerer Platzhalter mit konfigurierbarer Hoehe 12
divider Horizontale Trennlinie 12
heading Ueberschrift (H1-H4) 12
text-block Rich-Text Block (WYSIWYG Editor) 6

5.3 Widget Config-Beispiele

// kpi-number
{
  label: "Offene Deals",
  data_source: "deals",
  aggregation: "count",
  filter: { status: "open" },
  format: "number",
  icon: "TrendingUp",
  color: "primary",
  compare_period: "previous_month"  // Zeigt +/- Delta
}

// pipeline-kanban
{
  pipeline_id: "sales-pipeline",
  show_deal_value: true,
  show_contact_name: true,
  show_owner_avatar: true,
  max_cards_per_column: 20,
  highlight_rotting: true,
  rotting_days: 14,
  compact_mode: false,
  allow_drag: true                  // Drag & Drop zwischen Phasen
}

// chart-forecast
{
  pipeline_id: null,                // Alle Pipelines
  period: "monthly",
  months_ahead: 6,
  show_weighted: true,
  show_actual: true,
  show_target: true,
  target_values: {                  // Optionale Zielwerte
    "2026-03": 50000,
    "2026-04": 55000
  }
}

// entity-fields (fuer Contact Detail Page)
{
  sections: [
    {
      title: "Kontaktdaten",
      columns: 2,
      fields: [
        { key: "email", format: "email", editable: true },
        { key: "phone", format: "phone", editable: true },
        { key: "mobile", format: "phone", editable: true },
        { key: "website", format: "url", editable: true }
      ]
    },
    {
      title: "Adresse",
      columns: 2,
      fields: [
        { key: "address.street" },
        { key: "address.city" },
        { key: "address.zip" },
        { key: "address.country" }
      ]
    },
    {
      title: "Custom Fields",
      columns: 2,
      fields: [
        { key: "custom.branche", label: "Branche" },
        { key: "custom.mitarbeiter", label: "Mitarbeiter-Anzahl", format: "number" }
      ]
    }
  ]
}

6. Publish-Workflow

6.1 Draft/Published System

                    ┌──────────────┐
                    │   Erstellen  │
                    └──────┬───────┘
                    ┌──────────────┐
            ┌──────│    Draft     │◄─── Bearbeiten
            │      └──────┬───────┘
            │             ▼
            │      ┌──────────────┐
            │      │   Publish    │──── Sichtbar fuer alle
            │      └──────┬───────┘
            │             │
            │             ▼
            │      ┌──────────────┐
            └─────►│  Neuer Draft │──── Aenderungen nur fuer Editor
                   └──────┬───────┘
                   ┌──────────────┐
                   │   Publish    │──── Ueberschreibt Published
                   └──────────────┘

6.2 Versionshistorie

Jeder Publish erstellt einen Snapshot. Rollback jederzeit moeglich.

interface PageVersion {
  id: string
  page_id: string
  version: number                     // Auto-increment
  content: PageContent                // Vollstaendiger Snapshot
  published_by: string
  published_at: string
  change_summary: string              // Auto-generiert oder manuell
}

6.3 Berechtigungen

Permission Beschreibung
page.view Seite sehen (Published-Version)
page.edit Seite bearbeiten (Draft erstellen)
page.publish Draft veroeffentlichen
page.delete Seite loeschen
page.create Neue Seiten erstellen
theme.edit Theme-Einstellungen aendern
theme.publish Theme veroeffentlichen

7. API-Endpoints

Pages

GET    /api/v1/crm/pages                            # Alle Seiten des Tenants
GET    /api/v1/crm/pages/{id}                       # Seite (published oder draft)
GET    /api/v1/crm/pages/{id}/draft                 # Nur Draft
GET    /api/v1/crm/pages/{id}/published             # Nur Published
POST   /api/v1/crm/pages                            # Neue Seite erstellen
PUT    /api/v1/crm/pages/{id}/draft                 # Draft speichern (Auto-Save)
POST   /api/v1/crm/pages/{id}/publish               # Draft veroeffentlichen
POST   /api/v1/crm/pages/{id}/discard-draft         # Draft verwerfen
DELETE /api/v1/crm/pages/{id}                       # Seite loeschen
POST   /api/v1/crm/pages/{id}/duplicate             # Seite klonen
GET    /api/v1/crm/pages/{id}/versions              # Versionshistorie
POST   /api/v1/crm/pages/{id}/rollback/{version}   # Zu Version zurueckkehren
POST   /api/v1/crm/pages/{id}/set-default           # Als Standard setzen

Themes

GET    /api/v1/crm/themes                           # Alle Themes
GET    /api/v1/crm/themes/active                    # Aktives Theme
POST   /api/v1/crm/themes                           # Neues Theme
PUT    /api/v1/crm/themes/{id}                      # Theme aktualisieren
DELETE /api/v1/crm/themes/{id}                      # Theme loeschen
POST   /api/v1/crm/themes/{id}/activate             # Theme aktivieren
GET    /api/v1/crm/themes/presets                   # Preset-Themes
POST   /api/v1/crm/themes/from-preset/{slug}        # Aus Preset erstellen
POST   /api/v1/crm/themes/{id}/export               # Als JSON exportieren
POST   /api/v1/crm/themes/import                    # Aus JSON importieren

Widgets

GET    /api/v1/crm/widgets                          # Verfuegbare Widget-Typen
GET    /api/v1/crm/widgets/{type}/schema            # Config-Schema fuer Widget
GET    /api/v1/crm/widgets/{type}/preview-data      # Mock-Daten fuer Designer-Preview

Page Templates

GET    /api/v1/crm/page-templates                   # Verfuegbare Templates
GET    /api/v1/crm/page-templates/{id}              # Template-Details
POST   /api/v1/crm/pages/from-template/{id}         # Seite aus Template erstellen
POST   /api/v1/crm/page-templates                   # Seite als Template speichern

8. DB-Schema

-- CRM Pages (Seiten)
crm_pages (
    id CHAR(36) PRIMARY KEY,
    tenant_id CHAR(36) NOT NULL,
    name VARCHAR(200) NOT NULL,
    slug VARCHAR(200) NOT NULL,
    type ENUM('dashboard','detail','list','report','form','custom') NOT NULL,
    icon VARCHAR(50),
    entity_type VARCHAR(50),

    -- Versioning
    draft JSON NOT NULL,                -- PageContent (aktueller Entwurf)
    published JSON,                     -- PageContent (veroeffentlicht, NULL = noch nie)
    published_at TIMESTAMP,
    published_by CHAR(36),

    -- Meta
    is_system BOOLEAN DEFAULT FALSE,
    is_default BOOLEAN DEFAULT FALSE,
    is_public BOOLEAN DEFAULT TRUE,
    owner_id CHAR(36) NOT NULL,
    permissions JSON,                   -- ["admin", "manager", "sales"]
    sort_order INT DEFAULT 0,

    -- Navigation
    nav_section VARCHAR(50),
    nav_parent_id CHAR(36),

    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

    UNIQUE(tenant_id, slug),
    INDEX(tenant_id, type),
    INDEX(tenant_id, nav_section)
)

-- Page-Versionen (Publish-History)
crm_page_versions (
    id CHAR(36) PRIMARY KEY,
    page_id CHAR(36) NOT NULL,
    version INT NOT NULL,
    content JSON NOT NULL,              -- PageContent Snapshot
    published_by CHAR(36) NOT NULL,
    published_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    change_summary VARCHAR(500),

    INDEX(page_id, version),
    FOREIGN KEY (page_id) REFERENCES crm_pages(id) ON DELETE CASCADE
)

-- Themes
crm_themes (
    id CHAR(36) PRIMARY KEY,
    tenant_id CHAR(36) NOT NULL,
    name VARCHAR(100) NOT NULL,
    is_active BOOLEAN DEFAULT FALSE,
    colors JSON NOT NULL,
    typography JSON NOT NULL,
    layout_config JSON NOT NULL,
    branding JSON,
    mode ENUM('light','dark','auto') DEFAULT 'auto',
    dark_overrides JSON,
    preset_slug VARCHAR(50),
    created_by CHAR(36),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

    UNIQUE(tenant_id, name)
)

-- Page Templates (global, nicht tenant-spezifisch)
crm_page_templates (
    id CHAR(36) PRIMARY KEY,
    name VARCHAR(200) NOT NULL,
    description TEXT,
    type ENUM('dashboard','detail','list','report','form','custom') NOT NULL,
    entity_type VARCHAR(50),
    thumbnail_url VARCHAR(500),
    content JSON NOT NULL,              -- PageContent
    category VARCHAR(50),
    is_active BOOLEAN DEFAULT TRUE,
    sort_order INT DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)

-- User-Praeferenzen (welche Seite als Default)
crm_user_page_prefs (
    id CHAR(36) PRIMARY KEY,
    tenant_id CHAR(36) NOT NULL,
    user_id CHAR(36) NOT NULL,
    page_type VARCHAR(50) NOT NULL,
    page_id CHAR(36),
    widget_overrides JSON,              -- User-spezifische Widget-Einstellungen
    UNIQUE(tenant_id, user_id, page_type)
)

9. Frontend-Architektur

src/
  crm/
    designer/
      PageDesigner.vue                # WYSIWYG In-Page Designer (Haupt-Komponente)
      DesignerToolbar.vue             # Floating Toolbar (Edit/Preview/Publish)
      DesignerCanvas.vue              # Canvas-Wrapper (Viewport-Simulation)
      WidgetPalette.vue               # [+] Widget hinzufuegen Panel
      ConfigPanel.vue                 # Slide-Over rechts (Widget/Theme/Page Settings)
      RowEditor.vue                   # Row-Handles (+ ✕ ↑ ↓)
      CellWrapper.vue                 # Cell mit Drag/Resize/Select Overlay
      ResizeHandle.vue                # Edge-Handle fuer Spaltenbreite
      PublishDialog.vue               # Publish-Bestaetigung mit Aenderungs-Diff
      VersionHistory.vue              # Versionshistorie + Rollback

    renderer/
      PageRenderer.vue                # Rendert Published Page (fuer Endnutzer)
      RowRenderer.vue                 # Rendert eine Row
      CellRenderer.vue                # Rendert eine Cell (dynamisches Widget)

    theme/
      ThemeConfig.vue                 # Theme-Tab im Config-Panel
      ThemeProvider.vue               # Injiziert CSS Custom Properties
      ColorPicker.vue                 # Farbwahl

    widgets/
      kpi/
        KpiNumber.vue
        KpiTrend.vue
        KpiComparison.vue
        KpiGauge.vue
        KpiGroup.vue
      pipeline/
        PipelineKanban.vue
        PipelineFunnel.vue
        DealTable.vue
        DealSummary.vue
      lists/
        ContactTable.vue
        TicketTable.vue
        ActivityTimeline.vue
        TaskList.vue
        RecentItems.vue
      charts/
        ChartBar.vue
        ChartLine.vue
        ChartDonut.vue
        ChartForecast.vue
        ChartStackedBar.vue
      detail/
        EntityHeader.vue
        EntityFields.vue
        EntityRelations.vue
        NotesPanel.vue
        FilesPanel.vue
      misc/
        QuickActions.vue
        TeamLeaderboard.vue
        CalendarMini.vue
        HtmlEmbed.vue
        Spacer.vue
        Divider.vue
        Heading.vue
        TextBlock.vue

    composables/
      usePageDesigner.ts              # Designer-State (edit/preview, undo/redo, drag)
      useWidgetRegistry.ts            # Widget-Registry (type → component + meta)
      useTheme.ts                     # Theme laden, CSS-Vars setzen, Live-Update
      useAutoSave.ts                  # Draft Auto-Save (debounced, 3s)
      usePublish.ts                   # Publish-Workflow
      usePageFilters.ts               # Globale Seitenfilter (provide/inject)

    stores/
      pageStore.ts                    # Pinia: aktuelle Seite, Draft-State
      themeStore.ts                   # Pinia: aktives Theme
      designerStore.ts                # Pinia: Designer-UI-State (selected cell, panel open)

    views/
      CrmPageView.vue                 # Route: /crm/:slug — rendert Page (published)
      CrmDesignerView.vue             # Route: /crm/:slug/edit — WYSIWYG Designer
      CrmPagesListView.vue            # Route: /crm/pages — Alle Seiten verwalten
      CrmThemesView.vue               # Route: /crm/themes — Theme-Verwaltung

10. Implementierungsreihenfolge

Phase A: Kern-Infrastruktur

  1. DB-Tabellen (crm_pages, crm_themes, crm_page_versions, crm_page_templates)
  2. Backend API (Pages CRUD, Themes CRUD, Publish-Workflow)
  3. ThemeProvider (CSS Custom Properties Runtime-Injection)
  4. PageRenderer (Row/Cell/Widget dynamisches Rendering)
  5. Widget Registry (Registrierung, Resolve, Schema)

Phase B: Basis-Widgets

  1. KPI-Widgets (kpi-number, kpi-trend, kpi-comparison)
  2. Listen-Widgets (deal-table, contact-table, activity-timeline, task-list)
  3. Pipeline-Widgets (pipeline-kanban)
  4. Chart-Widgets (chart-bar, chart-line, chart-donut)
  5. Misc-Widgets (heading, text-block, spacer, divider, quick-actions)

Phase C: WYSIWYG Designer

  1. PageDesigner (Edit-Modus Overlay auf Live-Page)
  2. DesignerToolbar (Edit/Preview/Publish Toggle)
  3. CellWrapper (Select, Drag, Resize Overlays)
  4. WidgetPalette ([+] Panel mit Kategorien)
  5. ConfigPanel (Slide-Over mit Widget/Theme/Page Tabs)
  6. Auto-Save (Debounced Draft-Save)

Phase D: Publish & Versioning

  1. Publish-Dialog (Diff-Anzeige, Bestaetigung)
  2. VersionHistory (Timeline, Rollback)
  3. Draft/Published Split-Rendering

Phase E: Erweiterte Widgets

  1. pipeline-funnel, chart-forecast, chart-stacked-bar
  2. Detail-Widgets (entity-header, entity-fields, entity-relations, notes-panel, files-panel)
  3. team-leaderboard, calendar-mini, kpi-gauge, kpi-group

Phase F: Polish

  1. Responsive Designer (Viewport-Toggle, Breakpoint-spezifische Spans)
  2. Undo/Redo (Command-Stack)
  3. Page Templates (Galerie, Import/Export)
  4. Theme Presets (10 Themes)
  5. Seitenfilter (Globale Filter die Widgets beeinflussen)
  6. User-Praeferenzen (persoenliche Default-Pages)

11. Technische Entscheidungen

Entscheidung Wahl Begruendung
Designer-Ansatz In-Page Overlay (kein iframe) Echtes WYSIWYG, keine Styling-Isolation-Probleme
Charts Chart.js 4 (vue-chartjs) Leichtgewichtig, gute Vue-Integration, responsive
Drag & Drop HTML5 DnD + @vueuse/core Kein Extra-Package, ausreichend fuer Grid-Layout
Grid-CSS CSS Grid (12-Col, repeat + span) Nativ, performant, responsive Breakpoints
Themes JSON → CSS Custom Properties Kein Build-Step, sofortige Live-Aenderung
Auto-Save Debounced PUT (3s nach letzter Aenderung) Kein Datenverlust, keine uebermaessige API-Last
Widget-Rendering Vue <component :is> + Registry Standard-Pattern, Tree-Shakeable, Lazy-Load moeglich
Undo/Redo Command-Pattern (Array von Snapshots) Simpel, zuverlaessig, kein Extra-Package
Config UI Auto-generiert aus JSON Schema Einheitliches Config-Panel fuer alle Widgets

12. Abgrenzung

  • Kein Website-Builder — Der Designer ist fuer CRM-Seiten (Dashboards, Detail-Views, Reports), NICHT fuer oeffentliche Websites. Dafuer gibt es XyNaP.cms.
  • Kein Code-Editor — Alles visuell, kein HTML/CSS/JS Zugang fuer Endnutzer.
  • Keine Custom-Widgets (vorerst) — Nur mitgelieferte Widgets. Plugin-System fuer spaeter geplant.
  • Kein Pixel-Perfect — 12-Spalten-Grid mit Snap, kein freies Positionieren (Squarespace-Ansatz, nicht Figma).
  • Kein Echtzeit-Collaboration — Ein User bearbeitet eine Seite gleichzeitig. Multi-User spaeter via Locking.