# 通知設計書 4-AnonymousNotifiable

## 概要

本ドキュメントは、Laravel フレームワークにおける匿名通知対象クラス（AnonymousNotifiable）の設計仕様を定義する。このクラスは、ユーザーモデルに関連付けずにオンデマンドで通知を送信するために使用される。

### 本通知の処理概要

AnonymousNotifiable クラスは、データベースに保存されたユーザーモデルを必要とせずに通知を送信するための仕組みを提供する。メールアドレスや電話番号などの送信先情報を直接指定して通知を送信できる。

**業務上の目的・背景**：アプリケーションには、登録済みユーザー以外に通知を送信する必要があるケースがある。例えば、お問い合わせフォームからの受付確認メール、外部サービスへの通知、一時的なゲストユーザーへの通知などである。AnonymousNotifiable により、User モデルを作成せずに柔軟に通知を送信できる。

**通知の送信タイミング**：開発者が明示的に Notification ファサードの route() メソッドを使用してオンデマンド通知を作成し、notify() または notifyNow() を呼び出したとき。

**通知の受信者**：route() メソッドで指定されたチャネルごとの送信先。メールアドレス、電話番号、Slack チャネル URL など、チャネルに応じた送信先情報を設定できる。

**通知内容の概要**：送信する通知クラスの実装に依存する。AnonymousNotifiable 自体は通知内容を持たず、送信先のルーティング情報のみを保持する。

**期待されるアクション**：受信者は通常の通知と同様に通知内容を受け取る。ただし、database チャネルは使用できないため、永続化が必要な場合は別途対応が必要となる。

## 通知種別

AnonymousNotifiable 自体は通知種別を持たない。route() メソッドで指定したチャネルに対応する通知を送信可能。ただし、**database チャネルは明示的に使用不可**。

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 通知クラスの実装に依存（ShouldQueue の有無） |
| 優先度 | 通知クラスの実装に依存 |
| リトライ | 通知クラスの実装に依存 |

### 送信先決定ロジック

route() メソッドで明示的に指定されたチャネルごとの送信先情報を使用する。`$routes` プロパティに保存され、`routeNotificationFor()` メソッドで取得される。

## 通知テンプレート

### AnonymousNotifiable の機能

| 項目 | 内容 |
|-----|------|
| ルーティング情報 | $routes プロパティでチャネルごとの送信先を保持 |
| 通知送信 | notify() と notifyNow() メソッドを提供 |
| 制限事項 | database チャネルは使用不可（InvalidArgumentException がスロー） |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| routes | チャネルごとの送信先情報 | route() メソッドで設定 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| API/画面操作 | Notification::route()->notify() 呼び出し | なし | 開発者による明示的な呼び出し |
| コード | AnonymousNotifiable::notify() 直接呼び出し | なし | 開発者による明示的な呼び出し |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| database チャネル指定 | route('database', ...) を呼び出すと InvalidArgumentException がスロー |
| ルーティング情報なし | 指定されたチャネルのルーティング情報がない場合、送信されない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[Notification::route 呼び出し] --> B[AnonymousNotifiable インスタンス作成]
    B --> C[route メソッドでチャネル・送信先設定]
    C --> D{チャネルは database?}
    D -->|Yes| E[InvalidArgumentException スロー]
    D -->|No| F[$routes に送信先情報保存]
    F --> G[notify または notifyNow 呼び出し]
    G --> H[Dispatcher::send 呼び出し]
    H --> I[NotificationSender::sendNow]
    I --> J{database チャネル?}
    J -->|Yes| K[送信スキップ]
    J -->|No| L[routeNotificationFor で送信先取得]
    L --> M[Channel::send 実行]
    M --> N[通知送信完了]
    K --> N
    E --> O[エラー終了]
```

## データベース参照・更新仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| なし | - | AnonymousNotifiable はデータベースを参照しない |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| なし | - | database チャネルが使用不可のため、通知テーブルへの書き込みは発生しない |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| InvalidArgumentException | route('database', ...) を呼び出した場合 | database チャネル以外を使用する |
| 送信失敗 | チャネルごとのエラー | 各チャネルのエラー処理に依存 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 通知クラスの ShouldQueue 実装に依存 |
| リトライ間隔 | 通知クラスの実装に依存 |
| リトライ対象エラー | 通知クラスの実装に依存 |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 制限なし | AnonymousNotifiable 自体はレート制限を設けない |

### 配信時間帯

通知クラスの実装に依存

## セキュリティ考慮事項

- database チャネルが使用不可のため、通知履歴の永続化が必要な場合は別途実装が必要
- 送信先情報が直接コードに含まれる可能性があるため、機密情報の取り扱いに注意
- getKey() メソッドは何も返さないため、ユーザー識別が必要な処理では問題が発生する可能性

## 備考

- Notification ファサードの route() メソッドで簡単に作成可能
- 複数のチャネルに対してチェーンで route() を呼び出し可能
- 主な使用例：
  - お問い合わせフォームの受付確認メール
  - 外部サービスへの Slack/Teams 通知
  - SMS 認証コードの送信
  - ゲストユーザーへの一時的な通知

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: AnonymousNotifiable クラスの構造を理解する

まず、AnonymousNotifiable クラスの全体構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | AnonymousNotifiable.php | `src/Illuminate/Notifications/AnonymousNotifiable.php` | クラス全体の構造、$routes プロパティ（15行目）を確認 |

**読解のコツ**: このクラスは 79 行と非常にシンプル。route() メソッドでの database チャネル禁止ロジック（28-30行目）が重要。

#### Step 2: route() メソッドを理解する

ルーティング情報の設定方法を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AnonymousNotifiable.php | `src/Illuminate/Notifications/AnonymousNotifiable.php` | route() メソッド（26-35行目）で database チャネルが禁止されている理由を理解 |

**主要処理フロー**:
1. **26行目**: route() メソッドでチャネルと送信先を受け取る
2. **28-30行目**: database チャネルの場合は InvalidArgumentException をスロー
3. **32行目**: $routes 配列にチャネルごとの送信先を保存
4. **34行目**: $this を返してメソッドチェーンを可能に

#### Step 3: notify() と notifyNow() メソッドを理解する

通知送信の仕組みを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | AnonymousNotifiable.php | `src/Illuminate/Notifications/AnonymousNotifiable.php` | notify()（43-46行目）と notifyNow()（54-57行目）メソッドを確認 |

**主要処理フロー**:
- **43-46行目**: notify() で Dispatcher::send を呼び出し（非同期可能）
- **54-57行目**: notifyNow() で Dispatcher::sendNow を呼び出し（即時送信）

#### Step 4: routeNotificationFor() メソッドを理解する

送信先情報の取得方法を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | AnonymousNotifiable.php | `src/Illuminate/Notifications/AnonymousNotifiable.php` | routeNotificationFor()（65-68行目）で $routes から送信先を取得 |

**主要処理フロー**:
- **65-68行目**: 指定されたドライバー（チャネル）の送信先を $routes から取得、なければ null を返す

#### Step 5: NotificationSender での AnonymousNotifiable 処理を理解する

NotificationSender が AnonymousNotifiable をどう扱うかを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | NotificationSender.php | `src/Illuminate/Notifications/NotificationSender.php` | sendToNotifiable()（115行目）で AnonymousNotifiable の database チャネルをスキップ |

**主要処理フロー**:
- **115行目**: `if (! ($notifiable instanceof AnonymousNotifiable && $channel === 'database'))` で database チャネルの場合はスキップ

#### Step 6: Notification ファサードでの使用方法を理解する

ファサードからの呼び出し方法を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | Notification.php（ファサード） | `src/Illuminate/Support/Facades/Notification.php` | route() メソッドが ChannelManager に委譲される仕組みを確認 |

### プログラム呼び出し階層図

```
Notification::route('mail', 'user@example.com')
    │
    └─ ChannelManager::route()
           │
           └─ new AnonymousNotifiable
                  │
                  └─ AnonymousNotifiable::route('mail', 'user@example.com')
                         │
                         ├─ database チャネルチェック
                         │      └─ InvalidArgumentException（database の場合）
                         │
                         └─ $this->routes['mail'] = 'user@example.com'
                                │
                                └─ return $this（メソッドチェーン用）

AnonymousNotifiable::notify($notification)
    │
    └─ Dispatcher::send($this, $notification)
           │
           └─ NotificationSender::send()
                  │
                  └─ NotificationSender::sendNow()
                         │
                         └─ sendToNotifiable()
                                │
                                ├─ AnonymousNotifiable && database チェック
                                │      └─ スキップ（database の場合）
                                │
                                └─ routeNotificationFor($channel)
                                       │
                                       └─ $this->routes[$channel] ?? null
                                              │
                                              └─ Channel::send()
```

### データフロー図

```
[入力]                          [処理]                                [出力]

チャネル名 'mail'        ───▶  AnonymousNotifiable::route()
送信先 'user@example.com'             │
                                    ▼
                            database チャネル?
                                    │
                    ┌───────────────┴───────────────┐
                    ▼                               ▼
            InvalidArgumentException          $routes['mail'] = 'user@example.com'
                                                   │
                                                   ▼
$notification            ───▶  AnonymousNotifiable::notify()
                                    │
                                    ▼
                            Dispatcher::send()
                                    │
                                    ▼
                            NotificationSender::sendNow()
                                    │
                                    ▼
                            routeNotificationFor('mail')
                                    │
                                    ▼
                            'user@example.com'     ───▶  MailChannel::send()
                                                              │
                                                              ▼
                                                        メール送信完了
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AnonymousNotifiable.php | `src/Illuminate/Notifications/AnonymousNotifiable.php` | ソース | 匿名通知対象クラス |
| NotificationSender.php | `src/Illuminate/Notifications/NotificationSender.php` | ソース | 通知送信エンジン |
| ChannelManager.php | `src/Illuminate/Notifications/ChannelManager.php` | ソース | チャネル管理・ファサード元 |
| Notification.php（ファサード） | `src/Illuminate/Support/Facades/Notification.php` | ソース | Notification ファサード |
| Dispatcher.php（コントラクト） | `src/Illuminate/Contracts/Notifications/Dispatcher.php` | ソース | 通知ディスパッチャーインターフェース |
| MailChannel.php | `src/Illuminate/Notifications/Channels/MailChannel.php` | ソース | メールチャネル実装 |
| BroadcastChannel.php | `src/Illuminate/Notifications/Channels/BroadcastChannel.php` | ソース | ブロードキャストチャネル実装 |
| NotificationFake.php | `src/Illuminate/Support/Testing/Fakes/NotificationFake.php` | ソース | テスト用フェイク |
