# 機能設計書 45-コメント一覧表示

## 概要

本ドキュメントは、カードのコメント一覧を表示する機能の設計を定義するものである。

### 本機能の処理概要

**業務上の目的・背景**：カンバンボードでのタスク管理において、コメント機能はチームメンバー間のコミュニケーションの中核を担う。コメント一覧表示機能は、カードに対するすべての議論、質問、回答、進捗報告を時系列で一覧化し、タスクに関する情報を一箇所で確認できるようにする。これにより、チームの情報共有と意思疎通が効率化される。

**機能の利用シーン**：
- カードに対する過去の議論を確認したいとき
- タスクの経緯や意思決定の履歴を追いたいとき
- チームメンバーの意見や質問を確認したいとき
- 自分がメンションされたコメントを探したいとき

**主要な処理内容**：
1. 対象カードを特定しアクセス権限を確認
2. カードに紐づくコメントを時系列（古い順）で取得
3. ページネーション処理を適用
4. コメント一覧をレンダリングして返却

**関連システム・外部連携**：特になし（内部処理のみ）

**権限による制御**：カードへのアクセス権限を持つユーザーのみがコメントを閲覧可能。CardScopedモジュールにより、`Current.user.accessible_cards`でアクセス可能なカードのみ操作対象となる。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 19 | カード詳細画面 | 主機能 | カードのコメント一覧を表示 |
| 30 | カードコメント詳細画面 | 参照画面 | カードのコメント詳細を表示 |

## 機能種別

参照処理（Read）/ 一覧表示

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| card_id | Integer | Yes | 対象カードのID（URLパラメータ） | 存在確認、アクセス権限確認 |
| page | Integer | No | 表示するページ番号 | 正の整数 |

### 入力データソース

- URLパラメータからカードID
- セッション情報から現在のユーザー

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| @comments | Array<Comment> | コメントオブジェクトの配列 |
| comment.body | RichText | コメント本文（リッチテキスト） |
| comment.creator | User | コメント作成者 |
| comment.created_at | DateTime | 作成日時 |
| comment.reactions | Array<Reaction> | コメントへのリアクション |

### 出力先

画面表示（HTMLレンダリング）

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ GET /cards/:card_id/comments へのリクエストを受信

2. 認証・認可確認
   └─ CardScopedモジュールのset_cardでカードアクセス権限を確認

3. コメント一覧取得
   └─ @card.comments.chronologically でコメントを時系列順に取得

4. ページネーション処理
   └─ set_page_and_extract_portion_from でページング処理

5. ビューレンダリング
   └─ comments/index.html.erb でHTMLを生成して返却
```

### フローチャート

```mermaid
flowchart TD
    A[GET /cards/:card_id/comments] --> B{認証済み?}
    B -->|No| C[401 Unauthorized]
    B -->|Yes| D[set_card: カード取得]
    D --> E{カードアクセス可能?}
    E -->|No| F[404 Not Found]
    E -->|Yes| G[@card.comments.chronologically]
    G --> H[set_page_and_extract_portion_from]
    H --> I[ビューレンダリング]
    I --> J[HTML返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-45-01 | カードスコープ | コメントは紐づくカードへのアクセス権限があれば閲覧可能 | 常時 |
| BR-45-02 | 時系列表示 | コメントは作成日時の古い順（昇順）で表示される | 常時 |
| BR-45-03 | リッチテキスト | コメント本文はAction Textによるリッチテキスト形式 | 常時 |
| BR-45-04 | リアクション表示 | 各コメントに付けられたリアクションも合わせて表示 | 常時 |

### 計算ロジック

特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| カード取得 | cards | SELECT | 対象カードの存在確認とアクセス権限確認 |
| コメント一覧取得 | comments | SELECT | カードに紐づくコメントを取得 |
| リッチテキスト取得 | action_text_rich_texts | SELECT | コメント本文を取得 |
| リアクション取得 | reactions | SELECT | コメントへのリアクションを取得 |
| ユーザー取得 | users | SELECT | コメント作成者情報を取得 |

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

#### comments

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | WHERE card_id = @card.id ORDER BY created_at ASC, id DESC | chronologicallyスコープ |

#### reactions

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | WHERE reactable_type = 'Comment' AND reactable_id = comment.id | ポリモーフィック関連 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 401 | 認証エラー | 未認証状態でアクセス | ログイン画面へリダイレクト |
| 404 | Not Found | カードが存在しない/アクセス権限なし | エラーメッセージ表示 |

### リトライ仕様

特になし

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

読み取り専用のため、トランザクション管理は不要

## パフォーマンス要件

- コメント一覧表示のレスポンス時間: 500ms以内
- ページネーションによりデータ量を制御
- preloadedスコープでN+1問題を回避

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

- 認証必須: ログイン済みユーザーのみアクセス可能
- 認可: CardScopedモジュールにより、アクセス可能なカードのコメントのみ閲覧可能
- XSS対策: コメント本文はAction Textでサニタイズ済み

## 備考

- コメントにはメンション機能があり、@ユーザー名でメンション可能
- システムによる自動コメント（role: system）も一覧に含まれる
- コメント本文はリッチテキストで、画像や書式設定が可能

---

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

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

### 推奨読解順序

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

まず、コメントのデータ構造とリレーションを理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | comment.rb | `app/models/comment.rb` | Commentモデルの定義、includes、スコープ |
| 1-2 | schema.rb | `db/schema.rb` | commentsテーブルの構造（252-260行目） |

**読解のコツ**:
- `has_rich_text :body` によりAction Textでリッチテキストを管理
- `has_many :reactions, as: :reactable` でポリモーフィック関連によりリアクションを持つ
- `scope :chronologically` で created_at ASC, id DESC の順序
- `scope :preloaded` で `with_rich_text_body.includes(reactions: :reacter)` をプリロード

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

処理の起点となるコントローラーを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | comments_controller.rb | `app/controllers/cards/comments_controller.rb` | indexアクションの実装（8-10行目） |
| 2-2 | card_scoped.rb | `app/controllers/concerns/card_scoped.rb` | カードスコープの共通処理 |
| 2-3 | routes.rb | `config/routes.rb` | ルーティング定義（99行目） |

**主要処理フロー**:
1. **1行目**: `include CardScoped` によりカードアクセス権限確認を共通化
2. **8-10行目**: `index` アクションでコメント一覧を取得
3. **9行目**: `set_page_and_extract_portion_from @card.comments.chronologically` でページング付きで取得

#### Step 3: ビューレンダリングを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | _comment.html.erb | `app/views/cards/comments/_comment.html.erb` | コメントの部分テンプレート |

**主要処理フロー**:
- **1行目**: `cache comment` でフラグメントキャッシュ
- **6-8行目**: コメント作成者のアバター表示
- **14行目**: コメント作成者名とリンク
- **17-20行目**: 作成日時の表示
- **35-37行目**: コメント本文（`comment.body`）の表示
- **39行目**: リアクション表示（`render "reactions/reactions"`）

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

```
GET /cards/:card_id/comments
    │
    ├─ CardScoped#set_card
    │      └─ Current.user.accessible_cards.find_by!(number: params[:card_id])
    │
    ├─ CardScoped#set_board
    │      └─ @board = @card.board
    │
    └─ Cards::CommentsController#index
           │
           ├─ @card.comments.chronologically
           │      └─ Comment.chronologically
           │             └─ order(created_at: :asc, id: :desc)
           │
           └─ set_page_and_extract_portion_from
                  └─ ページネーション処理
```

### データフロー図

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

GET リクエスト ────────▶ Cards::CommentsController#index
  └─ card_id                   │
                               ├─▶ set_card
                               │      └─▶ @card
                               │
                               ├─▶ @card.comments.chronologically
                               │      └─▶ コメント配列
                               │
                               └─▶ set_page_and_extract_portion_from
                                      │
                                      ▼
                                   @comments
                                      │
                                      ▼
                               _comment.html.erb
                                      │
                                      ▼
                                   HTML
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| comments_controller.rb | `app/controllers/cards/comments_controller.rb` | コントローラー | コメントCRUD処理 |
| card_scoped.rb | `app/controllers/concerns/card_scoped.rb` | Concern | カードスコープ共通処理 |
| comment.rb | `app/models/comment.rb` | モデル | コメントのデータモデル定義 |
| _comment.html.erb | `app/views/cards/comments/_comment.html.erb` | ビュー | コメント部分テンプレート |
| _reactions.html.erb | `app/views/reactions/_reactions.html.erb` | ビュー | リアクション表示テンプレート |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義 |
| schema.rb | `db/schema.rb` | スキーマ | commentsテーブル定義 |
