feat: FCM HTTP v1 푸시 알림 발송 기능 구현
- google/auth 패키지 추가 (OAuth2 Service Account 인증) - FcmSender: FCM HTTP v1 API 발송 서비스 - FcmResponse: 응답 DTO (성공/실패, 토큰 유효성 체크) - FcmException: FCM 전용 예외 클래스 - fcm:test artisan 명령어 (테스트 발송) - PushNotificationService에 FcmSender 연동 - config/fcm.php 설정 파일 추가 - 알림 유형별 채널 분리 (push_default, push_urgent)
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
|
||||
use App\Models\PushDeviceToken;
|
||||
use App\Models\PushNotificationSetting;
|
||||
use App\Services\Fcm\FcmSender;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class PushNotificationService extends Service
|
||||
@@ -217,7 +218,7 @@ public function sendToUser(int $userId, string $notificationType, array $notific
|
||||
}
|
||||
|
||||
/**
|
||||
* FCM 메시지 전송 (실제 구현)
|
||||
* FCM 메시지 전송 (FCM HTTP v1 API)
|
||||
*/
|
||||
protected function sendFcmMessage(
|
||||
PushDeviceToken $token,
|
||||
@@ -225,18 +226,75 @@ protected function sendFcmMessage(
|
||||
string $sound,
|
||||
string $notificationType
|
||||
): bool {
|
||||
// TODO: FCM HTTP v1 API 구현
|
||||
// 현재는 로그만 기록
|
||||
Log::info('FCM message would be sent', [
|
||||
'token_id' => $token->id,
|
||||
'platform' => $token->platform,
|
||||
'title' => $notification['title'] ?? '',
|
||||
'body' => $notification['body'] ?? '',
|
||||
// FCM 설정이 없으면 로그만 기록
|
||||
if (empty(config('fcm.project_id'))) {
|
||||
Log::info('FCM message skipped (not configured)', [
|
||||
'token_id' => $token->id,
|
||||
'platform' => $token->platform,
|
||||
'title' => $notification['title'] ?? '',
|
||||
'body' => $notification['body'] ?? '',
|
||||
'type' => $notificationType,
|
||||
]);
|
||||
|
||||
return true; // 설정이 없어도 실패로 처리하지 않음
|
||||
}
|
||||
|
||||
// 알림 유형에 따른 채널 결정
|
||||
$channelId = $this->getChannelId($notificationType);
|
||||
|
||||
// 추가 데이터 구성
|
||||
$data = array_merge($notification['data'] ?? [], [
|
||||
'notification_type' => $notificationType,
|
||||
'sound' => $sound,
|
||||
'type' => $notificationType,
|
||||
]);
|
||||
|
||||
return true;
|
||||
try {
|
||||
$sender = new FcmSender;
|
||||
$response = $sender->sendToToken(
|
||||
$token->token,
|
||||
$notification['title'] ?? '',
|
||||
$notification['body'] ?? '',
|
||||
$channelId,
|
||||
$data
|
||||
);
|
||||
|
||||
// 유효하지 않은 토큰이면 비활성화
|
||||
if ($response->isInvalidToken()) {
|
||||
$token->update(['is_active' => false]);
|
||||
Log::warning('FCM token invalidated', [
|
||||
'token_id' => $token->id,
|
||||
'error' => $response->error,
|
||||
]);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return $response->success;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('FCM send failed', [
|
||||
'token_id' => $token->id,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 알림 유형에 따른 채널 ID 결정
|
||||
*/
|
||||
protected function getChannelId(string $notificationType): string
|
||||
{
|
||||
// 긴급 알림 유형들
|
||||
$urgentTypes = [
|
||||
PushNotificationSetting::TYPE_APPROVAL,
|
||||
PushNotificationSetting::TYPE_ORDER,
|
||||
];
|
||||
|
||||
return in_array($notificationType, $urgentTypes, true)
|
||||
? config('fcm.channels.urgent', 'push_urgent')
|
||||
: config('fcm.channels.default', 'push_default');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user