# 機能設計書 3-タイムライン表示切替

## 概要

本ドキュメントは、Fat Free CRMシステムにおけるタイムライン表示切替機能の設計を定義する。この機能は、コメントやメールのタイムライン表示状態（展開/折りたたみ）を切り替える。

### 本機能の処理概要

タイムライン表示切替機能は、各エンティティの詳細画面やダッシュボードに表示されるコメント・メールの表示状態を制御する機能である。ユーザーは個々のアイテムまたは複数のアイテムを一括で展開/折りたたみすることができる。

**業務上の目的・背景**：CRMシステムでは、取引先や商談に対して多数のコメントやメールが蓄積される。これらを全て展開表示すると画面が長くなり、必要な情報を見つけにくくなる。本機能により、ユーザーは必要な情報のみを展開し、それ以外は折りたたむことで、効率的な情報確認が可能となる。

**機能の利用シーン**：
- 詳細画面で最新のコメントのみを展開して確認する場面
- 過去のやり取りを一括で展開して確認する場面
- 長いタイムラインを折りたたんで画面を見やすくする場面

**主要な処理内容**：
1. クライアントからのAJAXリクエスト受信
2. 対象モデル（Comment/Email）の特定
3. 状態（Collapsed/Expanded）の更新
4. 複数アイテムの一括更新（オプション）

**関連システム・外部連携**：本機能は外部システムとの連携はなく、内部データベースの更新のみで構成される。

**権限による制御**：タイムライン表示切替は認証済みユーザーであれば実行可能。対象のコメント・メールへの直接的なアクセス権限チェックは行わないが、表示自体がアクセス権限に基づいてフィルタリングされているため、操作できるのは表示可能なアイテムのみ。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 6 | ホーム画面（ダッシュボード） | 補助機能 | コメント・メールのタイムライン展開/折りたたみ切替 |

## 機能種別

状態更新（UPDATE操作）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| state | String | Yes | 状態（Collapsed/Expanded） | "Collapsed"または"Expanded"のみ許可 |
| type | String | No | モデル種別（comment/email） | "comment"または"email"のみ許可 |
| id | String | Yes | 対象ID（単一または複数） | 形式: "123" または "123,456+789,012"（コメントID+メールID） |

### 入力データソース

- クライアントからのAJAXリクエスト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| なし | - | HTTPステータス200（:ok）のみ返却 |

### 出力先

- HTTPレスポンス（head :ok）

## 処理フロー

### 処理シーケンス

```
1. stateパラメータの検証
   └─ "Collapsed"または"Expanded"以外の場合は処理しない
2. typeパラメータの存在確認
   ├─ 【typeあり】単一アイテム更新
   │   └─ "comment"または"email"の場合
   │       └─ モデルを特定してfindし、state属性を更新
   └─ 【typeなし】複数アイテム一括更新
       └─ idパラメータを"+"で分割（コメントID群+メールID群）
       └─ 各ID群を","で分割して配列化
       └─ Comment.where(id: ...).update_all(state: state)
       └─ Email.where(id: ...).update_all(state: state)
3. head :okを返却
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B{state有効?}
    B -->|No| C[head :ok]
    B -->|Yes| D{type指定あり?}
    D -->|Yes| E{type有効?}
    E -->|No| C
    E -->|Yes| F[モデル特定・find]
    F --> G[update_attribute state]
    G --> C
    D -->|No| H[IDを+で分割]
    H --> I[コメントID群取得]
    I --> J[メールID群取得]
    J --> K[Comment.update_all]
    K --> L[Email.update_all]
    L --> C
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 有効な状態値 | "Collapsed"または"Expanded"のみ許可 | 常時 |
| BR-002 | 有効なモデル種別 | "comment"または"email"のみ許可 | typeパラメータ指定時 |
| BR-003 | 一括更新形式 | コメントIDとメールIDを"+"で区切り、各ID群は","で区切る | type未指定時 |

### 計算ロジック

特に計算ロジックは存在しない。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 単一更新 | comments | UPDATE | 指定コメントのstate更新 |
| 単一更新 | emails | UPDATE | 指定メールのstate更新 |
| 一括更新 | comments | UPDATE | 複数コメントのstate一括更新 |
| 一括更新 | emails | UPDATE | 複数メールのstate一括更新 |

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

#### comments

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | state | "Collapsed" or "Expanded" | id条件で特定 |

#### emails

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | state | "Collapsed" or "Expanded" | id条件で特定 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 401 | 認証エラー | 未ログイン状態でアクセス | ログイン画面へリダイレクト |
| - | 無効な状態値 | stateが"Collapsed"/"Expanded"以外 | 処理をスキップしhead :ok返却 |
| - | 無効なモデル種別 | typeが"comment"/"email"以外 | 処理をスキップしhead :ok返却 |

### リトライ仕様

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

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

update_allは一括処理だが、失敗時の部分ロールバックは行わない。

## パフォーマンス要件

- AJAX応答時間: 500ms以内を目標
- update_allによる効率的な一括更新

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

- 認証: Deviseによるユーザー認証が必須
- パラメータ検証: 状態値とモデル種別の厳密なバリデーション
- SQLインジェクション: ActiveRecordのwhereメソッドによる対策

## 備考

- 表示状態はデータベースに永続化されるため、リロード後も維持される
- UI操作はJavaScriptで非同期に実行される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | comment.rb | `app/models/polymorphic/comment.rb` | コメントモデルのstate属性 |
| 1-2 | email.rb | `app/models/polymorphic/email.rb` | メールモデルのstate属性 |

**読解のコツ**: 両モデルにstate属性（"Collapsed"/"Expanded"）が存在することを確認する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | routes.rb | `config/routes.rb` | /home/timelineルート |
| 2-2 | home_controller.rb | `app/controllers/home_controller.rb` | timelineアクション |

**主要処理フロー**:
1. **65行目**: timelineアクション開始
2. **66行目**: stateパラメータの取得と検証
3. **67行目**: "Collapsed"/"Expanded"の検証
4. **68-73行目**: 単一アイテム更新処理
5. **75-78行目**: 複数アイテム一括更新処理
6. **81行目**: head :ok返却

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | _timeline.html.haml | `app/views/shared/_timeline.html.haml` | タイムライン表示パーシャル |

**主要処理フロー**:
- タイムラインアイテムの展開/折りたたみ状態に応じたCSS classの適用

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

```
HomeController#timeline
    │
    ├─ state検証 (%w[Collapsed Expanded].include?)
    │
    ├─ 【type指定あり】
    │   └─ model_type.camelize.constantize
    │       └─ model.find(params[:id])
    │           └─ item.update_attribute(:state, state)
    │
    └─ 【type未指定】
        ├─ params[:id].split("+")
        │   ├─ comments (前半)
        │   └─ emails (後半)
        ├─ Comment.where(id: ...).update_all(state: state)
        └─ Email.where(id: ...).update_all(state: state)
```

### データフロー図

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

AJAXリクエスト ───▶ HomeController#timeline ───▶ HTTP 200 OK
(state,type,id)         │
                        ▼
                    状態検証
                        │
                        ▼
              ┌─────────┴─────────┐
              │                   │
        【type指定】        【type未指定】
              │                   │
              ▼                   ▼
        find & update      update_all
        (comments/emails)  (comments + emails)
              │                   │
              ▼                   ▼
        データベース        データベース
        (単一レコード)      (複数レコード)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| home_controller.rb | `app/controllers/home_controller.rb` | ソース | timelineアクション |
| comment.rb | `app/models/polymorphic/comment.rb` | ソース | コメントモデル |
| email.rb | `app/models/polymorphic/email.rb` | ソース | メールモデル |
| _timeline.html.haml | `app/views/shared/_timeline.html.haml` | テンプレート | タイムライン表示 |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義 |
