# 機能設計書 71-プッシュ通知

## 概要

本ドキュメントは、ECモバイルアプリケーションにおけるFirebase Cloud Messaging（FCM）を利用したプッシュ通知機能の設計を記述する。

### 本機能の処理概要

本機能はFirebase Cloud Messagingを通じて、サーバーからユーザーのモバイルデバイスにプッシュ通知を配信する仕組みを提供する。通知受信時には画像付き通知やダウンロード進捗通知など、様々な形式での表示が可能である。

**業務上の目的・背景**：ECサイトにおいて、セール情報、注文ステータスの更新、新商品の入荷など、ユーザーに対してタイムリーな情報を届けることは、エンゲージメント向上と売上促進に直結する。プッシュ通知により、アプリを起動していないユーザーに対しても能動的に情報を届けることができ、アプリの再訪率向上に貢献する。

**機能の利用シーン**：
- 注文確定後のステータス通知
- セールやキャンペーンの告知
- カート放棄リマインダー
- 新商品入荷のお知らせ
- ダウンロード商品の進捗表示

**主要な処理内容**：
1. Firebase初期化とFCMトークン生成
2. 通知トピック（Bagisto_mobikul）への購読
3. フォアグラウンド・バックグラウンドでの通知受信処理
4. ローカル通知の表示（画像付き通知対応）
5. 通知タップ時のペイロード処理（ファイルオープン等）
6. ダウンロード進捗通知の表示

**関連システム・外部連携**：
- Firebase Cloud Messaging（FCM）
- Flutter Local Notifications Plugin
- ネイティブプラットフォーム（Android/iOS）のMethodChannel

**権限による制御**：iOS端末ではユーザーからの通知許可が必要であり、初回起動時に許可ダイアログを表示する。Androidでは通知チャンネルの設定により、ユーザーがシステム設定から通知の有効/無効を切り替え可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | （バックグラウンド） | 主機能 | アプリ非起動時・バックグラウンド時の通知受信・表示 |
| 全画面 | （フォアグラウンド） | 補助機能 | アプリ起動中の通知受信とローカル通知表示 |

## 機能種別

プッシュ通知受信 / ローカル通知表示 / 外部API連携

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| RemoteMessage | RemoteMessage | Yes | FCMから受信した通知メッセージ | - |
| title | String | Yes | 通知タイトル | - |
| body | String | Yes | 通知本文 | HTMLタグ除去処理あり |
| attachment | String | No | 画像URL（data内） | - |
| payload | String | No | 通知タップ時のペイロード（JSON） | - |

### 入力データソース

- Firebase Cloud Messaging（リモート通知）
- アプリ内処理（ダウンロード進捗通知）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| FCMトークン | String | デバイス識別用のFCMトークン（GlobalData.fcmTokenに格納） |
| 通知表示 | ローカル通知 | システム通知領域への通知表示 |

### 出力先

- システム通知領域（Android/iOS）
- GlobalData.fcmToken（トークン保存）

## 処理フロー

### 処理シーケンス

```
1. アプリ起動時のFirebase初期化（main.dart）
   └─ Firebase.initializeApp()実行
   └─ バックグラウンドメッセージハンドラ登録
   └─ 通知チャンネル作成（Android）

2. PushNotificationsManager.setUpFirebase()呼び出し
   └─ フォアグラウンド通知表示設定
   └─ ローカル通知プラグイン初期化
   └─ FCMリスナー登録

3. FCMトークン生成とトピック購読
   └─ createFcmToken()でトークン取得
   └─ subscribeToTopic()で"Bagisto_mobikul"購読

4. 通知受信時の処理
   └─ フォアグラウンド: FirebaseMessaging.onMessage
   └─ バックグラウンド: onBackgroundMessage
   └─ アプリオープン時: onMessageOpenedApp

5. ローカル通知表示
   └─ showNotification()で通知生成
   └─ 画像がある場合はBigPictureStyleで表示
```

### フローチャート

```mermaid
flowchart TD
    A[アプリ起動] --> B[Firebase初期化]
    B --> C[PushNotificationsManager.setUpFirebase]
    C --> D{iOS?}
    D -->|Yes| E[通知許可リクエスト]
    D -->|No| F[FCMトークン生成]
    E --> F
    F --> G[トピック購読]
    G --> H[通知リスナー登録]
    H --> I{通知受信}
    I -->|フォアグラウンド| J[onMessage処理]
    I -->|バックグラウンド| K[onBackgroundMessage処理]
    J --> L[HTML除去・画像取得]
    L --> M[showNotification]
    M --> N[ローカル通知表示]
    N --> O{通知タップ}
    O -->|ペイロードあり| P[ペイロード処理]
    O -->|ペイロードなし| Q[終了]
    P --> R{type判定}
    R -->|openFile| S[ファイルオープン]
    R -->|その他| Q
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-71-01 | HTML除去 | 通知本文からHTMLタグを除去して表示 | 通知受信時 |
| BR-71-02 | 画像通知 | attachmentが存在する場合はBigPictureStyleで表示 | Android通知時 |
| BR-71-03 | トピック購読 | 全端末が"Bagisto_mobikul"トピックを購読 | 初期化時 |
| BR-71-04 | ダウンロード進捗 | ダウンロード中は進捗バー付き通知を表示 | ファイルダウンロード時 |

### 計算ロジック

ダウンロード進捗通知における進捗率計算：
- progress / total で進捗を算出
- total == progress の場合「完了」、それ以外は「開始」メッセージを表示

## データベース操作仕様

### 操作別データベース影響一覧

本機能ではデータベース操作は発生しない。FCMトークンはGlobalDataのメモリ上に保持される。

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | データベース操作なし |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | PlatformException | ファイルビューア起動失敗 | デバッグログ出力 |
| - | 通知許可拒否 | iOS通知許可が拒否された場合 | 通知機能が無効化される |
| - | ネットワークエラー | 画像取得失敗時 | 画像なしで通知表示 |

### リトライ仕様

FCMトークン取得やトピック購読に特別なリトライ処理は実装されていない。Firebase SDKの内部リトライ機構に依存。

## トランザクション仕様

本機能ではトランザクション管理は不要（データベース操作なし）。

## パフォーマンス要件

- 通知受信から表示までの遅延：1秒以内
- 画像付き通知の場合は画像取得時間が追加される
- バックグラウンド処理はシステムリソースを最小限に使用

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

- FCMトークンはデバイス固有の識別子であり、サーバー側で安全に管理する必要がある
- 通知ペイロードに機密情報を含めないこと
- ファイルオープン機能はMethodChannelを通じてネイティブ実装に委譲

## 備考

- iOS/Android両プラットフォームで同一のトピック名（Bagisto_mobikul）を使用
- ダウンロード完了通知のペイロードには{"type": "openFile", "path": "{ファイルパス}"}形式を使用

---

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

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

### 推奨読解順序

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

Firebase Messagingの主要なデータ構造と、通知表示に必要な設定を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | push_notifications_manager.dart | `lib/utils/push_notifications_manager.dart` | RemoteMessage、NotificationDetailsの構造 |

**読解のコツ**: FlutterのFirebase Messagingプラグインの型定義（RemoteMessage、RemoteNotification）はfirebase_messagingパッケージで定義されている。flutter_local_notificationsパッケージのAndroidNotificationDetails、DarwinNotificationDetailsはOS固有の通知設定を担当する。

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

アプリ起動時の初期化処理とFirebase設定を理解する。

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

**主要処理フロー**:
1. **45-68行目**: main()関数でFirebase.initializeApp()、バックグラウンドハンドラ登録、通知チャンネル作成
2. **34-36行目**: _firebaseMessagingBackgroundHandler()でバックグラウンド通知処理
3. **158行目**: PushNotificationsManager.instance.setUpFirebase(context)呼び出し

#### Step 3: 通知マネージャーの初期化を理解する

PushNotificationsManagerクラスの初期化処理と各メソッドの役割を理解する。

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

**主要処理フロー**:
- **44-61行目**: setUpFirebase()でフォアグラウンド設定、ローカル通知初期化、リスナー登録
- **50-58行目**: 通知タップ時のコールバック処理（ペイロードからファイルオープン判定）
- **99-103行目**: createFcmToken()でFCMトークン生成とGlobalDataへの保存
- **105-111行目**: subscribeToTopic()でBagisto_mobikulトピック購読

#### Step 4: 通知受信処理を理解する

フォアグラウンドとバックグラウンドでの通知受信処理を理解する。

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

**主要処理フロー**:
- **113-143行目**: _firebaseCloudMessagingListeners()でiOS許可、トークン生成、リスナー設定
- **120-137行目**: FirebaseMessaging.onMessage.listen()でフォアグラウンド通知処理
- **125-126行目**: HTMLタグ除去（RegExpによる正規表現置換）
- **139-142行目**: onMessageOpenedAppでアプリオープン時の処理

#### Step 5: ローカル通知表示を理解する

通知の実際の表示処理とカスタマイズを理解する。

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

**主要処理フロー**:
- **63-72行目**: getNotificationStyle()で画像付き通知スタイル生成
- **74-97行目**: showNotification()でAndroid/iOS両対応の通知表示
- **152-176行目**: createDownloadNotification()でダウンロード進捗通知

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

```
main()
    │
    ├─ Firebase.initializeApp()
    │
    ├─ FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler)
    │
    └─ BagistoApp
           │
           └─ _BagistoAppState.initState()
                  │
                  └─ PushNotificationsManager.instance.setUpFirebase(context)
                         │
                         ├─ FirebaseMessaging.setForegroundNotificationPresentationOptions()
                         │
                         ├─ flutterLocalNotificationsPlugin.initialize()
                         │
                         └─ _firebaseCloudMessagingListeners()
                                │
                                ├─ _iosPermission()
                                │
                                ├─ createFcmToken()
                                │
                                ├─ subscribeToTopic()
                                │
                                └─ FirebaseMessaging.onMessage.listen()
                                       │
                                       └─ showNotification()
                                              │
                                              └─ getNotificationStyle()
```

### データフロー図

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

FCMサーバー ───────▶ FirebaseMessaging ─────────────▶ RemoteMessage
                           │
                           ├─ フォアグラウンド
                           │      │
                           │      ▼
                           │  showNotification() ──────▶ システム通知
                           │      │
                           │      └─ getNotificationStyle() ──▶ 画像スタイル
                           │
                           └─ バックグラウンド
                                  │
                                  ▼
                           _firebaseMessagingBackgroundHandler ──▶ デバッグログ

アプリ内処理 ──────▶ createDownloadNotification() ──▶ 進捗通知

通知タップ ────────▶ onDidReceiveNotificationResponse ──▶ openFile()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| push_notifications_manager.dart | `lib/utils/push_notifications_manager.dart` | ソース | プッシュ通知管理のコアクラス |
| main.dart | `lib/main.dart` | ソース | Firebase初期化とアプリエントリーポイント |
| file_download.dart | `lib/screens/product_screen/view/file_download.dart` | ソース | ダウンロード進捗通知の呼び出し元 |
| server_configuration.dart | `lib/utils/server_configuration.dart` | ソース | defaultChannelName等の定数定義 |
