# 機能設計書 79-カスタムフィルタ

## 概要

本ドキュメントは、Chatwootにおけるカスタムフィルタ機能の仕様を定義する機能設計書である。

### 本機能の処理概要

ユーザーが定義した検索条件をカスタムフィルタとして保存・管理する機能。会話、連絡先、レポートに対するフィルタ条件を保存し、繰り返し使用できるようにすることで、日常的な検索・フィルタリング作業を効率化する。

**業務上の目的・背景**：カスタマーサポート業務では、特定の条件（例：未解決かつ高優先度の会話、特定ラベルが付いた連絡先など）で頻繁に検索を行うことが多い。毎回同じ条件を手動で設定するのは非効率であり、設定ミスも発生しやすい。本機能により、よく使う検索条件をカスタムフィルタとして保存し、ワンクリックで適用できるようにする。

**機能の利用シーン**：
- 「未解決かつVIP顧客の会話」をフィルタとして保存
- 「今週作成された高優先度会話」をフィルタとして保存
- 「特定ラベルが付いた連絡先」をセグメントとして保存
- レポートの期間・条件をフィルタとして保存

**主要な処理内容**：
1. カスタムフィルタのCRUD操作（作成・読取・更新・削除）
2. フィルタ条件（query）の保存
3. フィルタタイプ（conversation/contact/report）の設定
4. ユーザーごとのフィルタ管理

**関連システム・外部連携**：
- 会話フィルタリングAPI
- 連絡先フィルタリングAPI
- レポートフィルタリング

**権限による制御**：各ユーザーは自分が作成したフィルタのみ参照・編集・削除可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 14 | カスタムビュー会話一覧 | 主画面 | 保存済みフィルタの適用 |
| 21 | セグメント別連絡先一覧 | 主画面 | セグメントフィルタの適用 |

## 機能種別

CRUD操作 / ユーザー設定管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | String | Yes | フィルタ名 | 必須 |
| filter_type | String | No | フィルタタイプ | conversation/contact/report、デフォルトconversation |
| query | JSON | Yes | フィルタ条件 | 必須 |

### クエリ（query）の構造例

```json
{
  "payload": [
    {
      "attribute_key": "status",
      "filter_operator": "equal_to",
      "values": ["open"],
      "query_operator": "and"
    },
    {
      "attribute_key": "priority",
      "filter_operator": "equal_to",
      "values": ["urgent"]
    }
  ]
}
```

| フィールド | 型 | 説明 |
|-----------|-----|------|
| attribute_key | String | フィルタ対象の属性 |
| filter_operator | String | 比較演算子 |
| values | Array | 比較値 |
| query_operator | String | 論理演算子（and/or） |

### 入力データソース

- 管理画面からのフィルタ保存操作
- REST API経由

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | Integer | フィルタID |
| name | String | フィルタ名 |
| filter_type | String | フィルタタイプ |
| query | JSON | フィルタ条件 |
| created_at | DateTime | 作成日時 |
| updated_at | DateTime | 更新日時 |

### 出力先

- APIレスポンス（JSON形式）
- データベース（custom_filtersテーブル）

## 処理フロー

### 処理シーケンス

```
1. フィルタ作成リクエスト受信
   └─ POST /api/v1/accounts/:account_id/custom_filters
2. 権限チェック
   └─ check_authorization
3. フィルタ数上限チェック
   └─ validate_number_of_filters
4. フィルタ保存
   └─ custom_filtersテーブルへINSERT（user_idを自動設定）
5. レスポンス返却
```

### フローチャート

```mermaid
flowchart TD
    A[フィルタ作成リクエスト] --> B[権限チェック]
    B --> C{認証済み?}
    C -->|No| D[401 Unauthorized]
    C -->|Yes| E[フィルタ数チェック]
    E --> F{上限以下?}
    F -->|No| G[422 Unprocessable Entity]
    F -->|Yes| H[フィルタ保存]
    H --> I{保存成功?}
    I -->|No| J[エラーレスポンス]
    I -->|Yes| K[成功レスポンス]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-79-01 | 上限チェック | ユーザーあたりMAX_CUSTOM_FILTERS_PER_USER（1000件）まで | フィルタ作成時 |
| BR-79-02 | ユーザー所有 | フィルタは作成したユーザーのみ参照・編集・削除可能 | 常時 |
| BR-79-03 | デフォルトタイプ | filter_type未指定時はconversationが設定 | 作成時 |
| BR-79-04 | フィルタタイプ別取得 | indexではfilter_typeパラメータでフィルタ可能 | 一覧取得時 |

### 計算ロジック

フィルタ数上限チェック：
```ruby
def validate_number_of_filters
  return true if account.custom_filters.where(user_id: user_id).size < Limits::MAX_CUSTOM_FILTERS_PER_USER
  errors.add :account_id, I18n.t('errors.custom_filters.number_of_records')
end
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| フィルタ作成 | custom_filters | INSERT | 新規フィルタレコードの挿入 |
| フィルタ更新 | custom_filters | UPDATE | 既存フィルタの更新 |
| フィルタ削除 | custom_filters | DELETE | フィルタの削除 |
| フィルタ一覧取得 | custom_filters | SELECT | ユーザー・タイプでフィルタして取得 |

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

#### custom_filters

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | name, filter_type, query | リクエストパラメータ | user_id, account_idは自動設定 |
| UPDATE | name, filter_type, query | リクエストパラメータ | 既存レコードを更新 |
| DELETE | - | id = :id AND user_id = current_user.id | 自分のフィルタのみ削除可能 |
| SELECT (index) | * | user_id = current_user.id AND filter_type = :filter_type | タイプ別取得 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 422 | Unprocessable Entity | フィルタ数上限超過、バリデーションエラー | 不要なフィルタを削除 |
| 404 | Not Found | 指定フィルタが存在しないまたは権限がない | 正しいIDを指定 |
| 401 | Unauthorized | 未認証 | ログイン後に再試行 |

### リトライ仕様

特になし（CRUD操作のみ）

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

単一レコード操作のため、ActiveRecordの標準トランザクション制御に依存。

## パフォーマンス要件

- フィルタ一覧取得：100ms以内
- フィルタ作成/更新：200ms以内

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

- ユーザーは自分のフィルタのみアクセス可能
- fetch_custom_filterで user_id = Current.user を条件に取得
- 他ユーザーのフィルタにはアクセス不可

## 備考

- MAX_CUSTOM_FILTERS_PER_USER = 1000（lib/limits.rb）
- queryはJSONB型で保存され、フロントエンドでパース・適用される
- フィルタの適用（実際の検索実行）は別機能（会話フィルタリングAPI等）で処理

---

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

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

### 推奨読解順序

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

CustomFilterモデルの構造を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | custom_filter.rb | `app/models/custom_filter.rb` | モデル定義、バリデーション、enum |

**読解のコツ**:
- **1-17行目**: スキーマ情報でカラム定義確認
- **19-20行目**: belongs_to :user, :accountで所有関係
- **22行目**: `enum filter_type: { conversation: 0, contact: 1, report: 2 }`
- **23行目**: validate :validate_number_of_filters
- **25-29行目**: フィルタ数上限チェックの実装

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

APIコントローラーのCRUD操作を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | custom_filters_controller.rb | `app/controllers/api/v1/accounts/custom_filters_controller.rb` | CRUD操作の実装 |

**主要処理フロー**:
1. **11-15行目**: createアクションでuser: Current.userを設定
2. **17-19行目**: updateアクション
3. **21-24行目**: destroyアクションでhead :no_content
4. **29-34行目**: fetch_custom_filtersでuser, filter_typeでフィルタ
5. **36-40行目**: fetch_custom_filterでuser条件を追加

#### Step 3: 上限設定を確認する

Limits定数を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | limits.rb | `lib/limits.rb` | MAX_CUSTOM_FILTERS_PER_USER定数 |

**読解のコツ**:
- **11行目**: `MAX_CUSTOM_FILTERS_PER_USER = 1000`

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

```
CustomFiltersController
    │
    ├─ index: フィルタ一覧取得
    │      └─ fetch_custom_filters
    │             └─ where(user: Current.user, filter_type: params[:filter_type])
    │
    ├─ create: フィルタ作成
    │      ├─ check_authorization
    │      └─ Current.account.custom_filters.create!(params.merge(user: Current.user))
    │             └─ validate_number_of_filters
    │
    ├─ update: フィルタ更新
    │      └─ @custom_filter.update!(params)
    │
    └─ destroy: フィルタ削除
           └─ @custom_filter.destroy!
                  └─ head :no_content
```

### データフロー図

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

ユーザー設定               フィルタ保存                    DBへ永続化
(name, filter_type, ───▶ CustomFiltersController ───▶ custom_filtersテーブル
 query)                     │
                            ├─ user_id = Current.user.id 自動設定
                            └─ validate_number_of_filters

フィルタ一覧取得           条件でフィルタ                  JSONレスポンス
(filter_type)      ───▶ index ───────────────────▶ フィルタ配列
                            │
                            └─ user_id, filter_typeで絞り込み
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| custom_filter.rb | `app/models/custom_filter.rb` | モデル | データ構造・バリデーション |
| custom_filters_controller.rb | `app/controllers/api/v1/accounts/custom_filters_controller.rb` | コントローラー | CRUD API |
| _custom_filter.json.jbuilder | `app/views/api/v1/models/_custom_filter.json.jbuilder` | ビュー | JSONレスポンス |
| show.json.jbuilder | `app/views/api/v1/accounts/custom_filters/show.json.jbuilder` | ビュー | 詳細レスポンス |
| limits.rb | `lib/limits.rb` | 設定 | MAX_CUSTOM_FILTERS_PER_USER定数 |
