Operations

Reverb & Echo

Externa uses Reverb + Laravel Echo (laravel-echo + pusher-js) for admin realtime notifications and presence. Locally, prefer Herd Pro Reverb on :8080 (already running as a shared service). AI chat SSE is unchanged.

What websockets cover

Covered by WebSocketsNot covered (other transport)
Private user notifications (file zip / duplication outcomes)AI chat — browser SSE (POST /ai/chat), not Echo
Presence channel online (green dots on Users list)Activity log flood — Spatie rows stay poll/Inertia; not broadcast per row
Presence channel chat.{uuid} (team chat messages / typing)Public CMS / GraphQL / API keys — no realtime fan-out
Connection status indicator (avatar ConnectionDot)Unread count when BROADCAST_CONNECTION is log/null60s poll only then
Auth via /broadcasting/auth (session cookie)
Private user events ChatUnreadUpdated / ThreadUpserted

When realtime is on, the notifications bell does not poll every 60s. Poll is the fallback for the minimal stack only.

Team chat product docs: Chat (hub & items).

Events (notification classes that broadcast)

All four use trait App\Notifications\Concerns\BroadcastsWithDatabase:

  • Always database
  • Plus broadcast when BROADCAST_CONNECTION is not log / null / empty
Classdata.typeEmitted from
FileZipReadyNotificationfile_zip_readyPrepareFilesZipJob
FileZipFailedNotificationfile_zip_failedPrepareFilesZipJob
FileDuplicationCompletedNotificationfile_duplication_completedDuplicateFilesJob
FileDuplicationFailedNotificationfile_duplication_failedDuplicateFilesJob

toBroadcast() wraps the same toArray() payload as the database notification (BroadcastMessage).

Channels

Name in routes/channels.phpWire / Echo nameAuth
App.Models.User.{id}Private App.Models.User.{id}Owner only ((int) $user->id === (int) $id)
onlinePresence presence-online (Echo join('online'))Active User; returns { id, name }

Echo listen points (UI)

LocationBehavior
resources/js/lib/echo.tsensureEcho() — boots Reverb client when Inertia realtime.enabled is true
resources/js/app.tsxEager ensureEcho(true) on boot when enabled
NotificationsBellecho.private('App.Models.User.{id}').notification(...) — bumps unread + NOTIFICATIONS_UPDATED_EVENT
useOnlineUsersecho.join('online').here / .joining / .leaving → Users list green dots
useEchoConnection + ConnectionDotTracks Pusher connection state; rendered on sidebar avatar via UserInfo (nav-user.tsxshowConnectionStatus)

Connection dot tones: connected (green), connecting (amber pulse), disabled (muted), else destructive.

Herd Pro runs a shared Reverb on port 8080. Match credentials from Herd → Services → Reverb (defaults in externa-core/.env.example):

BROADCAST_CONNECTION=reverb

REVERB_APP_ID=1001
REVERB_APP_KEY=laravel-herd
REVERB_APP_SECRET=secret
REVERB_HOST=127.0.0.1
REVERB_PORT=8080
REVERB_SCHEME=http

VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="${REVERB_HOST}"
VITE_REVERB_PORT="${REVERB_PORT}"
VITE_REVERB_SCHEME="${REVERB_SCHEME}"
  • Host for Echo must be 127.0.0.1 or localhost (not 0.0.0.0).
  • After changing VITE_REVERB_*, restart npm run dev (or rebuild).
  • Do not also run php artisan reverb:start while Herd Reverb owns :8080 — port conflict.
  • Auth endpoint: /broadcasting/auth (web middleware / session cookie).

Docker Compose

compose.yaml runs a dedicated reverb service. Host port defaults to 8081 (container 8080) so it does not clash with Herd Pro on :8080. Use .env.docker.example (REVERB_PORT / VITE_REVERB_PORT=8081). Inside the Compose network the app talks to REVERB_HOST=reverb on port 8080; browsers use the published host port.

Production: proxy WebSocket upgrades to the Reverb service — Deployment — Docker.

Standalone Reverb (no Herd service)

php84 artisan reverb:start

Use your own REVERB_APP_* values on both the app and the Reverb process. composer run dev:full starts reverb:start for that path.

Feature detect

HandleInertiaRequests shares:

realtime: {
  enabled: boolean
  broadcaster: string
}

enabled is false when BROADCAST_CONNECTION is log or null — UI skips Echo; bell keeps the 60s unread poll.

Previous
Horizon