# 画面設計書 63-ルール編集画面

## 概要

本ドキュメントは、Medusa Admin Dashboard のルール編集画面について、画面仕様・機能・データ処理を定義した画面設計書です。

### 本画面の処理概要

この画面では、プロモーションの適用条件（ルール）を編集することができます。ルールタイプには「条件ルール」「購入ルール」「ターゲットルール」の3種類があり、それぞれの条件を追加・編集・削除できます。

**業務上の目的・背景**：プロモーションの効果を最大化するためには、適切な条件設定が不可欠です。特定の顧客グループ、商品カテゴリ、注文金額などの条件を設定することで、ターゲットを絞ったマーケティング施策を実施できます。買い物条件（Buy X Get Y形式のプロモーション）や適用対象の条件を柔軟に設定できます。

**画面へのアクセス方法**：プロモーション詳細画面から「条件を編集」「購入ルールを編集」「ターゲットルールを編集」などのアクションをクリックすることで、右側からスライドインするドロワー形式でこの画面が表示されます。URL: `/promotions/:id/:ruleType`（ruleTypeはrules/buy-rules/target-rules）

**主要な操作・処理内容**：
1. 既存のルールの確認・編集
2. 新しい条件（ルール）の追加
3. ルールの属性（フィールド）を選択
4. ルールの演算子（等しい/含む/含まないなど）を選択
5. ルールの値を入力または選択
6. 不要なルールの削除
7. 全てのルールをクリア

**画面遷移**：
- 遷移元：プロモーション詳細画面（`/promotions/:id`）
- 遷移先：保存成功時はプロモーション詳細画面に戻る、キャンセル時も同様

**権限による表示制御**：認証済みの管理者ユーザーのみがアクセス可能です。プロモーション管理権限を持つユーザーが操作できます。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 37 | プロモーションルール管理 | 主機能 | プロモーションルールの編集 |

## 画面種別

編集（モーダル/ドロワー形式）

## URL/ルーティング

`/promotions/:id/:ruleType`

- `:ruleType` は `rules`、`buy-rules`、`target-rules` のいずれか

## 入出力項目

| 項目名 | 項目ID | 型 | 必須 | 入力/出力 | 説明 |
|--------|--------|-----|------|-----------|------|
| ルール配列 | rules | array | - | 入力 | ルールオブジェクトの配列 |
| ルール属性 | rules[].attribute | string | ○ | 入力 | ルールの対象フィールド |
| ルール演算子 | rules[].operator | string | ○ | 入力 | 比較演算子（eq/in/not_in等） |
| ルール値 | rules[].values | string/array | ○ | 入力 | 比較値 |
| 必須フラグ | rules[].required | boolean | - | 出力 | 削除不可のルールかどうか |
| 偽装フラグ | rules[].disguised | boolean | - | 出力 | 内部的なルールかどうか |

## 表示項目

| 項目名 | 説明 |
|--------|------|
| 画面タイトル | ルールタイプに応じたタイトル |
| ルール一覧 | 現在設定されているルールの一覧 |
| 属性選択 | ドロップダウンでルール属性を選択 |
| 演算子選択 | ドロップダウンで演算子を選択 |
| 値入力/選択 | テキスト入力またはコンボボックスで値を設定 |
| 削除ボタン | 各ルールの削除ボタン（必須ルール以外） |
| 条件追加ボタン | 新しいルールを追加 |
| 全てクリアボタン | 全てのルールを削除（必須ルール以外） |
| キャンセルボタン | ドロワーを閉じる |
| 保存ボタン | 変更を保存 |

## イベント仕様

### 1-保存ボタン押下

**処理フロー**：
1. フォームバリデーションを実行
2. 新規追加ルール、更新ルール、削除ルールを分類
3. `usePromotionAddRules`、`usePromotionUpdateRules`、`usePromotionRemoveRules` フックを使用してAPIを呼び出し
4. 成功時：ドロワーを閉じてプロモーション詳細画面に戻る
5. 失敗時：エラーメッセージを表示

**API呼び出し**：
- 追加: `POST /admin/promotions/:id/:ruleType/batch` (add操作)
- 更新: `POST /admin/promotions/:id/:ruleType/batch` (update操作)
- 削除: `POST /admin/promotions/:id/:ruleType/batch` (remove操作)

### 2-キャンセルボタン押下

**処理フロー**：
1. フォームの変更を破棄
2. ドロワーを閉じてプロモーション詳細画面に戻る

### 3-条件追加ボタン押下

**処理フロー**：
1. 新しい空のルールオブジェクトをフォームに追加
2. フォームのrulesフィールドに追加される

### 4-全てクリアボタン押下

**処理フロー**：
1. 必須フラグが付いていないルールを特定
2. 削除対象リストに追加
3. フォームから該当ルールを削除

### 5-ルール削除ボタン押下

**処理フロー**：
1. 該当ルールを削除対象リストに追加
2. フォームから該当ルールを削除

### 6-属性変更

**処理フロー**：
1. 選択した属性に応じて演算子オプションを更新
2. 演算子が1つしかない場合は自動選択
3. 値フィールドをリセット

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 保存ボタン押下 | promotion_rule | INSERT | 新規ルールの追加 |
| 保存ボタン押下 | promotion_rule | UPDATE | 既存ルールの更新 |
| 保存ボタン押下 | promotion_rule | DELETE | ルールの削除 |

### テーブル別更新項目詳細

#### promotion_rule

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | attribute | フォームの attribute | |
| INSERT | operator | フォームの operator | |
| INSERT | values | フォームの values | JSON配列または文字列 |
| UPDATE | attribute | フォームの attribute | |
| UPDATE | operator | フォームの operator | |
| UPDATE | values | フォームの values | |
| DELETE | - | ルールID | 削除対象リストのルール |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|----------|
| MSG-001 | エラー | 属性を選択してください | 属性が未選択の場合 |
| MSG-002 | エラー | 値を入力してください | 値が未入力の場合 |

## 例外処理

| 例外 | 処理内容 |
|------|---------|
| プロモーションが見つからない | エラーをスローしてエラー画面を表示 |
| 無効なルールタイプ | "invalid page" をスローしてエラー表示 |
| API通信エラー | エラーメッセージを表示 |
| バリデーションエラー | 各フィールドにエラーメッセージを表示 |

## 備考

- ルールタイプによって利用可能な属性オプションが異なる
- Buy-One-Get-One（BOGO）タイプのプロモーションでは、buy-rulesとtarget-rulesが必須
- 標準タイプのプロモーションでは、rulesのみが使用可能
- 必須ルール（required: true）は削除不可
- ルール間はAND条件で結合される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | form-schema.ts | `packages/admin/dashboard/src/routes/promotions/common/edit-rules/components/edit-rules-form/form-schema.ts` | EditRulesスキーマでフォームの構造を確認 |
| 1-2 | edit-rules.tsx | `packages/admin/dashboard/src/routes/promotions/common/edit-rules/edit-rules.tsx` | RuleType enumでルールタイプを確認（9-14行目） |

**読解のコツ**: ルールタイプ（rules/buy-rules/target-rules）によって取得するルールの種類が異なります。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | edit-rules.tsx | `packages/admin/dashboard/src/routes/promotions/common/edit-rules/edit-rules.tsx` | usePromotionフックでデータ取得（32行目） |

**主要処理フロー**:
1. **17-22行目**: useParamsからruleTypeとidを取得
2. **24-26行目**: 無効なruleTypeの場合はエラーをスロー
3. **34-42行目**: ルールタイプに応じてプロモーションからルールを抽出
4. **55-59行目**: EditRulesWrapperコンポーネントにデータを渡す

#### Step 3: フォームコンポーネントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | edit-rules-wrapper.tsx | `packages/admin/dashboard/src/routes/promotions/common/edit-rules/components/edit-rules-wrapper/edit-rules-wrapper.tsx` | ルール更新のワークフロー |
| 3-2 | edit-rules-form.tsx | `packages/admin/dashboard/src/routes/promotions/common/edit-rules/components/edit-rules-form/edit-rules-form.tsx` | フォームUIとバリデーション |
| 3-3 | rules-form-field.tsx | `packages/admin/dashboard/src/routes/promotions/common/edit-rules/components/rules-form-field/rules-form-field.tsx` | ルール入力フィールドの実装 |

**主要処理フロー**:
- **rules-form-field.tsx 56-60行目**: useFieldArrayでルール配列を管理
- **rules-form-field.tsx 88-95行目**: usePromotionRulesで既存ルールを取得
- **rules-form-field.tsx 389-403行目**: 条件追加ボタンの処理
- **rules-form-field.tsx 405-421行目**: 全てクリアボタンの処理

#### Step 4: API層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | promotions.tsx | `packages/admin/dashboard/src/hooks/api/promotions.tsx` | usePromotionAddRules/UpdateRules/RemoveRulesの実装 |
| 4-2 | route.ts | `packages/medusa/src/api/admin/promotions/[id]/rules/batch/route.ts` | バッチAPIエンドポイント |

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

```
EditRules (edit-rules.tsx)
    │
    ├─ usePromotion() - プロモーションデータ取得
    │      └─ sdk.admin.promotion.retrieve()
    │
    └─ EditRulesWrapper
           │
           ├─ EditRulesForm
           │      │
           │      ├─ useForm() - フォーム状態管理
           │      │
           │      └─ RulesFormField
           │             │
           │             ├─ useFieldArray() - ルール配列管理
           │             │
           │             ├─ usePromotionRuleAttributes() - 属性オプション取得
           │             │
           │             ├─ usePromotionRules() - 既存ルール取得
           │             │
           │             └─ RuleValueFormField - 値入力コンポーネント
           │
           └─ handleSubmit
                  │
                  ├─ usePromotionAddRules() - ルール追加
                  │      └─ POST /admin/promotions/:id/:ruleType/batch
                  │
                  ├─ usePromotionUpdateRules() - ルール更新
                  │      └─ POST /admin/promotions/:id/:ruleType/batch
                  │
                  └─ usePromotionRemoveRules() - ルール削除
                         └─ POST /admin/promotions/:id/:ruleType/batch
```

### データフロー図

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

URLパラメータ ────▶ usePromotion ────▶ プロモーションデータ
  (id, ruleType)                               ↓
                                         ルール抽出
                                              ↓
                  usePromotionRules ──▶ 既存ルール
                                              ↓
                                         フォーム初期値
                                              ↓
属性選択 ────────▶ usePromotionRuleAttributes ──▶ 属性オプション
                                              ↓
演算子選択 ──────▶ 演算子オプション取得 ──▶ 演算子選択肢
                                              ↓
値入力 ──────────▶ RuleValueFormField ──▶ 値の設定
                                              ↓
保存ボタン ──────▶ handleSubmit ───▶ ルール分類
                                              ↓
                  ├─ addRules() ───▶ 新規ルール追加
                  ├─ updateRules() ▶ 既存ルール更新
                  └─ removeRules() ▶ ルール削除
                                              ↓
                                        handleSuccess()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| edit-rules.tsx | `packages/admin/dashboard/src/routes/promotions/common/edit-rules/edit-rules.tsx` | ソース | エントリーポイント |
| edit-rules-wrapper.tsx | `packages/admin/dashboard/src/routes/promotions/common/edit-rules/components/edit-rules-wrapper/edit-rules-wrapper.tsx` | ソース | ルール更新ロジック |
| edit-rules-form.tsx | `packages/admin/dashboard/src/routes/promotions/common/edit-rules/components/edit-rules-form/edit-rules-form.tsx` | ソース | フォームコンポーネント |
| rules-form-field.tsx | `packages/admin/dashboard/src/routes/promotions/common/edit-rules/components/rules-form-field/rules-form-field.tsx` | ソース | ルール入力フィールド |
| rule-value-form-field.tsx | `packages/admin/dashboard/src/routes/promotions/common/edit-rules/components/rule-value-form-field/rule-value-form-field.tsx` | ソース | 値入力フィールド |
| form-schema.ts | `packages/admin/dashboard/src/routes/promotions/common/edit-rules/components/edit-rules-form/form-schema.ts` | ソース | フォームスキーマ |
| promotions.tsx | `packages/admin/dashboard/src/hooks/api/promotions.tsx` | ソース | APIフック |
