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:
50
components/billing/CLAUDE.md
Normal file
50
components/billing/CLAUDE.md
Normal 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
137
components/canvas/CLAUDE.md
Normal 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`.
|
||||
39
components/dashboard/CLAUDE.md
Normal file
39
components/dashboard/CLAUDE.md
Normal 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
51
components/ui/CLAUDE.md
Normal 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
|
||||
Reference in New Issue
Block a user