# 機能設計書 97-一括既読

## 概要

本ドキュメントは、Chatwoot における通知一括既読機能の設計を記載する。

### 本機能の処理概要

一括既読機能は、ユーザーの未読通知を一括で既読状態にマークする機能である。すべての通知を一括既読にするか、特定の会話に関連する通知のみを一括既読にするかを選択できる。

**業務上の目的・背景**：大量の通知が溜まった際に、一件ずつ既読にするのは非効率である。一括既読機能により、通知の整理を効率化し、本当に重要な通知に集中できるようになる。また、特定の会話に関連する通知のみを一括既読にすることで、他の通知を見逃すリスクを軽減できる。

**機能の利用シーン**：
- 長期休暇後に溜まった通知を一括で処理する
- 特定の会話の対応完了後、その会話に関連する通知を一括既読にする
- 毎日の業務開始時に前日の通知を一括で既読にする

**主要な処理内容**：
1. 対象通知の特定（全通知 or 特定会話の通知）
2. 未読通知の一括read_at更新

**関連システム・外部連携**：特になし（内部データ操作のみ）

**権限による制御**：自分の通知のみ操作可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 26 | 通知一覧画面 | 主画面 | 「すべて既読にする」ボタンの実行 |

## 機能種別

バルク操作 / データ一括更新

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| primary_actor_type | String | No | 主体タイプ | PRIMARY_ACTORS（Conversation）に含まれる |
| primary_actor_id | Integer | No | 主体ID | primary_actor_type指定時は必須 |

### 入力データソース

画面入力（API経由）

## 出力仕様

### 出力データ

レスポンスボディは空。HTTPステータスコード200（OK）を返却。

### 出力先

HTTPレスポンス

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ NotificationsController#read_allがリクエストを受信
2. 対象の特定
   ├─ primary_actor指定あり: 特定の会話に関連する通知
   └─ primary_actor指定なし: すべての通知
3. 一括更新実行
   └─ update_all(read_at: DateTime.now.utc)
4. レスポンス返却
   └─ head :ok
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B{認証確認}
    B -->|未認証| C[401エラー]
    B -->|認証済| D{primary_actor_type指定?}
    D -->|あり| E{PRIMARY_ACTORSに含まれる?}
    E -->|いいえ| F[対象なし処理終了]
    E -->|はい| G[primary_actor取得]
    G --> H{primary_actor存在?}
    H -->|なし| F
    H -->|あり| I[特定会話の未読通知を一括更新]
    D -->|なし| J[すべての未読通知を一括更新]
    I --> K[200 OK]
    J --> K
    F --> K
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-97-01 | ユーザー制限 | 自分の通知のみ操作可能 | 全操作 |
| BR-97-02 | アカウント制限 | 現在のアカウントの通知のみ対象 | 全操作 |
| BR-97-03 | 未読のみ対象 | read_at IS NULL の通知のみ対象 | 全操作 |
| BR-97-04 | PRIMARY_ACTORS制限 | primary_actor_typeはConversationのみ許可 | primary_actor指定時 |

### 計算ロジック

特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| read_all | notifications | UPDATE | read_at一括更新 |

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

#### notifications

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE (全体) | read_at | DateTime.now.utc | user_id = current_user.id AND account_id = current_account.id AND read_at IS NULL |
| UPDATE (会話指定) | read_at | DateTime.now.utc | 上記 + primary_actor_type = 'Conversation' AND primary_actor_id = params[:primary_actor_id] |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 401 | Unauthorized | 未認証 | ログインが必要 |

### リトライ仕様

特になし。

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

update_allは単一SQLで実行されるため、暗黙のトランザクション内で処理される。

## パフォーマンス要件

- update_allによる単一SQLでの一括更新
- インデックス（user_id, account_id, snoozed_until, read_at）を活用

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

- current_user.notifications で自分の通知のみアクセス
- account_id による所有権チェック

## 備考

RuboCop の Rails/SkipsModelValidations を一時的に無効化してupdate_allを使用している。これはパフォーマンス上の理由による。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | notifications_controller.rb | `app/controllers/api/v1/accounts/notifications_controller.rb` | read_allアクションの実装 |

**読解のコツ**:
- **6行目**: before_action :set_primary_actor で primary_actor を設定
- **15-25行目**: read_all アクション - 一括既読処理
- **64-69行目**: set_primary_actor メソッド - primary_actor_type検証と取得

**主要処理フロー**:
1. **17-19行目**: @primary_actor が存在する場合、その会話に関連する未読通知のみ対象
2. **20-21行目**: @primary_actor が存在しない場合、すべての未読通知が対象
3. **22行目**: update_all(read_at: DateTime.now.utc) で一括更新
4. **24行目**: head :ok でレスポンス返却

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | notification.rb | `app/models/notification.rb` | PRIMARY_ACTORSの定義 |

**読解のコツ**:
- **56行目**: PRIMARY_ACTORS = ['Conversation'].freeze

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

```
Api::V1::Accounts::NotificationsController
    │
    ├─ before_action :set_primary_actor
    │      │
    │      ├─ params[:primary_actor_type] 確認
    │      │
    │      ├─ Notification::PRIMARY_ACTORS.include? 確認
    │      │
    │      └─ params[:primary_actor_type].safe_constantize.find_by
    │
    └─ read_all
           │
           ├─ @primary_actor 存在する場合
           │      └─ current_user.notifications
           │             .where(account_id:, primary_actor:, read_at: nil)
           │             .update_all(read_at: now)
           │
           └─ @primary_actor 存在しない場合
                  └─ current_user.notifications
                         .where(account_id:, read_at: nil)
                         .update_all(read_at: now)
```

### データフロー図

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

primary_actor_type ──────┐
                         ├──▶ NotificationsController#read_all
primary_actor_id ────────┘               │
                                         ▼
                               set_primary_actor
                                         │
                         ┌───────────────┼───────────────┐
                         ▼               ▼               ▼
                   @primary_actor    @primary_actor   無効なtype
                      あり              なし           (スキップ)
                         │               │
                         ▼               ▼
                特定会話の通知       全通知
                     WHERE             WHERE
               primary_actor=X       (all)
                         │               │
                         └───────┬───────┘
                                 ▼
                    UPDATE notifications
                    SET read_at = now()
                    WHERE read_at IS NULL
                                 │
                                 ▼
                           head :ok
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| notifications_controller.rb | `app/controllers/api/v1/accounts/notifications_controller.rb` | コントローラー | read_allアクション |
| notification.rb | `app/models/notification.rb` | モデル | PRIMARY_ACTORS定義 |
| routes.rb | `config/routes.rb` | 設定 | POST read_all ルーティング |
