docs: add Sub-Dokumentation section to AGENTS.md and CLAUDE.md for improved documentation structure

- Introduced a new section detailing the Single Source of Truth for various components, linking to their respective CLAUDE.md files.
- Enhanced clarity on documentation organization across different areas of the project.
This commit is contained in:
2026-03-31 21:12:26 +02:00
parent 4723fdca16
commit 1e99251506
10 changed files with 669 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
# components/billing/ — Billing & Subscription UI
UI-Komponenten für Credit-Anzeige, Subscription-Management und Top-Up.
---
## Dateien
| Datei | Zweck |
|-------|-------|
| `pricing-cards.tsx` | Tier-Vergleich (Free / Starter / Pro / Max) |
| `manage-subscription.tsx` | Aktuelle Subscription verwalten (Upgrade, Kündigung) |
| `topup-panel.tsx` | Credit-Nachkauf-UI (fixe Pakete + Custom-Betrag) |
---
## Tier-Struktur
Tiers und ihre Credit-Mengen sind in `convex/credits.ts → TIER_CONFIG` definiert. Die Billing-UI liest diese Werte über Convex-Queries — keine doppelte Konfiguration hier.
```
Free: 50 Cr/Monat (€0)
Starter: 400 Cr/Monat (€8)
Pro: 3.300 Cr/Monat (€59)
Max: 6.700 Cr/Monat (€119)
```
**1 Credit = €0,01** — Diese Umrechnung überall konsistent verwenden.
---
## Payment-Integration
**Polar.sh** ist der aktuelle Payment-Provider (MoR, VAT-Handling). Webhooks landen in `convex/http.ts``convex/polar.ts`.
> Hinweis: `convex/schema.ts` enthält noch `lemonSqueezySubscriptionId`-Felder — Überbleibsel einer früheren Integration. Lemon Squeezy ist nicht mehr aktiv. Polar-Felder (`polarSubscriptionId`) sind maßgeblich.
---
## Credit-Balance im Dashboard
Die Credit-Balance wird auch in `components/dashboard/credit-overview.tsx` angezeigt. Beide Komponenten nutzen dieselbe Convex-Query (`api.credits.getBalance`).
---
## Konventionen
- 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`)

137
components/canvas/CLAUDE.md Normal file
View File

@@ -0,0 +1,137 @@
# components/canvas/ — Canvas-Engine
Der Canvas ist das Herzstück von LemonSpace. Er basiert auf `@xyflow/react` (React Flow) und synchronisiert seinen Zustand bidirektional mit Convex.
---
## Architektur
```
app/(app)/canvas/[canvasId]/page.tsx
└── <Canvas canvasId={...} /> ← components/canvas/canvas.tsx
├── <ReactFlowProvider>
│ └── <CanvasInner> ← Haupt-Komponente (2800 Zeilen)
│ ├── Convex useQuery ← Realtime-Sync
│ ├── nodeTypes Map ← node-types.ts
│ ├── localStorage Cache ← canvas-local-persistence.ts
│ └── Panel-Komponenten
└── Context Providers
```
**`canvas.tsx`** ist die zentrale Datei. Sie enthält die gesamte State-Management-Logik, Convex-Mutations, Optimistic Updates und Event-Handler. Sehr groß — vor Änderungen immer den genauen Abschnitt lesen.
---
## Convex ↔ React Flow Mapping
Convex und React Flow verwenden unterschiedliche Datenmodelle. Das Mapping liegt in `lib/canvas-utils.ts`:
| 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)` |
**Wichtig:** Convex speichert `positionX` / `positionY` als separate Felder. React Flow erwartet `position: { x, y }`. Niemals RF-Node-Objekte direkt in Convex schreiben.
**Status-Injection:** `convexNodeToRF` schreibt `_status`, `_statusMessage` und `retryCount` in `data`, damit Node-Komponenten darauf zugreifen können ohne das Node-Dokument direkt zu kennen.
**URL-Caching:** Images mit `storageId` werden über einen batch-Storage-URL-Query aufgelöst (`urlByStorage`-Map). Die vorherige URL wird in `previousDataByNodeId` gecacht, um Flackern beim Reload zu vermeiden.
---
## 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`)
```
image: 280 × 200 prompt: 288 × 220
text: 256 × 120 ai-image: 320 × 408
group: 400 × 300 frame: 400 × 300
note: 208 × 100 compare: 500 × 380
```
---
## Node-Status-Modell
```
idle → analyzing → clarifying → executing (retry N/2) → done
→ error
```
Status + `statusMessage` werden direkt am Node angezeigt. Kein globales Loading-Banner. Bei `error` zeigt `statusMessage` die Kategorie: `Credits: ...`, `Timeout: ...`, `Provider: ...` etc.
---
## Edge-Glow-System
Jede Edge bekommt einen `drop-shadow`-Filter entsprechend dem Quell-Node-Typ. Farben in `lib/canvas-utils.ts → SOURCE_NODE_GLOW_RGB`:
- `prompt`, `ai-image` → Violett (139, 92, 246)
- `image`, `text`, `note` → Teal (13, 148, 136)
- `frame` → Orange (249, 115, 22)
- `group`, `compare` → Grau (100, 116, 139)
Compare-Node hat zusätzlich Handle-spezifische Farben (`left` → Blau, `right` → Smaragd).
---
## 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.
**localStorage-Cache** (`lib/canvas-local-persistence.ts`): Snapshot + Ops-Queue pro Canvas-ID.
- Key-Schema: `lemonspace.canvas:snapshot:v1:<canvasId>` und `lemonspace.canvas:ops:v1:<canvasId>`
- Snapshot = letzter bekannter State (Nodes + Edges) für schnellen initialen Render
- Ops-Queue = ausstehende Mutations (Recovery bei Verbindungsabbruch, Konzept — noch nicht vollständig implementiert)
---
## Panel-Komponenten
| Datei | Zweck |
|-------|-------|
| `canvas-toolbar.tsx` | Werkzeug-Leiste (Select, Pan, Zoom-Controls) |
| `canvas-app-menu.tsx` | App-Menü (Einstellungen, Logout, Canvas-Name) |
| `canvas-sidebar.tsx` | Node-Palette (linke Seite) |
| `canvas-command-palette.tsx` | Cmd+K Command Palette |
| `canvas-connection-drop-menu.tsx` | Kontext-Menü beim Loslassen einer Verbindung |
| `canvas-node-template-picker.tsx` | Node aus Template einfügen |
| `canvas-placement-context.tsx` | Context für Drag-and-Drop-Platzierung |
| `asset-browser-panel.tsx` | Freepik/Stock-Asset-Browser |
| `video-browser-panel.tsx` | Video-Asset-Browser |
| `canvas-user-menu.tsx` | User-Avatar und Menü |
| `credit-display.tsx` | Credit-Balance Anzeige in der Toolbar |
| `export-button.tsx` | Export-Button mit Format-Auswahl |
| `connection-banner.tsx` | Offline-Banner bei Convex-Verbindungsverlust |
| `custom-connection-line.tsx` | Angepasste temporäre Verbindungslinie |
---
## 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.
- **Min-Zoom:** `CANVAS_MIN_ZOOM = 0.5 / 3` — dreimal weiter raus als React-Flow-Default.
- **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`.

View File

@@ -0,0 +1,39 @@
# components/dashboard/ — Dashboard
UI-Komponenten für die Startseite nach dem Login.
---
## Dateien
| Datei | Zweck |
|-------|-------|
| `canvas-card.tsx` | Karte für einen Canvas in der Übersicht (Thumbnail, Name, Datum) |
| `credit-overview.tsx` | Monatsverbrauch und verfügbare Credits als Balken-Visualisierung |
| `recent-transactions.tsx` | Liste der letzten Credit-Transaktionen |
---
## Datenquellen
Alle Daten kommen aus Convex-Queries via `useAuthQuery` (aus `hooks/use-auth-query.ts`):
| Komponente | Query |
|-----------|-------|
| `canvas-card.tsx` | `api.canvases.list` |
| `credit-overview.tsx` | `api.credits.getBalance`, `api.credits.getUsageStats` |
| `recent-transactions.tsx` | `api.credits.getRecentTransactions` |
---
## 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

51
components/ui/CLAUDE.md Normal file
View File

@@ -0,0 +1,51 @@
# components/ui/ — Design System
ShadCN-Komponenten mit LemonSpace-spezifischen Anpassungen. Neue UI-Primitive immer hier ablegen.
---
## Stack
- **ShadCN UI** — Komponentenbibliothek (copy-paste, nicht installiertes Paket)
- **Tailwind CSS v4** — Utility-first, config in `globals.css` (kein `tailwind.config.ts` in v4)
- **Manrope** — Primäre Schrift (`--font-sans`), geladen via `next/font/google`
---
## Design-Token-Konventionen
Tokens folgen dem Manifest: **Teal-Primary, warme Neutraltöne (Sand/Beige), Zitronengelb als Akzent**.
```css
/* Primärfarbe */
--primary: teal /* Hauptaktionen, Links, aktive States */
/* Neutraltöne — immer warm tönen */
--background: warm-white /* Nie kaltes #fff oder gray-50 */
--muted: sand/beige /* Sekundäre Hintergründe */
--border: warm-gray /* Niemals kaltes gray-200 */
/* Akzentfarbe */
--accent: lemon-yellow /* Sparsam einsetzen — Highlights, Badges */
```
**Anti-Pattern:** Kalte Grautöne (`gray-100`, `slate-200`) ohne Wärme-Anpassung. Immer Richtung Sand/Beige tönen.
---
## Animationen
Übergänge mit **exponentiellem Easing** (`ease-out` / `cubic-bezier`). Keine linearen Transitions.
```css
transition: all 200ms cubic-bezier(0.16, 1, 0.3, 1); /* expo-out */
```
---
## Neue Komponenten
1. ShadCN-Komponente mit `npx shadcn@latest add <name>` hinzufügen
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