# 機能設計書 11-商品詳細表示

## 概要

本ドキュメントは、Eコマースモバイルアプリケーションにおける商品詳細表示機能の設計仕様を定義する。本機能は、個別商品の詳細情報（画像、価格、説明、レビュー、在庫状況等）をユーザーに表示し、カート追加やウィッシュリスト登録などの購買行動を促進する。

### 本機能の処理概要

**業務上の目的・背景**：
ユーザーが商品を購入する際、詳細な商品情報を確認することは購買意思決定において不可欠である。本機能は商品一覧やカテゴリ画面から遷移したユーザーに対し、商品の全情報を提供し、購入や比較検討を支援する。適切な商品情報の提示により、ユーザーの購買体験を向上させ、コンバージョン率の向上に貢献する。

**機能の利用シーン**：
- ホーム画面や商品一覧から特定の商品をタップした際
- 検索結果から商品を選択した際
- ウィッシュリストやカートから商品詳細を確認する際
- 商品URLを直接共有された際

**主要な処理内容**：
1. 商品ID（urlKey）を基にGraphQL APIから商品詳細データを取得
2. 商品画像ギャラリーの表示（スワイプによる画像切り替え、ズーム機能）
3. 価格情報の表示（通常価格、セール価格、税込表示）
4. 商品説明・追加情報の表示（HTMLレンダリング対応）
5. 商品タイプに応じたオプション選択（configurable、bundle、grouped、downloadable、booking）
6. 数量選択機能
7. カート追加、ウィッシュリスト追加、比較リスト追加機能
8. 商品レビューの表示
9. 最近閲覧した商品への登録（Hiveローカルストレージ）
10. SNS共有機能

**関連システム・外部連携**：
- Bagisto GraphQL API（商品情報取得、カート追加、ウィッシュリスト操作）
- Hive（ローカルストレージ、最近閲覧商品の保存）
- share_plus（SNS共有機能）

**権限による制御**：
- ウィッシュリスト追加：ログイン必須
- 比較リスト追加：ログイン必須
- カート追加：ゲストユーザーも可能
- レビュー投稿リンク：ログイン必須

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 7 | 商品詳細画面 | 主画面 | 商品詳細情報の表示、カート追加、ウィッシュリスト追加 |
| 2 | ホーム画面 | 参照画面 | 商品詳細画面への遷移元 |
| 8 | カテゴリ商品一覧画面 | 参照画面 | 商品詳細画面への遷移元 |
| 10 | 検索画面 | 参照画面 | 商品詳細画面への遷移元 |
| 12 | カート画面 | 遷移先画面 | カート追加後の遷移先 |

## 機能種別

CRUD操作（Read）/ データ連携 / バリデーション

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| productId | int? | No | 商品ID | 数値のみ |
| title | String? | No | 商品名（AppBar表示用） | - |
| urlKey | String? | Yes | 商品URL識別キー | 空文字不可 |
| qty | int | Yes | 購入数量 | 1以上の整数 |
| configurableParams | List | No | Configurable商品のバリアント選択 | 商品タイプがconfigurableの場合必須 |
| bundleParams | List | No | Bundle商品のオプション選択 | 商品タイプがbundleの場合必須 |
| groupedParams | List | No | Grouped商品の数量指定 | 商品タイプがgroupedの場合1つ以上必須 |
| downloadLinks | List | No | ダウンロード商品のリンク選択 | 商品タイプがdownloadableの場合必須 |
| bookingParams | Map<String, dynamic> | No | 予約商品のスロット情報 | 商品タイプがbookingの場合必須 |
| customizableOptionsSelection | Map<String, dynamic> | No | カスタマイズオプション選択 | isRequired=trueの項目は必須 |

### 入力データソース

- 画面遷移パラメータ（PassProductData）
- GraphQL API（商品詳細データ）
- ユーザー入力（数量、オプション選択）
- SharedPreferences（ログイン状態、カート数）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| productData | NewProducts? | 商品詳細情報オブジェクト |
| cart | CartModel? | カート情報 |
| addToCartModel | AddToCartModel? | カート追加結果 |
| downloadSampleModel | DownloadSampleModel? | サンプルダウンロード結果 |
| bookingSlotsData | BookingSlotsData? | 予約スロット情報 |

### 出力先

- 画面表示（商品情報、価格、画像、レビュー）
- Hive（最近閲覧商品への保存）
- GlobalData.cartCountController（カート数更新）

## 処理フロー

### 処理シーケンス

```
1. 画面初期化（initState）
   └─ ログイン状態確認、BLoCイベント発行（FetchProductEvent）
2. 商品詳細データ取得
   └─ ProductScreenRepo.getProductDetails()でGraphQL API呼び出し
3. 画面構築
   └─ BlocConsumer<ProductScreenBLoc, ProductBaseState>で状態管理
4. 商品タイプに応じたUI表示
   └─ ProductTypeViewで各商品タイプのオプションを表示
5. ユーザーアクション処理
   ├─ カート追加：_addToCart()でバリデーション後API呼び出し
   ├─ ウィッシュリスト追加：AddToWishListProductEvent発行
   └─ 比較リスト追加：AddToCompareListEvent発行
6. 画面終了時
   └─ setRecentViewed()で最近閲覧商品に保存
```

### フローチャート

```mermaid
flowchart TD
    A[画面表示開始] --> B[FetchProductEvent発行]
    B --> C{API呼び出し成功?}
    C -->|Yes| D[商品データ表示]
    C -->|No| E[エラー画面表示]
    D --> F[ユーザー操作待機]
    F --> G{操作種別}
    G -->|カート追加| H[バリデーションチェック]
    G -->|ウィッシュリスト| I{ログイン済み?}
    G -->|比較リスト| J{ログイン済み?}
    G -->|戻る| K[最近閲覧に保存]
    H --> L{商品タイプ別検証}
    L -->|OK| M[AddToCartProductEvent発行]
    L -->|NG| N[警告メッセージ表示]
    I -->|Yes| O[AddToWishListProductEvent発行]
    I -->|No| P[ログイン要求メッセージ]
    J -->|Yes| Q[AddToCompareListEvent発行]
    J -->|No| P
    K --> R[画面終了]
    M --> S{API成功?}
    S -->|Yes| T[成功メッセージ・カート数更新]
    S -->|No| U[エラーメッセージ表示]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | ログイン要求 | ウィッシュリスト・比較リスト追加はログインユーザーのみ | 非ログイン時にこれらの機能を使用しようとした場合 |
| BR-02 | 在庫チェック | isSaleable=falseの場合、カート追加ボタンを無効化 | 常時 |
| BR-03 | バリアント必須選択 | Configurable商品は全属性の選択が必須 | 商品タイプがconfigurableの場合 |
| BR-04 | グループ商品最低数量 | Grouped商品は1つ以上の商品数量指定が必須 | 商品タイプがgroupedの場合 |
| BR-05 | ダウンロードリンク必須 | Downloadable商品はリンク選択が必須 | 商品タイプがdownloadableの場合 |
| BR-06 | 予約スロット必須 | Booking商品はスロット選択が必須（eventタイプを除く） | 商品タイプがbookingの場合 |
| BR-07 | テーブル予約備考必須 | テーブル予約タイプはnoteフィールドが必須 | booking.type=tableの場合 |
| BR-08 | カスタマイズ必須項目 | isRequired=trueのカスタマイズオプションは入力必須 | カスタマイズオプションが存在する場合 |

### 計算ロジック

- 商品価格の表示はpriceHtmlフィールドのHTML形式をそのまま使用
- バリアント選択時の価格変動はconfigurableData.indexから対応するIDを特定

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 商品詳細取得 | products | SELECT | url_keyをキーに商品情報を取得 |
| カート追加 | cart_items | INSERT | 商品をカートに追加 |
| ウィッシュリスト追加 | wishlist_items | INSERT/DELETE | ウィッシュリストへの追加・削除 |
| 比較リスト追加 | compare_items | INSERT | 比較リストへの追加 |
| 最近閲覧保存 | - (Hive) | INSERT | ローカルストレージに保存 |

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

#### products（GraphQL経由）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | 全フィールド | url_key = 指定値 | GraphQL: getAllProducts |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ネットワークエラー | インターネット接続なし | 「インターネット接続を確認してください」メッセージ表示 |
| - | API失敗 | GraphQL APIエラー | FetchProductState.failでエラー画面表示 |
| - | バリデーションエラー | 必須オプション未選択 | ShowMessage.warningNotificationで警告表示 |
| - | ログイン必須エラー | 非ログイン時のウィッシュリスト等 | 「ログインしてください」メッセージ表示 |

### リトライ仕様

- Pull-to-Refreshによる手動リトライをサポート（RefreshIndicator）

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

本機能はGraphQL API経由でバックエンドと通信するため、トランザクション制御はバックエンド側で実施される。

## パフォーマンス要件

- 商品詳細画面の初期表示: 3秒以内
- 画像読み込み: 遅延読み込み（LazyLoad）採用
- ローディング表示: ProductDetailLoaderによるスケルトンUI

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

- ログイン状態の確認: appStoragePref.getCustomerLoggedIn()
- 認証トークン: GraphQL API呼び出し時にAuthorizationヘッダー付与
- ユーザー固有操作（ウィッシュリスト等）はログイン必須チェック

## 備考

- BLoCパターン（flutter_bloc）を使用した状態管理
- Hiveを使用した最近閲覧商品のローカルキャッシュ
- 多言語対応（GlobalData.locale）

---

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

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

### 推奨読解順序

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

商品詳細画面で扱うデータモデルを理解することが最初のステップである。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | product_details_model.dart | `lib/screens/product_screen/data_model/product_details_model.dart` | Product, PriceHtml, ProductCustomizableOptionsの構造を理解 |
| 1-2 | new_product_data.dart | `lib/screens/home_page/data_model/new_product_data.dart` | NewProducts, NewProductsModelの構造（APIレスポンス形式） |
| 1-3 | cart_data_model.dart | `lib/screens/cart_screen/cart_model/cart_data_model.dart` | CartModel, Itemsの構造（カート追加結果） |

**読解のコツ**: Dartの@JsonSerializable()アノテーションが付いたクラスはJSONシリアライズ/デシリアライズ用。`.g.dart`ファイルは自動生成されるため直接編集しない。

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

画面の起点となるWidgetを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | product_screen.dart | `lib/screens/product_screen/view/product_screen.dart` | ProductScreenクラスがエントリーポイント |

**主要処理フロー**:
1. **59-64行目**: initState()でログイン状態確認、FetchProductEvent発行
2. **152-196行目**: _setProductData()でBlocConsumerによる状態監視
3. **200-337行目**: buildContainer()で状態に応じたUI構築
4. **340-580行目**: _addToCart()でカート追加処理（商品タイプ別分岐）
5. **671-678行目**: setRecentViewed()で最近閲覧商品へ保存

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | product_page_event.dart | `lib/screens/product_screen/bloc/product_page_event.dart` | イベント定義（FetchProductEvent, AddToCartProductEvent等） |
| 3-2 | product_page_bloc.dart | `lib/screens/product_screen/bloc/product_page_bloc.dart` | イベントハンドリングとState発行ロジック |
| 3-3 | product_page_repository.dart | `lib/screens/product_screen/bloc/product_page_repository.dart` | API呼び出しの実装 |

**主要処理フロー（product_page_bloc.dart）**:
- **28-37行目**: FetchProductEventの処理（商品詳細取得）
- **38-61行目**: AddToCartProductEventの処理（カート追加）
- **62-75行目**: AddToCompareListEventの処理（比較リスト追加）
- **76-103行目**: AddToWishListProductEventの処理（ウィッシュリスト追加）
- **132-146行目**: DownloadProductSampleEventの処理（サンプルダウンロード）
- **147-156行目**: GetSlotEventの処理（予約スロット取得）

#### Step 4: View層のコンポーネントを理解する

画面を構成する各Widgetを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | product_view.dart | `lib/screens/product_screen/view/widget/product_view.dart` | 商品詳細のメインビュー構成 |
| 4-2 | about_product_view.dart | `lib/screens/product_screen/view/widget/about_product_view.dart` | 商品説明、追加情報、レビューサマリー |
| 4-3 | product_image_view.dart | `lib/screens/product_screen/view/product_image_view.dart` | 商品画像ギャラリー |
| 4-4 | product_type_view.dart | `lib/screens/product_screen/view/widget/product_type_view.dart` | 商品タイプ別オプション選択UI |

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

```
ProductScreen (view/product_screen.dart)
    │
    ├─ ProductScreenBLoc (bloc/product_page_bloc.dart)
    │      │
    │      └─ ProductScreenRepo (bloc/product_page_repository.dart)
    │             │
    │             └─ ApiClient (services/api_client.dart)
    │                    └─ GraphQL API (外部)
    │
    ├─ ProductView (view/widget/product_view.dart)
    │      │
    │      ├─ ProductImageView (view/product_image_view.dart)
    │      │
    │      ├─ ProductTypeView (view/widget/product_type_view.dart)
    │      │      ├─ QuantityView
    │      │      ├─ ConfigurableOptionView
    │      │      ├─ BundleOptionView
    │      │      ├─ GroupProductView
    │      │      ├─ DownloadableProductOptions
    │      │      └─ BookingOptionView
    │      │
    │      └─ AboutProductView (view/widget/about_product_view.dart)
    │             └─ ProductReviewSummaryView
    │
    └─ Hive (recentProducts box)
```

### データフロー図

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

urlKey ─────────────────▶ FetchProductEvent
                              │
                              ▼
                         ProductScreenBLoc
                              │
                              ▼
                         ProductScreenRepo.getProductDetails()
                              │
                              ▼
                         ApiClient.getAllProducts()
                              │
                              ▼
                         GraphQL API
                              │
                              ▼
                         NewProductsModel ──────────▶ 画面表示

ユーザー入力 ────────────▶ AddToCartProductEvent
(qty, options)                │
                              ▼
                         バリデーション
                              │
                              ▼
                         ApiClient.addToCart()
                              │
                              ▼
                         AddToCartModel ───────────▶ 成功/エラーメッセージ
                                                    カート数更新

商品データ ──────────────▶ setRecentViewed()
                              │
                              ▼
                         Hive.openBox("recentProducts")
                              │
                              ▼
                         ローカルストレージ保存
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| product_screen.dart | `lib/screens/product_screen/view/product_screen.dart` | ソース | 商品詳細画面のエントリーポイント |
| product_page_bloc.dart | `lib/screens/product_screen/bloc/product_page_bloc.dart` | ソース | 状態管理BLoC |
| product_page_event.dart | `lib/screens/product_screen/bloc/product_page_event.dart` | ソース | イベント定義 |
| product_page_state.dart | `lib/screens/product_screen/bloc/product_page_state.dart` | ソース | 状態定義 |
| product_page_repository.dart | `lib/screens/product_screen/bloc/product_page_repository.dart` | ソース | APIリポジトリ |
| product_details_model.dart | `lib/screens/product_screen/data_model/product_details_model.dart` | ソース | データモデル |
| download_sample_model.dart | `lib/screens/product_screen/data_model/download_sample_model.dart` | ソース | サンプルダウンロードモデル |
| product_view.dart | `lib/screens/product_screen/view/widget/product_view.dart` | ソース | メインビューWidget |
| about_product_view.dart | `lib/screens/product_screen/view/widget/about_product_view.dart` | ソース | 商品説明Widget |
| product_image_view.dart | `lib/screens/product_screen/view/product_image_view.dart` | ソース | 画像ギャラリーWidget |
| product_type_view.dart | `lib/screens/product_screen/view/widget/product_type_view.dart` | ソース | 商品タイプ別オプションWidget |
| quantity_view.dart | `lib/screens/product_screen/view/quantity_view.dart` | ソース | 数量選択Widget |
| index.dart | `lib/screens/product_screen/utils/index.dart` | ソース | エクスポート集約 |
