# 通知設計書 24-必須オプション未入力警告

## 概要

本ドキュメントは、商品のカスタマイズオプション（Customizable Options）が必須設定されている場合に、未入力のままカート追加を試みた際に表示される警告通知の設計について記載する。

### 本通知の処理概要

本通知は、ユーザーが商品詳細画面でカスタマイズオプション付き商品をカートに追加しようとした際に、必須のカスタマイズオプションが入力/選択されていない場合に警告を表示するアプリ内通知機能である。

**業務上の目的・背景**：ECサイトでは、商品に対してカスタマイズオプション（刻印テキスト、日付指定、ファイルアップロードなど）を設定できる。これらのオプションが「必須」として設定されている場合、ユーザーは必ず入力/選択してからカートに追加する必要がある。未入力状態での注文を防止し、正しい商品構成での購入を促すために警告通知が必要となる。

**通知の送信タイミング**：ユーザーが「カートに追加」ボタンをタップした際に、_addToCartメソッド内で各カスタマイズオプションの必須チェックを実行し、未入力の必須オプションが見つかった時点で即座に警告通知を表示する。

**通知の受信者**：操作を実行したユーザー本人のみがアプリ内通知を受信する。

**通知内容の概要**：黄色（amber）の背景で警告アイコン付きの警告通知が表示される。メッセージには未入力のオプション名と「is required」が含まれる。

**期待されるアクション**：ユーザーは警告通知で指摘されたオプションを入力/選択してから、再度カート追加を試みることが期待される。

## 通知種別

アプリ内通知（オーバーレイ警告通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（バリデーション時即時表示） |
| 優先度 | 高 |
| リトライ | なし |

### 送信先決定ロジック

操作を実行したユーザーのデバイス上のみに表示される。

## 通知テンプレート

### アプリ内通知の場合

| 項目 | 内容 |
|-----|------|
| タイトル | "Warning"（ローカライズ対応） |
| 背景色 | Colors.amber |
| アイコン | Icons.warning_amber |

### 本文テンプレート

```
{オプション名} {StringConstants.isRequired}
例: "刻印テキスト is required" / "Engraving Text は必須です"
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| option.translations?.label | オプションのローカライズ名 | CustomizableOption.translations.label | No |
| option.label | オプション名（フォールバック） | CustomizableOption.label | No |
| isRequired | 必須メッセージ | StringConstants.isRequired | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作 | カートに追加ボタンタップ | 必須オプションが未入力/未選択 | ユーザーがカート追加を試みる |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 必須オプションすべて入力済み | すべての必須オプションが入力/選択されている場合は警告なし |
| オプションなし | customizableOptionsが空の場合はチェックをスキップ |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ユーザーがカート追加ボタンをタップ] --> B{カスタマイズオプションあり?}
    B -->|なし| C[通常のカート追加処理へ]
    B -->|あり| D[オプションループ開始]
    D --> E{isRequired == true?}
    E -->|No| F[次のオプションへ]
    E -->|Yes| G{オプション入力済み?}
    G -->|Yes| F
    G -->|No| H[ShowMessage.warningNotification表示]
    H --> I[OnClickProductLoaderEvent発行 isReqToShowLoader: false]
    I --> J[処理終了 return]
    F --> K{全オプション処理完了?}
    K -->|No| D
    K -->|Yes| C
```

## データベース参照・更新仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| なし | クライアント側バリデーション | サーバー通信なし |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| なし | なし | バリデーションエラーのため更新なし |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| バリデーションエラー | 必須オプション未入力 | 警告通知を表示、処理中断 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

24時間対応

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

- クライアント側バリデーションのため特別なセキュリティ考慮は不要
- サーバー側でも同様のバリデーションが実施される

## 備考

- 対応するオプションタイプ: text, textarea, date, datetime, time, file, checkbox, multiselect, radio, select
- 各タイプごとに入力判定ロジックが異なる
- 最初に見つかった未入力の必須オプションで警告を表示し、処理を中断する

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | product_details_model.dart | `lib/screens/product_screen/data_model/product_details_model.dart` | CustomizableOptionクラスの構造、isRequired, type, translationsフィールド |
| 1-2 | string_constants.dart | `lib/utils/string_constants.dart` | isRequired定数（行423）の定義 |

**読解のコツ**: customizableOptionsSelectionはMap<String, dynamic>で、オプションIDをキーとして選択/入力値を保持。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | product_screen.dart | `lib/screens/product_screen/view/product_screen.dart` | _addToCartメソッド内のカスタマイズオプションチェック（行344-388） |

**主要処理フロー**:
1. **行345-346**: customOptions取得とhasCustomOptions判定
2. **行347-388**: オプションループと必須チェック
3. **行352-376**: オプションタイプ別の入力判定（switch文）
4. **行377-385**: 未入力時の警告通知表示

#### Step 3: 通知表示処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | show_message.dart | `lib/widgets/show_message.dart` | warningNotificationメソッド（行58-77） |

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

```
ProductScreen (product_screen.dart)
    │
    └─ _addToCart メソッド (行340-581)
           │
           ├─ カスタマイズオプション取得 (行345)
           │      └─ productData?.customizableOptions ?? []
           │
           ├─ オプションループ (行348-387)
           │      │
           │      ├─ isRequired判定 (行349)
           │      │
           │      ├─ オプションタイプ別入力判定 (行352-376)
           │      │      ├─ text/textarea/date/datetime/time
           │      │      ├─ file
           │      │      ├─ checkbox/multiselect
           │      │      └─ radio/select
           │      │
           │      └─ 未入力時の警告 (行377-385)
           │             ├─ ShowMessage.warningNotification
           │             ├─ OnClickProductLoaderEvent(false)
           │             └─ return
           │
           └─ 次の処理へ
```

### データフロー図

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

カート追加 ───▶ customizableOptions取得 ───▶ オプションループ
ボタンタップ            │                         │
                       │                         ▼
                       │               isRequired && !isFilled判定
                       │                         │
                       │        ┌────────────────┴────────────────┐
                       │        ▼                                 ▼
                       │   未入力発見                         全て入力済み
                       │        │                                 │
                       ▼        ▼                                 ▼
              warningNotification表示                 カート追加処理継続
              "{オプション名} is required"
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| product_screen.dart | `lib/screens/product_screen/view/product_screen.dart` | ソース | バリデーションと通知トリガー |
| show_message.dart | `lib/widgets/show_message.dart` | ソース | 警告通知表示 |
| string_constants.dart | `lib/utils/string_constants.dart` | ソース | メッセージ定数 |
| product_details_model.dart | `lib/screens/product_screen/data_model/product_details_model.dart` | ソース | カスタマイズオプションモデル |
| customizable_option_view.dart | `lib/screens/product_screen/view/widget/customizable_option_view.dart` | ソース | オプション入力UI |
