# 通知設計書 8-カート商品削除成功通知

## 概要

本ドキュメントは、Bagisto ECモバイルアプリにおけるカートから商品を削除した際に表示される成功通知の設計書である。

### 本通知の処理概要

本通知は、ユーザーがショッピングカートから特定の商品を削除した操作が正常に完了した際に、緑色のオーバーレイ通知を画面上部に表示し、削除成功をフィードバックする機能を提供する。

**業務上の目的・背景**：ECアプリにおいて、カート操作はユーザーの購買フローにおける重要なステップである。カートから商品を削除する際、その操作が正常に完了したことをユーザーに明確にフィードバックすることで、ユーザーは自分の操作が正しく反映されたことを確認できる。これにより、誤って削除していないか、削除が失敗していないかという不安を解消し、スムーズな購買体験を提供する。

**通知の送信タイミング**：カート画面で商品の削除ボタンをタップし、サーバーへの削除リクエストが成功した直後。BLoCパターンにおいて `RemoveCartItemState.success` が emit された時点で通知が表示される。

**通知の受信者**：カート画面で商品削除操作を実行したユーザー本人。

**通知内容の概要**：「Success」タイトルと、サーバーから返却された削除完了メッセージ（`removeCartProductModel?.message`）を表示。緑色の背景とチェックマークアイコン。

**期待されるアクション**：ユーザーは通知を確認し、カート画面が更新されて商品が削除されていることを視覚的に確認する。その後、買い物を継続するかチェックアウトに進む。

## 通知種別

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

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（BLoC状態変化時に即座表示） |
| 優先度 | 中 |
| リトライ | なし |

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

1. カート画面で削除操作を実行したユーザーに対してのみ表示
2. `BlocConsumer` の `listener` で状態変化を検出
3. `RemoveCartItemState` で `CartStatus.success` の場合に通知

## 通知テンプレート

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

| 項目 | 内容 |
|-----|------|
| 表示位置 | 画面上部 |
| 背景色 | Colors.green.shade400 |
| アイコン | Icons.check_circle_outline（白色） |
| 消去方向 | 上方向スワイプ |

### 本文テンプレート

```
タイトル: "Success" (StringConstants.success.localized())
サブタイトル: {removeCartProductModel.message} - サーバーからの成功メッセージ
```

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| message | 削除成功メッセージ | AddToCartModel.message | Yes（空文字許容） |
| context | ビルドコンテキスト | Flutter Widget | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作 | カート商品削除 | RemoveCartItemState.status == CartStatus.success | cart_screen.dart 行64-72 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 削除失敗 | RemoveCartItemState.status == CartStatus.fail の場合はエラー通知 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[削除ボタンタップ] --> B[RemoveCartItemEvent発行]
    B --> C[CartScreenBloc処理]
    C --> D[repository.removeFromCart呼び出し]
    D --> E{API結果}
    E -->|成功| F[RemoveCartItemState.success emit]
    E -->|失敗| G[RemoveCartItemState.fail emit]
    F --> H[BlocConsumer listener検出]
    H --> I[ShowMessage.successNotification呼び出し]
    I --> J[緑色オーバーレイ表示]
    J --> K[カート数更新]
    K --> L[カート画面リフレッシュ]
    G --> M[ShowMessage.errorNotification呼び出し]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| cart_items（サーバー側） | 削除対象商品の確認 | API経由 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| cart_items（サーバー側） | DELETE | 指定商品のカートからの削除 |
| ローカルストレージ | UPDATE | カート商品数の更新 |

#### 送信後の状態更新

| 操作 | 項目 | 更新値 | 備考 |
|-----|-----|-------|------|
| sink.add | GlobalData.cartCountController | 更新後の itemsQty | 行70-71 |
| setCartCount | appStoragePref | 更新後の itemsCount | 行162 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 削除失敗 | API エラー | errorNotification表示（行65-66） |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | なし |
| 1日あたり上限 | なし |

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

- 削除操作は認証済みユーザーのみ実行可能
- 他ユーザーのカート商品は削除不可（サーバー側で検証）

## 備考

- 削除成功後、自動的にカートデータを再取得（`fetchCartData()`）
- カート商品数はグローバルストリームで管理（`GlobalData.cartCountController`）
- 削除された商品IDは `productDeletedId` として状態に保持

---

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

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

### 推奨読解順序

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

カート商品削除のデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | cart_screen_state.dart | `lib/screens/cart_screen/bloc/cart_screen_state.dart` | RemoveCartItemStateの構造 |
| 1-2 | add_to_cart_model.dart | `lib/screens/cart_screen/cart_model/add_to_cart_model.dart` | AddToCartModelのmessageプロパティ |

**読解のコツ**: `CartStatus` 列挙型と各Stateの `.success()` / `.fail()` コンストラクタパターンを理解する。

#### Step 2: イベント発行を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | cart_screen_event.dart | `lib/screens/cart_screen/bloc/cart_screen_event.dart` | RemoveCartItemEventの定義 |

**主要処理フロー**:
- **行39-42**: `RemoveCartItemEvent` クラス
- **行40**: `int? cartItemId` - 削除対象のカートアイテムID

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | cart_screen_bloc.dart | `lib/screens/cart_screen/bloc/cart_screen_bloc.dart` | RemoveCartItemEvent処理 |

**主要処理フロー**:
- **行38-47**: `RemoveCartItemEvent` のハンドリング
- **行40-41**: `repository?.removeFromCart(event.cartItemId!)` 呼び出し
- **行42-44**: 成功時 `RemoveCartItemState.success` emit
- **行45-47**: 失敗時 `RemoveCartItemState.fail` emit

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | cart_screen.dart | `lib/screens/cart_screen/cart_screen.dart` | listenerでの通知処理 |

**主要処理フロー**:
- **行64-72**: `RemoveCartItemState` の処理
- **行65-66**: 失敗時 `ShowMessage.errorNotification(state.error ?? "", context)`
- **行67-69**: 成功時 `ShowMessage.successNotification(state.removeCartProductModel?.message ?? "", context)`
- **行70-71**: カート数更新 `GlobalData.cartCountController.sink.add(...)`

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

```
CartScreen（カート画面）
    |
    +-- 削除ボタンタップ
            |
            +-- cartScreenBloc.add(RemoveCartItemEvent(cartItemId: id))
                    |
                    +-- CartScreenBloc.mapEventToState()
                            |
                            +-- repository.removeFromCart(cartItemId)
                                    |
                                    +-- API呼び出し（GraphQL Mutation）
                                            |
                                            +-- emit(RemoveCartItemState.success/fail)
                                                    |
                                                    +-- BlocConsumer.listener
                                                            |
                                                            +-- ShowMessage.successNotification()
                                                                    |
                                                                    +-- オーバーレイ表示
```

### データフロー図

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

削除ボタンタップ ──────▶ RemoveCartItemEvent(cartItemId)
                                    |
                                    ▼
                            CartScreenBloc
                                    |
                                    ▼
                            repository.removeFromCart()
                                    |
                                    ▼
                            GraphQL API呼び出し
                                    |
                               ┌────┴────┐
                               ▼         ▼
                            成功       失敗
                               |         |
                               ▼         ▼
                    RemoveCartItemState  RemoveCartItemState
                        .success         .fail
                               |         |
                               ▼         ▼
                    successNotification  errorNotification
                               |
                               ▼
                    GlobalData.cartCountController.sink.add()
                               |
                               ▼
                    appStoragePref.setCartCount()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| cart_screen.dart | `lib/screens/cart_screen/cart_screen.dart` | ソース | カート画面UI・通知表示トリガー |
| cart_screen_bloc.dart | `lib/screens/cart_screen/bloc/cart_screen_bloc.dart` | ソース | カート操作のビジネスロジック |
| cart_screen_event.dart | `lib/screens/cart_screen/bloc/cart_screen_event.dart` | ソース | カート操作イベント定義 |
| cart_screen_state.dart | `lib/screens/cart_screen/bloc/cart_screen_state.dart` | ソース | カート操作状態定義 |
| cart_screen_repository.dart | `lib/screens/cart_screen/bloc/cart_screen_repository.dart` | ソース | カートAPI呼び出し |
| show_message.dart | `lib/widgets/show_message.dart` | ソース | 成功通知表示 |
| add_to_cart_model.dart | `lib/screens/cart_screen/cart_model/add_to_cart_model.dart` | モデル | カート操作レスポンスモデル |
