# 画面設計書 131-ロケーション作成画面

## 概要

本ドキュメントは、Medusa Admin Dashboardにおけるロケーション作成画面の設計仕様を定義するものである。

### 本画面の処理概要

ロケーション作成画面は、在庫を管理するための物理的な拠点（倉庫、店舗など）を新規登録するための画面である。

**業務上の目的・背景**：ECサイト運営において、在庫を複数拠点で管理する必要がある場合、各拠点（ロケーション）を登録することで、在庫の分散管理やフルフィルメント処理の最適化が可能となる。ロケーションは販売チャネルやフルフィルメントプロバイダーと紐付けることで、注文に応じた適切な出荷元の選定を実現する。

**画面へのアクセス方法**：設定画面 > ロケーション一覧画面 > 「新規作成」ボタンをクリックすることでアクセスできる。URLパスは `/settings/locations/create`。

**主要な操作・処理内容**：
1. ロケーション名の入力（必須）
2. 住所情報の入力（住所1、住所2、郵便番号、市区町村、国、都道府県、会社名、電話番号）
3. 「保存」ボタンで新規ロケーションを作成
4. 「キャンセル」ボタンで操作を中断し、前の画面に戻る

**画面遷移**：
- 遷移元：ロケーション一覧画面（`/settings/locations`）
- 遷移先：作成完了後、ロケーション詳細画面（`/settings/locations/{location_id}`）へ自動遷移

**権限による表示制御**：管理者権限を持つユーザーのみがこの画面にアクセスし、ロケーションを作成できる。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 79 | 在庫ロケーションCRUD | 主機能 | 新規ロケーションの作成 |
| 80 | ロケーション住所管理 | 補助機能 | ロケーション住所の設定 |

## 画面種別

登録画面（フルページモーダル形式）

## URL/ルーティング

- パス: `/settings/locations/create`
- コンポーネント: `LocationCreate`
- ルートファイル: `packages/admin/dashboard/src/routes/locations/location-create/location-create.tsx`

## 入出力項目

| 項目名 | 項目ID | 入出力 | 型 | 必須 | バリデーション | 説明 |
|--------|--------|--------|-----|------|---------------|------|
| ロケーション名 | name | 入力 | string | Yes | 1文字以上 | ロケーションの名称 |
| 住所1 | address.address_1 | 入力 | string | Yes | 1文字以上 | 主要な住所 |
| 住所2 | address.address_2 | 入力 | string | No | - | 補足住所 |
| 郵便番号 | address.postal_code | 入力 | string | No | - | 郵便番号 |
| 市区町村 | address.city | 入力 | string | No | - | 市区町村名 |
| 国 | address.country_code | 入力 | string | Yes | 2文字（ISO 3166-1 alpha-2） | 国コード |
| 都道府県 | address.province | 入力 | string | No | - | 都道府県名 |
| 会社名 | address.company | 入力 | string | No | - | 会社名 |
| 電話番号 | address.phone | 入力 | string | No | - | 電話番号 |

## 表示項目

| 項目名 | 説明 |
|--------|------|
| ヘッダータイトル | 「Create Location」（翻訳キー: `stockLocations.create.header`） |
| ヘッダー説明文 | 「Create and manage your stock locations.」（翻訳キー: `stockLocations.create.hint`） |

## イベント仕様

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

**トリガー**: 「Save」ボタンのクリック、または `Cmd/Ctrl + Enter` キーボードショートカット

**処理フロー**:
1. フォームバリデーションを実行
2. バリデーション成功時、`useCreateStockLocation`フックを通じてAPIを呼び出し
3. APIリクエスト: `POST /admin/stock-locations`
4. 成功時: トースト通知を表示し、作成されたロケーションの詳細画面へ遷移
5. 失敗時: エラーメッセージをトースト通知で表示

**送信データ**:
```typescript
{
  name: string,
  address: {
    address_1: string,
    address_2?: string,
    country_code: string,
    city?: string,
    postal_code?: string,
    province?: string,
    company?: string,
    phone?: string
  }
}
```

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

**トリガー**: 「Cancel」ボタンのクリック

**処理フロー**:
1. モーダルを閉じる
2. 前の画面（ロケーション一覧画面）に戻る

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 保存ボタン押下 | stock_location | INSERT | 新規ロケーションレコードの作成 |
| 保存ボタン押下 | stock_location_address | INSERT | ロケーション住所レコードの作成 |

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

#### stock_location

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id | システム自動生成（UUID） | 主キー |
| INSERT | name | フォーム入力値 | ロケーション名 |
| INSERT | created_at | システム自動設定 | 作成日時 |
| INSERT | updated_at | システム自動設定 | 更新日時 |

#### stock_location_address

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id | システム自動生成（UUID） | 主キー |
| INSERT | stock_location_id | 作成されたstock_locationのid | 外部キー |
| INSERT | address_1 | フォーム入力値 | 住所1 |
| INSERT | address_2 | フォーム入力値（任意） | 住所2 |
| INSERT | city | フォーム入力値（任意） | 市区町村 |
| INSERT | country_code | フォーム入力値 | 国コード |
| INSERT | postal_code | フォーム入力値（任意） | 郵便番号 |
| INSERT | province | フォーム入力値（任意） | 都道府県 |
| INSERT | company | フォーム入力値（任意） | 会社名 |
| INSERT | phone | フォーム入力値（任意） | 電話番号 |

## メッセージ仕様

| メッセージ種別 | メッセージキー | 表示条件 | 表示内容 |
|--------------|---------------|----------|---------|
| 成功 | locations.toast.create | ロケーション作成成功時 | 「Location created successfully」 |
| エラー | - | API呼び出し失敗時 | APIから返却されたエラーメッセージ |
| バリデーション | - | 必須項目未入力時 | 該当フィールドにエラー表示 |

## 例外処理

| 例外状況 | 処理内容 |
|---------|---------|
| ネットワークエラー | トースト通知でエラーメッセージを表示、フォーム状態は維持 |
| サーバーエラー（5xx） | トースト通知でエラーメッセージを表示 |
| バリデーションエラー（4xx） | トースト通知でエラーメッセージを表示、該当フィールドにエラー表示 |
| 認証エラー（401） | ログイン画面へリダイレクト |

## 備考

- 画面はフルページモーダル（`RouteFocusModal`）として実装されている
- フォームは`react-hook-form`と`zod`によるバリデーションを使用
- 国の選択は`CountrySelect`コンポーネントを使用し、ISO 3166-1 alpha-2形式の国コードを選択
- キーボードショートカット（Cmd/Ctrl + Enter）でフォーム送信が可能

---

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

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

### 推奨読解順序

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

フォームの入力値とAPIリクエストの型定義を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | create-location-form.tsx | `packages/admin/dashboard/src/routes/locations/location-create/components/create-location-form/create-location-form.tsx` | L15-27: `CreateLocationSchema`でフォームのバリデーションスキーマを定義。nameとaddressオブジェクトの構造を確認 |

**読解のコツ**: zodスキーマは`z.object()`でオブジェクト構造を定義し、`z.string().min(1)`で必須バリデーションを表現している。

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

画面コンポーネントの構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | location-create.tsx | `packages/admin/dashboard/src/routes/locations/location-create/location-create.tsx` | L4-10: `LocationCreate`コンポーネントが`RouteFocusModal`でラップされた`CreateLocationForm`をレンダリング |

**主要処理フロー**:
1. **L6**: `RouteFocusModal`でフルページモーダルを表示
2. **L7**: `CreateLocationForm`がフォームUIとロジックを担当

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

フォームの状態管理とAPI呼び出しの流れを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | create-location-form.tsx | `packages/admin/dashboard/src/routes/locations/location-create/components/create-location-form/create-location-form.tsx` | L29-69: フォーム初期化、API呼び出し、成功/エラーハンドリングの実装 |

**主要処理フロー**:
- **L33-48**: `useForm`でフォーム状態を初期化、デフォルト値とバリデーションリゾルバを設定
- **L50**: `useCreateStockLocation`フックでAPI呼び出し関数を取得
- **L52-69**: `handleSubmit`でフォーム送信時の処理を定義。成功時は`handleSuccess`でロケーション詳細画面へ遷移

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

バックエンドとの通信処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | stock-locations.tsx | `packages/admin/dashboard/src/hooks/api/stock-locations.tsx` | L64-82: `useCreateStockLocation`フックの実装。`sdk.admin.stockLocation.create`でAPIを呼び出し |

**主要処理フロー**:
- **L71**: `mutationFn`で`sdk.admin.stockLocation.create(payload)`を実行
- **L73-78**: 成功時にクエリキャッシュを無効化してリスト表示を更新

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

```
LocationCreate (location-create.tsx)
    │
    └─ CreateLocationForm (create-location-form.tsx)
           │
           ├─ useForm (react-hook-form)
           │      └─ zodResolver (CreateLocationSchema)
           │
           ├─ useCreateStockLocation (stock-locations.tsx)
           │      └─ sdk.admin.stockLocation.create
           │             └─ POST /admin/stock-locations
           │
           └─ handleSuccess (useRouteModal)
                  └─ navigate to /settings/locations/{id}
```

### データフロー図

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

フォーム入力 ───▶ zodバリデーション ───▶ バリデーションエラー表示
      │
      └─(valid)──▶ useCreateStockLocation ───▶ POST /admin/stock-locations
                          │
                          ├─(success)──▶ toast.success + 詳細画面遷移
                          │
                          └─(error)──▶ toast.error
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| location-create.tsx | `packages/admin/dashboard/src/routes/locations/location-create/location-create.tsx` | ソース | 画面エントリーポイント |
| create-location-form.tsx | `packages/admin/dashboard/src/routes/locations/location-create/components/create-location-form/create-location-form.tsx` | ソース | フォームコンポーネント |
| index.ts | `packages/admin/dashboard/src/routes/locations/location-create/index.ts` | ソース | エクスポート定義 |
| stock-locations.tsx | `packages/admin/dashboard/src/hooks/api/stock-locations.tsx` | ソース | API呼び出しフック |
| country-select.tsx | `packages/admin/dashboard/src/components/inputs/country-select/` | ソース | 国選択コンポーネント |
