Files
gochat/docs/requirements/M2-inbox-and-channels.md
T
2026-06-04 15:44:48 +08:00

753 lines
38 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# M2 Inbox与渠道管理 功能梳理文档
> 参照仓库:chatwoot-reference
> 产出日期:2026-05-22
> 版本基准:Chatwoot v3.x
---
## 目录
1. [Inbox CRUD + 设置 + 品牌](#1-inbox-crud--设置--品牌)
2. [InboxMember绑定](#2-inboxmember绑定)
3. [Channelable多渠道模式](#3-channelable多渠道模式)
4. [WebWidget渠道](#4-webwidget渠道)
5. [Telegram渠道](#5-telegram渠道)
6. [Facebook / Instagram渠道](#6-facebook--instagram渠道)
7. [WhatsApp渠道](#7-whatsapp渠道)
8. [Email渠道](#8-email渠道)
9. [Twilio SMS / WhatsApp渠道](#9-twilio-sms--whatsapp渠道)
10. [其他渠道(SMS、Line、Twitter、TikTok、API)](#10-其他渠道smsline-twitter-tiktok-api)
11. [Webhook回调(外部事件推送)](#11-webhook回调外部事件推送)
12. [OAuth刷新 / Reauthorizable](#12-oauth刷新--reauthorizable)
13. [企业版InboxCapacity](#13-企业版inboxcapacity)
---
## 1. Inbox CRUD + 设置 + 品牌
### 功能描述
Inbox(收件箱)是 Chatwoot 的核心聚合单元,代表一个对外沟通渠道的入口。每个 Inbox 绑定一个多态 Channel 对象(`channel_type` + `channel_id`),并拥有独立的设置:自动分配、工作时间、CSAT 调查、欢迎语、离线消息、品牌名等。
### 用户操作流程
1. **创建 Inbox**:管理员进入 Settings → Inboxes → 点击 "Add Inbox",选择渠道类型(WebWidget/Telegram/WhatsApp等),填写渠道配置,系统自动创建 Channel + Inbox
2. **查看 Inbox 列表**:按账户加载所有 Inbox(含 channel、portal、working_hours、avatar)
3. **更新 Inbox 设置**:修改名称、欢迎语、工作时间、CSAT、自动分配、品牌名、时区等;同时可更新底层 Channel 的属性
4. **删除 Inbox**:级联删除 Channel、InboxMember、Conversation、ContactInbox、Campaign 等
5. **查看可分配 Agent**:获取 Inbox 的 assignable_agents(成员 + 管理员)
6. **设置/移除 Agent Bot**:为 Inbox 关联一个 AgentBot(AI/自动回复机器人)
7. **上传/移除 Avatar**:Inbox 支持头像(ActiveStorage attachment)
### 涉及的API端点
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/api/v1/accounts/{account_id}/inboxes` | 列出所有 Inbox |
| POST | `/api/v1/accounts/{account_id}/inboxes` | 创建 Inbox(含 channel 参数) |
| GET | `/api/v1/accounts/{account_id}/inboxes/{id}` | 查看单个 Inbox |
| PATCH/PUT | `/api/v1/accounts/{account_id}/inboxes/{id}` | 更新 Inbox 设置 + Channel 属性 |
| DELETE | `/api/v1/accounts/{account_id}/inboxes/{id}` | 删除 Inbox |
| GET | `/api/v1/accounts/{account_id}/inboxes/{id}/assignable_agents` | (已废弃) 可分配 Agent |
| GET | `/api/v1/accounts/{account_id}/inboxes/{id}/campaigns` | Inbox 下的 Campaign |
| POST | `/api/v1/accounts/{account_id}/inboxes/{id}/avatar` | 移除头像 |
| POST | `/api/v1/accounts/{account_id}/inboxes/{id}/set_agent_bot` | 设置 Agent Bot |
### 涉及的数据模型 + 关键字段
- **Inbox** (`inboxes` 表)
- `id`, `name` (必填), `account_id` (必填), `channel_type` (多态类型), `channel_id` (多态ID)
- `enable_auto_assignment` (默认 true), `enable_email_collect` (默认 true)
- `greeting_enabled`, `greeting_message`, `out_of_office_message`
- `working_hours_enabled` (默认 false), `timezone` (默认 "UTC")
- `csat_survey_enabled` (默认 false), `csat_config` (jsonb: display_type/message/button_text/language/survey_rules)
- `allow_messages_after_resolved` (默认 true)
- `lock_to_single_conversation` (默认 false)
- `sender_name_type` (enum: friendly=0 / professional=1)
- `business_name`, `email_address`, `auto_assignment_config` (jsonb)
- `portal_id` (关联帮助中心 Portal)
- 关联: `has_many :inbox_members`, `has_many :contact_inboxes`, `has_many :conversations`, `has_many :campaigns`, `has_one :agent_bot_inbox`, `has_one :inbox_assignment_policy`, `has_many :webhooks`, `has_many :working_hours`, `belongs_to :channel` (多态, dependent: :destroy)
- **WorkingHour** (`working_hours` 表)
- `inbox_id`, `day_of_week`, `open_hour`, `open_minutes`, `close_hour`, `close_minutes`
- `closed_all_day`, `open_all_day`
- **AgentBotInbox** (`agent_bot_inboxes` 表)
- `inbox_id`, `agent_bot_id`, `account_id`, `status` (active/inactive)
### 涉及的业务逻辑(service层)
- `InboxesController#create` → 事务中先创建 Channel 再创建 Inbox
- `InboxesController#update` → 更新 Inbox 参数 + `update_inbox_working_hours` + `update_channel`(如果 channel 参数存在)
- `InboxesHelper#validate_email_channel` → 验证 IMAP/SMTP 连接
- `OutOfOffisable` concern → `out_of_office?` / `working_now?` / `create_default_working_hours` / `update_working_hours`
- `InboxAgentAvailability` concern → `available_agents`(基于 OnlineStatusTracker 筛选在线成员)
### 涉及的自动化/规则/事件
- `after_create_commit :dispatch_create_event` → 发布 `INBOX_CREATED` 事件
- `after_update_commit :dispatch_update_event` → 发布 `INBOX_UPDATED` 事件
- `after_destroy :delete_round_robin_agents` → 清除 Redis Round Robin 队列
- `validate_limit` → 创建前检查账户 Inbox 数量上限(企业版有更细粒度限制)
### Chatwoot原实现关键代码文件路径
- `app/models/inbox.rb`
- `app/models/concerns/out_of_offisable.rb`
- `app/models/concerns/inbox_agent_availability.rb`
- `app/models/working_hour.rb`
- `app/models/agent_bot_inbox.rb`
- `app/controllers/api/v1/accounts/inboxes_controller.rb`
- `app/helpers/api/v1/inboxes_helper.rb`
- `app/views/api/v1/accounts/inboxes/*.json.jbuilder`
### 版本标注:社区版 / 企业版
- **社区版**:Inbox CRUD、工作时间、CSAT、AgentBot、Avatar、基本数量限制
- **企业版**:Inbox数量精确限制(PlanUsageAndLimits)、InboxCapacityLimits、Captain Assistant绑定、CSAT模板
---
## 2. InboxMember绑定
### 功能描述
InboxMember 将 User(客服/Agent)绑定到 Inbox,形成「哪些Agent可以处理该收件箱的对话」的关系。创建/删除 InboxMember 会自动维护 Round Robin 队列。
### 用户操作流程
1. **查看 Inbox 成员**:进入 Inbox Settings → 查看已绑定的 Agent 列表
2. **添加成员**:选择 Agent 添加到 Inbox,触发 Round Robin 入队
3. **批量更新成员**:传入完整 user_ids 列表,自动计算增量(新增/移除)
4. **移除成员**:从 Inbox 中移除 Agent,触发 Round Robin 出队
5. **Widget端查看成员**:前端 Widget 可查询 Inbox 的在线成员列表
### 涉及的API端点
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/api/v1/accounts/{account_id}/inbox_members/{inbox_id}` | 查看成员列表 |
| POST | `/api/v1/accounts/{account_id}/inbox_members/{inbox_id}` | 添加成员 |
| PATCH/PUT | `/api/v1/accounts/{account_id}/inbox_members/{inbox_id}` | 批量更新成员 |
| DELETE | `/api/v1/accounts/{account_id}/inbox_members/{inbox_id}` | 移除成员 |
| GET | `/api/v1/widget/inbox_members` | Widget端查看成员(公开) |
### 涉及的数据模型 + 关键字段
- **InboxMember** (`inbox_members` 表)
- `id`, `inbox_id` (必填), `user_id` (必填)
- 联合唯一索引: `(inbox_id, user_id)`
- `belongs_to :inbox`, `belongs_to :user`
### 涉及的业务逻辑(service层)
- `InboxMembersController` → 调用 `@inbox.add_members(user_ids)` / `@inbox.remove_members(user_ids)`
- `Inbox#add_members` → 批量创建 `inbox_members` + `update_account_cache`
- `Inbox#remove_members` → 批量删除 + `update_account_cache`
### 涉及的自动化/规则/事件
- `InboxMember after_create :add_agent_to_round_robin` → 调用 `AutoAssignment::InboxRoundRobinService#add_agent_to_queue`
- `InboxMember after_destroy :remove_agent_from_round_robin` → 调用 `AutoAssignment::InboxRoundRobinService#remove_agent_from_queue`
- `Audit::InboxMember` mod → 审计日志记录
### Chatwoot原实现关键代码文件路径
- `app/models/inbox_member.rb`
- `app/models/inbox.rb` (add_members/remove_members)
- `app/controllers/api/v1/accounts/inbox_members_controller.rb`
- `app/controllers/api/v1/widget/inbox_members_controller.rb`
- `app/services/auto_assignment/inbox_round_robin_service.rb`
### 版本标注:社区版
---
## 3. Channelable多渠道模式
### 功能描述
Chatwoot 采用多态 + Concern 的设计模式实现多渠道。每个渠道类型(WebWidget/Telegram/Facebook/WhatsApp/Email 等)都是独立的 Channel 模型,通过 `Channelable` concern 统一接入 Inbox。Inbox 通过 `belongs_to :channel, polymorphic: true, dependent: :destroy` 关联,`channel_type` 字段存储类名(如 `'Channel::WebWidget'`),`channel_id` 存储对应表的 PK。
### 用户操作流程
1. 创建 Inbox 时选择渠道类型 → Controller 根据类型动态创建对应 Channel 模型
2. 更新 Inbox 时可选更新 Channel 属性 → 每个 Channel 模型定义 `EDITABLE_ATTRS` 常量控制可修改字段
3. 删除 Inbox → 级联删除 Channel 记录(`dependent: :destroy_async`)
### 涉及的数据模型 + 关键字段
- **Channelable concern** 核心逻辑:
- `validates :account_id, presence: true`
- `belongs_to :account`
- `has_one :inbox, as: :channel, dependent: :destroy_async, touch: true`
- `after_update :create_audit_log_entry`
- **Inbox 多态关联**:
- `belongs_to :channel, polymorphic: true, dependent: :destroy`
- `channel_type` 存储类名如 `'Channel::WebWidget'`
- `channel_id` 存储对应表的 PK
### 涉及的业务逻辑(service层)
- `InboxesController#channel_type_from_params` → 映射参数类型名到 Channel 类:
```ruby
{ 'web_widget' => Channel::WebWidget, 'api' => Channel::Api,
'email' => Channel::Email, 'line' => Channel::Line,
'telegram' => Channel::Telegram, 'whatsapp' => Channel::Whatsapp,
'sms' => Channel::Sms }
```
- `InboxesController#create_channel` → 根据 `EDITABLE_ATTRS` 创建 Channel 实例
- `InboxesController#update_channel` → 读取 `EDITABLE_ATTRS`,验证/更新 Channel 属性
- `InboxesController#allowed_channel_types` → 仅允许 `web_widget/api/email/line/telegram/whatsapp/sms` 七种通过此 Controller 创建(Facebook/Twilio/Instagram/TikTok/Twitter 有独立的创建流程)
### Chatwoot原实现关键代码文件路径
- `app/models/concerns/channelable.rb`
- `app/models/inbox.rb` (多态 belongs_to)
- `app/controllers/api/v1/accounts/inboxes_controller.rb` (create_channel / update_channel)
- `app/models/channel/web_widget.rb`, `telegram.rb`, `whatsapp.rb`, `email.rb`, `api.rb`, `sms.rb`, `line.rb`, `facebook_page.rb`, `instagram.rb`, `twilio_sms.rb`, `twitter_profile.rb`, `tiktok.rb`
### 版本标注:社区版(所有渠道模型均在社区版)
---
## 4. WebWidget渠道
### 功能描述
WebWidget 是 Chatwoot 的核心内置渠道,为网站提供嵌入式聊天窗口。支持自定义外观(颜色/欢迎语/回复时间)、预聊天表单、HMAC验证、域名白名单、邮件回访等。
### 用户操作流程
1. **创建 WebWidget Inbox**:选择 "Website" 渠道 → 输入网站URL、Widget颜色、欢迎标题/标语 → 生成 `website_token`
2. **配置 Widget**:设置预聊天表单(字段类型/必填/占位符)、HMAC强制验证、允许域名列表、邮件回访
3. **嵌入网站**:将生成的 JS SDK + `website_token` 嵌入目标网站
4. **Portal 关联**:WebWidget 可关联到 Portal(帮助中心),`portals.channel_web_widget_id`
### 涉及的API端点
- 创建/更新通过 InboxesController(channel.type = 'web_widget')
- Widget 前端通过 `website_token` 发起对话(`/api/v1/widget/conversations`)
### 涉及的数据模型 + 关键字段
- **Channel::WebWidget** (`channel_web_widgets` 表)
- `id`, `account_id`
- `website_url` (网站URL), `website_token` (唯一,用于前端SDK标识)
- `widget_color` (默认 "#1f93ff"), `welcome_title`, `welcome_tagline`
- `reply_time` (enum: in_a_few_minutes / in_a_few_hours / in_a_day)
- `pre_chat_form_enabled` (默认 false), `pre_chat_form_options` (jsonb)
- `hmac_mandatory` (默认 false), `hmac_token` (唯一,用于身份验证)
- `allowed_domains` (域名白名单)
- `continuity_via_email` (默认 true,关闭对话后邮件通知)
- `feature_flags` (FlagShihTzu 位标志,控制 Widget 功能)
### 涉及的业务逻辑(service层)
- Widget SDK 加载 → 通过 `website_token` 定位 Channel → 创建 ContactInbox + Conversation
- HMAC 验证 → `hmac_mandatory` 强制前端传递 HMAC 签名
- 预聊天表单 → `pre_chat_form_options` 定义表单字段
### 涉及的自动化/规则/事件
- 创建时自动生成 `website_token` + `hmac_token`(`has_secure_token`)
- Portal 关联 → `portals.channel_web_widget_id` 外键
### Chatwoot原实现关键代码文件路径
- `app/models/channel/web_widget.rb`
- `app/javascript/widget/` (前端SDK)
- `app/controllers/api/v1/widget/` (Widget API)
- `db/migrate/20240415210313_add_channel_web_widget_to_portals.rb`
### 版本标注:社区版
---
## 5. Telegram渠道
### 功能描述
通过 Telegram Bot API 接入,将 Telegram Bot 的消息同步到 Chatwoot Inbox。支持文本、附件发送,支持获取用户头像。
### 用户操作流程
1. **创建 Telegram Inbox**:输入 Bot Token → 系统验证 Token 有效性 → 自动注册 Webhook
2. **收发消息**:用户在 Telegram 发消息 → Webhook 推送到 Chatwoot → 创建 Conversation → Agent 回复通过 Bot API 发回 Telegram
3. **更新**:可修改 Bot Token(重新验证 + 重设 Webhook)
### 涉及的API端点
- 创建/更新通过 InboxesController(channel.type = 'telegram')
- Telegram Webhook: `/webhooks/telegram/{bot_token}` → `Webhooks::TelegramController#process_payload`
### 涉及的数据模型 + 关键字段
- **Channel::Telegram** (`channel_telegram` 表)
- `id`, `account_id`
- `bot_token` (必填, 唯一, 可加密), `bot_name`
- `EDITABLE_ATTRS = [:bot_token]`
### 涉及的业务逻辑(service层)
- `Telegram::IncomingMessageService` → 解析 Telegram Webhook payload → 创建/更新 Conversation + Message
- `Telegram::SendOnTelegramService` → Agent 回复通过 Bot API 发送
- `Telegram::SendAttachmentsService` → 处理附件发送
- `Telegram::UpdateMessageService` → 更新已发送消息
### 涉及的自动化/规则/事件
- `before_validation :ensure_valid_bot_token` → 创建时验证 Bot Token 有效(调用 `getMe` API)
- `before_save :setup_telegram_webhook` → 自动注册 Telegram Webhook URL
### Chatwoot原实现关键代码文件路径
- `app/models/channel/telegram.rb`
- `app/controllers/webhooks/telegram_controller.rb`
- `app/services/telegram/incoming_message_service.rb`
- `app/services/telegram/send_on_telegram_service.rb`
- `app/services/telegram/send_attachments_service.rb`
- `app/jobs/webhooks/telegram_events_job.rb`
### 版本标注:社区版
---
## 6. Facebook / Instagram渠道
### 功能描述
通过 Facebook Graph API 接入 Facebook Page 消息(Messenger)和 Instagram DM。需要 OAuth 授权获取 Page Access Token,支持 Webhook 接收消息,支持 Reauthorization 机制。
### 用户操作流程
1. **Facebook 创建**:通过 OAuth 流程 → 选择 Page → 获取 Page Access Token → 自动订阅 Webhook
2. **Instagram 创建**:类似 Facebook OAuth → 获取 Instagram Business Account ID + Access Token
3. **收发消息**:Facebook/Instagram Webhook 推送 → 创建 Conversation → Agent 回复通过 Graph API 发回
4. **Reauthorization**:Token 失效后提示重新授权(Reauthorizable concern)
### 涉及的API端点
- Facebook OAuth: `/api/v1/accounts/{id}/facebook/authorize`
- Instagram OAuth: `/api/v1/accounts/{id}/instagram/authorizations`
- Facebook Webhook: `/webhooks/facebook` (全局)
- Instagram Webhook: `/webhooks/instagram/{instagram_id}` → `Webhooks::InstagramController`
- InboxesController 创建 Facebook/Instagram Inbox(通过 OAuth 回调后)
### 涉及的数据模型 + 关键字段
- **Channel::FacebookPage** (`channel_facebook_pages` 表)
- `id`, `account_id`, `page_id` (必填, scope唯一), `page_access_token` (加密), `user_access_token` (加密)
- `instagram_id` (可选,关联 Instagram Business Account)
- `include Reauthorizable`
- **Channel::Instagram** (`channel_instagram` 表)
- `id`, `account_id`, `instagram_id` (必填, 唯一), `access_token` (加密), `expires_at`
- `include Reauthorizable`, `AUTHORIZATION_ERROR_THRESHOLD = 1`
### 涉及的业务逻辑(service层)
- `Facebook::SendOnFacebookService` → 通过 Graph API 发送 Messenger 消息
- `Instagram::SendOnInstagramService` / `Instagram::Messenger::SendOnInstagramService` → 发送 Instagram DM
- `Instagram::RefreshOauthTokenService` → 刷新 Instagram Access Token
- `Channel::FacebookPage#subscribe` / `unsubscribe` → 注册/注销 Facebook Webhook
- `Channel::Instagram#subscribe` / `unsubscribe` → 注册/注销 Instagram Webhook
### 涉及的自动化/规则/事件
- `after_create_commit :subscribe` → 自动订阅 Facebook/Instagram Webhook
- `before_destroy :unsubscribe` → 删除时注销 Webhook
- `Reauthorizable` → Token 失效计数 + 邮件通知 + UI 提示重新授权
### Chatwoot原实现关键代码文件路径
- `app/models/channel/facebook_page.rb`
- `app/models/channel/instagram.rb`
- `app/models/concerns/reauthorizable.rb`
- `app/controllers/webhooks/instagram_controller.rb`
- `app/controllers/api/v1/accounts/instagram/authorizations_controller.rb`
- `app/services/facebook/send_on_facebook_service.rb`
- `app/services/instagram/send_on_instagram_service.rb`
- `app/services/instagram/refresh_oauth_token_service.rb`
### 版本标注:社区版
---
## 7. WhatsApp渠道
### 功能描述
支持两种 WhatsApp 提供商:360dialog(默认)和 WhatsApp Cloud API(Meta官方)。创建时需要手机号 + provider配置,自动同步消息模板,自动设置 Webhook。
### 用户操作流程
1. **创建 WhatsApp Inbox**:选择 Provider → 输入手机号 → 配置 API Key / Webhook Verify Token
2. **Embedded Signup(企业版)**:通过 Meta Embedded Signup 流程一键创建
3. **模板管理**:自动同步 WhatsApp 消息模板 → 用于 Campaign 发送
4. **收发消息**:WhatsApp Webhook 推送 → 创建 Conversation → Agent 回复通过 Provider API 发回
### 涟及的API端点
- 创建/更新通过 InboxesController(channel.type = 'whatsapp')
- WhatsApp Webhook: `/webhooks/whatsapp/{phone_number}` → `Webhooks::WhatsappController`
- WhatsApp Health: `/api/v1/accounts/{id}/inboxes/{id}/whatsapp_health` (企业版 WhatsappHealthManagement)
### 涉及的数据模型 + 关键字段
- **Channel::Whatsapp** (`channel_whatsapp` 表)
- `id`, `account_id`, `phone_number` (必填, 唯一)
- `provider` (enum: default / whatsapp_cloud)
- `provider_config` (jsonb: webhook_verify_token, api_key, source 等)
- `message_templates` (jsonb), `message_templates_last_updated`
- `include Reauthorizable`
### 涉及的业务逻辑(service层)
- `Whatsapp::IncomingMessageWhatsappCloudService` / `Whatsapp::IncomingMessageBaseService` → 处理 WhatsApp Webhook payload
- `Whatsapp::SendOnWhatsappService` → 通过 Provider API 发送消息
- `Whatsapp::ChannelCreationService` → 创建 WhatsApp Channel
- `Whatsapp::WebhookSetupService` / `Whatsapp::WebhookTeardownService` → 设置/注销 Webhook
- `Whatsapp::TokenExchangeService` / `Whatsapp::TokenValidationService` → Token 管理
- `Whatsapp::TemplateProcessorService` / `Whatsapp::SyncTemplatesJob` → 模板同步
- `Whatsapp::EmbeddedSignupService` → Meta Embedded Signup 流程
- `Whatsapp::ReauthorizationService` → 360dialog Token 重新授权
- `Whatsapp::PhoneNumberNormalizationService` → 手机号规范化
### 涉及的自动化/规则/事件
- `after_create :sync_templates` → 创建时同步消息模板
- `after_commit :setup_webhooks, on: :create` → 自动设置 Webhook(条件: `should_auto_setup_webhooks?`)
- `before_destroy :teardown_webhooks` → 删除时注销 Webhook
- Webhook 签名验证 → `MetaTokenVerifyConcern` (WhatsApp Cloud)
- `Reauthorizable` → Token 失效处理
### Chatwoot原实现关键代码文件路径
- `app/models/channel/whatsapp.rb`
- `app/controllers/webhooks/whatsapp_controller.rb`
- `app/services/whatsapp/incoming_message_whatsapp_cloud_service.rb`
- `app/services/whatsapp/incoming_message_base_service.rb`
- `app/services/whatsapp/send_on_whatsapp_service.rb`
- `app/services/whatsapp/webhook_setup_service.rb`
- `app/services/whatsapp/channel_creation_service.rb`
- `app/services/whatsapp/embedded_signup_service.rb`
- `app/services/whatsapp/reauthorization_service.rb`
- `app/controllers/api/v1/accounts/concerns/whatsapp_health_management.rb`
### 版本标注:社区版(核心功能)/ 企业版(Embedded Signup、WhatsApp Health Dashboard)
---
## 8. Email渠道
### 功能描述
通过 IMAP + SMTP 接入邮件,将客户邮件同步到 Chatwoot Inbox。支持 IMAP 收件(拉取邮件)和 SMTP 发件(Agent回复通过邮件发出),也支持邮件转发(forward_to_email)。
### 用户操作流程
1. **创建 Email Inbox**:输入邮箱地址 → 系统生成 `forward_to_email` → 可选配置 IMAP/SMTP
2. **配置 IMAP**:设置 IMAP 地址/端口/SSL/认证/登录凭据 → 验证连接 → 启用 IMAP 收件
3. **配置 SMTP**:设置 SMTP 地址/端口/SSL/认证/域名/登录凭据 → 验证连接 → 启用 SMTP 发件
4. **收发邮件**:IMAP 拉取 → 创建 Conversation → Agent 回复通过 SMTP 发出
### 涉及的API端点
- 创建/更新通过 InboxesController(channel.type = 'email')
- 更新时额外验证 IMAP/SMTP 连接(`InboxesHelper#validate_email_channel`)
### 涉及的数据模型 + 关键字段
- **Channel::Email** (`channel_email` 表)
- `id`, `account_id`, `email` (唯一), `forward_to_email` (唯一)
- IMAP: `imap_enabled`, `imap_address`, `imap_port`, `imap_login`, `imap_password`, `imap_enable_ssl`, `imap_authentication`
- SMTP: `smtp_enabled`, `smtp_address`, `smtp_port`, `smtp_login`, `smtp_password`, `smtp_domain`, `smtp_enable_ssl_tls`, `smtp_enable_starttls_auto`, `smtp_authentication`, `smtp_openssl_verify_mode`
- `provider`, `provider_config` (jsonb)
- `verified_for_sending` (默认 false)
- `EDITABLE_ATTRS` 包含所有 IMAP/SMTP 字段
### 涉及的业务逻辑(service层)
- `Email::SendOnEmailService` → Agent 回复通过 SMTP 发送邮件
- `Imap::FetchService` → 定期通过 IMAP 拉取新邮件 → 创建 Conversation/Message
- `InboxesHelper#validate_email_channel` → 创建/更新时验证 IMAP/SMTP 连接
### 涉及的自动化/规则/事件
- IMAP 拉取 → 定时任务(Scheduler)定期调用 `Imap::FetchService`
- SMTP 发件 → Agent 回复触发 `Email::SendOnEmailService`
- 验证 → 创建/更新 Email Inbox 时必须验证 IMAP/SMTP 连接
### Chatwoot原实现关键代码文件路径
- `app/models/channel/email.rb`
- `app/services/email/send_on_email_service.rb`
- `app/services/imap/fetch_service.rb`
- `app/helpers/api/v1/inboxes_helper.rb`
- `app/services/imap/` (IMAP 相关)
### 版本标注:社区版 / 企业版(Email Channel Migration - Platform API)
---
## 9. Twilio SMS / WhatsApp渠道
### 功能描述
通过 Twilio API 接入 SMS 和 WhatsApp 消息。Twilio 渠道有独立的创建流程(不通过 InboxesController),支持 API Key 认证、Messaging Service、语音通话(企业版)。
### 用户操作流程
1. **创建 Twilio Inbox**:输入 Account SID + Auth Token / API Key → 选择 medium (sms/whatsapp) → 输入手机号或 Messaging Service SID → 系统验证 Twilio 凭据 → 自动设置 Webhook
2. **收发消息**:Twilio Webhook 推送 → 创建 Conversation → Agent 回复通过 Twilio API 发回
3. **模板同步**:WhatsApp 模板可通过 Twilio Content API 同步
### 涉及的API端点
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | `/api/v1/accounts/{id}/channels/twilio_channel` | 创建 Twilio Inbox(独立 Controller) |
| POST | `/webhooks/twilio/callback` | Twilio 回调 Webhook |
### 涉及的数据模型 + 关键字段
- **Channel::TwilioSms** (`channel_twilio_sms` 表)
- `id`, `account_id`, `account_sid` (必填), `auth_token` (必填, 加密), `api_key_sid`, `api_key_secret`
- `phone_number`, `messaging_service_sid`
- `medium` (enum: sms=0 / whatsapp=1)
- `voice_enabled` (默认 false, 企业版语音通话)
- `content_templates` (jsonb), `content_templates_last_updated`
- `twiml_app_sid`
### 涉及的业务逻辑(service层)
- `Twilio::IncomingMessageService` → 处理 Twilio Webhook payload
- `Twilio::SendOnTwilioService` → 通过 Twilio API 发送消息
- `Twilio::WebhookSetupService` → 设置 Twilio Webhook URL
- `Twilio::DeliveryStatusService` → 处理消息送达状态回调
- `Twilio::TemplateSyncService` → 同步 WhatsApp Content Templates
- `Twilio::OneoffSmsCampaignService` → SMS 短信营销
### 涉及的自动化/规则/事件
- 创建时验证 Twilio 凭据(`authenticate_twilio` → `client.messages.list(limit: 1)`)
- 创建 SMS 时自动设置 Webhook(`setup_webhooks` → `Twilio::WebhookSetupService`)
### Chatwoot原实现关键代码文件路径
- `app/models/channel/twilio_sms.rb`
- `app/controllers/api/v1/accounts/channels/twilio_channels_controller.rb`
- `app/controllers/webhooks/twilio_controller.rb`
- `app/services/twilio/incoming_message_service.rb`
- `app/services/twilio/send_on_twilio_service.rb`
- `app/services/twilio/webhook_setup_service.rb`
- `app/services/twilio/template_sync_service.rb`
### 版本标注:社区版(SMS/WhatsApp)/ 企业版(Voice 通话、Twilio CSAT 模板)
---
## 10. 其他渠道(SMS、Line、Twitter、TikTok、API)
### SMS(Bandwidth)
- **Channel::Sms** (`channel_sms` 表)
- `phone_number` (唯一), `provider` (default), `provider_config` (jsonb: application_id 等)
- 通过 Bandwidth API 发送 SMS
- Webhook: `/webhooks/sms/{phone_number}` → `Webhooks::SmsController`
- **关键文件**: `app/models/channel/sms.rb`, `app/services/sms/`
### Line
- **Channel::Line** (`channel_line` 表)
- `line_channel_id` (唯一), `line_channel_secret`, `line_channel_token` (加密)
- 使用 `line-bot-api` gem
- Webhook: `/webhooks/line/{line_channel_id}` → `Webhooks::LineController`
- **关键文件**: `app/models/channel/line.rb`, `app/services/line/incoming_message_service.rb`, `app/services/line/send_on_line_service.rb`
### Twitter
- **Channel::TwitterProfile** (`channel_twitter_profiles` 表)
- `profile_id` (scope唯一), `twitter_access_token` (加密), `twitter_access_token_secret` (加密)
- `tweets_enabled` (默认 true)
- `before_destroy :unsubscribe`
- 注:Twitter API v1.1 已停用,此渠道功能受限
- **关键文件**: `app/models/channel/twitter_profile.rb`
### TikTok
- **Channel::Tiktok** (`channel_tiktok` 表)
- `business_id` (唯一), `access_token` (加密), `refresh_token` (加密)
- `expires_at`, `refresh_token_expires_at`
- `include Reauthorizable`
- OAuth 授权: `/api/v1/accounts/{id}/tiktok/authorizations`
- **关键文件**: `app/models/channel/tiktok.rb`, `app/services/tiktok/`, `app/controllers/webhooks/tiktok_controller.rb`
### API Channel
- **Channel::Api** (`channel_api` 表)
- `identifier` (唯一, auto token), `hmac_token` (唯一, auto token), `webhook_url`
- `hmac_mandatory`, `additional_attributes` (jsonb: agent_reply_time_window 等)
- `secret` (auto token, `WebhookSecretable`)
- 适合第三方系统通过 API + Webhook 集成
- **关键文件**: `app/models/channel/api.rb`, `app/controllers/api/v1/accounts/inboxes_controller.rb`
### 版本标注
- SMS/Line/Twitter/API: 社区版
- TikTok: 社区版(OAuth + Webhook)
---
## 11. Webhook回调(外部事件推送)
### 功能描述
Chatwoot 支持两类 Webhook:
1. **渠道 Webhook**:外部平台(Telegram/WhatsApp/Facebook等)向 Chatwoot 推送消息事件的回调入口
2. **用户自定义 Webhook**:Chatwoot 向外部系统推送内部事件(对话创建/更新/消息等)的出站 Webhook
### 用户操作流程
1. **渠道 Webhook**:创建渠道时自动注册 → 外部平台推送消息 → WebhookController 接收 → 异步 Job 处理
2. **自定义 Webhook**:管理员创建 Webhook → 选择订阅事件 → 事件触发时 Chatwoot POST 到指定 URL
### 涉及的API端点
**渠道 Webhook(入站)**:
| 路径 | 说明 |
|------|------|
| `/webhooks/telegram/{bot_token}` | Telegram 消息回调 |
| `/webhooks/whatsapp/{phone_number}` | WhatsApp 消息回调 |
| `/webhooks/line/{line_channel_id}` | Line 消息回调 |
| `/webhooks/sms/{phone_number}` | SMS 消息回调 |
| `/webhooks/instagram/{instagram_id}` | Instagram 消息回调 |
| `/webhooks/tiktok` | TikTok 消息回调 |
| `/webhooks/facebook` | Facebook 消息回调 |
| `/twilio/callback` | Twilio 回调 |
**自定义 Webhook(出站)**:
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/api/v1/accounts/{id}/webhooks` | 列出 Webhook |
| POST | `/api/v1/accounts/{id}/webhooks` | 创建 Webhook |
| PATCH | `/api/v1/accounts/{id}/webhooks/{wid}` | 更新 Webhook |
| DELETE | `/api/v1/accounts/{id}/webhooks/{wid}` | 删除 Webhook |
### 涉及的数据模型 + 关键字段
- **Webhook** (`webhooks` 表)
- `id`, `account_id`, `inbox_id` (可选), `url`, `name`, `secret` (WebhookSecretable)
- `subscriptions` (jsonb: 允许的事件列表)
- `webhook_type` (enum: account_type=0 / inbox_type=1)
- 联合唯一索引: `(account_id, url)`
### 允许的订阅事件
```ruby
ALLOWED_WEBHOOK_EVENTS = %w[
conversation_status_changed conversation_updated conversation_created
contact_created contact_updated
message_created message_updated
webwidget_triggered
inbox_created inbox_updated
conversation_typing_on conversation_typing_off
]
```
### 涉及的业务逻辑(service层)
- 各渠道 WebhookController → 接收 payload → 异步 Job 处理(如 `Webhooks::TelegramEventsJob`, `Webhooks::WhatsappEventsJob`)
- 自定义 Webhook → 事件触发时 `WebhookJob` POST 到用户指定 URL(带 HMAC 签名)
- `WebhookSecretable` → 生成/验证 Webhook Secret
### 涉及的自动化/规则/事件
- 渠道创建时自动注册 Webhook(Telegram/WhatsApp/Facebook/Instagram/Twilio)
- 渠道删除时自动注销 Webhook
- WhatsApp Webhook 签名验证 → `MetaTokenVerifyConcern`
### Chatwoot原实现关键代码文件路径
- `app/controllers/webhooks/` (各渠道 Webhook Controller)
- `app/models/webhook.rb`
- `app/controllers/api/v1/accounts/webhooks_controller.rb`
- `app/models/concerns/webhook_secretable.rb`
- `app/jobs/webhooks/` (各渠道异步 Job)
### 版本标注:社区版
---
## 12. OAuth刷新 / Reauthorizable
### 功能描述
部分渠道(Facebook、Instagram、WhatsApp、TikTok)依赖外部 OAuth Token,Token 可能过期或失效。`Reauthorizable` concern 提供统一机制:计数授权错误 → 达到阈值后标记需要重新授权 → 发邮件通知 → UI 提示重新授权流程。
### 用户操作流程
1. **正常使用**:Token 有效,消息正常收发
2. **Token 失效**:外部 API 返回授权错误 → `authorization_error!` 计数 +1
3. **达到阈值**:标记 `reauthorization_required?` → 发邮件通知管理员 → UI 显示"需要重新授权"提示
4. **重新授权**:管理员点击重新授权 → 通过 OAuth 流程获取新 Token → `reauthorized!` 清除标记
5. **自动刷新**:Instagram/Google/Microsoft 有 `RefreshOauthTokenService` 自动刷新 Token
### 涉及的数据模型 + 关键字段
- **Reauthorizable concern**:
- `reauthorization_required?` → Redis 键检查
- `authorization_error_count` → Redis 计数
- `authorization_error!` → 计数递增 + 阈值判断
- `prompt_reauthorization!` → 设置 Redis 标记 + 发邮件
- `reauthorized!` → 清除 Redis 标记 + 计数
- 使用此 concern 的模型:
- `Channel::FacebookPage` (阈值=2)
- `Channel::Instagram` (阈值=1)
- `Channel::Whatsapp` (阈值=2)
- `Channel::Tiktok` (阈值=1)
### 涉及的业务逻辑(service层)
- `Instagram::RefreshOauthTokenService` → 自动刷新 Instagram Token
- `Google::RefreshOauthTokenService` → 自动刷新 Google Token
- `Microsoft::RefreshOauthTokenService` → 自动刷新 Microsoft Token
- `Whatsapp::ReauthorizationService` → 360dialog Token 重新授权
- `Tiktok::TokenService` → TikTok Token 管理
### 涉及的自动化/规则/事件
- `Inbox#dispatch_reauthorization_event` → 发布 `INBOX_UPDATED` 事件(包含 reauthorization_required 变化)
- 邮件通知 → `Reauthorizable` 阈值触发时发送邮件给管理员
- `after_update :create_audit_log_entry` (Channelable) → Channel 更新时创建审计日志
### Chatwoot原实现关键代码文件路径
- `app/models/concerns/reauthorizable.rb`
- `app/models/inbox.rb` (dispatch_reauthorization_event)
- `app/services/instagram/refresh_oauth_token_service.rb`
- `app/services/google/refresh_oauth_token_service.rb`
- `app/services/microsoft/refresh_oauth_token_service.rb`
- `app/services/whatsapp/reauthorization_service.rb`
- `app/services/tiktok/token_service.rb`
### 版本标注:社区版
---
## 13. 企业版InboxCapacity
### 功能描述
企业版的 Agent Capacity Policy 机制允许为每个 Inbox + Agent 组合设定对话数量上限(`conversation_limit`)。当 Agent 在某 Inbox 的活跃对话数达到上限时,自动分配系统不再将新对话分配给该 Agent。
### 用户操作流程
1. **创建 Agent Capacity Policy**:定义全局分配容量策略
2. **设置 Inbox 容量限制**:为 Policy 下的每个 Inbox 设定 `conversation_limit`
3. **分配生效**:自动分配时检查 Agent 在该 Inbox 的容量是否已满
### 涉及的API端点
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | `/api/v1/accounts/{id}/agent_capacity_policies/{policy_id}/inbox_limits` | 创建 Inbox 容量限制 |
| PATCH | `/api/v1/accounts/{id}/agent_capacity_policies/{policy_id}/inbox_limits/{limit_id}` | 更新限制 |
| DELETE | `/api/v1/accounts/{id}/agent_capacity_policies/{policy_id}/inbox_limits/{limit_id}` | 删除限制 |
### 涉及的数据模型 + 关键字段
- **InboxCapacityLimit** (`inbox_capacity_limits` 表)
- `id`, `agent_capacity_policy_id` (必填), `inbox_id` (必填)
- `conversation_limit` (必填, >=0)
- 联合唯一索引: `(agent_capacity_policy_id, inbox_id)`
- **Enterprise::Concerns::Inbox** → `has_many :inbox_capacity_limits`
- **AgentCapacityPolicy** → `has_many :inbox_capacity_limits`
- **Inbox#member_ids_with_assignment_capacity** → 企业版覆写,返回有剩余容量的成员 ID
### 涉及的业务逻辑(service层)
- `Api::V1::Accounts::AgentCapacityPolicies::InboxLimitsController` → CRUD InboxCapacityLimit
- `Inbox#member_ids_with_assignment_capacity` → 社区版返回所有 member_ids,企业版根据容量筛选
- `Enterprise::Account::PlanUsageAndLimits` → `usage_limits` 包含 `inboxes` 数量限制
### 涉及的自动化/规则/事件
- 创建 InboxCapacityLimit 时验证无重复(同一 Policy + Inbox 只能有一条)
- 自动分配时 `member_ids_with_assignment_capacity` 筛选有容量的 Agent
- `validate_limit` → 创建 Inbox 时检查账户 Inbox 数量上限
### Chatwoot原实现关键代码文件路径
- `enterprise/app/models/inbox_capacity_limit.rb`
- `enterprise/app/models/enterprise/concerns/inbox.rb`
- `enterprise/app/models/enterprise/account/plan_usage_and_limits.rb`
- `enterprise/app/controllers/api/v1/accounts/agent_capacity_policies/inbox_limits_controller.rb`
- `app/models/concerns/inbox_agent_availability.rb` (社区版 member_ids_with_assignment_capacity)
### 版本标注:**企业版**
---
## 附录:渠道模型对照表
| 渠道 | 模型类 | 表名 | 关键标识字段 | 创建方式 | Reauthorizable | 加密字段 |
|------|--------|------|------------|---------|---------------|---------|
| WebWidget | Channel::WebWidget | channel_web_widgets | website_token | InboxesController | ❌ | ❌ |
| Telegram | Channel::Telegram | channel_telegram | bot_token | InboxesController | ❌ | bot_token |
| Facebook | Channel::FacebookPage | channel_facebook_pages | page_id | OAuth回调 | ✅ (阈值2) | page_access_token, user_access_token |
| Instagram | Channel::Instagram | channel_instagram | instagram_id | OAuth回调 | ✅ (阈值1) | access_token |
| WhatsApp | Channel::Whatsapp | channel_whatsapp | phone_number | InboxesController | ✅ (阈值2) | ❌ (provider_config含API key) |
| Email | Channel::Email | channel_email | email | InboxesController | ❌ | imap_password, smtp_password |
| Twilio | Channel::TwilioSms | channel_twilio_sms | account_sid+phone_number | TwilioChannelsController | ❌ | auth_token |
| SMS | Channel::Sms | channel_sms | phone_number | InboxesController | ❌ | ❌ |
| Line | Channel::Line | channel_line | line_channel_id | InboxesController | ❌ | line_channel_secret, line_channel_token |
| Twitter | Channel::TwitterProfile | channel_twitter_profiles | account_id+profile_id | OAuth | ❌ | twitter_access_token, twitter_access_token_secret |
| TikTok | Channel::Tiktok | channel_tiktok | business_id | OAuth回调 | ✅ (阈值1) | access_token, refresh_token |
| API | Channel::Api | channel_api | identifier | InboxesController | ❌ | ❌ |
---
## 附录:Inbox多态类型判断方法
```ruby
# Inbox 模型中的渠道类型判断方法
inbox.web_widget? # Channel::WebWidget
inbox.telegram? # Channel::Telegram
inbox.facebook? # Channel::FacebookPage
inbox.instagram? # Facebook? + channel.instagram_id.present? || Channel::Instagram
inbox.whatsapp? # Channel::Whatsapp
inbox.email? # Channel::Email
inbox.twilio? # Channel::TwilioSms
inbox.twilio_whatsapp? # Channel::TwilioSms && medium == 'whatsapp'
inbox.sms? # Channel::Sms
inbox.twitter? # Channel::TwitterProfile
inbox.tiktok? # Channel::Tiktok
inbox.api? # Channel::Api
# Inbox 通用类型名
inbox.inbox_type # channel.name (如 'WebWidget', 'Telegram', 'Whatsapp' 等)
```
---
## 附录:Inbox回调Webhook URL生成
```ruby
# Inbox#callback_webhook_url 根据渠道类型生成
Channel::TwilioSms → "#{FRONTEND_URL}/twilio/callback"
Channel::Sms → "#{FRONTEND_URL}/webhooks/sms/#{phone_number}"
Channel::Line → "#{FRONTEND_URL}/webhooks/line/#{line_channel_id}"
Channel::Whatsapp → "#{FRONTEND_URL}/webhooks/whatsapp/#{phone_number}"
```