# 通知設計書 6-BrowserFlashMessage

## 概要

本ドキュメントは、Symfony NotifierコンポーネントにおけるBrowser通知（BrowserFlashMessage）の設計仕様を記述する。BrowserChannelを通じてHTTPリクエストのセッションにフラッシュメッセージを追加する仕組みについて詳細に定義する。

### 本通知の処理概要

BrowserFlashMessageは、Symfony Notifierコンポーネントが提供するブラウザ向け通知チャネルである。BrowserChannelはHTTPリクエストのセッションにフラッシュメッセージを追加することで、次のページレンダリング時にユーザーに通知を表示する。他のチャネル（Email、SMS等）とは異なり、外部サービスへの送信は行わず、HTTPセッションを介した通知を行う。

**業務上の目的・背景**：Webアプリケーションにおいて、ユーザー操作の結果（保存成功、エラー発生等）をブラウザ上で即座にフィードバックする必要がある。フラッシュメッセージは1回限りの表示で自動消去されるため、操作結果の通知に最適である。Notifierを通じてフラッシュメッセージを扱うことで、同じ通知オブジェクトを他のチャネル（メール、Slack等）にも同時に送信できる統一的なAPIを提供する。

**通知の送信タイミング**：Notifier::send()が呼び出され、Notificationのchannelsに"browser"が含まれている場合に実行される。HTTPリクエストが存在しない場合（CLIコンテキスト等）は処理がスキップされる。

**通知の受信者**：BrowserChannelはすべてのRecipientInterfaceをサポートする（supports()が常にtrueを返す）。フラッシュメッセージはHTTPセッションに追加されるため、現在のセッションに紐づくユーザーが受信者となる。

**通知内容の概要**：Notification::getSubject()がメッセージ本文として使用される。絵文字（emoji）が設定されている場合はメッセージの先頭に付加される。重要度（importance）に応じてフラッシュメッセージのタイプ（Bootstrap: danger/warning/info/success等）が決定される。

**期待されるアクション**：受信者はブラウザに表示されたフラッシュメッセージを確認し、必要に応じた操作を行う。フラッシュメッセージは次のリクエストで自動的に消去される。

## 通知種別

ブラウザフラッシュメッセージ

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（HTTPセッションへの直接追加） |
| 優先度 | FlashMessageImportanceMapperによりフラッシュメッセージタイプにマッピング |
| リトライ | なし（セッションへの直接書き込みのため失敗しない） |

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

1. BrowserChannel::supports()は常にtrueを返すため、すべてのRecipientに対して利用可能（BrowserChannel.php 行44-47）
2. RequestStack::getCurrentRequest()でHTTPリクエストを取得（BrowserChannel.php 行33）
3. リクエストがnullの場合（CLIコンテキスト等）は処理をスキップして即座にreturn（BrowserChannel.php 行33-35）
4. リクエストのセッションのFlashBagにメッセージを追加

## 通知テンプレート

### 本文テンプレート

```
{emoji（設定されている場合）} {Notification::getSubject()}
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| 該当なし | - | - | フラッシュメッセージには添付ファイル機能なし |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| subject | メッセージ本文 | Notification::getSubject() | Yes |
| emoji | メッセージ先頭の絵文字 | Notification::getEmoji() | No |
| importance | 重要度（フラッシュメッセージタイプの決定に使用） | Notification::getImportance() | Yes（デフォルト: high） |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作 | Notifier::send()の実行（HTTPリクエストコンテキスト内） | Notificationのchannelsに"browser"が含まれる、かつHTTPリクエストが存在する | コントローラ等からの呼び出し |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| HTTPリクエストが存在しない | RequestStack::getCurrentRequest()がnullの場合、処理がスキップされる（CLIコンテキスト等） |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[Notifier::send呼び出し] --> B[getChannels: チャネル決定]
    B --> C[BrowserChannel::supports チェック]
    C -->|常にtrue| D[BrowserChannel::notify 実行]
    D --> E{HTTPリクエスト存在?}
    E -->|No| F[即座にreturn]
    E -->|Yes| G[メッセージ組み立て]
    G --> H{emoji設定あり?}
    H -->|Yes| I[emoji + subject]
    H -->|No| J[subjectのみ]
    I --> K[FlashMessageImportanceMapper でタイプ変換]
    J --> K
    K --> L[セッションFlashBagにメッセージ追加]
    L --> M[終了]
    F --> M
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| 該当なし | - | BrowserChannelはデータベースを参照しない。HTTPセッションを使用 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| 該当なし | - | HTTPセッション（FlashBag）にメッセージを追加する |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| FlashMessageImportanceMapperException | 不明なimportance値が指定された場合 | 有効なimportance値（urgent/high/medium/low）を設定する |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし（セッションへの直接書き込みのため） |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | なし（セッション操作のため） |
| 1日あたり上限 | なし |

### 配信時間帯

制限なし。HTTPリクエストのタイミングに依存。

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

- フラッシュメッセージはサーバーサイドのセッションに保存されるため、クライアントからの改竄リスクは低い
- メッセージ内容にユーザー入力を含む場合は、テンプレート側でHTMLエスケープを行うこと
- セッションハイジャックによりフラッシュメッセージが第三者に表示される可能性があるため、セッション管理の適切な設定が必要

## 備考

- BrowserChannelはfinalクラスとして定義されており、継承による拡張はできない（BrowserChannel.php 行23）
- BrowserChannelはAbstractChannelを継承していない。Transport/Busを使用せず、RequestStackとFlashMessageImportanceMapperInterfaceに依存する独自の構造を持つ
- FlashMessageImportanceMapperには2つの実装がある：
  - DefaultFlashMessageImportanceMapper: すべての重要度を"notification"にマッピング
  - BootstrapFlashMessageImportanceMapper: urgent->danger, high->warning, medium->info, low->success
- デフォルトのマッパーはDefaultFlashMessageImportanceMapper（コンストラクタのデフォルト値、BrowserChannel.php 行27）

---

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

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

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | FlashMessageImportanceMapperInterface.php | `src/Symfony/Component/Notifier/FlashMessage/FlashMessageImportanceMapperInterface.php` | flashMessageTypeFromImportance()のシグネチャ（行24）。importance文字列をフラッシュメッセージタイプに変換 |
| 1-2 | AbstractFlashMessageImportanceMapper.php | `src/Symfony/Component/Notifier/FlashMessage/AbstractFlashMessageImportanceMapper.php` | IMPORTANCE_MAPの参照とFlashMessageImportanceMapperExceptionのスロー条件（行21-28） |
| 1-3 | DefaultFlashMessageImportanceMapper.php | `src/Symfony/Component/Notifier/FlashMessage/DefaultFlashMessageImportanceMapper.php` | すべての重要度を"notification"にマッピング（行21-26） |
| 1-4 | BootstrapFlashMessageImportanceMapper.php | `src/Symfony/Component/Notifier/FlashMessage/BootstrapFlashMessageImportanceMapper.php` | Bootstrap CSSクラスにマッピング: urgent->danger, high->warning, medium->info, low->success（行21-26） |

**読解のコツ**: BrowserChannelは他のチャネルとは根本的に異なる構造を持つ。TransportやMessageクラスを使用せず、HTTPセッションのFlashBagに直接メッセージを追加する。

#### Step 2: チャネル処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | BrowserChannel.php | `src/Symfony/Component/Notifier/Channel/BrowserChannel.php` | finalクラス。コンストラクタ（行25-28）でRequestStackとMapperを受け取る。notify()（行31-42）でフラッシュメッセージ追加 |

**主要処理フロー**:
- **行25-28**: コンストラクタでRequestStackとFlashMessageImportanceMapperInterfaceを受け取る（MapperのデフォルトはDefaultFlashMessageImportanceMapper）
- **行33-35**: RequestStack::getCurrentRequest()がnullの場合、即座にreturn
- **行37-39**: emoji設定時はemoji + " " + subjectでメッセージを組み立て
- **行41**: FlashBag::add()でマッパーが返すタイプとメッセージを追加

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

```
Notifier::send()
    |
    +-- getChannels()
    |
    +-- BrowserChannel::supports()  [常にtrue]
    |
    +-- BrowserChannel::notify()
            |
            +-- RequestStack::getCurrentRequest()
            |       +-- [null] return（CLIコンテキスト）
            |
            +-- Notification::getSubject()
            +-- Notification::getEmoji()
            |       +-- [emoji存在] emoji + " " + subject
            |
            +-- FlashMessageImportanceMapper::flashMessageTypeFromImportance()
            |       +-- Notification::getImportance()を変換
            |
            +-- Request::getSession()->getFlashBag()->add(type, message)
```

### データフロー図

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

Notification                    BrowserChannel::notify()
  - subject          -------->    |
  - emoji                         v
  - importance                 メッセージ組み立て                -------->  HTTPセッション
                                  |                                        FlashBag
RequestStack                      v
  - currentRequest   -------->  ImportanceMapper
                                  |
FlashMessageMapper               v
  - IMPORTANCE_MAP   -------->  FlashBag::add(type, message)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| BrowserChannel.php | `src/Symfony/Component/Notifier/Channel/BrowserChannel.php` | ソース | ブラウザフラッシュメッセージ通知チャネル |
| FlashMessageImportanceMapperInterface.php | `src/Symfony/Component/Notifier/FlashMessage/FlashMessageImportanceMapperInterface.php` | ソース | 重要度マッピングインターフェース |
| AbstractFlashMessageImportanceMapper.php | `src/Symfony/Component/Notifier/FlashMessage/AbstractFlashMessageImportanceMapper.php` | ソース | マッピング基底クラス |
| DefaultFlashMessageImportanceMapper.php | `src/Symfony/Component/Notifier/FlashMessage/DefaultFlashMessageImportanceMapper.php` | ソース | デフォルトマッパー（全て"notification"） |
| BootstrapFlashMessageImportanceMapper.php | `src/Symfony/Component/Notifier/FlashMessage/BootstrapFlashMessageImportanceMapper.php` | ソース | Bootstrapマッパー（CSSクラスにマッピング） |
| Notification.php | `src/Symfony/Component/Notifier/Notification/Notification.php` | ソース | 通知基本クラス |
| Notifier.php | `src/Symfony/Component/Notifier/Notifier.php` | ソース | 通知送信エントリーポイント |
