# 機能設計書 59-カスタム属性

## 概要

本ドキュメントは、Chatwootにおける連絡先のカスタム属性機能について記述する。本機能は、標準の連絡先フィールド（名前、メール、電話番号等）以外に、ビジネス固有の属性（会員ランク、契約プラン、地域等）を連絡先に設定できる機能である。

### 本機能の処理概要

**業務上の目的・背景**：カスタマーサポートにおいて、標準フィールドだけでは顧客情報を十分に管理できない場合がある。例えば、会員ランク、契約種別、業種、地域など、ビジネス固有の情報を連絡先に紐づけて管理することで、よりパーソナライズされた対応が可能となる。また、カスタム属性による顧客セグメント分けや、自動化ルールのトリガー条件としても活用できる。

**機能の利用シーン**：
- 顧客の会員ランク（ゴールド、シルバー、ブロンズ等）を設定する
- 契約プラン情報を記録する
- 地域や業種などの分類情報を設定する
- カスタム属性を条件とした自動化ルールを設定する
- カスタム属性によるセグメント分けを行う

**主要な処理内容**：
1. カスタム属性値の設定・更新（JSONB形式）
2. カスタム属性の取得・表示
3. カスタム属性の削除
4. 既存属性とのマージ処理
5. カスタム属性によるフィルタリング

**関連システム・外部連携**：カスタム属性定義（CustomAttributeDefinition）と連携し、属性の型やオプションを参照。

**権限による制御**：カスタム属性の設定・更新はエージェント権限以上が必要。カスタム属性定義の作成は管理者権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 24 | 連絡先編集画面 | 主画面 | カスタム属性値の設定・編集 |
| 73 | カスタム属性一覧画面 | 参照画面 | カスタム属性定義の管理 |

## 機能種別

CRUD操作 / データ拡張

## 入力仕様

### 入力パラメータ（設定・更新）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| custom_attributes | Object | Yes | カスタム属性のキーバリューペア | JSONB形式 |

### 入力パラメータ（削除）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| custom_attributes | Array | Yes | 削除する属性キーの配列 | 文字列の配列 |

### custom_attributesの構造例

```json
{
  "membership_tier": "gold",
  "contract_plan": "enterprise",
  "region": "tokyo",
  "signup_date": "2024-01-15"
}
```

### 入力データソース

- 連絡先編集画面からの入力
- APIリクエスト
- Widget経由での自動設定

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| custom_attributes | Object | カスタム属性のキーバリューペア |

### 出力先

- contactsテーブルのcustom_attributesカラム
- API レスポンス

## 処理フロー

### 処理シーケンス（設定・更新）

```
1. リクエスト受信
   └─ custom_attributesパラメータを取得
2. 既存値とのマージ
   └─ 既存のcustom_attributesと新しい値をマージ
3. バリデーション
   └─ JSONB形式の検証
4. 連絡先更新
   └─ contact.save!
5. イベント発行
   └─ CONTACT_UPDATEDイベントをディスパッチ
```

### 処理シーケンス（削除）

```
1. リクエスト受信
   └─ 削除対象の属性キー配列を取得
2. 属性の削除
   └─ custom_attributesからキーを削除
3. 連絡先更新
   └─ contact.save!
4. イベント発行
   └─ CONTACT_UPDATEDイベントをディスパッチ
```

### フローチャート

```mermaid
flowchart TD
    A[カスタム属性リクエスト] --> B{操作種別?}
    B -->|設定/更新| C[既存値とマージ]
    B -->|削除| D[指定キーを除外]
    C --> E[contact.save!]
    D --> E
    E --> F[CONTACT_UPDATEDイベント発行]
    F --> G[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-59-01 | マージ更新 | 既存のcustom_attributesと新しい値をマージ（新しい値を優先） | 更新時 |
| BR-59-02 | 空値初期化 | custom_attributesが空の場合は{}で初期化 | 連絡先作成・更新時 |
| BR-59-03 | キー削除 | destroying指定されたキーは除外（excluding） | 削除時 |
| BR-59-04 | JSONB形式 | 値はJSONB形式で保存 | 常時 |

### custom_attributesとadditional_attributesの違い

| 項目 | custom_attributes | additional_attributes |
|------|-------------------|----------------------|
| 設定者 | ユーザー（エージェント） | システム自動 |
| 用途 | ビジネス固有情報 | IP情報、ブラウザ情報等 |
| 編集可否 | ユーザー編集可能 | 通常は編集不可 |
| 例 | 会員ランク、契約プラン | city, country, browser |

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 設定・更新 | contacts | UPDATE | custom_attributesカラムを更新 |
| 削除 | contacts | UPDATE | custom_attributesカラムを更新 |

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

#### contacts

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | custom_attributes | マージ後のJSONB | デフォルト: {} |

### custom_attributesカラムの定義

- 型: jsonb
- デフォルト: {}
- NOT NULL制約なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 422 | バリデーションエラー | 不正なJSON形式 | エラーメッセージを返却 |
| 403 | 権限エラー | 権限のないユーザーによる操作 | 403 Forbiddenを返却 |

### リトライ仕様

なし（同期処理）

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

カスタム属性の更新は単一のUPDATE操作であり、特別なトランザクション管理は不要。

## パフォーマンス要件

- JSONB形式によりキー単位でのクエリが可能
- GINインデックスにより効率的な検索が可能

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

- カスタム属性にはセンシティブな情報を保存する可能性があるため、適切なアクセス制御が必要
- APIレスポンスにはカスタム属性が含まれるため、権限チェックが必須

## 備考

- custom_attributesはJSONB形式で保存され、任意のキーバリューペアを設定可能
- カスタム属性定義（CustomAttributeDefinition）で型やオプションを定義可能

---

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

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

### 推奨読解順序

#### Step 1: 連絡先モデルのカスタム属性関連を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | contact.rb | `app/models/contact.rb` | custom_attributesカラムの定義と初期化 |

**主要処理フロー**:
- **12行目**: custom_attributesカラムの定義（:jsonb）
- **226-229行目**: prepare_jsonb_attributesでcustom_attributesの初期化

**読解のコツ**: RailsのJSONBカラムは通常のHashとして扱える。`contact.custom_attributes['key']`でアクセス可能。

#### Step 2: コントローラーの更新・削除処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | contacts_controller.rb | `app/controllers/api/v1/accounts/contacts_controller.rb` | update、destroy_custom_attributesアクション |

**主要処理フロー**:
- **80-83行目**: destroy_custom_attributesでexcludingを使用して削除
- **177-181行目**: contact_custom_attributesで既存値とマージ
- **189-193行目**: contact_update_paramsでマージ済み属性を設定

#### Step 3: カスタム属性定義を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | custom_attribute_definition.rb | `app/models/custom_attribute_definition.rb` | 属性の型やオプション定義 |

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

```
Api::V1::Accounts::ContactsController
    │
    ├─ #update
    │      ├─ contact_update_params
    │      │      └─ contact_custom_attributes
    │      │             └─ 既存値とマージ
    │      └─ @contact.save!
    │
    └─ #destroy_custom_attributes
           ├─ custom_attributes.excluding(keys)
           └─ @contact.save!
```

### データフロー図

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

custom_attributes    ContactsController       contacts.custom_attributes
(JSONB)         ───▶ マージ/削除処理    ───▶  (JSONB)
                                                  │
                                                  ▼
                                           CONTACT_UPDATEDイベント
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| contact.rb | `app/models/contact.rb` | モデル | custom_attributesカラム定義 |
| contacts_controller.rb | `app/controllers/api/v1/accounts/contacts_controller.rb` | コントローラー | 更新・削除エンドポイント |
| custom_attribute_definition.rb | `app/models/custom_attribute_definition.rb` | モデル | 属性定義 |
