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.

This commit is contained in:
Matthias
2026-04-08 14:03:16 +02:00
parent 87d78e4c99
commit a7eb2bc99c
8 changed files with 283 additions and 73 deletions

View File

@@ -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:<userId>`
- **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)