# 機能設計書 59-通知一括既読

## 概要

本ドキュメントは、Fizzyアプリケーションにおける通知一括既読機能の詳細設計を記述する。

### 本機能の処理概要

複数の通知を一括で既読にすることで、大量の未読通知を効率的に処理する機能である。

**業務上の目的・背景**：長期間ログインしていなかった場合や、プロジェクトが活発な時期には多数の未読通知が溜まることがある。一つずつ既読にするのは非効率なため、本機能によりすべての未読通知をワンクリックで既読にでき、作業効率を向上させる。

**機能の利用シーン**：通知一覧画面や通知トレイで「すべて既読にする」ボタンをクリックして実行する。休暇明けや長期不在後に大量の通知が溜まっている場合、過去のプロジェクトに関する通知をまとめて片付けたい場合などに利用する。

**主要な処理内容**：
1. ユーザーが「すべて既読にする」ボタンをクリック
2. ユーザーの未読通知をすべて取得
3. 各通知のread_atに現在時刻を設定し、unread_countを0にする
4. 通知一覧画面にリダイレクト（またはOK返却）

**関連システム・外部連携**：Action Cableによるリアルタイム更新

**権限による制御**：ユーザー固有の未読通知のみが一括既読される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 33 | 通知一覧画面 | 主画面 | 複数の通知を一括で既読にする |

## 機能種別

CRUD操作（UPDATE - バッチ処理）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| from_tray | Boolean | No | 通知トレイからのリクエストか | - |

### 入力データソース

画面操作（一括既読ボタンクリック）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| なし | - | 処理成功時はリダイレクトまたはステータスコードのみ |

### 出力先

- 画面リダイレクト（通知一覧画面）
- HTTPレスポンス（200 OK - トレイから / 204 No Content - JSON時）

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ POST /notifications/bulk_reading
2. 未読通知一括既読
   └─ Current.user.notifications.unread.read_all
      └─ 各通知に対してreadメソッドを実行
3. レスポンス返却
   └─ トレイから: 200 OK
   └─ 通常: 通知一覧画面にリダイレクト
   └─ JSON: 204 No Content
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B[未読通知取得]
    B --> C[read_all実行]
    C --> D[各通知をread]
    D --> E{リクエスト形式}
    E -->|HTML + from_tray| F[200 OK返却]
    E -->|HTML| G[通知一覧にリダイレクト]
    E -->|JSON| H[204 No Content返却]
    F --> I[終了]
    G --> I
    H --> I
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-59-01 | 一括既読 | ユーザーのすべての未読通知を既読にする | 常時 |
| BR-59-02 | 逐次処理 | 各通知に対して個別にreadメソッドを呼び出す | 常時 |
| BR-59-03 | トレイ対応 | from_trayパラメータがある場合はリダイレクトせず200 OK | トレイからの呼び出し時 |

### 計算ロジック

該当なし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 一括既読更新 | notifications | UPDATE | 複数の通知のread_at、unread_countを更新 |

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

#### notifications

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | user_id | Current.user.id | ユーザー制限 |
| SELECT | read_at | IS NULL | 未読フィルタ |
| UPDATE | read_at | Time.current | 各通知ごとに現在時刻 |
| UPDATE | unread_count | 0 | 未読カウント |
| UPDATE | updated_at | 現在時刻 | 自動更新 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 空処理 | 未読通知がない場合 | 正常終了（何も更新しない） |

### リトライ仕様

リトライは不要

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

各通知のupdate!は個別のトランザクションで実行される（read_allメソッドがeach(&:read)を使用）。大量の未読通知がある場合はパフォーマンスに影響する可能性がある。

## パフォーマンス要件

- レスポンス時間: 未読通知数に依存（1000件で約2-3秒を目安）
- 各通知ごとにブロードキャストが発生するため、大量更新時は負荷に注意

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

- ログイン必須（ApplicationControllerで制御）
- Current.user.notificationsスコープによりユーザー固有の通知のみ更新可能
- CSRFトークン検証（Railsデフォルト）

## 備考

- read_allはeach(&:read)で実装されているため、N回のUPDATEが発生する
- 大量の未読通知がある場合はパフォーマンスに影響する可能性がある
- 通知トレイからの呼び出し時は画面リダイレクトではなく200 OKを返す

---

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

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

### 推奨読解順序

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

まず、通知モデルのread_allクラスメソッドを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | notification.rb | `app/models/notification.rb` | read_allクラスメソッド、readインスタンスメソッド |

**読解のコツ**:
- `read_all`はクラスメソッドで`all.each(&:read)`を実行
- 各通知に対してreadを呼び出すため、N回のUPDATEが発生

**主要処理フロー**:
- **32-34行目**: read_allクラスメソッド
- **41-43行目**: readインスタンスメソッド

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | bulk_readings_controller.rb | `app/controllers/notifications/bulk_readings_controller.rb` | createアクションの処理フロー |

**主要処理フロー**:
- **2-14行目**: createアクション（一括既読処理）
- **3行目**: unread.read_allの呼び出し
- **6-10行目**: HTMLレスポンス（トレイからかどうかで分岐）
- **13行目**: JSONレスポンス
- **17-19行目**: from_tray?プライベートメソッド

**読解のコツ**:
- `from_tray?`でトレイからのリクエストを判定
- トレイからの場合はhead :ok、そうでなければリダイレクト

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

```
Notifications::BulkReadingsController#create
    │
    └─ Current.user.notifications.unread.read_all
           │
           └─ Notification.read_all
                  │
                  └─ all.each(&:read)
                         │
                         └─ [各通知] Notification#read
                                │
                                └─ update!(read_at: Time.current, unread_count: 0)
                                       │
                                       └─ [after_update_commit] broadcast_update
```

### データフロー図

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

POST /notifications/bulk_reading
    │
    ▼
from_tray パラメータ
    │
    ▼
Current.user.notifications.unread
    │
    ▼
read_all
    │
    ├─ 通知1.read ───▶ UPDATE
    ├─ 通知2.read ───▶ UPDATE
    ├─ 通知3.read ───▶ UPDATE
    └─ ...
    │
    ▼
respond_to
    │
    ├─ from_tray? ───▶ 200 OK
    ├─ html       ───▶ redirect_to notifications_path
    └─ json       ───▶ 204 No Content
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| bulk_readings_controller.rb | `app/controllers/notifications/bulk_readings_controller.rb` | コントローラー | 一括既読処理 |
| notification.rb | `app/models/notification.rb` | モデル | 通知のデータモデル、read_allメソッド |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義 |
| schema.rb | `db/schema.rb` | スキーマ | notificationsテーブル定義 |
