# 通知設計書 36-ダウンロード完了通知

## 概要

本ドキュメントは、ECモバイルアプリケーションにおける「ダウンロード完了通知」の設計仕様を定義する。ユーザーがダウンロード可能商品（デジタルコンテンツ）をダウンロードした際の完了結果をアプリ内通知およびシステム通知バーで表示する機能について記載する。

### 本通知の処理概要

ダウンロード完了通知は、ユーザーがダウンロード可能商品の一覧画面からダウンロードボタンをタップし、ファイルのダウンロード処理が完了した際に、その結果を通知する機能である。進捗バー付きの通知が「Completed」（完了）に変わり、ユーザーはダウンロードが正常に終了したことを確認できる。

**業務上の目的・背景**：デジタルコンテンツ（電子書籍、音楽、ソフトウェア等）の販売において、ダウンロード可能商品は重要な商品カテゴリである。ユーザーが購入したデジタルコンテンツをダウンロードする際、バックグラウンドでの処理完了を明確に通知することで、ユーザーはダウンロードが成功したことを確認し、コンテンツを利用開始できる。また、ダウンロード失敗時には適切なエラー通知によりトラブルシューティングを支援する。

**通知の送信タイミング**：ダウンロード処理が完了した時点で、システム通知バーに完了通知が表示される。ダウンロード進捗が100%（total == progress）に達した時点でトリガーされる。

**通知の受信者**：ダウンロード操作を実行したユーザー本人のみが通知を受け取る。通知はAndroid/iOSのシステム通知バーに表示される。

**通知内容の概要**：通知タイトルにダウンロードしたファイル名、本文に「Completed」（完了）のステータスが表示される。通知をタップすると、ダウンロードしたファイルを開くことができる。

**期待されるアクション**：ユーザーは通知をタップしてダウンロードしたファイルを開き、コンテンツを利用する。または、アプリ内のダウンロード可能商品一覧から該当ファイルにアクセスする。

## 通知種別

プッシュ通知（ローカル通知）- システム通知バー表示

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（ダウンロード完了に対する即時通知） |
| 優先度 | 高（Priority.high） |
| リトライ | 無 |

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

ダウンロード操作を実行したユーザー本人のデバイスに表示される。システム通知のためユーザー認証は不要。

## 通知テンプレート

### システム通知バーの場合

| 項目 | 内容 |
|-----|------|
| 表示位置 | システム通知バー |
| 表示時間 | ユーザーが消去するまで表示 |
| タップアクション | ファイルビューアでダウンロードファイルを開く |

### 完了時テンプレート

| 項目 | 内容 |
|-----|------|
| タイトル | {ファイル名（name）} |
| 本文 | "Completed"（StringConstants.completed） |
| 通知ID | 1（固定） |
| チャンネルID | "progress channel" |
| チャンネル名 | "Bagisto Notification" |

```
タイトル: {ダウンロードファイル名}
本文: Completed
```

### 通知ペイロード

```json
{
  "type": "openFile",
  "path": "{ダウンロードファイルパス}"
}
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| なし | - | - | 通知自体には添付なし。ファイルは別途保存 |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| name | ファイル名 | createDownloadNotification引数 | Yes |
| path | ファイルパス | createDownloadNotification引数 | Yes |
| total | 総バイト数 | createDownloadNotification引数 | Yes |
| progress | 進捗バイト数 | createDownloadNotification引数 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作 | DownloadProductEvent発行 | total == progress | ダウンロードボタンタップ後、完了時 |
| Bloc状態変化 | DownloadBase64ProductState | status == success | Base64データ取得成功時 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| ダウンロード失敗 | エラー発生時は完了通知ではなくエラー通知を表示 |
| 注文ステータス不正 | order.status != "completed" の場合はダウンロード不可 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ダウンロードボタンタップ] --> B{注文ステータス確認}
    B -->|completed| C[DownloadProductEvent発行]
    B -->|その他| D[エラー通知表示]
    C --> E[DownloadableProductsBloc処理]
    E --> F[Repository.downloadProductLink呼び出し]
    F --> G{API応答}
    G -->|成功| H[DownloadBase64ProductEvent発行]
    G -->|失敗| I[エラー状態発行]
    H --> J[Base64データ取得]
    J --> K[DownloadFile.saveBase64String呼び出し]
    K --> L[createDownloadNotification呼び出し]
    L --> M{進捗確認}
    M -->|total == progress| N[完了通知表示 Completed]
    M -->|進行中| O[進捗通知表示 Started]
    N --> P[ユーザーがタップ]
    P --> Q[openFile呼び出し]
    Q --> R[ファイルビューアで開く]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| downloadable_link_purchases | ダウンロード権限確認 | GraphQL API経由 |
| orders | 注文ステータス確認 | completed状態のみ許可 |

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

#### downloadable_link_purchases

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | ダウンロードリンク識別 | DownloadProductEvent.id |
| download_bought | 購入回数 | available計算用 |
| download_used | 使用回数 | available計算用 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| downloadable_link_purchases | UPDATE | download_usedのインクリメント |

#### 送信ログテーブル

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| なし | - | - | ローカル通知のためログ記録なし |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| API通信エラー | ネットワーク接続不可 | errorNotification表示 |
| ダウンロード回数超過 | available == 0 | ダウンロードボタン無効化 |
| 注文ステータス不正 | status != completed | ボタン無効化、エラー表示 |
| ファイル保存エラー | ストレージ不足等 | エラー通知表示 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし（ユーザー操作による再試行） |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 購入したダウンロード回数に依存 |

### 配信時間帯

制限なし（24時間対応）

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

- ダウンロード操作はログイン済みユーザーのみ実行可能
- ダウンロード権限は購入履歴に基づいて検証
- ファイルパスはローカルストレージ内のみ許可
- MethodChannelを使用したネイティブファイルビューア連携

## 備考

- flutter_local_notificationsパッケージを使用したローカル通知を採用
- Android/iOSの両プラットフォームに対応
- 通知タップ時のペイロードにファイルパスを含め、openFileメソッドで処理
- ダウンロードファイルはBase64エンコードされたデータをデコードして保存
- MethodChannel（defaultChannelName）を使用してネイティブコードでファイルを開く

---

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

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

### 推奨読解順序

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

通知に関連するモデルクラスとダウンロード関連の構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | download_product_model.dart | `lib/screens/downloadable_products/data_model/download_product_model.dart` | Downloadモデルの構造 |
| 1-2 | download_product_Image_model.dart | `lib/screens/downloadable_products/data_model/download_product_Image_model.dart` | DownloadLinkDataModelの構造（Base64データ） |

**読解のコツ**: ダウンロード処理は2段階（DownloadProductEvent → DownloadBase64ProductEvent）で行われる。

#### Step 2: 通知作成ロジックを理解する

通知を作成するコアメソッドを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | push_notifications_manager.dart | `lib/utils/push_notifications_manager.dart` | createDownloadNotificationメソッド（152-176行目） |

**主要処理フロー**:
1. **155-163行目**: AndroidNotificationDetails設定（進捗バー、優先度等）
2. **165-166行目**: NotificationDetails作成
3. **167-174行目**: flutterLocalNotificationsPlugin.show呼び出し
4. **170-172行目**: 完了/進行中の判定（total == progress ? Completed : Started）

#### Step 3: ファイルオープン処理を理解する

通知タップ時のファイルオープン処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | push_notifications_manager.dart | `lib/utils/push_notifications_manager.dart` | openFileメソッド（178-189行目）、onDidReceiveNotificationResponse（51-58行目） |

**主要処理フロー**:
- **51-58行目**: 通知タップ時のコールバック（payloadからpathを取得）
- **178-189行目**: MethodChannelを使用したネイティブファイルビューア呼び出し

#### Step 4: ダウンロード処理フローを理解する

全体のダウンロード処理フローを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | downloadable_products.dart | `lib/screens/downloadable_products/view/downloadable_products.dart` | BlocConsumerのlistener（110-133行目） |
| 4-2 | downloadable_products_bloc.dart | `lib/screens/downloadable_products/bloc/downloadable_products_bloc.dart` | イベントハンドリング（41-68行目） |

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

```
download_button.dart (UI Layer)
    │
    └─ DownloadProductEvent発行
           │
           ▼
    DownloadableProductsBloc
           │
           ├─ DownloadProductEvent handler
           │      │
           │      └─ Repository.downloadProductLink()
           │             │
           │             └─ DownloadProductState発行
           │
           └─ DownloadBase64ProductEvent handler（自動発行）
                  │
                  └─ Repository.dataBase64ProductModel()
                         │
                         └─ DownloadBase64ProductState発行
                                │
                                ▼
    downloadable_products.dart (listener)
           │
           └─ DownloadFile.saveBase64String()
                  │
                  └─ createDownloadNotification()
                         │
                         ▼
    PushNotificationsManager
           │
           └─ flutterLocalNotificationsPlugin.show()
                  │
                  ▼
    System Notification Bar
           │
           └─ User Tap → openFile() → MethodChannel → Native File Viewer
```

### データフロー図

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

User Tap Download  ───▶  DownloadProductEvent       ───▶  API Call
                              │
                              ▼
                         Download Link取得
                              │
                              ▼
                    DownloadBase64ProductEvent
                              │
                              ▼
                         Base64データ取得
                              │
                              ▼
                    DownloadFile.saveBase64String()
                              │
                              ▼
                    createDownloadNotification()
                              │
                              ▼
                    System Notification Bar
                    "filename - Completed"
                              │
                              ▼
User Tap Notification ───▶  openFile()              ───▶  Native File Viewer
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| push_notifications_manager.dart | `lib/utils/push_notifications_manager.dart` | ソース | 通知管理、createDownloadNotification |
| downloadable_products.dart | `lib/screens/downloadable_products/view/downloadable_products.dart` | ソース | ダウンロード可能商品一覧画面 |
| download_button.dart | `lib/screens/downloadable_products/view/widgets/download_button.dart` | ソース | ダウンロードボタンウィジェット |
| downloadable_products_bloc.dart | `lib/screens/downloadable_products/bloc/downloadable_products_bloc.dart` | ソース | 状態管理、API呼び出し |
| download_product_model.dart | `lib/screens/downloadable_products/data_model/download_product_model.dart` | ソース | ダウンロードリンクモデル |
| download_product_Image_model.dart | `lib/screens/downloadable_products/data_model/download_product_Image_model.dart` | ソース | Base64データモデル |
| string_constants.dart | `lib/utils/string_constants.dart` | 設定 | 文字列定数定義（completed, started） |
| server_configuration.dart | `lib/utils/server_configuration.dart` | 設定 | MethodChannelの定数定義 |
