# 画面設計書 65-キャンペーン作成画面

## 概要

本ドキュメントは、Medusa Admin Dashboard のキャンペーン作成画面について、画面仕様・機能・データ処理を定義した画面設計書です。

### 本画面の処理概要

この画面では、新規キャンペーンを作成することができます。キャンペーンの基本情報（名前、識別子、説明）、期間設定（開始日・終了日）、予算設定（タイプ、上限、通貨）を入力し、キャンペーンを登録します。

**業務上の目的・背景**：キャンペーンは複数のプロモーションをグループ化し、マーケティング施策を一元管理するための機能です。予算管理機能により、支出額や使用回数を制限でき、マーケティング費用のコントロールが可能になります。期間設定により、期間限定のセールやイベントに合わせたプロモーション展開ができます。

**画面へのアクセス方法**：キャンペーン一覧画面から「作成」ボタンをクリックすることで、フルページのモーダル形式でこの画面が表示されます。URL: `/campaigns/create`

**主要な操作・処理内容**：
1. キャンペーン名を入力（必須）
2. キャンペーン識別子を入力（必須）
3. 説明を入力（任意）
4. 開始日・終了日を設定（任意）
5. 予算タイプを選択（使用回数/支出額）
6. 予算タイプが支出額の場合、通貨を選択
7. 予算上限を入力（任意）
8. 予算属性を設定（使用回数タイプの場合、顧客IDやメールで制限可能）

**画面遷移**：
- 遷移元：キャンペーン一覧画面（`/campaigns`）
- 遷移先：作成成功時はキャンペーン詳細画面（`/campaigns/:id`）に遷移、キャンセル時はキャンペーン一覧画面に戻る

**権限による表示制御**：認証済みの管理者ユーザーのみがアクセス可能です。キャンペーン管理権限を持つユーザーが操作できます。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 38 | キャンペーン管理 | 主機能 | 新規キャンペーンの作成 |
| 39 | キャンペーン予算管理 | 補助機能 | 予算の設定 |

## 画面種別

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

## URL/ルーティング

`/campaigns/create`

## 入出力項目

| 項目名 | 項目ID | 型 | 必須 | 入力/出力 | 説明 |
|--------|--------|-----|------|-----------|------|
| キャンペーン名 | name | string | ○ | 入力 | 1文字以上 |
| 識別子 | campaign_identifier | string | ○ | 入力 | 1文字以上 |
| 説明 | description | string | - | 入力 | キャンペーンの説明 |
| 開始日 | starts_at | date | - | 入力 | キャンペーン開始日時 |
| 終了日 | ends_at | date | - | 入力 | キャンペーン終了日時 |
| 予算タイプ | budget.type | enum | ○ | 入力 | usage/spend |
| 予算上限 | budget.limit | number | - | 入力 | 0以上 |
| 通貨 | budget.currency_code | string | △ | 入力 | 予算タイプがspendの場合必須 |
| 予算属性 | budget.attribute | string | - | 入力 | customer_id/customer_email |

## 表示項目

| 項目名 | 説明 |
|--------|------|
| 画面タイトル | 「キャンペーンを作成」 |
| 基本情報セクション | 名前、識別子、説明の入力フィールド |
| 期間設定セクション | 開始日・終了日の入力フィールド |
| 予算設定セクション | 予算タイプ、上限、通貨、属性の入力フィールド |
| キャンセルボタン | モーダルを閉じる |
| 作成ボタン | キャンペーンを作成 |

## イベント仕様

### 1-作成ボタン押下

**処理フロー**：
1. フォームバリデーションを実行
2. 予算属性が設定されている場合、予算タイプを「use_by_attribute」に変換
3. `useCreateCampaign` フックを使用してAPIを呼び出し
4. 成功時：トースト通知を表示し、キャンペーン詳細画面へ遷移
5. 失敗時：エラーメッセージをトーストで表示

**API呼び出し**：
- エンドポイント: `POST /admin/campaigns`
- リクエストボディ:
```json
{
  "name": string,
  "description": string,
  "campaign_identifier": string,
  "starts_at": date | null,
  "ends_at": date | null,
  "budget": {
    "type": "usage" | "spend" | "use_by_attribute",
    "attribute": string | null,
    "limit": number | null,
    "currency_code": string | null
  }
}
```

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

**処理フロー**：
1. フォームの入力内容を破棄
2. モーダルを閉じてキャンペーン一覧画面に戻る

### 3-予算タイプ変更

**処理フロー**：
1. 予算上限をリセット
2. 支出額タイプの場合：通貨選択を有効化、予算属性を無効化
3. 使用回数タイプの場合：通貨選択を無効化、予算属性を有効化

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 作成ボタン押下 | campaign | INSERT | キャンペーンの新規作成 |
| 作成ボタン押下 | campaign_budget | INSERT | キャンペーン予算の作成 |

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

#### campaign

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | name | フォームの name | |
| INSERT | description | フォームの description | |
| INSERT | campaign_identifier | フォームの campaign_identifier | |
| INSERT | starts_at | フォームの starts_at | null許可 |
| INSERT | ends_at | フォームの ends_at | null許可 |

#### campaign_budget

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | type | usage/spend/use_by_attribute | |
| INSERT | limit | フォームの budget.limit | null許可 |
| INSERT | currency_code | フォームの budget.currency_code | spendタイプの場合 |
| INSERT | attribute | フォームの budget.attribute | use_by_attributeタイプの場合 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|----------|
| MSG-001 | 成功 | キャンペーン「{name}」を作成しました | 作成成功時 |
| MSG-002 | エラー | 名前は必須です | 名前が空の場合 |
| MSG-003 | エラー | 識別子は必須です | 識別子が空の場合 |
| MSG-004 | エラー | {エラーメッセージ} | API通信エラー時 |

## 例外処理

| 例外 | 処理内容 |
|------|---------|
| API通信エラー | エラーメッセージをtoastで表示 |
| バリデーションエラー | 各フィールドにエラーメッセージを表示 |

## 備考

- 予算タイプが「usage」の場合、予算属性を設定すると自動的に「use_by_attribute」タイプに変換される
- 予算属性はcustomer_id（顧客ID）またはcustomer_email（顧客メール）から選択可能
- 支出額タイプの場合、ストアでサポートされている通貨のみ選択可能
- 開始日・終了日を設定しない場合、キャンペーンは常に有効となる

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | create-campaign-form.tsx | `packages/admin/dashboard/src/routes/campaigns/campaign-create/components/create-campaign-form/create-campaign-form.tsx` | CreateCampaignSchema（17-29行目）でフォームの構造を確認 |
| 1-2 | constants.ts | `packages/admin/dashboard/src/routes/campaigns/common/constants.ts` | DEFAULT_CAMPAIGN_VALUESでデフォルト値を確認 |

**読解のコツ**: budgetオブジェクト内のtype、limit、currency_code、attributeの関係性を理解することが重要です。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | campaign-create.tsx | `packages/admin/dashboard/src/routes/campaigns/campaign-create/campaign-create.tsx` | RouteFocusModalレイアウトとCreateCampaignFormの配置 |

**主要処理フロー**:
1. **4-9行目**: RouteFocusModalでフルページモーダルをレンダリング
2. **7行目**: CreateCampaignFormコンポーネントを表示

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | create-campaign-form.tsx | `packages/admin/dashboard/src/routes/campaigns/campaign-create/components/create-campaign-form/create-campaign-form.tsx` | フォームロジックと送信処理 |
| 3-2 | create-campaign-form-fields.tsx | `packages/admin/dashboard/src/routes/campaigns/common/components/create-campaign-form-fields/create-campaign-form-fields.tsx` | フォームフィールドの実装 |

**主要処理フロー**:
- **34行目**: useCreateCampaignでミューテーション準備
- **36-39行目**: useFormでフォーム初期化
- **41-74行目**: handleSubmitで送信処理
- **42-44行目**: 予算属性が設定されている場合のタイプ変換ロジック

#### Step 4: フォームフィールドの実装

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | create-campaign-form-fields.tsx | `packages/admin/dashboard/src/routes/campaigns/common/components/create-campaign-form-fields/create-campaign-form-fields.tsx` | 各フィールドの実装と条件分岐 |

**主要処理フロー**:
- **28-33行目**: useWatchで予算タイプを監視
- **47-55行目**: useEffectで予算タイプ変更時のリセット処理
- **194-237行目**: 予算タイプ選択（usage/spend）
- **239-292行目**: 通貨選択（支出額タイプの場合）
- **295-347行目**: 予算上限入力
- **349-398行目**: 予算属性選択（使用回数タイプの場合）

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

```
CampaignCreate (campaign-create.tsx)
    │
    └─ CreateCampaignForm (create-campaign-form.tsx)
           │
           ├─ useForm() - フォーム状態管理
           │
           ├─ useCreateCampaign() - 作成ミューテーション
           │      └─ sdk.admin.campaign.create()
           │             └─ POST /admin/campaigns
           │                    └─ createCampaignsWorkflow
           │
           └─ CreateCampaignFormFields (create-campaign-form-fields.tsx)
                  │
                  ├─ useStore() - ストア情報取得（通貨一覧用）
                  │
                  ├─ useWatch() - フォーム値監視
                  │
                  └─ Form.Field components - 各フィールド
```

### データフロー図

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

フォーム入力 ────────▶ useForm ──────▶ フォーム状態
                                              ↓
予算タイプ選択 ──────▶ useWatch ────▶ タイプ監視
                                              ↓
                  useEffect ────────▶ リセット処理
                                              ↓
作成ボタン ──────────▶ handleSubmit ───▶ バリデーション
                                              ↓
                  タイプ変換 ────────▶ use_by_attribute判定
                                              ↓
                  useCreateCampaign ──▶ API作成
                                              ↓
                  toast.success() ──▶ 成功通知
                                              ↓
                  handleSuccess() ──▶ 詳細画面遷移
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| campaign-create.tsx | `packages/admin/dashboard/src/routes/campaigns/campaign-create/campaign-create.tsx` | ソース | エントリーポイント |
| create-campaign-form.tsx | `packages/admin/dashboard/src/routes/campaigns/campaign-create/components/create-campaign-form/create-campaign-form.tsx` | ソース | フォームコンポーネント |
| create-campaign-form-fields.tsx | `packages/admin/dashboard/src/routes/campaigns/common/components/create-campaign-form-fields/create-campaign-form-fields.tsx` | ソース | フォームフィールド |
| constants.ts | `packages/admin/dashboard/src/routes/campaigns/common/constants.ts` | ソース | デフォルト値定義 |
| campaigns.tsx | `packages/admin/dashboard/src/hooks/api/campaigns.tsx` | ソース | APIフック |
| route.ts | `packages/medusa/src/api/admin/campaigns/route.ts` | ソース | APIエンドポイント |
