11 KiB
11 KiB
Broadcasting (실시간 이벤트)
중요도: 중요 관련 문서: service-repository.md | authentication.md
TL;DR (5초 요약)
1. Laravel Reverb 사용 (WebSocket)
2. 이벤트: ShouldBroadcast 인터페이스 구현
3. 채널: public, private, presence
4. 훅 연동: HookManager에서 broadcast() 호출
5. 클라이언트: Laravel Echo + Pusher-js
목차
- 개요
- Laravel Reverb 설정
- 브로드캐스트 이벤트 생성
- 채널 인증
- API 인증 엔드포인트
- 훅을 통한 이벤트 발생
- 스케줄러를 통한 주기적 브로드캐스트
- 개발 환경 설정
- 프로덕션 환경 설정
개요
G7은 Laravel Reverb를 사용하여 실시간 WebSocket 통신을 지원합니다.
주요 사용 사례:
- 대시보드 실시간 통계 업데이트
- 알림 실시간 전송
- 채팅 기능
- 실시간 협업 기능
아키텍처:
클라이언트 (Echo/Pusher-js)
↕ WebSocket
Laravel Reverb 서버
↕
Laravel 백엔드 (broadcast() 호출)
↕
Queue Worker (이벤트 처리)
Laravel Reverb 설정
환경변수 (.env)
# Broadcasting 드라이버
BROADCAST_CONNECTION=reverb
# Reverb 서버 설정
REVERB_APP_ID=467955
REVERB_APP_KEY=zm0vobuy4zpqorc3ro9r
REVERB_APP_SECRET=your-secret-key
REVERB_HOST=localhost
REVERB_PORT=8080
REVERB_SCHEME=https
# 개발 환경에서 자체 서명 인증서 사용 시
REVERB_VERIFY_SSL=false
# 클라이언트용 설정 (Vite)
VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="${REVERB_HOST}"
VITE_REVERB_PORT="${REVERB_PORT}"
VITE_REVERB_SCHEME="${REVERB_SCHEME}"
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',
],
'client_options' => [
// 개발 환경에서 자체 서명 인증서 사용 시 SSL 검증 비활성화
'verify' => env('REVERB_VERIFY_SSL', true),
],
],
주의: 프로덕션 환경에서는
REVERB_VERIFY_SSL=true로 설정해야 합니다.
브로드캐스트 이벤트 생성
기본 구조
<?php
namespace App\Events\Dashboard;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
/**
* 대시보드 업데이트 브로드캐스트 이벤트
*/
class DashboardUpdated implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* 이벤트 인스턴스를 생성합니다.
*
* @param string $type 업데이트 타입 ('stats', 'resources', 'activities')
* @param array $data 업데이트된 데이터
*/
public function __construct(
public string $type,
public array $data
) {}
/**
* 브로드캐스트할 채널을 반환합니다.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
return [new PrivateChannel('admin.dashboard')];
}
/**
* 브로드캐스트 이벤트명을 반환합니다.
*
* @return string
*/
public function broadcastAs(): string
{
return "dashboard.{$this->type}.updated";
}
}
채널 타입
| 타입 | 클래스 | 용도 | 인증 필요 |
|---|---|---|---|
| Public | Channel |
모든 사용자 접근 가능 | ❌ |
| Private | PrivateChannel |
인증된 사용자만 접근 | ✅ |
| Presence | PresenceChannel |
인증 + 접속자 목록 공유 | ✅ |
이벤트 발생
// 방법 1: broadcast() 헬퍼 (권장)
broadcast(new DashboardUpdated('stats', $statsData));
// 방법 2: event() 헬퍼
event(new DashboardUpdated('resources', $resourceData));
// 방법 3: 즉시 전송 (큐 미사용)
broadcast(new DashboardUpdated('alerts', $alertData))->toOthers();
채널 인증
routes/channels.php
<?php
use Illuminate\Support\Facades\Broadcast;
// 사용자별 Private 채널
Broadcast::channel('App.Models.User.{id}', function ($user, $id) {
return (int) $user->id === (int) $id;
});
// 관리자 대시보드 채널 - 권한 체크
Broadcast::channel('admin.dashboard', function ($user) {
return $user->hasPermission('core.dashboard.read');
});
// 특정 리소스 채널
Broadcast::channel('orders.{orderId}', function ($user, $orderId) {
return $user->hasPermission('ecommerce.orders.read');
});
인증 콜백 규칙
// ✅ DO: boolean 반환 (Private 채널)
Broadcast::channel('admin.dashboard', function ($user) {
return $user->hasPermission('core.dashboard.read');
});
// ✅ DO: 배열 반환 (Presence 채널 - 사용자 정보 공유)
Broadcast::channel('chat.{roomId}', function ($user, $roomId) {
if ($user->canJoinRoom($roomId)) {
return ['id' => $user->id, 'name' => $user->name];
}
return false;
});
// ❌ DON'T: 예외 던지기
Broadcast::channel('admin.dashboard', function ($user) {
throw new \Exception('Unauthorized'); // 금지
});
API 인증 엔드포인트
G7은 SPA 환경에서 Sanctum 토큰 기반 인증을 사용합니다. 기본 /broadcasting/auth 엔드포인트는 세션 기반이므로, API용 별도 엔드포인트를 사용합니다.
routes/api.php
// 브로드캐스팅 인증 (Sanctum 토큰 사용)
Route::middleware(['auth:sanctum'])->post('broadcasting/auth', function (\Illuminate\Http\Request $request) {
return \Illuminate\Support\Facades\Broadcast::auth($request);
})->name('api.broadcasting.auth');
클라이언트 설정 (WebSocketManager)
const pusherOptions = {
// ... 기타 옵션
authEndpoint: '/api/broadcasting/auth',
auth: {
headers: {
'Authorization': `Bearer ${authToken}`,
'Accept': 'application/json',
},
},
};
훅을 통한 이벤트 발생
Service 계층에서 데이터 변경 시 훅 리스너를 통해 브로드캐스트 이벤트를 발생시킵니다.
config/hooks.php
return [
'listeners' => [
// 대시보드 통계 업데이트 시 브로드캐스트
'core.dashboard.stats_updated' => [
\App\Listeners\BroadcastDashboardStats::class,
],
// 사용자 생성 시 대시보드 통계 업데이트
'core.user.after_create' => [
\App\Listeners\UpdateDashboardStatsOnUserChange::class,
],
],
];
리스너 구현
<?php
namespace App\Listeners;
use App\Events\Dashboard\DashboardUpdated;
use App\Services\DashboardService;
class BroadcastDashboardStats
{
public function __construct(
private DashboardService $dashboardService
) {}
/**
* 대시보드 통계 브로드캐스트
*
* @param array $data 훅 데이터
* @return void
*/
public function handle(array $data): void
{
$stats = $this->dashboardService->getStats();
broadcast(new DashboardUpdated('stats', $stats));
}
}
스케줄러를 통한 주기적 브로드캐스트
시스템 리소스 등 주기적으로 업데이트가 필요한 데이터는 스케줄러를 사용합니다.
Artisan 커맨드
<?php
namespace App\Console\Commands;
use App\Events\Dashboard\DashboardUpdated;
use App\Services\DashboardService;
use Illuminate\Console\Command;
class BroadcastDashboardResources extends Command
{
protected $signature = 'dashboard:broadcast-resources';
protected $description = '시스템 리소스 정보를 WebSocket으로 브로드캐스트합니다.';
public function handle(DashboardService $dashboardService): int
{
$resources = $dashboardService->getSystemResources();
broadcast(new DashboardUpdated('resources', $resources));
$this->info('시스템 리소스 정보가 브로드캐스트되었습니다.');
return Command::SUCCESS;
}
}
routes/console.php (스케줄러 등록)
use Illuminate\Support\Facades\Schedule;
// 30초마다 시스템 리소스 브로드캐스트
Schedule::command('dashboard:broadcast-resources')->everyThirtySeconds();
실행 방법
# 스케줄러 실행 (개발 환경)
php artisan schedule:work
# 큐 워커 실행 (브로드캐스트 이벤트 처리)
php artisan queue:work
# Reverb 서버 실행
php artisan reverb:start --debug
개발 환경 설정
필요한 프로세스
개발 환경에서 WebSocket을 테스트하려면 다음 프로세스가 모두 실행 중이어야 합니다:
# 터미널 1: Laravel 개발 서버
php artisan serve
# 터미널 2: Reverb WebSocket 서버
php artisan reverb:start --debug
# 터미널 3: 큐 워커 (브로드캐스트 이벤트 처리)
php artisan queue:work
# 터미널 4: 스케줄러 (주기적 브로드캐스트 사용 시)
php artisan schedule:work
SSL 인증서 문제 해결
개발 환경에서 자체 서명 인증서 사용 시 다음 설정이 필요합니다:
# .env
REVERB_VERIFY_SSL=false
이 설정은 Laravel이 Reverb 서버로 이벤트를 전송할 때 SSL 인증서 검증을 비활성화합니다.
프로덕션 환경 설정
권장 설정
# .env (프로덕션)
REVERB_VERIFY_SSL=true
REVERB_SCHEME=https
REVERB_PORT=443
Supervisor 설정 예시
[program:reverb]
command=php /var/www/g7/artisan reverb:start
directory=/var/www/g7
user=www-data
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/reverb.log
[program:queue-worker]
command=php /var/www/g7/artisan queue:work --sleep=3 --tries=3
directory=/var/www/g7
user=www-data
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/queue-worker.log
디버깅
이벤트 전송 확인
# 수동으로 이벤트 발생
php artisan dashboard:broadcast-resources
# 큐 작업 확인
php artisan queue:work --once
로그 확인
# Laravel 로그
tail -f storage/logs/laravel.log
# Reverb 서버 로그 (--debug 옵션 사용 시)
php artisan reverb:start --debug
클라이언트 디버깅
브라우저 개발자 도구에서:
- Network 탭 → WS 필터 → WebSocket 연결 확인
- Messages 탭에서 송수신 메시지 확인
- Console 탭에서
[WebSocketManager]로그 확인
관련 문서
- Service-Repository 패턴 - 훅 실행 위치
- 인증 - Sanctum 토큰 인증
- 프론트엔드 WebSocket - 클라이언트 WebSocket 구독