# 画面設計書 6-商品作成画面

## 概要

本ドキュメントは、Medusa Admin Dashboard の商品作成画面の設計仕様を定義するものです。新規商品を登録するためのウィザード形式の画面で、詳細情報、組織情報、バリアント、在庫キットの4ステップで構成されています。

### 本画面の処理概要

本画面は、新規商品を作成するためのマルチステップフォームを提供するモーダル形式の画面です。商品の基本情報から始まり、カテゴリ・タグの設定、バリアントの作成、在庫キットの設定まで、段階的に商品情報を入力していきます。

**業務上の目的・背景**：ECサイトへの商品登録は、タイトル、説明文、価格、在庫、カテゴリなど多岐にわたる情報の入力が必要です。本画面は、これらの情報を論理的なステップに分割し、ユーザーが迷わずに必要な情報を入力できるよう設計されています。また、下書き保存機能により、入力途中の状態を保存することも可能です。

**画面へのアクセス方法**：
- 商品一覧画面の「作成」ボタンから
- ブラウザで直接 `/products/create` へアクセス

**主要な操作・処理内容**：
1. 詳細タブ - タイトル、サブタイトル、ハンドル、説明文、メディア、バリアント設定
2. 組織タブ - タイプ、コレクション、カテゴリ、タグ、販売チャネル、属性の設定
3. バリアントタブ - バリアントの価格、在庫、SKUなどの設定
4. 在庫キットタブ（条件付き）- 在庫キットの設定
5. 下書きとして保存 - 「draft」ステータスで商品を保存
6. 公開 - 「published」ステータスで商品を保存

**画面遷移**：
- 遷移元：商品一覧画面
- 遷移先：商品詳細画面（作成成功後）、商品一覧画面（キャンセル時）

**権限による表示制御**：本画面は認証済みユーザーのみアクセス可能です。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | 商品CRUD | 主機能 | 新規商品の作成処理 |
| 2 | 商品バリアント管理 | 補助機能 | 商品バリアントの同時作成 |
| 3 | 商品オプション管理 | 補助機能 | 商品オプションの設定 |
| 52 | 価格設定管理 | 補助機能 | 商品価格の設定 |
| 70 | 販売チャネルCRUD | API連携 | 販売チャネル情報の取得 |

## 画面種別

登録画面（モーダル・ウィザード形式）

## URL/ルーティング

`/products/create`

## 入出力項目

### 詳細タブ

| 項目名 | 項目ID | データ型 | 必須 | 説明 |
|--------|--------|----------|------|------|
| タイトル | title | string | 必須 | 商品名 |
| サブタイトル | subtitle | string | 任意 | 商品のサブタイトル |
| ハンドル | handle | string | 必須 | URL用のスラッグ |
| 素材 | material | string | 任意 | 素材情報 |
| 説明文 | description | string | 任意 | 商品の説明文 |
| 割引可能 | discountable | boolean | 必須 | 割引適用可否（デフォルト: true） |
| メディア | media | File[] | 任意 | 商品画像・動画 |
| サムネイル | thumbnail | File | 任意 | サムネイル画像 |

### 組織タブ

| 項目名 | 項目ID | データ型 | 必須 | 説明 |
|--------|--------|----------|------|------|
| タイプ | type_id | string | 任意 | 商品タイプ |
| コレクション | collection_id | string | 任意 | 所属コレクション |
| カテゴリ | categories | string[] | 任意 | 商品カテゴリ |
| タグ | tags | string[] | 任意 | 商品タグ |
| 販売チャネル | sales_channels | Object[] | 任意 | 販売チャネル |
| 幅 | width | number | 任意 | 商品の幅 |
| 長さ | length | number | 任意 | 商品の長さ |
| 高さ | height | number | 任意 | 商品の高さ |
| 重量 | weight | number | 任意 | 商品の重量 |
| MIDコード | mid_code | string | 任意 | MIDコード |
| HSコード | hs_code | string | 任意 | HSコード |
| 原産国 | origin_country | string | 任意 | 原産国 |

### バリアントタブ

| 項目名 | 項目ID | データ型 | 必須 | 説明 |
|--------|--------|----------|------|------|
| オプション | options | Object[] | 任意 | バリアントオプション |
| バリアント | variants | Object[] | 任意 | バリアントの配列 |

#### バリアント詳細

| 項目名 | 項目ID | データ型 | 必須 | 説明 |
|--------|--------|----------|------|------|
| タイトル | title | string | 必須 | バリアント名 |
| SKU | sku | string | 任意 | SKUコード |
| バーコード | barcode | string | 任意 | バーコード |
| EAN | ean | string | 任意 | EANコード |
| UPC | upc | string | 任意 | UPCコード |
| 在庫管理 | manage_inventory | boolean | 必須 | 在庫管理有無 |
| 在庫キット | inventory_kit | boolean | 必須 | 在庫キット有無 |
| 価格 | prices | Object[] | 必須 | 通貨/地域別価格 |

## 表示項目

### ヘッダー

| 項目名 | 表示位置 | データソース | 説明 |
|--------|----------|--------------|------|
| タブナビゲーション | ヘッダー | 静的 | Details / Organize / Variants / Inventory |
| 進行状況インジケーター | タブ | 動的 | not-started / in-progress / completed |

### フッター

| 項目名 | 表示位置 | データソース | 説明 |
|--------|----------|--------------|------|
| キャンセルボタン | フッター左 | i18n (actions.cancel) | キャンセルボタン |
| 下書き保存ボタン | フッター右 | i18n (actions.saveAsDraft) | 下書き保存ボタン |
| 次へ/公開ボタン | フッター右 | i18n | 次のステップまたは公開ボタン |

## イベント仕様

### 1-次へボタン押下

**トリガー**: 「続ける」ボタンのクリック（各タブ）

**処理フロー**:
1. 現在のタブのバリデーションを実行（form.trigger()）
2. バリデーション成功時、次のタブに移動
3. タブの状態（tabState）を更新

**遷移先**: 次のタブ（Details → Organize → Variants → Inventory）

### 2-タブ切り替え

**トリガー**: タブのクリック

**処理フロー**:
1. バリデーションを実行
2. バリデーション成功時、選択したタブに移動
3. タブの状態を更新

### 3-下書き保存ボタン押下

**トリガー**: 「下書きとして保存」ボタンのクリック

**処理フロー**:
1. フォームデータを収集
2. メディアファイルがある場合、`sdk.admin.upload.create` でアップロード
3. `useCreateProduct` フックで商品を作成（status: "draft"）
4. 成功時:
   - トースト通知で成功メッセージを表示
   - 作成された商品の詳細画面へ遷移
5. 失敗時:
   - トースト通知でエラーメッセージを表示

**遷移先**: 商品詳細画面（/products/{productId}）

### 4-公開ボタン押下

**トリガー**: 「公開」ボタンのクリック（最終タブ）

**処理フロー**:
1. フォームデータを収集
2. メディアファイルがある場合、`sdk.admin.upload.create` でアップロード
3. `useCreateProduct` フックで商品を作成（status: "published"）
4. 成功時:
   - トースト通知で成功メッセージを表示
   - 作成された商品の詳細画面へ遷移
5. 失敗時:
   - トースト通知でエラーメッセージを表示

**遷移先**: 商品詳細画面（/products/{productId}）

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

**トリガー**: 「キャンセル」ボタンのクリック

**処理フロー**:
1. RouteFocusModal.Close によりモーダルを閉じる

**遷移先**: 商品一覧画面（/products）

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 商品作成 | product | INSERT | 商品レコードの作成 |
| バリアント作成 | product_variant | INSERT | バリアントレコードの作成 |
| オプション作成 | product_option | INSERT | オプションレコードの作成 |
| 価格作成 | price | INSERT | 価格レコードの作成 |
| 在庫作成 | inventory_item | INSERT | 在庫アイテムレコードの作成 |
| メディアアップロード | file | INSERT | ファイルレコードの作成 |
| 画像紐付け | product_image | INSERT | 商品画像紐付けレコードの作成 |

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

#### product

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | title | 入力値 | 必須 |
| INSERT | subtitle | 入力値 | 任意 |
| INSERT | handle | 入力値（自動生成可） | 必須 |
| INSERT | description | 入力値 | 任意 |
| INSERT | status | "draft" または "published" | 保存方法による |
| INSERT | discountable | 入力値 | デフォルト: true |
| INSERT | type_id | 入力値 | 任意 |
| INSERT | collection_id | 入力値 | 任意 |
| INSERT | created_at | 現在日時 | 自動設定 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|----------|
| products.create.successToast | 成功 | {title}を作成しました | 商品作成成功時 |
| validation.required | エラー | この項目は必須です | 必須項目が未入力の場合 |
| validation.email | エラー | 有効なメールアドレスを入力してください | メールアドレス形式が不正な場合 |

## 例外処理

| 例外条件 | 処理内容 | ユーザーへの表示 |
|---------|---------|-----------------|
| バリデーションエラー | 次のタブへの遷移をブロック | フィールドにエラーメッセージを表示 |
| メディアアップロード失敗 | トーストでエラー表示 | エラーメッセージをトーストで表示 |
| 商品作成API失敗 | トーストでエラー表示 | エラーメッセージをトーストで表示 |
| ストア情報取得失敗 | エラーをスロー | エラー境界でキャッチして表示 |
| リージョン情報取得失敗 | エラーをスロー | エラー境界でキャッチして表示 |

## 備考

- 本画面は認証済みユーザーのみアクセス可能なプロテクト画面です
- モーダル形式（RouteFocusModal）で表示されます
- 4つのタブ（Details, Organize, Variants, Inventory）で構成されます
- Inventoryタブは、バリアントで `manage_inventory` と `inventory_kit` の両方が true の場合のみ表示されます
- デフォルト販売チャネルはストア設定から自動設定されます
- 拡張機能により、フォームにカスタムフィールドを追加可能です（getFormConfigs, getFormFields）
- Enter + Cmd/Ctrl で次のタブへ移動、最終タブでは送信を実行します

---

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

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

### 推奨読解順序

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

まず、商品作成フォームのスキーマ定義を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | constants.ts | `packages/admin/dashboard/src/routes/products/product-create/constants.ts` | ProductCreateSchemaとデフォルト値の定義 |
| 1-2 | types.ts | `packages/admin/dashboard/src/routes/products/product-create/types.ts` | 型定義 |

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

ProductCreateコンポーネントから処理の流れを確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | product-create.tsx | `packages/admin/dashboard/src/routes/products/product-create/product-create.tsx` | メインコンポーネント |

**主要処理フロー**:
1. **12-54行目**: 必要なデータの取得（ストア、販売チャネル、リージョン、価格設定）
2. **46-54行目**: ready状態の判定
3. **72-87行目**: RouteFocusModalでProductCreateFormを表示

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

ProductCreateFormコンポーネントの詳細を確認します。

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

**主要処理フロー**:
1. **50-72行目**: フォーム初期化とタブ状態管理
2. **74行目**: useCreateProductフックの取得
3. **105-169行目**: handleSubmit関数（メディアアップロード→商品作成）
4. **171-214行目**: タブ状態更新のuseEffect
5. **216-357行目**: UIレンダリング（ProgressTabs）

#### Step 4: 各タブコンポーネントを理解する

各タブフォームの実装を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | product-create-details-form.tsx | `packages/admin/dashboard/src/routes/products/product-create/components/product-create-details-form/product-create-details-form.tsx` | 詳細タブ |
| 4-2 | product-create-organize-form.tsx | `packages/admin/dashboard/src/routes/products/product-create/components/product-create-organize-form/product-create-organize-form.tsx` | 組織タブ |
| 4-3 | product-create-variants-form.tsx | `packages/admin/dashboard/src/routes/products/product-create/components/product-create-variants-form/product-create-variants-form.tsx` | バリアントタブ |
| 4-4 | product-create-inventory-kit-form.tsx | `packages/admin/dashboard/src/routes/products/product-create/components/product-create-inventory-kit-form/product-create-inventory-kit-form.tsx` | 在庫キットタブ |

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

```
ProductCreate (product-create.tsx)
    │
    ├─ useStore
    ├─ useSalesChannel
    ├─ useRegions
    └─ usePricePreferences
           │
           └─ ProductCreateForm (product-create-form.tsx)
                  │
                  ├─ useExtendableForm
                  ├─ useCreateProduct
                  │
                  └─ ProgressTabs
                         ├─ ProductCreateDetailsForm
                         │      ├─ ProductCreateGeneralSection
                         │      ├─ ProductCreateMediaSection
                         │      └─ ProductCreateVariantSection
                         │
                         ├─ ProductCreateOrganizeForm
                         │      ├─ ProductCreateOrganizeSection
                         │      └─ ProductCreateAttributeSection
                         │
                         ├─ ProductCreateVariantsForm
                         │
                         └─ ProductCreateInventoryKitForm (条件付き)
```

### データフロー図

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

詳細情報 ───┐
            │
組織情報 ──┼──▶ ProductCreateForm
            │         │
バリアント ─┤         ▼
            │   handleSubmit
在庫キット ─┘         │
                      ├─ [メディアあり] → sdk.admin.upload.create
                      │                        │
                      │                        ▼
                      │                  uploadedMedia
                      │                        │
                      └─ normalizeProductFormValues
                                │
                                ▼
                          useCreateProduct
                                │
                                ▼
                       sdk.admin.product.create
                                │
                                ├─ [成功] → toast.success → navigate(詳細画面)
                                │
                                └─ [失敗] → toast.error
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| product-create.tsx | `packages/admin/dashboard/src/routes/products/product-create/product-create.tsx` | ソース | 商品作成画面のメインコンポーネント |
| product-create-form.tsx | `packages/admin/dashboard/src/routes/products/product-create/components/product-create-form/product-create-form.tsx` | ソース | メインフォームコンポーネント |
| product-create-details-form.tsx | `packages/admin/dashboard/src/routes/products/product-create/components/product-create-details-form/product-create-details-form.tsx` | ソース | 詳細タブフォーム |
| product-create-organize-form.tsx | `packages/admin/dashboard/src/routes/products/product-create/components/product-create-organize-form/product-create-organize-form.tsx` | ソース | 組織タブフォーム |
| product-create-variants-form.tsx | `packages/admin/dashboard/src/routes/products/product-create/components/product-create-variants-form/product-create-variants-form.tsx` | ソース | バリアントタブフォーム |
| product-create-inventory-kit-form.tsx | `packages/admin/dashboard/src/routes/products/product-create/components/product-create-inventory-kit-form/product-create-inventory-kit-form.tsx` | ソース | 在庫キットタブフォーム |
| constants.ts | `packages/admin/dashboard/src/routes/products/product-create/constants.ts` | ソース | スキーマとデフォルト値定義 |
| types.ts | `packages/admin/dashboard/src/routes/products/product-create/types.ts` | ソース | 型定義 |
| utils.ts | `packages/admin/dashboard/src/routes/products/product-create/utils.ts` | ソース | ユーティリティ関数 |
| index.ts | `packages/admin/dashboard/src/routes/products/product-create/index.ts` | ソース | エクスポート定義 |
