Dashboard/Index
Zentrales Dashboard mit Follower-Verlauf, Winners/Losers-Listen und Top-Ranglisten fuer den aktuellen Workspace.
Route: /dashboard
View: resources/views/livewire/dashboard/index.blade.php
Location: app/Livewire/Dashboard/Index.php
Public Properties
| Property | Typ | Default | Query String | Beschreibung |
|---|---|---|---|---|
$workspace | Workspace|null | -- | nein | Aktueller Workspace (Route-Model oder Default) |
$period | string | '7d' | ja | Zeitraum: '3d', '7d', '14d' |
$chartSeries | string | 'followers' | ja | Chart-Metrik: followers, views, videos, etc. |
$onlyFavorites | bool | false | ja | Nur Favoriten anzeigen |
$winners | array | [] | nein | Top-Gewinner des Zeitraums |
$losers | array | [] | nein | Top-Verlierer des Zeitraums |
$topFollowers | array | [] | nein | Top-Profile nach Followern |
$topGrowth | array | [] | nein | Top-Profile nach prozentualem Wachstum |
$chartData | array | [] | nein | Kumulative Chart-Daten |
$chartXTickValues | array | [] | nein | X-Achsen-Ticks (Datumswerte) |
$chartYTickValues | array | [] | nein | Y-Achsen-Ticks (gerundete Schrittweiten) |
$chartMax | int | 0 | nein | Maximaler Chart-Wert |
$rangeEndDate | string|null | null | nein | End-Datum fuer Navigation |
$canGoPrevious | bool | false | nein | Rueckwaerts-Navigation verfuegbar |
$canGoNext | bool | false | nein | Vorwaerts-Navigation verfuegbar |
Verfuegbare Metriken
| Metrik | Label | Verfuegbar fuer |
|---|---|---|
followers | Follower | YouTube, Instagram |
views | Views | YouTube |
videos | Videos | YouTube |
posts | Beitraege | |
following | Following |
Actions
| Method | Beschreibung |
|---|---|
updatedPeriod() | Daten fuer neuen Zeitraum laden |
updatedChartSeries() | Chart-Daten fuer neue Metrik laden |
updatedOnlyFavorites() | Filter umschalten, Daten neu laden |
goPreviousRange() | Zeitfenster zurueck verschieben |
goNextRange() | Zeitfenster vor verschieben |
Datenquellen
Die Dashboard-Daten werden aus vorberechneten Rollups geladen -- nicht live aus den Metriken-Tabellen:
dashboard_workspace_snapshots: Workspace-spezifische Aggregate pro PeriodeSocialProfileDailyMetric: Fallback fuer Chart-Daten falls kein Snapshot
Die Rollups werden taeglich um 00:10 UTC durch dashboard:rollup-daily-metrics erzeugt.
Workspace-Switcher
Der Workspace-Kontext wird ueber die separate WorkspaceSwitcher-Komponente im Header gesetzt. Dashboard reagiert auf Workspace-Wechsel durch Neuinitialisierung in mount().
Date-Range-Navigation
Der Zeitraum laesst sich in Schritten der gewaehlten Periodenlaenge (3/7/14 Tage) vor- und zurueckblaetern. Die Navigation wird begrenzt durch:
- Rueckwaerts: Fruehester verfuegbarer Datenpunkt
- Vorwaerts: Gestern (aktuellster vollstaendiger Tag)
Events
| Richtung | Event | Beschreibung |
|---|---|---|
| dispatch | show-toast | Fehlermeldungen bei Datenlade-Problemen |
| listen | daily-scrape-completed | Daten nach Scrape-Abschluss neu laden |
Performance
- Rollup-basiert statt Live-Queries
chunkById()fuer grosse Workspace-AggregationenwithCount()statt separate Queries- Charts nutzen native Flux UI
<flux:chart>Komponenten (Achsen-Skalierung automatisch)
Sub-Components
Das Dashboard bindet zwei eigenstaendige Slider-Components ein, die unterhalb des Haupt-Charts angezeigt werden.
Dashboard/TrendingSlider
Horizontaler Slider mit aktuell trendigen Profilen (hoher Postbox Score 80–100), unabhaengig vom User-Tracking.
Route: Eingebettet in /dashboard
View: resources/views/livewire/dashboard/trending-slider.blade.php
Location: app/Livewire/Dashboard/TrendingSlider.php
Public Properties
| Property | Typ | Default | Beschreibung |
|---|---|---|---|
$trendingProfiles | array | [] | Bis zu 25 Trending-Profile |
$addedProfileIds | array | [] | Map social_profile_id → watcher_id fuer bereits getrackte Profile |
Actions
| Method | Beschreibung |
|---|---|
mount() | Laedt Trending-Profile aus Cache (1h TTL) |
addToWorkspace(int $socialProfileId) | Profil zum ersten regulaeren Workspace hinzufuegen (mit Kapazitaetspruefung) |
Datenquelle und Algorithmus
- Aktuelle Score-Berechnung aus
SocialProfileScoreermitteln (letztescalculated_atDatum) - Profile mit Score 80–100,
tracking_enabled=trueundnotExcluded()-Filter - Zufaellige Auswahl von 25 Profilen (
inRandomOrder()->limit(25)) - Sortierung nach Score absteigend fuer Anzeige
- Konditionale Ausschluss-Logik: User mit ≤1.000 Watchern sehen eigene Profile nicht; bei >1.000 keine Ausschlussfilterung
Cache: 1h TTL, Key "trending_slider:{$user->id}"
UI-Elemente pro Karte
- Profilbild mit Platform-Badge (YouTube/Instagram)
- Postbox Score Badge (oben links)
- Verified-/PRO-Badge (oben rechts)
- Handle, Follower-Count
- "Hinzufuegen"- oder "Ansehen"-Button
Dashboard/RecommendedProfiles
Personalisierter Empfehlungs-Slider ("Koennte dich interessieren") basierend auf den Kategorien der vom User getrackten Profile.
Route: Eingebettet in /dashboard
View: resources/views/livewire/dashboard/recommended-profiles.blade.php
Location: app/Livewire/Dashboard/RecommendedProfiles.php
Public Properties
| Property | Typ | Default | Beschreibung |
|---|---|---|---|
$recommendedProfiles | array | [] | Bis zu 25 empfohlene Profile |
$addedProfileIds | array | [] | Map social_profile_id → watcher_id |
Actions
| Method | Beschreibung |
|---|---|
mount() | Laedt Empfehlungen aus Cache (6h TTL) |
addToWorkspace(int $socialProfileId) | Profil zum ersten regulaeren Workspace hinzufuegen (mit Kapazitaetspruefung) |
Architektur: Global Pool + Per-User Personalisierung
Die Empfehlungen nutzen eine zweistufige Architektur fuer maximale Performance:
Stufe 1 — Globaler Pool (geteilt, 6h Cache):
- Top 1.000 Profile nach Postbox Score (≥50)
- Filter:
notExcluded(),tracking_enabled, keine "other"-Kategorie, Mindest-Follower - JOIN auf
explore_profile_metrics(Kategorie) +social_profile_scores(Score) - Inklusive vorberechneter Kategorie-Metadata (Icon, deutsches Label)
- Cache-Key:
recommended_profiles_global_pool
Stufe 2 — Per-User Personalisierung (6h Cache pro User):
- 1 Query: User's getrackte Profile-IDs laden (als Hash-Map fuer O(1)-Lookup)
- 1 Query: User's Kategorie-Praeferenzen (GROUP BY + ORDER BY auf
explore_profile_metrics) - Reines PHP: Pool filtern → getrackte Profile raus → nach User-Kategorien sortieren → 5 pro Kategorie → 25 total → Score-absteigend
graph TD
A["Globaler Pool (6h Cache)"] --> B["Top 1.000 nach Score"]
B --> C["Per-User Cache (6h)"]
C --> D["Getrackte Profile-IDs laden"]
D --> E["Getrackte aus Pool entfernen"]
E --> F["User-Kategorien ermitteln"]
F --> G["Nach Kategorien sortieren"]
G --> H["Max. 5 pro Kategorie"]
H --> I["Max. 25 total, Score desc"]
Performance: ~5ms pro User statt ~300ms+ (normal) / TIMEOUT (Admin mit 469k Watchern).
Cache:
- Global Pool: 6h TTL, Key
recommended_profiles_global_pool - Per-User: 6h TTL, Key
recommended_profiles:{$user->id}
UI-Elemente pro Karte
- Profilbild mit Platform-Badge
- Postbox Score Badge (oben links)
- Kategorie-Icon (oben rechts)
- Handle, Follower-Count, Kategorie-Label mit Icon
- "Hinzufuegen"- oder "Ansehen"-Button
Slider-Navigation (Alpine.js)
Beide Slider nutzen inline Alpine.js fuer horizontales Scrollen. Navigation per Pfeil-Buttons (links/rechts), die sich automatisch ein-/ausblenden:
- Linker Pfeil: Sichtbar wenn
scrollLeft > 0 - Rechter Pfeil: Sichtbar wenn
scrollLeft < maxScroll - Scroll-Logik:
scrollRight()nutztMath.min(rawScroll, maxScroll)um sicherzustellen, dass der letzte Slide korrektmaxScrollerreicht und der Pfeil verschwindet - Keine Tooltips: Karten zeigen keine nativen Browser-Tooltips (flux:tooltip entfernt)
Lazy Loading + Skeleton
Beide Slider-Components (TrendingSlider, RecommendedProfiles) nutzen #[Lazy] fuer asynchrones Laden per XHR. Waehrend des Ladens wird der gemeinsame Flux UI Skeleton-Platzhalter mit Shimmer-Animation angezeigt. Layout der Skeletons entspricht den tatsaechlichen Karten (Bildbereich, Textzeilen, Metriken, Button).
Shared Placeholder View: resources/views/livewire/partials/slider-placeholder.blade.php
Derselbe Placeholder wird auch von den Watcher-Slidern (RelatedChannels, RelatedProfiles, CrossPlatformRelated) verwendet. Alle horizontalen Profil-Slider teilen sich eine einzige View-Datei mit <flux:skeleton.group animate="shimmer"> und 7 Karten-Skeletons im w-48-Format.
Vergleich TrendingSlider vs. RecommendedProfiles
| Aspekt | TrendingSlider | RecommendedProfiles |
|---|---|---|
| Personalisierung | Keine (global) | Kategorie-basiert (Global Pool + User-Filter) |
| Cache TTL | 1 Stunde (per User) | 6h global + 6h per User |
| Score-Range | 80–100 | ≥50 |
| Auswahl | Zufaellig | Kategorie-gruppiert (max. 5/Kat.) |
| Badges | Verified/PRO | Kategorie-Icon |
| Max. Profile | 25 | 25 |
| Lazy Loading | Ja (#[Lazy]) | Ja (#[Lazy]) |