# 通知設計書 1-Firebase Cloud Messaging (FCM) プッシュ通知

## 概要

本ドキュメントは、Bagisto ECモバイルアプリにおけるFirebase Cloud Messaging (FCM) を使用したリモートプッシュ通知機能の設計書である。

### 本通知の処理概要

本通知は、Firebase Cloud Messaging (FCM) を活用してサーバーからモバイルアプリへリモートプッシュ通知を送信・受信する機能を提供する。アプリがフォアグラウンド、バックグラウンドいずれの状態においても通知を受け取り、ユーザーに情報を伝達する。

**業務上の目的・背景**：ECサイトにおいて、注文状況の更新、プロモーション情報、在庫復活通知など、リアルタイムでユーザーに重要な情報を届ける必要がある。プッシュ通知により、ユーザーがアプリを開いていない状態でも即座に情報を届けることができ、顧客エンゲージメントの向上とコンバージョン率の改善に寄与する。

**通知の送信タイミング**：サーバーサイドからFCMを経由して任意のタイミングで送信される。具体的には、注文ステータス変更時、新商品入荷時、セール開始時、カート放棄リマインダーなど、バックエンドシステムのイベントトリガーに基づいて送信される。

**通知の受信者**：「Bagisto_mobikul」トピックを購読している全アプリユーザー。FCMトークンを発行済みで、通知権限を許可しているデバイスが対象となる。

**通知内容の概要**：タイトル、本文（HTMLタグは除去）、および任意の画像添付を含むリッチ通知。ペイロードには追加データ（商品ID、注文IDなど）を含めることが可能。

**期待されるアクション**：ユーザーが通知をタップすることで、関連する画面（商品詳細、注文詳細など）へ遷移し、該当するアクションを実行することが期待される。

## 通知種別

プッシュ通知（リモート通知 / ローカル通知への変換）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（Firebase Cloud Messaging） |
| 優先度 | 高（Priority.max） |
| リトライ | FCMによる自動リトライ |

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

1. アプリ起動時に `Bagisto_mobikul` トピックに自動購読
2. FCMトークンは `createFcmToken()` メソッドで生成・管理
3. iOS/Android両プラットフォームで同一トピックに購読
4. 通知権限はOSレベルで制御（iOSは明示的許可要求、AndroidはAPI 33以降で許可要求）

## 通知テンプレート

### プッシュ通知の場合

| 項目 | 内容 |
|-----|------|
| チャンネルID | ランダム生成（`${Random().nextDouble()}`） |
| チャンネル名 | Bagisto Notification |
| アイコン | @mipmap/ic_launcher |
| 音声 | 有効 |

### 本文テンプレート

```
タイトル: {notification.title}
本文: {notification.body} (HTMLタグは正規表現で除去)
画像: {data.attachment} (オプション)
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| attachment | 画像（URL） | dataに含まれる場合 | BigPictureStyleで表示 |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| title | 通知タイトル | RemoteMessage.notification.title | Yes |
| body | 通知本文 | RemoteMessage.notification.body | Yes |
| attachment | 画像URL | RemoteMessage.data['attachment'] | No |
| payload | 追加データ | RemoteMessage.data | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| サーバー送信 | FCMメッセージ受信 | アプリがフォアグラウンド | `FirebaseMessaging.onMessage` で処理 |
| サーバー送信 | FCMメッセージ受信 | アプリがバックグラウンド | `_firebaseMessagingBackgroundHandler` で処理 |
| タップ操作 | 通知タップ | アプリが停止状態から起動 | `getInitialMessage` で処理 |
| タップ操作 | 通知タップ | アプリがバックグラウンドから復帰 | `onMessageOpenedApp` で処理 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 通知権限なし | ユーザーが通知権限を拒否している場合 |
| トピック未購読 | Bagisto_mobikulトピックに購読していない場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[FCMメッセージ受信] --> B{アプリ状態確認}
    B -->|フォアグラウンド| C[onMessage リスナー]
    B -->|バックグラウンド| D[BackgroundHandler]
    C --> E[HTMLタグ除去]
    E --> F[画像取得判定]
    F -->|画像あり| G[BigPictureStyle生成]
    F -->|画像なし| H[標準スタイル]
    G --> I[ローカル通知表示]
    H --> I
    D --> J[システム通知表示]
    I --> K[通知タップ待機]
    J --> K
    K --> L{タップ検出}
    L -->|タップ| M[ペイロード解析]
    M --> N[画面遷移]
    L -->|無視| O[終了]
    N --> O
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| ローカルストレージ | FCMトークン保存 | GlobalData.fcmToken |

### テーブル別参照項目詳細

#### GlobalData（グローバル状態管理）

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| fcmToken | FCMトークン | アプリ起動時に生成・保存 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| GlobalData | UPDATE | FCMトークンの更新 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| トークン生成失敗 | ネットワークエラー | 空文字列をデフォルト値として使用 |
| 画像取得失敗 | URLが無効または接続エラー | 画像なしで通知表示 |
| 通知表示失敗 | プラットフォーム固有エラー | デバッグログ出力 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | FCMによる自動管理 |
| リトライ間隔 | FCMによる自動管理 |
| リトライ対象エラー | ネットワーク一時障害 |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | FCM制限に準拠 |
| 1日あたり上限 | FCM制限に準拠 |

### 配信時間帯

制限なし（24時間配信可能）

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

- FCMトークンは端末固有の識別子であり、外部への漏洩を防ぐ必要がある
- ペイロードに機密情報（パスワード、クレジットカード情報等）を含めない
- 通知権限はユーザーの明示的な同意に基づいて取得
- HTTPSによる通信の暗号化（FCMインフラストラクチャにより保証）

## 備考

- iOS では明示的な通知権限リクエストが必要（`_iosPermission()` メソッド）
- Android API 33以降では通知権限の明示的リクエストが必要
- 高重要度通知チャンネル（`high_importance_channel`）を使用
- 画像付き通知は `BigPictureStyleInformation` を使用（Androidのみ）

---

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

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

### 推奨読解順序

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

FCMメッセージの構造とローカル通知の設定パラメータを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | push_notifications_manager.dart | `lib/utils/push_notifications_manager.dart` | PushNotificationsManagerクラスの全体構造、初期化設定を確認 |

**読解のコツ**: `firebase_messaging` パッケージの `RemoteMessage` と `flutter_local_notifications` パッケージの `NotificationDetails` の関係を理解する。

#### Step 2: エントリーポイントを理解する

アプリ起動時のFirebase初期化フローを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | main.dart | `lib/main.dart` | Firebase.initializeApp() とバックグラウンドハンドラの登録 |

**主要処理フロー**:
1. **行54**: `Firebase.initializeApp()` でFirebaseを初期化
2. **行55**: `FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler)` でバックグラウンドハンドラ登録
3. **行56-59**: Androidの通知チャンネル作成
4. **行158**: `PushNotificationsManager.instance.setUpFirebase(context)` でプッシュ通知マネージャーを設定

#### Step 3: 通知設定の初期化を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | push_notifications_manager.dart | `lib/utils/push_notifications_manager.dart` | setUpFirebase() メソッドの処理内容 |

**主要処理フロー**:
- **行44-61**: `setUpFirebase()` - フォアグラウンド通知設定、ローカル通知プラグイン初期化、リスナー設定
- **行50-58**: 通知タップ時のコールバック処理（ファイルを開く場合）
- **行60**: `_firebaseCloudMessagingListeners()` 呼び出し

#### Step 4: FCMリスナーの実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | push_notifications_manager.dart | `lib/utils/push_notifications_manager.dart` | _firebaseCloudMessagingListeners() の処理詳細 |

**主要処理フロー**:
- **行113-143**: `_firebaseCloudMessagingListeners()` - FCMリスナーの設定
- **行116**: `createFcmToken()` - FCMトークン生成
- **行117**: `subscribeToTopic()` - トピック購読
- **行120-137**: `FirebaseMessaging.onMessage.listen()` - フォアグラウンド通知処理
- **行125-126**: HTMLタグの正規表現による除去
- **行136**: `showNotification()` 呼び出し

#### Step 5: 通知表示処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | push_notifications_manager.dart | `lib/utils/push_notifications_manager.dart` | showNotification() と getNotificationStyle() |

**主要処理フロー**:
- **行63-72**: `getNotificationStyle()` - 画像付き通知スタイルの生成
- **行74-97**: `showNotification()` - ローカル通知の表示
- **行77-82**: Android通知チャンネル設定（高優先度、音声有効）
- **行84-88**: iOS通知設定
- **行95-96**: 通知の実際の表示

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

```
main()
    |
    +-- Firebase.initializeApp()
    |
    +-- FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler)
    |
    +-- BagistoApp
            |
            +-- initState()
                    |
                    +-- PushNotificationsManager.instance.setUpFirebase(context)
                            |
                            +-- flutterLocalNotificationsPlugin.initialize()
                            |
                            +-- _firebaseCloudMessagingListeners()
                                    |
                                    +-- createFcmToken()
                                    |
                                    +-- subscribeToTopic()
                                    |
                                    +-- FirebaseMessaging.onMessage.listen()
                                            |
                                            +-- getNotificationStyle()
                                            |
                                            +-- showNotification()
```

### データフロー図

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

FCMサーバー ──────▶ FirebaseMessaging ──────▶ RemoteMessage取得
                                                    |
                                                    ▼
                                            HTMLタグ除去（正規表現）
                                                    |
                                                    ▼
                                            画像URL取得（data.attachment）
                                                    |
                                                    ▼
                                            NotificationDetails生成
                                                    |
                                                    ▼
                                            flutterLocalNotificationsPlugin.show()
                                                    |
                                                    ▼
                                            システム通知バーに表示 ──────▶ ユーザーに通知表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| push_notifications_manager.dart | `lib/utils/push_notifications_manager.dart` | ソース | FCM通知の受信・表示処理を管理 |
| main.dart | `lib/main.dart` | ソース | アプリエントリーポイント、Firebase初期化 |
| server_configuration.dart | `lib/utils/server_configuration.dart` | 設定 | defaultChannelName等の定数定義 |
| string_constants.dart | `lib/utils/string_constants.dart` | 設定 | 通知テキストの定数定義 |
