# 画面設計書 18-商品バリアント作成画面

## 概要

本ドキュメントは、Medusa Admin Dashboard における商品バリアント作成画面の設計仕様を定義するものである。

### 本画面の処理概要

商品バリアント作成画面は、商品に新しいバリアント（オプションの組み合わせによる商品のバリエーション）を追加するための画面である。詳細情報、価格、在庫（インベントリキット）の設定が可能。

**業務上の目的・背景**：商品バリアントは、同一商品の異なるバリエーション（サイズ・色の組み合わせ等）を表現するために必要である。本画面は、バリアントの基本情報（SKU、タイトル等）、各通貨・リージョンの価格、在庫管理設定を一貫して設定するために必要である。

**画面へのアクセス方法**：商品詳細画面のバリアントセクションから「Add Variant」ボタンをクリックすることでモーダル形式で表示される。URLパスは `/products/:id/variants/create` となる。

**主要な操作・処理内容**：
1. 詳細タブ：タイトル、SKU、オプション値、在庫管理設定の入力
2. 価格タブ：通貨別・リージョン別価格の設定
3. インベントリタブ（オプション）：インベントリキットの設定
4. バリアントの作成・保存

**画面遷移**：
- 遷移元：商品詳細画面（No.7）
- 遷移先：商品詳細画面（保存/キャンセル後）

**権限による表示制御**：本画面へのアクセスには商品管理権限が必要。権限がない場合は画面にアクセスできない。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 2 | 商品バリアント管理 | 主機能 | 商品バリアントの新規作成 |
| 52 | 価格設定管理 | 補助機能 | バリアント価格の設定 |
| 48 | 在庫アイテム管理 | 補助機能 | バリアント在庫の設定 |

## 画面種別

登録（モーダル形式・フルスクリーン・マルチステップ）

## URL/ルーティング

```
/products/:id/variants/create
```

パラメータ：
- `id`：商品ID（必須）

## 入出力項目

### 入力項目

#### 詳細タブ

| 項目名 | 項目ID | 型 | 必須 | バリデーション | 備考 |
|--------|--------|-----|------|---------------|------|
| タイトル | title | string | - | - | バリアント名 |
| SKU | sku | string | - | - | 在庫管理番号 |
| オプション値 | options | Record<string, string> | - | - | オプションIDと値のマップ |
| 在庫管理 | manage_inventory | boolean | - | - | デフォルトfalse |
| バックオーダー許可 | allow_backorder | boolean | - | - | デフォルトfalse |
| インベントリキット | inventory_kit | boolean | - | - | デフォルトfalse |

#### 価格タブ

| 項目名 | 項目ID | 型 | 必須 | バリデーション | 備考 |
|--------|--------|-----|------|---------------|------|
| 価格 | prices | Record<string, string \| number> | - | 数値または空文字 | 通貨/リージョンIDをキー |

#### インベントリタブ

| 項目名 | 項目ID | 型 | 必須 | バリデーション | 備考 |
|--------|--------|-----|------|---------------|------|
| インベントリアイテムID | inventory[].inventory_item_id | string | - | - | 在庫アイテムの参照 |
| 必要数量 | inventory[].required_quantity | number | - | - | 1バリアントあたりの必要数 |

### 出力項目

| 項目名 | 項目ID | 型 | 備考 |
|--------|--------|-----|------|
| 作成されたバリアント | variant | ProductVariant | APIレスポンス |

## 表示項目

### ProgressTabs（タブ形式）

| タブ名 | 状態 | 備考 |
|--------|------|------|
| Details | in-progress/completed | 詳細情報入力 |
| Prices | not-started/in-progress/completed | 価格設定 |
| Inventory | not-started/in-progress/completed | インベントリキット時のみ表示 |

### 詳細タブ

| 項目名 | 表示形式 | 備考 |
|--------|---------|------|
| タイトル | Input | |
| SKU | Input | |
| オプション選択 | Select/Combobox | 各オプションごとに表示 |
| 在庫管理 | Checkbox | |
| バックオーダー許可 | Checkbox | |
| インベントリキット | Checkbox | 在庫管理ON時のみ表示 |

## イベント仕様

### 1-タブ遷移

**トリガー**：「Continue」ボタン押下またはタブクリック

**処理フロー**：
1. 現在タブのバリデーションを実行（partialFormValidation）
2. バリデーション成功時、現在タブをcompletedに設定
3. 次タブをin-progressに設定して遷移
4. バリデーション失敗時、現在タブに留まる

### 2-インベントリキット有効化

**トリガー**：inventory_kitチェックボックスON

**処理フロー**：
1. manage_inventoryがtrueであることを確認
2. inventoryFieldArrayに初期行を追加
3. InventoryタブをProgressTabsに追加
4. tabOrderを更新

### 3-保存

**トリガー**：最終タブで「Save」ボタン押下

**処理フロー**：
1. フォーム全体のバリデーションを実行
2. 価格データを変換（リージョンIDの判定、castNumber変換）
3. インベントリアイテムデータを変換
4. `useCreateProductVariant`ミューテーションでバリアントを作成
5. 成功時にモーダルを閉じる
6. 失敗時にエラートースト表示

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 保存ボタン押下 | product_variant | INSERT | 新規バリアントの作成 |
| 保存ボタン押下 | product_variant_option | INSERT | バリアントとオプション値の紐付け |
| 保存ボタン押下 | product_variant_price | INSERT | バリアント価格の作成 |
| 保存ボタン押下 | product_variant_inventory_item | INSERT | インベントリキットの紐付け（オプション） |

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

#### product_variant

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | product_id | 対象商品ID | 必須 |
| INSERT | title | バリアントタイトル | |
| INSERT | sku | SKU | |
| INSERT | manage_inventory | 在庫管理フラグ | |
| INSERT | allow_backorder | バックオーダー許可フラグ | |

#### product_variant_price

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | variant_id | 作成されたバリアントID | |
| INSERT | currency_code | 通貨コード | |
| INSERT | amount | 価格金額 | |
| INSERT | rules | リージョンルール | リージョン価格の場合 |

## メッセージ仕様

| 種別 | メッセージキー | 表示条件 |
|------|--------------|---------|
| 成功 | (なし - モーダル遷移) | 保存成功時 |
| エラー | (API error message) | API呼び出し失敗時 |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| 商品が見つからない | エラーをスロー |
| バリデーションエラー | フォームエラーを表示、該当タブに留まる |
| API呼び出し失敗 | エラートースト表示 |

## 備考

- ProgressTabsコンポーネントによるマルチステップフォーム
- 各タブに独立したバリデーションスキーマ（CreateVariantDetailsSchema, CreateVariantPriceSchema）
- inventory_kit有効時のみInventoryタブが表示される
- useDocumentDirectionでRTL対応
- PrimaryButtonコンポーネントで最終タブ判定（SaveボタンとContinueボタンの切り替え）

---

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

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

### 推奨読解順序

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

まず、バリアント作成のデータ構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | constants.ts | `packages/admin/dashboard/src/routes/products/product-create-variant/components/create-product-variant-form/constants.ts` | CreateProductVariantSchema、部分スキーマの定義 |

**読解のコツ**: 全体スキーマと部分バリデーション用スキーマ（CreateVariantDetailsSchema, CreateVariantPriceSchema）が分離されている。partialFormValidationで段階的バリデーションを実現。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | product-create-variant.tsx | `packages/admin/dashboard/src/routes/products/product-create-variant/product-create-variant.tsx` | ルートコンポーネント、商品データのフェッチ |

**主要処理フロー**:
- **7行目**: useParamsでidを取得
- **9-12行目**: useProductで商品データを取得
- **18-22行目**: RouteFocusModal内でCreateProductVariantFormをレンダリング

#### Step 3: マルチステップフォームを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | create-product-variant-form.tsx | `packages/admin/dashboard/src/routes/products/product-create-variant/components/create-product-variant-form/create-product-variant-form.tsx` | メインのフォームロジック |

**主要処理フロー**:
- **55-57行目**: Tab enumとTabState定義
- **58-68行目**: useFormの初期化
- **72-86行目**: リージョンと通貨のマッピング
- **105-111行目**: tabOrderの動的生成（インベントリキット有無）
- **122-195行目**: handleChangeTab - タブ遷移とバリデーション
- **206-259行目**: handleSubmit - 保存処理

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

```
ProductCreateVariant (product-create-variant.tsx)
    │
    ├─ useParams
    │      └─ id を取得
    │
    ├─ useProduct (hooks/api/products.tsx)
    │      └─ sdk.admin.product.retrieve
    │
    └─ CreateProductVariantForm (create-product-variant-form.tsx)
           │
           ├─ useForm (react-hook-form)
           │      └─ zodResolver(CreateProductVariantSchema)
           │
           ├─ useFieldArray (inventory)
           │
           ├─ useRegions
           │      └─ sdk.admin.region.list
           │
           ├─ ProgressTabs
           │      ├─ DetailsTab (details-tab.tsx)
           │      ├─ PricingTab (pricing-tab.tsx)
           │      └─ InventoryKitTab (inventory-kit-tab.tsx)
           │
           ├─ partialFormValidation
           │      └─ 段階的バリデーション
           │
           └─ useCreateProductVariant
                  └─ sdk.admin.product.createVariant
```

### データフロー図

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

DetailsTab入力 ───────────▶ useForm ────────────────────────▶ フォーム状態更新
        │
        └─ title, sku, options, manage_inventory, ...

PricingTab入力 ───────────▶ useForm ────────────────────────▶ prices更新
        │
        └─ prices[currency/region]

InventoryTab入力 ─────────▶ useFieldArray ──────────────────▶ inventory配列更新
        │
        └─ inventory_item_id, required_quantity

保存ボタン ───────────────▶ handleSubmit ───────────────────▶ API更新
        │
        ├─ 価格変換（リージョン判定、castNumber）
        ├─ インベントリ変換
        │
        └─ useCreateProductVariant
               └─ sdk.admin.product.createVariant
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| product-create-variant.tsx | `packages/admin/dashboard/src/routes/products/product-create-variant/product-create-variant.tsx` | ソース | ルートコンポーネント |
| create-product-variant-form.tsx | `packages/admin/dashboard/src/routes/products/product-create-variant/components/create-product-variant-form/create-product-variant-form.tsx` | ソース | メインフォーム |
| constants.ts | `packages/admin/dashboard/src/routes/products/product-create-variant/components/create-product-variant-form/constants.ts` | ソース | スキーマ定義 |
| details-tab.tsx | `packages/admin/dashboard/src/routes/products/product-create-variant/components/create-product-variant-form/details-tab.tsx` | ソース | 詳細タブ |
| pricing-tab.tsx | `packages/admin/dashboard/src/routes/products/product-create-variant/components/create-product-variant-form/pricing-tab.tsx` | ソース | 価格タブ |
| inventory-kit-tab.tsx | `packages/admin/dashboard/src/routes/products/product-create-variant/components/create-product-variant-form/inventory-kit-tab.tsx` | ソース | インベントリタブ |
| products.tsx | `packages/admin/dashboard/src/hooks/api/products.tsx` | ソース | 商品関連APIフック |
| validation.ts | `packages/admin/dashboard/src/lib/validation.ts` | ソース | partialFormValidation関数 |
