# 機能設計書 129-Telegram

## 概要

本ドキュメントは、ChatwootのTelegramボット連携機能の設計仕様を記載する。この機能は、Telegram Bot APIを通じたメッセージングをChatwootで一元管理するためのチャネル統合機能である。

### 本機能の処理概要

Telegram連携は、Telegram Bot APIを通じてボットに送信されたメッセージを受信し、Chatwootの会話として管理する。エージェントはChatwootからTelegramユーザーへの返信を直接送信できる。Telegram Businessチャットにも対応。

**業務上の目的・背景**：Telegramは特に東欧・中央アジア・中東で広く利用されるメッセージングプラットフォームであり、セキュリティ意識の高いユーザー層に支持されている。本機能により、Telegram経由の顧客対応をChatwootで統合管理でき、グローバルなカスタマーサポート体制を強化できる。

**機能の利用シーン**：
- 顧客からのTelegramメッセージを受信・返信する場面
- ボットを通じた自動応答と有人対応の連携
- 画像・動画・音声・ファイル・位置情報の送受信
- インラインキーボード（選択肢）を使用したインタラクション

**主要な処理内容**：
1. Telegram Botの登録とWebhook設定
2. Webhookを通じたメッセージ・位置情報・連絡先カードの受信処理
3. Telegram Bot APIを使用したメッセージ・添付ファイル送信
4. HTMLパース対応のマークダウン変換
5. 連絡先（Telegramユーザー）の自動作成・アバター取得

**関連システム・外部連携**：
- Telegram Bot API
- Telegram Webhook

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

## 関連画面

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

## 機能種別

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

## 入力仕様

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

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| bot_token | String | Yes | Telegram Botトークン | 一意性、有効性検証 |
| bot_name | String | Auto | ボット名 | 自動取得 |
| account_id | Integer | Yes | Chatwootアカウント | 必須 |

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

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

### 入力データソース

- Telegram @BotFatherからのボットトークン取得
- Chatwoot会話画面からのメッセージ入力

## 出力仕様

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

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

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

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

### 出力先

- Chatwootデータベース（messages, conversations, contacts）
- Telegram Bot API（送信メッセージ）

## 処理フロー

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

```
1. Telegram Webhookからイベント受信
   └─ TelegramController#process_payloadで処理
2. TelegramEventsJobで処理
   └─ IncomingMessageService実行
3. メッセージ処理
   └─ Businessメッセージの変換（必要に応じて）
   └─ プライベートメッセージかチェック
   └─ 連絡先の作成/取得、アバター更新
   └─ 会話の作成/取得
   └─ メッセージの作成、添付ファイル処理
```

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

```
1. Chatwootでメッセージ作成
   └─ Message#after_create_commitコールバック
2. SendOnTelegramServiceの実行
   └─ channel.send_message_on_telegram呼び出し
3. メッセージ送信
   └─ テキスト送信（sendMessage API）
   └─ 添付ファイル送信（SendAttachmentsService）
4. レスポンス処理
   └─ message_idをsource_idとして保存
```

### フローチャート

```mermaid
flowchart TD
    A[Webhook受信] --> B{プライベートメッセージ?}
    B -->|No| C[処理終了（グループ未対応）]
    B -->|Yes| D[連絡先作成/取得]
    D --> E[アバター更新]
    E --> F[会話作成/取得]
    F --> G[メッセージ作成]
    G --> H{添付ファイルあり?}
    H -->|Yes| I[添付ファイル処理]
    H -->|No| J[メッセージ保存]
    I --> J
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | プライベートメッセージのみ | グループチャットは現在未対応 | メッセージ受信時 |
| BR-002 | Webhook自動設定 | 保存前にdeleteWebhook→setWebhookを実行 | チャネル作成・更新時 |
| BR-003 | ボットトークン検証 | getMe APIで有効性を確認、bot_nameを自動取得 | チャネル作成時 |
| BR-004 | HTMLパースモード | メッセージ送信時はparse_mode='HTML'を使用 | メッセージ送信時 |
| BR-005 | インラインキーボード | input_selectの場合はreply_markupでボタン生成 | メッセージ送信時 |

### 計算ロジック

- telegram_api_url: `https://api.telegram.org/bot#{bot_token}`
- ファイルURL: `https://api.telegram.org/file/bot#{bot_token}/#{file_path}`

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

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

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

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

#### channel_telegram

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | bot_token, bot_name, account_id | 設定フォームから取得 | bot_token暗号化（deterministic） |

#### conversations

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | additional_attributes | {chat_id: X, business_connection_id: Y} | Telegram固有情報 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| invalid_token | Validation Error | ボットトークンが無効 | 正しいトークンを入力 |
| webhook_error | Setup Error | Webhook設定失敗 | サーバー設定を確認 |
| send_failed | API Error | メッセージ送信失敗 | external_errorに詳細保存 |

### リトライ仕様

- 自動リトライなし
- エラー詳細をexternal_errorに保存

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

- メッセージ受信時：メッセージ・会話・連絡先の作成は単一トランザクション

## パフォーマンス要件

- Webhook処理はバックグラウンドジョブで実行

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

- bot_tokenは暗号化して保存（deterministic: true）
- WebhookはボットトークンをURL含むため、HTTPSが必須

## 備考

- EDITABLE_ATTRS = [:bot_token]
- グループチャットは現在未対応（private_message?チェック）
- Telegram Businessメッセージにも対応（transform_business_message!）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | telegram.rb | `app/models/channel/telegram.rb` | チャネルモデルの構造、メッセージ送信、Webhook設定 |

**読解のコツ**:
- `bot_token`はdeterministic暗号化（検索可能）
- `send_message_on_telegram`がエントリーポイント

**主要処理フロー**:
- **21行目**: 暗号化設定（deterministic: true）
- **24行目**: EDITABLE_ATTRS定義
- **26-27行目**: バリデーション
- **28行目**: setup_telegram_webhook before_save
- **34-36行目**: telegram_api_url
- **38-42行目**: send_message_on_telegram - テキストと添付ファイル送信
- **62-69行目**: process_error - エラー処理
- **85-93行目**: ensure_valid_bot_token - getMe APIで検証
- **95-102行目**: setup_telegram_webhook - deleteWebhook→setWebhook
- **104-114行目**: send_message - sendMessage API呼び出し
- **116-128行目**: reply_markup - input_select用インラインキーボード生成
- **130-155行目**: convert_markdown_to_telegram_html - マークダウン→HTML変換
- **157-170行目**: message_request - HTTParty.post実行

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | send_on_telegram_service.rb | `app/services/telegram/send_on_telegram_service.rb` | 送信サービス |
| 2-2 | send_attachments_service.rb | `app/services/telegram/send_attachments_service.rb` | 添付ファイル送信 |

**主要処理フロー（SendOnTelegramService）**:
- **8-13行目**: perform_reply - channel.send_message_on_telegram呼び出し

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | telegram_controller.rb | `app/controllers/webhooks/telegram_controller.rb` | Webhook受信 |
| 3-2 | incoming_message_service.rb | `app/services/telegram/incoming_message_service.rb` | メッセージ処理 |

**主要処理フロー（IncomingMessageService）**:
- **9-36行目**: perform - メイン処理フロー
- **11行目**: transform_business_message! - Businessメッセージ変換
- **12行目**: private_message? チェック
- **14-15行目**: set_contact, update_contact_avatar
- **16行目**: set_conversation
- **24-32行目**: メッセージビルド
- **34行目**: process_message_attachments
- **40-54行目**: set_contact - ContactInboxWithContactBuilder使用
- **56-60行目**: process_message_attachments - 位置情報・ファイル・連絡先カード処理
- **79-90行目**: set_conversation - lock_to_single_conversation対応

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

```
[メッセージ送信フロー]
Message#after_create_commit
    │
    └─ SendReplyJob.perform_later
           │
           └─ Telegram::SendOnTelegramService#perform
                  │
                  └─ channel.send_message_on_telegram
                         │
                         ├─ send_message (テキスト)
                         │      │
                         │      ├─ message_request
                         │      │      └─ HTTParty.post (sendMessage)
                         │      │
                         │      └─ reply_markup (input_select時)
                         │
                         └─ SendAttachmentsService#perform (添付あり)
                                └─ 各種添付送信メソッド

[メッセージ受信フロー]
Telegram Webhook
    │
    └─ Webhooks::TelegramController#process_payload
           │
           └─ TelegramEventsJob.perform_later
                  │
                  └─ Telegram::IncomingMessageService#perform
                         │
                         ├─ transform_business_message!
                         ├─ private_message? チェック
                         ├─ set_contact
                         │      └─ ContactInboxWithContactBuilder
                         ├─ update_contact_avatar
                         │      └─ get_telegram_profile_image
                         ├─ set_conversation
                         └─ メッセージ作成
                                └─ process_message_attachments
```

### データフロー図

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

Message作成     ───▶ SendReplyJob
                      │
                      ▼
                SendOnTelegramService
                      │
                      ▼
                channel.send_message_on_telegram
                      │
                      ├─▶ [テキスト] send_message
                      │      │
                      │      └─▶ message_request
                      │             └─ HTTParty.post
                      │
                      └─▶ [添付] SendAttachmentsService
                             └─ 各種添付送信API
                      │
                      ▼
                Telegram Bot API    ───▶ Telegram
                      │
                      ▼
                message_id受信      ◀───  API Response
                      │
                      ▼
                source_id保存

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

Webhook Event   ───▶ TelegramController
                      │
                      └─▶ TelegramEventsJob
                             │
                             └─▶ IncomingMessageService
                                    │
                                    ├─▶ set_contact
                                    │      └─ アバター取得
                                    │
                                    ├─▶ set_conversation
                                    │      └─ chat_id保存
                                    │
                                    └─▶ メッセージ作成
                                           └─ 添付ファイル処理
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| telegram.rb | `app/models/channel/telegram.rb` | モデル | チャネル定義・メッセージ送信 |
| send_on_telegram_service.rb | `app/services/telegram/send_on_telegram_service.rb` | サービス | 送信サービス |
| send_attachments_service.rb | `app/services/telegram/send_attachments_service.rb` | サービス | 添付ファイル送信 |
| incoming_message_service.rb | `app/services/telegram/incoming_message_service.rb` | サービス | メッセージ受信処理 |
| update_message_service.rb | `app/services/telegram/update_message_service.rb` | サービス | メッセージ更新処理 |
| param_helpers.rb | `app/services/telegram/param_helpers.rb` | ヘルパー | パラメータ抽出 |
| telegram_controller.rb | `app/controllers/webhooks/telegram_controller.rb` | コントローラー | Webhook受信 |
| telegram_events_job.rb | `app/jobs/webhooks/telegram_events_job.rb` | ジョブ | Webhook処理 |
