# 通知設計書 34-レビュー投稿成功/失敗通知

## 概要

本ドキュメントは、ECモバイルアプリケーションにおける「レビュー投稿成功/失敗通知」の設計仕様を定義する。ユーザーが商品に対してレビュー（評価・コメント）を投稿した際の処理結果をアプリ内通知で表示する機能について記載する。

### 本通知の処理概要

レビュー投稿成功/失敗通知は、ユーザーが商品レビュー投稿画面からタイトル、評価（星）、コメント、画像を入力して投稿した際に、その操作結果をリアルタイムでフィードバックする通知機能である。

**業務上の目的・背景**：商品レビューは他の購入検討者にとって重要な判断材料であり、ECサイトの信頼性向上に貢献する。ユーザーが投稿したレビューが正常に受け付けられたか、または入力内容の問題等でエラーが発生したかを即座にフィードバックすることで、ユーザーは投稿完了を確認でき、必要に応じて再投稿や修正を行うことができる。これにより、質の高いレビューの蓄積を促進し、ECサイト全体の価値向上に寄与する。

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

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

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

**期待されるアクション**：成功通知の場合、約3秒後に投稿画面が自動的に閉じられ、ユーザーは商品詳細画面に戻る。失敗通知の場合、ユーザーはエラー原因を確認し、入力内容を修正して再投稿する。

## 通知種別

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

## 送信仕様

### 基本情報

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

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

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

## 通知テンプレート

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

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

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

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

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

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

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

```
本文: {エラーメッセージ}
```

### 評価未選択時テンプレート

| 項目 | 内容 |
|-----|------|
| タイトル | "Warning"（ローカライズ対応） |
| 背景色 | 黄色（Colors.yellow） |
| アイコン | 警告マーク（Icons.warning_amber） |

```
本文: {pleaseAddRatingメッセージ}
```

### 添付ファイル

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

## テンプレート変数

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

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作 | AddReviewFetchEvent発行 | API応答受信後 | 送信ボタンタップ時 |
| Bloc状態変化 | AddReviewFetchState | status == success または fail | BlocConsumerのlistenerで検知 |
| バリデーション | rating == 0 | 投稿前チェック | 評価未選択時の警告 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 画面遷移中 | レビュー投稿画面から離脱している場合は表示されない |
| Bloc未初期化 | AddReviewBlocが初期化されていない場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[送信ボタンタップ] --> B{フォームバリデーション}
    B -->|OK| C{評価チェック}
    B -->|NG| D[バリデーションエラー表示]
    C -->|rating > 0| E[処理中ダイアログ表示]
    C -->|rating == 0| F[警告通知表示]
    E --> G[AddReviewFetchEvent発行]
    G --> H[AddReviewBloc処理]
    H --> I[Repository.callAddReviewApi呼び出し]
    I --> J{API応答}
    J -->|成功| K[AddReviewFetchState.success発行]
    J -->|失敗| L[AddReviewFetchState.fail発行]
    K --> M[BlocConsumer.listener検知]
    L --> M
    M --> N{状態判定}
    N -->|success| O[ShowMessage.showNotification 成功]
    N -->|fail| P[ShowMessage.showNotification 失敗]
    O --> Q[3秒後に画面クローズ×2]
    P --> R[エラー表示継続]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| products | レビュー対象商品の確認 | GraphQL API経由 |

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

#### products

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | レビュー対象商品識別 | AddReviewFetchEvent.productId |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| product_reviews | INSERT | 新規レビューの登録 |

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

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

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| API通信エラー | ネットワーク接続不可 | エラーメッセージ表示 |
| サーバーエラー | バックエンドエラー | サーバーレスポンスのエラーメッセージ表示 |
| 評価未選択 | rating == 0 | pleaseAddRating警告表示 |
| 入力エラー | フォームバリデーション失敗 | フィールドエラー表示 |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

制限なし（24時間対応）

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

- レビュー投稿はログイン済みユーザーのみ実行可能
- 不正なコンテンツはサーバー側でフィルタリング
- 通知内容に個人情報は含まない

## 備考

- overlay_supportパッケージを使用したオーバーレイ通知を採用
- ShowMessage.showNotificationメソッドで汎用的な通知表示を使用
- 投稿成功後、3秒のディレイを2回経て画面が閉じられる（ダイアログ閉じ + 画面戻り）
- 画像添付機能はhttp.MultipartFileを使用してアップロード

---

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

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

### 推奨読解順序

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | add_review_bloc.dart | `lib/screens/add_review/bloc/add_review_bloc.dart` | AddReviewBlocの構造、状態発行ロジック |
| 1-2 | index.dart | `lib/screens/add_review/utils/index.dart` | 関連ファイルのexport定義 |

**読解のコツ**: AddReviewFetchState.success/failのfactory constructorパターンに注目する。

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

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

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

**主要処理フロー**:
1. **65-66行目**: `if (state is AddReviewFetchState)` - 状態判定、isLoading = true
2. **67-69行目**: 失敗時の`ShowMessage.showNotification`呼び出し
3. **70-77行目**: 成功時の`ShowMessage.showNotification`呼び出し

#### Step 3: 送信処理を理解する

投稿ボタンタップ時の処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | add_review.dart | `lib/screens/add_review/view/add_review.dart` | _onPressSubmitButtonメソッド（272-336行目） |

**主要処理フロー**:
- **273行目**: フォームバリデーション
- **275行目**: 評価チェック（rating > 0）
- **276-309行目**: 処理中ダイアログ表示
- **310-316行目**: AddReviewFetchEvent発行
- **317-320行目**: 3秒後に画面クローズ×2
- **322-327行目**: 評価未選択時の警告通知

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | add_review_bloc.dart | `lib/screens/add_review/bloc/add_review_bloc.dart` | AddReviewFetchEventハンドリング（22-36行目） |

**主要処理フロー**:
- **22行目**: `if (event is AddReviewFetchEvent)` - イベント判定
- **24-30行目**: repository.callAddReviewApi呼び出し
- **32行目**: 成功時の状態発行
- **34行目**: 失敗時の状態発行

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

```
add_review.dart (UI Layer)
    │
    ├─ _onPressSubmitButton()
    │      │
    │      ├─ フォームバリデーション
    │      │
    │      ├─ 評価チェック (rating > 0)
    │      │      │
    │      │      └─ 失敗 → ShowMessage.showNotification (警告)
    │      │
    │      ├─ 処理中ダイアログ表示
    │      │
    │      └─ AddReviewFetchEvent発行
    │
    ├─ BlocConsumer<AddReviewBloc, AddReviewBaseState>
    │      │
    │      └─ listener: (state is AddReviewFetchState)
    │             │
    │             ├─ success → ShowMessage.showNotification (成功)
    │             │
    │             └─ fail → ShowMessage.showNotification (失敗)
    │
    └─ AddReviewBloc (Business Logic Layer)
           │
           └─ AddReviewFetchEvent handler
                  │
                  └─ AddReviewRepository.callAddReviewApi()
                         │
                         └─ GraphQL API Call + MultipartFile
```

### データフロー図

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

User Input:
- title              ───▶  AddReviewFetchEvent       ───▶  UI Dispatch
- rating
- comment
- images (optional)
                              │
                              ▼
                         AddReviewBloc
                              │
                              ▼
                    AddReviewRepository.callAddReviewApi()
                              │
                              ▼
                         GraphQL API + MultipartFile
                              │
                              ▼
                         AddReviewModel
                              │
                              ▼
                    AddReviewFetchState (success/fail)
                              │
                              ▼
BlocConsumer       ───▶  listener検知              ───▶  ShowMessage
                              │
                              ▼
                    success: 3秒後に画面クローズ
                    fail: エラー通知表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| add_review.dart | `lib/screens/add_review/view/add_review.dart` | ソース | レビュー投稿画面、通知表示トリガー |
| add_review_bloc.dart | `lib/screens/add_review/bloc/add_review_bloc.dart` | ソース | 状態管理、API呼び出し |
| add_review_event.dart | `lib/screens/add_review/bloc/add_review_event.dart` | ソース | イベント定義 |
| add_review_state.dart | `lib/screens/add_review/bloc/add_review_state.dart` | ソース | 状態定義 |
| add_review_repository.dart | `lib/screens/add_review/bloc/add_review_repository.dart` | ソース | API通信処理 |
| show_message.dart | `lib/widgets/show_message.dart` | ソース | 通知表示ユーティリティ |
| string_constants.dart | `lib/utils/string_constants.dart` | 設定 | 文字列定数定義 |
| add_image_view.dart | `lib/screens/add_review/view/widgets/add_image_view.dart` | ソース | 画像追加UI |
