# 機能設計書 29-商談詳細表示

## 概要

本ドキュメントは、Fat Free CRMシステムにおける商談詳細表示機能の設計を定義する。この機能は、個別の商談情報を詳細に閲覧し、関連するタイムライン、タスク、連絡先、バージョン履歴を確認するための画面を提供する。

### 本機能の処理概要

商談詳細表示機能は、営業活動における商談の全容を把握するための機能である。

**業務上の目的・背景**：営業担当者が商談の進捗状況、関連する連絡先、過去のコミュニケーション履歴を一元的に確認し、適切な営業活動を行うために必要な機能である。商談の金額、確度、クローズ予定日などの重要指標を確認することで、営業パイプラインの管理と売上予測の精度向上に貢献する。

**機能の利用シーン**：商談の進捗を確認する場合、顧客との商談前に情報を確認する場合、商談に関連する連絡先やタスクを管理する場合、商談の変更履歴を追跡する場合に利用される。

**主要な処理内容**：
1. 商談IDに基づく商談情報の取得と表示
2. 商談に紐付くコメント・メールのタイムライン表示
3. 関連タスクの一覧表示
4. 関連連絡先の一覧表示
5. バージョン履歴（変更履歴）の表示

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

**権限による制御**：CanCanによる認可制御が行われ、ユーザーは自分が作成した商談、自分に割り当てられた商談、または共有された商談のみ閲覧可能である。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 25 | 商談詳細画面 | 主画面 | 商談詳細情報、タイムライン表示 |
| 25 | 商談詳細画面 | 補助機能 | コメント一覧表示（機能No.42） |
| 25 | 商談詳細画面 | 補助機能 | コメント作成（機能No.43） |
| 25 | 商談詳細画面 | 補助機能 | 購読/購読解除（機能No.86） |
| 25 | 商談詳細画面 | 補助機能 | バージョン履歴（機能No.85） |
| 25 | 商談詳細画面 | 遷移先機能 | 商談削除（機能No.32） |

## 機能種別

データ参照（READ）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | Integer | Yes | 商談ID | 数値、存在確認 |

### 入力データソース

- URL: GET `/opportunities/:id`
- HTTPメソッド: GET
- データソース: opportunitiesテーブル（主テーブル）、comments/emailsテーブル（タイムライン用）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| @opportunity | Opportunity | 商談オブジェクト |
| @comment | Comment | 新規コメント用の空オブジェクト |
| @timeline | Array | コメントとメールの配列（作成日時降順） |

### 出力先

- HTML形式: 詳細画面表示（show.html.haml）
- JS形式: AJAX更新用（show.js.haml）

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ GET /opportunities/:id を受信
2. 認証・認可チェック
   └─ CanCanによる権限確認
3. 商談データ取得
   └─ Opportunityモデルから商談情報を取得
4. 関連データ取得
   └─ タイムライン（コメント + メール）を取得・ソート
5. 閲覧履歴記録
   └─ バージョン履歴に閲覧イベントを記録
6. レスポンス生成
   └─ フォーマットに応じた出力（HTML/JS）
```

### フローチャート

```mermaid
flowchart TD
    A[GET /opportunities/:id] --> B[認証チェック]
    B --> C{認可チェック}
    C -->|許可| D[商談データ取得]
    C -->|拒否| E[403 Forbidden]
    D --> F[タイムライン取得]
    F --> G[閲覧履歴記録]
    G --> H{フォーマット判定}
    H -->|HTML| I[詳細画面表示]
    H -->|JS| J[AJAX応答]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-29-01 | アクセス権限チェック | ユーザーは自分が作成、割当て、または共有された商談のみ閲覧可能 | 常時 |
| BR-29-02 | タイムラインソート | コメントとメールは作成日時の降順で表示 | 常時 |
| BR-29-03 | 閲覧履歴記録 | 商談詳細を表示した際にバージョン履歴に記録 | 常時 |
| BR-29-04 | 重み付け金額表示 | (amount - discount) * probability / 100 で計算した金額を表示 | 常時 |

### 計算ロジック

重み付け金額の計算:
- `weighted_amount = (amount.to_f - discount.to_f) * probability.to_i / 100.0`

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 商談取得 | opportunities | SELECT | 指定IDの商談情報取得 |
| 取引先取得 | accounts | SELECT | 商談に紐付く取引先取得 |
| 連絡先取得 | contacts | SELECT | 商談に紐付く連絡先一覧取得 |
| タイムライン取得 | comments | SELECT | 商談に紐付くコメント取得 |
| タイムライン取得 | emails | SELECT | 商談に紐付くメール取得 |
| 閲覧履歴記録 | versions | INSERT | 閲覧イベントを記録 |

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

#### opportunities

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | id = :id | 全カラム取得 |

#### versions

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | item_type | 'Opportunity' | |
| INSERT | item_id | 商談ID | |
| INSERT | event | 'view' | |
| INSERT | whodunnit | 現在のユーザーID | |
| INSERT | created_at | 現在日時 | |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 404 | Not Found | 指定IDの商談が存在しない | エラーページ表示 |
| 403 | Forbidden | アクセス権限がない | エラーページ表示 |

### リトライ仕様

リトライは実装されていない（参照操作のため不要）

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

閲覧履歴の記録はafter_actionコールバックで実行され、メイン処理とは別トランザクションで処理される。

## パフォーマンス要件

- 詳細画面のレスポンスタイム: 2秒以内

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

- CanCanによる認可制御でアクセス権限をチェック
- XSS対策としてビューでのエスケープ処理
- 閲覧履歴がバージョン履歴として記録される

## 備考

- タイムラインはコメントとメールをマージして日時降順ソート
- 関連連絡先は別タブで表示可能

---

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

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

### 推奨読解順序

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

商談のデータ構造を理解することが最初のステップである。

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

**読解のコツ**:
- **8-27行目**: Schema Informationでテーブル構造を確認
- **30-39行目**: belongs_to/has_many関係で商談の関連エンティティを理解
- **34-37行目**: account, contacts への関連（through）
- **72-77行目**: uses_user_permissions、acts_as_commentable等のmixin定義
- **103-105行目**: weighted_amountメソッドで重み付け金額の計算

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | opportunities_controller.rb | `app/controllers/entities/opportunities_controller.rb` | showアクションの実装 |
| 2-2 | entities_controller.rb | `app/controllers/entities_controller.rb` | 基底クラスの共通処理 |

**主要処理フロー**:
1. **27-31行目** (opportunities_controller.rb): showアクション - @commentと@timelineを設定
2. **17行目** (entities_controller.rb): after_action :update_recently_viewedで閲覧履歴記録
3. **215-217行目** (entities_controller.rb): timelineメソッドでコメント+メールをソート

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

画面表示のロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | show.html.haml | `app/views/opportunities/show.html.haml` | 詳細画面のレイアウト構造 |

**主要処理フロー**:
- **1-2行目**: カスタムビューテンプレートがあれば使用
- **9-13行目**: タイトルバー、サイドバー、コメント入力、タイムライン表示
- **15-23行目**: hookによる拡張ポイント、タスク一覧、連絡先一覧、バージョン履歴表示

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

```
OpportunitiesController#show
    │
    ├─ load_and_authorize_resource (CanCan)
    │      └─ Opportunity.find(params[:id])
    │
    ├─ Comment.new (コメント入力用)
    │
    ├─ timeline(@opportunity)
    │      └─ opportunity.comments + opportunity.emails
    │             └─ sort by created_at DESC
    │
    ├─ respond_with(@opportunity)
    │      ├─ format.html → show.html.haml
    │      └─ format.js → show.js.haml
    │
    └─ update_recently_viewed (after_action)
           └─ entity.versions.create(event: :view)
```

### データフロー図

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

GET /opportunities/:id ───▶ OpportunitiesController#show ───▶ HTML/JS
      │                           │
      │                           ├─▶ Opportunity.find()
      │                           │       └─▶ [opportunities]テーブル
      │                           │
      │                           ├─▶ timeline()
      │                           │       ├─▶ [comments]テーブル
      │                           │       └─▶ [emails]テーブル
      │                           │
      │                           └─▶ versions.create()
      │                                   └─▶ [versions]テーブル
      │
      └─▶ show.html.haml
              ├─▶ _title_bar.html.haml
              ├─▶ _sidebar_show.html.haml
              ├─▶ comments/_new.html.haml
              ├─▶ shared/_timeline.html.haml
              ├─▶ tasks/_tasks.html.haml
              ├─▶ contacts/_contacts.html.haml
              └─▶ versions/_versions.html.haml
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| opportunities_controller.rb | `app/controllers/entities/opportunities_controller.rb` | コントローラー | 商談操作のエントリーポイント |
| entities_controller.rb | `app/controllers/entities_controller.rb` | コントローラー | エンティティ共通処理の基底クラス |
| opportunity.rb | `app/models/entities/opportunity.rb` | モデル | 商談のデータモデル定義 |
| opportunities_helper.rb | `app/helpers/opportunities_helper.rb` | ヘルパー | 商談表示用ヘルパーメソッド |
| show.html.haml | `app/views/opportunities/show.html.haml` | ビュー | 詳細画面のメインテンプレート |
| show.js.haml | `app/views/opportunities/show.js.haml` | ビュー | AJAX応答用テンプレート |
| _title_bar.html.haml | `app/views/opportunities/_title_bar.html.haml` | ビュー | タイトルバーパーシャル |
| _sidebar_show.html.haml | `app/views/opportunities/_sidebar_show.html.haml` | ビュー | サイドバーパーシャル |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義 |
