# 機能設計書 57-リスト作成

## 概要

本ドキュメントは、Fat Free CRMにおけるリスト（検索条件保存）作成機能の設計書である。ユーザーが検索条件やフィルタ条件を保存し、再利用できるようにする機能について、処理仕様・データベース操作・コード構造を定義する。

### 本機能の処理概要

ユーザーが各エンティティ（取引先、連絡先、商談等）の一覧画面で適用した検索条件やフィルタ条件を「リスト」として保存する機能である。保存したリストはサイドバーに表示され、クリックすることで同じ条件で検索結果を再表示できる。

**業務上の目的・背景**：CRMでは同じ検索条件を繰り返し使用することが多い。例えば「今月成約予定の商談」「自分が担当する未対応リード」など、日常的に確認したい条件をリストとして保存することで、業務効率が大幅に向上する。

**機能の利用シーン**：
- 頻繁に使用する検索条件を保存しておきたい場面
- チーム内で共有したいフィルタ条件がある場面
- 定期的なレビューで同じ検索結果を確認したい場面
- 個人用とグローバル（全ユーザー共有）用のリストを使い分けたい場面

**主要な処理内容**：
1. 一覧画面でフィルタ/検索条件を適用
2. リスト保存フォームにリスト名を入力
3. グローバル/個人の選択
4. 現在のURLとリスト名を保存
5. サイドバーのリスト一覧を更新

**関連システム・外部連携**：特になし

**権限による制御**：
- ログインユーザーは個人用リストを作成可能
- グローバルリスト（is_global=1）は全ユーザーが利用可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 57 | リスト（Lists） | 主画面 | 検索条件を保存するリスト作成 |

## 機能種別

設定保存処理 / INSERT/UPDATE操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| list[name] | String | Yes | リスト名 | 必須 |
| list[url] | String | Yes | 保存するURL（検索条件含む） | 必須 |
| is_global | String | No | グローバルリストフラグ（"1"で有効） | "1" または未指定 |

### 入力データソース

- 画面入力（リスト保存フォーム）
- 現在のURL（JavaScriptで取得）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 更新されたリスト一覧HTML | HTML | サイドバーのリスト表示用HTML |

### 出力先

- listsテーブル（リストレコード）
- 画面（サイドバー更新）

## 処理フロー

### 処理シーケンス

```
1. リスト保存フォーム入力
   └─ リスト名、グローバルフラグ
2. フォーム送信（POST /lists）
   └─ ListsController#create
3. パラメータ処理
   ├─ is_global=1の場合: user_idをNULLに
   └─ それ以外: user_idをcurrent_user.idに
4. 既存リスト検索
   └─ 同名（大文字小文字区別なし）・同user_idのリストを検索
5. リスト保存
   ├─ 存在する場合: UPDATE
   └─ 存在しない場合: INSERT
6. JSレスポンス
   └─ サイドバーのリスト一覧を更新
```

### フローチャート

```mermaid
flowchart TD
    A[リスト名入力] --> B{is_global?}
    B -->|Yes| C[user_id = NULL]
    B -->|No| D[user_id = current_user.id]
    C --> E[同名リスト検索]
    D --> E
    E --> F{既存リストあり?}
    F -->|Yes| G[UPDATE]
    F -->|No| H[INSERT]
    G --> I[JSレスポンス]
    H --> I
    I --> J[サイドバー更新]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-57-01 | 名前重複時更新 | 同名・同スコープのリストが存在する場合は更新 | 常時 |
| BR-57-02 | 大文字小文字無視 | リスト名の重複チェックは大文字小文字を区別しない | 常時 |
| BR-57-03 | グローバル/個人分離 | グローバルリストと個人リストは別スコープ | 常時 |
| BR-57-04 | URL保存 | 現在の検索条件を含むURLをそのまま保存 | 常時 |

### 計算ロジック

特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 既存リスト検索 | lists | SELECT | 同名・同スコープのリスト検索 |
| リスト保存 | lists | INSERT/UPDATE | リストレコード作成/更新 |

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

#### lists

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT/UPDATE | name | 入力値 | リスト名 |
| INSERT/UPDATE | url | 入力値 | 検索条件含むURL |
| INSERT/UPDATE | user_id | current_user.id または NULL | 個人/グローバル判定 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | バリデーションエラー | リスト名が空 | エラー表示、送信ボタン再有効化 |
| - | バリデーションエラー | URLが空 | エラー表示、送信ボタン再有効化 |

### リトライ仕様

- バリデーション失敗時は同一フォームで修正・再試行可能

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

単一レコードのINSERT/UPDATEのため、特別なトランザクション制御は不要。

## パフォーマンス要件

- レスポンス時間: 500ms以内
- 単純なCRUD操作のため、負荷は軽微

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

- CSRFトークン検証あり
- リスト作成はログインユーザーのみ可能
- グローバルリストは全ユーザーがアクセス可能（閲覧のみ）

## 備考

- リスト機能は各エンティティ一覧画面のサイドバーから利用
- URLにはRansack検索条件やページネーション情報が含まれる場合がある

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | list.rb | `app/models/list.rb` | Listモデル、バリデーション、controllerメソッド |
| 1-2 | schema.rb | `db/schema.rb` | listsテーブル構造 |

**読解のコツ**:
- **9-10行目（list.rb）**: name, urlのバリデーション
- **11行目（list.rb）**: user関連（optional: true）
- **14-16行目（list.rb）**: URLからコントローラーを抽出するメソッド
- **318-325行目（schema.rb）**: listsテーブル構造（name, url, user_id）

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | lists_controller.rb | `app/controllers/lists_controller.rb` | createアクション |
| 2-2 | routes.rb | `config/routes.rb` | ルーティング |

**主要処理フロー**:
1. **11-13行目（lists_controller.rb）**: is_globalフラグによるuser_id設定
2. **15-19行目（lists_controller.rb）**: 同名リスト検索（大文字小文字無視）、UPDATE/INSERT判定

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | create.js.haml | `app/views/lists/create.js.haml` | 作成成功/失敗時のJS処理 |
| 3-2 | _lists.html.haml | `app/views/lists/_lists.html.haml` | リスト一覧パーシャル |
| 3-3 | _sidebar.html.haml | `app/views/lists/_sidebar.html.haml` | サイドバー表示 |

**主要処理フロー**:
- **create.js.haml 1-3行目**: 成功時にサイドバーを更新
- **create.js.haml 5-8行目**: 失敗時にフォームにフォーカス、ボタン再有効化

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

```
POST /lists
    │
    └─ ListsController#create
           │
           ├─ パラメータ処理
           │      └─ is_global判定 → user_id設定
           │
           ├─ List.where（同名検索）
           │      └─ lower(name) = lower(入力値)
           │
           ├─ @list.update または List.create
           │
           └─ respond_with(@list)
                  └─ create.js.haml
                         └─ サイドバー更新
```

### データフロー図

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

リスト名 ────────▶ パラメータ処理 ─────────▶ listsテーブル
URL ──────────────▶ 同名検索 ────────────────▶ INSERT/UPDATE
is_global ────────▶ user_id決定
                           │
                           └───────────────────▶ JSレスポンス
                                                   │
                                                   ▼
                                              サイドバー更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| lists_controller.rb | `app/controllers/lists_controller.rb` | コントローラー | リスト作成 |
| list.rb | `app/models/list.rb` | モデル | Listモデル |
| create.js.haml | `app/views/lists/create.js.haml` | ビュー | 作成結果のJS |
| _lists.html.haml | `app/views/lists/_lists.html.haml` | ビュー | リスト一覧 |
| _sidebar.html.haml | `app/views/lists/_sidebar.html.haml` | ビュー | サイドバー |
| routes.rb | `config/routes.rb` | 設定 | ルーティング |
| schema.rb | `db/schema.rb` | スキーマ | listsテーブル定義 |
