XyNaP.crm — WYSIWYG Page Designer, Theming & UI Components¶
Status:Concept v1.0 (2026-03-06) Abhaengigkeit:modular product system.md (Phase 2: CRM Core) Ziel:CRM with real WYSIWYG In-Page designer — directly on the live page design, preview and publishing
1. Vision¶
The XyNaP.crm Designer is no separate editor — it is the page. The user works directly on the live view, can add widgets, move, configure and immediately see the result. Change. See. Publish.
┌──────────────────────────────────────────────────────────────────┐
│ 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 │ │
│ └────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
Core principles:¶
- In-Place Editing— No separate designer mode. The live page is edited directly.
- Preview = Reality — What to see in the designer is exactly the published result.
- Publish-Workflow— Changes are only visible after explicit "publish" for all (draft/published).
- Responsive Live— Switch between desktop/tablet/mobile — directly in the designer.
- Zero Code— No HTML/CSS/JS noetig. All visual.
Two. Page architecture¶
2.1 Page types¶
| Type | Description | Examples |
|---|---|---|
| **dashboard * * | Overview pages with KPIs, charts, lists | Sales Dashboard, Support Dashboard, CEO View |
| **detail * * | Entity-Detail with dynamic fields | Contact page, Deal page, Ticket page |
| list * | Filtered lists/tables | Open deals, My tasks, All contacts |
| report * | Evaluations with data sources + filter | MRR Report, Pipeline Report, Team Performance |
| form | Forms (internal + external) | Lead-Erfassung, Contact Form, Survey |
| *custome * | Free pages | Onboarding-Wizard, Welcome page |
2.2 Page data model¶
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 Model¶
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 in 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 Add widget (+ Panel)¶
Click [+ Widget] to open an overlay panel (no separate 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. │
└─────────────────────────────────────────────────────────┘
ClickWorkflow:widget → will be inserted at the end of the page → immediately drag to bold position → Config panel opens automatically.
3.4 Inline configuration¶
Instead of a separate Config screen, anSlide-Over Panelopens up to the right:
┌─ 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 in 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 architecture¶
Themes are stored per tenant and applied live via CSS Custom Properties. The theme editor is part of the WYSIWYG designer.
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 (integrated in designer)¶
The theme editor is a tab in the designer's Config panel — NOT a separate page:
┌─ 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 changes will be displayed sofort on the live page (WYSIWYG), but only after "Publish" all users will be active.
4.3 Preset-Themes¶
| Theme | Primary | Style |
|---|---|---|
| XyNaP Default | #2563eb | Modern, Clean |
| Corporate | #140af | Serioes, Business |
| Startup | #059669 | Fresh, Dynamic |
| Creative | #7c3aed | Creative |
| Warm | ♪ | Inviting |
| Minimal | 18181b | Reduced |
| Ocean | #0891b2 | Professional |
| Rose | #e11d48 | Income |
| Forest | #166534 | Trustful |
| Slate | #475569 | Timeless |
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;
}
Five. UI Components (Widget library)¶
5.1 Architecture¶
Each widget is a self-contained cue component that:
- Your own data via API
- Configured viawidget_config
- Theme-CSS-Variablen uses (no hardcoding)
- The WYSIWYG designer can be placed
- AnEdit-Overlayfor the designer
- AConfig-Schemafor the Config panel delivers
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 catalog¶
KPIs¶
| Widget | Description | Default chip |
|---|---|---|
kpi-number |
Single large number with label, icon, trend arrow | 3 |
kpi-trend |
Number + Sparkline (7d/30d/90d) | 3 |
kpi-comparison |
Aktuell vs. previous period with Delta | 3 |
kpi-gauge |
Circular progress bar (0-100%) | 3 |
kpi-group |
2-4 KPIs in a compact card | 6 |
Pipeline & Deals¶
| Widget | Description | Default chip |
|---|---|---|
pipeline-kanban |
Kanban board with drag & drop between phases | 8 |
pipeline-funnel |
Funnel visualization with conversion rates | 6 |
deal-table |
Sortable, filterable deal table | 12 |
deal-summary |
Compact Deal Card (fuer Detail-Pages) | 4 |
Lists & tables¶
| Widget | Description | Default chip |
|---|---|---|
contact-table |
Contact list with search, filter, inline action | 12 |
ticket-table |
Ticket list with status badges, SLA-Countdown | 12 |
activity-timeline |
Chronological feed (e-mails, calls, notes) | 4 |
task-list |
Tasks with Checkbox, Skill, Priority | 4 |
recent-items |
Recently edited entities (deals, contacts, ...) | 4 |
Charts¶
| Widget | Description | Default chip |
|---|---|---|
chart-bar |
Bar chart (vertical/horizontal) | 6 |
chart-line |
Line diagram with optional area-fill | 6 |
chart-donut |
Donut/Pie with optional Center-Total | 4 |
chart-forecast |
CRM-Forecast (weighted, historical + projection) | 6 |
chart-stacked-bar |
Stacked bars (e.g. deals per phase per month) | 6 |
Detail Fields (fuer Entity-Pages)¶
| Widget | Description | Default chip |
|---|---|---|
entity-header |
Head area: Avatar, Name, Tags, Status, Actions | 12 |
entity-fields |
Editable Field Group (Grid or List) | 6 |
entity-relations |
Verknuepfte Entities (Deals, Tickets, Files, ...) | 6 |
notes-panel |
Notes with Pinned, Add, Timeline | 4 |
files-panel |
Filed with Upload | 4 |
Other¶
| Widget | Description | Default chip |
|---|---|---|
quick-actions |
Button-Leiste (New Deal, New Contact, ...) | 12 |
team-leaderboard |
Ranking to metrics (deals, sales, tickets) | 4 |
calendar-mini |
Mini calendar with CRM events | 4 |
html-embed |
Free HTML Block (sanitized) | 6 |
spacer |
Spacer with configurable view | 12 |
divider |
Horizontal separation line | 12 |
heading |
Heading (H1-H4) | 12 |
text-block |
Rich-Text Block (WYSIWYG Editor) | 6 |
5.3 Widget Config Examples¶
// 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 Version history¶
Each publishing creates a snapshot. Rollback at any time.
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 Permissions¶
| Permission | Description |
|---|---|
page.view |
See page (Published version) |
page.edit |
Edit Page (Create Draft) |
page.publish |
Draft negotiable |
page.delete |
Page Loose |
page.create |
Create new pages |
theme.edit |
Change Theme settings |
theme.publish |
Theme veroeffent |
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 architecture¶
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. Implementation order¶
Phase A: Core infrastructure¶
- DB-Tabellen(crm pages, crm themes, crm page versions, crm page templates)
- Backend API(Pages CRUD, Themes CRUD, Publish workflow)
- ThemeProvider(CSS Custom Properties Runtime-Injection)
- PageRenderer(Row/Cell/Widget dynamic rendering)
- Widget Registry(Registration, Resolve, Scheme)
Phase B: Basic widgets¶
- KPI-Widgets(kpi-number, kpi-trend, kpi-comparison)
- Listen-Widgets(deal-table, contact-table, activity-timeline, task-list)
- Pipeline-Widgets(pipeline canban)
- Chart-Widgets(chart-bar, chart-line, chart-donut)
- Misc-Widgets(heading, text-block, spacer, divider, quick-actions)
Phase C: WYSIWYG Designer¶
- PageDesigner(Edit Mode Overlay on Live Position)
- DesignerToolbar(Edit/Preview/Publish Toggle)
- CellWrapper(Select, Drag, Resize Overlays)
- WidgetPalette([+] Panel with categories)
- ConfigPanel(Slide-Over with Widget/Theme/Page Tabs)
- Auto-Save(Debounced Draft-Save)
Phase D: Publish & Versioning¶
- Publish-Dialog(diff display, confirmation)
- VersionHistory(Timeline, Rollback)
- Draft/PublishedSplit rendering
Phase E: Advanced Widgets¶
- pipeline-funnel, chart-forecast, *chart-stacked-bar *
- Detail-Widgets(entity-header, entity-fields, entity-relations, notes-panel, files-panel)
- team leaderboard, calendar-mini, kpi-gauge, **kpi-group * *
Phase F: Polish¶
- Responsive Designer(Viewport-Toggle, Breakpoint-specific Spans)
- Undo/Redo(Command stack)
- Page Templates(Galerie, Import/Export)
- Theme Presets(10 Themes)
- Seitenfilter(Global filters affect widgets)
- User-Praeferenzen
11. Technical decisions¶
| Decision | Choice | Mining |
|---|---|---|
| Designer-Ansatz | In-Page Overlay (no iframe) | Real WYSIWYG, no styling insulation problems |
| Charts | Chart.js 4 (vue-chartjs) | Lightweight, good vue integration, responsive |
| **Drag & Drop * * | HTML5 DnD + @vueuse/core | No extra pack, sufficient for grid layout |
| Grid-CSS | CSS Grid (12-Col, repeat + span) | Nativ, performant, responsive breakpoints |
| Themes | JSON → CSS Custom Properties | No build-Step, immediate live change |
| Auto-Save | Debounced PUT (3s after last modification) | No data loss, no excessive API load |
| Widget-Rendering | Vue<component :is>+ Registry |
Standard batteries, Tree-Shakeable, Lazy-Load available |
| Undo/Redo | Command-Pattern (Array of Snapshots) | Simpel, reliable, no extra pack |
| Config UI | Car-generated from JSON Schema | Unique Config panel for all widgets |
12. Delimitation¶
- Kein Website-Builder, The designer is for CRM pages (Dashboards, Detail-Views, Reports), NOT for public websites. There are XyNaP.cms.
- Kein Code-Editor— All visual, no HTML/CSS/JS access for end users.
- No custom widgets (first) — Only included widgets. Plugin system for later planned.
- Kein Pixel-Perfect— 12 column grid with snap, no free positioning (squarespace approach, not Figma).
- Kein Echtzeit-Collaboration, A user edits a page simultaneously. Multi-user spaeter via Locking.