# 通知設計書 33-再注文成功/失敗通知

## 概要

本ドキュメントは、ECモバイルアプリケーションにおける「再注文成功/失敗通知」の設計仕様を定義する。ユーザーが過去の注文履歴から同じ商品を再度カートに追加（再注文）した際の処理結果をアプリ内通知で表示する機能について記載する。

### 本通知の処理概要

再注文成功/失敗通知は、ユーザーが注文詳細画面から「再注文」機能を使用して過去の注文内容を現在のカートに追加した際に、その操作結果をリアルタイムでフィードバックする通知機能である。

**業務上の目的・背景**：リピート購入を促進するため、ユーザーが過去に購入した商品を簡単に再注文できる機能は重要である。この機能により、定期的に同じ商品を購入するユーザーの利便性が大幅に向上する。操作結果を即座にフィードバックすることで、ユーザーは再注文が正常に処理されたか、在庫切れなどの問題が発生したかを明確に認識できる。これにより、次のアクション（カート確認や代替商品検索）へスムーズに移行できる。

**通知の送信タイミング**：注文詳細画面において、ユーザーが「再注文」ボタンをタップし、APIリクエストが完了した時点で通知が表示される。BlocパターンによりReOrderStateの状態変化を検知してトリガーされる。

**通知の受信者**：再注文操作を実行したユーザー本人のみが通知を受け取る。通知はアプリ内のオーバーレイ表示であり、他のユーザーには影響しない。

**通知内容の概要**：成功時は緑色の背景でチェックマークアイコンとともにサーバーから返されたメッセージを表示する。失敗時は赤色の背景でキャンセルアイコンとともにエラーメッセージを表示する。

**期待されるアクション**：成功通知の場合、約2秒後にカート画面へ自動遷移し、ユーザーは追加された商品を確認して購入手続きを進める。失敗通知の場合、ユーザーはエラー原因（在庫切れ、商品廃止等）を確認し、代替商品を検索するか、カスタマーサポートに問い合わせる。

## 通知種別

アプリ内通知（オーバーレイ通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（ユーザー操作に対する即時レスポンス） |
| 優先度 | 高（購買フローに直結） |
| リトライ | 無（単発表示、自動消失） |

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

再注文操作を実行したユーザー本人のアプリ画面にのみ表示される。ユーザーIDやセッション情報に基づく送信先決定は不要（ローカル表示のため）。

## 通知テンプレート

### アプリ内通知の場合

| 項目 | 内容 |
|-----|------|
| 表示位置 | 画面上部オーバーレイ |
| 表示時間 | 自動消失（約3秒）、ただし成功時は2秒後にカート画面遷移 |
| スワイプ操作 | 上方向スワイプで即時消去可能 |

### 成功時テンプレート

| 項目 | 内容 |
|-----|------|
| タイトル | "Success"（ローカライズ対応） |
| 背景色 | 緑色（Colors.green.shade400） |
| アイコン | チェックマーク（Icons.check_circle_outline） |

```
本文: {サーバーレスポンスのmessageフィールド}
```

### 失敗時テンプレート

| 項目 | 内容 |
|-----|------|
| タイトル | "Failed"（ローカライズ対応） |
| 背景色 | 赤色（Colors.red） |
| アイコン | キャンセルマーク（Icons.cancel_outlined） |

```
本文: {エラーメッセージ または graphqlErrors}
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| なし | - | - | 本通知には添付ファイルなし |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| message | 成功/エラーメッセージ | AddToCartModel.message / error | Yes |
| title | 通知タイトル | StringConstants（ローカライズ） | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作 | ReOrderEvent発行 | API応答受信後 | 再注文ボタンタップ時 |
| Bloc状態変化 | ReOrderState | status == success または fail | BlocConsumerのlistenerで検知 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 画面遷移中 | 注文詳細画面から離脱している場合は表示されない |
| Bloc未初期化 | OrderDetailBlocが初期化されていない場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[再注文ボタンタップ] --> B[ReOrderEvent発行]
    B --> C[OrderDetailBloc処理]
    C --> D[Repository.reOrderCustomerOrder呼び出し]
    D --> E{API応答}
    E -->|success == true| F[ReOrderState.success発行]
    E -->|success == false/エラー| G[ReOrderState.fail発行]
    F --> H[BlocConsumer.listener検知]
    G --> H
    H --> I{状態判定}
    I -->|success| J[ShowMessage.successNotification]
    I -->|fail| K[ShowMessage.errorNotification]
    J --> L[オーバーレイ表示]
    K --> L
    J --> M[2秒後にカート画面遷移]
    L --> N[自動消失/スワイプ消去]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| orders | 再注文元の注文情報取得 | GraphQL API経由 |
| order_items | 再注文対象商品の取得 | GraphQL API経由 |
| products | 商品の現在在庫確認 | GraphQL API経由 |

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

#### orders

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | 再注文元注文識別 | ReOrderEvent.id |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| cart | INSERT/UPDATE | カートに商品を追加 |
| cart_items | INSERT | カートアイテムの追加 |

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

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

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| API通信エラー | ネットワーク接続不可 | "Something went wrong"メッセージ表示 |
| 在庫切れ | 商品の在庫がない | サーバーエラーメッセージ表示 |
| 商品廃止 | 商品が販売終了 | サーバーエラーメッセージ表示 |
| 認証エラー | セッション切れ | graphqlErrors表示 |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし（ユーザー操作起点） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（24時間対応）

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

- 再注文操作はログイン済みユーザーのみ実行可能
- 自身の注文履歴からのみ再注文可能（他ユーザーの注文は再注文不可）
- 通知内容に個人情報（住所詳細等）は含まない

## 備考

- overlay_supportパッケージを使用したオーバーレイ通知を採用
- 通知のローカライズはStringConstantsおよびlocalized()メソッドで対応
- 再注文成功後、2秒のディレイを経てカート画面（cartScreen）へ自動遷移
- 再注文APIはAddToCartModelを返却し、カートへの商品追加と同様の処理を行う

---

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

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

### 推奨読解順序

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

通知に関連するモデルクラスと状態クラスを理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | order_detail_state.dart | `lib/screens/order_detail/bloc/order_detail_state.dart` | ReOrderState クラスの構造、success/fail の状態定義（66-77行目） |
| 1-2 | order_detail_event.dart | `lib/screens/order_detail/bloc/order_detail_event.dart` | ReOrderEvent の引数（注文ID）（43-50行目） |
| 1-3 | add_to_cart_model.dart | `lib/screens/cart_screen/cart_model/add_to_cart_model.dart` | AddToCartModelの構造（success, message） |

**読解のコツ**: ReOrderStateはAddToCartModelを保持し、成功時にはmodelフィールドからmessageを取得して通知表示に使用する。

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

処理の起点となる画面ファイルを特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | order_detail.dart | `lib/screens/order_detail/view/order_detail.dart` | BlocConsumerのlistener部分（72-82行目） |

**主要処理フロー**:
1. **72行目**: `else if(state is ReOrderState)` - 状態判定
2. **73-77行目**: 成功時の処理（successNotification + 2秒後にcartScreen遷移）
3. **79-81行目**: 失敗時の`ShowMessage.errorNotification`呼び出し

#### Step 3: Bloc処理を理解する

状態管理とAPI呼び出しのロジックを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | order_detail_bloc.dart | `lib/screens/order_detail/bloc/order_detail_bloc.dart` | ReOrderEventハンドリング（58-70行目） |

**主要処理フロー**:
- **58行目**: `else if (event is ReOrderEvent)` - イベント判定
- **60行目**: `repository?.reOrderCustomerOrder(event.id)` - API呼び出し
- **61-62行目**: 成功時の状態発行（success == true）
- **64行目**: 失敗時の状態発行（message または graphqlErrors）

#### Step 4: 通知表示ロジックを理解する

実際の通知表示処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | show_message.dart | `lib/widgets/show_message.dart` | successNotification/errorNotificationメソッド |

**主要処理フロー**:
- **18-36行目**: `successNotification` - 成功通知の表示ロジック
- **38-56行目**: `errorNotification` - エラー通知の表示ロジック

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

```
order_detail.dart (UI Layer)
    │
    ├─ BlocConsumer<OrderDetailBloc, OrderDetailBaseState>
    │      │
    │      └─ listener: (state is ReOrderState)
    │             │
    │             ├─ success → ShowMessage.successNotification()
    │             │                  │
    │             │                  └─ Future.delayed(2秒)
    │             │                         └─ Navigator.pushNamed(cartScreen)
    │             │
    │             └─ fail → ShowMessage.errorNotification()
    │                          └─ showSimpleNotification()
    │
    └─ OrderDetailBloc (Business Logic Layer)
           │
           └─ ReOrderEvent handler
                  │
                  └─ OrderDetailRepository.reOrderCustomerOrder()
                         │
                         └─ GraphQL API Call
```

### データフロー図

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

User Tap ReOrder   ───▶  ReOrderEvent              ───▶  UI Dispatch
                              │
                              ▼
                         OrderDetailBloc
                              │
                              ▼
                    OrderDetailRepository.reOrderCustomerOrder()
                              │
                              ▼
                         GraphQL API
                              │
                              ▼
                         AddToCartModel
                              │
                              ▼
                    ReOrderState (success/fail)
                              │
                              ▼
BlocConsumer       ───▶  listener検知              ───▶  ShowMessage
                              │
                              ▼
                    success: 2秒後にcartScreen遷移
                    fail: エラー通知表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| order_detail.dart | `lib/screens/order_detail/view/order_detail.dart` | ソース | 注文詳細画面、通知表示トリガー |
| order_detail_bloc.dart | `lib/screens/order_detail/bloc/order_detail_bloc.dart` | ソース | 状態管理、API呼び出し |
| order_detail_event.dart | `lib/screens/order_detail/bloc/order_detail_event.dart` | ソース | イベント定義 |
| order_detail_state.dart | `lib/screens/order_detail/bloc/order_detail_state.dart` | ソース | 状態定義 |
| order_detail_repository.dart | `lib/screens/order_detail/bloc/order_detail_repository.dart` | ソース | API通信処理 |
| add_to_cart_model.dart | `lib/screens/cart_screen/cart_model/add_to_cart_model.dart` | ソース | カート追加レスポンスモデル |
| show_message.dart | `lib/widgets/show_message.dart` | ソース | 通知表示ユーティリティ |
| string_constants.dart | `lib/utils/string_constants.dart` | 設定 | 文字列定数定義 |
| order_detail_tile.dart | `lib/screens/order_detail/widgets/order_detail_tile.dart` | ソース | 注文詳細タイル、再注文ボタン |
