Backend

laravel-reverb

Sets up Laravel Reverb WebSocket server for real-time features

Overview

The laravel-reverb agent sets up Laravel Reverb for real-time WebSocket communication. It configures broadcasting, creates events, sets up channel authorization, and integrates Laravel Echo on the client side.

Responsibilities

  • Reverb Installation - Install and configure the WebSocket server
  • Broadcast Events - Create events that broadcast to channels
  • Channel Authorization - Private and presence channel auth
  • Echo Integration - Client-side WebSocket setup
  • Scaling Configuration - Redis pub/sub for horizontal scaling
  • SSL/TLS Setup - Secure WebSocket connections

What It Creates

Component Location Purpose
Broadcast Config config/broadcasting.php Reverb connection settings
Channel Routes routes/channels.php Channel authorization
Broadcast Events app/Events/ Real-time event classes
Echo Bootstrap resources/js/bootstrap.js Client-side Echo setup

Generated Broadcast Event

<?php

namespace App\Events;

use App\Models\Message;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class MessageSent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(
        public Message $message
    ) {}

    public function broadcastOn(): array
    {
        return [
            new PrivateChannel('chat.' . $this->message->conversation_id),
        ];
    }

    public function broadcastWith(): array
    {
        return [
            'id' => $this->message->id,
            'body' => $this->message->body,
            'user' => [
                'id' => $this->message->user->id,
                'name' => $this->message->user->name,
                'avatar' => $this->message->user->avatar_url,
            ],
            'created_at' => $this->message->created_at->toIso8601String(),
        ];
    }

    public function broadcastAs(): string
    {
        return 'message.sent';
    }
}

Channel Authorization

// routes/channels.php

// Private channel
Broadcast::channel('orders.{orderId}', function ($user, $orderId) {
    return $user->id === Order::find($orderId)?->user_id;
});

// Presence channel with user data
Broadcast::channel('chat.{conversationId}', function ($user, $conversationId) {
    if ($user->canAccessConversation($conversationId)) {
        return [
            'id' => $user->id,
            'name' => $user->name,
            'avatar' => $user->avatar_url,
        ];
    }
});

// Public channel (no auth needed)
Broadcast::channel('notifications', function () {
    return true;
});

Laravel Echo Setup

// resources/js/bootstrap.js
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

window.Pusher = Pusher;
window.Echo = new Echo({
    broadcaster: 'reverb',
    key: import.meta.env.VITE_REVERB_APP_KEY,
    wsHost: import.meta.env.VITE_REVERB_HOST,
    wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
    wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
    forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
    enabledTransports: ['ws', 'wss'],
});

// Listen to private channel
Echo.private(`chat.${conversationId}`)
    .listen('.message.sent', (event) => {
        messages.value.push(event);
    });

// Presence channel
Echo.join(`chat.${conversationId}`)
    .here((users) => {
        onlineUsers.value = users;
    })
    .joining((user) => {
        onlineUsers.value.push(user);
    })
    .leaving((user) => {
        onlineUsers.value = onlineUsers.value.filter(u => u.id !== user.id);
    });

Reverb Configuration

// config/broadcasting.php
'reverb' => [
    'driver' => 'reverb',
    'key' => env('REVERB_APP_KEY'),
    'secret' => env('REVERB_APP_SECRET'),
    'app_id' => env('REVERB_APP_ID'),
    'options' => [
        'host' => env('REVERB_HOST'),
        'port' => env('REVERB_PORT', 443),
        'scheme' => env('REVERB_SCHEME', 'https'),
        'useTLS' => env('REVERB_SCHEME', 'https') === 'https',
    ],
],

// .env
BROADCAST_DRIVER=reverb
REVERB_APP_ID=app-id
REVERB_APP_KEY=app-key
REVERB_APP_SECRET=app-secret
REVERB_HOST="localhost"
REVERB_PORT=8080
REVERB_SCHEME=http

Invoked By Commands

Guardrails

The Reverb agent follows strict rules:

  • ALWAYS authorize private channels properly
  • ALWAYS use broadcastAs() for consistent event names
  • ALWAYS keep broadcast payloads small
  • NEVER broadcast sensitive data without channel auth
  • NEVER forget to run queue workers for ShouldBroadcast

See Also