# 機能設計書 98-未読カウント

## 概要

本ドキュメントは、Chatwoot における未読通知カウント取得機能の設計を記載する。

### 本機能の処理概要

未読カウント機能は、ユーザーの未読通知数を取得する機能である。UI上のバッジ表示や通知アイコンの状態更新に使用される。

**業務上の目的・背景**：ユーザーは常に未対応の通知がどれだけあるかを把握する必要がある。未読カウントをリアルタイムで表示することで、重要な通知の見落としを防ぎ、迅速な対応を促すことができる。

**機能の利用シーン**：
- ダッシュボードのヘッダーで未読通知バッジを表示する
- ポーリングにより定期的に未読数を更新する
- 新しい通知が作成された際にカウントを更新する

**主要な処理内容**：
1. NotificationFinderを使用して未読件数をカウント
2. JSON形式で未読件数を返却

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

**権限による制御**：自分の通知のみカウント対象。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 26 | 通知一覧画面 | 主画面 | 未読通知数の表示 |
| 9 | ダッシュボードホーム画面 | 参照画面 | ヘッダーの通知バッジ表示 |

## 機能種別

データ取得 / カウント処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| なし | - | - | - | - |

### 入力データソース

なし（ユーザー認証情報のみ使用）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| (直接値) | Integer | 未読通知件数 |

### 出力先

API レスポンス（JSON形式）

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ NotificationsController#unread_countがリクエストを受信
2. NotificationFinder初期化
   └─ Current.user, Current.account, params で初期化
3. 未読件数カウント
   └─ notification_finder.unread_count
4. レスポンス返却
   └─ render json: @unread_count
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B{認証確認}
    B -->|未認証| C[401エラー]
    B -->|認証済| D[NotificationFinder初期化]
    D --> E[未読件数カウント]
    E --> F[JSON返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-98-01 | ユーザー制限 | 自分の通知のみカウント対象 | 全操作 |
| BR-98-02 | アカウント制限 | 現在のアカウントの通知のみ対象 | 全操作 |
| BR-98-03 | 未読のみ対象 | read_at IS NULL の通知のみカウント | 全操作 |
| BR-98-04 | スヌーズ除外 | スヌーズ中の通知はカウントから除外 | 全操作 |

### 計算ロジック

未読件数カウント：
```ruby
# type_included?('read')がfalseの場合（デフォルト）
@notifications.count

# type_included?('read')がtrueの場合
@notifications.where(read_at: nil).count
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| unread_count | notifications | SELECT COUNT | 未読件数カウント |

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

#### notifications

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT COUNT | COUNT(*) | user_id = current_user.id AND account_id = current_account.id AND read_at IS NULL AND snoozed_until IS NULL | - |

## エラー処理

### エラーケース一覧

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

### リトライ仕様

特になし。

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

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

## パフォーマンス要件

- COUNTクエリのため高速に処理可能
- インデックス（user_id, account_id, snoozed_until, read_at）を活用
- 頻繁に呼び出されるAPIのため、キャッシュ検討の余地あり

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

- current_user の通知のみカウント
- account_id による所有権チェック

## 備考

このAPIは通知バッジ更新のためにポーリングで頻繁に呼び出される可能性がある。WebSocketによるリアルタイム更新と併用することで、ポーリング頻度を下げることが推奨される。

---

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

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

### 推奨読解順序

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

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

**読解のコツ**:
- **51-54行目**: unread_count アクション - NotificationFinderを使用

**主要処理フロー**:
1. **52行目**: notification_finder.unread_count でカウント取得
2. **53行目**: render json: @unread_count でJSON返却

#### Step 2: Finderロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | notification_finder.rb | `app/finders/notification_finder.rb` | unread_countメソッドの実装 |

**読解のコツ**:
- **17-25行目**: unread_count メソッド - 条件に応じたカウント処理

**主要処理フロー**:
- **18-20行目**: type_included?('read')がtrueの場合、追加でread_at: nilフィルタ
- **22-23行目**: デフォルト（readを含まない場合）は既にフィルタ済みなのでそのままcount
- **47-48行目**: filter_read_notifications - デフォルトでread_at: nilフィルタ適用

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

```
Api::V1::Accounts::NotificationsController
    │
    └─ unread_count
           │
           └─ notification_finder.unread_count
                  │
                  └─ NotificationFinder
                         │
                         ├─ find_all_notifications
                         │      └─ user.notifications.where(account_id:)
                         │
                         ├─ filter_snoozed_notifications
                         │      └─ where(snoozed_until: nil)
                         │
                         ├─ filter_read_notifications
                         │      └─ where(read_at: nil)
                         │
                         └─ unread_count
                                └─ @notifications.count
```

### データフロー図

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

認証情報 ───────────▶ NotificationsController#unread_count
    │                              │
    │                              ▼
    │                    NotificationFinder.new
    │                              │
    │                              ▼
    └────────────────▶ notifications
                              │
                              ├─▶ WHERE user_id = current_user.id
                              │
                              ├─▶ WHERE account_id = current_account.id
                              │
                              ├─▶ WHERE snoozed_until IS NULL
                              │
                              ├─▶ WHERE read_at IS NULL
                              │
                              └─▶ COUNT(*)
                                       │
                                       ▼
                                  { 123 }  (JSON Integer)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| notifications_controller.rb | `app/controllers/api/v1/accounts/notifications_controller.rb` | コントローラー | unread_countアクション |
| notification_finder.rb | `app/finders/notification_finder.rb` | Finder | カウントロジック |
| routes.rb | `config/routes.rb` | 設定 | GET unread_count ルーティング |
