Events
Alle Broadcast-Events in Postbox. Events werden über Laravel Reverb (WebSockets) an verbundene Clients gesendet. Alle Events (außer TestBroadcast) nutzen private Channels mit Autorisierung.
Location: app/Events/
Event-Übersicht
| Event | Channel(s) | broadcastAs | Interface | Persistenz |
|---|---|---|---|---|
WatcherImportProgress | workspace.{id} | import.progress | ShouldBroadcast | Nur bei Finish |
YouTubeVideoSyncCompleted | user.{id} | youtube.sync.completed | ShouldBroadcastNow | Nur manuell |
DailyScrapeCompleted | user.{id} | daily.scrape.completed | ShouldBroadcast | Nur Toast |
RelatedProfilesCalculated | profile.{id} + user.{id} | related.profiles.calculated | ShouldBroadcast | Nur manuell |
ProfileReactivated | user.{id} (alle betroffenen) | profile.reactivated | ShouldBroadcast | Immer |
ProfileSanitized | user.{id} (alle betroffenen) | profile.sanitized | ShouldBroadcast | Immer |
ProfileUnsanitized | user.{id} (alle betroffenen) | profile.unsanitized | ShouldBroadcast | Immer |
UserRegistered | admin | user.registered | ShouldBroadcast | Immer (Admin) |
TestBroadcast | test-channel (public) | toast.show | ShouldBroadcastNow | Nein |
ServerMetricsUpdated | admin | server.metrics.updated | ShouldBroadcastNow | Nein |
ServerAlertTriggered | admin | server.alert.triggered | ShouldBroadcastNow | Nein |
ContactLinkProfileImported | workspace.{id} | contact.link.imported | ShouldBroadcast | Ja (7 Tage) |
YouTubeResearchBatchProgress | admin | youtube.research.batch.progress | ShouldBroadcastNow | Nein |
YouTubeResearchBatchProgress
Broadcast fuer Echtzeit-Fortschritts-Updates waehrend einer YouTube Research Batch-Suche. Wird nach jedem verarbeiteten Keyword gesendet.
Location: app/Events/YouTubeResearchBatchProgress.php
Properties
public string $batchId,
public int $processedCount,
public int $totalCount,
public ?string $currentKeyword,
public int $currentResultCount,
public int $filteredCount,
public string $status, // 'processing', 'completed', 'failed'
public ?string $errorMessage,
Broadcast
- Channel:
PrivateChannel('admin') - broadcastAs:
youtube.research.batch.progress - Interface:
ShouldBroadcastNow(synchron, kein Queue-Delay) - Trait:
SuppressesBroadcastFailures - Payload: Inkl. berechneter
progressProzent (0-100)
Trigger
Dispatched von ProcessYouTubeResearchBatch nach jedem verarbeiteten Keyword und bei Batch-Completion.
ContactLinkProfileImported
Broadcast wenn ein Kontaktlink-Import erfolgreich abgeschlossen wurde (Profil wurde gefunden/erstellt und verknüpft).
Location: app/Events/ContactLinkProfileImported.php
Properties
public int $sourceProfileId,
public int $importedProfileId,
public int $workspaceId,
public int $triggeredBy,
Broadcast
- Channel:
PrivateChannel("workspace.{workspaceId}") - broadcastAs:
contact.link.imported - Payload:
sourceHandle,importedHandle,platform,watcherId,message - Trait:
SuppressesBroadcastFailures
Trigger
Dispatched von ImportContactLinkProfile nach erfolgreichem Import.
WatcherImportProgress
Broadcast von Fortschritts-Updates während eines Watcher-Imports. Wird nach jeder verarbeiteten URL gesendet.
Location: app/Events/WatcherImportProgress.php
Properties
public int $importRunId,
public int $workspaceId,
public int $processedCount,
public int $totalCount,
public int $addedCount,
public int $failedCount,
public int $alreadyInWorkspaceCount,
public string $status,
public ?string $lastProcessedUrl = null,
public ?string $lastResult = null,
Broadcast
- Channel:
PrivateChannel("workspace.{workspaceId}") - broadcastAs:
import.progress - broadcastQueue:
imports-youtube - Payload: Inkl. berechneter
progressProzent (0-100) - Trait:
SuppressesBroadcastFailures
Trigger
Dispatched von ImportWatcherFromUrl nach jeder verarbeiteten URL und bei Run-Completion.
YouTubeVideoSyncCompleted
Broadcast wenn ein YouTube-Video-Stats-Sync abgeschlossen ist (Erfolg oder Fehler).
Location: app/Events/YouTubeVideoSyncCompleted.php
Properties
public int $userId,
public int $socialProfileId,
public string $profileHandle,
public ?string $profileTitle,
public int $videosSynced,
public bool $success,
public ?string $errorMessage = null,
public bool $triggeredManually = false,
public ?int $watcherId = null,
Broadcast
- Channel:
PrivateChannel("user.{userId}") - broadcastAs:
youtube.sync.completed - Interface:
ShouldBroadcastNow(synchron, kein Queue-Delay) - Trait:
SuppressesBroadcastFailures - Message:
"YouTube-Statistiken für @{handle} aktualisiert ({n} Videos)"oder Fehlermeldung
Trigger
Nur bei manuell angefordertem Sync (requested_by gesetzt). Automatische nightly Syncs senden kein Event.
DailyScrapeCompleted
Broadcast wenn alle täglichen Scrapes für einen User abgeschlossen sind.
Location: app/Events/DailyScrapeCompleted.php
Properties
public int $userId,
public string $date,
public int $expectedCount,
public int $completedCount,
public int $failedCount,
Broadcast
- Channel:
PrivateChannel("user.{userId}") - broadcastAs:
daily.scrape.completed - Trait:
SuppressesBroadcastFailures - Payload: Inkl. berechneter
successRate(Prozent) - Message:
"Tägliche Aktualisierung abgeschlossen: X/Y Profile aktualisiert"
Rotation-System
expectedCount berücksichtigt das Rotation-System -- nicht alle Profile werden täglich gescrapt, nur die des aktuellen Rotation-Buckets.
RelatedProfilesCalculated
Broadcast wenn die Berechnung ähnlicher Profile/Channels abgeschlossen ist.
Location: app/Events/RelatedProfilesCalculated.php
Properties
public int $socialProfileId,
public string $platform, // 'youtube', 'instagram', 'cross_platform_youtube', ...
public string $profileHandle,
public ?string $profileTitle,
public string $status, // 'completed' oder 'failed'
public int $foundCount,
public ?string $errorMessage = null,
public ?int $triggeredByUserId = null,
public ?int $watcherId = null,
Broadcast
- Channels:
PrivateChannel("profile.{socialProfileId}")+ optionalPrivateChannel("user.{triggeredByUserId}") - broadcastAs:
related.profiles.calculated - Trait:
SuppressesBroadcastFailures
Der User-Channel wird nur hinzugefügt wenn triggeredByUserId gesetzt ist (manueller Trigger).
Trigger
Dispatched von FindRelatedYouTubeChannels, FindRelatedInstagramProfiles und FindCrossPlatformRelatedProfiles.
ProfileReactivated
Broadcast wenn ein deaktiviertes Profil erfolgreich reaktiviert wurde. Gesendet an alle User, die einen Watcher für dieses Profil haben.
Location: app/Events/ProfileReactivated.php
Properties
public int $socialProfileId,
public string $profileHandle,
public ?string $profileTitle,
public string $platform,
public ?int $triggeredByUserId = null,
public bool $isManualRetry = false,
Broadcast
- Channels:
PrivateChannel("user.{userId}")für jeden betroffenen User - broadcastAs:
profile.reactivated - Trait:
SuppressesBroadcastFailures - Message:
"Profil @{handle} wurde reaktiviert und wird wieder aktualisiert"
Betroffene User ermitteln
// Constructor: Join über watcher_sources -> watchers -> workspaces
$this->userIds = DB::table('watcher_sources')
->join('watchers', ...)
->join('workspaces', ...)
->where('social_profile_id', $this->socialProfileId)
->distinct()
->pluck('workspaces.owner_id');
Trigger
Dispatched von RetryInactiveProfileScrape bei erfolgreichem Retry.
ProfileSanitized
Broadcast wenn ein Profil durch den Sanitizer automatisch deaktiviert wurde.
Location: app/Events/ProfileSanitized.php
Properties
public int $socialProfileId,
public string $profileHandle,
public ?string $profileTitle,
public string $platform,
public string $reason,
Broadcast
- Channels:
PrivateChannel("user.{userId}")für jeden betroffenen User - broadcastAs:
profile.sanitized - Trait:
SuppressesBroadcastFailures - Message:
"Profil @{handle} wurde automatisch deaktiviert: {reason}"
Trigger
Dispatched von profiles:sanitize Command.
ProfileUnsanitized
Broadcast wenn ein zuvor sanitized Profil wieder aktiviert wird (Admin Override).
Location: app/Events/ProfileUnsanitized.php
Properties
public int $socialProfileId,
public string $profileHandle,
public ?string $profileTitle,
public string $platform,
Broadcast
- Channels:
PrivateChannel("user.{userId}")für jeden betroffenen User - broadcastAs:
profile.unsanitized - Trait:
SuppressesBroadcastFailures - Message:
"Profil @{handle} wurde reaktiviert und wird wieder aktualisiert"
Trigger
Dispatched von Admin\SocialProfiles\Index::enableTracking().
UserRegistered
Broadcast wenn sich ein neuer User registriert. Nur an Admins.
Location: app/Events/UserRegistered.php
Properties
public int $userId,
public string $userName,
public string $userEmail,
public ?string $userAvatar,
Broadcast
- Channel:
PrivateChannel('admin') - broadcastAs:
user.registered - Trait:
SuppressesBroadcastFailures - Message:
"Neuer User registriert: {name} ({email})"
Trigger
Dispatched von UserObserver::created() (indirekt über NotificationCenter).
TestBroadcast
Test-Event für die Verifikation der Reverb WebSocket-Konnektivität. Einziges Event auf einem public Channel.
Location: app/Events/TestBroadcast.php
Properties
public string $message,
public string $type = 'info', // 'success', 'info', 'warning', 'danger'
Broadcast
- Channel:
Channel('test-channel')(public, keine Auth) - broadcastAs:
toast.show - Interface:
ShouldBroadcastNow(synchron, kein Queue) - Kein
SuppressesBroadcastFailuresTrait (Test soll Fehler zeigen)
Trigger
Admin-Seite /admin/reverb-test oder CLI:
php artisan tinker --execute='App\Events\TestBroadcast::dispatch("Test", "success");'
ServerMetricsUpdated
Broadcast von Server-Metriken (CPU, RAM, Disk, etc.) an das Admin-Dashboard. Wird alle ~15 Sekunden gesendet.
Location: app/Events/ServerMetricsUpdated.php
Properties
public array $metrics, // Komplettes Metriken-Array
Broadcast
- Channel:
PrivateChannel('admin') - broadcastAs:
server.metrics.updated - Interface:
ShouldBroadcastNow(Metriken müssen sofort ankommen) - Trait:
SuppressesBroadcastFailures
ServerAlertTriggered
Broadcast wenn eine Server-Metrik einen Warn-/Kritisch-Schwellwert überschreitet.
Location: app/Events/ServerAlertTriggered.php
Properties
public string $metric, // z.B. 'cpu_percent'
public string $level, // 'warning' oder 'critical'
public float $value, // Aktueller Wert
public float $threshold, // Überschrittener Schwellwert
public string $message, // Menschenlesbare Nachricht
Broadcast
- Channel:
PrivateChannel('admin') - broadcastAs:
server.alert.triggered - Interface:
ShouldBroadcastNow - Trait:
SuppressesBroadcastFailures
Trigger
Dispatched von ServerAlertService::check() via server:check-alerts Command (alle 5 min).
Channel-Autorisierung
Alle privaten Channels werden in routes/channels.php autorisiert:
// User kann nur eigenen Kanal abonnieren
Broadcast::channel('user.{userId}', fn ($user, $userId) =>
(int) $user->id === (int) $userId
);
// User muss Mitglied des Workspace sein
Broadcast::channel('workspace.{workspaceId}', fn ($user, $workspaceId) =>
$user->workspaces()->where('workspaces.id', $workspaceId)->exists()
);
// User muss Watcher mit diesem Profil haben
Broadcast::channel('profile.{profileId}', fn ($user, $profileId) =>
WatcherSource::query()
->where('social_profile_id', $profileId)
->whereHas('watcher', fn ($q) => $q->whereIn('workspace_id', ...))
->exists()
);
// Nur Admins
Broadcast::channel('admin', fn ($user) => $user->isAdmin());
Location: routes/channels.php