# 機能設計書 13-商品フィルタリング

## 概要

本ドキュメントは、Eコマースモバイルアプリケーションにおける商品フィルタリング機能の設計仕様を定義する。本機能は、カテゴリ商品一覧画面において、属性・価格等による商品の絞り込みを提供する。

### 本機能の処理概要

**業務上の目的・背景**：
ECサイトにおいて、多数の商品の中からユーザーが目的の商品を見つけやすくするために、フィルタリング機能は不可欠である。属性（色、サイズ等）や価格帯での絞り込みにより、ユーザーの購買体験を向上させ、商品発見から購入までの時間を短縮する。

**機能の利用シーン**：
- カテゴリ商品一覧画面で「フィルター」ボタンをタップした際
- 価格帯で商品を絞り込みたい際
- 特定の属性（色、サイズ等）で商品を絞り込みたい際
- 複数の条件を組み合わせて絞り込みたい際

**主要な処理内容**：
1. カテゴリスラグを基にフィルター属性情報を取得
2. 価格範囲フィルター（RangeSlider）の表示と選択
3. 属性オプションフィルター（CheckboxListTile）の表示と選択
4. 複数フィルター条件の組み合わせ
5. フィルター条件のクリア
6. フィルター適用後の商品一覧再取得

**関連システム・外部連携**：
- Bagisto GraphQL API（フィルター属性取得、商品検索）

**権限による制御**：
- 認証不要（ゲストユーザーも利用可能）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 8 | カテゴリ商品一覧画面 | 親画面 | フィルタリング機能を提供する画面 |
| - | フィルター画面 | 主画面 | フィルター条件選択のモーダル画面 |

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| categorySlug | String | Yes | カテゴリ識別スラグ | 空文字不可 |
| filters | List<Map<String, dynamic>> | Yes | 現在のフィルター条件 | - |
| startPriceValue | double | No | 価格範囲下限 | minPrice以上 |
| endPriceValue | double | No | 価格範囲上限 | maxPrice以下 |
| superAttributes | List | No | 選択された属性フィルター | - |

### 入力データソース

- ユーザー入力（価格スライダー、チェックボックス）
- GraphQL API（フィルター属性情報）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| filters | List<Map<String, dynamic>> | 更新されたフィルター条件 |
| superAttributes | List | 選択された属性フィルター |

### 出力先

- 親画面（カテゴリ商品一覧画面）への戻り値
- CategoryBloc（FetchSubCategoryEvent発行）

## 処理フロー

### 処理シーケンス

```
1. フィルター画面表示
   └─ カテゴリ商品一覧画面からNavigator.push
2. フィルター属性データの解析
   └─ fetchFilterData()で既存フィルター条件を解析
3. ユーザーのフィルター選択
   ├─ 価格範囲：RangeSlider操作
   └─ 属性選択：CheckboxListTile操作
4. フィルター適用
   └─ 戻るボタンタップでFetchSubCategoryEvent発行
5. フィルタークリア
   └─ CLEARボタンで全条件解除
```

### フローチャート

```mermaid
flowchart TD
    A[カテゴリ商品一覧画面] --> B[FILTERボタンタップ]
    B --> C[フィルター画面表示]
    C --> D[既存フィルター条件解析]
    D --> E[フィルター属性表示]
    E --> F{ユーザー操作}
    F -->|価格範囲変更| G[RangeSlider値更新]
    F -->|属性選択/解除| H[CheckboxListTile状態更新]
    F -->|CLEARタップ| I[全条件クリア]
    F -->|戻る| J[フィルター適用]
    G --> K[superAttributes更新]
    H --> K
    K --> E
    I --> L[filters条件削除]
    L --> M[FetchSubCategoryEvent発行]
    M --> N[画面終了]
    J --> O[FetchSubCategoryEvent発行]
    O --> P[フィルター結果を親画面に返却]
    P --> Q[画面終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 価格範囲制約 | 価格はminPrice〜maxPriceの範囲内 | 価格フィルター使用時 |
| BR-02 | 複数選択許可 | 同一属性内で複数オプションを選択可能 | 属性フィルター使用時 |
| BR-03 | AND条件 | 異なる属性間はAND条件で適用 | 複数属性フィルター使用時 |
| BR-04 | カテゴリID保持 | CLEARしてもcategory_idフィルターは保持 | フィルタークリア時 |

### 計算ロジック

- 価格フィルター形式：`"startPrice, endPrice"`
- 属性フィルター形式：`"optionId1,optionId2,..."`

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| フィルター属性取得 | attributes | SELECT | カテゴリに関連する属性とオプションを取得 |
| 商品検索 | products | SELECT | フィルター条件で商品を検索 |

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

#### attributes（GraphQL経由）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | code, adminName, options | category_slug = 指定値 | GraphQL: getFilterAttributes |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | API失敗 | フィルター属性取得エラー | エラーログ出力、空の属性リストを使用 |

### リトライ仕様

特になし（親画面のPull-to-Refreshで対応）

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

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

## パフォーマンス要件

- フィルター属性取得: 1秒以内
- フィルター適用後の商品取得: 2秒以内

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

- フィルター値のサニタイズはバックエンドで実施

## 備考

- フィルター画面はモーダル表示（MaterialPageRoute）
- 選択状態はsuperAttributes配列で管理

---

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

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

### 推奨読解順序

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

フィルタリング機能で扱うデータモデルを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | filter_product_model.dart | `lib/data_model/categories_data_model/filter_product_model.dart` | GetFilterAttribute, SortOrderの構造 |

**読解のコツ**: filterAttributesはdynamic型のリストとして定義されており、各要素にcode, adminName, optionsフィールドが含まれる。

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

フィルター画面の起点を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | sub_categories_view.dart | `lib/screens/categories_screen/widget/sub_categories_view.dart` | FILTERボタンのタップハンドラ（302-320行目） |
| 2-2 | filter_screen.dart | `lib/screens/filter_screen/view/filter_screen.dart` | SubCategoriesFilterScreenクラス |

**主要処理フロー（filter_screen.dart）**:
1. **36-53行目**: initState()で既存フィルター条件を解析、価格範囲を設定
2. **56-105行目**: fetchFilterData()でフィルター属性データを処理
3. **211-377行目**: _listElement()で各フィルター項目（価格スライダー、チェックボックス）を生成
4. **230-273行目**: 価格フィルターのRangeSlider実装
5. **275-368行目**: 属性フィルターのCheckboxListTile実装
6. **111-126行目**: 戻るボタンでフィルター適用、FetchSubCategoryEvent発行
7. **133-148行目**: CLEARボタンでフィルター条件クリア

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | categories_event.dart | `lib/screens/categories_screen/bloc/categories_event.dart` | FetchSubCategoryEvent, FilterFetchEventの定義 |
| 3-2 | categories_bloc.dart | `lib/screens/categories_screen/bloc/categories_bloc.dart` | FilterFetchEventの処理（116-123行目） |
| 3-3 | categories_repository.dart | `lib/screens/categories_screen/bloc/categories_repository.dart` | getFilterProducts()の実装（42-51行目） |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | filter_repository.dart | `lib/screens/filter_screen/bloc/filter_repository.dart` | FilterRepositoryImp.getFilterProducts()の実装 |

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

```
SubCategoriesView (widget/sub_categories_view.dart)
    │
    ├─ GestureDetector (FILTERボタン, 302行目)
    │      │
    │      └─ Navigator.push → SubCategoriesFilterScreen
    │
    └─ CategoryBloc
           │
           └─ FetchSubCategoryEvent (フィルター適用時)

SubCategoriesFilterScreen (filter_screen.dart)
    │
    ├─ RangeSlider (価格フィルター)
    │
    ├─ CheckboxListTile (属性フィルター)
    │
    └─ CategoryBloc
           │
           ├─ OnClickSubCategoriesLoaderEvent
           │
           └─ FetchSubCategoryEvent
                  │
                  └─ CategoriesRepo.callCategoriesData()
                         │
                         └─ ApiClient.getAllProducts()
                                │
                                └─ GraphQL API
```

### データフロー図

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

categorySlug ───────────▶ FilterFetchEvent
                              │
                              ▼
                         CategoriesRepo.getFilterProducts()
                              │
                              ▼
                         ApiClient.getFilterAttributes()
                              │
                              ▼
                         GraphQL API
                              │
                              ▼
                         GetFilterAttribute ─────────▶ フィルター画面表示

ユーザー操作 ───────────▶ RangeSlider / CheckboxListTile
(価格範囲/属性選択)            │
                              ▼
                         filters配列更新
                         superAttributes更新
                              │
                              ▼
                         FetchSubCategoryEvent
                              │
                              ▼
                         フィルター適用済み商品取得
                              │
                              ▼
                         Navigator.pop(superAttributes)
                              │
                              ▼
                         親画面で商品一覧更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| filter_screen.dart | `lib/screens/filter_screen/view/filter_screen.dart` | ソース | フィルター画面のUI |
| filter_bloc.dart | `lib/screens/filter_screen/bloc/filter_bloc.dart` | ソース | フィルター状態管理BLoC |
| filter_event.dart | `lib/screens/filter_screen/bloc/filter_event.dart` | ソース | フィルターイベント定義 |
| filter_state.dart | `lib/screens/filter_screen/bloc/filter_state.dart` | ソース | フィルター状態定義 |
| filter_repository.dart | `lib/screens/filter_screen/bloc/filter_repository.dart` | ソース | フィルターAPIリポジトリ |
| filter_product_model.dart | `lib/data_model/categories_data_model/filter_product_model.dart` | ソース | フィルターデータモデル |
| sub_categories_view.dart | `lib/screens/categories_screen/widget/sub_categories_view.dart` | ソース | フィルター呼び出し元 |
| categories_bloc.dart | `lib/screens/categories_screen/bloc/categories_bloc.dart` | ソース | カテゴリBLoC（FilterFetchEvent処理） |
| categories_repository.dart | `lib/screens/categories_screen/bloc/categories_repository.dart` | ソース | カテゴリAPIリポジトリ |
| categories_event.dart | `lib/screens/categories_screen/bloc/categories_event.dart` | ソース | カテゴリイベント定義 |
