diff --git a/.docs/LemonSpace_Manifest.md b/.docs/LemonSpace_Manifest.md index 44497c2..c002307 100644 --- a/.docs/LemonSpace_Manifest.md +++ b/.docs/LemonSpace_Manifest.md @@ -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* diff --git a/.docs/LemonSpace_PRD.md b/.docs/LemonSpace_PRD.md index 65a115c..81b2410 100644 --- a/.docs/LemonSpace_PRD.md +++ b/.docs/LemonSpace_PRD.md @@ -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* \ No newline at end of file +*LemonSpace PRD v2.0 — April 2026* diff --git a/app/CLAUDE.md b/app/CLAUDE.md index f826aad..575abfc 100644 --- a/app/CLAUDE.md +++ b/app/CLAUDE.md @@ -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:** `` — Convex + Theme + Auth 6. **InitUser:** `` — Ruft `api.credits.initBalance` beim ersten Login auf ---- - -## Provider-Pattern - +**Provider-Pattern:** ```tsx // components/providers.tsx @@ -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`) diff --git a/components/billing/CLAUDE.md b/components/billing/CLAUDE.md index ba953fa..2b01e40 100644 --- a/components/billing/CLAUDE.md +++ b/components/billing/CLAUDE.md @@ -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 diff --git a/components/canvas/CLAUDE.md b/components/canvas/CLAUDE.md index 63f2f7b..2ced3c9 100644 --- a/components/canvas/CLAUDE.md +++ b/components/canvas/CLAUDE.md @@ -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`. diff --git a/components/dashboard/CLAUDE.md b/components/dashboard/CLAUDE.md index 7de4d38..d792c16 100644 --- a/components/dashboard/CLAUDE.md +++ b/components/dashboard/CLAUDE.md @@ -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 diff --git a/components/ui/CLAUDE.md b/components/ui/CLAUDE.md index c70178d..883a45f 100644 --- a/components/ui/CLAUDE.md +++ b/components/ui/CLAUDE.md @@ -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. diff --git a/convex/CLAUDE.md b/convex/CLAUDE.md index cefaca6..50bcc0f 100644 --- a/convex/CLAUDE.md +++ b/convex/CLAUDE.md @@ -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. diff --git a/hooks/CLAUDE.md b/hooks/CLAUDE.md index 43beea6..d05a557 100644 --- a/hooks/CLAUDE.md +++ b/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(key: string, initialValue: T) { + const [storedValue, setStoredValue] = useState(() => { + 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 +} +``` diff --git a/lib/CLAUDE.md b/lib/CLAUDE.md index 1669dde..efcf791 100644 --- a/lib/CLAUDE.md +++ b/lib/CLAUDE.md @@ -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 ---