Zum Hauptinhalt springen

Watchers/Show

Detailseite eines Watchers mit Metriken-Charts, Profil-Info, Bild-Lightbox und Admin-Aktionen (Rescrape, Video Sync, Block, Score Penalty).

Route: /watcher/{watcher} View: resources/views/livewire/watchers/show.blade.php Location: app/Livewire/Watchers/Show.php

Public Properties

PropertyTypDefaultBeschreibung
$watcherWatcher--Route-Model-Binding
$confirmingDeleteboolfalseDelete-Confirmation Modal State
$showImageModalboolfalseBild-Lightbox State
$activeImageSourceIdint|nullnullAktive Source fuer Lightbox
$activeImageIndexint0Aktueller Bild-Index in Lightbox
$imageMaparray[]Source-ID => Bilder-Array
$favoriteProfileIdsarray[]Favorisierte Profile des Users
$moveWorkspaceIdint|nullnullZiel-Workspace fuer Move

Actions

MethodParameterAuthBeschreibung
confirmDelete()--UserDelete-Modal oeffnen
deleteWatcherConfirmed()--UserWatcher loeschen (Proxy)
deleteWatcher()CurrentWorkspace, FavoriteManagerUserWatcher + Sources loeschen, Profil bleibt
moveToWorkspace(int $id)Workspace-IDUserWatcher in anderen Workspace verschieben
toggleFavorite(int $sourceId)Source-IDUserFavorit-Status toggeln
openImageModal(int $sourceId, int $index)Source-ID, Bild-IndexUserLightbox oeffnen
closeImageModal()--UserLightbox schliessen
nextImage() / prevImage()--UserLightbox-Navigation
queuePriorityRescrape()--AdminPriority-Rescrape aller Sources queuen
requestYouTubeVideoStats()--AdminYouTube Video Stats Sync starten
enableYouTubeVideoAutoSync()--AdminAuto-Sync aktivieren + initialen Sync
disableYouTubeVideoAutoSync()--AdminAuto-Sync deaktivieren
toggleProfileBlock()--AdminProfil sperren/entsperren
toggleScorePenalty()--AdminScore-Strafe (25%) toggeln

Metriken-Charts

Pro Source/Profil werden plattformspezifische Metriken als Charts dargestellt:

YouTube:

  • Followers, Views, Videos, Kommentare

Instagram:

  • Followers, Following, Beitraege

Die Chart-Daten werden aus SocialProfileDailyMetric geladen (max. 180 Datenpunkte) und als Zeitserie mit optionalem Delta aufbereitet. Charts nutzen native Flux UI <flux:chart> Komponenten mit automatischer Achsen-Skalierung und Delta-Tooltips (Δ mit signDisplay).

Video Performance Summary

Fuer YouTube-Profile wird eine Video-Performance-Zusammenfassung berechnet:

// Basiert auf YouTubeVideoScore fuer den letzten verfuegbaren Tag
[
'date' => '2026-02-08',
'avg_score' => 72,
'total_scored' => 15,
'top_videos' => [...], // Top 3 nach Score
'flop_videos' => [...], // Bottom 3 nach Score
]

Location: buildVideoPerformanceSummary() in app/Livewire/Watchers/Show.php

Admin-only Features

Alle Admin-Aktionen sind durch $this->authorizeAdmin() geschuetzt (Gate::allows('admin')).

AI Enhancer Anzeige

Unterhalb der "Letzte Aktualisierung"-Zeile wird fuer Admins das Datum der letzten AI-Enhancer-Ausfuehrung angezeigt, sofern $profile->detected_at gesetzt ist. Sichtbarkeit via @can('admin') im Blade-Template.

Format: "Letzte Aktualisierung durch den AI-Enhancer: 9. Februar 2026, 14:30 Uhr"

Priority Rescrape

Erzeugt einen neuen WatcherImportRun und dispatcht ImportWatcherFromUrl-Jobs auf der Priority-Queue (imports-youtube-priority). Instagram-Sources nutzen den CollectorJobDispatcher mit erhoehter Priority.

YouTube Video Stats

  • requestYouTubeVideoStats(): Erstellt/aktualisiert YouTubeVideoSync-Eintrag und dispatcht SyncYouTubeVideoStats-Job (Queue: imports-youtube-video-priority, Mode: full). Aufruf via Form-POST an watchers.youtube-video-stats.
  • enableYouTubeVideoAutoSync() / disableYouTubeVideoAutoSync(): Toggle fuer Auto-Sync. Im View als Form-POST an dedizierte Controller-Routes implementiert (watchers.youtube-video-auto-sync.enable / .disable), da $wire-Calls innerhalb von Flux-Dropdowns unzuverlaessig sind (Dropdown schliesst vor Wire-Ausfuehrung).

Profil-Block

Toggelt blocked_at/blocked_by/block_reason auf dem SocialProfile. Geblockte Profile werden aus Explore, Related und Scoring ausgeschlossen.

Score Penalty

Toggelt manual_penalty zwischen 0 und 25 (25% Abzug auf den Postbox Score).

Events

RichtungEventBeschreibung
dispatchshow-toastErfolgs-/Fehlermeldungen
listenyoutube-sync-completedSeite neu laden nach Video-Sync

Autorisierung

authorizeWatcher() prueft ob der Watcher zum aktuellen User-Workspace gehoert. Admins erhalten Zugriff auf den Admin-Workspace (AdminWorkspaceManager::ADMIN_WORKSPACE_ID).

Profil-Bilder

ensureProfileImageStored() prueft bei jedem Seitenaufruf:

  1. Kein Bild in DB → Bild erstmalig von Platform-API holen (YouTube/Instagram)
  2. Bilder in DB → Proaktive R2-Verifizierung: Storage::exists() pruefen ob die primaere Bilddatei in R2 tatsaechlich existiert. Falls nicht: stale DB-Records loeschen und Bild sofort neu von der Platform-API holen.
  3. Rate-Limitexists()-Check nur alle 10 Minuten pro Profil (Cache-Key: profile-image-verified:{profile_id})

Die Lightbox (flux:lightbox) zeigt alle gespeicherten Bilder chronologisch sortiert. Als src wird $displayImageUrl verwendet (Fallback-Kette: gespeichertes Bild → externe thumbnail_url → Placeholder), damit auch bei fehlenden R2-Dateien sofort ein Bild angezeigt wird.

Wichtig — Lazy Loading + Visibility: Die flux:lightbox.image Komponente (resources/views/flux/lightbox/image.blade.php) nutzt loading="lazy" auf dem <img>. Thumbnails duerfen NICHT mit x-show (= display:none) versteckt werden, da der Browser unsichtbare Bilder nicht laedt (Deadlock). Stattdessen wird opacity-0/opacity-100 verwendet — das Bild bleibt im Layout sichtbar, ist aber visuell erst nach dem Load-Event sichtbar. Das Skeleton-Overlay liegt per z-10 darueber.