# 機能設計書 122-Facebook

## 概要

本ドキュメントは、ChatwootのFacebook Messenger連携機能の設計仕様を記載する。この機能は、Facebook Messengerを通じた顧客とのコミュニケーションをChatwootで一元管理するためのチャネル統合機能である。

### 本機能の処理概要

Facebook Messenger連携は、Facebookページに紐づくMessengerを通じて受信したメッセージをChatwootの会話として取り込み、エージェントからの返信をMessenger経由で顧客に送信する双方向コミュニケーション機能を提供する。

**業務上の目的・背景**：多くの企業がFacebookページを顧客接点として活用しており、Messengerを通じた問い合わせが増加している。本機能により、Messengerでの顧客対応をChatwootの統合インターフェースで行うことができ、複数チャネルの一元管理とエージェントの効率的な顧客対応を実現する。

**機能の利用シーン**：
- Facebookページ経由でMessengerメッセージを受信する場面
- エージェントがChatwootからMessengerユーザーに返信する場面
- テキストメッセージ、画像、動画、ファイルを送受信する場面
- クイックリプライ（選択式入力）を使用する場面

**主要な処理内容**：
1. Facebookページとの認証・接続設定
2. Webhookを通じたメッセージ受信・配信通知・既読通知の処理
3. Messenger APIを使用したメッセージ送信
4. 連絡先（Facebook Messengerユーザー）の自動作成・更新
5. 添付ファイル（画像・動画・音声・ファイル）の送受信

**関連システム・外部連携**：
- Facebook Graph API（メッセージ送信）
- Facebook Messenger Webhook（メッセージ受信）
- facebook-messenger gem（Rubyクライアント）

**権限による制御**：インボックスの作成・管理にはAdministrator権限が必要。メッセージの送受信はインボックスにアサインされたエージェントが実行可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 49 | チャネル設定画面 | 主画面 | Facebookチャネルの設定・認可フロー |
| 11 | 会話詳細画面 | 主画面 | Messengerメッセージの送受信 |

## 機能種別

データ連携 / メッセージング

## 入力仕様

### 入力パラメータ（チャネル作成時）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| page_id | String | Yes | FacebookページID | 一意性（account_idとの組み合わせ） |
| page_access_token | String | Yes | ページアクセストークン | 必須 |
| user_access_token | String | Yes | ユーザーアクセストークン | 必須 |
| account_id | Integer | Yes | Chatwootアカウント | 必須 |

### 入力パラメータ（メッセージ送信時）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| content | String | No | メッセージ本文 | content_typeによる |
| content_type | String | No | コンテンツタイプ（text/input_select等） | - |
| attachments | Array | No | 添付ファイル | image/audio/video/file |

### 入力データソース

- Facebook OAuth認可フローからトークン取得
- Chatwoot会話画面からのメッセージ入力

## 出力仕様

### 出力データ（Webhook受信時）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| message | Message | 作成されたメッセージレコード |
| conversation | Conversation | 関連する会話 |
| contact | Contact | 送信者の連絡先 |

### 出力データ（メッセージ送信時）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| message_id | String | Facebook側のメッセージID（source_idとして保存） |

### 出力先

- Chatwootデータベース（messages, conversations, contacts）
- Facebook Messenger（送信メッセージ）

## 処理フロー

### 処理シーケンス（メッセージ受信）

```
1. Facebook Webhookからイベント受信
   └─ MessengerController#eventsで処理
2. イベントタイプの判定
   └─ messages / message_deliveries / message_echoes / message_reads
3. メッセージイベントの場合
   └─ 連絡先の作成または取得
   └─ 会話の作成または取得
   └─ メッセージの作成
   └─ 添付ファイルの処理
4. WebSocket経由でリアルタイム通知
```

### 処理シーケンス（メッセージ送信）

```
1. Chatwootでメッセージ作成
   └─ Message#after_create_commitコールバック
2. SendOnFacebookServiceの実行
   └─ チャネル検証
   └─ outgoingメッセージ判定
   └─ private note除外
3. Facebook Messenger APIへ送信
   └─ テキストメッセージ送信
   └─ 添付ファイル送信（存在する場合）
4. レスポンス処理
   └─ message_idをsource_idとして保存
   └─ エラー時はステータス更新
```

### フローチャート

```mermaid
flowchart TD
    A[メッセージ作成] --> B{チャネル検証}
    B -->|NG| C[処理終了]
    B -->|OK| D{outgoingメッセージ?}
    D -->|No| C
    D -->|Yes| E{private note?}
    E -->|Yes| C
    E -->|No| F{source_id存在?}
    F -->|Yes| C
    F -->|No| G[FB APIへ送信]
    G --> H{送信成功?}
    H -->|Yes| I[source_id保存]
    H -->|No| J[ステータスをfailedに更新]
    I --> K[処理完了]
    J --> K
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 24時間ルール | 最後の受信メッセージから24時間以内の場合のみ通常メッセージ送信可能 | メッセージ送信時 |
| BR-002 | メッセージタグ | 24時間後はACCOUNT_UPDATEタグを使用して送信 | メッセージ送信時 |
| BR-003 | 重複防止 | source_idが存在するメッセージは再送信しない | メッセージ送信時 |
| BR-004 | プライベートノート除外 | privateフラグがtrueのメッセージは送信しない | メッセージ送信時 |

### 計算ロジック

特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| チャネル作成 | channel_facebook_pages | INSERT | Facebookチャネル情報保存 |
| メッセージ受信 | messages | INSERT | 受信メッセージ保存 |
| メッセージ送信 | messages | UPDATE | source_id更新 |
| 連絡先作成 | contacts | INSERT/UPDATE | 送信者情報保存 |
| 会話作成 | conversations | INSERT | 新規会話作成 |

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

#### channel_facebook_pages

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | page_id, page_access_token, user_access_token, account_id | OAuth認可フローから取得 | 暗号化保存 |
| SELECT | page_access_token | チャネルID指定 | メッセージ送信時に使用 |

#### messages

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | content, account_id, inbox_id, conversation_id, sender_id, message_type, source_id | Webhook受信データから | 受信メッセージ |
| UPDATE | source_id | Facebook APIレスポンスのmessage_id | 送信成功時 |
| UPDATE | status, external_error | 'failed', エラーメッセージ | 送信失敗時 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| session_invalidated | Facebook Error | セッション無効化 | チャネル再認可 |
| access_token_error | Facebook Error | アクセストークン無効 | チャネル再認可 |
| timeout | Network Error | Facebook APIタイムアウト | メッセージステータスをfailedに更新 |
| json_parse_error | Parse Error | レスポンス解析失敗 | メッセージステータスをfailedに更新 |

### リトライ仕様

- 自動リトライなし
- ユーザーによる手動再送信が必要

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

- メッセージ受信時：メッセージ・会話・連絡先の作成は単一トランザクション
- メッセージ送信時：source_id更新は独立したトランザクション

## パフォーマンス要件

- Webhook処理はバックグラウンドジョブで実行
- メッセージ送信もバックグラウンドで実行

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

- page_access_token、user_access_tokenは暗号化して保存（Chatwoot.encryption_configured?時）
- Webhook署名検証による不正リクエスト防止
- OAuthフローによる安全な認可

## 備考

- instagram_idカラムはInstagram連携用（Facebook経由のInstagram接続）
- Reauthorizableモジュールで認可エラー時の再認可フロー対応

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | facebook_page.rb | `app/models/channel/facebook_page.rb` | チャネルモデルの構造、暗号化設定、Webhook購読 |

**読解のコツ**:
- `Channelable`モジュールがhas_one :inboxを提供
- `Reauthorizable`モジュールが認可エラー処理を提供
- `encrypts`メソッドでトークンを暗号化

**主要処理フロー**:
- **30行目**: テーブル名定義
- **32行目**: page_idの一意性バリデーション
- **34-35行目**: 作成時にsubscribe、削除時にunsubscribe
- **49-60行目**: subscribe処理（Webhook購読フィールド設定）

#### Step 2: メッセージ送信処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | send_on_channel_service.rb | `app/services/base/send_on_channel_service.rb` | 基底クラスの共通処理フロー |
| 2-2 | send_on_facebook_service.rb | `app/services/facebook/send_on_facebook_service.rb` | Facebook固有の送信処理 |

**主要処理フロー（SendOnFacebookService）**:
- **8-20行目**: perform_reply - テキストと添付ファイルを順次送信
- **22-32行目**: send_message_to_facebook - API呼び出しとレスポンス処理
- **47-54行目**: fb_text_message_params - テキストメッセージのパラメータ構築
- **56-71行目**: fb_text_message_payload - input_selectの場合はquick_repliesを構築
- **81-95行目**: fb_attachment_message_params - 添付ファイルのパラメータ構築
- **108-113行目**: handle_facebook_error - 認可エラー時の処理

#### Step 3: メッセージ受信処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | facebook_events_job.rb | `app/jobs/webhooks/facebook_events_job.rb` | Webhookイベント処理ジョブ |

**読解のコツ**: facebook-messenger gemがWebhookのルーティングとイベント処理を行う

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

```
[メッセージ送信フロー]
Message#after_create_commit
    │
    └─ SendReplyJob.perform_later
           │
           └─ Facebook::SendOnFacebookService#perform
                  │
                  ├─ validate_target_channel
                  ├─ outgoing_message? チェック
                  ├─ invalid_message? チェック
                  │
                  └─ perform_reply
                         │
                         ├─ send_message_to_facebook (テキスト)
                         │      └─ Facebook::Messenger::Bot.deliver
                         │
                         └─ send_message_to_facebook (添付ファイル) × N
                                └─ Facebook::Messenger::Bot.deliver

[メッセージ受信フロー]
Facebook Webhook
    │
    └─ facebook-messenger gem
           │
           └─ Webhooks::FacebookEventsJob
                  │
                  └─ メッセージ・会話・連絡先作成
```

### データフロー図

```
[送信フロー]
[Chatwoot]              [処理]                    [Facebook]

Message作成     ───▶ SendReplyJob
                      │
                      ▼
                SendOnFacebookService
                      │
                      ▼
                fb_text_message_params
                fb_attachment_message_params
                      │
                      ▼
                Facebook::Messenger::Bot.deliver ───▶ Messenger API
                      │
                      ▼
                message_id受信              ◀───  API Response
                      │
                      ▼
                source_id更新

[受信フロー]
[Facebook]              [処理]                    [Chatwoot]

Webhook Event   ───▶ facebook-messenger gem
                      │
                      ▼
                FacebookEventsJob
                      │
                      ├─▶ Contact作成/取得
                      ├─▶ Conversation作成/取得
                      └─▶ Message作成          ───▶ messages テーブル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| facebook_page.rb | `app/models/channel/facebook_page.rb` | モデル | チャネル定義 |
| send_on_facebook_service.rb | `app/services/facebook/send_on_facebook_service.rb` | サービス | メッセージ送信処理 |
| send_on_channel_service.rb | `app/services/base/send_on_channel_service.rb` | サービス | 送信処理基底クラス |
| channelable.rb | `app/models/concerns/channelable.rb` | concern | チャネル共通処理 |
| reauthorizable.rb | `app/models/concerns/reauthorizable.rb` | concern | 再認可処理 |
| facebook_events_job.rb | `app/jobs/webhooks/facebook_events_job.rb` | ジョブ | Webhook処理 |
| callbacks_controller.rb | `app/controllers/api/v1/accounts/callbacks_controller.rb` | コントローラー | OAuth認可コールバック |
