# 機能設計書 12-商品検索

## 概要

本ドキュメントは、Eコマースモバイルアプリケーションにおける商品検索機能の設計仕様を定義する。本機能は、ユーザーがキーワード入力、音声入力、画像認識により商品を検索し、結果を一覧表示する。

### 本機能の処理概要

**業務上の目的・背景**：
ECサイトにおいて商品検索は、ユーザーが目的の商品に素早くアクセスするための最重要機能である。カテゴリブラウジングだけでなく、直接的なキーワード検索を提供することで、ユーザーの購買意思を迅速に商品発見へ結びつける。また、音声検索や画像検索といった多様な入力手段を提供することで、ユーザビリティを向上させる。

**機能の利用シーン**：
- ホーム画面の検索アイコンをタップして検索画面を開いた際
- 特定の商品名やブランド名で商品を探したい際
- 音声で商品名を伝えて検索したい際
- 商品画像やテキストを撮影して類似商品を検索したい際

**主要な処理内容**：
1. テキスト入力による商品名検索（3文字以上で自動検索開始）
2. 音声認識による検索キーワード入力（SpeechToText使用）
3. カメラを使用した画像検索・テキスト認識検索
4. 検索結果の商品一覧表示
5. カテゴリ一覧の表示（検索画面上部）
6. 検索キーワードのクリア機能

**関連システム・外部連携**：
- Bagisto GraphQL API（商品検索、カテゴリ取得）
- SpeechToText（speech_to_text パッケージ）
- カメラ機能（MethodChannel経由でネイティブ連携）
- InternetConnectionChecker（ネットワーク状態確認）

**権限による制御**：
- カメラ検索：カメラ権限の許可が必要
- 音声検索：マイク権限の許可が必要
- 商品検索自体は認証不要（ゲストユーザーも利用可能）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 10 | 検索画面 | 主画面 | キーワード入力、音声入力、画像検索、結果表示 |
| 7 | 商品詳細画面 | 遷移先画面 | 検索結果から商品を選択した際の遷移先 |
| 8 | カテゴリ商品一覧画面 | 遷移先画面 | カテゴリ選択時の遷移先 |

## 機能種別

CRUD操作（Read）/ データ連携 / ユーザー入力処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| searchText | String | Yes | 検索キーワード | 3文字以上 |
| filters | List<Map<String, dynamic>> | Yes | 検索フィルター | name フィールドを含む |

### 入力データソース

- ユーザーのテキスト入力（TextField）
- 音声認識結果（SpeechToText）
- 画像認識・テキスト認識結果（MethodChannel経由）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| products | NewProductsModel? | 検索結果の商品リスト |
| data | List<HomeCategories>? | カテゴリ一覧 |

### 出力先

- 画面表示（検索結果リスト、カテゴリ一覧）

## 処理フロー

### 処理シーケンス

```
1. 画面初期化（initState）
   ├─ 音声認識の初期化（activateSpeechRecognizer）
   └─ カテゴリ一覧取得（FetchCategoryPageEvent）
2. ユーザー入力待機
   ├─ テキスト入力：onChanged で3文字以上で検索開始
   ├─ 音声入力：マイクボタンタップで録音開始
   └─ 画像入力：カメラボタンタップでダイアログ表示
3. 検索実行
   └─ FetchSearchEvent発行 → SearchRepository.callSearchAPi
4. 結果表示
   └─ FetchSearchDataStateで商品リスト更新
```

### フローチャート

```mermaid
flowchart TD
    A[検索画面表示] --> B[カテゴリ一覧取得]
    B --> C[入力待機]
    C --> D{入力方法}
    D -->|テキスト| E{3文字以上?}
    D -->|音声| F[音声認識開始]
    D -->|画像| G[カメラ起動]
    E -->|Yes| H[FetchSearchEvent発行]
    E -->|No| C
    F --> I[認識結果取得]
    I --> H
    G --> J[画像/テキスト認識]
    J --> H
    H --> K[API呼び出し]
    K --> L{成功?}
    L -->|Yes| M[検索結果表示]
    L -->|No| N[エラー/空結果表示]
    M --> C
    N --> C
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 最小文字数 | 検索キーワードは3文字以上必要 | テキスト/音声入力時 |
| BR-02 | 自動検索 | 3文字以上入力で自動的に検索開始 | テキスト入力時 |
| BR-03 | カメラ権限 | 画像検索にはカメラ権限が必要 | 画像検索時 |
| BR-04 | ネットワーク必須 | 画像検索はネットワーク接続が必須 | 画像検索時 |

### 計算ロジック

特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 商品検索 | products | SELECT | name フィールドで部分一致検索 |
| カテゴリ取得 | categories | SELECT | status=1, parent_id=1 のカテゴリ取得 |

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

#### products（GraphQL経由）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | 全フィールド | name LIKE '%keyword%' | GraphQL: getAllProducts |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ネットワークエラー | インターネット接続なし | DialogHelper.networkErrorDialog表示 |
| - | カメラ権限エラー | カメラ権限が拒否された | 設定画面への誘導 |
| - | 検索結果なし | 該当商品がない | EmptyDataView表示 |
| - | 音声認識エラー | 音声認識が利用不可 | マイクアイコン変更で状態表示 |

### リトライ仕様

- 画像検索時のネットワークエラーはダイアログで再試行可能

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

読み取り専用のため、トランザクション制御は不要。

## パフォーマンス要件

- 検索結果表示: 2秒以内
- インクリメンタル検索: 入力後即時リクエスト
- LinearProgressIndicatorでローディング状態を表示

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

- 検索クエリのサニタイズはバックエンドで実施
- カメラ・マイク権限は都度確認

## 備考

- 音声認識はspeech_to_textパッケージを使用
- 画像認識はネイティブコード（MethodChannel）経由で実装

---

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

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

### 推奨読解順序

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

検索機能で扱うデータモデルを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | new_product_data.dart | `lib/screens/home_page/data_model/new_product_data.dart` | NewProductsModel, NewProductsの構造 |
| 1-2 | categories_data_model.dart | `lib/data_model/categories_data_model/categories_data_model.dart` | GetDrawerCategoriesData, HomeCategoriesの構造 |

**読解のコツ**: 検索結果はNewProductsModelとして返却され、商品一覧と同じデータ構造を使用している。

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

検索画面のメインWidgetを確認する。

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

**主要処理フロー**:
1. **39-47行目**: initState()で音声認識初期化、カテゴリ取得イベント発行
2. **50-58行目**: activateSpeechRecognizer()で音声認識を初期化
3. **60-73行目**: onRecognitionResult()で音声認識結果を処理
4. **162-170行目**: テキスト入力のonChangedで3文字以上なら検索開始
5. **233-260行目**: 音声入力ボタンのUI（アニメーション付き）
6. **288-308行目**: カメラ権限確認とネイティブ呼び出し
7. **310-324行目**: 画像検索結果の処理

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | search_event.dart | `lib/screens/search_screen/bloc/search_event.dart` | イベント定義 |
| 3-2 | search_bloc.dart | `lib/screens/search_screen/bloc/search_bloc.dart` | イベント処理ロジック |
| 3-3 | search_repository.dart | `lib/screens/search_screen/bloc/search_repository.dart` | API呼び出し |

**主要処理フロー（search_bloc.dart）**:
- **26-31行目**: SearchBarTextEventの処理（検索テキスト状態管理）
- **36-45行目**: FetchSearchEventの処理（商品検索API呼び出し）
- **48-59行目**: FetchCategoryPageEventの処理（カテゴリ取得）

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | categories_view.dart | `lib/screens/search_screen/view/widget/categories_view.dart` | カテゴリ一覧表示 |
| 4-2 | product_list.dart | `lib/screens/search_screen/view/widget/product_list.dart` | 検索結果の商品リスト表示 |

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

```
SearchScreen (view/search_screen.dart)
    │
    ├─ SearchBloc (bloc/search_bloc.dart)
    │      │
    │      └─ SearchRepositoryImp (bloc/search_repository.dart)
    │             │
    │             └─ ApiClient
    │                    ├─ getAllProducts() → GraphQL API
    │                    └─ homeCategories() → GraphQL API
    │
    ├─ SpeechToText (speech_to_text パッケージ)
    │
    ├─ MethodChannel (ネイティブ連携)
    │      ├─ imageSearch
    │      └─ textSearch
    │
    ├─ CategoriesView (view/widget/categories_view.dart)
    │
    └─ ProductList (view/widget/product_list.dart)
```

### データフロー図

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

テキスト入力 ───────────▶ SearchBarTextEvent
(3文字以上)                   │
                              ▼
                         FetchSearchEvent
                              │
                              ▼
                         SearchRepositoryImp.callSearchAPi()
                              │
                              ▼
                         ApiClient.getAllProducts()
                              │
                              ▼
                         GraphQL API
                              │
                              ▼
                         NewProductsModel ──────────▶ ProductList表示

音声入力 ─────────────▶ SpeechToText.listen()
                              │
                              ▼
                         onRecognitionResult()
                              │
                              ▼
                         SearchBarTextEvent ─────────▶ (同上)

画像入力 ─────────────▶ MethodChannel.invokeMethod()
                              │
                              ▼
                         認識結果テキスト
                              │
                              ▼
                         FetchSearchEvent ──────────▶ (同上)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| search_screen.dart | `lib/screens/search_screen/view/search_screen.dart` | ソース | 検索画面のエントリーポイント |
| search_bloc.dart | `lib/screens/search_screen/bloc/search_bloc.dart` | ソース | 状態管理BLoC |
| search_event.dart | `lib/screens/search_screen/bloc/search_event.dart` | ソース | イベント定義 |
| search_state.dart | `lib/screens/search_screen/bloc/search_state.dart` | ソース | 状態定義 |
| search_repository.dart | `lib/screens/search_screen/bloc/search_repository.dart` | ソース | APIリポジトリ |
| categories_view.dart | `lib/screens/search_screen/view/widget/categories_view.dart` | ソース | カテゴリ表示Widget |
| product_list.dart | `lib/screens/search_screen/view/widget/product_list.dart` | ソース | 商品リストWidget |
| index.dart | `lib/screens/search_screen/utils/index.dart` | ソース | エクスポート集約 |
