# 画面設計書 101-WhatsAppキャンペーン画面

## 概要

WhatsAppキャンペーン機能を管理するための画面設計書です。WhatsAppチャネルを通じて顧客にマーケティングキャンペーンメッセージを配信するための一覧表示・作成・削除機能を提供します。

### 本画面の処理概要

**業務上の目的・背景**：WhatsAppを活用したマーケティングキャンペーンを効率的に管理し、顧客エンゲージメントを向上させることを目的としています。企業は事前に承認されたWhatsAppテンプレートを使用して、ラベルで分類された顧客グループに対して、スケジュール配信でメッセージを一斉送信できます。これにより、プロモーション、お知らせ、フォローアップなどのマーケティング活動を自動化できます。

**画面へのアクセス方法**：サイドバーのナビゲーションから「Campaigns」を選択し、「WhatsApp」タブをクリックしてアクセスします。URLパスは `/app/accounts/:accountId/campaigns/whatsapp` です。

**主要な操作・処理内容**：
1. WhatsAppキャンペーン一覧の表示（完了済み/スケジュール済みステータス別）
2. 新規キャンペーンの作成（テンプレート選択、オーディエンス設定、スケジュール設定）
3. 既存キャンペーンの削除
4. キャンペーン詳細情報の確認（送信元インボックス、配信日時など）

**画面遷移**：
- 遷移元：キャンペーンホーム画面、ライブチャットキャンペーン画面、SMSキャンペーン画面（タブ切り替え）
- 遷移先：キャンペーン作成ダイアログ（モーダル）、削除確認ダイアログ（モーダル）

**権限による表示制御**：管理者（administrator）権限のみアクセス可能です。また、WHATSAPP_CAMPAIGNSフィーチャーフラグが有効な場合のみ表示されます。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 68 | キャンペーン作成・管理 | 主機能 | WhatsAppキャンペーンの一覧表示、作成、削除 |
| 126 | WhatsApp | 補助機能 | WhatsApp送信チャネル設定、テンプレート選択 |

## 画面種別

一覧 / 登録（ダイアログ）

## URL/ルーティング

| パス | ルート名 |
|------|----------|
| `/app/accounts/:accountId/campaigns/whatsapp` | `campaigns_whatsapp_index` |

## 入出力項目

### 新規作成フォーム入力項目

| 項目名 | 物理名 | 型 | 必須 | バリデーション | 備考 |
|--------|--------|-----|------|---------------|------|
| タイトル | title | string | Yes | 必須、1文字以上 | キャンペーン名 |
| インボックス | inboxId | number | Yes | 必須 | WhatsAppインボックスのみ選択可 |
| テンプレート | templateId | number | Yes | 必須 | 選択したインボックスに紐づくテンプレート |
| オーディエンス | selectedAudience | array | Yes | 必須 | ラベルIDの配列 |
| 配信日時 | scheduledAt | datetime | Yes | 必須、現在日時以降 | UTC形式で送信 |

### 出力項目（一覧）

| 項目名 | 物理名 | 型 | 備考 |
|--------|--------|-----|------|
| キャンペーンID | id | number | 内部識別子 |
| タイトル | title | string | キャンペーン名 |
| ステータス | status | string | Completed / Scheduled |
| 送信元インボックス | inbox.name | string | インボックス名 |
| 配信日時 | scheduled_at | datetime | スケジュールされた日時 |

## 表示項目

### キャンペーン一覧カード

| 項目名 | 表示形式 | 備考 |
|--------|----------|------|
| キャンペーンタイトル | テキスト | 太字表示 |
| ステータスバッジ | Completed/Scheduled | 色分け表示 |
| 送信元情報 | "Sent from {インボックス名} on {日時}" | フォーマット済み |
| 削除ボタン | アイコンボタン | ドロップダウンメニュー内 |

### 空状態表示

| 条件 | タイトル | サブタイトル |
|------|----------|--------------|
| キャンペーンが0件 | "No WhatsApp campaigns are available" | "Launch a WhatsApp campaign to reach your customers directly..." |

## イベント仕様

### 1-キャンペーン作成ボタン押下

1. 「Create campaign」ボタンをクリック
2. `toggleWhatsAppCampaignDialog()` が呼び出される
3. `WhatsAppCampaignDialog` コンポーネントがモーダル表示される
4. フォーム入力後、Submit時に `campaigns/create` アクションが dispatch される
5. API成功時：成功メッセージ表示、ダイアログクローズ、一覧自動更新
6. API失敗時：エラーメッセージ表示

### 2-キャンペーン削除

1. キャンペーンカードのメニューから「Delete」を選択
2. `handleDelete(campaign)` が呼び出される
3. `ConfirmDeleteCampaignDialog` が表示される
4. 確認後、`campaigns/delete` アクションが dispatch される
5. API成功時：成功メッセージ表示、一覧から該当キャンペーン削除
6. API失敗時：エラーメッセージ表示

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| キャンペーン作成 | campaigns | INSERT | 新規キャンペーンレコード作成 |
| キャンペーン削除 | campaigns | DELETE | 指定キャンペーンの削除 |
| 一覧取得 | campaigns | SELECT | アカウントに紐づくキャンペーン取得 |

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

#### campaigns

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | title | フォーム入力値 | キャンペーン名 |
| INSERT | message | テンプレートのレンダリング結果 | 送信メッセージ本文 |
| INSERT | template_params | テンプレートパラメータJSON | 名前、名前空間、カテゴリ、言語、処理済みパラメータ |
| INSERT | inbox_id | 選択したインボックスID | WhatsAppインボックス |
| INSERT | scheduled_at | UTC変換後の日時 | 配信予定日時 |
| INSERT | audience | ラベルIDと種別の配列 | `[{id: x, type: 'Label'}]` |
| INSERT | campaign_type | 'one_off' | 固定値 |
| SELECT | - | `account_id = current_account.id AND campaign_type = 'one_off' AND inbox.channel_type = 'Channel::Whatsapp'` | 一覧取得条件 |
| DELETE | - | `id = campaign_id` | 指定ID削除 |

## メッセージ仕様

| 種別 | メッセージキー | メッセージ内容 |
|------|---------------|---------------|
| 成功 | CAMPAIGN.WHATSAPP.CREATE.FORM.API.SUCCESS_MESSAGE | "WhatsApp campaign created successfully" |
| エラー | CAMPAIGN.WHATSAPP.CREATE.FORM.API.ERROR_MESSAGE | "There was an error. Please try again." |
| 成功 | CAMPAIGN.CONFIRM_DELETE.API.SUCCESS_MESSAGE | "Campaign deleted successfully" |
| エラー | CAMPAIGN.CONFIRM_DELETE.API.ERROR_MESSAGE | "There was an error. Please try again." |

## 例外処理

| 例外条件 | 処理内容 | 表示 |
|----------|----------|------|
| データ取得中 | Spinnerコンポーネント表示 | ローディングインジケータ |
| キャンペーン0件 | EmptyState表示 | 空状態メッセージとアクションボタン |
| API通信エラー | アラート表示 | エラーメッセージ |
| バリデーションエラー | フォームフィールドにエラー表示 | 各項目下にエラーテキスト |
| 権限不足 | 画面アクセス不可 | ルートガードによりリダイレクト |
| フィーチャーフラグ無効 | 画面アクセス不可 | フィーチャーフラグチェック |

## 備考

- WhatsAppキャンペーンは「One-off」タイプのキャンペーンとして分類される
- テンプレートはMeta Business APIで事前承認されたものを使用
- テンプレート内の変数は動的に入力フィールドが生成される
- 配信日時は現地時間で入力し、UTC形式に変換して保存
- オーディエンスはラベルベースでセグメント化された連絡先グループ

---

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

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

### 推奨読解順序

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

まず、キャンペーンデータの構造とストアの状態管理を理解することが重要です。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | campaigns.js | `app/javascript/dashboard/store/modules/campaigns.js` | キャンペーンストアの状態定義、ゲッター（getWhatsAppCampaigns）、アクション（create/delete）を確認 |
| 1-2 | campaign.js | `shared/constants/campaign.js` | CAMPAIGN_TYPES定数（ONE_OFF、ONGOING）の定義を確認 |

**読解のコツ**: Vuexストアの `getWhatsAppCampaigns` ゲッターは、`getCampaigns` を使用してWHATSAPPチャネルタイプでフィルタリングしています（43-46行目）。

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

処理の起点となるVueコンポーネントとルーティング設定を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | campaigns.routes.js | `app/javascript/dashboard/routes/dashboard/campaigns/campaigns.routes.js` | ルーティング定義、メタ情報（権限、フィーチャーフラグ）を確認 |
| 2-2 | WhatsAppCampaignsPage.vue | `app/javascript/dashboard/routes/dashboard/campaigns/pages/WhatsAppCampaignsPage.vue` | メインコンポーネントの構造、computed、メソッドを確認 |

**主要処理フロー**:
1. **17行目**: `selectedCampaign` のref定義
2. **18行目**: `useToggle` でダイアログ表示状態管理
3. **25-27行目**: `WhatsAppCampaigns` computedでストアからデータ取得
4. **33-36行目**: `handleDelete` で削除ダイアログ表示

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

キャンペーン作成フォームのバリデーションと送信処理を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | WhatsAppCampaignDialog.vue | `app/javascript/dashboard/components-next/Campaigns/Pages/CampaignPage/WhatsAppCampaign/WhatsAppCampaignDialog.vue` | ダイアログラッパー、submitハンドラを確認 |
| 3-2 | WhatsAppCampaignForm.vue | `app/javascript/dashboard/components-next/Campaigns/Pages/CampaignPage/WhatsAppCampaign/WhatsAppCampaignForm.vue` | フォーム定義、バリデーションルール、データ整形を確認 |

**主要処理フロー**:
- **38-44行目**: Vuelidateバリデーションルール定義
- **125-152行目**: `prepareCampaignDetails` でAPI送信用データ整形
- **155-162行目**: `handleSubmit` でバリデーション後に送信

#### Step 4: API通信層を理解する

バックエンドとの通信処理を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | campaigns.js (API) | `app/javascript/dashboard/api/campaigns.js` | APIクライアントクラス、エンドポイント定義を確認 |

**主要処理フロー**:
- **3-7行目**: `CampaignsAPI` クラスがApiClientを継承、`campaigns` エンドポイント使用

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

```
WhatsAppCampaignsPage.vue
    |
    +-- CampaignLayout.vue (レイアウト)
    |       |
    |       +-- ヘッダー表示、ボタン配置
    |
    +-- CampaignList.vue (一覧表示)
    |       |
    |       +-- キャンペーンカード描画
    |       +-- 削除イベント発火
    |
    +-- WhatsAppCampaignDialog.vue (作成ダイアログ)
    |       |
    |       +-- WhatsAppCampaignForm.vue
    |               |
    |               +-- Vuelidate (バリデーション)
    |               +-- WhatsAppTemplateParser.vue (テンプレート処理)
    |
    +-- ConfirmDeleteCampaignDialog.vue (削除確認)
    |
    +-- Vuex Store (campaigns)
            |
            +-- CampaignsAPI
                    |
                    +-- POST /api/v1/accounts/:id/campaigns
                    +-- DELETE /api/v1/accounts/:id/campaigns/:id
```

### データフロー図

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

フォーム入力 ──────────▶ WhatsAppCampaignForm
                              │
                              ▼
                        Vuelidate検証
                              │
                              ▼
                        prepareCampaignDetails()
                              │
                              ▼
                        campaigns/create (Vuex)
                              │
                              ▼
                        CampaignsAPI.create()
                              │
                              ▼
                        POST /api/v1/.../campaigns
                              │
                              ▼
                        Mutation: ADD_CAMPAIGN
                              │
                              ▼
                        一覧自動更新 ──────────▶ キャンペーン一覧表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| WhatsAppCampaignsPage.vue | `app/javascript/dashboard/routes/dashboard/campaigns/pages/WhatsAppCampaignsPage.vue` | ソース | メイン画面コンポーネント |
| campaigns.routes.js | `app/javascript/dashboard/routes/dashboard/campaigns/campaigns.routes.js` | 設定 | ルーティング定義 |
| campaigns.js (store) | `app/javascript/dashboard/store/modules/campaigns.js` | ソース | Vuexストアモジュール |
| campaigns.js (api) | `app/javascript/dashboard/api/campaigns.js` | ソース | APIクライアント |
| WhatsAppCampaignDialog.vue | `app/javascript/dashboard/components-next/Campaigns/Pages/CampaignPage/WhatsAppCampaign/WhatsAppCampaignDialog.vue` | ソース | 作成ダイアログ |
| WhatsAppCampaignForm.vue | `app/javascript/dashboard/components-next/Campaigns/Pages/CampaignPage/WhatsAppCampaign/WhatsAppCampaignForm.vue` | ソース | 作成フォーム |
| CampaignLayout.vue | `app/javascript/dashboard/components-next/Campaigns/CampaignLayout.vue` | ソース | レイアウトコンポーネント |
| CampaignList.vue | `app/javascript/dashboard/components-next/Campaigns/Pages/CampaignPage/CampaignList.vue` | ソース | 一覧表示コンポーネント |
| ConfirmDeleteCampaignDialog.vue | `app/javascript/dashboard/components-next/Campaigns/Pages/CampaignPage/ConfirmDeleteCampaignDialog.vue` | ソース | 削除確認ダイアログ |
| WhatsAppCampaignEmptyState.vue | `app/javascript/dashboard/components-next/Campaigns/EmptyState/WhatsAppCampaignEmptyState.vue` | ソース | 空状態表示 |
| campaign.json | `app/javascript/dashboard/i18n/locale/en/campaign.json` | 設定 | 多言語リソース |
