# 機能設計書 127-SMS

## 概要

本ドキュメントは、ChatwootのSMS連携機能の設計仕様を記載する。この機能は、SMSを通じた顧客とのコミュニケーションをChatwootで一元管理するためのチャネル統合機能である。Twilio SMSおよびBandwidth SMSの2つのプロバイダに対応。

### 本機能の処理概要

SMS連携は、SMS APIを通じてテキストメッセージの送受信を行い、Chatwootの会話として管理する。プロバイダとしてTwilio（TwilioSms）とBandwidth（Sms）の2種類をサポートしている。

**業務上の目的・背景**：SMSは世界中で広く利用される通信手段であり、特にモバイルユーザーへの確実なリーチにおいて重要な役割を果たす。本機能により、SMS経由の顧客コミュニケーションをChatwootで統合管理でき、マルチチャネルサポート体制を強化できる。

**機能の利用シーン**：
- 顧客からのSMSを受信・返信する場面
- 予約確認やアラート通知の送信
- 2要素認証コードの送信
- キャンペーンメッセージの一斉送信

**主要な処理内容**：
1. Twilio / Bandwidth SMSプロバイダとの接続設定
2. Webhookを通じたSMS受信処理
3. SMS API経由でのメッセージ送信
4. 配信ステータス（delivered/failed）の追跡
5. メディアメッセージ（MMS）の送受信（Twilioのみ）

**関連システム・外部連携**：
- Twilio SMS API
- Bandwidth Messaging API
- Twilio配信ステータスWebhook

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

## 関連画面

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

## 機能種別

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

## 入力仕様

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

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| account_sid | String | Yes | Twilioアカウント SID | 必須 |
| auth_token | String | Yes | 認証トークン（またはAPI Key Secret） | 必須 |
| api_key_sid | String | No | API Key SID（API Key認証時） | - |
| phone_number | String | Cond | 電話番号 | messaging_service_sidなしの場合必須 |
| messaging_service_sid | String | Cond | メッセージングサービスSID | phone_numberなしの場合必須 |
| medium | Integer | Yes | メディア種別（sms: 0, whatsapp: 1） | 列挙値 |

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

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| phone_number | String | Yes | 電話番号 | 一意性 |
| provider_config | JSONB | Yes | プロバイダ設定 | - |

### provider_config（Bandwidth）

| パラメータ名 | 型 | 必須 | 説明 |
|-------------|-----|-----|------|
| account_id | String | Yes | BandwidthアカウントID |
| application_id | String | Yes | アプリケーションID |
| api_key | String | Yes | APIキー |
| api_secret | String | Yes | APIシークレット |

### 入力データソース

- 設定フォームからの入力
- Chatwoot会話画面からのメッセージ入力

## 出力仕様

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

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

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

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

### 出力先

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

## 処理フロー

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

```
1. Bandwidth Webhookからイベント受信
   └─ SmsController#process_payloadで処理
2. SmsEventsJobで処理
   └─ 連絡先・会話・メッセージの作成
```

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

```
1. Chatwootでメッセージ作成
   └─ Message#after_create_commitコールバック
2. チャネルのsend_messageメソッド実行
   └─ Bandwidth APIへHTTP POST
3. レスポンス処理
   └─ 成功: メッセージIDを返却
   └─ 失敗: external_error設定、status=failed
```

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

```
1. Chatwootでメッセージ作成
2. Twilio::REST::Client#messages.create実行
   └─ status_callback URLを設定
3. 配信ステータスWebhook受信
   └─ メッセージステータスを更新
```

### フローチャート

```mermaid
flowchart TD
    A[メッセージ作成] --> B{チャネルタイプ}
    B -->|TwilioSms| C[Twilio Client生成]
    B -->|Sms| D[Bandwidth API呼び出し]
    C --> E[messages.create]
    E --> F{送信成功?}
    D --> G{送信成功?}
    F -->|Yes| H[配信ステータスWebhook待機]
    F -->|No| I[エラー処理]
    G -->|Yes| J[message_id返却]
    G -->|No| K[external_error設定 & failed]
    H --> L[ステータス更新]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 電話番号排他 | phone_numberとmessaging_service_sidのどちらか一方のみ設定可能 | Twilioチャネル |
| BR-002 | メディアタイプ | medium=1の場合はWhatsApp（Twilio WhatsApp） | Twilioチャネル |
| BR-003 | メディア添付 | 添付ファイルはmedia_urlとして送信 | Twilioチャネル |
| BR-004 | ステータスコールバック | 配信ステータスを追跡するためコールバックURL設定 | Twilioチャネル |

### 計算ロジック

特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| チャネル作成 | channel_twilio_sms / channel_sms | INSERT | SMSチャネル情報保存 |
| メッセージ受信 | messages | INSERT | 受信メッセージ保存 |
| メッセージ送信 | messages | UPDATE | source_id, status更新 |
| 連絡先作成 | contacts | INSERT/UPDATE | 送信者情報保存 |

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

#### channel_twilio_sms

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | account_sid, auth_token, api_key_sid, phone_number, messaging_service_sid, medium | 設定フォームから取得 | auth_token暗号化 |

#### channel_sms

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | phone_number, provider, provider_config, account_id | 設定フォームから取得 | - |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| invalid_number | API Error | 無効な電話番号 | 正しい電話番号を指定 |
| authentication_error | Auth Error | 認証情報が無効 | チャネル再設定 |
| rate_limit | API Error | レート制限超過 | 時間を置いて再試行 |

### リトライ仕様

- 自動リトライなし
- Bandwidthの場合、エラー詳細をexternal_errorに保存

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

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

## パフォーマンス要件

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

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

- auth_tokenは暗号化して保存（Chatwoot.encryption_configured?時）
- API認証情報は安全に管理

## 備考

- TwilioSmsチャネルはSMSとWhatsApp（Twilio経由）の両方をサポート
- Smsチャネル（Bandwidth）はSMSのみ

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | twilio_sms.rb | `app/models/channel/twilio_sms.rb` | Twilioチャネルモデルの構造 |
| 1-2 | sms.rb | `app/models/channel/sms.rb` | Bandwidthチャネルモデルの構造 |

**読解のコツ（TwilioSms）**:
- `medium`でsms/whatsappを区別
- `messaging_service_sid`と`phone_number`は排他的

**主要処理フロー（TwilioSms）**:
- **38-41行目**: EDITABLE_ATTRS定義
- **44-46行目**: messaging_service_sidとphone_numberの排他バリデーション
- **48行目**: medium enum定義（sms: 0, whatsapp: 1）
- **54-59行目**: send_messageメソッド - status_callback設定
- **63-69行目**: client生成 - API Key認証対応
- **71-77行目**: send_message_from - messaging_service_sid優先

**主要処理フロー（Sms/Bandwidth）**:
- **27行目**: nameメソッド = 'Sms'
- **36-41行目**: send_message - メディア添付対応
- **43-46行目**: send_text_message - テキストのみ送信
- **59-73行目**: send_to_bandwidth - HTTPartyでPOST

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | twilio_sms.rb | `app/models/channel/twilio_sms.rb` | Twilio送信処理（send_message） |
| 2-2 | sms.rb | `app/models/channel/sms.rb` | Bandwidth送信処理（send_to_bandwidth） |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | sms_controller.rb | `app/controllers/webhooks/sms_controller.rb` | Bandwidth Webhook受信 |
| 3-2 | sms_events_job.rb | `app/jobs/webhooks/sms_events_job.rb` | メッセージ処理ジョブ |

**主要処理フロー（SmsController）**:
- **2-5行目**: process_payload - JSONの最初の要素を取得してジョブに渡す

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

```
[Twilioメッセージ送信フロー]
Message#after_create_commit
    │
    └─ SendReplyJob.perform_later
           │
           └─ チャネル固有の送信サービス
                  │
                  └─ Channel::TwilioSms#send_message
                         │
                         ├─ client（Twilio::REST::Client）
                         │
                         └─ messages.create
                                ├─ to, body, media_url
                                └─ status_callback

[Bandwidthメッセージ送信フロー]
Message#after_create_commit
    │
    └─ SendReplyJob.perform_later
           │
           └─ Channel::Sms#send_message
                  │
                  └─ send_to_bandwidth
                         │
                         └─ HTTParty.post (Bandwidth API)

[SMS受信フロー（Bandwidth）]
Bandwidth Webhook
    │
    └─ Webhooks::SmsController#process_payload
           │
           └─ SmsEventsJob.perform_later
                  │
                  └─ メッセージ処理
                         ├─ Contact作成/取得
                         ├─ Conversation作成/取得
                         └─ Message作成
```

### データフロー図

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

Message作成     ───▶ SendReplyJob
                      │
                      ▼
                TwilioSms#send_message
                      │
                      ▼
                Twilio::REST::Client
                      │
                      ▼
                messages.create        ───▶ Twilio SMS API
                      │
                      │                 ◀─── 配信ステータスWebhook
                      ▼
                ステータス更新

[Bandwidth送信フロー]
[Chatwoot]              [処理]                    [Bandwidth]

Message作成     ───▶ SendReplyJob
                      │
                      ▼
                Sms#send_message
                      │
                      ▼
                send_to_bandwidth
                      │
                      ▼
                HTTParty.post          ───▶ Bandwidth API
                      │
                      ▼
                message_id受信         ◀───  API Response
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| twilio_sms.rb | `app/models/channel/twilio_sms.rb` | モデル | Twilioチャネル定義 |
| sms.rb | `app/models/channel/sms.rb` | モデル | Bandwidthチャネル定義 |
| sms_controller.rb | `app/controllers/webhooks/sms_controller.rb` | コントローラー | Bandwidth Webhook受信 |
| sms_events_job.rb | `app/jobs/webhooks/sms_events_job.rb` | ジョブ | SMS受信処理 |
| twilio_delivery_status_controller.rb | `app/controllers/twilio/delivery_status_controller.rb` | コントローラー | Twilio配信ステータス |
