# 機能設計書 22-リード作成

## 概要

本ドキュメントは、Fat Free CRMシステムにおけるリード作成機能の設計を定義する。この機能は、新規の見込み顧客（リード）情報を登録し、キャンペーンとの紐付けやコメントの追加を行う。

### 本機能の処理概要

リード作成機能は、営業活動の起点となる見込み顧客情報をシステムに登録するための機能である。

**業務上の目的・背景**：マーケティング活動や問い合わせから得られた見込み顧客情報を一元管理し、営業チームが効率的にフォローアップできるようにするために必要な機能である。リードの属性情報、連絡先情報、キャンペーンとの関連付けを記録することで、顧客獲得プロセスの可視化と追跡を実現する。

**機能の利用シーン**：展示会やセミナーで取得した名刺情報を登録する場合、Webフォームからの問い合わせを手動で登録する場合、電話問い合わせの内容を記録する場合に利用される。また、キャンペーン詳細画面から関連リードを直接作成する場合にも使用される。

**主要な処理内容**：
1. リード新規作成フォームの表示（newアクション）
2. 入力データのバリデーション
3. リードデータのデータベースへの保存
4. キャンペーンとの関連付け（オプション）
5. 初期コメントの追加（オプション）
6. アクセス権限の設定

**関連システム・外部連携**：キャンペーン機能との連携により、リードの獲得元キャンペーンを追跡可能である。

**権限による制御**：CanCanによる認可制御が行われ、認証済みユーザーのみがリードを作成可能である。作成時にアクセス権限（Public/Private/Shared/Campaign）を設定できる。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 17 | リード新規作成フォーム | 主画面 | 新規リード情報入力、キャンペーン紐付け、作成実行 |
| 17 | リード新規作成フォーム | 補助機能 | タグ付け（機能No.83） |
| 17 | リード新規作成フォーム | 補助機能 | アクセス権限管理（機能No.84） |

## 機能種別

CRUD操作（CREATE） / データ登録

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| lead[first_name] | String | 条件付き | 名 | Setting.require_first_namesがtrueの場合必須、最大64文字 |
| lead[last_name] | String | 条件付き | 姓 | Setting.require_last_namesがtrueの場合必須、最大64文字 |
| lead[company] | String | No | 会社名 | 最大64文字 |
| lead[title] | String | No | 役職 | 最大64文字 |
| lead[source] | String | No | リード獲得元 | 設定値リストから選択 |
| lead[status] | String | No | ステータス | 設定値リストから選択 |
| lead[email] | String | No | メールアドレス | 最大64文字 |
| lead[alt_email] | String | No | 代替メールアドレス | 最大64文字 |
| lead[phone] | String | No | 電話番号 | 最大32文字 |
| lead[mobile] | String | No | 携帯電話番号 | 最大32文字 |
| lead[rating] | Integer | No | 評価（星） | 0-5の整数 |
| lead[referred_by] | String | No | 紹介元 | 最大64文字 |
| lead[do_not_call] | Boolean | No | 電話禁止フラグ | true/false |
| lead[access] | String | No | アクセス権限 | Public/Private/Shared/Campaign |
| lead[assigned_to] | Integer | No | 担当者ID | 存在するユーザーID |
| campaign | Integer | No | キャンペーンID | 存在するキャンペーンID |
| comment_body | String | No | 初期コメント | 任意文字列 |
| lead[tag_list] | String | No | タグ（カンマ区切り） | 任意文字列 |
| lead[background_info] | String | No | 背景情報 | 最大255文字 |

### 入力データソース

- URL: POST `/leads`
- HTTPメソッド: POST
- データソース: Webフォーム入力

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| @lead | Lead | 作成されたリードオブジェクト |
| @leads | Array | 一覧画面から呼ばれた場合のリード一覧 |
| @campaigns | Array | キャンペーン選択肢 |
| @lead_status_total | Hash | ステータス別リード件数 |

### 出力先

- HTML形式: リダイレクト（成功時）またはフォーム再表示（エラー時）
- JS形式: AJAX応答（create.js.haml）

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ POST /leads を受信
2. 認証・認可チェック
   └─ CanCanによる権限確認
3. Leadオブジェクト生成
   └─ 新規Leadインスタンスを作成
4. キャンペーン取得
   └─ ユーザーがアクセス可能なキャンペーン一覧を取得
5. バリデーション・保存
   └─ save_with_permissionsメソッドで権限付きで保存
6. コメント追加
   └─ comment_bodyがあれば初期コメントを追加
7. サイドバーデータ更新
   └─ 呼び出し元に応じてサイドバー情報を更新
8. レスポンス生成
   └─ フォーマットに応じた出力
```

### フローチャート

```mermaid
flowchart TD
    A[POST /leads] --> B[認証チェック]
    B --> C{認可チェック}
    C -->|許可| D[Leadオブジェクト生成]
    C -->|拒否| E[403 Forbidden]
    D --> F[キャンペーン一覧取得]
    F --> G[save_with_permissions]
    G --> H{保存成功?}
    H -->|Yes| I[コメント追加]
    H -->|No| J[エラー情報設定]
    I --> K{呼び出し元判定}
    K -->|一覧画面| L[リード一覧更新]
    K -->|キャンペーン画面| M[キャンペーン情報更新]
    L --> N[レスポンス生成]
    M --> N
    J --> N
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-22-01 | 名前必須設定 | Setting.require_first_namesがtrueの場合、first_nameは必須 | 設定依存 |
| BR-22-02 | 姓必須設定 | Setting.require_last_namesがtrueの場合、last_nameは必須 | 設定依存 |
| BR-22-03 | キャンペーン権限継承 | accessが"Campaign"の場合、キャンペーンの権限を継承 | access="Campaign"時 |
| BR-22-04 | 共有アクセス検証 | accessが"Shared"の場合、少なくとも1人のユーザー選択が必要 | access="Shared"時 |
| BR-22-05 | キャンペーンリード数更新 | リード作成時に関連キャンペーンのleads_countを増加 | キャンペーン紐付け時 |
| BR-22-06 | デフォルトアクセス | 新規作成時のデフォルトアクセスはSetting.default_access | 常時 |

### 計算ロジック

特になし

## データベース操作仕様

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| リード作成 | leads | INSERT | 新規リード情報の挿入 |
| 権限設定 | permissions | INSERT | 共有設定時の権限レコード作成 |
| コメント追加 | comments | INSERT | 初期コメントの挿入 |
| キャンペーン更新 | campaigns | UPDATE | leads_countのインクリメント |
| アドレス追加 | addresses | INSERT | 住所情報の挿入（任意） |
| タグ追加 | taggings | INSERT | タグの関連付け |

### テーブル別操作詳細

#### leads

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | user_id | current_user.id | 作成者 |
| INSERT | campaign_id | params[:campaign] | キャンペーン紐付け |
| INSERT | assigned_to | params[:lead][:assigned_to] | 担当者 |
| INSERT | first_name | params[:lead][:first_name] | 名 |
| INSERT | last_name | params[:lead][:last_name] | 姓 |
| INSERT | access | params[:lead][:access] | アクセス権限 |
| INSERT | status | params[:lead][:status] | ステータス |
| INSERT | created_at | 現在日時 | 自動設定 |

#### campaigns

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | leads_count | leads_count + 1 | after_createコールバック |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 422 | Validation Error | 必須項目未入力 | エラーメッセージ表示 |
| 422 | Validation Error | 共有設定時にユーザー未選択 | エラーメッセージ表示 |
| 403 | Forbidden | 認可エラー | エラーページ表示 |

### リトライ仕様

リトライは実装されていない（ユーザー操作による再送信）

## トランザクション仕様

- リード作成、権限設定、コメント追加は同一トランザクション内で実行
- キャンペーンのleads_count更新はafter_createコールバックで実行

## パフォーマンス要件

- フォーム表示のレスポンスタイム: 1秒以内
- 保存処理のレスポンスタイム: 2秒以内

## セキュリティ考慮事項

- CanCanによる認可制御でアクセス権限をチェック
- Strong Parametersによる入力パラメータ制限
- XSS対策としてビューでのエスケープ処理

## 備考

- キャンペーン詳細画面からの作成時はparams[:related]で関連情報を受け取る
- 住所情報はnested_attributesで同時に保存可能

---

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

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

### 推奨読解順序

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

リードのデータ構造と関連モデルを理解することが最初のステップである。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | lead.rb | `app/models/entities/lead.rb` | リードモデルの属性定義、バリデーション、コールバック |

**読解のコツ**:
- **76-79行目**: validates_presence_ofで名前の必須設定を確認
- **78行目**: users_for_shared_accessカスタムバリデーション
- **81-82行目**: after_create/after_destroyでキャンペーンカウンター更新
- **96-104行目**: save_with_permissionsメソッドで権限付き保存ロジック
- **170-177行目**: increment_leads_count/decrement_leads_countでカウンター操作

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

コントローラーのnew/createアクションがエントリーポイントである。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | leads_controller.rb | `app/controllers/entities/leads_controller.rb` | new/createアクションの実装 |

**主要処理フロー**:
1. **36-50行目** (newアクション): デフォルト値設定、キャンペーン取得、関連エンティティ処理
2. **64-79行目** (createアクション): save_with_permissions呼び出し、コメント追加、サイドバー更新
3. **207-209行目**: get_campaignsメソッドでユーザーがアクセス可能なキャンペーン取得

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

フォーム表示のロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | _new.html.haml | `app/views/leads/_new.html.haml` | 新規作成フォームの構造 |

**主要処理フロー**:
- **1行目**: simple_form_forでフォーム生成
- **8-15行目**: 各セクションのパーシャルをrender（top_section, status, contact, web等）
- **15行目**: entities/permissionsでアクセス権限設定

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

```
LeadsController#new
    │
    ├─ @lead.attributes = { ... } (デフォルト値設定)
    │
    ├─ get_campaigns
    │      └─ Campaign.my(current_user).order('name')
    │
    └─ respond_with(@lead)
           └─ new.js.haml → _new.html.haml

LeadsController#create
    │
    ├─ get_campaigns
    │
    ├─ @lead.save_with_permissions(params)
    │      ├─ Campaign.find(params[:campaign])
    │      ├─ save_with_model_permissions (access="Campaign"時)
    │      └─ save
    │            └─ increment_leads_count (after_create)
    │
    ├─ @lead.add_comment_by_user(@comment_body, current_user)
    │
    └─ get_data_for_sidebar
           └─ Lead.my(current_user).count
```

### データフロー図

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

POST /leads ────▶ LeadsController#create ───▶ HTML/JS
      │                     │
      │                     ├─▶ Lead.new
      │                     │
      │                     ├─▶ save_with_permissions
      │                     │       ├─▶ [leads]テーブル INSERT
      │                     │       └─▶ [campaigns]テーブル UPDATE
      │                     │
      │                     ├─▶ add_comment_by_user
      │                     │       └─▶ [comments]テーブル INSERT
      │                     │
      │                     └─▶ [permissions]テーブル INSERT
      │
      └─▶ create.js.haml
              └─▶ _lead.html.haml (一覧に追加)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| leads_controller.rb | `app/controllers/entities/leads_controller.rb` | コントローラー | リード操作のエントリーポイント |
| lead.rb | `app/models/entities/lead.rb` | モデル | リードのデータモデル定義 |
| _new.html.haml | `app/views/leads/_new.html.haml` | ビュー | 新規作成フォーム |
| new.js.haml | `app/views/leads/new.js.haml` | ビュー | AJAX応答でフォーム表示 |
| create.js.haml | `app/views/leads/create.js.haml` | ビュー | 作成完了後のAJAX応答 |
| _top_section.html.haml | `app/views/leads/_top_section.html.haml` | ビュー | フォーム上部セクション |
| _status.html.haml | `app/views/leads/_status.html.haml` | ビュー | ステータス選択セクション |
| _contact.html.haml | `app/views/leads/_contact.html.haml` | ビュー | 連絡先情報セクション |
| _permissions.html.haml | `app/views/entities/_permissions.html.haml` | ビュー | アクセス権限設定 |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義 |
