# 画面設計書 24-バリアント編集画面

## 概要

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

### 本画面の処理概要

バリアント編集画面は、商品バリアントの詳細情報を編集するためのドロワー形式の画面である。基本情報、在庫関連設定、属性情報（寸法・重量・原産国など）を一括で編集できる。

**業務上の目的・背景**：商品バリアントは商品運営の中核であり、SKU、オプション値、在庫管理設定、物流に必要な寸法・重量情報など多岐にわたる情報を持つ。この画面により、バリアント固有の情報を効率的に更新でき、在庫管理ポリシーの変更や商品属性の修正を容易に行える。

**画面へのアクセス方法**：バリアント詳細画面のアクションメニューから「編集」を選択、または商品詳細画面のバリアント一覧から「編集」アクションを選択することでドロワー形式で表示される。URLは `/products/:id/variants/:variant_id/edit` の形式となる。

**主要な操作・処理内容**：
1. バリアントタイトルの編集
2. 素材（マテリアル）の編集
3. オプション値（サイズ・色など）の変更
4. SKU、EAN、UPC、バーコードの編集
5. 在庫管理有効/無効の切り替え
6. バックオーダー許可の切り替え
7. 寸法・重量情報の編集
8. HSコード、MIDコード、原産国の編集

**画面遷移**：バリアント詳細画面または商品詳細画面からドロワーとして開き、保存またはキャンセル後に元の画面に戻る。

**権限による表示制御**：商品の編集権限を持つユーザーのみが操作可能。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 2 | 商品バリアント管理 | 主機能 | バリアント情報の編集 |

## 画面種別

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

## URL/ルーティング

`/products/:id/variants/:variant_id/edit`

または

`/products/:id/edit?variant_id=:variant_id`（クエリパラメータ形式もサポート）

## 入出力項目

| 項目名 | 項目ID | データ型 | 必須 | 入力/出力 | 説明 |
|--------|--------|----------|------|-----------|------|
| タイトル | title | string | 必須 | 入出力 | バリアントの名前 |
| 素材 | material | string | - | 入出力 | 素材情報 |
| オプション値 | options | Record<string, string> | - | 入出力 | オプションタイトルをキーとした値 |
| SKU | sku | string | - | 入出力 | 在庫管理単位コード |
| EAN | ean | string | - | 入出力 | 欧州商品コード |
| UPC | upc | string | - | 入出力 | 米国統一商品コード |
| バーコード | barcode | string | - | 入出力 | バーコード番号 |
| 在庫管理 | manage_inventory | boolean | - | 入出力 | 在庫管理を有効にするか |
| バックオーダー許可 | allow_backorder | boolean | - | 入出力 | 在庫切れ時の注文を許可するか |
| 重量 | weight | number | - | 入出力 | 重量（グラム） |
| 幅 | width | number | - | 入出力 | 幅（センチメートル） |
| 高さ | height | number | - | 入出力 | 高さ（センチメートル） |
| 長さ | length | number | - | 入出力 | 長さ（センチメートル） |
| MIDコード | mid_code | string | - | 入出力 | 製造者識別コード |
| HSコード | hs_code | string | - | 入出力 | 関税分類コード |
| 原産国 | origin_country | string | - | 入出力 | 原産国コード |

## 表示項目

| 項目名 | データ型 | 説明 |
|--------|----------|------|
| フォームヘッダー | Heading | 「バリアントを編集」 |
| 基本情報セクション | section | タイトル、素材、オプション値の入力フィールド |
| 在庫セクション | section | SKU、EAN、UPC、バーコード、在庫設定のフィールド |
| 属性セクション | section | 寸法、重量、関税コード、原産国のフィールド |

## イベント仕様

### 1-タイトル入力

必須フィールド。空の場合はバリデーションエラーとなる。

### 2-オプション値選択

商品に定義されているオプション（サイズ、色など）ごとにComboboxで値を選択。既存のオプション値から選択する形式。

### 3-在庫管理スイッチ切り替え

在庫管理を有効/無効に切り替える。無効にすると在庫数量の追跡が行われなくなる。

### 4-バックオーダースイッチ切り替え

バックオーダー（在庫切れ時の注文受付）を許可/禁止に切り替える。

### 5-寸法・重量入力

数値入力フィールド。空の場合はnullとして保存される。

### 6-原産国選択

CountrySelectコンポーネントで国を選択。

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

フォームの内容を検証し、APIを呼び出してバリアントを更新する。成功時はトースト通知を表示し、ドロワーを閉じる。

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

変更を破棄し、ドロワーを閉じて元の画面に戻る。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 保存ボタン押下 | product_variant | UPDATE | バリアント情報を更新 |
| 保存ボタン押下 | product_variant_option | UPDATE | オプション値を更新 |

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

#### product_variant

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | title | フォーム入力値 | 必須 |
| UPDATE | material | フォーム入力値（空はnull） | オプション |
| UPDATE | sku | フォーム入力値（空はnull） | オプション |
| UPDATE | ean | フォーム入力値（空はnull） | オプション |
| UPDATE | upc | フォーム入力値（空はnull） | オプション |
| UPDATE | barcode | フォーム入力値（空はnull） | オプション |
| UPDATE | manage_inventory | フォーム入力値 | boolean |
| UPDATE | allow_backorder | フォーム入力値 | boolean |
| UPDATE | weight | フォーム入力値（数値変換） | オプション |
| UPDATE | width | フォーム入力値（数値変換） | オプション |
| UPDATE | height | フォーム入力値（数値変換） | オプション |
| UPDATE | length | フォーム入力値（数値変換） | オプション |
| UPDATE | mid_code | フォーム入力値（空はnull） | オプション |
| UPDATE | hs_code | フォーム入力値（空はnull） | オプション |
| UPDATE | origin_country | フォーム入力値（空はnull） | オプション |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|----------|
| products.variant.edit.success | 成功 | バリアントが正常に更新されました | 保存成功時 |
| - | エラー | {エラーメッセージ} | API呼び出し失敗時 |

## 例外処理

| 例外条件 | 処理内容 |
|----------|----------|
| バリアントが見つからない | エラーをthrowし、エラーバウンダリで処理 |
| 商品が見つからない | エラーをthrowし、エラーバウンダリで処理 |
| API呼び出し失敗 | トースト通知でエラーメッセージを表示 |
| バリデーションエラー | フォームフィールドにエラーメッセージを表示 |

## 備考

- zodスキーマによるバリデーション
- transformNullableFormData/transformNullableFormNumberで空値のnull変換
- optionalIntでオプショナルな整数値の検証
- オプション値はオプションタイトルをキーとしたRecord形式で管理
- 既存のオプション値はComboboxで選択形式
- URLパラメータとクエリパラメータの両方をサポート

---

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

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

### 推奨読解順序

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

フォームスキーマとバリデーションルールを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | product-edit-variant-form.tsx | `packages/admin/dashboard/src/routes/product-variants/product-variant-edit/components/product-edit-variant-form/product-edit-variant-form.tsx` | ProductEditVariantSchema（25-42行目）でフォーム構造を確認 |

**読解のコツ**: zodスキーマでtitleは必須（min(1)）、その他はオプショナル。optionalIntは空文字または整数を許容。

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

ルートコンポーネントの処理を追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | product-variant-edit.tsx | `packages/admin/dashboard/src/routes/product-variants/product-variant-edit/product-variant-edit.tsx` | useParams/useSearchParamsでパラメータ取得（15-17行目） |
| 2-2 | product-variant-edit.tsx | `packages/admin/dashboard/src/routes/product-variants/product-variant-edit/product-variant-edit.tsx` | useProductVariantとuseProductでデータ取得（19-42行目） |
| 2-3 | product-variant-edit.tsx | `packages/admin/dashboard/src/routes/product-variants/product-variant-edit/product-variant-edit.tsx` | ready状態でフォーム描画（44, 59行目） |

**主要処理フロー**:
1. **15-17行目**: URLパラメータとクエリパラメータを取得
2. **19-26行目**: useProductVariantでバリアントデータをフェッチ
3. **28-42行目**: useProductで商品データをフェッチ（オプション情報取得のため）
4. **44行目**: ready変数で両方のデータ取得完了を確認
5. **59行目**: readyになったらProductEditVariantFormを描画

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

編集フォームの実装詳細を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | product-edit-variant-form.tsx | `packages/admin/dashboard/src/routes/product-variants/product-variant-edit/components/product-edit-variant-form/product-edit-variant-form.tsx` | defaultValuesの設定（51-75行目） |
| 3-2 | product-edit-variant-form.tsx | `packages/admin/dashboard/src/routes/product-variants/product-variant-edit/components/product-edit-variant-form/product-edit-variant-form.tsx` | handleSubmit処理（84-122行目） |
| 3-3 | product-edit-variant-form.tsx | `packages/admin/dashboard/src/routes/product-variants/product-variant-edit/components/product-edit-variant-form/product-edit-variant-form.tsx` | フォームフィールド配置（131-430行目） |

**主要処理フロー**:
- **51-56行目**: defaultOptionsで商品オプションからバリアントの現在のオプション値を取得
- **57-77行目**: useFormでフォーム初期化
- **84-122行目**: handleSubmitでtransformNullableFormDataを使用してnull変換後、API呼び出し

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

```
ProductVariantEdit (product-variant-edit.tsx:9-62)
    │
    ├─ useLoaderData() → SSR初期データ取得
    │
    ├─ useParams() → URLパラメータ取得
    │
    ├─ useSearchParams() → クエリパラメータ取得
    │
    ├─ useProductVariant(id, variant_id) → バリアントデータ取得
    │      └─ sdk.admin.productVariant.retrieve()
    │
    ├─ useProduct(variant.product_id) → 商品データ取得
    │      └─ sdk.admin.product.retrieve()
    │
    └─ ProductEditVariantForm (product-edit-variant-form.tsx:45-447)
           │
           ├─ useForm() → フォーム状態管理
           │
           ├─ useUpdateProductVariant() → 更新処理
           │      └─ sdk.admin.productVariant.update()
           │
           └─ handleSubmit()
                  ├─ transformNullableFormData() → 空値のnull変換
                  └─ mutateAsync() → API呼び出し
```

### データフロー図

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

URLパラメータ(id, variant_id) ───▶ useProductVariant ───▶ バリアントデータ取得
                                          │
クエリパラメータ(variant_id) ─────────────┘
                                          │
                                          ▼
variant.product_id ─────────────▶ useProduct ───▶ 商品データ取得
                                          │
                                          ▼
                                  defaultOptions計算
                                          │
フォーム入力 ─────────────────────────────▶ useForm
                                          │
保存ボタン押下 ───────────────────────────▶ handleSubmit
                                          │
                                          ▼
                              transformNullableFormData
                                          │
                                          ▼
                              mutateAsync ───▶ API更新
                                          │
                                          ▼
                              handleSuccess("../") ───▶ ドロワーを閉じる
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| product-variant-edit.tsx | `packages/admin/dashboard/src/routes/product-variants/product-variant-edit/product-variant-edit.tsx` | ソース | 画面のエントリーポイント |
| loader.ts | `packages/admin/dashboard/src/routes/product-variants/product-variant-edit/loader.ts` | ソース | SSRデータローダー |
| product-edit-variant-form.tsx | `packages/admin/dashboard/src/routes/product-variants/product-variant-edit/components/product-edit-variant-form/product-edit-variant-form.tsx` | ソース | 編集フォームコンポーネント |
| useProductVariant | `packages/admin/dashboard/src/hooks/api/products.ts` | ソース | バリアント取得フック |
| useProduct | `packages/admin/dashboard/src/hooks/api/products.ts` | ソース | 商品取得フック |
| useUpdateProductVariant | `packages/admin/dashboard/src/hooks/api/products.ts` | ソース | バリアント更新フック |
| RouteDrawer | `packages/admin/dashboard/src/components/modals/` | ソース | ドロワーモーダルコンポーネント |
| Combobox | `packages/admin/dashboard/src/components/inputs/combobox/` | ソース | オプション選択コンポーネント |
| CountrySelect | `packages/admin/dashboard/src/components/inputs/country-select/` | ソース | 国選択コンポーネント |
