# 画面設計書 13-キャンペーン新規作成フォーム

## 概要

Fat Free CRM における新規キャンペーン（マーケティングキャンペーン）を作成するためのフォーム画面設計書である。

### 本画面の処理概要

本画面は、マーケティングキャンペーンを新規作成するための入力フォームであり、Ajax通信によるモーダル形式で表示される。

**業務上の目的・背景**：
マーケティング担当者が新しいキャンペーン（メール配信、広告、イベントなど）を計画・登録する際に使用する。キャンペーンの基本情報（名前、期間、ステータス）に加えて、目標値（リード獲得数、コンバージョン率、収益目標）を設定することで、キャンペーンの成果を測定するための基準を定義できる。また、アクセス権限を設定することで、チーム内での情報共有範囲を制御する。

**画面へのアクセス方法**：
1. キャンペーン一覧画面で「Create Campaign」ボタンをクリック
2. 他の画面（ダッシュボードなど）からの新規作成リンク
3. Ajax通信でモーダルとして表示される

**主要な操作・処理内容**：
1. キャンペーン基本情報の入力（名前、開始日、終了日、ステータス）
2. 背景情報の入力（オプション）
3. タグの付与
4. キャンペーン目標の設定（リード数、コンバージョン率、収益、予算）
5. 目標テキストの入力
6. カスタムフィールドの入力
7. コメントの追加（オプション）
8. アクセス権限の設定（Public/Private/Shared）
9. 保存またはキャンセル

**画面遷移**：
- 遷移元: キャンペーン一覧画面
- 遷移先（保存成功時）: キャンペーン一覧画面（更新）
- 遷移先（キャンセル時）: キャンペーン一覧画面（変更なし）

**権限による表示制御**：
- 認証済みユーザーのみアクセス可能
- 新規作成は全ての認証ユーザーに許可
- アクセス権限設定により、作成後の閲覧範囲を制御可能

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 12 | キャンペーン作成 | 主機能 | 新規キャンペーン情報入力、作成実行 |
| 83 | タグ付け | 補助機能 | キャンペーンへのタグ付け |
| 84 | アクセス権限管理 | 補助機能 | キャンペーンのアクセス権限設定 |

## 画面種別

登録

## URL/ルーティング

| HTTPメソッド | URL | アクション | 説明 |
|-------------|-----|----------|------|
| GET | /campaigns/new | new | 新規作成フォーム表示 |
| POST | /campaigns | create | 新規作成実行 |

## 入出力項目

### 基本情報セクション

| 項目名 | 入力形式 | 必須 | 最大長 | 説明 |
|--------|---------|------|--------|------|
| キャンペーン名 | テキスト | ○ | 64文字 | キャンペーンの名称 |
| 開始日 | 日付ピッカー | - | - | キャンペーン開始日 |
| 終了日 | 日付ピッカー | - | - | キャンペーン終了日 |
| ステータス | セレクトボックス | - | - | planned/started/on_hold/completed/called_off |
| 背景情報 | テキストエリア | - | 255文字 | キャンペーンの背景説明（設定有効時のみ表示） |
| タグ | テキスト | - | - | カンマ区切りでタグを入力 |

### 目標セクション（Objectives）

| 項目名 | 入力形式 | 必須 | 説明 |
|--------|---------|------|------|
| 目標リード数 | 数値 | - | 獲得目標リード数 |
| 目標コンバージョン率 | 数値 | - | 目標コンバージョン率（%） |
| 目標収益 | 数値 | - | 目標収益額 |
| 予算 | 数値 | - | キャンペーン予算 |
| 目標（テキスト） | テキストエリア | - | 目標の詳細説明 |

### カスタムフィールドセクション

| 項目名 | 入力形式 | 必須 | 説明 |
|--------|---------|------|------|
| カスタムフィールド | 動的 | 設定依存 | 管理者が定義したカスタムフィールド |

### コメントセクション

| 項目名 | 入力形式 | 必須 | 説明 |
|--------|---------|------|------|
| コメント | テキストエリア | - | 作成時の初期コメント |

### 権限セクション

| 項目名 | 入力形式 | 必須 | 説明 |
|--------|---------|------|------|
| アクセス権限 | ラジオボタン | ○ | Public/Private/Shared |
| 共有ユーザー | マルチセレクト | 条件付 | Shared選択時に表示 |
| 共有グループ | マルチセレクト | 条件付 | Shared選択時に表示 |

## 表示項目

なし（入力フォームのみ）

## イベント仕様

### 01-フォーム表示

「Create Campaign」リンクをクリックすると、Ajax通信で新規作成フォームが読み込まれ、画面上部にモーダルとして展開される。

### 02-ステータス選択

ステータスセレクトボックスでステータスを選択する。デフォルトは「planned」。select2によるスタイリングが適用される。

### 03-日付選択

開始日・終了日フィールドをクリックすると、日付ピッカーが表示される。autocomplete:offにより、ブラウザの自動補完は無効化されている。

### 04-目標セクション展開

「Objectives」セクション見出しをクリックすると、折りたたまれた目標入力フォームが展開/折りたたみされる。

### 05-タグ入力

タグ入力フィールドにカンマ区切りでタグを入力。既存タグの候補が表示される場合がある。

### 06-アクセス権限選択

- Public: 全ユーザーがアクセス可能
- Private: 作成者のみアクセス可能
- Shared: 選択したユーザー/グループがアクセス可能（選択UIが表示される）

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

「Create Campaign」ボタンをクリックすると、Ajax通信でPOSTリクエストが送信される。成功時は一覧画面が更新され、フォームが閉じる。失敗時はエラーメッセージが表示される。

### 08-キャンセル

「Cancel」リンクをクリックすると、フォームが閉じ、入力内容は破棄される。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 保存 | campaigns | INSERT | 新規キャンペーン作成 |
| 保存（コメントあり） | comments | INSERT | 初期コメント追加 |
| 保存（Shared） | permissions | INSERT | 共有権限レコード作成 |
| 保存 | taggings | INSERT | タグ紐付け |
| 保存 | versions | INSERT | 作成履歴記録 |

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

#### campaigns

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | user_id | current_user.id | 作成者 |
| INSERT | assigned_to | nil（初期値） | 担当者（未設定） |
| INSERT | name | 入力値 | 必須 |
| INSERT | access | 入力値（デフォルト: Setting.default_access） | Public/Private/Shared |
| INSERT | status | 入力値（デフォルト: planned） | |
| INSERT | budget | 入力値 | |
| INSERT | target_leads | 入力値 | |
| INSERT | target_conversion | 入力値 | |
| INSERT | target_revenue | 入力値 | |
| INSERT | starts_on | 入力値 | |
| INSERT | ends_on | 入力値 | |
| INSERT | objectives | 入力値 | |
| INSERT | background_info | 入力値 | |
| INSERT | created_at | 現在日時 | |
| INSERT | updated_at | 現在日時 | |

#### comments

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | commentable_type | 'Campaign' | |
| INSERT | commentable_id | 作成されたキャンペーンID | |
| INSERT | comment | 入力値 | |
| INSERT | user_id | current_user.id | |
| INSERT | created_at | 現在日時 | |

#### permissions

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | user_id | 選択されたユーザーID | Shared時のみ |
| INSERT | group_id | 選択されたグループID | Shared時のみ |
| INSERT | asset_type | 'Campaign' | |
| INSERT | asset_id | 作成されたキャンペーンID | |

## メッセージ仕様

| メッセージ種別 | メッセージコード | 表示内容 | 表示条件 |
|--------------|----------------|---------|---------|
| エラー | missing_campaign_name | "Campaign name is required." | 名前未入力時 |
| エラー | dates_not_in_sequence | "End date must be after start date." | 終了日が開始日より前の場合 |
| エラー | share_campaign | "Please select users and/or groups to share with." | Shared選択時に共有先未選択 |
| エラー | uniqueness | "Campaign name has already been taken." | 同名キャンペーンが存在する場合 |

## 例外処理

| 例外ケース | 処理内容 | 表示 |
|-----------|---------|------|
| バリデーションエラー | フォーム再表示 | エラーメッセージをフィールド上部に表示 |
| 認証エラー | ログイン画面にリダイレクト | Deviseのデフォルトメッセージ |
| サーバーエラー | エラー画面表示 | 500エラー画面 |

## 備考

- simple_form_for を使用したフォーム生成
- remote: true により Ajax 送信
- one_submit_only によりダブルサブミット防止
- Setting.background_info に :campaign が含まれる場合のみ背景情報フィールドが表示される
- フックポイント（entity_form）によりプラグインからの拡張が可能

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | campaign.rb | `app/models/entities/campaign.rb` | バリデーション定義（64-68行目）を確認 |
| 1-2 | campaign.rb | `app/models/entities/campaign.rb` | start_and_end_dates バリデータ（105-107行目） |

**読解のコツ**: `validates_presence_of :name` で必須チェック、`validates_uniqueness_of :name, scope: [:user_id, :deleted_at]` で同一ユーザー内の重複チェックを行っている。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | campaigns_controller.rb | `app/controllers/entities/campaigns_controller.rb` | newアクション（69-82行目） |
| 2-2 | campaigns_controller.rb | `app/controllers/entities/campaigns_controller.rb` | createアクション（94-104行目） |

**主要処理フロー**:
1. **70行目**: デフォルト属性の設定（user, access, assigned_to）
2. **72-79行目**: 関連エンティティからの呼び出し処理
3. **96行目**: コメント本文の取得
4. **98-101行目**: 保存成功時の処理（コメント追加、一覧再取得、サイドバー更新）

#### Step 3: ビューを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | _new.html.haml | `app/views/campaigns/_new.html.haml` | 新規作成フォームの構成 |
| 3-2 | _top_section.html.haml | `app/views/campaigns/_top_section.html.haml` | 基本情報入力セクション |
| 3-3 | _objectives.html.haml | `app/views/campaigns/_objectives.html.haml` | 目標入力セクション |
| 3-4 | _permissions.html.haml | `app/views/entities/_permissions.html.haml` | 権限設定セクション |

**主要処理フロー**:
- **1行目（_new.html.haml）**: simple_form_for でフォーム開始、remote: true
- **7-12行目**: 各セクションのパーシャルレンダリング
- **15-18行目**: ボタンバー（Create Campaign / Cancel）

#### Step 4: フォームセクションを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | _top_section.html.haml | `app/views/campaigns/_top_section.html.haml` | 名前、日付、ステータス、タグの入力 |

**主要処理フロー**:
- **6-7行目**: キャンペーン名入力（autofocus, required）
- **11-15行目**: 日付入力（date class による日付ピッカー）
- **18-19行目**: ステータスセレクト（Setting.unroll(:campaign_status)）
- **21-25行目**: 背景情報（設定により表示/非表示）
- **27行目**: タグ入力パーシャル

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

```
[HTTP Request: GET /campaigns/new]
    │
    ├─ routes.rb (64行目)
    │      └─ CampaignsController#new
    │
    ├─ CampaignsController#new (69-82行目)
    │      ├─ @campaign.attributes = { user, access, assigned_to }
    │      └─ respond_with(@campaign)
    │
    └─ campaigns/_new.html.haml
           ├─ simple_form_for(@campaign, remote: true)
           ├─ campaigns/_top_section.html.haml
           │      ├─ 名前入力フィールド
           │      ├─ 日付入力フィールド（date class）
           │      ├─ ステータスセレクト
           │      └─ shared/_tags.html.haml
           ├─ fields/_edit_custom_field_group.html.haml
           ├─ shared/_add_comment.html.haml
           ├─ campaigns/_objectives.html.haml
           │      ├─ target_leads
           │      ├─ target_conversion
           │      ├─ target_revenue
           │      └─ budget
           ├─ fields/_groups.html.haml
           ├─ entities/_permissions.html.haml
           │      ├─ Public/Private/Shared radio
           │      └─ User/Group select (Shared時)
           └─ hook(:entity_form)

[HTTP Request: POST /campaigns]
    │
    └─ CampaignsController#create (94-104行目)
           ├─ @campaign.save
           ├─ @campaign.add_comment_by_user
           ├─ get_campaigns
           └─ get_data_for_sidebar
```

### データフロー図

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

フォーム入力 ───────▶ params[:campaign]
                           │
                           ▼
                    CampaignsController#create
                           │
                    ┌──────┴──────┐
                    ▼             ▼
              バリデーション    失敗
                    │             │
               成功 │             ▼
                    │        エラーメッセージ
                    ▼
              campaigns テーブル INSERT
                    │
              ┌─────┼─────┐
              ▼     ▼     ▼
          comments permissions taggings
           INSERT   INSERT     INSERT
                    │
                    ▼
              Ajax レスポンス ───▶ 一覧画面更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| campaign.rb | `app/models/entities/campaign.rb` | モデル | キャンペーンのバリデーション定義 |
| campaigns_controller.rb | `app/controllers/entities/campaigns_controller.rb` | コントローラー | new/createアクション |
| _new.html.haml | `app/views/campaigns/_new.html.haml` | ビュー | 新規作成フォームメインテンプレート |
| _top_section.html.haml | `app/views/campaigns/_top_section.html.haml` | ビュー | 基本情報入力セクション |
| _objectives.html.haml | `app/views/campaigns/_objectives.html.haml` | ビュー | 目標入力セクション |
| _permissions.html.haml | `app/views/entities/_permissions.html.haml` | ビュー | 権限設定セクション |
| _add_comment.html.haml | `app/views/shared/_add_comment.html.haml` | ビュー | コメント追加セクション |
| _tags.html.haml | `app/views/shared/_tags.html.haml` | ビュー | タグ入力セクション |
| routes.rb | `config/routes.rb` | 設定 | URLルーティング定義 |
