feat(docs): update LemonSpace manifest and PRD for v2.0 release
- Updated version from v1.5 to v2.0 in both the LemonSpace Manifest and PRD documents. - Expanded Phase 1 scope to include video and asset nodes, and integrated non-destructive image editing capabilities. - Enhanced node taxonomy to reflect 6 categories with 27 node types. - Added details on offline sync features and optimistic updates in the documentation. - Improved clarity and structure of the product vision and problem statement sections.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# 🍋 LemonSpace — Produkt-Manifest
|
||||
|
||||
**v1.5 — April 2026**
|
||||
**v2.0 — April 2026**
|
||||
|
||||
*Self-Hosted, Source-Available Creative Workspace*
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
## 1. Vision
|
||||
|
||||
LemonSpace ist eine self-hosted, source-available Alternative zu Freepik Spaces. Eine visuelle Arbeitsfläche, auf der kreative Teams aus wenigen Input-Assets schnell kampagnenfähige Bildvarianten erzeugen — mit KI-gestützter Generierung, durchdachter Latenz-UX und voller Kontrolle über ihre Daten.
|
||||
LemonSpace ist eine self-hosted, source-available Alternative zu Freepik Spaces. Eine visuelle Arbeitsfläche, auf der kreative Teams aus wenigen Input-Assets schnell kampagnenfähige Bildvarianten erzeugen — mit KI-gestützter Generierung, non-destruktiver Bildbearbeitung, durchdachter Latenz-UX und voller Kontrolle über ihre Daten.
|
||||
|
||||
Das Produkt positioniert sich nicht als generisches „AI Creative Workspace", sondern löst ein spezifisches Problem: **Vom Rohbild zur fertigen Kampagnenvariante in Minuten statt Stunden** — auf eigener Infrastruktur oder als gehosteter Service.
|
||||
|
||||
@@ -44,40 +44,50 @@ Freepik Spaces zeigt, dass KI-gestützte Canvas-Workflows funktionieren. Aber:
|
||||
|
||||
Phase 1 löst genau einen End-to-End-Job so gut, dass Nutzer wiederkommen oder zahlen:
|
||||
|
||||
> **Upload Bilder → Prompt / Brief → Bildvarianten generieren → Vergleichen → Export**
|
||||
> **Upload Bilder → Prompt / Brief → Bildvarianten generieren → Bearbeiten (Adjustments) → Vergleichen → Export**
|
||||
>
|
||||
> *Alles, was diesen Flow nicht direkt besser macht, ist erstmal verdächtig.*
|
||||
|
||||
### Konkret bedeutet das für Phase 1
|
||||
|
||||
1. Nutzer lädt 1–5 Produktbilder auf den Canvas (Bild-Node)
|
||||
2. Schreibt einen Prompt oder Brief direkt am Canvas (Prompt-Node — jetzt Phase 1)
|
||||
2. Schreibt einen Prompt oder Brief direkt am Canvas (Prompt-Node)
|
||||
3. Generiert 4–8 Bildvarianten per KI (KI-Bild-Nodes)
|
||||
4. Vergleicht Ergebnisse nebeneinander (Compare-Node — jetzt Phase 1)
|
||||
5. Exportiert fertige Varianten als PNG oder ZIP (Export — jetzt Phase 1)
|
||||
4. Wendet non-destruktive Bildbearbeitung an (Kurven, Farbe, Licht, Detail)
|
||||
5. Vergleicht Ergebnisse nebeneinander (Compare-Node)
|
||||
6. Exportiert fertige Varianten als PNG (Export)
|
||||
|
||||
> **Inkonsistenzen aus v1.0 behoben:** Prompt-Node und Compare-Node sind in Phase 1 vorgezogen, weil sie für den Kern-Job essenziell sind. Export (PNG/ZIP) ist ebenfalls Phase 1 — ohne Export gibt es kein „Job done".
|
||||
> **Phase-1-Umfang erweitert (v2.0):** Video- und Asset-Nodes wurden vorgezogen, Bildbearbeitungs-Nodes (Kurven, Farbe, Licht, Detail, Render) mit vollständiger WebGL-Pipeline implementiert. Der MVP-Job umfasst jetzt auch die non-destruktive Bildbearbeitung als integralen Bestandteil.
|
||||
|
||||
---
|
||||
|
||||
## 5. Node-System — Phase 1
|
||||
|
||||
Nur die Nodes, die den MVP-Job ermöglichen. Die vollständige Node-Taxonomie (5 Kategorien, 25+ Node-Typen) wird in einem separaten **Node Spec Doc** dokumentiert.
|
||||
15 Node-Typen sind in Phase 1 implementiert. Die vollständige Node-Taxonomie (6 Kategorien, 27 Node-Typen) wird im PRD dokumentiert.
|
||||
|
||||
| Node | Kategorie | Rolle im MVP-Job |
|
||||
|------|-----------|------------------|
|
||||
| Bild | Quelle | Upload eigener Bilder (PNG, JPG, WebP) oder Einbindung per URL |
|
||||
| Text | Quelle | Freitextfeld für Copy, Brief, Beschreibungen — semantisch kein Prompt |
|
||||
| Prompt | Quelle | Dedizierter Node für Modellinstruktionen. Verbindet sich mit KI-Nodes |
|
||||
| KI-Bild | KI-Ausgabe | Output eines Bildgenerierungs-Calls. Speichert Prompt, Modell, Parameter |
|
||||
| Gruppe | Layout | Container für Nodes. Collapse/Expand, benannte Scopes |
|
||||
| Frame | Layout | Artboard mit definierter Auflösung. Export-Boundary für PNG/ZIP |
|
||||
| Notiz | Layout | Annotation auf dem Canvas. Markdown, kein Datenanschluss |
|
||||
| Compare | Layout | Zwei Bilder nebeneinander mit interaktivem Slider |
|
||||
| Node | Kategorie | Implementiert | Rolle im MVP-Job |
|
||||
|------|-----------|---------------|------------------|
|
||||
| Bild | Quelle | ✅ | Upload eigener Bilder (PNG, JPG, WebP) oder Einbindung per URL |
|
||||
| Text | Quelle | ✅ | Freitextfeld für Copy, Brief, Beschreibungen |
|
||||
| Video | Quelle | ✅ | Video-Upload und Playback |
|
||||
| Asset | Quelle | ✅ | Stock-Assets aus Asset Browser |
|
||||
| Prompt | KI-Ausgabe | ✅ | Dedizierter Node für Modellinstruktionen |
|
||||
| KI-Bild | KI-Ausgabe | ✅ | Output eines Bildgenerierungs-Calls |
|
||||
| Kurven | Bildbearbeitung | ✅ | Tonwert-Kurven, Levels, Histogram |
|
||||
| Farbe | Bildbearbeitung | ✅ | HSL, Color Balance, Temperature/Tint |
|
||||
| Licht | Bildbearbeitung | ✅ | Brightness, Contrast, Exposure, HDR, Vignette |
|
||||
| Detail | Bildbearbeitung | ✅ | Sharpen, Clarity, Denoise, Grain |
|
||||
| Render | Bildbearbeitung | ✅ | Materialisiert den Adjustment-Stack als neues Bild |
|
||||
| Gruppe | Layout | ✅ | Container für Nodes, Collapse/Expand |
|
||||
| Frame | Layout | ✅ | Artboard mit definierter Auflösung |
|
||||
| Notiz | Layout | ✅ | Annotation auf dem Canvas |
|
||||
| Compare | Layout | ✅ | Zwei Bilder nebeneinander mit Slider |
|
||||
|
||||
### Ausblick: Spätere Phasen
|
||||
|
||||
Transformation (BG entfernen, Upscale, Crop), Steuerung & Flow (Splitter, Loop, Agent, Mixer, Weiche), erweiterte Layout-Nodes (Text-Overlay, Kommentar, Präsentation) und weitere Quell-Nodes (Video, Asset, Farbe/Palette). Details im Node Spec Doc.
|
||||
**Phase 2:** Farbe/Palette (Quelle), KI-Text, KI-Video (KI-Ausgabe), Crop/Resize, BG entfernen, Upscale (Transformation), Splitter, Loop, Agent (Steuerung), Text-Overlay (Layout).
|
||||
|
||||
**Phase 3:** Style Transfer, Gesicht (Transformation), Mixer, Weiche (Steuerung), Kommentar, Präsentation (Layout).
|
||||
|
||||
---
|
||||
|
||||
@@ -103,6 +113,12 @@ Sobald ein Agent seinen Execution-Plan erstellt hat, erscheinen Skeleton-Nodes a
|
||||
|
||||
Opt-in via Browser Notifications API: Bei Tab-Wechsel und fertigem Job erhält der Nutzer eine native Benachrichtigung. Nicht erzwungen.
|
||||
|
||||
### Offline-Sync & Optimistic Updates
|
||||
|
||||
- **IndexedDB-Sync-Queue:** Persistente Queue für Canvas-Mutations mit Retry-Backoff und 24h-TTL
|
||||
- **localStorage-Cache:** Snapshot + leichtgewichtiger Op-Mirror für sofortige UI
|
||||
- **Optimistic IDs:** Temporäre IDs mit `optimistic_`-Prefix, automatisches Remapping bei Server-Bestätigung
|
||||
|
||||
---
|
||||
|
||||
## 7. Bewusste Entscheidungen
|
||||
@@ -113,18 +129,21 @@ Kompakt statt erschöpfend. Details wandern in eigene Architecture Decision Reco
|
||||
|-------|-------------|--------|
|
||||
| Backend | Convex (self-hosted). Bewusster Lock-in für Realtime, Storage, Jobs. Migrations-Pfad: Convex Cloud EU. | ✅ |
|
||||
| Auth | Better Auth + Magic Link (via polar-sh/better-auth plugin) | ✅ |
|
||||
| AI Layer | OpenRouter als primäre AI-Schicht. 9 Image-Modelle, Text/Reasoning via Claude / GPT. | ✅ |
|
||||
| AI Layer | OpenRouter als primäre AI-Schicht. 9 Image-Modelle, Phase 1: nur Gemini 2.5 Flash aktiv. | ✅ |
|
||||
| Self-hosted KI | rembg, Real-ESRGAN, GFPGAN — kostenlos, separate Repos | ✅ |
|
||||
| Payment | Polar.sh (MoR, VAT, Better Auth Plugin @polar-sh/better-auth) | ✅ |
|
||||
| Credits | Reservation + Commit. Credit-Abstraktion (1 Cr = €0,01 OR intern). Markup: 2× Bild, 2,5–3× Agent. | ✅ |
|
||||
| Pricing | 4 Tiers: Free (50 Cr) / Starter €8 (400 Cr) / Pro €59 (3.300 Cr) / Max €119 (6.700 Cr). ≥29% Marge nach LS + USt. Top-Up: fix (€5/€10/€20/€50) + Custom (€5–200, Bonus-Staffel 0–13%). | ✅ |
|
||||
| Pricing | 4 Tiers: Free (50 Cr) / Starter €8 (400 Cr) / Pro €59 (3.300 Cr) / Max €119 (6.700 Cr). ≥29% Marge. Top-Up: fix + Custom. | ✅ |
|
||||
| Lizenz | BSL 1.1, 3J Change Date → Apache 2.0. Private Nutzung frei. | ✅ |
|
||||
| Repo-Strategie | Zwei unabhängige Repos (lemonspace-web + lemonspace-landing). Auth-Cookie-Sharing via `.lemonspace.io`. | ✅ |
|
||||
| Frontend | Next.js 16 + Tailwind v4 + ShadCN | ✅ |
|
||||
| Canvas | @xyflow/react + dnd-kit | ✅ |
|
||||
| Bildbearbeitung | WebGL + GLSL Shader als primäre Engine. WASM-Backend vorbereitet. Client-seitig, credit-frei. | ✅ |
|
||||
| Preset-Persistierung | User-Presets in Convex (`adjustmentPresets`-Tabelle) | ✅ |
|
||||
| Offline Sync | IndexedDB Queue + localStorage Cache + Optimistic Updates | ✅ |
|
||||
| Sidebar | Resizable via react-resizable-panels, Rail-Mode (collapsible) | ✅ |
|
||||
| E-Mail | useSend + Stalwart (Self-Hosted). Für lemonspace.app pragmatisch externer SMTP möglich. | ✅ |
|
||||
| Kollaboration | Phase 3. Phase 1 fokussiert auf Solo-/Kleinteam-Workflows. | ⏳ |
|
||||
| Abuse Prevention | Daily Caps, Concurrency Limits, Freemium-Guardrails — Design TBD. | ⏳ |
|
||||
|
||||
---
|
||||
|
||||
@@ -137,11 +156,11 @@ Fokus heißt Nein sagen. Diese Features sind bewusst ausgeklammert, nicht verges
|
||||
| Echtzeit-Kollaboration | Kein Kernbedürfnis des primären ICP in Phase 1. Solo-/Kleinteam reicht. |
|
||||
| Agent Nodes | Zu komplex für MVP. Erst bauen, wenn der Basis-Job validiert ist. |
|
||||
| Video-Generierung | Anderer Job, andere Kosten, anderer ICP. |
|
||||
| Freepik Asset Browser | Nice-to-have, nicht Kern-Job. |
|
||||
| Style Transfer / GFPGAN | Transformation-Nodes kommen in Phase 2–3. |
|
||||
| Team-Features | Workspaces, Rollen, Rechte, Seat-Management — erst wenn Business-Tier validiert. |
|
||||
| docker-compose.yml | Self-Hosting dokumentieren, aber nicht den Hosted-MVP verzögern. |
|
||||
| E2E-Testing | Neubewertung bei Skalierung. |
|
||||
| Modellauswahl-UI | Phase 1 nur ein Modell (Gemini 2.5 Flash). Auswahl-UI folgt in Phase 2. |
|
||||
|
||||
---
|
||||
|
||||
@@ -175,16 +194,14 @@ Ohne messbare Ziele ist jedes PRD Wünsch-dir-was. Diese Metriken entscheiden, o
|
||||
|
||||
Ein AI-Kreativtool mit Free-Tier und Premium-Modellen braucht von Tag 1 Schutzmaßnahmen. Kein Randthema.
|
||||
|
||||
### Geplante Maßnahmen
|
||||
### Implementierte Maßnahmen
|
||||
|
||||
- Daily Generation Caps pro Tier (Free: 10/Tag, Starter: 50, Pro: 200, Max: 500)
|
||||
- Concurrency Limits: max. 2 parallele Generierungen (Free: 1)
|
||||
- Rate Limiting auf allen API-Endpunkten (Redis-backed)
|
||||
- Premium-Modelle erst ab Starter-Tier (Free nur Budget-Modelle)
|
||||
- Top-Up-Limit pro Monat (verhindert Missbrauch des Selbstkostenpreises)
|
||||
- Account-Verifizierung per E-Mail, optional Telefon bei Abuse-Verdacht
|
||||
|
||||
> **Offene Entscheidung:** Konkretes Design der Caps und Limits wird nach ersten Nutzungsdaten kalibriert. Initiale Werte sind konservativ.
|
||||
- Top-Up-Limit pro Monat
|
||||
- Account-Verifizierung per E-Mail
|
||||
|
||||
---
|
||||
|
||||
@@ -208,15 +225,20 @@ BSL 1.1 mit 3-Jahres-Change-Date zu Apache 2.0. Nach Change Date ist jedes Relea
|
||||
|
||||
Priorisiert nach Abhängigkeiten. Jeder Schritt hat ein klares Artefakt.
|
||||
|
||||
| # | Schritt | Artefakt |
|
||||
|---|---------|----------|
|
||||
| 1 | Repos scaffolden | `lemonspace-web` (Next.js + Convex + BetterAuth) + `lemonspace-landing` (Next.js) |
|
||||
| 2 | Convex Schema entwerfen | Schema-Datei mit Node-Typen + Credit-System |
|
||||
| 3 | Basis-Canvas mit @xyflow/react | Funktionierender Canvas mit Bild- und Prompt-Nodes |
|
||||
| 4 | OpenRouter-Prototyp | Image Gen (Gemini 2.5 Flash) funktioniert im Canvas |
|
||||
| 5 | Compare + Export | PNG/ZIP-Export aus Frame-Nodes |
|
||||
| 6 | Better Auth + Polar + Credit-System | Login, Polar Checkout via @polar-sh/better-auth, Balance-Tracking, Reservation+Commit |
|
||||
| 7 | Polar Webhook-Handling | Subscription-Events, automatische Credit-Zuweisung |
|
||||
| # | Schritt | Artefakt | Status |
|
||||
|---|---------|----------|--------|
|
||||
| 1 | Repos scaffolden | `lemonspace-web` + `lemonspace-landing` | ✅ |
|
||||
| 2 | Convex Schema entwerfen | Schema-Datei mit Node-Typen + Credit-System | ✅ |
|
||||
| 3 | Basis-Canvas mit @xyflow/react | Funktionierender Canvas mit Bild- und Prompt-Nodes | ✅ |
|
||||
| 4 | OpenRouter-Prototyp | Image Gen (Gemini 2.5 Flash) funktioniert im Canvas | ✅ |
|
||||
| 5 | Compare + Export | PNG-Export aus Frame-Nodes | ✅ |
|
||||
| 6 | Better Auth + Polar + Credit-System | Login, Checkout, Balance-Tracking, Reservation+Commit | ✅ |
|
||||
| 7 | Polar Webhook-Handling | Subscription-Events, automatische Credit-Zuweisung | ✅ |
|
||||
| 8 | WebGL Image Pipeline | Adjustment-Nodes mit GLSL-Shadern | ✅ |
|
||||
| 9 | Vollständige OpenRouter Integration | Alle 9 Modelle + Modellauswahl-UI | ☐ |
|
||||
| 10 | Agent Node | Analyse, Clarification, Execution, Output | ☐ |
|
||||
| 11 | Self-hosted KI-Services | rembg, Real-ESRGAN, GFPGAN | ☐ |
|
||||
| 12 | docker-compose.yml + Setup-README | Self-Hosting-Anleitung | ☐ |
|
||||
|
||||
---
|
||||
|
||||
@@ -226,12 +248,13 @@ Folgende Themen werden in eigenen Dokumenten vertieft. Das Manifest bleibt schla
|
||||
|
||||
| Dokument | Inhalt |
|
||||
|----------|--------|
|
||||
| PRD | Vollständige Node-Taxonomie, Tech Stack, Datenmodell, Pricing-Details, Phasen-Plan |
|
||||
| System Design Doc | Tech Stack mit Versionen, Zwei-Repo-Strategie, Infra-Details, Convex-Architektur, Redis, Cloudflare |
|
||||
| Node Spec Doc | Vollständige Node-Taxonomie (5 Kategorien, 25+ Typen), Datenmodell pro Node-Typ |
|
||||
| Credit & Pricing Doc | Detaillierte Pricing-Tabellen, Credit-Abstraktion, Tier-Kalkulation (nach LS + USt), Top-Up-System (fix + Custom mit Bonus-Staffel), Reservation+Commit-Flow, Agent Partial Failure |
|
||||
| Credit & Pricing Doc | Detaillierte Pricing-Tabellen, Credit-Abstraktion, Tier-Kalkulation, Top-Up-System, Reservation+Commit-Flow |
|
||||
| Self-Hosting Guide | docker-compose.yml, .env.example, Setup-README, Coolify-Anleitung |
|
||||
| ADR-Sammlung | Architecture Decision Records für Convex, OpenRouter, BSL 1.1, useSend, etc. |
|
||||
| ADR-Sammlung | Architecture Decision Records für Convex, OpenRouter, BSL 1.1, WebGL, etc. |
|
||||
| CLAUDE.md (pro Ordner) | Implementierungsdokumentation, synchronisiert mit Codebase |
|
||||
|
||||
---
|
||||
|
||||
*LemonSpace Manifest v1.5 — April 2026*
|
||||
*LemonSpace Manifest v2.0 — April 2026*
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
| Version | Status | Datum | Projekt |
|
||||
|---------|--------|-------|---------|
|
||||
| v1.5 | Draft | April 2026 | lemonspace.app |
|
||||
| v2.0 | Draft | April 2026 | lemonspace.app |
|
||||
|
||||
---
|
||||
|
||||
@@ -24,8 +24,9 @@
|
||||
| v1.1 | Monorepo verworfen → Zwei unabhängige Repos (lemonspace-web + lemonspace-landing), Auth-Cookie-Sharing via .lemonspace.io |
|
||||
| v1.2 | Pricing überarbeitet: Credit-Abstraktion (1 Cr = €0,01 intern), Tiers €8/€59/€119 (Business→Max), Top-Up-System (fix + Custom mit Bonus-Staffel), Marge nach LS-Gebühr + USt validiert |
|
||||
| v1.3 | Payment: Lemon Squeezy → Polar.sh (niedrigere Gebühren, Better Auth Plugin, Open Source). Gebührenmodell angepasst: 4% + $0,40 + 1,5% intl. + 0,5% Subscription |
|
||||
| v1.4 | Bildbearbeitung: Neue Kategorie 4 „Bildbearbeitung" mit non-destruktivem Adjustment-Stack (zwischen Transformation und Steuerung). 4 Adjustment-Nodes (Kurven, Farbe, Licht, Detail) + Render-Node. Alle Operationen credit-frei (client-seitig via Canvas API / WebGL). Steuerung → Kat. 5, Canvas & Layout → Kat. 6. Phase 2.
|
||||
| v1.4 | Bildbearbeitung: Neue Kategorie 4 „Bildbearbeitung" mit non-destruktivem Adjustment-Stack (zwischen Transformation und Steuerung). 4 Adjustment-Nodes (Kurven, Farbe, Licht, Detail) + Render-Node. Alle Operationen credit-frei (client-seitig via Canvas API / WebGL). Steuerung → Kat. 5, Canvas & Layout → Kat. 6. Phase 2. |
|
||||
| v1.5 | Stage 3 Offline Sync: Local-First Canvas mit IndexedDB Queue, Optimistic Updates, ID-Remapping. Magic Link Auth via Better Auth Plugin. react-resizable-panels für Sidebar Resizing. Canvas Modularisierung, Dashboard Dialoge, Auth Race-Härtung.|
|
||||
| v2.0 | **Phase-1-Umfang erweitert:** Video- und Asset-Nodes vorgezogen (Phase 2→1). Bildbearbeitungs-Nodes (Kurven, Farbe, Licht, Detail, Render) vorgezogen (Phase 2→1). Vollständige WebGL-basierte Image-Pipeline implementiert (`lib/image-pipeline/`). Node-Taxonomie hat 6 Kategorien mit 27 Node-Typen. Phase-1-Status-Tabelle aktualisiert. |
|
||||
|
||||
---
|
||||
|
||||
@@ -37,7 +38,7 @@ LemonSpace ist eine self-hosted, source-available Alternative zu Freepik Spaces
|
||||
|
||||
## 2. Problemstellung
|
||||
|
||||
Freepik Spaces ist ein leistungsstarkes Tool für KI-gestützte kreative Workflows, aber:
|
||||
Freepik Spaces ist ein leiststarkes Tool für KI-gestützte kreative Workflows, aber:
|
||||
|
||||
- Proprietäres SaaS-Produkt ohne Self-Hosting-Option
|
||||
- Nutzer abhängig von Freepiks Pricing und Verfügbarkeit
|
||||
@@ -65,50 +66,91 @@ Freepik Spaces ist ein leistungsstarkes Tool für KI-gestützte kreative Workflo
|
||||
- Nodes als wiederverwendbare kreative Bausteine
|
||||
- Drag & Drop von Assets, KI-Outputs und Mediendateien
|
||||
- Gruppierung und Layering von Canvas-Elementen
|
||||
- Resizable Sidebar mit Rail-Mode (collapsible)
|
||||
- Offline-fähige Sync-Queue (IndexedDB + localStorage)
|
||||
- Optimistic Updates mit ID-Remapping
|
||||
|
||||
### 4.2 Node-System
|
||||
|
||||
Das Canvas-System basiert auf einem erweiterbaren Node-Modell. Nodes sind typisierte Bausteine, die untereinander verbunden werden und Daten weitergeben. Es gibt sechs Kategorien.
|
||||
Das Canvas-System basiert auf einem erweiterbaren Node-Modell. Nodes sind typisierte Bausteine, die untereinander verbunden werden und Daten weitergeben. Es gibt **sechs Kategorien** mit insgesamt **27 Node-Typen**.
|
||||
|
||||
> **Single Source of Truth:** Die Node-Taxonomie wird zentral in `lib/canvas-node-types.ts` (Typen), `lib/canvas-node-catalog.ts` (Katalog) und `components/canvas/node-types.ts` (React-Flow-Registrierung) verwaltet. Der Katalog bestimmt automatisch den `implemented`-Status basierend auf vorhandenen React-Flow-Komponenten.
|
||||
|
||||
#### Kategorie 1: Quelle
|
||||
|
||||
Quelle-Nodes bringen Inhalte in den Canvas. Sie haben keine eingehenden Verbindungen, nur ausgehende.
|
||||
Quelle-Nodes bringen Inhalte in den Canvas.
|
||||
|
||||
| Node | Beschreibung | Phase |
|
||||
|------|--------------|-------|
|
||||
| Bild | Upload eigener Bilder (PNG, JPG, WebP) oder Einbindung per URL. Basis-Asset für alle weiteren Operationen. | 1 |
|
||||
| Text | Freitextfeld mit Markdown-Support. Enthält Inhalte (Copy, Brief, Beschreibung) — semantisch verschieden vom Prompt-Node. | 1 |
|
||||
| Prompt | Dedizierter Node für Modellinstruktionen. Verbindet sich ausschließlich mit KI-Nodes. | 2 |
|
||||
| Farbe / Palette | Definiert Farben oder Farbpaletten als Style-Referenz. Kann an KI-Nodes oder Style-Transfer übergeben werden. | 2 |
|
||||
| Video | Upload von Videodateien oder Einbindung per Link. Darstellung als Thumbnail-Node, Playback im Panel. | 2 |
|
||||
| Asset | Freepik Stock-Assets (Fotos, Vektoren, Icons), direkt aus dem Asset Browser auf den Canvas gezogen. | 2 |
|
||||
| Node | Beschreibung | Phase | Implementiert |
|
||||
|------|--------------|-------|---------------|
|
||||
| Bild | Upload eigener Bilder (PNG, JPG, WebP) oder Einbindung per URL. Basis-Asset für alle weiteren Operationen. | 1 | ✅ |
|
||||
| Text | Freitextfeld mit Markdown-Support. Enthält Inhalte (Copy, Brief, Beschreibung) — semantisch verschieden vom Prompt-Node. | 1 | ✅ |
|
||||
| Video | Upload von Videodateien oder Einbindung per Link. Darstellung als Thumbnail-Node, Playback im Panel. | 1 | ✅ |
|
||||
| Asset | Stock-Assets (Fotos, Vektoren, Icons), direkt aus dem Asset Browser auf den Canvas gezogen. | 1 | ✅ |
|
||||
| Farbe / Palette | Definiert Farben oder Farbpaletten als Style-Referenz. Kann an KI-Nodes oder Style-Transfer übergeben werden. | 2 | ☐ |
|
||||
| Prompt | Dedizierter Node für Modellinstruktionen. Verbindet sich ausschließlich mit KI-Nodes. Kategorie: KI-Ausgabe. | 1 | ✅ |
|
||||
|
||||
#### Kategorie 2: KI-Ausgabe
|
||||
|
||||
KI-Ausgabe-Nodes sind das Ergebnis einer Modell-Operation. Sie werden vom System erzeugt, nicht vom Nutzer angelegt.
|
||||
|
||||
| Node | Beschreibung | Phase |
|
||||
|------|--------------|-------|
|
||||
| KI-Bild | Output eines Bildgenerierungs-Calls. Speichert Prompt, verwendetes Modell und Generierungsparameter. | 1 |
|
||||
| KI-Text | Output eines Text/Reasoning-Calls. Enthält generierten Copy, Captions, strukturierte Texte. | 2 |
|
||||
| KI-Video | Output eines Videogenerierungs-Calls. Keyframe-basierte Generierung aus Bild-Input möglich. | 2 |
|
||||
| Agent-Ausgabe | Bundle-Output eines Agent Nodes. Kann mehrere typisierte Sub-Outputs enthalten. | 3 |
|
||||
| Node | Beschreibung | Phase | Implementiert |
|
||||
|------|--------------|-------|---------------|
|
||||
| KI-Bild (`ai-image`) | Output eines Bildgenerierungs-Calls. Speichert Prompt, verwendetes Modell und Generierungsparameter. | 1 | ✅ |
|
||||
| KI-Text | Output eines Text/Reasoning-Calls. Enthält generierten Copy, Captions, strukturierte Texte. | 2 | ☐ |
|
||||
| KI-Video | Output eines Videogenerierungs-Calls. Keyframe-basierte Generierung aus Bild-Input möglich. | 2 | ☐ |
|
||||
| Agent-Ausgabe | Bundle-Output eines Agent Nodes. Kann mehrere typisierte Sub-Outputs enthalten. | 3 | ☐ |
|
||||
|
||||
#### Kategorie 3: Transformation
|
||||
|
||||
| Node | Beschreibung | Phase |
|
||||
|------|--------------|-------|
|
||||
| Crop / Resize | Freie Bildausschnitt-Auswahl direkt auf dem Canvas, mit Aspect-Ratio-Lock. | 2 |
|
||||
| BG entfernen | Hintergrundentfernung via rembg. Output ist ein freigestelltes Bild. Batch-Modus möglich. | 2 |
|
||||
| Upscale | Hochskalierung via Real-ESRGAN. Unterstützt Faktoren 2×, 4×, 8×. | 2 |
|
||||
| Style Transfer | Überträgt visuellen Stil eines Referenzbildes auf einen anderen Input. | 3 |
|
||||
| Gesicht | Face Restoration via GFPGAN. Verbessert Gesichtsdetails in generierten oder degradierten Bildern. | 3 |
|
||||
| Node | Beschreibung | Phase | Implementiert |
|
||||
|------|--------------|-------|---------------|
|
||||
| Crop / Resize | Freie Bildausschnitt-Auswahl direkt auf dem Canvas, mit Aspect-Ratio-Lock. | 2 | ☐ |
|
||||
| BG entfernen | Hintergrundentfernung via rembg. Output ist ein freigestelltes Bild. Batch-Modus möglich. | 2 | ☐ |
|
||||
| Upscale | Hochskalierung via Real-ESRGAN. Unterstützt Faktoren 2×, 4×, 8×. | 2 | ☐ |
|
||||
| Style Transfer | Überträgt visuellen Stil eines Referenzbildes auf einen anderen Input. | 3 | ☐ |
|
||||
| Gesicht | Face Restoration via GFPGAN. Verbessert Gesichtsdetails in generierten oder degradierten Bildern. | 3 | ☐ |
|
||||
|
||||
#### Kategorie 4: Bildbearbeitung
|
||||
|
||||
Bildbearbeitungs-Nodes arbeiten **non-destruktiv**. Sie verändern das Originalbild nicht, sondern definieren Adjustments, die als Stack auf das Eingangsbild angewendet werden. Erst der Render-Node materialisiert das Ergebnis als neues Bild. Adjustments sind jederzeit änder-, umsortier- und löschbar — wie Adjustment Layers in Photoshop.
|
||||
Bildbearbeitungs-Nodes arbeiten **non-destruktiv**. Sie verändern das Originalbild nicht, sondern definieren Adjustments, die als Stack auf das Eingangsbild angewendet werden. Erst der Render-Node materialisiert das Ergebnis als neues Bild.
|
||||
|
||||
**Architektur-Prinzip: Adjustment-Stack**
|
||||
**Architektur: WebGL-basierte Image-Pipeline (`lib/image-pipeline/`)**
|
||||
|
||||
Die Bildbearbeitung nutzt eine vollständige WebGL-Pipeline für hardwarebeschleunigte Bildverarbeitung direkt im Browser:
|
||||
|
||||
```
|
||||
lib/image-pipeline/
|
||||
├── adjustment-types.ts ← Typen und Default-Werte für alle Adjustments
|
||||
├── contracts.ts ← Pipeline-Schnittstellen
|
||||
├── render-core.ts ← Kern-Rendering-Logik
|
||||
├── render-types.ts ← Render-Typen
|
||||
├── render-size.ts ← Größenberechnung
|
||||
├── source-loader.ts ← Bildquellen-Lader
|
||||
├── preview-renderer.ts ← Echtzeit-Vorschau
|
||||
├── histogram.ts ← Histogram-Berechnung
|
||||
├── histogram-plot.ts ← Histogram-Visualisierung
|
||||
├── presets.ts ← Built-in und User-Presets
|
||||
├── bridge.ts ← Worker-Bridge
|
||||
├── worker-client.ts ← Web-Worker-Client
|
||||
├── image-pipeline.worker.ts ← Web-Worker für Hintergrundverarbeitung
|
||||
└── backend/
|
||||
├── backend-router.ts ← Backend-Auswahl (WebGL/WASM)
|
||||
├── backend-types.ts ← Backend-Typen
|
||||
├── capabilities.ts ← Feature-Erkennung
|
||||
├── feature-flags.ts ← Backend-Flags
|
||||
├── webgl/
|
||||
│ ├── webgl-backend.ts ← WebGL-Renderer
|
||||
│ └── shaders/ ← GLSL-Shader
|
||||
│ ├── curves.frag.glsl
|
||||
│ ├── color-adjust.frag.glsl
|
||||
│ ├── light-adjust.frag.glsl
|
||||
│ └── detail-adjust.frag.glsl
|
||||
└── wasm/
|
||||
├── wasm-loader.ts ← WASM-Loader (zukünftig)
|
||||
└── wasm-backend.ts ← WASM-Backend (zukünftig)
|
||||
```
|
||||
|
||||
**Adjustment-Stack:**
|
||||
|
||||
```
|
||||
Bild-Node (Original)
|
||||
@@ -118,43 +160,39 @@ Bild-Node (Original)
|
||||
→ Render-Node → Neues Bild (materialisiert)
|
||||
```
|
||||
|
||||
Jeder Adjustment-Node hat einen Eingang (Bild oder vorheriger Adjustment) und einen Ausgang. Die Kette ist beliebig lang und umsortierbar. Das Originalbild bleibt unverändert — identischer Input kann mit verschiedenen Adjustment-Stacks zu verschiedenen Varianten führen (Branching).
|
||||
| Node | Beschreibung | Phase | Implementiert |
|
||||
|------|--------------|-------|---------------|
|
||||
| Kurven | Tonwert-Kurven (RGB + Einzelkanäle). Kontrollpunkte per Drag auf der Kurve. Presets: Kontrast, Aufhellen, Abdunkeln, Film-Look, Cross-Process. | 1 | ✅ |
|
||||
| Farbe | HSL-Regler (Hue, Saturation, Luminance — global + pro Farbbereich). Color Balance. Temperature/Tint. Presets. | 1 | ✅ |
|
||||
| Licht | Brightness, Contrast, Exposure, Highlights, Shadows, Whites, Blacks. HDR-Tone-Mapping. Vignette. Presets. | 1 | ✅ |
|
||||
| Detail | Unscharf maskieren (Amount, Radius, Threshold). Clarity / Structure. Denoise. Grain. Presets. | 1 | ✅ |
|
||||
| Render | Materialisierer: Wendet den gesamten Adjustment-Stack an und erzeugt ein neues Bild (in Convex Storage). Unterstützt Ausgabe-Auflösung und Format. | 1 | ✅ |
|
||||
|
||||
**Live-Vorschau:** Jeder Adjustment-Node zeigt eine Echtzeit-Vorschau des Bildes mit allen bisherigen Adjustments. Die Verarbeitung läuft client-seitig (Canvas 2D API / WebGL) — kein Server-Roundtrip, keine Credits.
|
||||
> **Credits:** Alle Adjustment-Nodes sind **credit-frei** — die Verarbeitung läuft vollständig im Browser (WebGL). Nur der Render-Node erzeugt serverseitig ein finales Bild (ebenfalls credit-frei).
|
||||
|
||||
| Node | Beschreibung | Phase |
|
||||
|------|--------------|-------|
|
||||
| Kurven | Tonwert-Kurven (RGB + Einzelkanäle). Kontrollpunkte per Drag auf der Kurve. Presets: Kontrast, Aufhellen, Abdunkeln, Film-Look, Cross-Process. Zusätzlich: Levels (Schwarz-/Weißpunkt, Gamma) und Histogram-Anzeige. | 2 |
|
||||
| Farbe | HSL-Regler (Hue, Saturation, Luminance — global + pro Farbbereich). Color Balance (Schatten/Mitten/Lichter). Selective Color. Temperature/Tint. Vibrance vs. Saturation. Presets: Warm, Cool, Vintage, Desaturate. | 2 |
|
||||
| Licht | Brightness, Contrast, Exposure, Highlights, Shadows, Whites, Blacks. HDR-Tone-Mapping (local contrast). Vignette (Stärke, Größe, Rundheit). Presets: HDR, Low Key, High Key, Flat. | 2 |
|
||||
| Detail | Unscharf maskieren (Amount, Radius, Threshold). Clarity / Structure (Midtone Contrast). Denoise (Luminance, Color). Grain (Amount, Size). Presets: Schärfen für Web, Schärfen für Print, Soft Glow, Film Grain. | 2 |
|
||||
| Render | Materialisierer: Wendet den gesamten Adjustment-Stack an und erzeugt ein neues Bild (in Convex Storage). Unterstützt Ausgabe-Auflösung (Original, 2×, Custom) und Format (PNG, JPG mit Qualitätsstufe, WebP). Trigger: manueller „Render"-Button am Node. | 2 |
|
||||
|
||||
> **Credits:** Alle Adjustment-Nodes (Kurven, Farbe, Licht, Detail) sind **credit-frei** — die Verarbeitung läuft vollständig im Browser. Nur der Render-Node erzeugt serverseitig ein finales Bild in Convex Storage (ebenfalls credit-frei, da keine KI-API involviert).
|
||||
|
||||
> **Technische Umsetzung:** Phase-2-Entscheidung zwischen Canvas 2D API (breite Kompatibilität, einfacher) und WebGL/WebGPU (performanter bei großen Bildern, Shader-Pipeline). Für den MVP reicht Canvas 2D; WebGL wird evaluiert wenn Performance-Grenzen erreicht werden.
|
||||
> **Technische Umsetzung:** Die Entscheidung für WebGL als primäre Rendering-Engine ist getroffen. GLSL-Shader für alle vier Adjustment-Typen sind implementiert. Ein WASM-Backend ist als Alternative vorbereitet (`wasm-backend.ts`), aber noch nicht aktiv.
|
||||
|
||||
#### Kategorie 5: Steuerung & Flow
|
||||
|
||||
| Node | Semantik | Beschreibung | Phase |
|
||||
|------|----------|--------------|-------|
|
||||
| Splitter | 1 → N | Verteilt 1 Input auf N identische oder abgeleitete Outputs. Ohne Bedingung. | 2 |
|
||||
| Loop | Liste → N | Iteriert über eine Liste von Inputs und führt dieselbe verknüpfte Operation für jeden Eintrag aus. | 2 |
|
||||
| Agent | N → Plan → N | LLM-Orchestrator. Analysiert Inputs, plant strukturierten Ausführungsplan, delegiert Operationen. | 2 |
|
||||
| Mixer / Merge | N → 1 | Kombiniert N Inputs zu 1 Output durch Überblendung, Komposition oder Selektion. | 3 |
|
||||
| Weiche | 1 → Pfad A/B/... | Bedingter Router. Leitet den Input anhand einer definierbaren Bedingung auf einen von mehreren Ausgangspfaden. | 3 |
|
||||
| Node | Semantik | Beschreibung | Phase | Implementiert |
|
||||
|------|----------|--------------|-------|---------------|
|
||||
| Splitter | 1 → N | Verteilt 1 Input auf N identische oder abgeleitete Outputs. | 2 | ☐ |
|
||||
| Loop | Liste → N | Iteriert über eine Liste von Inputs und führt dieselbe verknüpfte Operation für jeden Eintrag aus. | 2 | ☐ |
|
||||
| Agent | N → Plan → N | LLM-Orchestrator. Analysiert Inputs, plant strukturierten Ausführungsplan, delegiert Operationen. | 2 | ☐ |
|
||||
| Mixer / Merge | N → 1 | Kombiniert N Inputs zu 1 Output durch Überblendung, Komposition oder Selektion. | 3 | ☐ |
|
||||
| Weiche | 1 → Pfad A/B/... | Bedingter Router. Leitet den Input anhand einer definierbaren Bedingung auf einen von mehreren Ausgangspfaden. | 3 | ☐ |
|
||||
|
||||
#### Kategorie 6: Canvas & Layout
|
||||
|
||||
| Node | Beschreibung | Phase |
|
||||
|------|--------------|-------|
|
||||
| Gruppe | Container für andere Nodes. Unterstützt Collapse/Expand und benannte Scopes. | 1 |
|
||||
| Frame | Artboard mit definierter Auflösung. Dient als Export-Boundary. | 1 |
|
||||
| Notiz | Annotation auf dem Canvas. Markdown-Support, kein Datenanschluss. | 1 |
|
||||
| Text-Overlay | Editierbarer Text-Layer über Bild- oder Video-Nodes innerhalb eines Frames. Verbraucht keine Credits. | 2 |
|
||||
| Compare | Stellt zwei Bilder nebeneinander mit interaktivem Slider dar. | 2 |
|
||||
| Kommentar | Kollaborations-Node für Reviews. Unterstützt Threads, @mentions und Resolve-Status. | 3 |
|
||||
| Präsentation | Definiert Canvas-Bereiche als geordnete Slideshow. Export als PDF möglich. | 3 |
|
||||
| Node | Beschreibung | Phase | Implementiert |
|
||||
|------|--------------|-------|---------------|
|
||||
| Gruppe | Container für andere Nodes. Unterstützt Collapse/Expand und benannte Scopes. | 1 | ✅ |
|
||||
| Frame | Artboard mit definierter Auflösung. Dient als Export-Boundary. | 1 | ✅ |
|
||||
| Notiz | Annotation auf dem Canvas. Markdown-Support, kein Datenanschluss. | 1 | ✅ |
|
||||
| Compare | Stellt zwei Bilder nebeneinander mit interaktivem Slider dar. | 1 | ✅ |
|
||||
| Text-Overlay | Editierbarer Text-Layer über Bild- oder Video-Nodes innerhalb eines Frames. | 2 | ☐ |
|
||||
| Kommentar | Kollaborations-Node für Reviews. Unterstützt Threads, @mentions und Resolve-Status. | 3 | ☐ |
|
||||
| Präsentation | Definiert Canvas-Bereiche als geordnete Slideshow. Export als PDF möglich. | 3 | ☐ |
|
||||
|
||||
### 4.3 Agent Nodes
|
||||
|
||||
@@ -197,6 +235,8 @@ Agent Nodes sind ein spezieller Node-Typ auf dem Canvas. Sie fungieren als Smart
|
||||
| Error Tracking | Sentry Cloud | Free Tier (5.000 Errors/Monat) |
|
||||
| DNS / DDoS / CDN | Cloudflare | Domain-Routing, DDoS-Schutz, Asset-Caching |
|
||||
| Panel Resizing | react-resizable-panels | ShadCN UI Komponente für Resizable Layouts |
|
||||
| Image Pipeline | WebGL + GLSL Shaders | Hardware-beschleunigte Bildverarbeitung im Browser |
|
||||
| Offline Sync | IndexedDB + localStorage | Canvas-Sync-Queue, Snapshot-Persistenz, Optimistic Updates |
|
||||
| Package Manager | pnpm | Je Repo |
|
||||
|
||||
### Zwei-Repo-Strategie
|
||||
@@ -228,7 +268,7 @@ Convex liefert Realtime-Sync, File Storage und Background Jobs out-of-the-box, o
|
||||
|
||||
> **Risiko (bewusst akzeptiert):** Der gesamte Realtime-, Storage- und Job-Stack ist an Convex gebunden. Eine spätere Migration ist aufwändig. Es wird keine künstliche Abstraktionsschicht eingebaut, da sie den Kernvorteil von Convex aufheben würde.
|
||||
|
||||
Dokumentierter Migrations-Pfad bei Skalierung: Convex Cloud mit EU-Standort. Convex bietet das eigene Migrations-Tooling und kennt das Ökosystem. Self-hosted Convex bleibt die Default-Strategie für Phase 1.
|
||||
Dokumentierter Migrationspfad bei Skalierung: Convex Cloud mit EU-Standort. Convex bietet das eigene Migrations-Tooling und kennt das Ökosystem. Self-hosted Convex bleibt die Default-Strategie für Phase 1.
|
||||
|
||||
---
|
||||
|
||||
@@ -255,6 +295,14 @@ Dokumentierter Migrations-Pfad bei Skalierung: Convex Cloud mit EU-Standort. Con
|
||||
| Gemini 3 Pro Image | google/gemini-3-pro-image-preview | Multi-Image, 4K, bestes Text-Rendering | ~€0,08–0,15 |
|
||||
| GPT-5 Image | openai/gpt-5-image | Instruction Following, Text in Bild | ~€0,10–0,20 |
|
||||
|
||||
### Aktuell aktiviertes Modell (Phase 1)
|
||||
|
||||
| Modell | ID | Credits | Tier-Zugang |
|
||||
|--------|-----|---------|-------------|
|
||||
| Gemini 2.5 Flash Image | google/gemini-2.5-flash-image | 4 Cr | Alle Tiers |
|
||||
|
||||
> Weitere Modelle werden in Phase 2 freigeschaltet (Modellauswahl-UI im Canvas).
|
||||
|
||||
### Self-hosted Services
|
||||
|
||||
| Service | Funktion | Credits |
|
||||
@@ -275,23 +323,27 @@ Dokumentierter Migrations-Pfad bei Skalierung: Convex Cloud mit EU-Standort. Con
|
||||
│ Node-Kategorien: │
|
||||
│ [Quelle] [KI-Ausgabe] [Transformation] │
|
||||
│ [Bildbearbeitung] [Steuerung] [Canvas & Layout] │
|
||||
│ │
|
||||
│ Image Pipeline: │
|
||||
│ WebGL + GLSL Shaders (client-seitig, credit-frei) │
|
||||
│ IndexedDB Sync Queue (offline-fähig) │
|
||||
└───────────────────────┬──────────────────────────────────┘
|
||||
│
|
||||
┌─────────▼─────────┐
|
||||
│ Convex Backend │
|
||||
│ (Self-hosted) │
|
||||
│ - Realtime Sync │
|
||||
│ - File Storage │
|
||||
│ - Auth │
|
||||
│ - Modell-Router │
|
||||
│ - Agent Executor │
|
||||
└──┬────────┬───┬───┘
|
||||
│ │ │
|
||||
┌────────────▼──┐ ┌───▼──────────────┐ ┌──▼──────────┐
|
||||
│ OpenRouter │ │ Self-hosted KI │ │ Freepik API │
|
||||
│ Image Gen + │ │ rembg / ESRGAN │ │ (Assets) │
|
||||
│ Text/Reason │ │ GFPGAN │ └─────────────┘
|
||||
└───────────────┘ └──────────────────┘
|
||||
│ Convex Backend │
|
||||
│ (Self-hosted) │
|
||||
│ - Realtime Sync │
|
||||
│ - File Storage │
|
||||
│ - Auth │
|
||||
│ - Modell-Router │
|
||||
│ - Agent Executor │
|
||||
└──┬────────┬───┬───┘
|
||||
│ │ │
|
||||
┌────────────▼──┐ ┌───▼──────────────┐ ┌──▼──────────┐
|
||||
│ OpenRouter │ │ Self-hosted KI │ │ Freepik API │
|
||||
│ Image Gen + │ │ rembg / ESRGAN │ │ (Assets) │
|
||||
│ Text/Reason │ │ GFPGAN │ └─────────────┘
|
||||
└───────────────┘ └──────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
@@ -310,12 +362,17 @@ Node (Basis)
|
||||
├── type (image | text | prompt | color | video | asset |
|
||||
│ ai-image | ai-text | ai-video | agent-output |
|
||||
│ crop | bg-remove | upscale | style-transfer | face-restore |
|
||||
│ curves | color-adjust | light | detail | render |
|
||||
│ curves | color-adjust | light-adjust | detail-adjust | render |
|
||||
│ splitter | loop | agent | mixer | switch |
|
||||
│ group | frame | note | text-overlay | compare | comment | presentation)
|
||||
│ group | frame | note | compare | text-overlay | comment | presentation)
|
||||
├── position { x, y }
|
||||
├── size { width, height }
|
||||
├── data (je nach Typ)
|
||||
├── status (idle | analyzing | clarifying | executing | done | error)
|
||||
├── statusMessage?
|
||||
├── retryCount?
|
||||
├── parentId?
|
||||
├── zIndex?
|
||||
└── createdAt
|
||||
```
|
||||
|
||||
@@ -335,20 +392,32 @@ CreditTransaction
|
||||
├── amount // positiv = Gutschrift, negativ = Verbrauch (in Credits)
|
||||
├── type // subscription | topup | usage | reservation | refund
|
||||
├── status // committed | reserved | released | failed
|
||||
├── description // z.B. "Bildgenerierung – Gemini 2.5 Flash Image (8 Cr)"
|
||||
├── description // z.B. "Bildgenerierung – Gemini 2.5 Flash Image (4 Cr)"
|
||||
├── nodeId? // Referenz auf den auslösenden Node
|
||||
├── creditCost // Credit-Preis der Operation
|
||||
├── openRouterCost? // tatsächliche OpenRouter-Kosten in € (intern, für Marge-Tracking)
|
||||
├── canvasId? // Zugehöriger Canvas
|
||||
├── openRouterCost? // tatsächliche OpenRouter-Kosten in €
|
||||
├── model? // OpenRouter Model ID
|
||||
└── createdAt
|
||||
|
||||
Subscription
|
||||
├── id, userId
|
||||
├── tier // free | starter | pro | max
|
||||
├── status // active | cancelled | past_due
|
||||
├── tier // free | starter | pro | max | business
|
||||
├── status // active | cancelled | past_due | trialing
|
||||
├── currentPeriodStart / currentPeriodEnd
|
||||
└── polarSubscriptionId?
|
||||
```
|
||||
|
||||
### Adjustment Presets
|
||||
|
||||
```
|
||||
AdjustmentPreset
|
||||
├── id, userId
|
||||
├── name // Benutzerdefinierter Name
|
||||
├── nodeType // curves | color-adjust | light-adjust | detail-adjust
|
||||
├── params // Typ-spezifische Parameter (v.any())
|
||||
└── createdAt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Pricing & Credit-System
|
||||
@@ -397,8 +466,8 @@ Credits = ROUND(API-Kosten × Markup ÷ Kurs). Agent-Calls haben höheren Markup
|
||||
|
||||
| Operation | Modell | API-Kosten | Markup | Credits | Tier-Zugang |
|
||||
|-----------|--------|------------|--------|---------|-------------|
|
||||
| Bildgenerierung (Standard) | Gemini 2.5 Flash Image | ~€0,04 | 2× | 4 Cr | Alle Tiers |
|
||||
| Bildgenerierung (Budget) | FLUX.2 Klein 4B | ~€0,02 | 2× | 4 Cr | Alle Tiers |
|
||||
| Bildgenerierung (Standard) | Gemini 2.5 Flash Image | ~€0,04 | 2× | 8 Cr | Alle Tiers |
|
||||
| Bildgenerierung (Standard+) | Gemini 3.1 Flash Image | ~€0,06 | 2× | 12 Cr | Alle Tiers |
|
||||
| Bildgenerierung (Premium) | GPT-5 Image Mini | ~€0,08 | 2× | 16 Cr | Ab Starter |
|
||||
| Bildgenerierung (Ultra) | GPT-5 Image | ~€0,18 | 2× | 36 Cr | Ab Starter |
|
||||
@@ -410,8 +479,8 @@ Credits = ROUND(API-Kosten × Markup ÷ Kurs). Agent-Calls haben höheren Markup
|
||||
| Upscaling | Real-ESRGAN (self-hosted) | €0 | — | 0 Cr | Alle Tiers |
|
||||
| Face Restoration | GFPGAN (self-hosted) | €0 | — | 0 Cr | Alle Tiers |
|
||||
| Canvas-Operationen | — | €0 | — | 0 Cr | Alle Tiers |
|
||||
| Bildbearbeitung (Kurven, Farbe, Licht, Detail) | Client-seitig | €0 | — | 0 Cr | Alle Tiers |
|
||||
| Render (Adjustment-Stack materialisieren) | Server-seitig (jimp/Canvas) | €0 | — | 0 Cr | Alle Tiers |
|
||||
| Bildbearbeitung (Kurven, Farbe, Licht, Detail) | WebGL (client-seitig) | €0 | — | 0 Cr | Alle Tiers |
|
||||
| Render (Adjustment-Stack materialisieren) | Server-seitig (Canvas API) | €0 | — | 0 Cr | Alle Tiers |
|
||||
| Export (PNG/ZIP) | — | €0 | — | 0 Cr | Alle Tiers |
|
||||
|
||||
### Credit Reservation + Commit
|
||||
@@ -477,44 +546,60 @@ Agent Status: analyzing
|
||||
- Opt-in Browser Notifications API: wenn der Nutzer den Tab verlässt und der Job fertig wird, native Browser-Benachrichtigung
|
||||
- Nicht erzwungen — Nutzer die im Tab bleiben sehen den Node-Status direkt
|
||||
|
||||
### Offline-Sync & Optimistic Updates
|
||||
|
||||
- **IndexedDB-Sync-Queue** (`lib/canvas-op-queue.ts`): Persistente Queue für Canvas-Mutations mit Retry-Backoff und 24h-TTL
|
||||
- **localStorage-Cache** (`lib/canvas-local-persistence.ts`): Snapshot + leichtgewichtiger Op-Mirror für sofortige UI-Pins/Recovery
|
||||
- **Optimistic IDs:** Temporäre Nodes/Edges erhalten `optimistic_`-Prefix, werden durch echte Convex-IDs ersetzt
|
||||
- **ID-Remapping:** Folge-Operationen werden automatisch auf neue IDs remappt
|
||||
|
||||
---
|
||||
|
||||
## 11. Entwicklungsphasen
|
||||
|
||||
### Phase 1 — Foundation (MVP)
|
||||
|
||||
**Nodes:**
|
||||
- Quelle: Bild, Text
|
||||
- KI-Ausgabe: KI-Bild
|
||||
- Canvas & Layout: Gruppe, Frame, Notiz
|
||||
**Nodes (15 implementiert):**
|
||||
- Quelle: Bild ✅, Text ✅, Video ✅, Asset ✅
|
||||
- KI-Ausgabe: Prompt ✅, KI-Bild (`ai-image`) ✅
|
||||
- Bildbearbeitung: Kurven ✅, Farbe ✅, Licht ✅, Detail ✅, Render ✅
|
||||
- Canvas & Layout: Gruppe ✅, Frame ✅, Notiz ✅, Compare ✅
|
||||
|
||||
**Infrastruktur & Features:**
|
||||
|
||||
| Task | Status |
|
||||
|------|--------|
|
||||
| Projektsetup: Next.js 16 + Tailwind v4 + ShadCN | ☐ Offen |
|
||||
| Zwei Repos aufsetzen (`lemonspace-web` für app.lemonspace.io, `lemonspace-landing` für lemonspace.io) | ☐ Offen |
|
||||
| Convex Self-hosted Backend aufsetzen | ☐ Offen |
|
||||
| Basis-Canvas mit @xyflow/react | ☐ Offen |
|
||||
| Drag & Drop von Bildern via dnd-kit | ☐ Offen |
|
||||
| Authentifizierung via Better Auth | ☐ Offen |
|
||||
| OpenRouter Integration (Image Gen, Gemini 2.5 Flash Image) | ☐ Offen |
|
||||
| Credit-System: Balance-Tracking (in Credits), Reservation+Commit, Kosten-Voranzeige | ☐ Offen |
|
||||
| Abo-Verwaltung: Free/Starter/Pro/Max Tiers, monatliche Credit-Zuweisung (50/400/3300/6700) | ☐ Offen |
|
||||
| Polar Integration: Checkout, Webhooks, Credit-Zuweisung | ☐ Offen |
|
||||
| Credit-Nachkauf: Fixe Top-Ups (€5/€10/€20/€50) + Custom (€5–200 mit Bonus-Staffel) | ☐ Offen |
|
||||
| Node-Status-Modell (idle/executing/done/error) direkt am Node | ☐ Offen |
|
||||
| Projektsetup: Next.js 16 + Tailwind v4 + ShadCN | ✅ Erledigt |
|
||||
| Convex Self-hosted Backend | ✅ Erledigt |
|
||||
| Basis-Canvas mit @xyflow/react | ✅ Erledigt |
|
||||
| Drag & Drop von Bildern | ✅ Erledigt |
|
||||
| Authentifizierung via Better Auth + Magic Link | ✅ Erledigt |
|
||||
| OpenRouter Integration (Gemini 2.5 Flash Image) | ✅ Erledigt |
|
||||
| Credit-System: Balance, Reservation+Commit | ✅ Erledigt |
|
||||
| Abo-Verwaltung: Free/Starter/Pro/Max Tiers | ✅ Erledigt |
|
||||
| Polar Integration: Checkout, Webhooks | ✅ Erledigt |
|
||||
| Credit-Nachkauf: Fixe Top-Ups + Custom | ✅ Erledigt |
|
||||
| Node-Status-Modell (idle/executing/done/error) | ✅ Erledigt |
|
||||
| WebGL Image Pipeline (Adjustments) | ✅ Erledigt |
|
||||
| Resizable Sidebar mit Rail-Mode | ✅ Erledigt |
|
||||
| Offline Sync (IndexedDB Queue) | ✅ Erledigt |
|
||||
| Optimistic Updates + ID-Remapping | ✅ Erledigt |
|
||||
| Auth Race-Härtung | ✅ Erledigt |
|
||||
| Canvas Modularisierung | ✅ Erledigt |
|
||||
| Asset Browser (Stock-Fotos, Vektoren) | ✅ Erledigt |
|
||||
| Video Browser | ✅ Erledigt |
|
||||
| Connection Policy (Edge-Validierung) | ✅ Erledigt |
|
||||
| Adjustment Presets (Built-in + User-defined) | ✅ Erledigt |
|
||||
| docker-compose.yml + .env.example + Setup-README | ☐ Offen |
|
||||
|
||||
### Phase 2 — KI-Features
|
||||
|
||||
**Nodes:**
|
||||
- Quelle: Prompt, Farbe / Palette, Video, Asset
|
||||
- Quelle: Farbe / Palette
|
||||
- KI-Ausgabe: KI-Text, KI-Video
|
||||
- Transformation: Crop / Resize, BG entfernen, Upscale
|
||||
- Bildbearbeitung: Kurven, Farbe, Licht, Detail, Render
|
||||
- Steuerung: Splitter, Loop, Agent
|
||||
- Canvas & Layout: Text-Overlay, Compare
|
||||
- Canvas & Layout: Text-Overlay
|
||||
|
||||
**Infrastruktur & Features:**
|
||||
|
||||
@@ -524,19 +609,12 @@ Agent Status: analyzing
|
||||
| Experten-Modus: Modellauswahl-UI im Canvas AI Panel | ☐ Offen |
|
||||
| OpenRouter Text/Reasoning Integration (Claude 3.5 Sonnet) | ☐ Offen |
|
||||
| Agent Node: Analyse, Clarification, Execution, Output | ☐ Offen |
|
||||
| Skeleton-Nodes: Platzierung nach Plan-Erstellung, sequenzielle Befüllung | ☐ Offen |
|
||||
| Skeleton-Nodes: Platzierung nach Plan-Erstellung | ☐ Offen |
|
||||
| Browser Notifications API (opt-in, Tab-Wechsel) | ☐ Offen |
|
||||
| Erster Agent Template: Instagram Curator | ☐ Offen |
|
||||
| Self-hosted KI-Services (rembg, Real-ESRGAN) | ☐ Offen |
|
||||
| Freepik Asset Browser (Stock-Fotos, Vektoren) | ☐ Offen |
|
||||
| Prompt-History und Re-Generation | ☐ Offen |
|
||||
| Bildbearbeitung: Non-destruktiver Adjustment-Stack (Client-seitige Architektur) | ☐ Offen |
|
||||
| Kurven-Node: RGB/Einzelkanal-Kurven, Levels, Histogram | ☐ Offen |
|
||||
| Farbe-Node: HSL, Color Balance, Selective Color, Temperature/Tint | ☐ Offen |
|
||||
| Licht-Node: Brightness, Contrast, Exposure, Highlights/Shadows, HDR, Vignette | ☐ Offen |
|
||||
| Detail-Node: Sharpen, Clarity, Denoise, Grain | ☐ Offen |
|
||||
| Render-Node: Stack-Materialisierung, Auflösungs- und Formatwahl, Convex Storage | ☐ Offen |
|
||||
| Preset-System für Adjustment-Nodes (Built-in + User-defined) | ☐ Offen |
|
||||
| Text-Overlay Node | ☐ Offen |
|
||||
|
||||
### Phase 3 — Kollaboration & Polish
|
||||
|
||||
@@ -564,30 +642,30 @@ Agent Status: analyzing
|
||||
|-------|----------------------|
|
||||
| Authentifizierung | ✅ Better Auth (self-hosted, open-source) |
|
||||
| Tailwind v4 | ✅ v4 ist Standard, keine Migration nötig |
|
||||
| Pricing / Credit-System | ✅ Credit-Abstraktion (1 Cr = €0,01 intern), 4 Tiers (Free/Starter €8/Pro €59/Max €119), Reservation+Commit, Top-Up fix + Custom |
|
||||
| Pricing / Credit-System | ✅ Credit-Abstraktion (1 Cr = €0,01 intern), 4 Tiers, Reservation+Commit, Top-Up |
|
||||
| Payment Provider | ✅ Polar (Merchant of Record, VAT-Handling) |
|
||||
| Self-Hosting-Strategie | ✅ docker-compose.yml + .env.example + README, für technisch versierte Nutzer |
|
||||
| Self-Hosting-Strategie | ✅ docker-compose.yml + .env.example + README |
|
||||
| Convex Lock-in | ✅ Bewusst akzeptiert; Migrations-Pfad: Convex Cloud EU |
|
||||
| OpenRouter Image-Modelle | ✅ 9 Modelle definiert, alle Tiers haben Zugriff |
|
||||
| Lizenz | ✅ BSL 1.1, 3 Jahre Change Date, Apache 2.0, nur private Nutzung frei |
|
||||
| Repo-Strategie | ✅ Zwei unabhängige Repos (lemonspace-web + lemonspace-landing), Auth-Cookie-Sharing via .lemonspace.io |
|
||||
| OpenRouter Image-Modelle | ✅ 9 Modelle definiert, Phase 1: nur Gemini 2.5 Flash aktiv |
|
||||
| Lizenz | ✅ BSL 1.1, 3 Jahre Change Date, Apache 2.0 |
|
||||
| Repo-Strategie | ✅ Zwei unabhängige Repos, Auth-Cookie-Sharing |
|
||||
| Job Queue | ✅ Convex native (Phase 1), externe Lösung bei Bedarf |
|
||||
| E-Mail | ✅ Unsend + Stalwart, self-hosted |
|
||||
| Analytics | ✅ Rybbit, self-hosted |
|
||||
| Error Tracking | ✅ Sentry Cloud (Free Tier) |
|
||||
| Cache-Strategie | ✅ Cloudflare (Edge) + Redis (Application, TTL ~10min für OpenRouter-Preise) |
|
||||
| E2E-Testing | ✅ Kein E2E in Phase 1, Neubewertung bei Skalierung |
|
||||
| UX-Latenzen | ✅ Node-Status-Modell, Skeleton-Nodes, Browser Notifications (opt-in) |
|
||||
| Credit Fehlerbehandlung | ✅ Reservation + Commit, gecachte Preise, kein nachträglicher Ausgleich |
|
||||
| Cache-Strategie | ✅ Cloudflare (Edge) + Redis (Application) |
|
||||
| E2E-Testing | ✅ Kein E2E in Phase 1 |
|
||||
| UX-Latenzen | ✅ Node-Status-Modell, Skeleton-Nodes |
|
||||
| Credit Fehlerbehandlung | ✅ Reservation + Commit |
|
||||
| Bildbearbeitung: Rendering-Engine | ✅ WebGL + GLSL Shader als primäre Engine. WASM-Backend vorbereitet |
|
||||
| Bildbearbeitung: Preset-Persistierung | ✅ User-Presets in Convex (`adjustmentPresets`-Tabelle) |
|
||||
| Offline Sync | ✅ IndexedDB Queue + localStorage Cache + Optimistic Updates |
|
||||
| Kollaborationstiefe | ⏳ Cursor-Sync, gleichzeitige Edits, Kommentare |
|
||||
| Agent Clarification UX | ⏳ Inline am Node vs. Modal vs. Chat-Sidebar |
|
||||
| Agent Template Format | ⏳ Markdown-Datei vs. strukturiertes JSON-Schema |
|
||||
| Weiche: Bedingungslogik | ⏳ Visueller Rule-Builder vs. Ausdruckssprache |
|
||||
| Mixer: Blend Modes | ⏳ min. Normal, Multiply, Screen, Overlay |
|
||||
| Canvas-Export | ⏳ PNG, PDF, ZIP (Phase 3, Library TBD) |
|
||||
| Bildbearbeitung: Rendering-Engine | ⏳ Canvas 2D API (einfacher, breite Kompatibilität) vs. WebGL/WebGPU (performanter bei großen Bildern). MVP: Canvas 2D, WebGL bei Bedarf. |
|
||||
| Bildbearbeitung: Preset-Persistierung | ⏳ User-Presets in Convex speichern vs. nur Built-in-Presets. |
|
||||
| Bildbearbeitung: Render-Node Server-Engine | ⏳ jimp (bereits im Stack, pure JS) vs. sharp (performanter, aber arm64-Problem). Alternativ: Client rendert und uploaded Ergebnis. |
|
||||
|
||||
---
|
||||
|
||||
@@ -603,17 +681,18 @@ Agent Status: analyzing
|
||||
| Sicherheit | Rate Limiting auf allen API-Endpunkten via Redis, DDoS-Schutz via Cloudflare |
|
||||
| UX-Resilienz | Alle KI-Operationen zeigen Status direkt am Node; Skeleton-Nodes bei Agent-Workflows |
|
||||
| Credit-Integrität | Reservation+Commit-Mechanismus verhindert Credit-Verlust bei fehlgeschlagenen API-Calls |
|
||||
| Offline-Fähigkeit | Canvas-Sync via IndexedDB Queue; Optimistic Updates mit ID-Remapping |
|
||||
|
||||
---
|
||||
|
||||
## 14. Nächste Schritte
|
||||
|
||||
1. Zwei Repos aufsetzen (`lemonspace-web` mit Next.js 16 + Tailwind v4 + ShadCN + Better Auth + Convex, `lemonspace-landing` mit Next.js 16 + Tailwind v4 + ShadCN)
|
||||
2. Convex Schema: Detailliertes Datenbankschema entwerfen (Node-Taxonomie + Credit-System inkl. CreditBalance.reserved/available)
|
||||
3. UI/UX Wireframes: Canvas-Interface, Node-Status-Modell, Skeleton-Nodes, Agent Clarification-UX skizzieren
|
||||
4. API-Prototyp: OpenRouter Anbindung testen — Image Gen (Gemini 2.5 Flash Image) und Text/Reasoning (Claude 3.5 Sonnet)
|
||||
5. Polar Integration: Abo-Tiers anlegen, Webhook-Handling für Subscription-Events und Credit-Zuweisung
|
||||
6. docker-compose.yml + .env.example + Setup-README ausarbeiten
|
||||
1. docker-compose.yml + .env.example + Setup-README ausarbeiten
|
||||
2. Vollständige OpenRouter Integration (alle 9 Modelle + Modellauswahl-UI)
|
||||
3. Agent Node: Analyse, Clarification, Execution, Output
|
||||
4. Self-hosted KI-Services (rembg, Real-ESRGAN, GFPGAN)
|
||||
5. Transformation-Nodes (Crop/Resize, BG entfernen, Upscale)
|
||||
6. Echtzeit-Kollaboration via Convex Subscriptions
|
||||
|
||||
---
|
||||
|
||||
@@ -642,4 +721,4 @@ Die Software wird unter der Business Source License 1.1 (BSL 1.1) veröffentlich
|
||||
|
||||
---
|
||||
|
||||
*LemonSpace PRD v1.5 — April 2026*
|
||||
*LemonSpace PRD v2.0 — April 2026*
|
||||
|
||||
@@ -13,7 +13,8 @@ app/
|
||||
├── globals.css ← Tailwind v4 + Design-Tokens
|
||||
├── (app)/ ← Authentifizierte App-Routen
|
||||
│ ├── canvas/[canvasId]/ ← Canvas-Editor
|
||||
│ │ └── page.tsx ← SSR-Auth/ID-Validation, rendert dann `CanvasShell`
|
||||
│ │ ├── page.tsx ← SSR-Auth/ID-Validation, rendert dann `CanvasShell`
|
||||
│ │ └── error.tsx ← Error Boundary für Canvas
|
||||
│ └── settings/
|
||||
│ └── billing/ ← Billing-Einstellungen
|
||||
├── auth/ ← Auth-Routen (Better Auth)
|
||||
@@ -39,10 +40,7 @@ Server Component. Initialisiert:
|
||||
5. **Providers:** `<Providers initialToken={...}>` — Convex + Theme + Auth
|
||||
6. **InitUser:** `<InitUser />` — Ruft `api.credits.initBalance` beim ersten Login auf
|
||||
|
||||
---
|
||||
|
||||
## Provider-Pattern
|
||||
|
||||
**Provider-Pattern:**
|
||||
```tsx
|
||||
// components/providers.tsx
|
||||
<ConvexProvider client={convex}>
|
||||
@@ -91,3 +89,31 @@ BETTER_AUTH_SECRET
|
||||
BETTER_AUTH_URL
|
||||
NEXT_PUBLIC_CONVEX_URL
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Canvas Route (`app/(app)/canvas/[canvasId]/`)
|
||||
|
||||
**Server Component** (`page.tsx`):
|
||||
|
||||
1. **Auth-Check (SSR):** `getAuthUser()` ruft Dashboard zurück, wenn nicht authentifiziert
|
||||
2. **Canvas-Existenz-Check:** `api.canvases.get` prüft ob Canvas existiert und gehört zum User
|
||||
3. **Rendering:** Wenn alles ok → `CanvasShell` rendern
|
||||
4. **Error Boundary:** `error.tsx` fängt Fälle ab, wo Canvas-Daten fehlen
|
||||
|
||||
**Client Component** (`CanvasShell`):
|
||||
|
||||
- Injiziert über `useEffect` nach SSR, um Hydration-Sync sicherzustellen
|
||||
- Verwaltet Canvas-Sync-Kontext (`CanvasSyncContext`)
|
||||
- Responsive Resizing Sidebar/Main-Layout
|
||||
- Rail-Mode Unterstützung (collapsible Sidebar)
|
||||
|
||||
---
|
||||
|
||||
## Konventionen
|
||||
|
||||
- Alle Server Components zuerst prüfen ob sie User-Daten brauchen (`getAuthUser()`)
|
||||
- Alle Client Components mit `"use client"` markieren
|
||||
- Auth-Queries über `useAuthQuery` (aus `hooks/use-auth-query.ts`) statt `useQuery`, um Auth-Races zu vermeiden
|
||||
- Fehlerbehandlung immer mit Error Boundaries und Toasts
|
||||
- SEO-Optimierung für Landing-Page (`page.tsx`)
|
||||
|
||||
@@ -48,3 +48,41 @@ Die Credit-Balance wird auch in `components/dashboard/credit-overview.tsx` angez
|
||||
- Tier-Upgrades immer über Polar-Checkout (kein direktes Schreiben in `subscriptions`-Tabelle)
|
||||
- `topUp` Mutation (`convex/credits.ts`) für Credit-Nachkauf aufrufen
|
||||
- Monatliches Top-Up-Limit pro Tier beachten (siehe `TIER_CONFIG.topUpLimit`)
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
### Pricing Cards
|
||||
|
||||
Zeigt alle verfügbaren Tiers mit:
|
||||
- Beschreibung
|
||||
- Credits pro Monat
|
||||
- Preise (Euro)
|
||||
- Feature-Checkmarks
|
||||
- Aktives Tier hervorheben
|
||||
|
||||
### Manage Subscription
|
||||
|
||||
UI für:
|
||||
- Aktuelles Tier anzeigen
|
||||
- Upgrade zum nächsthöheren Tier
|
||||
- Abonnement verwalten (Stornierung, Abo verwalten)
|
||||
- Webhook-Feedback-Feedback
|
||||
|
||||
### Top-Up Panel
|
||||
|
||||
Bietet:
|
||||
- Feste Pakete (z.B. 100 Credits, 500 Credits)
|
||||
- Custom-Betrag
|
||||
- Bonus-Staffel-Berechnung (`topup-calculator.ts`)
|
||||
- Direkter Checkout über Polar
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **UI-Updates**: Änderungen an Tiers/Kosten immer in `convex/credits.ts` zuerst ändern, dann in UI-Dateien anpassen
|
||||
2. **Mock-Mode**: Für Development kann `ALLOW_TEST_CREDIT_GRANT=true` verwendet werden, um Test-Credits zu generieren
|
||||
3. **Error Handling**: Webhook-Fehler und Payment-Fehler müssen im Dashboard transparent dargestellt werden
|
||||
4. **Audit Trail**: Alle Credit-Transaktionen (subscriptions, topups, usage) müssen im Backend persistiert werden
|
||||
|
||||
@@ -39,47 +39,52 @@ app/(app)/canvas/[canvasId]/page.tsx
|
||||
|
||||
---
|
||||
|
||||
## Convex ↔ React Flow Mapping
|
||||
## Node-Taxonomie (Phase 1)
|
||||
|
||||
Convex und React Flow verwenden unterschiedliche Datenmodelle. Das Mapping liegt in `lib/canvas-utils.ts`:
|
||||
Alle verfügbaren Node-Typen sind in `lib/canvas-node-catalog.ts` definiert:
|
||||
|
||||
| Richtung | Funktion |
|
||||
|----------|----------|
|
||||
| Convex Node → RF Node | `convexNodeToRF(doc)` |
|
||||
| Convex Edge → RF Edge | `convexEdgeToRF(doc)` |
|
||||
| Edge + Glow | `convexEdgeToRFWithSourceGlow(edge, sourceType, colorMode)` |
|
||||
| StorageId → URL merge | `convexNodeDocWithMergedStorageUrl(node, urlMap, prevMap)` |
|
||||
### Kategorien
|
||||
|
||||
**Wichtig:** Convex speichert `positionX` / `positionY` als separate Felder. React Flow erwartet `position: { x, y }`. Niemals RF-Node-Objekte direkt in Convex schreiben.
|
||||
| Kategorie | Nodes | Beschreibung |
|
||||
|-----------|-------|-------------|
|
||||
| **source** (Quelle) | `image`, `text`, `video`, `asset`, `color` | Input-Quellen für den Workflow |
|
||||
| **ai-output** (KI-Ausgabe) | `prompt`, `ai-text`, `ai-video`, `agent-output` | KI-generierte Inhalte |
|
||||
| **transform** (Transformation) | `crop`, `bg-remove`, `upscale` | Bildbearbeitung-Transformationen |
|
||||
| **image-edit** (Bildbearbeitung) | `curves`, `color-adjust`, `light-adjust`, `detail-adjust` | Preset-basierte Adjustments |
|
||||
| **control** (Steuerung & Flow) | `condition`, `loop`, `parallel`, `switch` | Kontrollfluss-Elemente |
|
||||
| **layout** (Canvas & Layout) | `group`, `frame`, `note`, `compare` | Layout-Elemente |
|
||||
|
||||
**Status-Injection:** `convexNodeToRF` schreibt `_status`, `_statusMessage` und `retryCount` in `data`, damit Node-Komponenten darauf zugreifen können ohne das Node-Dokument direkt zu kennen.
|
||||
### Node-Typen im Detail
|
||||
|
||||
**URL-Caching:** Images mit `storageId` werden im Canvas nicht mehr über eine reaktive Query aufgelöst. `canvas.tsx` sammelt die aktuellen `storageId`s aus `nodes.list` und ruft `storage.batchGetUrlsForCanvas` gezielt per Mutation auf, nur wenn sich das Set ändert. Die vorherige URL wird in `previousDataByNodeId` gecacht, um Flackern beim Reload zu vermeiden.
|
||||
| Typ | Phase | Implementiert | Kategorie | Handles |
|
||||
|-----|-------|---------------|-----------|---------|
|
||||
| `image` | 1 | ✅ | source | source (default), target (default) |
|
||||
| `text` | 1 | ✅ | source | source (default), target (default) |
|
||||
| `video` | 1 | ✅ | source | source (default), target (default) |
|
||||
| `asset` | 1 | ✅ | source | source (default), target (default) |
|
||||
| `prompt` | 1 | ✅ | ai-output | source: `prompt-out`, target: `image-in` |
|
||||
| `ai-text` | 2 | 🔲 | ai-output | source: `text-out`, target: `text-in` |
|
||||
| `ai-video` | 2 | 🔲 | ai-output | source: `video-out`, target: `video-in` |
|
||||
| `agent-output` | 3 | 🔲 | ai-output | systemOutput: true |
|
||||
| `crop` | 2 | 🔲 | transform | 🔲 |
|
||||
| `bg-remove` | 2 | 🔲 | transform | 🔲 |
|
||||
| `upscale` | 2 | 🔲 | transform | 🔲 |
|
||||
| `curves` | 1 | ✅ | image-edit | Preset-basiert (nicht standalone) |
|
||||
| `color-adjust` | 1 | ✅ | image-edit | Preset-basiert |
|
||||
| `light-adjust` | 1 | ✅ | image-edit | Preset-basiert |
|
||||
| `detail-adjust` | 1 | ✅ | image-edit | Preset-basiert |
|
||||
| `group` | 1 | ✅ | layout | source (default), target (default) |
|
||||
| `frame` | 1 | ✅ | layout | source: `frame-out`, target: `frame-in` |
|
||||
| `note` | 1 | ✅ | layout | source (default), target (default) |
|
||||
| `compare` | 1 | ✅ | layout | source: `compare-out`, targets: `left`, `right` |
|
||||
|
||||
**Load-Shedding-Hot-Path:** Der Canvas-Hot-Path soll so wenig Convex-Abhängigkeiten wie möglich haben. Direkt reaktiv bleiben nur die Kernmodelle (`nodes.list`, `edges.list`, `canvases.get`). Nebenpfade wie Storage-URL-Auflösung, Adjustment-Presets und Toolbar-Credits sind bewusst entkoppelt oder zusammengefasst.
|
||||
> `implemented: false` (🔲) bedeutet Phase-2/3 Node, der noch nicht implementiert ist. **Hinweis:** Phase-2/3 Nodes müssen im Schema (`convex/node_type_validator.ts`) vordeklariert werden, damit das System nicht bei jeder Phasenübergang neu migriert werden muss. Die UI filtert Nodes nach Phase.
|
||||
|
||||
**SystemOutput Nodes** (`ai-text`, `ai-video`, `agent-output`): Wird typischerweise vom KI-System erzeugt — nicht aus Palette/DnD anlegbar.
|
||||
|
||||
---
|
||||
|
||||
## Node-Typen (Phase 1)
|
||||
|
||||
Alle registrierten Node-Typen in `node-types.ts`:
|
||||
|
||||
| Typ | Komponente | Kategorie | Handles |
|
||||
|-----|-----------|-----------|---------|
|
||||
| `image` | `ImageNode` | Quelle | source (default), target (default) |
|
||||
| `text` | `TextNode` | Quelle | source (default), target (default) |
|
||||
| `prompt` | `PromptNode` | KI-Ausgabe | source: `prompt-out`, target: `image-in` |
|
||||
| `ai-image` | `AiImageNode` | KI-Ausgabe | source: `image-out`, target: `prompt-in` |
|
||||
| `group` | `GroupNode` | Layout | source (default), target (default) |
|
||||
| `frame` | `FrameNode` | Layout | source: `frame-out`, target: `frame-in` |
|
||||
| `note` | `NoteNode` | Layout | source (default), target (default) |
|
||||
| `compare` | `CompareNode` | Layout | source: `compare-out`, targets: `left`, `right` |
|
||||
| `asset` | `AssetNode` | Quelle | source (default), target (default) |
|
||||
| `video` | `VideoNode` | Quelle | source (default), target (default) |
|
||||
|
||||
> `nodeTypes`-Map **muss** außerhalb jeder React-Komponente definiert sein (sonst re-rendert React Flow bei jedem Render alle Nodes).
|
||||
|
||||
### Default-Größen (`lib/canvas-utils.ts → NODE_DEFAULTS`)
|
||||
## Default-Größen (`lib/canvas-utils.ts → NODE_DEFAULTS`)
|
||||
|
||||
```
|
||||
image: 280 × 200 prompt: 288 × 220
|
||||
@@ -94,7 +99,7 @@ note: 208 × 100 compare: 500 × 380
|
||||
|
||||
```
|
||||
idle → analyzing → clarifying → executing (retry N/2) → done
|
||||
→ error
|
||||
→ error
|
||||
```
|
||||
|
||||
Status + `statusMessage` werden direkt am Node angezeigt. Kein globales Loading-Banner. Bei `error` zeigt `statusMessage` die Kategorie: `Credits: ...`, `Timeout: ...`, `Provider: ...` etc.
|
||||
@@ -109,6 +114,7 @@ Jede Edge bekommt einen `drop-shadow`-Filter entsprechend dem Quell-Node-Typ. Fa
|
||||
- `image`, `text`, `note` → Teal (13, 148, 136)
|
||||
- `frame` → Orange (249, 115, 22)
|
||||
- `group`, `compare` → Grau (100, 116, 139)
|
||||
- `curves`, `color-adjust`, `light-adjust`, `detail-adjust` → Pink (236, 72, 153)
|
||||
|
||||
Compare-Node hat zusätzlich Handle-spezifische Farben (`left` → Blau, `right` → Smaragd).
|
||||
|
||||
@@ -116,6 +122,20 @@ Im **Light Mode** wird der eigentliche Edge-`stroke` ebenfalls aus dieser Akzent
|
||||
|
||||
---
|
||||
|
||||
## Adjustments (Curves, Color, Light, Detail)
|
||||
|
||||
**Wichtig:** Diese Nodes werden **nicht als eigene Node-Typen** in der Palette angezeigt. Stattdessen existieren sie als **Presets**, die direkt in einem vorhandenen Node angewendet werden können.
|
||||
|
||||
- Preset-Verwaltung: `presets.list` (Convex-Query)
|
||||
- Preset-Provider: `CanvasPresetsProvider` (Kontext)
|
||||
- Hook: `useCanvasAdjustmentPresets()` für Preset-Management
|
||||
|
||||
**Regeln:**
|
||||
- Curves-, Color-, Light-, Detail-Adjustment Nodes dürfen keine eigene `presets.list`-Query feuern.
|
||||
- Immer `CanvasPresetsProvider` + `useCanvasAdjustmentPresets(...)` verwenden.
|
||||
|
||||
---
|
||||
|
||||
## Optimistic Updates & Local Persistence
|
||||
|
||||
**Optimistic Prefix:** Temporäre Nodes/Edges erhalten IDs mit `optimistic_` / `optimistic_edge_`-Prefix. Sie werden durch echte Convex-IDs ersetzt sobald die Mutation abgeschlossen ist.
|
||||
@@ -153,6 +173,10 @@ Im **Light Mode** wird der eigentliche Edge-`stroke` ebenfalls aus dieser Akzent
|
||||
| `export-button.tsx` | Export-Button mit Format-Auswahl |
|
||||
| `connection-banner.tsx` | Offline-Banner bei Convex-Verbindungsverlust |
|
||||
| `custom-connection-line.tsx` | Angepasste temporäre Verbindungslinie |
|
||||
| `default-edge.tsx` | Standard Edge-Rendering |
|
||||
| `node-error-boundary.tsx` | Error-Boundary für Node-Fehler |
|
||||
| `adjustment-preview.tsx` | Vorschau für Adjustment-Presets |
|
||||
| `adjustment-controls.tsx` | UI-Controls für Adjustments |
|
||||
|
||||
---
|
||||
|
||||
@@ -181,3 +205,5 @@ Im **Light Mode** wird der eigentliche Edge-`stroke` ebenfalls aus dieser Akzent
|
||||
- **Parent-Nodes:** `parentId` zeigt auf einen Group- oder Frame-Node. React Flow erwartet, dass Parent-Nodes vor Child-Nodes in der `nodes`-Array stehen.
|
||||
- **Bridge-Edges:** Beim Löschen eines mittleren Nodes werden Kanten automatisch neu verbunden (`computeBridgeCreatesForDeletedNodes` aus `lib/canvas-utils.ts`).
|
||||
- **`"null"`-Handles:** Convex kann `"null"` als String speichern. `convexEdgeToRF` sanitized Handles: `"null"` → `undefined`.
|
||||
- **Optimistic IDs:** Temporäre Nodes/Edges erhalten IDs mit `optimistic_` / `optimistic_edge_`-Prefix, werden durch echte Convex-IDs ersetzt, sobald die Mutation abgeschlossen ist.
|
||||
- **Node-Taxonomie:** Alle Node-Typen sind in `lib/canvas-node-catalog.ts` definiert. Phase-2/3 Nodes haben `implemented: false` und `disabledHint`.
|
||||
|
||||
@@ -14,6 +14,22 @@ UI-Komponenten für die Startseite nach dem Login.
|
||||
|
||||
---
|
||||
|
||||
## Layout-Seite
|
||||
|
||||
`app/dashboard/page.tsx` — Server Component, rendert Dashboard-Layout mit den Komponenten oben.
|
||||
|
||||
**Layout-Struktur:**
|
||||
```
|
||||
Dashboard
|
||||
├── Header (User-Avatar, Name)
|
||||
├── Quick Actions (Create Canvas, Search)
|
||||
├── Credit Overview (Balance, Usage Bars)
|
||||
├── Recent Transactions (List)
|
||||
└── Canvas Grid (Canvas Cards)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Datenquellen
|
||||
|
||||
Alle Daten kommen aus Convex-Queries via `useAuthQuery` (aus `hooks/use-auth-query.ts`):
|
||||
@@ -32,14 +48,55 @@ Alle Daten kommen aus Convex-Queries via `useAuthQuery` (aus `hooks/use-auth-que
|
||||
|
||||
---
|
||||
|
||||
## Layout-Seite
|
||||
|
||||
`app/dashboard/page.tsx` — Server Component, rendert Dashboard-Layout mit den Komponenten oben.
|
||||
|
||||
---
|
||||
|
||||
## Konventionen
|
||||
|
||||
- Kein lokaler State für Server-Daten — alles via Convex-Subscriptions (reaktiv)
|
||||
- `useAuthQuery` statt `useQuery` verwenden, um Auth-Races zu vermeiden (skippt Query bis Token bereit ist)
|
||||
- Canvas-Thumbnails sind optional (`thumbnail?: Id<"_storage">`) — Fallback-State immer behandeln
|
||||
- Responsive Grid-Layout für Canvas-Cards (`grid-cols-1 md:grid-cols-2 lg:grid-cols-3`)
|
||||
- Leere Zustände (keine Canvases, keine Transaktionen) mit nutzerfreundlichen Platzhaltern zeigen
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
### Canvas Cards
|
||||
|
||||
Jede Karte zeigt:
|
||||
- Canvas-Thumbnail (wenn verfügbar)
|
||||
- Canvas-Name (truncate)
|
||||
- Letzte Änderungszeit (relative Formatierung)
|
||||
- Klick → Öffnen im Canvas-Editor
|
||||
- Menü → Umbenennen, Löschen
|
||||
|
||||
### Credit Overview
|
||||
|
||||
Zeigt:
|
||||
- Aktueller Credit-Balance (z.B. "350 Credits")
|
||||
- Verbrauchs-Balken (Progress Bar) für aktuellen Monat
|
||||
- Monats-Details (vom `api.credits.getUsageStats`)
|
||||
- Link zum Upgrade im Abo-Settings
|
||||
|
||||
### Recent Transactions
|
||||
|
||||
Liste der letzten Credit-Transaktionen mit:
|
||||
- Transaktions-Typ (Subscription, Top-Up, Usage)
|
||||
- Betrag (+/-)
|
||||
- Beschreibung
|
||||
- Datum (relative Formatierung)
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
- **Auth-Race**: `useAuthQuery` verhindert Fehler beim Initialisierungs-Flash
|
||||
- **Empty States**: Wenn keine Canvases/Transaktionen vorhanden sind, informative Platzhalter zeigen
|
||||
- **Offline**: Connection-Banner anzeigen, wenn Convex nicht erreichbar
|
||||
|
||||
---
|
||||
|
||||
## Performance
|
||||
|
||||
- Canvas-Thumbnails werden über `api.canvases.list` geladen (nur wenn vorhanden)
|
||||
- Transaktions-Listen sind paginiert oder limitiert (z.B. letzte 20 Transaktionen)
|
||||
- Kein lokaler State für Canvas-Daten — alles über real-time Convex-Subscriptions
|
||||
|
||||
@@ -49,3 +49,31 @@ transition: all 200ms cubic-bezier(0.16, 1, 0.3, 1); /* expo-out */
|
||||
2. In `components/ui/` ablegen (automatisch durch ShadCN-CLI)
|
||||
3. Anpassungen direkt in der Komponente — keine separaten Override-Dateien
|
||||
4. Token-Konventionen aus `globals.css` verwenden, keine Hardcoded-Farben
|
||||
|
||||
---
|
||||
|
||||
## Layout-Komponenten
|
||||
|
||||
| Komponente | Pfad | Verwendung |
|
||||
|------------|------|------------|
|
||||
| `resizable` | `components/ui/resizable.tsx` | Sidebar-Resizing in Canvas |
|
||||
| `dialog` | `components/ui/dialog.tsx` | Confirmations, Popovers |
|
||||
| `popover` | `components/ui/popover.tsx` | Dropdowns, Kontext-Menüs |
|
||||
| `badge` | `components/ui/badge.tsx` | Status-Tags, Badges |
|
||||
| `tooltip` | `components/ui/tooltip.tsx` | Explainer-Texte |
|
||||
| `separator` | `components/ui/separator.tsx` | Trennungen |
|
||||
|
||||
---
|
||||
|
||||
## ShadCN Integration
|
||||
|
||||
ShadCN-Komponenten werden nicht als npm-Paket installiert, sondern als Copy-Paste in das Projekt kopiert. Dies ermöglicht volle Kontrolle über die Implementierung und Anpassung an die LemonSpace-Design-Systeme.
|
||||
|
||||
**Standard-Prozess:**
|
||||
```bash
|
||||
npx shadcn@latest add button
|
||||
npx shadcn@latest add input
|
||||
# ... andere Komponenten
|
||||
```
|
||||
|
||||
Komponenten werden direkt in `components/ui/` abgelegt. Lokale Anpassungen erfolgen durch Überladen von Props oder direkt in der Komponentendatei.
|
||||
|
||||
@@ -9,6 +9,7 @@ Convex ist das vollständige Backend von LemonSpace: Datenbank, Realtime-Subscri
|
||||
| Datei | Zweck |
|
||||
|-------|-------|
|
||||
| `schema.ts` | Einzige Wahrheitsquelle für alle Tabellen und Typen |
|
||||
| `node_type_validator.ts` | Node-Typen Validator (Phase 1, Phase 2, Phase 3, Adjustment Presets) |
|
||||
| `ai.ts` | KI-Bildgenerierungs-Pipeline |
|
||||
| `credits.ts` | Credit-System: Balance, Reservation+Commit, Tier-Config |
|
||||
| `nodes.ts` | CRUD für Canvas-Nodes |
|
||||
@@ -17,6 +18,8 @@ Convex ist das vollständige Backend von LemonSpace: Datenbank, Realtime-Subscri
|
||||
| `openrouter.ts` | OpenRouter-HTTP-Client + Modell-Config (Backend) |
|
||||
| `auth.ts` | Better Auth Integration |
|
||||
| `helpers.ts` | `requireAuth()` + `optionalAuth()` für Auth-Checks |
|
||||
| `batch_validation_utils.ts` | Validierung von Batch-Node-Operationen |
|
||||
| `canvas-connection-policy.ts` | Verbindungspolitiken zwischen Nodes (Validierung) |
|
||||
| `polar.ts` | Polar.sh Webhook-Handler (Subscriptions) |
|
||||
| `pexels.ts` | Pexels Stock-Bilder API |
|
||||
| `freepik.ts` | Freepik Asset-Browser API |
|
||||
@@ -28,7 +31,31 @@ Convex ist das vollständige Backend von LemonSpace: Datenbank, Realtime-Subscri
|
||||
|
||||
## Schema (`schema.ts`)
|
||||
|
||||
Alle Node-Typen sind in zwei Validators definiert: `phase1NodeTypes` (aktiv) und `nodeType` (alle Phasen). Phase-2/3-Typen werden im Schema vordeklariert, um spätere Schema-Migrationen zu vermeiden — die UI filtert nach Phase.
|
||||
Alle Node-Typen werden über Validators definiert: `phase1NodeTypeValidator`, `nodeTypeValidator` (Phase 1+), `adjustmentNodeTypeValidator`, und `adjustmentPresetNodeTypeValidator`.
|
||||
|
||||
### Phase-Struktur
|
||||
|
||||
- **Phase 1 Nodes:** Aktiv implementierte Nodes (`PHASE1_CANVAS_NODE_TYPES`)
|
||||
- **Phase 2/3 Nodes:** Vordeklariert, aber `implemented: false` — UI filtert nach Phase
|
||||
- **Adjustment Presets:** Spezielle Presets für Curves, Color Adjust, Light Adjust, Detail Adjust
|
||||
|
||||
### Node Data Shapes
|
||||
|
||||
| Node-Typ | Felder | Bemerkung |
|
||||
|----------|--------|-----------|
|
||||
| `image` | `storageId`, `url`, `mimeType`, `width`, `height` | Bild-Upload oder URL |
|
||||
| `text` | `content` | Markdown-Text |
|
||||
| `prompt` | `content`, `model`, `modelTier` | KI-Generierungsanweisung |
|
||||
| `ai-image` | `storageId`, `prompt`, `model`, `modelTier`, `parameters`, `generationTimeMs`, `creditCost` | Generiertes KI-Bild |
|
||||
| `text-node` | `content` | Generierter KI-Text |
|
||||
| `compare` | `leftNodeId`, `rightNodeId`, `sliderPosition` | Vergleichs-Node |
|
||||
| `frame` | `label`, `exportWidth`, `exportHeight`, `backgroundColor` | Artboard |
|
||||
| `group` | `label`, `collapsed` | Container-Node |
|
||||
| `note` | `content`, `color` | Anmerkung |
|
||||
| `curves` | Presets (Kurven) | Nicht im UI als Node-Typ, sondern als Presets |
|
||||
| `color-adjust` | Presets (Farbkorrektur) | |
|
||||
| `light-adjust` | Presets (Helligkeit) | |
|
||||
| `detail-adjust` | Presets (Details) | |
|
||||
|
||||
### Tabellen
|
||||
|
||||
@@ -36,12 +63,14 @@ Alle Node-Typen sind in zwei Validators definiert: `phase1NodeTypes` (aktiv) und
|
||||
|
||||
**`nodes`** — Alle Nodes eines Canvas. Felder: `type`, `positionX/Y`, `width`, `height`, `status` (`idle|analyzing|clarifying|executing|done|error`), `statusMessage`, `retryCount`, `data` (v.any()), `parentId`, `zIndex`. Index: `by_canvas`, `by_canvas_type`, `by_parent`.
|
||||
|
||||
> `data` ist `v.any()` — Typ-Safety läuft über den `type`-Discriminator + Zod im Frontend. Die Node-Data-Shapes sind in `schema.ts` dokumentiert (`imageNodeData`, `promptNodeData`, etc.).
|
||||
> `data` ist `v.any()` — Typ-Safety läuft über den `type`-Discriminator + Zod im Frontend. Die Node-Data-Shapes sind in `schema.ts` dokumentiert.
|
||||
|
||||
**`edges`** — Verbindungen zwischen Nodes. Index: `by_canvas`, `by_source`, `by_target`.
|
||||
|
||||
**`mutationRequests`** — Idempotenz-Layer für Client-Replay (`clientRequestId`) bei offline/Retry-Sync. Felder: `userId`, `mutation`, `clientRequestId`, optionale Ziel-IDs (`canvasId`, `nodeId`, `edgeId`). Index: `by_user_mutation_request`.
|
||||
|
||||
**`adjustmentPresets`** — Benutzerspezifische Presets für Adjustment-Nodes. Index: `by_userId`, `by_userId_nodeType`.
|
||||
|
||||
**`creditBalances`** — Pro User: `balance`, `reserved`, `monthlyAllocation`. `available = balance - reserved` (computed, nicht gespeichert).
|
||||
|
||||
**`creditTransactions`** — Jede Credit-Bewegung. Types: `subscription | topup | usage | reservation | refund`. Status: `committed | reserved | released | failed`.
|
||||
@@ -148,6 +177,43 @@ Wirft bei unauthentifiziertem Zugriff. Wird von allen Queries und Mutations genu
|
||||
|
||||
---
|
||||
|
||||
## Nodes & Edges (`nodes.ts` / `edges.ts`)
|
||||
|
||||
### Nodes (`nodes.ts`)
|
||||
|
||||
**Validierung:**
|
||||
- `getValidatedBatchNodesOrThrow()` — Validiert Batch von Nodes mit `validateBatchNodesForUserOrThrow()`
|
||||
- Verwendet `canvas-connection-policy.ts` für Verbindungsberechtigungen
|
||||
|
||||
**Mutationen:**
|
||||
- `create`, `update`, `delete` — Standard CRUD
|
||||
- `createWithEdgeSplit`, `createWithEdgeFromSource`, `createWithEdgeToTarget` — Erstellen mit Edge-Verbindung
|
||||
- `batchRemove`, `batchRemoveNodes` — Batch-Entfernung
|
||||
- `splitEdgeAtExistingNode` — Split einer Edge am existierenden Node
|
||||
|
||||
**Optimistische IDs:**
|
||||
- Nodes erhalten temporäre IDs mit `optimistic_`-Prefix für optimistic updates
|
||||
|
||||
**Bridge-Edges:**
|
||||
- Bei Node-Löschung werden `computeBridgeCreatesForDeletedNodes` in `canvas-utils.ts` verwendet, um Kanten neu zu verbinden
|
||||
|
||||
### Edges (`edges.ts`)
|
||||
|
||||
**Validierung:**
|
||||
- `assertConnectionPolicy()` — Prüft, ob Source-Node Output erlaubt und Target-Node Input erlaubt
|
||||
- `assertTargetAllowsIncomingEdge()` — Performance-optimierte Prüfung auf eingehende Edges
|
||||
- `getCanvasConnectionValidationMessage()` — Fehlermeldung bei ungültigen Verbindungen
|
||||
|
||||
**Validierungsregeln (aus `canvas-connection-policy.ts`):**
|
||||
- Source-Typ muss Output-Ports haben
|
||||
- Target-Typ muss Input-Ports haben
|
||||
- Keine self-loops (Edge von Node zu sich selbst)
|
||||
- Quelle: `image`, `text`, `note`, `group`, `compare`, `frame` → Source-Ports
|
||||
- Ziel: `ai-image`, `compare` → Target-Ports
|
||||
- Curves- und Adjustment-Node-Presets: Nur Presets nutzen, keine direkten Edges
|
||||
|
||||
---
|
||||
|
||||
## Storage (`storage.ts`)
|
||||
|
||||
- `generateUploadUrl` bleibt eine normale Mutation für Upload-Start im Client.
|
||||
|
||||
121
hooks/CLAUDE.md
121
hooks/CLAUDE.md
@@ -24,12 +24,67 @@ Wrapper um Convex `useQuery`, der automatisch `"skip"` setzt wenn der Auth-Token
|
||||
|
||||
Berechnet die Canvas-Position für einen neuen Node, sodass er im aktuellen Viewport-Zentrum erscheint. Wird beim Einfügen eines Nodes aus der Palette oder Command Palette genutzt.
|
||||
|
||||
**Verwendung:**
|
||||
```typescript
|
||||
const centeredPosition = useCenteredFlowNodePosition(viewport)
|
||||
const onNodeDragStop = (node) => {
|
||||
// Node wird im Viewport-Zentrum erstellt
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `use-debounced-callback.ts`
|
||||
|
||||
Standard-Debounce-Hook. Wird für teure Operationen wie Canvas-Snapshots und Convex-Mutations beim Resizen/Bewegen von Nodes verwendet.
|
||||
|
||||
**Verwendung:**
|
||||
```typescript
|
||||
const debouncedUpdate = useDebouncedCallback(() => {
|
||||
// Nur alle 300ms ausgeführt
|
||||
updateCanvasSnapshot()
|
||||
}, 300)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `use-ai-generation-status.ts`
|
||||
|
||||
Hook für AI-Generation-Status-Tracking. Überwacht Node-Status-Änderungen und zeigt Toasts bei Fehlern.
|
||||
|
||||
**Features:**
|
||||
- Schwellenwert-basiertes Fehler-Tracking
|
||||
- Auto-Hiding Toasts nach 5 Sekunden
|
||||
- Fehler-Kategorisierung (Credits, Timeout, Provider, etc.)
|
||||
|
||||
**Verwendung:**
|
||||
```typescript
|
||||
const { status, statusMessage } = useAiGenerationStatus()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `use-adjustment-presets.ts`
|
||||
|
||||
Hook für Adjustment-Preset-Management. Bündelt Preset-Queries und bietet helper-Funktionen für Preset-Validierung.
|
||||
|
||||
**Verwendung:**
|
||||
```typescript
|
||||
const { presets, isLoading } = useAdjustmentPresets(nodeType)
|
||||
const savePreset = (name, params) => { /* ... */ }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `use-canvas-sync-status.ts`
|
||||
|
||||
Hook für Canvas-Sync-Status (Online/Offline). Zeigt Banner oder Icons basierend auf der Verbindungsqualität.
|
||||
|
||||
**Verwendung:**
|
||||
```typescript
|
||||
const { isOnline, pendingOps, syncStatus } = useCanvasSyncStatus()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Konventionen
|
||||
@@ -37,3 +92,69 @@ Standard-Debounce-Hook. Wird für teure Operationen wie Canvas-Snapshots und Con
|
||||
- Hooks immer mit `use-` Prefix im Dateinamen
|
||||
- Nur wiederverwendbare Hooks hier — canvas-spezifische Inline-Logik bleibt in `canvas.tsx`
|
||||
- Kein direkter Convex-Zugriff in Hooks wenn möglich — Queries/Mutations von der aufrufenden Komponente übergeben lassen
|
||||
- Hooks immer mit `"use client"` am Anfang der Datei markieren
|
||||
- TypeScript-Typen immer definieren und exportieren
|
||||
- Hooks dokumentieren mit JSDoc für bessere IDE-Unterstützung
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Keine Side Effects außerhalb von useEffect:** Alle Nebeneffekte in useEffect oder custom hooks implementieren
|
||||
2. **Type Safety:** Hook-Props und Return-Werte immer typisieren
|
||||
3. **Performance:** useMemo und useCallback für teure Berechnungen nutzen
|
||||
4. **Error Handling:** Hooks sollten keine Exceptions werfen, sondern Fehler via Callbacks propagieren
|
||||
5. **Dependencies:** useMemo/useCallback Dependencies immer korrekt angeben
|
||||
6. **Testing:** Hooks sollen unit-testbar sein (keine React-Abhängigkeiten außer Callbacks)
|
||||
|
||||
---
|
||||
|
||||
## Examples
|
||||
|
||||
### Custom Hook für Node-Resizing
|
||||
|
||||
```typescript
|
||||
// hooks/use-node-resize.ts
|
||||
export function useNodeResize(nodeId, updateNode) {
|
||||
const debouncedUpdate = useDebouncedCallback(
|
||||
(newData) => updateNode(nodeId, newData),
|
||||
200
|
||||
)
|
||||
|
||||
const handleResize = (newDimensions) => {
|
||||
debouncedUpdate({
|
||||
width: newDimensions.width,
|
||||
height: newDimensions.height,
|
||||
})
|
||||
}
|
||||
|
||||
return { handleResize }
|
||||
}
|
||||
```
|
||||
|
||||
### Custom Hook für LocalStorage-Backups
|
||||
|
||||
```typescript
|
||||
// hooks/use-local-storage.ts
|
||||
export function useLocalStorage<T>(key: string, initialValue: T) {
|
||||
const [storedValue, setStoredValue] = useState<T>(() => {
|
||||
try {
|
||||
const item = window.localStorage.getItem(key)
|
||||
return item ? JSON.parse(item) : initialValue
|
||||
} catch (error) {
|
||||
return initialValue
|
||||
}
|
||||
})
|
||||
|
||||
const setValue = (value: T) => {
|
||||
try {
|
||||
setStoredValue(value)
|
||||
window.localStorage.setItem(key, JSON.stringify(value))
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
return [storedValue, setValue] as const
|
||||
}
|
||||
```
|
||||
|
||||
@@ -10,7 +10,9 @@ Geteilte Hilfsfunktionen, Typ-Definitionen und Konfiguration. Keine React-Kompon
|
||||
|-------|-------|
|
||||
| `canvas-utils.ts` | Convex↔React Flow Adapter, Edge-Glow, Node-Defaults, Bridge-Edges |
|
||||
| `canvas-node-catalog.ts` | Vollständige Node-Taxonomie (alle Phasen, Kategorien, Phase-Flags) |
|
||||
| `canvas-node-types.ts` | TypeScript-Typen und Union-Typen für Canvas-Nodes |
|
||||
| `canvas-node-templates.ts` | Default-Daten für neue Nodes (beim Einfügen aus Palette) |
|
||||
| `canvas-connection-policy.ts` | Validierungsregeln für Edge-Verbindungen zwischen Nodes |
|
||||
| `ai-models.ts` | Client-seitige Modell-Definitionen (muss mit `convex/openrouter.ts` in sync bleiben) |
|
||||
| `image-formats.ts` | Aspect-Ratio-Strings, Node-Chrome-Höhen (`AI_IMAGE_NODE_HEADER_PX` etc.) |
|
||||
| `auth.ts` | Better Auth Server-Instanz |
|
||||
@@ -47,6 +49,21 @@ Alle Adapter-Funktionen zwischen Convex-Datenmodell und React Flow. Details in `
|
||||
|
||||
---
|
||||
|
||||
## `canvas-node-types.ts` — TypeScript-Typen
|
||||
|
||||
Einzige Quelle für Node-Typ-Union-Typen und Schema-Validatoren.
|
||||
|
||||
```typescript
|
||||
PHASE1_CANVAS_NODE_TYPES // Phase 1 Nodes (aktiv)
|
||||
CANVAS_NODE_TYPES // Phase 1 + Phase 2 + Phase 3 (alle)
|
||||
ADJUSTMENT_NODE_TYPES // Adjustment-Preset-Nodes (curves, color-adjust, etc.)
|
||||
ADJUSTMENT_PRESET_NODE_TYPES // Spezifische Adjustment-Presets
|
||||
```
|
||||
|
||||
**Wichtig:** Dieser Datei und `convex/node_type_validator.ts` müssen immer synchron gehalten werden. Neue Nodes → Validator anpassen.
|
||||
|
||||
---
|
||||
|
||||
## `canvas-node-catalog.ts` — Node-Taxonomie
|
||||
|
||||
Einzige Wahrheitsquelle für alle Node-Typen auf Client-Seite.
|
||||
@@ -54,13 +71,57 @@ Einzige Wahrheitsquelle für alle Node-Typen auf Client-Seite.
|
||||
```typescript
|
||||
NODE_CATALOG // Alle Nodes aller Phasen
|
||||
NODE_CATEGORY_META // Label + Sortierung pro Kategorie
|
||||
isNodePaletteEnabled // true wenn: implementiert + kein systemOutput + Template vorhanden
|
||||
NODE_CATEGORIES_ORDERED // Sortierte Kategorien-Liste
|
||||
catalogEntriesByCategory() // Gruppiert für Sidebar-Rendering
|
||||
isNodePaletteEnabled // true wenn: implementiert + kein systemOutput + Template vorhanden
|
||||
```
|
||||
|
||||
**Kategorien:** `source`, `ai-output`, `transform`, `image-edit`, `control`, `layout`
|
||||
**Kategorien:**
|
||||
- `source` — Quelle (image, text, video, asset, color)
|
||||
- `ai-output` — KI-Ausgabe (prompt, ai-text, ai-video, agent-output)
|
||||
- `transform` — Transformation (crop, bg-remove, upscale)
|
||||
- `image-edit` — Bildbearbeitung (adjustments)
|
||||
- `control` — Steuerung & Flow
|
||||
- `layout` — Canvas & Layout (group, frame, note, compare)
|
||||
|
||||
Phase-2/3-Nodes haben `implemented: false` und `disabledHint`. Nie `implemented: true` setzen ohne zugehörige React-Flow-Komponente in `components/canvas/nodes/`.
|
||||
**Node-Eigenschaften:**
|
||||
- `type` — Node-Typ (als String)
|
||||
- `label` — Anzeigetext
|
||||
- `category` — Kategorisierung
|
||||
- `phase` — 1, 2 oder 3 (für zukünftige Feature-Phasen)
|
||||
- `implemented` — true wenn React-Flow-Komponente vorhanden
|
||||
- `systemOutput` — true wenn KI-System diese Nodes erzeugt (nicht aus Palette nutzbar)
|
||||
- `disabledHint` — Kurzer Hinweis für deaktivierte Nodes
|
||||
|
||||
**Phase-2/3-Nodes:** Haben `implemented: false` und `disabledHint`. UI filtert nach Phase, niemals ohne zugehörige React-Flow-Komponente `implemented: true` setzen.
|
||||
|
||||
---
|
||||
|
||||
## `canvas-node-templates.ts` — Default-Daten
|
||||
|
||||
Default-Initial-Daten für neue Nodes beim Einfügen aus Palette.
|
||||
|
||||
- Erstellt durch die Node-Katalog-Einträge
|
||||
- Enthält default-Werte für `data`-Felder
|
||||
- Wird von `canvas.tsx` verwendet beim Node-Create
|
||||
|
||||
---
|
||||
|
||||
## `canvas-connection-policy.ts` — Validierungsregeln
|
||||
|
||||
Regeln für erlaubte Verbindungen zwischen Node-Typen.
|
||||
|
||||
**Validierungs-Funktionen:**
|
||||
- `validateCanvasConnectionPolicy()` — Prüft, ob Verbindung erlaubt ist
|
||||
- `getCanvasConnectionValidationMessage()` — Gibt lesbare Fehlermeldung zurück
|
||||
- `assertConnectionPolicy()` — Wirft Fehler bei ungültiger Verbindung
|
||||
|
||||
**Regeln:**
|
||||
- Source-Typ muss Output-Ports haben, Target-Typ muss Input-Ports haben
|
||||
- Keine self-loops (Edge von Node zu sich selbst)
|
||||
- Quelle: `image`, `text`, `note`, `group`, `compare`, `frame` → Source-Ports
|
||||
- Ziel: `ai-image`, `compare` → Target-Ports
|
||||
- Curves- und Adjustment-Node-Presets: Nur Presets nutzen, keine direkten Edges
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user