From a7eb2bc99c3100ec839cca0b6da607f9a4eb3a9d Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 8 Apr 2026 14:03:16 +0200 Subject: [PATCH] Update LemonSpace Manifest to v2.1, enabling all 9 image models in OpenRouter with server-side tier enforcement. Enhance dashboard functionality with a bundled snapshot query and localStorage caching for improved performance and analytics. Introduce credits activity chart and optimize canvas graph queries for better data handling. --- .docs/LemonSpace_Manifest.md | 11 +-- .docs/LemonSpace_PRD.md | 53 ++++++++----- components/canvas/CLAUDE.md | 36 +++++++++ components/dashboard/CLAUDE.md | 132 ++++++++++++++++++++------------- components/ui/CLAUDE.md | 16 ++++ convex/CLAUDE.md | 37 +++++++++ hooks/CLAUDE.md | 24 ++++++ lib/CLAUDE.md | 47 ++++++++++++ 8 files changed, 283 insertions(+), 73 deletions(-) diff --git a/.docs/LemonSpace_Manifest.md b/.docs/LemonSpace_Manifest.md index c002307..70c9ed1 100644 --- a/.docs/LemonSpace_Manifest.md +++ b/.docs/LemonSpace_Manifest.md @@ -1,6 +1,6 @@ # 🍋 LemonSpace — Produkt-Manifest -**v2.0 — April 2026** +**v2.1 — April 2026** *Self-Hosted, Source-Available Creative Workspace* @@ -129,7 +129,7 @@ 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, Phase 1: nur Gemini 2.5 Flash aktiv. | ✅ | +| AI Layer | OpenRouter als primĂ€re AI-Schicht. Alle 9 Image-Modelle aktiv, serverseitiges Tier-Enforcement, tier-aware Model Selector. | ✅ | | 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. | ✅ | @@ -160,7 +160,7 @@ Fokus heißt Nein sagen. Diese Features sind bewusst ausgeklammert, nicht verges | 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. | + --- @@ -235,10 +235,11 @@ Priorisiert nach AbhĂ€ngigkeiten. Jeder Schritt hat ein klares Artefakt. | 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 | ☐ | +| 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 | ☐ | +| 13 | Dashboard Snapshot + Analytics | GebĂŒndelte Query, localStorage-Cache, Credits-Activity-Chart | ✅ | --- @@ -257,4 +258,4 @@ Folgende Themen werden in eigenen Dokumenten vertieft. Das Manifest bleibt schla --- -*LemonSpace Manifest v2.0 — April 2026* +*LemonSpace Manifest v2.1 — April 2026* diff --git a/.docs/LemonSpace_PRD.md b/.docs/LemonSpace_PRD.md index 81b2410..6cfa6dd 100644 --- a/.docs/LemonSpace_PRD.md +++ b/.docs/LemonSpace_PRD.md @@ -4,7 +4,7 @@ | Version | Status | Datum | Projekt | |---------|--------|-------|---------| -| v2.0 | Draft | April 2026 | lemonspace.app | +| v2.1 | Draft | April 2026 | lemonspace.app | --- @@ -27,6 +27,7 @@ | 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. | +| v2.1 | **Alle 9 Image-Modelle aktiviert (Phase 2→1):** VollstĂ€ndige OpenRouter Image Gen Integration mit serverseitigem Tier-Enforcement und modellspezifischen Request-Modalities. Tier-aware Model Selector im Prompt-Node. AI-Modularisierung: `ai_errors.ts`, `ai_node_data.ts`, `ai_retry.ts` aus `ai.ts` extrahiert. Dashboard Snapshot Cache (`convex/dashboard.ts`): GebĂŒndelte Query mit localStorage-Cache (`lib/dashboard-snapshot-cache.ts`). Credits Activity Analytics: `lib/credits-activity.ts` + `CreditsActivityChart` (Recharts). Canvas Graph Query Cache (`convex/canvasGraph.ts` + `canvas-graph-query-cache.ts`): Performance-Optimierung durch separaten Graph-Endpunkt mit Optimistic Store. Neuer Hook `use-dashboard-snapshot.ts`. ShadCN Chart-Komponente (`components/ui/chart.tsx`) + Recharts 3.8. | --- @@ -238,6 +239,7 @@ Agent Nodes sind ein spezieller Node-Typ auf dem Canvas. Sie fungieren als Smart | 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 | +| Charts / Visualization | Recharts + ShadCN Chart | v3.8.0 — Dashboard Credits Activity Chart | ### Zwei-Repo-Strategie @@ -295,13 +297,23 @@ Dokumentierter Migrationspfad bei Skalierung: Convex Cloud mit EU-Standort. Conv | 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) +### Aktuell aktivierte Modelle (Phase 1) -| Modell | ID | Credits | Tier-Zugang | -|--------|-----|---------|-------------| -| Gemini 2.5 Flash Image | google/gemini-2.5-flash-image | 4 Cr | Alle Tiers | +Alle 9 Image-Modelle sind aktiviert. Server-seitiges Tier-Enforcement prĂŒft `minTier` pro Modell. Der Prompt-Node bietet einen tier-aware Model Selector. -> Weitere Modelle werden in Phase 2 freigeschaltet (Modellauswahl-UI im Canvas). +| Modell | ID | Credits | Tier-Zugang | Modalities | +|--------|-----|---------|-------------|------------| +| Gemini 2.5 Flash | google/gemini-2.5-flash-image | 4 Cr | Alle Tiers | image + text | +| FLUX.2 Klein 4B | black-forest-labs/flux.2-klein-4b | 2 Cr | Alle Tiers | image only | +| Seedream 4.5 | bytedance-seed/seedream-4.5 | 5 Cr | Alle Tiers | image only | +| Gemini 3.1 Flash Image | google/gemini-3.1-flash-image-preview | 6 Cr | Alle Tiers | image + text | +| GPT-5 Image Mini | openai/gpt-5-image-mini | 8 Cr | Ab Starter | image + text | +| Riverflow V2 Fast | sourceful/riverflow-v2-fast | 9 Cr | Ab Starter | image only | +| Riverflow V2 Pro | sourceful/riverflow-v2-pro | 12 Cr | Ab Starter | image only | +| Gemini 3 Pro Image | google/gemini-3-pro-image-preview | 13 Cr | Ab Starter | image + text | +| GPT-5 Image | openai/gpt-5-image | 15 Cr | Ab Starter | image + text | + +> **Request Modalities:** Modelle mit `image only` senden `modalities: ["image"]`, alle anderen `modalities: ["image", "text"]`. Dies wird in `convex/openrouter.ts` ĂŒber das `requestModalities`-Feld gesteuert. ### Self-hosted Services @@ -466,12 +478,15 @@ 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 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 | -| Bildgen. (Pro Text/4K) | Riverflow V2 Pro | ~€0,33 | 1,5× | 50 Cr | Ab Starter | +| Bildgenerierung (Standard) | Gemini 2.5 Flash | ~€0,04 | 1× | 4 Cr | Alle Tiers | +| Bildgenerierung (Budget) | FLUX.2 Klein 4B | ~€0,02 | 1× | 2 Cr | Alle Tiers | +| Bildgenerierung (Standard) | Seedream 4.5 | ~€0,05 | 1× | 5 Cr | Alle Tiers | +| Bildgenerierung (Standard+) | Gemini 3.1 Flash Image | ~€0,06 | 1× | 6 Cr | Alle Tiers | +| Bildgenerierung (Premium) | GPT-5 Image Mini | ~€0,08 | 1× | 8 Cr | Ab Starter | +| Bildgenerierung (Premium) | Riverflow V2 Fast | ~€0,09 | 1× | 9 Cr | Ab Starter | +| Bildgenerierung (Premium) | Riverflow V2 Pro | ~€0,12 | 1× | 12 Cr | Ab Starter | +| Bildgenerierung (Premium) | Gemini 3 Pro Image | ~€0,13 | 1× | 13 Cr | Ab Starter | +| Bildgenerierung (Ultra) | GPT-5 Image | ~€0,15 | 1× | 15 Cr | Ab Starter | | Agent Reasoning (leicht) | Claude Sonnet | ~€0,03 | 3× | 9 Cr | Ab Starter | | Agent Reasoning (mittel) | Claude Sonnet | ~€0,06 | 2,5× | 15 Cr | Ab Starter | | Agent-Run (komplex) | Multi-Step Workflow | ~€0,15 | 2,5× | 38 Cr | Ab Starter | @@ -590,6 +605,12 @@ Agent Status: analyzing | Video Browser | ✅ Erledigt | | Connection Policy (Edge-Validierung) | ✅ Erledigt | | Adjustment Presets (Built-in + User-defined) | ✅ Erledigt | +| VollstĂ€ndige OpenRouter Image Gen (alle 9 Modelle + Tier-Enforcement) | ✅ Erledigt | +| Tier-aware Model Selector im Prompt-Node | ✅ Erledigt | +| Dashboard Snapshot Cache (gebĂŒndelte Query + localStorage) | ✅ Erledigt | +| Credits Activity Analytics (Recharts Chart) | ✅ Erledigt | +| Canvas Graph Query Cache (Performance-Optimierung) | ✅ Erledigt | +| AI Modularisierung (`ai_errors.ts`, `ai_retry.ts`, `ai_node_data.ts`) | ✅ Erledigt | | docker-compose.yml + .env.example + Setup-README | ☐ Offen | ### Phase 2 — KI-Features @@ -605,8 +626,6 @@ Agent Status: analyzing | Task | Status | |------|--------| -| VollstĂ€ndige OpenRouter Image Gen Integration (alle 9 Modelle) | ☐ Offen | -| 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 | ☐ Offen | @@ -632,7 +651,7 @@ Agent Status: analyzing | Versions-History | ☐ Offen | | Weitere Agent Templates | ☐ Offen | | Export-Funktionen (PNG, PDF, ZIP) | ☐ Offen | -| Performance-Optimierung fĂŒr große Canvases | ☐ Offen | +| Performance-Optimierung fĂŒr große Canvases | ✅ Erledigt | --- @@ -646,7 +665,7 @@ Agent Status: analyzing | Payment Provider | ✅ Polar (Merchant of Record, VAT-Handling) | | 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, Phase 1: nur Gemini 2.5 Flash aktiv | +| OpenRouter Image-Modelle | ✅ Alle 9 Modelle aktiv mit serverseitigem Tier-Enforcement | | 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 | @@ -721,4 +740,4 @@ Die Software wird unter der Business Source License 1.1 (BSL 1.1) veröffentlich --- -*LemonSpace PRD v2.0 — April 2026* +*LemonSpace PRD v2.1 — April 2026* diff --git a/components/canvas/CLAUDE.md b/components/canvas/CLAUDE.md index b5b5645..aa363e8 100644 --- a/components/canvas/CLAUDE.md +++ b/components/canvas/CLAUDE.md @@ -36,6 +36,8 @@ app/(app)/canvas/[canvasId]/page.tsx | `canvas-delete-handlers.ts` | Hook fĂŒr `onBeforeDelete`, `onNodesDelete`, `onEdgesDelete` inkl. Bridge-Edges | | `canvas-reconnect.ts` | Hook fĂŒr Edge-Reconnect (`onReconnectStart`, `onReconnect`, `onReconnectEnd`) | | `canvas-media-utils.ts` | Media-Helfer wie `getImageDimensions(file)` | +| `use-canvas-data.ts` | Hook: BĂŒndelt Canvas-Graph-Query, Storage-URL-Auflösung und Auth-State in einer einzigen Abstraktion | +| `canvas-graph-query-cache.ts` | Optimistic Store Helper fĂŒr `canvasGraph.get` (getNodes, getEdges, setNodes, setEdges) | --- @@ -231,6 +233,39 @@ Im **Light Mode** wird der eigentliche Edge-`stroke` ebenfalls aus dieser Akzent --- +## Canvas Graph Query Cache + +Performance-Optimierung: Statt separater Queries fĂŒr Nodes und Edges nutzt der Canvas eine einzige gebĂŒndelte Query (`canvasGraph.get`), die ĂŒber einen Optimistic Store Layer lĂ€uft. + +**Architektur:** +``` +useCanvasData (use-canvas-data.ts) + ├── canvasGraphQuery (canvasGraph.get) ← Einzelne gebĂŒndelte Query + ├── canvasGraphQueryCache (Optimistic Store Helper) + │ ├── getCanvasGraphNodesFromQuery() + │ ├── getCanvasGraphEdgesFromQuery() + │ ├── setCanvasGraphNodesInQuery() + │ └── setCanvasGraphEdgesInQuery() + ├── Storage URL Resolution (batchGetUrlsForCanvas) + └── Auth State (authClient.useSession + useConvexAuth) +``` + +**Vorteil:** Optimistic Updates (Node-Erstellung, Edge-Erstellung etc.) aktualisieren den Optimistic Store direkt, ohne auf die Server-BestĂ€tigung warten zu mĂŒssen. Die separaten Node/Edge-Queries wurden durch diesen Ansatz abgelöst. + +**`use-canvas-data.ts`:** +- Kapselt den gesamten Canvas-Datenfluss: Graph-Query → Storage-URLs → fertige Daten +- `shouldSkipCanvasQueries` verhindert API-Calls vor Auth-Ready +- `storageIdsForCanvas` extrahiert Storage-IDs aus Nodes und löst sie via `batchGetUrlsForCanvas` auf +- Development-Logging fĂŒr Auth-State-Debugging + +**`canvas-graph-query-cache.ts`:** +- Typisierter Zugriff auf den Convex Optimistic Local Store +- `canvasGraphQuery` — Typ-safe Reference auf `api.canvasGraph.get` +- `getCanvasGraphNodesFromQuery/EdgesFromQuery` — Lesen +- `setCanvasGraphNodesInQuery/EdgesInQuery` — Schreiben (fĂŒr Optimistic Updates) + +--- + ## Wichtige Gotchas - **`data.url` vs `storageId`:** Node-Komponenten erhalten `data.url` (aufgelöste HTTP-URL), nicht `storageId` direkt. Die URL wird von `convexNodeDocWithMergedStorageUrl` injiziert. Bei neuen Node-Typen mit Bild immer diesen Flow prĂŒfen. @@ -244,3 +279,4 @@ Im **Light Mode** wird der eigentliche Edge-`stroke` ebenfalls aus dieser Akzent - **Node-Taxonomie:** Alle Node-Typen sind in `lib/canvas-node-catalog.ts` definiert. Phase-2/3 Nodes haben `implemented: false` und `disabledHint`. - **Video-Connection-Policy:** `video-prompt` darf **nur** mit `ai-video` verbunden werden (und umgekehrt). `text → video-prompt` ist erlaubt (Prompt-Quelle). `ai-video → compare` ist erlaubt. - **Convex Generated Types:** `api.ai.generateVideo` wird u. U. nicht in `convex/_generated/api.d.ts` exportiert. Der Code verwendet `api as unknown as {...}` als Workaround. Ein `npx convex dev`-Zyklus wĂŒrde die Typen korrekt generieren. +- **Canvas Graph Query:** Der Canvas nutzt `canvasGraph.get` (aus `convex/canvasGraph.ts`) statt separater `nodes.list`/`edges.list` Queries. Optimistic Updates laufen ĂŒber `canvas-graph-query-cache.ts`. diff --git a/components/dashboard/CLAUDE.md b/components/dashboard/CLAUDE.md index d792c16..7bff2c1 100644 --- a/components/dashboard/CLAUDE.md +++ b/components/dashboard/CLAUDE.md @@ -10,93 +10,123 @@ UI-Komponenten fĂŒr die Startseite nach dem Login. |-------|-------| | `canvas-card.tsx` | Karte fĂŒr einen Canvas in der Übersicht (Navigation, Umbenennen, Löschen mit Confirm-Dialog) | | `credit-overview.tsx` | Monatsverbrauch und verfĂŒgbare Credits als Balken-Visualisierung | +| `credits-activity-chart.tsx` | Credits-AktivitĂ€ts-Chart (Recharts AreaChart) mit Verbrauch, AktivitĂ€t und verfĂŒgbaren Credits | | `recent-transactions.tsx` | Liste der letzten Credit-Transaktionen | --- ## Layout-Seite -`app/dashboard/page.tsx` — Server Component, rendert Dashboard-Layout mit den Komponenten oben. +`app/dashboard/page-client.tsx` — Client Component, rendert Dashboard mit gebĂŒndelter Snapshot-Query. **Layout-Struktur:** ``` Dashboard -├── Header (User-Avatar, Name) -├── Quick Actions (Create Canvas, Search) -├── Credit Overview (Balance, Usage Bars) -├── Recent Transactions (List) -└── Canvas Grid (Canvas Cards) +├── Header (Logo, Suche, User-MenĂŒ mit Theme-Wechsel) +├── BegrĂŒĂŸung (Name, Untertitel) +├── Credit-Übersicht (Balance, Usage Bars) +├── Arbeitsbereiche (Canvas Grid) +├── Credits Verlauf + Transaktionen (zwei-spaltig) +│ ├── CreditsActivityChart (Recharts AreaChart) +│ └── Recent Transactions (List) ``` --- +## Dashboard Snapshot Architecture + +**FrĂŒher:** Separate Convex-Queries fĂŒr Balance, Subscription, UsageStats, Transactions, Canvases → 5+ gleichzeitige Queries. + +**Jetzt:** GebĂŒndelte Snapshot-Query (`api.dashboard.getSnapshot`) + localStorage-Cache. + +### Datenfluss + +``` +page-client.tsx + └── useDashboardSnapshot(userId) + ├── Convex Query: api.dashboard.getSnapshot (gebĂŒndelt) + │ → Balance + Subscription + UsageStats + Transactions + Canvases + ├── localStorage Cache: readDashboardSnapshotCache (12h TTL) + │ → Sofortige Anzeige aus Cache wĂ€hrend Query lĂ€dt + └── Automatisches Cache-Write bei neuen Query-Daten +``` + +### Snapshot Cache (`lib/dashboard-snapshot-cache.ts`) + +- **Key:** `lemonspace.dashboard:snapshot:v1:` +- **TTL:** 12 Stunden (DEFAULT_TTL_MS) +- **Version:** `CACHE_VERSION = 1` — Version-Bumps invalidieren automatisch +- **Cache-Invalidierung:** Bei Logout wird der Cache des vorherigen Users gelöscht (via `sessionStorage("ls-last-dashboard-user")`) +- Defensiv: Alle Storage-Zugriffe sind try-catch-gewrappt (Quota-Fehler, Disabled Storage etc.) + +### Snapshot Query (`convex/dashboard.ts`) + +- `getSnapshot` — GebĂŒndelte Query, lĂ€dt alle Dashboard-Daten in einem Convex-Call +- Nutzt `optionalAuth` → Default-Werte bei fehlender Session (kein Error) +- Transaktions-Priorisierung via `prioritizeRecentCreditTransactions` (Usage > Reservation > Refund > Topup > Subscription) + +--- + ## Datenquellen -Alle Daten kommen aus Convex-Queries via `useAuthQuery` (aus `hooks/use-auth-query.ts`): +| Komponente | Datenquelle | +|-----------|-------------| +| `credit-overview.tsx` | `dashboardSnapshot.balance`, `dashboardSnapshot.subscription`, `dashboardSnapshot.usageStats` | +| `credits-activity-chart.tsx` | `dashboardSnapshot.balance`, `dashboardSnapshot.recentTransactions` | +| `recent-transactions.tsx` | `dashboardSnapshot.recentTransactions` | +| `canvas-card.tsx` | `dashboardSnapshot.canvases` | -| Komponente | Query | -|-----------|-------| -| `canvas-card.tsx` | `api.canvases.list` | -| `credit-overview.tsx` | `api.credits.getBalance`, `api.credits.getUsageStats` | -| `recent-transactions.tsx` | `api.credits.getRecentTransactions` | +> Alle Daten kommen aus dem gebĂŒndelten Snapshot (`useDashboardSnapshot`). Keine separaten Queries mehr. ## Mutations | Komponente | Mutation | |-----------|----------| | `canvas-card.tsx` | `api.canvases.update`, `api.canvases.remove` | +| `page-client.tsx` | `api.canvases.create` | + +--- + +## Credits Activity Chart + +Recharts-basiertes AreaChart (via ShadCN `ChartContainer`) mit drei Datenseries: + +- **Usage** (gefĂŒllt): TatsĂ€chlicher Credit-Verbrauch pro Tag (committed usage-Transactions) +- **Activity** (gefĂŒllt): Usage + aktive Reservationen pro Tag +- **Available** (Linie): Aktueller verfĂŒgbarer Credit-Stand als Referenzlinie + +**Daten-Processing:** `lib/credits-activity.ts` +- `buildCreditsActivitySeries()` — Gruppiert Transactions nach Tag, aggregiert Usage/Activity +- `calculateUsageActivityDomain()` — Berechnet Y-Achsen-Domain mit Headroom +- `prioritizeRecentCreditTransactions()` — Sortiert Transactions nach Typ-PrioritĂ€t + +**Chart Config:** Teal fĂŒr Usage, Accent-Foreground fĂŒr Activity, Muted-Foreground fĂŒr Available. --- ## 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) +- Kein lokaler State fĂŒr Server-Daten — Snapshot kommt aus `useDashboardSnapshot` +- Dashboard zeigt sofort Cache-Daten an, wĂ€hrend Live-Query lĂ€dt (`source: "cache" | "live" | "none"`) - 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) +- Responsive Grid-Layout fĂŒr Canvas-Cards (`grid-cols-1 sm:grid-cols-3`) +- Leere ZustĂ€nde (keine Canvases, keine Transaktionen, keine Chart-Daten) mit nutzerfreundlichen Platzhaltern zeigen +- Chart-Komponente nutzt ShadCN `ChartContainer` (`components/ui/chart.tsx`) + Recharts 3.8 --- ## 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 +- **Auth-Race:** `useDashboardSnapshot` nutzt `useAuthQuery` intern → skippt bis Auth bereit +- **Empty States:** Wenn keine Canvases/Transaktionen vorhanden sind, informative Platzhalter zeigen +- **Cache-Fehler:** localStorage-Zugriffe sind defensiv gewrappt (quota, disabled storage) +- **Offline:** Snapshot-Cache bietet Fallback bei fehlender Verbindung --- ## 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 +- GebĂŒndelte Snapshot-Query statt 5+ separater Queries → weniger WebSocket-Last +- localStorage-Cache mit 12h TTL → sofortige Anzeige bei wiederholtem Besuch +- Canvas-Thumbnails werden ĂŒber den Snapshot geladen (nur wenn vorhanden) +- Transaktions-Liste ist auf 20 EintrĂ€ge limitiert (priorisiert nach Typ) diff --git a/components/ui/CLAUDE.md b/components/ui/CLAUDE.md index 883a45f..37a3911 100644 --- a/components/ui/CLAUDE.md +++ b/components/ui/CLAUDE.md @@ -62,6 +62,7 @@ transition: all 200ms cubic-bezier(0.16, 1, 0.3, 1); /* expo-out */ | `badge` | `components/ui/badge.tsx` | Status-Tags, Badges | | `tooltip` | `components/ui/tooltip.tsx` | Explainer-Texte | | `separator` | `components/ui/separator.tsx` | Trennungen | +| `chart` | `components/ui/chart.tsx` | ShadCN Chart-Wrapper fĂŒr Recharts (ChartContainer, ChartTooltip, ChartLegend) | --- @@ -77,3 +78,18 @@ npx shadcn@latest add input ``` Komponenten werden direkt in `components/ui/` abgelegt. Lokale Anpassungen erfolgen durch Überladen von Props oder direkt in der Komponentendatei. + +--- + +## Chart-Komponente (`chart.tsx`) + +ShadCN-Wrapper fĂŒr Recharts v3.8. Bietet konsistentes Styling fĂŒr Chart-Elemente: + +- `ChartContainer` — Root-Wrapper mit CSS-Variablen-basierten Farben +- `ChartTooltip` / `ChartTooltipContent` — Tooltip mit Design-Token-Support +- `ChartLegend` / `ChartLegendContent` — Legende mit konsistentem Styling +- `ChartConfig` — Typ fĂŒr Chart-Farbkonfiguration + +**Verwendung:** Dashboard Credits Activity Chart. Farben ĂŒber CSS-Variablen (`hsl(var(--primary))` etc.). + +**AbhĂ€ngigkeit:** `recharts` v3.8.0 (in `package.json`). diff --git a/convex/CLAUDE.md b/convex/CLAUDE.md index da30791..1f86320 100644 --- a/convex/CLAUDE.md +++ b/convex/CLAUDE.md @@ -27,6 +27,11 @@ Convex ist das vollstĂ€ndige Backend von LemonSpace: Datenbank, Realtime-Subscri | `storage.ts` | Convex File Storage Helpers + gebĂŒndelte Canvas-URL-Auflösung | | `export.ts` | Canvas-Export-Logik | | `http.ts` | HTTP-Endpunkte (Webhooks) | +| `dashboard.ts` | GebĂŒndelte Dashboard-Snapshot-Query (Balance, Subscription, Usage, Transactions, Canvases in einem Call) | +| `canvasGraph.ts` | Canvas Graph Query — Performance-optimierte Query fĂŒr Nodes+Edges in einem Call | +| `ai_errors.ts` | Error-Kategorisierung und User-facing Fehlermeldungen (aus `ai.ts` extrahiert) | +| `ai_node_data.ts` | Node-Data-Helpers (z. B. `getNodeDataRecord`) | +| `ai_retry.ts` | Retry-Logik fĂŒr AI-Generierung (`generateImageWithAutoRetry`, aus `ai.ts` extrahiert) | --- @@ -247,6 +252,7 @@ Wirft bei unauthentifiziertem Zugriff. Wird von allen Queries und Mutations genu - `credits.getSubscription` fĂ€llt bei fehlender Session auf Free/Active zurĂŒck (statt Throw), damit Tier-UI stabil bleibt. - `credits.getRecentTransactions` gibt bei fehlender Session `[]` zurĂŒck (statt Throw), damit AktivitĂ€tslisten beim Logout sauber leeren. - `credits.getUsageStats` gibt bei fehlender Session `0`-Statistiken zurĂŒck (statt Throw), damit Verbrauchsanzeigen ohne Fehler ausrendern. +- `dashboard.getSnapshot` gibt bei fehlender Session einen vollstĂ€ndigen Default-Snapshot zurĂŒck (Balance 0, Free-Tier, leere Listen) ### Idempotente Canvas-Mutations @@ -305,6 +311,37 @@ Wirft bei unauthentifiziertem Zugriff. Wird von allen Queries und Mutations genu --- +## Dashboard Snapshot (`dashboard.ts`) + +GebĂŒndelte Query, die alle Dashboard-relevanten Daten in einem einzigen Convex-Call lĂ€dt. Ersetzt separate Queries fĂŒr Balance, Subscription, UsageStats, Transactions und Canvases. + +**`getSnapshot` (query, public):** +- Nutzt `optionalAuth` — gibt bei fehlender Session Default-Werte zurĂŒck (kein Throw) +- LĂ€dt parallel: `creditBalances`, `subscriptions`, `creditTransactions` (usage-type), `creditTransactions` (recent, max 80), `canvases` +- Berechnet `monthlyUsage` und `totalGenerations` aus usage-Transactions des aktuellen Monats +- Nutzt `prioritizeRecentCreditTransactions` aus `lib/credits-activity.ts` fĂŒr sortierte Transaktionsliste +- Gibt strukturiertes Snapshot-Objekt zurĂŒck: `{ balance, subscription, usageStats, recentTransactions, canvases, generatedAt }` + +--- + +## Canvas Graph Query (`canvasGraph.ts`) + +Performance-optimierte Query, die Nodes und Edges fĂŒr einen Canvas in einem einzigen Call lĂ€dt. Wird vom Frontend ĂŒber den Canvas Graph Query Cache verwendet. + +**`loadCanvasGraph(ctx, { canvasId, userId })` (internal):** +- PrĂŒft Canvas-Existenz und Ownership +- LĂ€dt Nodes und Edges parallel via `Promise.all` +- Performance-Logging bei Queries > 250ms + +**`get` (query, public):** +- Nutzt `requireAuth` +- Delegiert an `loadCanvasGraph` +- Loggt bei langsamer AusfĂŒhrung (`PERFORMANCE_LOG_THRESHOLD_MS = 250`) + +**Frontend-Integration:** Der Canvas nutzt diese Query ĂŒber `canvas-graph-query-cache.ts` (Optimistic Store Helper). + +--- + ## Konventionen - `internalMutation` / `internalAction` — Nur von anderen Convex-Funktionen aufrufbar, nicht direkt vom Client. diff --git a/hooks/CLAUDE.md b/hooks/CLAUDE.md index d05a557..5b1c34f 100644 --- a/hooks/CLAUDE.md +++ b/hooks/CLAUDE.md @@ -87,6 +87,30 @@ const { isOnline, pendingOps, syncStatus } = useCanvasSyncStatus() --- +### `use-dashboard-snapshot.ts` + +Hook fĂŒr gebĂŒndeltes Dashboard-Datenladen mit localStorage-Cache. Ersetzt separate Queries fĂŒr Balance, Subscription, UsageStats, Transactions und Canvases. + +**Features:** +- GebĂŒndelte Convex-Query (`api.dashboard.getSnapshot`) in einem Call +- Automatisches Caching im localStorage (12h TTL) +- Sofortige Anzeige aus Cache wĂ€hrend Live-Query lĂ€dt +- Cache-Invalidierung bei Logout (via sessionStorage Tracking) +- Source-Tracking: `{ snapshot, source: "live" | "cache" | "none" }` + +**Verwendung:** +```typescript +const { snapshot, source } = useDashboardSnapshot(userId) +// source="cache" → sofortige Anzeige aus Cache +// source="live" → aktuelle Daten vom Server +// source="none" → weder Cache noch Query vorhanden +``` + +**Typen:** +- `DashboardSnapshot` — VollstĂ€ndiger RĂŒckgabewert von `api.dashboard.getSnapshot` + +--- + ## Konventionen - Hooks immer mit `use-` Prefix im Dateinamen diff --git a/lib/CLAUDE.md b/lib/CLAUDE.md index bbf87a7..6f5f9c5 100644 --- a/lib/CLAUDE.md +++ b/lib/CLAUDE.md @@ -33,6 +33,8 @@ Geteilte Hilfsfunktionen, Typ-Definitionen und Konfiguration. Keine React-Kompon | `topup-calculator.ts` | Bonus-Staffel-Berechnung fĂŒr Credit-Top-Ups | | `format-time.ts` | Zeitformatierung (relative Zeitangaben) | | `utils.ts` | `cn()` (clsx + tailwind-merge), allgemeine Utilities | +| `credits-activity.ts` | Credits-AktivitĂ€ts-Analytics: Transaktions-Priorisierung, Activity-Series, Usage-Domain-Berechnung | +| `dashboard-snapshot-cache.ts` | localStorage-Cache fĂŒr Dashboard-Snapshots (12h TTL, versioniert) | --- @@ -198,6 +200,51 @@ Verwendet in `convex/ai.ts` (`pollVideoTask`) und `convex/freepik.ts` (`getVideo --- +## `credits-activity.ts` — Credits Analytics + +Analytics-Helpers fĂŒr die Dashboard Credits-AktivitĂ€ts-Anzeige. Wird von `components/dashboard/credits-activity-chart.tsx` und `convex/dashboard.ts` verwendet. + +**Kernfunktionen:** + +```typescript +// Transaktions-Priorisierung (Usage → Reservation → Refund → Topup → Subscription) +prioritizeRecentCreditTransactions(transactions, limit) + +// Tages-aggregierte Activity-Series fĂŒr Recharts (max. 7 Tage) +buildCreditsActivitySeries(transactions, availableCredits, locale, maxPoints?) + +// Y-Achsen-Domain mit Headroom (mind. 8, +20% Headroom) +calculateUsageActivityDomain(points) + +// Credit-Formatierung ("1.234 Cr") +formatCredits(value, locale) +``` + +**Typen:** +- `CreditTransactionLike` — Minimales Transaction-Interface fĂŒr Analytics +- `CreditActivityPoint` — Tages-Datenpunkt (`{ day, usage, activity, available }`) + +--- + +## `dashboard-snapshot-cache.ts` — Dashboard Snapshot Cache + +localStorage-basierter Cache fĂŒr Dashboard-Snapshot-Daten. + +```typescript +readDashboardSnapshotCache(userId, options?) // Cached Snapshot lesen (mit TTL-PrĂŒfung) +writeDashboardSnapshotCache(userId, snapshot) // Snapshot schreiben +clearDashboardSnapshotCache(userId) // Cache invalidieren +``` + +**Konfiguration:** +- Namespace: `lemonspace.dashboard` +- Key: `lemonspace.dashboard:snapshot:v1:` +- TTL: 12 Stunden (`DEFAULT_TTL_MS = 12 * 60 * 60 * 1000`) +- Version: `CACHE_VERSION = 1` — Bumps invalidieren bestehende Caches +- Alle Storage-Zugriffe defensiv (try-catch, quota handling) + +--- + ## `canvas-local-persistence.ts` — localStorage-Cache ```typescript