# 機能設計書 15-連絡先一覧表示

## 概要

本ドキュメントは、Fat Free CRMにおける連絡先一覧表示機能の設計を記述する。システムに登録された連絡先を一覧表示し、CSV/XLS形式でエクスポートする機能である。

### 本機能の処理概要

**業務上の目的・背景**：営業活動において連絡先（顧客担当者、見込み顧客等）の情報を一元管理し、効率的に参照・検索できるようにする。連絡先一覧により、営業担当者は自分が担当する連絡先を素早く確認でき、フォローアップすべき連絡先を特定できる。

**機能の利用シーン**：営業担当者が担当連絡先を確認する場合、新規顧客へのアプローチ対象を探す場合、連絡先情報を外部システムと連携するためにエクスポートする場合に利用される。また、高度な検索（Ransack）を使って特定条件の連絡先を抽出する場合にも使用される。

**主要な処理内容**：
1. 現在ユーザーがアクセス可能な連絡先の取得
2. テキスト検索、タグ検索、高度な検索（Ransack）によるフィルタリング
3. ソート、ページネーション処理
4. 各種フォーマット（HTML、JS、XLS、CSV）でのレスポンス生成

**関連システム・外部連携**：CSV/XLS形式でのエクスポートにより、Excelや外部システムとのデータ連携が可能。

**権限による制御**：CanCanによるアクセス権限管理が行われ、ユーザーがアクセス可能な連絡先のみ表示される。連絡先のアクセス設定（Public/Private/Shared）により閲覧可否が決定される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 20 | 連絡先一覧画面 | 主画面 | 連絡先の一覧表示、CSV/XLSエクスポート |

## 機能種別

データ参照（Read操作）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| page | Integer | No | ページ番号 | 正の整数 |
| per_page | Integer | No | 1ページあたりの表示件数 | 1-200 |
| query | String | No | テキスト検索クエリ | - |
| q | Hash | No | Ransack検索条件 | Ransack形式 |
| format | String | No | レスポンス形式（html/js/xls/csv） | 許可された形式のみ |

### 入力データソース

- URLパラメータ
- セッション情報（現在のユーザー情報、ソート設定、ページ情報）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| @contacts | Array | 連絡先オブジェクトの配列（ページネーション済み） |
| @search_results_count | Integer | 検索結果の総件数 |

### 出力先

- HTML画面表示
- AJAX（JS）レスポンス
- XLS/CSVファイルダウンロード

## 処理フロー

### 処理シーケンス

```
1. ユーザー認証確認
   └─ authenticate_user!でログイン状態を確認
2. 検索条件の構築
   └─ Ransack検索オブジェクトのロード
3. 連絡先一覧取得
   └─ get_contactsメソッドで条件に合致する連絡先を取得
4. ソート・ページネーション
   └─ ユーザー設定に基づくソート、ページネーション適用
5. レスポンス生成
   └─ フォーマットに応じた出力（HTML/JS/XLS/CSV）
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B[ユーザー認証]
    B --> C{認証OK?}
    C -->|No| D[ログインページへリダイレクト]
    C -->|Yes| E[Ransack検索条件ロード]
    E --> F[get_contacts実行]
    F --> G{テキスト検索?}
    G -->|Yes| H[text_search適用]
    G -->|No| I{タグ検索?}
    H --> I
    I -->|Yes| J[tagged_with適用]
    I -->|No| K[ソート適用]
    J --> K
    K --> L{XLS/CSV?}
    L -->|Yes| M[全件取得]
    L -->|No| N[ページネーション適用]
    M --> O[ファイル生成]
    N --> P[ビュー描画]
    O --> Q[終了]
    P --> Q
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-15-01 | アクセス権限制御 | 連絡先のaccess設定に基づき閲覧可否を判定 | 常時 |
| BR-15-02 | デフォルトソート | created_at DESC（作成日時の降順） | ソート未指定時 |
| BR-15-03 | デフォルト表示件数 | 20件/ページ | 表示件数未指定時 |
| BR-15-04 | エクスポート時ページネーション無効 | XLS/CSV形式では全件出力 | XLS/CSVリクエスト時 |
| BR-15-05 | 名前検索の柔軟性 | 姓名の順序を問わず検索可能 | テキスト検索時 |

### 計算ロジック

名前検索ロジック（text_search）：
```ruby
# スペースを含む場合、姓名の順列を全て検索
name_query = query.name_permutations.map do |first, last|
  first_name LIKE '%first%' AND last_name LIKE '%last%'
end.or(...)

# メール、電話番号も同時検索
other = email LIKE '%query%' OR alt_email LIKE '%query%' OR phone LIKE '%query%' OR mobile LIKE '%query%'
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 連絡先一覧取得 | contacts | SELECT | アクセス権限を考慮した一覧取得 |
| 関連取引先取得 | accounts | SELECT | 連絡先に紐付く取引先情報取得（includes） |
| タグ取得 | tags, taggings | SELECT | 連絡先に紐付くタグ情報取得（includes） |

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

#### contacts

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | 全カラム | my(current_user)スコープ、deleted_at IS NULL | ページネーション・ソート適用 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 401 | 認証エラー | 未ログイン状態でアクセス | ログインページへリダイレクト |

### リトライ仕様

本機能にリトライ処理は実装されていない。

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

参照系処理のみであり、明示的なトランザクション管理は不要。

## パフォーマンス要件

- 一覧表示は2秒以内を目標
- XLS/CSVエクスポートは10秒以内を目標（件数依存）

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

- CanCanによるアクセス権限チェック実施
- CSRF対策（protect_from_forgery）
- SQLインジェクション対策（ActiveRecord/Ransack使用）
- XSS対策（ERB::Util使用）

## 備考

- 高度な検索（Ransack）機能は別機能（No.81）として管理
- オートコンプリート機能は別機能（No.82）として管理

---

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

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

### 推奨読解順序

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

まず、連絡先エンティティの構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | contact.rb | `app/models/entities/contact.rb` | Contactモデルの属性、関連、スコープ定義 |

**読解のコツ**:
- **40-52行目**: 関連定義（belongs_to :user, has_one :account, has_many :opportunities等）
- **66-84行目**: `text_search`スコープで名前検索ロジックを確認
- **94行目**: `sortable`で利用可能なソートキーを確認

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

処理の起点となるコントローラーのindexアクションを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | contacts_controller.rb | `app/controllers/entities/contacts_controller.rb` | indexアクションの処理内容 |

**主要処理フロー**:
1. **13-19行目**: indexアクション - get_contacts呼び出し、フォーマット別レスポンス
2. **133行目**: `alias get_contacts get_list_of_records`でget_list_of_recordsを使用

#### Step 3: 基底コントローラーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | entities_controller.rb | `app/controllers/entities_controller.rb` | get_list_of_recordsメソッドの詳細 |

**主要処理フロー**:
- **138-178行目**: `get_list_of_records`メソッド - 検索、フィルタ、ソート、ページネーションの統合処理
- **146行目**: `entities.merge(ransack_search.result(distinct: true))`でRansack検索結果をマージ
- **154-155行目**: テキスト検索、タグ検索の適用

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | index.html.haml | `app/views/contacts/index.html.haml` | 一覧画面のレイアウト構成 |
| 4-2 | _contact.html.haml | `app/views/contacts/_contact.html.haml` | 個別連絡先の表示 |

**主要処理フロー**:
- **11-15行目**: 連絡先一覧のレンダリング、空の場合のハンドリング
- **17-18行目**: ページネーションとエクスポートボタン

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

```
ContactsController#index
    │
    ├─ EntitiesController (継承)
    │      ├─ load_and_authorize_resource
    │      └─ set_options (per_page, sort_by設定)
    │
    └─ get_contacts (= get_list_of_records)
           │
           ├─ ransack_search.result
           │
           ├─ text_search (オプション)
           │      └─ Contact.text_search
           │             └─ 名前・メール・電話の検索
           │
           ├─ tagged_with (オプション)
           │
           ├─ order
           │
           └─ paginate
```

### データフロー図

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

検索条件 ─────────▶ ContactsController#index ───▶ HTML画面/XLS/CSV
                          │
ページ/ソート設定         ├─▶ get_list_of_records
                          │     ├─▶ Ransack検索
                          │     ├─▶ text_search
                          │     ├─▶ tagged_with
                          │     └─▶ paginate
                          │
                          └─▶ respond_with
                                ├─▶ HTML: ビュー描画
                                ├─▶ JS: AJAX更新
                                └─▶ XLS/CSV: ファイル生成
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| contacts_controller.rb | `app/controllers/entities/contacts_controller.rb` | コントローラー | 連絡先関連アクションの処理 |
| entities_controller.rb | `app/controllers/entities_controller.rb` | コントローラー | エンティティ共通処理 |
| contact.rb | `app/models/entities/contact.rb` | モデル | 連絡先エンティティ定義 |
| index.html.haml | `app/views/contacts/index.html.haml` | ビュー | 一覧画面テンプレート |
| _contact.html.haml | `app/views/contacts/_contact.html.haml` | ビュー | 連絡先パーシャル |
| index.xls.builder | `app/views/contacts/index.xls.builder` | ビュー | XLSエクスポートテンプレート |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義 |
