# 機能設計書 168-Widget Dyte

## 概要

本ドキュメントは、Chatwoot WebウィジェットにおけるWidget Dyte統合機能の設計を記載する。この機能はエンドユーザー（訪問者）がWebサイト上のチャットウィジェットからDyteビデオ会議に参加するためのAPIを提供する。

### 本機能の処理概要

Widget Dyte機能は、Webサイト訪問者がチャットウィジェット経由でDyteビデオ会議に参加するための機能を提供する。エージェントが作成したDyteミーティングに対して、訪問者を参加者として追加することができる。

**業務上の目的・背景**：テキストベースのチャットでは解決が難しい複雑な問い合わせに対して、ビデオ通話によるサポートを提供するため、Dyteビデオ会議への参加機能が必要である。これにより、訪問者は画面共有やフェイスツーフェイスのコミュニケーションを通じて、より効果的なサポートを受けることができる。

**機能の利用シーン**：
- エージェントがビデオ通話を開始し、訪問者が参加する場面
- 複雑な技術サポートで画面共有が必要な場面
- 商品デモやコンサルティングをビデオで行う場面

**主要な処理内容**：
1. Dyteミーティングへの参加者追加（add_participant_to_meeting）

**関連システム・外部連携**：
- Dyte API（ビデオ会議プラットフォーム）
- Integrations::Dyte::ProcessorService（Dyte API連携サービス）

**権限による制御**：
- website_tokenによるウィジェット認証が必要
- メッセージがintegrations型である必要がある

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 116 | メッセージ画面 | 主画面 | Dyteミーティング参加ボタン |

## 機能種別

外部API連携

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| website_token | String | Yes | ウェブウィジェットの識別トークン | 有効なトークンである必要がある |
| message_id | Integer | Yes | 対象メッセージのID | integrationsタイプのメッセージ |

### 入力データソース

- Webウィジェット（JavaScript SDK）からのHTTPリクエスト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| participant_id | String | Dyte参加者ID |
| token | String | Dyte認証トークン |
| error | String | エラーメッセージ（エラー時） |

### 出力先

- JSON形式のHTTPレスポンス

## 処理フロー

### 処理シーケンス

```
1. 参加者追加（add_participant_to_meeting）
   └─ メッセージの取得
   └─ content_typeの検証（integrations必須）
   └─ meeting_idの取得（content_attributesから）
   └─ Dyte::ProcessorServiceで参加者追加
   └─ 結果をレスポンスとして返却
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B[メッセージ取得]
    B --> C{content_type=integrations?}
    C -->|No| D[422 エラー返却]
    C -->|Yes| E[meeting_id取得]
    E --> F[Dyte API呼び出し]
    F --> G{API成功?}
    G -->|Yes| H[200 レスポンス返却]
    G -->|No| I[422 エラー返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-168-01 | メッセージタイプ検証 | content_typeがintegrationsである必要がある | add_participant_to_meeting時 |
| BR-168-02 | meeting_id取得 | content_attributes.data.meeting_idを使用 | add_participant_to_meeting時 |
| BR-168-03 | 連絡先情報使用 | 会話の連絡先をDyte参加者として追加 | add_participant_to_meeting時 |

### 計算ロジック

特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| add_participant_to_meeting | messages | SELECT | メッセージ取得 |
| add_participant_to_meeting | hooks | SELECT | Dyte統合設定取得 |

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

#### messages

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | - | id = params[:message_id] | メッセージID条件 |
| SELECT | content_type | - | integrationsチェック |
| SELECT | content_attributes | - | meeting_id取得 |

#### hooks

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | - | app_id = 'dyte' | Dyte統合条件 |
| SELECT | settings | - | organization_id, api_key取得 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 401 | Unauthorized | website_tokenが無効 | 正しいトークンを使用 |
| 422 | Unprocessable Entity | content_typeがintegrationsでない | 正しいメッセージを指定 |
| 422 | Unprocessable Entity | Dyte API呼び出しエラー | Dyte統合設定を確認 |

### リトライ仕様

特になし（同期処理のため）

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

読み取り操作と外部API呼び出しのため、トランザクション制御は不要

## パフォーマンス要件

- レスポンス時間: 3000ms以内（外部API依存）

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

- website_tokenによるウィジェット認証
- Dyte API認証情報はhooksテーブルで管理
- 連絡先のIDと名前がDyteに送信される

## 備考

- Dyte統合がアカウントで有効化されている必要がある
- エージェントが先にミーティングを作成する必要がある
- 訪問者のアバターURLがDyteに送信される（存在する場合）
- アバターがない場合はデフォルト画像が使用される

---

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

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

### 推奨読解順序

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

Dyte統合に関連するデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | hook.rb | `app/models/integrations/hook.rb` | 統合フック（app_id, settings） |
| 1-2 | message.rb | `app/models/message.rb` | content_type, content_attributes |

**読解のコツ**: messagesのcontent_typeがintegrationsの場合、content_attributesにDyteミーティング情報が格納されていることを理解すること。

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

処理の起点となるコントローラーを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | dyte_controller.rb | `app/controllers/api/v1/widget/integrations/dyte_controller.rb` | Dyte統合のWidget側実装 |

**主要処理フロー**:
1. **2行目**: before_action :set_message（メッセージ取得）
2. **4-16行目**: add_participant_to_meeting処理
3. **5-9行目**: content_type検証（integrationsチェック）
4. **10-14行目**: ProcessorService呼び出しとレスポンス返却
5. **28-31行目**: set_message（メッセージと会話の設定）

#### Step 3: Dyteサービスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | processor_service.rb | `lib/integrations/dyte/processor_service.rb` | Dyte API連携サービス |

**主要処理フロー**:
- **15-17行目**: add_participant_to_meeting（Dyteクライアント呼び出し）
- **40-44行目**: avatar_url（デフォルトアバター処理）
- **46-48行目**: dyte_hook（統合設定取得）
- **50-53行目**: dyte_client（Dyteクライアント初期化）

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

```
Api::V1::Widget::Integrations::DyteController
    │
    ├─ BaseController (認証・共通処理)
    │      └─ set_web_widget
    │      └─ set_contact
    │
    ├─ set_message
    │      └─ @message = inbox.messages.find(message_id)
    │      └─ @conversation = @message.conversation
    │
    └─ Integrations::Dyte::ProcessorService
           │
           ├─ add_participant_to_meeting
           │      └─ dyte_client.add_participant_to_meeting
           │
           ├─ dyte_hook
           │      └─ account.hooks.find_by!(app_id: 'dyte')
           │
           └─ dyte_client
                  └─ Dyte.new(organization_id, api_key)
```

### データフロー図

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

website_token ────────▶ BaseController#set_web_widget ────▶ @web_widget
                              │
message_id ───────────▶ set_message ──────────────────────▶ @message
                              │                              @conversation
                        content_type検証 ─────────────────▶ 検証結果
                              │
                        ProcessorService ─────────────────▶ Dyte API呼び出し
                              │
                        JSON Response ────────────────────▶ クライアント
                              │                              - participant_id
                              │                              - token
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| dyte_controller.rb | `app/controllers/api/v1/widget/integrations/dyte_controller.rb` | ソース | Widget Dyteのメインコントローラー |
| base_controller.rb | `app/controllers/api/v1/widget/base_controller.rb` | ソース | Widget APIの基底コントローラー |
| processor_service.rb | `lib/integrations/dyte/processor_service.rb` | ソース | Dyte API連携サービス |
| hook.rb | `app/models/integrations/hook.rb` | ソース | 統合フックモデル |
| message.rb | `app/models/message.rb` | ソース | メッセージモデル |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義（413-418行目） |
