# 機能設計書 24-割り当てポリシー

## 概要

本ドキュメントは、Chatwootにおけるインボックス毎の割り当てポリシー設定機能について記述する。この機能は、会話の自動割り当てに関するルール（割り当て順序、優先度、公平分配制限等）を定義し、インボックスに適用する。

### 本機能の処理概要

**業務上の目的・背景**：カスタマーサポートチームにおいて、会話の割り当て方法を一元的に管理し、複数のインボックスで共通のポリシーを適用することで、運用の標準化と効率化を実現する。公平分配制限により、特定のエージェントに負荷が集中することを防ぎ、チーム全体の生産性を最適化する。

**機能の利用シーン**：
- 割り当てポリシーの作成・編集・削除
- インボックスへのポリシー適用
- ポリシーに基づく自動割り当ての実行
- 複数インボックスで同一ポリシーを共有

**主要な処理内容**：
1. 割り当てポリシーの作成（名前、割り当て順序、会話優先度、公平分配設定）
2. ポリシーのインボックスへの関連付け（1インボックス = 1ポリシー）
3. 自動割り当て時のポリシー参照（レート制限、優先度順序）
4. ポリシー適用インボックスの一覧表示

**関連システム・外部連携**：
- 自動割り当てサービス（AutoAssignment::AssignmentService）
- レート制限機能（AutoAssignment::RateLimiter）

**権限による制御**：割り当てポリシーの作成・編集・削除は管理者権限を持つユーザーのみ実行可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 80 | 割り当てポリシー一覧画面 | 主画面 | ポリシーの一覧表示・作成・編集・削除 |
| 81 | エージェント割り当て一覧 | 参照画面 | ポリシー適用状況の確認 |
| 82 | エージェント割り当て作成 | 補助画面 | 新規ポリシー作成 |
| 83 | エージェント割り当て編集 | 補助画面 | 既存ポリシー編集 |

## 機能種別

CRUD操作 / 設定管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | String | Yes | ポリシー名 | 必須、アカウント内でユニーク |
| description | Text | No | ポリシーの説明 | - |
| assignment_order | Integer | No | 割り当て順序 | round_robin: 0 |
| conversation_priority | Integer | No | 会話優先度 | earliest_created: 0, longest_waiting: 1 |
| fair_distribution_limit | Integer | No | 公平分配の上限数 | 1以上の数値（デフォルト: 100） |
| fair_distribution_window | Integer | No | 公平分配の時間枠（秒） | 1以上の数値（デフォルト: 3600） |
| enabled | Boolean | No | 有効/無効 | デフォルト: true |

### 入力データソース

- 画面入力: 割り当てポリシー設定画面から管理者が設定
- APIエンドポイント: `/api/v1/accounts/:account_id/assignment_policies`

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | BigInt | ポリシーID |
| name | String | ポリシー名 |
| description | Text | 説明 |
| assignment_order | String | 割り当て順序（enum値） |
| conversation_priority | String | 会話優先度（enum値） |
| fair_distribution_limit | Integer | 公平分配上限 |
| fair_distribution_window | Integer | 公平分配時間枠 |
| enabled | Boolean | 有効フラグ |

### 出力先

- DBテーブル: assignment_policies
- APIレスポンス: ポリシー情報JSON

## 処理フロー

### 処理シーケンス

```
1. ポリシー作成
   └─ POST /api/v1/accounts/:account_id/assignment_policies
   └─ バリデーション（名前必須・ユニーク、数値バリデーション）
   └─ assignment_policiesテーブルにINSERT

2. ポリシー更新
   └─ PATCH /api/v1/accounts/:account_id/assignment_policies/:id
   └─ 対象ポリシーを取得・更新

3. ポリシー削除
   └─ DELETE /api/v1/accounts/:account_id/assignment_policies/:id
   └─ 関連するinbox_assignment_policiesも削除（dependent: :destroy）

4. インボックスへの適用
   └─ POST /api/v1/accounts/:account_id/inboxes/:inbox_id/assignment_policy
   └─ 既存のinbox_assignment_policyがあれば削除
   └─ 新しいinbox_assignment_policyを作成

5. インボックスからの解除
   └─ DELETE /api/v1/accounts/:account_id/inboxes/:inbox_id/assignment_policy
   └─ inbox_assignment_policyを削除
```

### フローチャート

```mermaid
flowchart TD
    A[ポリシー操作] --> B{操作種別}
    B -->|作成| C[パラメータ受け取り]
    B -->|更新| D[ポリシー取得]
    B -->|削除| E[ポリシー取得]
    B -->|インボックス適用| F[インボックス・ポリシー取得]

    C --> G{バリデーション}
    G -->|OK| H[DBに保存]
    G -->|NG| I[エラー返却]

    D --> J[パラメータ受け取り]
    J --> G

    E --> K[依存レコード削除]
    K --> L[ポリシー削除]

    F --> M{既存関連あり?}
    M -->|Yes| N[既存関連削除]
    M -->|No| O[新規関連作成]
    N --> O

    H --> P[完了]
    L --> P
    O --> P
    I --> P
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-24-01 | ポリシー名ユニーク | 同一アカウント内でポリシー名は一意 | 作成・更新時 |
| BR-24-02 | 1インボックス1ポリシー | インボックスには1つのポリシーのみ適用可能 | インボックス適用時 |
| BR-24-03 | ポリシー共有 | 複数のインボックスで同一ポリシーを共有可能 | 常時 |
| BR-24-04 | 公平分配制限 | fair_distribution_limitは1以上の正の整数 | 作成・更新時 |
| BR-24-05 | 公平分配時間枠 | fair_distribution_windowは1以上の正の整数（秒） | 作成・更新時 |

### 計算ロジック

**公平分配の適用**:
- 時間枠（fair_distribution_window秒）内に、エージェントへの割り当て数がfair_distribution_limitを超えないように制限
- AutoAssignment::RateLimiterで判定

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| ポリシー作成 | assignment_policies | INSERT | 新規ポリシーレコード作成 |
| ポリシー更新 | assignment_policies | UPDATE | 既存ポリシーレコード更新 |
| ポリシー削除 | assignment_policies | DELETE | ポリシーレコード削除 |
| ポリシー削除 | inbox_assignment_policies | DELETE | 関連する中間テーブルレコード削除 |
| インボックス適用 | inbox_assignment_policies | INSERT | 関連レコード作成 |
| インボックス解除 | inbox_assignment_policies | DELETE | 関連レコード削除 |

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

#### assignment_policies

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT/UPDATE | name | ポリシー名 | 必須、アカウント内ユニーク |
| INSERT/UPDATE | description | 説明文 | オプション |
| INSERT/UPDATE | assignment_order | 0 (round_robin) | enum |
| INSERT/UPDATE | conversation_priority | 0 (earliest_created) / 1 (longest_waiting) | enum |
| INSERT/UPDATE | fair_distribution_limit | 1以上の整数 | デフォルト: 100 |
| INSERT/UPDATE | fair_distribution_window | 1以上の整数（秒） | デフォルト: 3600 |
| INSERT/UPDATE | enabled | true/false | デフォルト: true |

#### inbox_assignment_policies

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | inbox_id | 関連インボックスID | ユニーク制約 |
| INSERT | assignment_policy_id | 関連ポリシーID | - |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | RecordNotFound | 指定されたポリシーが存在しない | 404エラーを返却 |
| - | RecordInvalid | バリデーションエラー | 422エラーとエラー詳細を返却 |
| - | NotFound | インボックスにポリシーが未設定 | "Assignment policy not found"エラーを返却 |

### リトライ仕様

リトライ不要（同期処理）

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

ポリシー作成・更新・削除はActiveRecordの標準的なトランザクション処理に従う。インボックス適用時の既存関連削除と新規作成は個別のトランザクションで実行。

## パフォーマンス要件

- インデックス: account_id、(account_id, name)ユニーク、enabled
- ポリシー参照: 自動割り当て時にinbox経由で取得

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

- Punditポリシーによる認可チェック（AssignmentPolicy）
- 管理者権限のみ操作可能
- アカウント間のデータ分離

## 備考

- OSSではassignment_orderはround_robinのみ。Enterprise版で追加の順序が利用可能
- Enterprise版ではConcerns::AssignmentPolicyで拡張される

---

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

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

### 推奨読解順序

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

割り当てポリシーのモデル構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | assignment_policy.rb | `app/models/assignment_policy.rb` | スキーマ、バリデーション、enum定義 |
| 1-2 | inbox_assignment_policy.rb | `app/models/inbox_assignment_policy.rb` | 中間テーブル、ユニーク制約 |

**読解のコツ**:
- **1-22行目** (assignment_policy): スキーマ定義でカラム構成を確認
- **28-30行目**: バリデーションルール（名前必須・ユニーク、数値バリデーション）
- **32行目**: conversation_priorityのenum定義
- **34行目**: assignment_orderのenum（OSS版はround_robinのみ）

**主要処理フロー**:
- **24行目**: belongs_to :account でアカウント所属
- **25-26行目**: has_many :inboxes through: :inbox_assignment_policies

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

APIコントローラーの構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | assignment_policies_controller.rb | `app/controllers/api/v1/accounts/assignment_policies_controller.rb` | ポリシーCRUD |
| 2-2 | inboxes/assignment_policies_controller.rb | `app/controllers/api/v1/accounts/inboxes/assignment_policies_controller.rb` | インボックスへの適用 |
| 2-3 | assignment_policies/inboxes_controller.rb | `app/controllers/api/v1/accounts/assignment_policies/inboxes_controller.rb` | ポリシー適用インボックス一覧 |

**主要処理フロー**:
- **5-7行目** (assignment_policies_controller): index で全ポリシー取得
- **11-13行目**: create でポリシー作成
- **15-17行目**: update でポリシー更新
- **11-18行目** (inboxes/assignment_policies_controller): create で既存関連を削除して新規作成
- **27-29行目**: remove_inbox_assignment_policy で既存関連削除

#### Step 3: 自動割り当てでの使用を理解する

ポリシーが自動割り当てでどのように使用されるかを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | rate_limiter.rb | `app/services/auto_assignment/rate_limiter.rb` | 公平分配制限の実装 |
| 3-2 | assignment_service.rb | `app/services/auto_assignment/assignment_service.rb` | 会話優先度の使用 |

**主要処理フロー**:
- **30-31行目** (rate_limiter): limit = config.fair_distribution_limit
- **34-35行目**: window = config.fair_distribution_window
- **38-39行目**: config = inbox.assignment_policy
- **35-39行目** (assignment_service): conversation_priorityで優先度順を決定

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

```
AssignmentPoliciesController
    │
    ├─ #index
    │      └─ Current.account.assignment_policies
    │
    ├─ #create
    │      └─ assignment_policies.create!(params)
    │
    ├─ #update
    │      └─ assignment_policy.update!(params)
    │
    └─ #destroy
           └─ assignment_policy.destroy!
                  └─ inbox_assignment_policies (dependent: :destroy)

Inboxes::AssignmentPoliciesController
    │
    ├─ #show
    │      └─ @inbox.assignment_policy
    │
    ├─ #create
    │      ├─ remove_inbox_assignment_policy
    │      │      └─ inbox_assignment_policy.destroy
    │      │
    │      └─ @inbox.create_inbox_assignment_policy!
    │
    └─ #destroy
           └─ remove_inbox_assignment_policy

[自動割り当て時]
AutoAssignment::AssignmentService
    │
    └─ AutoAssignment::RateLimiter
           │
           └─ inbox.assignment_policy
                  ├─ fair_distribution_limit
                  └─ fair_distribution_window
```

### データフロー図

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

ポリシーパラメータ ───▶ バリデーション ───▶ assignment_policies
                              │
                              ▼
                      名前ユニーク確認
                      数値バリデーション

インボックスID + ───▶ 既存関連削除 ───▶ inbox_assignment_policies
ポリシーID              │
                        ▼
                   新規関連作成

[自動割り当て時]

inbox.assignment_policy ───▶ RateLimiter ───▶ 割り当て可否判定
        │                        │
        ▼                        ▼
  fair_distribution_limit   current_count < limit?
  fair_distribution_window
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| assignment_policy.rb | `app/models/assignment_policy.rb` | モデル | ポリシー定義 |
| inbox_assignment_policy.rb | `app/models/inbox_assignment_policy.rb` | モデル | 中間テーブル |
| assignment_policies_controller.rb | `app/controllers/api/v1/accounts/assignment_policies_controller.rb` | コントローラー | ポリシーCRUD |
| inboxes/assignment_policies_controller.rb | `app/controllers/api/v1/accounts/inboxes/assignment_policies_controller.rb` | コントローラー | インボックス適用 |
| assignment_policies/inboxes_controller.rb | `app/controllers/api/v1/accounts/assignment_policies/inboxes_controller.rb` | コントローラー | ポリシー適用インボックス一覧 |
| rate_limiter.rb | `app/services/auto_assignment/rate_limiter.rb` | サービス | 公平分配制限 |
| assignment_service.rb | `app/services/auto_assignment/assignment_service.rb` | サービス | 自動割り当てでの使用 |
