# 画面設計書 21-商品メタデータ編集画面

## 概要

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

### 本画面の処理概要

商品メタデータ編集画面は、商品に関連付けられたカスタムメタデータ（キーと値のペア）を編集するためのモーダル形式の画面である。

**業務上の目的・背景**：ECサイト運営において、商品には標準フィールドでは表現できないカスタム情報（例：仕入先コード、内部管理番号、特殊な属性情報）を付与する必要がある。メタデータ機能により、システムの柔軟性を維持しながら、業務固有の情報を商品に紐付けて管理できる。これにより、外部システム連携やカスタマイズされた商品表示が可能となる。

**画面へのアクセス方法**：商品詳細画面のJSONセクション内にある「メタデータを編集」ボタンをクリックすることで、ドロワー形式でこの画面が表示される。URLは `/products/:id/metadata` の形式となる。

**主要な操作・処理内容**：
1. 既存のメタデータキー・値ペアの表示と編集
2. 新規メタデータ行の追加（行の上または下に挿入可能）
3. メタデータ行の削除
4. 複雑なデータ型（オブジェクト、配列）の読み取り専用表示
5. 変更内容の保存とキャンセル

**画面遷移**：商品詳細画面からモーダルとして開き、保存またはキャンセル後に商品詳細画面に戻る。

**権限による表示制御**：商品の編集権限を持つユーザーのみがメタデータを編集可能。読み取り専用ユーザーはこの画面にアクセスできない。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | 商品CRUD | 主機能 | 商品メタデータの編集 |

## 画面種別

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

## URL/ルーティング

`/products/:id/metadata`

## 入出力項目

| 項目名 | 項目ID | データ型 | 必須 | 入力/出力 | 説明 |
|--------|--------|----------|------|-----------|------|
| 商品ID | id | string | 必須 | 入力（URLパラメータ） | 編集対象の商品ID |
| メタデータキー | metadata[].key | string | - | 入出力 | メタデータのキー名 |
| メタデータ値 | metadata[].value | string/number/boolean | - | 入出力 | メタデータの値 |

## 表示項目

| 項目名 | データ型 | 説明 |
|--------|----------|------|
| メタデータテーブル | array | キーと値のペアを表形式で表示 |
| キー列ヘッダー | string | "Key" ラベル |
| 値列ヘッダー | string | "Value" ラベル |
| 複雑データ警告 | InlineTip | オブジェクト/配列型の値がある場合に警告表示 |

## イベント仕様

### 1-行メニュー表示

メタデータ行にホバーすると、行の右端にアクションメニュー（縦三点リーダー）が表示される。

### 2-上に行を挿入

行メニューから「上に行を挿入」を選択すると、現在の行の上に新しい空のメタデータ行が追加される。

### 3-下に行を挿入

行メニューから「下に行を挿入」を選択すると、現在の行の下に新しい空のメタデータ行が追加される。

### 4-行を削除

行メニューから「行を削除」を選択すると、該当行が削除される。最後の行を削除した場合は、新しい空の行が自動的に追加される。

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

フォームの内容を検証し、APIを呼び出してメタデータを更新する。成功時はトースト通知を表示し、モーダルを閉じる。

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

変更を破棄し、モーダルを閉じて商品詳細画面に戻る。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 保存ボタン押下 | product | UPDATE | 商品のmetadataフィールドを更新 |

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

#### product

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | metadata | フォーム入力されたキー・値ペアをJSON形式で保存 | 空のキーは除外、削除されたキーは空文字で上書き |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|----------|
| metadata.edit.successToast | 成功 | メタデータが正常に更新されました | 保存成功時 |
| - | エラー | {エラーメッセージ} | API呼び出し失敗時 |
| metadata.edit.complexRow.label | 警告 | 複雑なデータ | オブジェクト/配列型の値がある場合 |
| metadata.edit.complexRow.description | 情報 | 一部のメタデータフィールドは編集できません | オブジェクト/配列型の値がある場合 |
| metadata.edit.complexRow.tooltip | ヒント | この行は編集できません | 複雑なデータ行にホバー時 |

## 例外処理

| 例外条件 | 処理内容 |
|----------|----------|
| 商品が見つからない | エラーをthrowし、エラーバウンダリで処理 |
| API呼び出し失敗 | トースト通知でエラーメッセージを表示 |
| ネットワークエラー | トースト通知でエラーメッセージを表示 |

## 備考

- 文字列、数値、真偽値以外の複雑なデータ型（オブジェクト、配列）は読み取り専用で表示される
- 値が "true" または "false" の文字列の場合、保存時に真偽値型に変換される
- 数値形式の文字列は保存時に数値型に変換される
- MetadataFormコンポーネントは商品以外のエンティティ（バリアント、カテゴリなど）でも再利用される汎用コンポーネント

---

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

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

### 推奨読解順序

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

メタデータはJSONオブジェクト形式で商品テーブルに保存される。フォームではキー・値・無効フラグの配列として管理される。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | metadata-form.tsx | `packages/admin/dashboard/src/components/forms/metadata-form/metadata-form.tsx` | MetadataFieldSchema（42-46行目）でフォームの単一行の構造を確認 |
| 1-2 | metadata-form.tsx | `packages/admin/dashboard/src/components/forms/metadata-form/metadata-form.tsx` | MetadataSchema（48-50行目）でフォーム全体の構造を確認 |

**読解のコツ**: zodライブラリによるスキーマ定義。keyは文字列、valueはany型、disabledは編集可否を示すオプショナルな真偽値。

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

ルートコンポーネントから処理の流れを追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | product-metadata.tsx | `packages/admin/dashboard/src/routes/products/product-metadata/product-metadata.tsx` | useParamsでURLから商品IDを取得（6行目） |
| 2-2 | product-metadata.tsx | `packages/admin/dashboard/src/routes/products/product-metadata/product-metadata.tsx` | useProductフックで商品データ取得（8-12行目） |
| 2-3 | product-metadata.tsx | `packages/admin/dashboard/src/routes/products/product-metadata/product-metadata.tsx` | useUpdateProductフックで更新処理を準備（14行目） |

**主要処理フロー**:
1. **6行目**: URLパラメータから商品IDを取得
2. **8-12行目**: useProductフックで商品データをフェッチ
3. **14行目**: useUpdateProductフックでmutateAsync関数を取得
4. **20-27行目**: MetadataFormコンポーネントにpropsを渡して描画

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

MetadataFormコンポーネントの内部処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | metadata-form.tsx | `packages/admin/dashboard/src/components/forms/metadata-form/metadata-form.tsx` | getDefaultValues関数（333-367行目）で初期値の変換ロジックを確認 |
| 3-2 | metadata-form.tsx | `packages/admin/dashboard/src/components/forms/metadata-form/metadata-form.tsx` | handleSubmit（91-108行目）で保存処理の流れを確認 |
| 3-3 | metadata-form.tsx | `packages/admin/dashboard/src/components/forms/metadata-form/metadata-form.tsx` | parseValues関数（369-428行目）で送信データの変換ロジックを確認 |

**主要処理フロー**:
- **84-89行目**: react-hook-formのuseFormでフォーム状態を初期化
- **110-113行目**: useFieldArrayで動的な行の追加・削除を管理
- **91-108行目**: handleSubmitでフォーム送信時にparseValuesで変換後、hook関数（mutateAsync）を呼び出し

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

```
ProductMetadata (product-metadata.tsx:5-28)
    │
    ├─ useParams() → 商品ID取得
    │
    ├─ useProduct(id) → 商品データ取得
    │      └─ sdk.admin.product.retrieve()
    │
    ├─ useUpdateProduct(product.id) → 更新関数取得
    │      └─ sdk.admin.product.update()
    │
    └─ MetadataForm (metadata-form.tsx:52-68)
           │
           ├─ useForm() → フォーム状態管理
           │
           ├─ useFieldArray() → 動的行管理
           │
           ├─ getDefaultValues() → 初期値変換
           │
           └─ handleSubmit()
                  └─ parseValues() → 送信データ変換
                         └─ hook() → mutateAsync呼び出し
```

### データフロー図

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

URLパラメータ(id) ───▶ useProduct ───▶ 商品データ取得
                            │
                            ▼
                      getDefaultValues
                            │
                            ▼
フォーム入力 ──────────▶ useForm/useFieldArray
                            │
                            ▼
                      parseValues
                            │
                            ▼
保存ボタン押下 ────────▶ mutateAsync ───▶ API更新
                            │
                            ▼
                      handleSuccess ───▶ モーダルを閉じる
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| product-metadata.tsx | `packages/admin/dashboard/src/routes/products/product-metadata/product-metadata.tsx` | ソース | 画面のエントリーポイント |
| index.ts | `packages/admin/dashboard/src/routes/products/product-metadata/index.ts` | ソース | エクスポート定義 |
| metadata-form.tsx | `packages/admin/dashboard/src/components/forms/metadata-form/metadata-form.tsx` | ソース | メタデータ編集フォームの汎用コンポーネント |
| useProduct | `packages/admin/dashboard/src/hooks/api/products.ts` | ソース | 商品データ取得フック |
| useUpdateProduct | `packages/admin/dashboard/src/hooks/api/products.ts` | ソース | 商品更新フック |
| RouteDrawer | `packages/admin/dashboard/src/components/modals/` | ソース | ドロワーモーダルコンポーネント |
