# 機能設計書 52-コメントのリアクション削除

## 概要

本ドキュメントは、Fizzyアプリケーションにおけるコメントへのリアクション削除機能の詳細設計を記述する。

### 本機能の処理概要

コメントに付けたリアクションを削除することで、誤って追加したリアクションや不要になったリアクションを取り消す機能である。

**業務上の目的・背景**：ユーザーが誤ってリアクションを追加した場合や、状況の変化によりリアクションが不適切になった場合に、それを取り消す手段が必要となる。本機能により、ユーザーは自身のリアクションを削除でき、コミュニケーションの正確性を維持できる。

**機能の利用シーン**：カードコメント詳細画面において、過去に追加したリアクションを確認し、不要なリアクションを削除する場合に使用される。例えば、誤って異なる絵文字を選択してしまった場合や、議論の方向性が変わり当初のリアクションが適切でなくなった場合などに利用する。

**主要な処理内容**：
1. ユーザーが自分のリアクションの削除ボタンをクリック
2. リアクターがCurrentユーザーであることを検証
3. 検証成功後、リアクションレコードをデータベースから削除
4. Turbo Streamで画面がリアルタイム更新される

**関連システム・外部連携**：Action Cable経由でリアルタイム更新が行われ、他のユーザーの画面からもリアクションが削除される。

**権限による制御**：リアクションを追加した本人（reacter）のみが削除可能。他のユーザーのリアクションは削除できない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 30 | カードコメント詳細画面 | 主画面 | コメントに付けたリアクションを削除 |

## 機能種別

CRUD操作（DELETE）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| card_id | String(Number) | Yes | 対象カードの番号 | カード番号として存在すること |
| comment_id | UUID | Yes | 対象コメントのID | コメントIDとして存在すること |
| id | UUID | Yes | 削除対象リアクションのID | リアクションIDとして存在すること |

### 入力データソース

画面操作（削除ボタンクリック）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| なし | - | 削除成功時はコンテンツなし |

### 出力先

- 画面表示（Turbo Stream - 要素削除）
- HTTPレスポンス（204 No Content）

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ DELETE /cards/:card_id/comments/:comment_id/reactions/:id
2. 認証・認可チェック
   └─ CardScopedコンサーンによるカードアクセス権確認
3. コメント取得
   └─ 指定されたcomment_idでコメントを検索
4. リアクション取得
   └─ 指定されたidでリアクションを検索
5. 権限チェック
   └─ Current.userがreacterと一致することを確認
6. リアクション削除
   └─ @reaction.destroyでリアクションを削除
7. レスポンス返却
   └─ Turbo Stream/JSONでレスポンスを返す
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B[カードアクセス権確認]
    B --> C{アクセス権あり?}
    C -->|No| D[403 Forbidden]
    C -->|Yes| E[コメント取得]
    E --> F{コメント存在?}
    F -->|No| G[404 Not Found]
    F -->|Yes| H[リアクション取得]
    H --> I{リアクション存在?}
    I -->|No| J[404 Not Found]
    I -->|Yes| K{reacterがCurrentユーザー?}
    K -->|No| L[403 Forbidden]
    K -->|Yes| M[リアクション削除]
    M --> N{リクエスト形式}
    N -->|Turbo Stream| O[Turbo Stream返却]
    N -->|JSON| P[204 No Content返却]
    O --> Q[終了]
    P --> Q
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-52-01 | 削除権限 | リアクションを追加した本人（reacter）のみ削除可能 | 常時 |
| BR-52-02 | 物理削除 | リアクションは物理削除される（論理削除ではない） | リアクション削除時 |

### 計算ロジック

該当なし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| リアクション削除 | reactions | DELETE | リアクションレコードを物理削除 |

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

#### reactions

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | id | パラメータで指定されたID | 主キーで特定 |
| DELETE | reactable_type | "Comment" | ポリモーフィック関連 |
| DELETE | reactable_id | comment_id | コメントのID |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 403 | Forbidden | カードへのアクセス権がない | エラーページ表示 |
| 403 | Forbidden | リアクターがCurrentユーザーでない | head :forbidden |
| 404 | Not Found | カード、コメント、またはリアクションが存在しない | エラーページ表示 |

### リトライ仕様

リトライは不要（即時エラー返却）

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

リアクション削除はRailsのデフォルトトランザクション内で実行される。destroyは単一レコードの削除であり、追加のトランザクション制御は不要。

## パフォーマンス要件

- レスポンス時間: 200ms以内

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

- ログイン必須（ApplicationControllerで制御）
- CardScopedコンサーンによるカードアクセス権チェック
- ensure_permission_to_administer_reactionによるリアクター権限チェック
- CSRFトークン検証（Railsデフォルト）

## 備考

- 削除されたリアクションは復元できない
- 削除後、Turbo Streamにより画面から即座にリアクションが消える

---

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

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

### 推奨読解順序

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

まず、リアクションのデータモデルと関連を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | reaction.rb | `app/models/reaction.rb` | Reactionモデルの構造、belongs_to関連 |

**読解のコツ**:
- `belongs_to :reacter`でリアクションを追加したユーザーを保持
- 削除時は特別なコールバックはなく、シンプルにDELETEされる

**主要処理フロー**:
- **4行目**: reacterの関連定義

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

リクエストを受け取るコントローラーの処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | reactions_controller.rb | `app/controllers/cards/comments/reactions_controller.rb` | destroyアクションの処理フロー、権限チェック |

**主要処理フロー**:
- **7-10行目**: destroyアクション用のbefore_action定義
- **29-35行目**: destroyアクション（リアクション削除とレスポンス返却）
- **47-48行目**: set_reactionメソッド（リアクションの取得）
- **51-52行目**: ensure_permission_to_administer_reactionメソッド（権限チェック）

**読解のコツ**:
- `with_options only: :destroy`でdestroy専用のbefore_actionを定義
- `head :forbidden`で権限エラー時に403を返す

#### Step 3: 権限チェックの仕組みを理解する

削除権限の検証ロジックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | reactions_controller.rb | `app/controllers/cards/comments/reactions_controller.rb` | ensure_permission_to_administer_reactionメソッド |

**主要処理フロー**:
- **51-52行目**: Current.userとreacterの比較による権限チェック

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

```
Cards::Comments::ReactionsController#destroy
    │
    ├─ [before_action] CardScoped#set_card
    │      └─ Current.user.accessible_cards.find_by!(number: params[:card_id])
    │
    ├─ [before_action] CardScoped#set_board
    │      └─ @board = @card.board
    │
    ├─ [before_action] #set_comment
    │      └─ @card.comments.find(params[:comment_id])
    │
    ├─ [before_action] #set_reactable
    │      └─ @reactable = @comment
    │
    ├─ [before_action] #set_reaction
    │      └─ @reactable.reactions.find(params[:id])
    │
    ├─ [before_action] #ensure_permission_to_administer_reaction
    │      └─ head :forbidden if Current.user != @reaction.reacter
    │
    └─ @reaction.destroy
```

### データフロー図

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

card_id     ───▶ CardScoped#set_card    ───▶ @card
comment_id  ───▶ #set_comment           ───▶ @comment
                       │
                       ▼
                 #set_reactable         ───▶ @reactable = @comment
                       │
                       ▼
id          ───▶ #set_reaction          ───▶ @reaction
                       │
                       ▼
                 #ensure_permission     ───▶ 403 or continue
                       │
                       ▼
                 @reaction.destroy      ───▶ reactions (DELETE)
                       │
                       ▼
                 Turbo Stream / JSON    ───▶ ブラウザ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| reactions_controller.rb | `app/controllers/cards/comments/reactions_controller.rb` | コントローラー | コメントリアクションのCRUD処理 |
| reaction.rb | `app/models/reaction.rb` | モデル | リアクションのデータモデル |
| card_scoped.rb | `app/controllers/concerns/card_scoped.rb` | コンサーン | カードスコープの共通処理 |
| destroy.turbo_stream.erb | `app/views/reactions/destroy.turbo_stream.erb` | ビュー | Turbo Streamレスポンス（要素削除） |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義 |
| schema.rb | `db/schema.rb` | スキーマ | データベーススキーマ定義 |
