> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# 알림(Notifications)

> Laravel의 알림 시스템을 사용해 메일·데이터베이스·Slack 등 여러 채널에 일괄 전송하는 방법을 설명합니다.

## Notification이란

Laravel의 알림(Notification) 시스템은 메일·SMS·Slack·데이터베이스 등 여러 배송 채널에 대해 통일된 API로 알림을 보내는 구조입니다.

**Mail과 Notification의 차이**

| 비교    | Mail        | Notification           |
| ----- | ----------- | ---------------------- |
| 주된 용도 | 리치한 HTML 메일 | 짧은 정보 알림               |
| 배송 채널 | 메일만         | 메일·DB·Slack·SMS 등 여러 개 |
| 템플릿   | 완전히 자유      | 심플한 메시지 형식             |

청구서 결제 완료 알림처럼 여러 채널에 같은 알림을 보내고 싶다면 Notification이 적합합니다.

## Notification 클래스 생성

`make:notification` Artisan 명령으로 클래스를 생성합니다.

```shell theme={null}
php artisan make:notification InvoicePaid
```

생성된 클래스는 `app/Notifications/` 디렉터리에 배치됩니다. 클래스에는 `via()` 메서드와 각 채널용 메시지 생성 메서드가 포함됩니다.

## 알림 전송 방법

### Notifiable 트레이트 사용하기

`App\Models\User`에는 기본적으로 `Notifiable` 트레이트가 포함되어 있습니다. `notify()` 메서드로 알림을 보냅니다.

```php theme={null}
use App\Notifications\InvoicePaid;

$user->notify(new InvoicePaid($invoice));
```

<Info>
  `Notifiable` 트레이트는 `User` 모델뿐만 아니라 임의의 모델에 추가할 수 있습니다.
</Info>

### Notification 파사드 사용하기

여러 사용자에게 동시에 전송하려면 `Notification` 파사드를 사용합니다.

```php theme={null}
use Illuminate\Support\Facades\Notification;

Notification::send($users, new InvoicePaid($invoice));
```

즉시 전송(큐를 건너뜀)하려면 `sendNow()`를 사용합니다.

```php theme={null}
Notification::sendNow($developers, new DeploymentCompleted($deployment));
```

## 배송 채널 지정

`via()` 메서드에서 사용할 채널을 배열로 반환합니다.

```mermaid theme={null}
flowchart TD
    A["$user->notify(new InvoicePaid())"] --> B["via()로<br>채널 결정"]
    B --> C{"채널 선택"}
    C --> D["mail<br>toMail()"]
    C --> E["database<br>toArray()"]
    C --> F["broadcast<br>toBroadcast()"]
    C --> G["vonage<br>toVonage()"]
    C --> H["slack<br>toSlack()"]
```

```php theme={null}
public function via(object $notifiable): array
{
    return ['mail', 'database'];
}
```

사용자의 설정에 따라 채널을 전환할 수도 있습니다.

```php theme={null}
public function via(object $notifiable): array
{
    return $notifiable->prefers_sms ? ['vonage'] : ['mail', 'database'];
}
```

이용 가능한 주요 채널은 다음과 같습니다.

| 채널     | 키           | 설명                         |
| ------ | ----------- | -------------------------- |
| 메일     | `mail`      | 메일로 알림을 보냄                 |
| 데이터베이스 | `database`  | DB에 저장하고 UI 상에 표시          |
| 브로드캐스트 | `broadcast` | 실시간 알림(WebSocket)          |
| SMS    | `vonage`    | Vonage(구 Nexmo) 경유로 SMS 전송 |
| Slack  | `slack`     | Slack 채널에 게시               |

## 메일 채널로 알림 보내기

`toMail()` 메서드에서 `MailMessage` 인스턴스를 반환합니다.

```php theme={null}
use Illuminate\Notifications\Messages\MailMessage;

public function toMail(object $notifiable): MailMessage
{
    $url = url('/invoice/'.$this->invoice->id);

    return (new MailMessage)
        ->greeting('안녕하세요!')
        ->line('청구서 결제를 확인했습니다.')
        ->action('청구서 확인하기', $url)
        ->line('이용해 주셔서 감사합니다.');
}
```

`MailMessage`의 주요 메서드는 다음과 같습니다.

| 메서드          | 설명      |
| ------------ | ------- |
| `greeting()` | 서두의 인사말 |
| `line()`     | 본문 한 줄  |
| `action()`   | 버튼 링크   |
| `subject()`  | 제목      |
| `from()`     | 발신자 주소  |
| `mailer()`   | 사용할 메일러 |

에러를 알리는 경우 `error()` 메서드를 추가하면 버튼이 빨간색으로 표시됩니다.

```php theme={null}
return (new MailMessage)
    ->error()
    ->subject('결제에 실패했습니다')
    ->line('청구서 결제 처리에 실패했습니다.');
```

### 마크다운 알림 메일

마크다운 형식의 리치한 메일도 사용할 수 있습니다. `--markdown` 옵션으로 클래스를 생성합니다.

```shell theme={null}
php artisan make:notification InvoicePaid --markdown=mail.invoice.paid
```

`toMail()` 대신 마크다운 메서드를 사용합니다.

```php theme={null}
use Illuminate\Notifications\Messages\MailMessage;

public function toMail(object $notifiable): MailMessage
{
    return (new MailMessage)
        ->markdown('mail.invoice.paid', [
            'url' => url('/invoice/'.$this->invoice->id),
            'invoice' => $this->invoice,
        ]);
}
```

## 데이터베이스 채널로 알림 보내기

데이터베이스 채널을 사용하면 알림을 DB에 저장하고 앱의 UI 상에 표시할 수 있습니다.

### 테이블 준비

먼저 `notifications` 테이블을 생성합니다.

```shell theme={null}
php artisan make:notifications-table

php artisan migrate
```

### toArray 메서드 정의

`toArray()` 메서드에서 저장할 데이터를 배열로 반환합니다.

```php theme={null}
public function toArray(object $notifiable): array
{
    return [
        'invoice_id' => $this->invoice->id,
        'amount' => $this->invoice->amount,
        'message' => '청구서 결제를 확인했습니다.',
    ];
}
```

이 데이터는 `notifications` 테이블의 `data` 컬럼에 JSON 형식으로 저장됩니다.

### 알림 조회

`Notifiable` 트레이트가 제공하는 `notifications` 릴레이션으로 알림을 조회할 수 있습니다.

```php theme={null}
$user = App\Models\User::find(1);

foreach ($user->notifications as $notification) {
    echo $notification->type;
    echo $notification->data['message'];
}
```

읽지 않은 알림만 조회하려면 `unreadNotifications`를 사용합니다.

```php theme={null}
foreach ($user->unreadNotifications as $notification) {
    echo $notification->data['message'];
}
```

### 읽음 처리

`markAsRead()`로 알림을 읽음 상태로 만듭니다.

```php theme={null}
// 개별적으로 읽음 처리
foreach ($user->unreadNotifications as $notification) {
    $notification->markAsRead();
}

// 일괄 읽음 처리
$user->unreadNotifications->markAsRead();

// 쿼리로 일괄 갱신
$user->unreadNotifications()->update(['read_at' => now()]);
```

## 알림 큐 처리

알림 전송에 시간이 걸리는 경우 `ShouldQueue` 인터페이스와 `Queueable` 트레이트를 추가해 큐 처리로 만듭니다. `make:notification`으로 생성한 클래스에는 처음부터 임포트되어 있습니다.

```php theme={null}
<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;

class InvoicePaid extends Notification implements ShouldQueue
{
    use Queueable;

    // ...
}
```

`ShouldQueue`를 구현하면 `notify()`를 호출하는 것만으로 자동으로 큐에 들어갑니다.

```php theme={null}
$user->notify(new InvoicePaid($invoice));
```

지연 전송도 가능합니다.

```php theme={null}
$user->notify(
    (new InvoicePaid($invoice))->delay(now()->plus(minutes: 10))
);
```

## 여러 채널로의 동시 전송

`via()` 메서드에서 여러 채널을 반환하고 각각의 메서드를 정의하는 것만으로, 같은 알림을 여러 채널에 동시에 전송할 수 있습니다.

```php theme={null}
<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;

class InvoicePaid extends Notification implements ShouldQueue
{
    use Queueable;

    public function __construct(
        private readonly Invoice $invoice,
    ) {}

    public function via(object $notifiable): array
    {
        // 메일과 데이터베이스 양쪽에 전송
        return ['mail', 'database'];
    }

    public function toMail(object $notifiable): MailMessage
    {
        return (new MailMessage)
            ->subject('청구서 결제를 확인했습니다')
            ->line('청구서 #'.$this->invoice->id.'의 결제를 확인했습니다.')
            ->action('청구서 확인하기', url('/invoice/'.$this->invoice->id));
    }

    public function toArray(object $notifiable): array
    {
        return [
            'invoice_id' => $this->invoice->id,
            'amount' => $this->invoice->amount,
        ];
    }
}
```

## 온디맨드 알림

앱에 계정이 없는 사용자에게도 알림을 보내고 싶다면 `Notification::route()`를 사용합니다.

```php theme={null}
use Illuminate\Support\Facades\Notification;

Notification::route('mail', 'guest@example.com')
    ->route('vonage', '5555551212')
    ->notify(new InvoicePaid($invoice));
```

## 정리

| 하고 싶은 일         | 방법                                                 |
| --------------- | -------------------------------------------------- |
| Notification 생성 | `php artisan make:notification ClassName`          |
| 사용자에게 알림        | `$user->notify(new MyNotification())`              |
| 여러 사용자에게 알림     | `Notification::send($users, new MyNotification())` |
| 메일로 전송          | `via()`에서 `mail` 반환 후 `toMail()` 정의                |
| DB에 저장          | `via()`에서 `database` 반환 후 `toArray()` 정의           |
| 큐로 비동기 전송       | `ShouldQueue` 구현                                   |
| 여러 채널로 전송       | `via()`에서 여러 키를 반환                                 |


## Related topics

- [알림 채널 - Laravel Bluesky](/ko/packages/laravel-bluesky/notification.md)
- [Laravel Notification for Discord(Webhook)](/ko/packages/laravel-notification-discord-webhook.md)
- [알림 채널 - LINE SDK for Laravel](/ko/packages/laravel-line-sdk/notification.md)
- [BlueskyManager와 HasShortHand](/ko/packages/laravel-bluesky/bluesky-manager.md)
- [Laravel Console Starter](/ko/packages/laravel-console-starter/index.md)
