# 画面設計書 154-タグメタデータ編集画面

## 概要

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

### 本画面の処理概要

タグメタデータ編集画面は、商品タグに関連付けられたカスタムメタデータ（キー・バリューペア）を編集するためのドロワー形式の画面である。管理者はこの画面を通じて、商品タグに任意の追加情報を付与することができる。

**業務上の目的・背景**：メタデータは、標準的なフィールドでは表現できない追加情報を格納するために使用される。商品タグにメタデータを追加することで、外部システムとの連携情報、内部管理用のフラグ、カスタム属性など、柔軟なデータ管理が可能となる。

**画面へのアクセス方法**：
1. 商品タグ詳細画面のメタデータセクションから「編集」をクリック
2. 直接URL `/settings/product-tags/{id}/metadata` にアクセス

**主要な操作・処理内容**：
1. 既存のメタデータ（キー・バリューペア）が表示される
2. 新しいメタデータ行を追加する（上または下に挿入）
3. 既存のメタデータを編集する
4. メタデータ行を削除する
5. 「保存」ボタンをクリックして変更を保存する
6. 「キャンセル」ボタンで編集をキャンセルしてドロワーを閉じる

**画面遷移**：
- 遷移元：商品タグ詳細画面（No.152）
- 遷移先：編集完了後は遷移元に戻る（ドロワーを閉じる）

**権限による表示制御**：認証済みの管理ユーザーのみがアクセス可能。

## 関連機能

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

## 画面種別

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

## URL/ルーティング

- パス: `/settings/product-tags/:id/metadata`
- コンポーネント: `ProductTagMetadata`
- モーダルタイプ: `RouteDrawer`

## 入出力項目

| 項目名 | 項目ID | 型 | 必須 | 備考 |
|--------|--------|-----|------|------|
| メタデータキー | metadata[].key | string | No | 空の場合は無視される |
| メタデータ値 | metadata[].value | any | No | 文字列、数値、真偽値をサポート |

## 表示項目

| 項目名 | 説明 | 表示位置 |
|--------|------|----------|
| ヘッダータイトル | 「メタデータを編集」 | ドロワーヘッダー |
| キーラベル | 「Key」 | テーブルヘッダー左 |
| 値ラベル | 「Value」 | テーブルヘッダー右 |
| アクションメニュー | 行の挿入・削除メニュー | 各行の右側 |
| 複雑な値の警告 | オブジェクトや配列は編集不可の警告 | フォーム下部 |
| キャンセルボタン | 「キャンセル」 | フッター左 |
| 保存ボタン | 「保存」 | フッター右 |

## イベント仕様

### 1-フォーム送信（保存ボタン押下）

1. フォームデータを解析し、有効なキー・バリューペアを抽出
2. `useUpdateProductTag` フックを通じて API 呼び出し
3. API呼び出し: `sdk.admin.productTag.update(id, { metadata })`
4. 成功時:
   - トースト通知「メタデータが更新されました」を表示
   - ドロワーを閉じ、前の画面に戻る
5. 失敗時:
   - エラーメッセージをトースト通知で表示

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

1. ドロワーを閉じる
2. 前の画面（商品タグ詳細画面）に戻る

### 3-行の挿入（上に挿入）

1. アクションメニューから「上に行を挿入」を選択
2. 選択した行の上に空のキー・バリューペアを追加

### 4-行の挿入（下に挿入）

1. アクションメニューから「下に行を挿入」を選択
2. 選択した行の下に空のキー・バリューペアを追加

### 5-行の削除

1. アクションメニューから「行を削除」を選択
2. 選択した行を削除
3. 最後の行を削除した場合、空の行を自動追加

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 画面表示 | product_tag | SELECT | 既存メタデータの取得 |
| 保存ボタン押下 | product_tag | UPDATE | メタデータの更新 |

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

#### product_tag

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | metadata | WHERE id = :id | 既存メタデータの取得 |
| UPDATE | metadata | 編集されたメタデータオブジェクト | JSONB形式 |
| UPDATE | updated_at | システム日時 | 更新日時 |

## メッセージ仕様

| 種別 | メッセージキー | メッセージ内容 | 表示条件 |
|------|---------------|---------------|----------|
| 成功 | metadata.edit.successToast | メタデータが更新されました | 更新成功時 |
| エラー | （APIエラーメッセージ） | APIからのエラーメッセージを表示 | 更新失敗時 |
| 警告 | metadata.edit.complexRow.label | 複雑な値 | オブジェクト/配列値がある場合 |
| 警告 | metadata.edit.complexRow.description | オブジェクトや配列は編集できません | オブジェクト/配列値がある場合 |

## 例外処理

| 例外ケース | 処理内容 |
|-----------|---------|
| タグが存在しない | エラーをスロー（エラー境界でキャッチ） |
| ネットワークエラー | エラーメッセージをトースト通知で表示 |
| サーバーエラー | APIからのエラーメッセージをトースト通知で表示 |
| 複雑な値（オブジェクト/配列） | 編集不可として表示、プレースホルダーで表現 |

## 備考

- `MetadataForm` 汎用コンポーネントを使用
- 複雑な値（オブジェクト、配列）は編集不可だが、削除は可能
- 値の型は自動判定: "true"/"false" は真偽値に、数値文字列は数値に変換
- 空のキーを持つ行は保存時に無視される
- 元のメタデータから削除されたキーは空文字で上書き（削除扱い）

---

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

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

### 推奨読解順序

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

まず、メタデータのデータ構造とスキーマを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | MetadataFieldSchema | `packages/admin/dashboard/src/components/forms/metadata-form/metadata-form.tsx:42-46` | メタデータフィールドのZodスキーマ |
| 1-2 | MetadataSchema | `packages/admin/dashboard/src/components/forms/metadata-form/metadata-form.tsx:48-50` | メタデータ配列のスキーマ |

**読解のコツ**: メタデータは `{ key: string, value: any, disabled?: boolean }` の配列として管理される。disabled は複雑な値（オブジェクト/配列）の場合に true となる。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ProductTagMetadata | `packages/admin/dashboard/src/routes/product-tags/product-tag-metadata/product-tag-metadata.tsx` | メタデータ編集のエントリーポイント |

**主要処理フロー**:
1. **行6**: useParams で id を取得
2. **行8**: useProductTag でタグデータ（メタデータ含む）を取得
3. **行10-12**: useUpdateProductTag でミューテーションフックを取得
4. **行18-24**: MetadataForm コンポーネントにプロパティを渡す

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | MetadataForm | `packages/admin/dashboard/src/components/forms/metadata-form/metadata-form.tsx` | 汎用メタデータ編集フォーム |

**主要処理フロー**:
- **行52-68**: MetadataForm コンポーネント（外側のドロワー構造）
- **行74-294**: InnerForm コンポーネント（実際のフォームロジック）
- **行84-89**: useForm による初期化
- **行91-108**: handleSubmit でフォーム送信処理
- **行110-113**: useFieldArray で動的フィールド管理
- **行115-134**: 行の削除と挿入のヘルパー関数
- **行333-367**: getDefaultValues で既存メタデータを初期値に変換
- **行369-426**: parseValues で保存用データを生成

#### Step 4: APIフックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | useUpdateProductTag | `packages/admin/dashboard/src/hooks/api/tags.tsx:113-136` | メタデータ更新に使用するフック |

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

```
ProductTagMetadata（エントリーポイント）
    │
    ├─ useParams（id 取得）
    │
    ├─ useProductTag（既存データ取得）
    │      └─ sdk.admin.productTag.retrieve()
    │
    ├─ useUpdateProductTag（ミューテーション）
    │
    └─ MetadataForm
           │
           ├─ RouteDrawer（ドロワー構造）
           │
           └─ InnerForm
                  │
                  ├─ useForm (react-hook-form)
                  │      └─ defaultValues: getDefaultValues(metadata)
                  │
                  ├─ useFieldArray (動的フィールド管理)
                  │      ├─ insert (行追加)
                  │      └─ remove (行削除)
                  │
                  └─ handleSubmit
                         │
                         ├─ parseValues (データ変換)
                         │
                         └─ hook({ metadata })
                                ├─ onSuccess → toast.success()
                                └─ onError → toast.error()
```

### データフロー図

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

URL params (id) ───▶ ProductTagMetadata ───▶ ドロワーを閉じる
                          │
                          ├─ useProductTag
                          │      │
                          │      └─ GET /admin/product-tags/{id}
                          │              │
                          │              └─ metadata データ
                          │
                          └─ MetadataForm
                                 │
metadata entries ───▶ InnerForm
                          │
                          ├─ getDefaultValues (初期値変換)
                          │      └─ 複雑な値は disabled: true
                          │
                          ├─ useFieldArray (動的フィールド)
                          │
                          ├─ parseValues (保存データ変換)
                          │      ├─ "true"/"false" → boolean
                          │      ├─ 数値文字列 → number
                          │      └─ 削除されたキー → ""
                          │
                          └─ PUT /admin/product-tags/{id}
                                 │
                                 └─ 更新された product_tag
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| product-tag-metadata.tsx | `packages/admin/dashboard/src/routes/product-tags/product-tag-metadata/product-tag-metadata.tsx` | ソース | エントリーポイント |
| metadata-form.tsx | `packages/admin/dashboard/src/components/forms/metadata-form/metadata-form.tsx` | ソース | 汎用メタデータフォーム |
| tags.tsx | `packages/admin/dashboard/src/hooks/api/tags.tsx` | ソース | 商品タグAPIフック |
| index.ts | `packages/admin/dashboard/src/routes/product-tags/product-tag-metadata/index.ts` | ソース | モジュールエクスポート |
