# 機能設計書 26-ウィッシュリストへ移動

## 概要

本ドキュメントは、ECモバイルアプリにおけるカート内商品をウィッシュリストに移動する機能について設計仕様を定義する。

### 本機能の処理概要

本機能は、ショッピングカートに追加された商品をカートから削除し、同時にウィッシュリスト（お気に入り）に追加する機能である。

**業務上の目的・背景**：ECサイトにおいて、ユーザーがカートに入れた商品を後で購入したい場合や、購入を検討中の商品を一時的に保存したい場合がある。カートから直接ウィッシュリストに移動できる機能により、商品を再検索する手間を省き、購入検討中の商品を効率的に管理できる。また、カート内の商品整理を容易にする。

**機能の利用シーン**：ユーザーがカート画面で購入を後回しにしたい商品がある場合に利用される。例えば、予算調整のためにカートから一部商品を外しつつ、後で購入したい場合や、セール待ちの商品をウィッシュリストに保存する場合に活用される。

**主要な処理内容**：
1. カート画面のアイテムリストにて「Move to Wishlist」ボタンを押下
2. ログイン状態を確認（ログイン必須）
3. MoveToCartEventを発行し、GraphQL API経由でサーバーに送信
4. サーバーでカートから削除とウィッシュリスト追加を実行
5. 成功時はカートから商品を削除し、画面を更新
6. 成功メッセージを表示

**関連システム・外部連携**：Bagisto GraphQL APIとの連携により、`moveToWishlist` mutationを使用してカートからウィッシュリストへ商品を移動する。

**権限による制御**：ログインユーザーのみ利用可能。ウィッシュリストはユーザーアカウントに紐づくため、認証が必須となる。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 12 | カート画面 | 主画面 | カート内商品をウィッシュリストに移動する処理 |

## 機能種別

CRUD操作（Delete + Create）/ 認証必須

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | int | Yes | カートアイテムID | 正の整数であること |

### 入力データソース

画面操作（カートアイテムの「Move to Wishlist」ボタン押下）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| success | bool | 処理成功可否 |
| message | String | 処理結果メッセージ |
| cart | CartModel | 更新後のカート情報 |

### 出力先

- 画面表示（カート画面から該当アイテムを削除）
- ウィッシュリストへの商品追加（サーバー側）
- グローバルカート数表示の更新

## 処理フロー

### 処理シーケンス

```
1. ユーザーが「Move to Wishlist」ボタンを押下
   └─ CartListItem.onPressed処理
2. ログイン状態をチェック
   └─ appStoragePref.getCustomerLoggedIn()
3. ログイン済みの場合、MoveToCartEventを発行
   └─ カートアイテムIDをパラメータとして渡す
4. CartScreenBlocがイベントを受信
   └─ repository.moveToWishlistを呼び出し
5. CartScreenRepositoryがApiClientを経由でAPI呼び出し
   └─ GraphQL mutation moveToWishlistを実行
6. サーバーでカート削除＋ウィッシュリスト追加を実行
7. 成功時: MoveToCartState.successを発行
   └─ ローカルのカートリストからアイテムを削除
8. カートデータを再取得し画面更新
9. 成功メッセージを表示
```

### フローチャート

```mermaid
flowchart TD
    A[Move to Wishlistボタン押下] --> B{ログイン済み?}
    B -->|No| C[ログイン警告メッセージ表示]
    B -->|Yes| D[MoveToCartEvent発行]
    D --> E[CartScreenBloc処理]
    E --> F[API呼び出し]
    F --> G{成功?}
    G -->|Yes| H[MoveToCartState.success]
    H --> I[ローカルリストから削除]
    I --> J[カートデータ再取得]
    J --> K[画面更新]
    K --> L[成功メッセージ表示]
    G -->|No| M[MoveToCartState.fail]
    M --> N[エラーメッセージ表示]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-026-01 | ログイン必須 | ウィッシュリストへの移動はログインユーザーのみ可能 | ボタン押下時 |
| BR-026-02 | 一括処理 | カート削除とウィッシュリスト追加を一度のAPIで実行 | API呼び出し時 |
| BR-026-03 | 重複確認 | 既にウィッシュリストにある商品も移動可能（サーバー側で処理） | API呼び出し時 |

### 計算ロジック

カート合計金額 = 移動後の残存商品の合計

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| カートから削除 | cart_items | DELETE | 指定されたカートアイテムを削除 |
| ウィッシュリスト追加 | wishlists | INSERT | 商品をウィッシュリストに追加 |
| カート再計算 | carts | UPDATE | カートの合計金額等を再計算 |

### テーブル別操作詳細

#### cart_items

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | - | cart_item_id = 指定ID | 対象レコードを削除 |

#### wishlists

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | customer_id, product_id | ログインユーザーID、商品ID | 新規レコード作成 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 未ログイン | ログインしていない状態で操作 | ログイン警告メッセージ表示 |
| - | ネットワークエラー | API通信失敗 | エラーメッセージを表示 |
| - | セッション切れ | カートセッションが無効 | エラー表示 |

### リトライ仕様

自動リトライは行わない。ユーザーに再操作を促す。

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

サーバー側でトランザクション管理。カート削除とウィッシュリスト追加は同一トランザクション内で実行される。

## パフォーマンス要件

- API応答時間: 2秒以内を目標

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

- 認証: ログインユーザーのみ利用可能
- アクセス権限: 自身のカートアイテムのみ移動可能

## 備考

ウィッシュリストに移動した商品は、ウィッシュリスト画面から「カートに追加」操作で再度カートに戻すことができる。

---

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

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

### 推奨読解順序

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

API応答のデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | add_to_cart_model.dart | `lib/screens/cart_screen/cart_model/add_to_cart_model.dart` | AddToCartModel（移動操作の応答） |
| 1-2 | cart_data_model.dart | `lib/screens/cart_screen/cart_model/cart_data_model.dart` | CartModel（更新後のカート情報） |

**読解のコツ**: moveToWishlistはAddToCartModelを返し、内部にCartModelを含む。

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

Move to Wishlistボタン押下からの流れを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | cart_item.dart | `lib/screens/cart_screen/widget/cart_item.dart` | Move to Wishlistボタンとログインチェック |

**主要処理フロー**:
1. **263-304行目**: Move to Wishlistボタン部分
2. **265-277行目**: ボタン押下時のログインチェック処理
3. **266-267行目**: ログイン済みの場合、MoveToCartEvent発行
4. **272-275行目**: 未ログインの場合、警告メッセージ表示

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

状態管理とビジネスロジックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | cart_screen_event.dart | `lib/screens/cart_screen/bloc/cart_screen_event.dart` | MoveToCartEventの定義（30-33行目） |
| 3-2 | cart_screen_state.dart | `lib/screens/cart_screen/bloc/cart_screen_state.dart` | MoveToCartStateの定義（83-96行目） |
| 3-3 | cart_screen_bloc.dart | `lib/screens/cart_screen/bloc/cart_screen_bloc.dart` | MoveToCartEventの処理（83-99行目） |

**主要処理フロー**:
- **83-99行目**: MoveToCartEventを受信し、repository経由でAPI呼び出し、success判定で状態分岐

#### Step 4: リポジトリ層とAPI層を理解する

実際のAPI呼び出し処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | cart_screen_repository.dart | `lib/screens/cart_screen/bloc/cart_screen_repository.dart` | moveToWishlistメソッド（96-106行目） |
| 4-2 | api_client.dart | `lib/services/api_client.dart` | moveCartToWishlist API呼び出し（556-568行目） |
| 4-3 | mutation_query.dart | `lib/services/mutation_query.dart` | GraphQL mutation定義（421-429行目） |

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

```
CartListItem (cart_item.dart)
    │
    └─ MaterialButton.onPressed
           │
           └─ appStoragePref.getCustomerLoggedIn()
                  │
                  ├─ (ログイン済み) → MoveToCartEvent発行
                  │                     │
                  │                     └─ CartScreenBloc.mapEventToState
                  │                            │
                  │                            └─ CartScreenRepository.moveToWishlist
                  │                                   │
                  │                                   └─ ApiClient.moveCartToWishlist
                  │                                          │
                  │                                          └─ MutationQuery.moveCartToWishlist
                  │
                  └─ (未ログイン) → ShowMessage.warningNotification
```

### データフロー図

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

Move to Wishlist ───▶ ログインチェック ───▶ MoveToCartEvent
      (UI)              (認証確認)          (イベント発行)
                                                  │
                        ┌─────────────────────────┘
                        ▼
              CartScreenBloc
                        │
                        ▼
              CartScreenRepository
                        │
                        ▼
                  ApiClient
                        │
                        ▼
           GraphQL API (moveToWishlist)
                        │
                        ▼
             AddToCartModel ───▶ MoveToCartState ───▶ UI更新
              (応答データ)        (状態通知)      (カートから削除)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| cart_screen.dart | `lib/screens/cart_screen/cart_screen.dart` | ソース | カート画面メインWidget |
| cart_item.dart | `lib/screens/cart_screen/widget/cart_item.dart` | ソース | カートアイテムリスト、移動ボタン |
| cart_screen_bloc.dart | `lib/screens/cart_screen/bloc/cart_screen_bloc.dart` | ソース | カート画面BLoC |
| cart_screen_event.dart | `lib/screens/cart_screen/bloc/cart_screen_event.dart` | ソース | BLoCイベント定義 |
| cart_screen_state.dart | `lib/screens/cart_screen/bloc/cart_screen_state.dart` | ソース | BLoC状態定義 |
| cart_screen_repository.dart | `lib/screens/cart_screen/bloc/cart_screen_repository.dart` | ソース | カート画面リポジトリ |
| add_to_cart_model.dart | `lib/screens/cart_screen/cart_model/add_to_cart_model.dart` | ソース | カート操作応答モデル |
| api_client.dart | `lib/services/api_client.dart` | ソース | API通信クライアント |
| mutation_query.dart | `lib/services/mutation_query.dart` | ソース | GraphQLクエリ定義 |
