# 機能設計書 60-最近閲覧した商品表示

## 概要

本ドキュメントは、閲覧履歴のある商品一覧を表示する機能の設計を記述する。

### 本機能の処理概要

本機能は、ユーザーが過去に閲覧した商品の履歴をローカルストレージ（Hive）から取得し、ホーム画面に表示する機能を提供する。最近閲覧した商品を表示することで、ユーザーの購買意欲を促進し、関心のある商品への再アクセスを容易にする。

**業務上の目的・背景**：ECサイトにおいて、ユーザーが以前閲覧した商品を再度見つけやすくすることは、購買率向上に直結する重要な機能である。カートに入れ忘れた商品や、比較検討中の商品に再度アクセスできることで、購入完了率の向上が期待できる。

**機能の利用シーン**：ホーム画面を表示した時、商品を閲覧した後にホーム画面に戻った時などに自動的に表示される。

**主要な処理内容**：
1. Hiveローカルストレージから閲覧履歴を取得
2. 最新5件の商品データを取得
3. NewProductViewコンポーネントで商品一覧を表示
4. StreamControllerによる履歴更新の監視

**関連システム・外部連携**：Hiveローカルデータベースに閲覧履歴を保存・取得。StreamControllerで閲覧履歴の更新をリアルタイム監視。

**権限による制御**：ログイン状態に関わらず閲覧履歴を表示（ローカル保存のため）。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 2 | ホーム画面 | 主画面 | 最近閲覧した商品セクションの表示 |
| 7 | 商品詳細画面 | 関連画面 | 商品閲覧時に履歴へ追加 |

## 機能種別

データ表示（CRUD - Read）/ ローカルストレージ

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| isLogin | bool | No | ログイン状態 | - |

### 入力データソース

- Hiveローカルストレージ: recentProducts Box

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| _recentProductList | List<NewProducts> | 最近閲覧した商品リスト（最大5件） |
| NewProducts.id | String | 商品ID |
| NewProducts.name | String | 商品名 |
| NewProducts.sku | String | SKU |
| NewProducts.price | String | 価格 |
| NewProducts.images | List | 商品画像リスト |

### 出力先

画面表示（ホーム画面の最近閲覧商品セクション）

## 処理フロー

### 処理シーケンス

```
1. 画面初期化
   └─ initStateでfetchRecentProductsを呼び出し
2. StreamController設定
   └─ RecentViewController.controller.streamのリッスン開始
3. Hiveデータ取得
   └─ recentProducts Boxを開き、最新5件を取得
4. 状態更新
   └─ setStateで_recentProductListを更新
5. UI表示
   └─ NewProductViewコンポーネントで商品を表示
6. 更新監視
   └─ Streamからイベント受信時にfetchRecentProductsを再実行
```

### フローチャート

```mermaid
flowchart TD
    A[画面初期化] --> B[StreamController設定]
    B --> C[fetchRecentProducts呼び出し]
    C --> D[Hive Box open]
    D --> E[閲覧履歴取得]
    E --> F{履歴あり?}
    F -->|Yes| G[最新5件抽出]
    G --> H[setState更新]
    H --> I[NewProductView表示]
    F -->|No| J[空のSizedBox表示]
    I --> K[Stream監視]
    J --> K
    K --> L{更新イベント?}
    L -->|Yes| C
    L -->|No| K
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-60-01 | 最大表示件数 | 最近閲覧した商品は最大5件まで表示 | 常時 |
| BR-60-02 | 新しい順 | 閲覧履歴は新しい順（後ろから）に取得 | 常時 |
| BR-60-03 | 空データ非表示 | 閲覧履歴がない場合はセクション自体を非表示 | 履歴0件時 |
| BR-60-04 | リアルタイム更新 | 商品閲覧後、ホーム画面に戻ると履歴が更新される | 閲覧後 |

### 計算ロジック

特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 履歴取得 | recentProducts (Hive) | SELECT | 閲覧履歴をローカルから取得 |

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

#### recentProducts (Hive Box)

| 操作 | 項目 | 取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | NewProducts | 後ろから最大5件 | 新しい順に取得 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Hive初期化エラー | Boxオープン失敗 | 空のリストを返す |
| - | データ不整合 | 保存データの形式不正 | エラーをキャッチして処理続行 |

### リトライ仕様

画面を再度開くことで再取得が可能。

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

ローカルストレージの読み取りのみのため、トランザクション管理は不要。

## パフォーマンス要件

- Hiveからのデータ取得: 100ms以内
- UI更新: 即時（setStateによる再描画）

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

- 閲覧履歴はローカルにのみ保存（サーバーに送信しない）
- 個人を特定する情報は含まない
- アプリアンインストール時にデータ削除

## 備考

- HiveはNoSQLのローカルデータベースで、軽量・高速
- NewProductsはHiveTypeAdapterでシリアライズ対応
- RecentViewControllerはSingletonパターンで実装
- StreamController.broadcastで複数リスナーに対応

---

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

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

### 推奨読解順序

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

最近閲覧商品で使用するデータ構造とコントローラーを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | recent_view_controller.dart | `lib/screens/recent_product/utils/recent_view_controller.dart` | StreamControllerの構造、Singletonパターン |

**読解のコツ**: RecentViewControllerはprivateコンストラクタでSingleton実装。StreamController.broadcast()で複数のリスナーに対応。商品詳細画面から閲覧イベントを発行する際に使用。

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

最近閲覧商品表示のメインウィジェットを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | recent_product_view.dart | `lib/screens/recent_product/recent_product_view.dart` | 画面構築とHiveアクセス |

**主要処理フロー**:
1. **34-40行目**: initStateでサイズ計算、fetchRecentProducts呼び出し、Streamリッスン設定
2. **44-59行目**: fetchRecentProductsでHive Boxを開き、最新5件を取得
3. **47-52行目**: for文で後ろから5件を取得（新しい順）
4. **63-73行目**: buildメソッドでNewProductViewを使用して表示

#### Step 3: Hiveデータアクセスを理解する

Hiveの使用方法を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | recent_product_view.dart | `lib/screens/recent_product/recent_product_view.dart` | Hive.openBox, box.getAt |

**主要処理フロー**:
- **45行目**: Hive.openBox("recentProducts")でBoxを開く
- **48行目**: box.getAt(i)でインデックス指定でデータ取得
- **49行目**: NewProductsにキャストして使用

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

```
RecentView (recent_product_view.dart)
    │
    ├─ initState()
    │      │
    │      ├─ fetchRecentProducts()
    │      │      │
    │      │      └─ Hive.openBox("recentProducts")
    │      │             │
    │      │             └─ box.getAt(i) → NewProducts
    │      │
    │      └─ RecentViewController.controller.stream.listen()
    │             │
    │             └─ fetchRecentProducts() 再実行
    │
    └─ build()
           │
           └─ NewProductView(
                  title: "Recent Products",
                  model: _recentProductList
              )
```

### データフロー図

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

initState ───▶ fetchRecentProducts()
                     │
                     ▼
              Hive.openBox("recentProducts")
                     │
                     ▼
              box.getAt(i) × 5件
                     │
                     ▼
              _recentProductList更新
                     │
                     ▼
              setState()
                     │
                     ▼
              NewProductView表示

[商品閲覧時]
商品詳細画面 ───▶ RecentViewController.controller.add()
                     │
                     ▼
              Stream event
                     │
                     ▼
              fetchRecentProducts() 再実行
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| recent_product_view.dart | `lib/screens/recent_product/recent_product_view.dart` | ソース | メイン画面 |
| recent_view_controller.dart | `lib/screens/recent_product/utils/recent_view_controller.dart` | ソース | StreamController管理 |
| index.dart | `lib/screens/recent_product/utils/index.dart` | ソース | インポート集約 |

### 補足情報

#### Hiveへの書き込み（参考）

最近閲覧した商品表示機能を理解するため、書き込み側の処理も把握しておくと良い。商品詳細画面（product_screen）で商品を閲覧した際に、Hiveに書き込みが行われる。

```dart
// 商品詳細画面での書き込み例（参考）
Box box = await Hive.openBox("recentProducts");
box.add(product); // NewProductsオブジェクトを追加
RecentViewController.controller.add("update"); // 更新イベント発行
```

#### NewProductsデータモデル（参考）

NewProductsはHiveTypeAdapterを使用してシリアライズ対応している。主要なフィールドは以下の通り。

- id: 商品ID
- name: 商品名
- sku: SKU
- price / priceHtml: 価格情報
- images: 商品画像リスト
- avgRatings: 平均評価
