34 KiB
M12 平台与集成 — Chatwoot 功能梳理文档
基于 Chatwoot 源码深度阅读 + CodeGraph 上下文梳理
生成日期:2026-05-22
参照仓库:chatwoot-reference
模块覆盖:PlatformApp · AgentBot · DashboardApp · DataImport · Webhook · AccessToken认证 · InstallationConfig
目录
- PlatformApp(平台应用 / Partner API)
- PlatformAppPermissible(权限授权)
- Platform API 路由体系
- AccessToken 与 AccessTokenable(API令牌认证)
- AccessTokenAuthHelper(令牌鉴权中间件)
- AgentBot(智能机器人)
- AgentBotInbox(Bot-Inbox绑定)
- AgentBotListener(Bot事件监听)
- AgentBots::WebhookJob(Bot Webhook投递)
- DashboardApp(仪表盘扩展应用)
- DataImport(数据导入)
- DataImportJob + ContactManager(导入处理流程)
- Webhook(账户级Webhook)
- WebhookSecretable(签名密钥机制)
- Webhooks::Trigger(Webhook投递引擎)
- InstallationConfig(平台级配置)
- GlobalConfig + GlobalConfigService(配置缓存层)
1. PlatformApp(平台应用 / Partner API)
功能描述
PlatformApp 是 Chatwoot 为第三方合作伙伴(Partner)提供的平台级 API 认证主体。每个 PlatformApp 拥有一个 AccessToken,通过该令牌可调用 Platform API(独立于普通 Account API),实现对用户、账户、AgentBot、AccountUser 等资源的 CRUD 管理。PlatformApp 与被操作资源之间通过 PlatformAppPermissible 多态关联授权——只有被授权的资源才能被该 PlatformApp 访问/修改。
用户操作流程
- Super Admin 在后台创建 PlatformApp,系统自动生成 AccessToken
- 第三方系统持有该 AccessToken,通过
api_access_tokenHeader 调用 Platform API - PlatformController 验证令牌 → 解析出 PlatformApp → 校验 Permissible 授权范围
- 通过授权校验后,第三方可操作被授权的 Account / User / AgentBot 等资源
- 第三方可通过
POST /platform/api/v1/users/:id/token获取用户的 SSO 登录令牌
涉及的API端点
| 方法 | 路径 | 说明 |
|---|---|---|
| Super Admin CRUD | /super_admin/platform_apps |
管理后台管理 PlatformApp |
| GET | /platform/api/v1/users |
列出授权用户(需 Permissible) |
| POST | /platform/api/v1/users |
创建用户并自动授权 |
| GET | /platform/api/v1/users/:id |
查看(需 Permissible) |
| PATCH | /platform/api/v1/users/:id |
更新(需 Permissible) |
| DELETE | /platform/api/v1/users/:id |
删除(需 Permissible) |
| GET | /platform/api/v1/users/:id/login |
获取用户 SSO 登录 URL |
| POST | /platform/api/v1/users/:id/token |
获取用户 API Token |
| GET | /platform/api/v1/accounts |
列出授权账户 |
| POST | /platform/api/v1/accounts |
创建账户并授权 |
| GET | /platform/api/v1/accounts/:id |
查看授权账户 |
| PATCH | /platform/api/v1/accounts/:id |
更新授权账户(含 features/limits) |
| DELETE | /platform/api/v1/accounts/:id |
删除授权账户 |
| GET | /platform/api/v1/accounts/:account_id/account_users |
列出账户成员 |
| POST | /platform/api/v1/accounts/:account_id/account_users |
添加账户成员 |
| DELETE | /platform/api/v1/accounts/:account_id/account_users |
移除账户成员 |
| GET | /platform/api/v1/agent_bots |
列出授权 AgentBot |
| POST | /platform/api/v1/agent_bots |
创建 AgentBot 并授权 |
| GET | /platform/api/v1/agent_bots/:id |
查看授权 AgentBot |
| PATCH | /platform/api/v1/agent_bots/:id |
更新授权 AgentBot |
| DELETE | /platform/api/v1/agent_bots/:id |
删除授权 AgentBot |
| DELETE | /platform/api/v1/agent_bots/:id/avatar |
删除 AgentBot 头像 |
| POST | /platform/api/v1/accounts/:account_id/email_channel_migrations |
执行邮箱渠道迁移 |
涉及的数据模型+关键字段
- PlatformApp(
platform_apps表):id(bigint, PK)name(string, NOT NULL) — 应用名称created_at,updated_at(datetime)- 关联:
has_many :platform_app_permissibles, dependent: :destroy_async - Concern:
include AccessTokenable(创建时自动生成 AccessToken) - 验证:
validates :name, presence: true
涉及的业务逻辑
- PlatformApp 创建时:
AccessTokenableconcern 的after_create :create_access_token自动创建 AccessToken - PlatformController(
app/controllers/platform_controller.rb):全局鉴权基类ensure_access_token— 从 Header 中解析api_access_tokenset_platform_app— 从 AccessToken owner 解析出 PlatformApp,否则返回 401validate_platform_app_permissible— 校验当前资源是否在 Permissible 授权范围内
- 各子 Controller:继承 PlatformController,在 create 操作时自动创建 Permissible 授权关系
2. PlatformAppPermissible(权限授权)
功能描述
PlatformAppPermissible 是 PlatformApp 与被授权资源之间的多态授权桥梁。每个 Permissible 记录代表"某 PlatformApp 可以操作某资源"。资源类型可以是 Account、User、AgentBot 等。创建用户/账户/AgentBot 时,子控制器会自动为 PlatformApp 添加 Permissible 记录。
涉及的数据模型+关键字段
- PlatformAppPermissible(
platform_app_permissibles表):id(bigint, PK)platform_app_id(bigint, NOT NULL) — 所属 PlatformApppermissible_id(bigint, NOT NULL) — 被授权资源 IDpermissible_type(string, NOT NULL) — 被授权资源类型(Account / User / AgentBot 等)created_at,updated_at(datetime)- 索引:
index_platform_app_permissibles_on_permissibles— (permissible_type, permissible_id)index_platform_app_permissibles_on_platform_app_id— (platform_app_id)unique_permissibles_index— (platform_app_id, permissible_id, permissible_type) UNIQUE
- 关联:
belongs_to :platform_app,belongs_to :permissible, polymorphic: true - 验证:
validates :platform_app, presence: true; uniqueness scoped by[permissible_id, permissible_type]
涉及的业务逻辑
- 授权校验:
PlatformController#validate_platform_app_permissible查询platform_app_permissibles.find_by(permissible: @resource),不在授权范围内返回 401 - 自动授权:
UsersController#create→find_or_create_by(permissible: @resource)AccountsController#create→find_or_create_by(permissible: @resource)AgentBotsController#create→find_or_create_by(permissible: @resource)
- 查询授权资源:
AccountsController#index→ 查询where(permissible_type: 'Account')并 includes permissibleAgentBotsController#index→ 查询where(permissible_type: 'AgentBot')
3. Platform API 路由体系
功能描述
Platform API 是 Chatwoot 提供给合作伙伴的独立 API 套件,使用 AccessToken(而非 User session)鉴权,路由独立于 Account API 体系。所有 Platform API 控制器继承 PlatformController,统一走 AccessToken + Permissible 双重校验。
路由结构
namespace :platform, defaults: { format: 'json' } do
namespace :api do
namespace :v1 do
resources :users, only: [:create, :show, :update, :destroy]
member do
get :login # SSO 登录链接
post :token # 获取用户 API token
end
resources :agent_bots, only: [:index, :create, :show, :update, :destroy]
member do
delete :avatar # 删除头像
end
resources :accounts, only: [:index, :create, :show, :update, :destroy]
resources :account_users, only: [:index, :create]
collection do
delete :destroy # 移除成员
end
resources :email_channel_migrations, only: [:create]
end
end
end
控制器矩阵
| Controller | 基类 | 特殊 before_action |
|---|---|---|
Platform::Api::V1::UsersController |
PlatformController | set_resource + validate_platform_app_permissible(含 login/token) |
Platform::Api::V1::AccountsController |
PlatformController | 标准 set_resource + validate |
Platform::Api::V1::AgentBotsController |
PlatformController | 标准 set_resource + validate |
Platform::Api::V1::AccountUsersController |
PlatformController | 手动 set_resource + validate |
Platform::Api::V1::EmailChannelMigrationsController |
PlatformController | validate_account_permissible + validate_feature_flag + validate_params |
4. AccessToken 与 AccessTokenable(API令牌认证)
功能描述
AccessToken 是 Chatwoot 中多态令牌模型,服务于两类场景:① PlatformApp 的 Partner API 鉴权;② AgentBot 的 Bot API 鉴权。AccessToken 通过 AccessTokenable concern 自动创建——任何包含此 concern 的模型在创建后自动生成一条 AccessToken 记录。Token 通过 has_secure_token 生成,唯一且不可预测。
涉及的数据模型+关键字段
- AccessToken(
access_tokens表):id(bigint, PK)owner_type(string) — 令牌所属者类型(PlatformApp / AgentBot)owner_id(bigint) — 令牌所属者 IDtoken(string, UNIQUE) — 令牌值(has_secure_token自动生成)created_at,updated_at(datetime)- 索引:
index_access_tokens_on_owner_type_and_owner_id— (owner_type, owner_id);index_access_tokens_on_token— UNIQUE - 关联:
belongs_to :owner, polymorphic: true
AccessTokenable Concern
module AccessTokenable
extend ActiveSupport::Concern
included do
has_one :access_token, as: :owner, dependent: :destroy_async
after_create :create_access_token
end
def create_access_token
AccessToken.create!(owner: self)
end
end
- 自动在模型创建后生成一条 AccessToken
dependent: :destroy_async— 父模型删除时异步删除令牌- 包含此 concern 的模型:PlatformApp、AgentBot
Token 再生成
AgentBotsController#reset_access_token— 调用@agent_bot.access_token.regenerate_tokenhas_secure_token提供了regenerate_token方法
5. AccessTokenAuthHelper(令牌鉴权中间件)
功能描述
AccessTokenAuthHelper 是用于 Account API(非 Platform API)场景的 AccessToken 鉴权 concern。它允许 AgentBot 通过 AccessToken 代替用户 session 调用特定 Account API 端点。但 Bot 仅能访问有限的端点集合(BOT_ACCESSIBLE_ENDPOINTS),防止越权。
核心逻辑
- ensure_access_token — 从 Header 解析
api_access_token,查找对应 AccessToken 记录 - authenticate_access_token! — 验证令牌存在,设置
@resource = @access_token.owner,如 owner 是 User 则设置Current.user - validate_bot_access_token! — 如果 owner 是 AgentBot,则检查当前端点是否在
BOT_ACCESSIBLE_ENDPOINTS白名单内 - BOT_ACCESSIBLE_ENDPOINTS 白名单:
api/v1/accounts/conversations→toggle_status, toggle_typing_status, toggle_priority, create, update, custom_attributesapi/v1/accounts/conversations/messages→createapi/v1/accounts/conversations/assignments→create
- allowed_current_user_type? — 仅 User 和 AgentBot 可设置为 Current.user
6. AgentBot(智能机器人)
功能描述
AgentBot 是 Chatwoot 的智能机器人模型,支持 Webhook 类型(将对话事件推送到外部 URL)。AgentBot 可绑定到 Inbox(通过 AgentBotInbox),也可被直接分配为会话的 assignee(assignee_agent_bot_id)。Bot 创建时自动获得 AccessToken 和 Secret(用于 Webhook 签名),支持头像管理。Bot 分为账户级(account_id 有值)和全局级(account_id = nil)。
用户操作流程
- 管理员在 Agent Bot 设置页创建 AgentBot,填写名称、描述、outgoing_url
- 系统自动生成 AccessToken + Secret
- 管理员将 Bot 绑定到 Inbox(AgentBotInbox),Bot 开始监听该 Inbox 的对话事件
- 事件触发 → AgentBotListener 收集该 Inbox 的 Bot → 通过 AgentBots::WebhookJob 将 payload 推送到 outgoing_url
- 外部 Bot 服务处理后,通过 AccessToken 鉴权调用 Account API 回写消息/更新会话状态
- 管理员也可将 Bot 直接设置为会话的 assignee
涉及的API端点
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/v1/accounts/:account_id/agent_bots |
列出 accessible Bot(含全局 + 本账户) |
| POST | /api/v1/accounts/:account_id/agent_bots |
创建账户级 Bot |
| GET | /api/v1/accounts/:account_id/agent_bots/:id |
查看某 Bot |
| PATCH | /api/v1/accounts/:account_id/agent_bots/:id |
更新 Bot |
| DELETE | /api/v1/accounts/:account_id/agent_bots/:id |
删除 Bot |
| DELETE | /api/v1/accounts/:account_id/agent_bots/:id/avatar |
删除头像 |
| POST | /api/v1/accounts/:account_id/agent_bots/:id/reset_access_token |
重置 AccessToken |
| POST | /api/v1/accounts/:account_id/agent_bots/:id/reset_secret |
重置 Webhook Secret |
涉及的数据模型+关键字段
- AgentBot(
agent_bots表):id(bigint, PK)name(string) — Bot 名称description(string) — Bot 描述outgoing_url(string) — Webhook 推送 URLbot_type(integer, default: webhook) — Bot 类型枚举(目前仅 webhook: 0)bot_config(jsonb) — Bot 自定义配置secret(string) — Webhook 签名密钥(has_secure_token+ 可选加密)account_id(bigint, nullable) — 所属账户(nil = 全局 Bot)- 关联:
has_many :agent_bot_inboxes, dependent: :destroy_asynchas_many :inboxes, through: :agent_bot_inboxeshas_many :messages, as: :sender, dependent: :nullifyhas_many :platform_app_permissibles, as: :permissible, dependent: :destroyhas_many :assigned_conversations(foreign_key:assignee_agent_bot_id)belongs_to :account, optional: true
- Concern:
AccessTokenable— 自动创建 AccessTokenAvatarable— 支持头像WebhookSecretable— 自动生成 Secret(可加密)
- Scope:
accessible_to(account)→where(account_id: [nil, account.id]) - 方法:
push_event_data(inbox)→{ id, name, avatar_url, type: 'agent_bot' }
涉及的业务逻辑
- AgentBotPolicy — index/show 需 administrator 或 agent;create/update/destroy/reset_access_token/reset_secret/avatar 仅 administrator
- AgentBotPresenter —
access_token方法:仅当Current.account.id == account_id时返回 token(跨账户不暴露令牌) - AvatarFromUrlJob — 支持
avatar_url参数远程拉取头像
7. AgentBotInbox(Bot-Inbox绑定)
功能描述
AgentBotInbox 是 AgentBot 与 Inbox 之间的绑定关系模型。每个绑定记录表示"某 Bot 监听某 Inbox"。支持 active/inactive 状态控制,允许管理员在不删除绑定的情况下暂停 Bot 对某 Inbox 的监听。account_id 由 Inbox 自动继承。
涉及的数据模型+关键字段
- AgentBotInbox(
agent_bot_inboxes表):id(bigint, PK)agent_bot_id(integer, NOT NULL)inbox_id(integer, NOT NULL)account_id(integer) — 从 inbox.account_id 自动填充status(integer, default: active) — 状态枚举:active(0), inactive(1)- 关联:
belongs_to :inbox,belongs_to :agent_bot,belongs_to :account before_validation :ensure_account_id— 自动从 inbox 继承 account_id
8. AgentBotListener(Bot事件监听)
功能描述
AgentBotListener 是事件驱动的 Bot Webhook 推送监听器,继承 BaseListener。监听对话和消息相关事件,将 payload 推送给与 Inbox 绑定的 Bot。Bot 来源分两种:① Inbox 绑定的活跃 Bot(AgentBotInbox.active);② 会话的 assignee Bot(conversation.assignee_agent_bot)。
监听的事件
| 事件 | 推送内容 |
|---|---|
conversation_resolved |
conversation.webhook_data.merge(event: 'conversation_resolved') |
conversation_opened |
conversation.webhook_data.merge(event: 'conversation_opened') |
conversation_status_changed |
webhook_data + changed_attributes |
conversation_updated |
webhook_data + changed_attributes |
message_created |
message.webhook_data.merge(event: 'message_created') |
message_updated |
message.webhook_data.merge(event: 'message_updated') |
webwidget_triggered |
inbox 数据 + contact 信息 |
涉及的业务逻辑
- agent_bots_for(inbox, conversation) — 收集活跃 Bot 列表:
- 会话 assignee Bot(
conversation.assignee_agent_bot) - Inbox 绑定的活跃 Bot(
inbox.agent_bot,仅当agent_bot_inbox.active?) - 去重合并
- 会话 assignee Bot(
- process_webhook_bot_event — 如果 Bot 的
outgoing_url不为空,通过AgentBots::WebhookJob.perform_later异步推送 - 推送参数:
(outgoing_url, payload, :agent_bot_webhook, secret: agent_bot.secret, delivery_id: SecureRandom.uuid)
9. AgentBots::WebhookJob(Bot Webhook投递)
功能描述
AgentBots::WebhookJob 是 AgentBot 专用的 Webhook 推送 Job,继承 WebhookJob,队列优先级为 high。支持 RetryableError(HTTP 429/500)的3次重试,每次间隔 3秒。重试失败后调用 Webhooks::Trigger#handle_failure 处理。
核心逻辑
perform(url, payload, webhook_type = :agent_bot_webhook, secret:, delivery_id:)→ 调用Webhooks::Trigger.execute- 重试策略:
retry_on Webhooks::Trigger::RetryableError, wait: 3.seconds, attempts: 3 - 失败日志:
Rails.logger.warn("[AgentBots::WebhookJob] attempt #{executions} failed")
10. DashboardApp(仪表盘扩展应用)
功能描述
DashboardApp 是 Chatwoot 仪表盘侧边栏的 iframe 扩展应用模型。每个 DashboardApp 由账户内用户创建,包含一个 content jsonb 字段,存储一个数组——数组中的每个元素定义一个 iframe 面板(type: 'frame', url: 指定 iframe URL)。DashboardApp 用于第三方将自建界面嵌入 Chatwoot 仪表盘侧边栏。
用户操作流程
- 管理员在设置页创建 DashboardApp,填写 title 和 iframe URL 列表
- 系统验证 content 格式(必须是数组,每个元素包含 type:'frame' + 合法 http/https URL)
- DashboardApp 创建后关联到创建者和所属账户
- 仪表盘侧边栏渲染时加载该账户的所有 DashboardApp,每个 app 以 iframe 嵌入
涉及的API端点
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/v1/accounts/:account_id/dashboard_apps |
列出账户所有 DashboardApp |
| GET | /api/v1/accounts/:account_id/dashboard_apps/:id |
查看单个 |
| POST | /api/v1/accounts/:account_id/dashboard_apps |
创建(自动绑定 user_id) |
| PATCH | /api/v1/accounts/:account_id/dashboard_apps/:id |
更新 |
| DELETE | /api/v1/accounts/:account_id/dashboard_apps/:id |
删除 |
涉及的数据模型+关键字段
- DashboardApp(
dashboard_apps表):id(bigint, PK)title(string, NOT NULL) — 应用标题content(jsonb) — iframe 配置数组,格式:[{ type: 'frame', url: 'https://...' }]account_id(bigint, NOT NULL) — 所属账户user_id(bigint) — 创建者- 关联:
belongs_to :user,belongs_to :account
Content 验证规则
- 必须是数组(
is_a?(Array)),非空(minItems: 1) - 每个元素必须包含
type(仅允许'frame')和url(必须 http/https URI) - 使用 JSONSchemer 校验 schema
- 空白/非数组数据自动重置为
[]
11. DataImport(数据导入)
功能描述
DataImport 是 Chatwoot 的批量数据导入模型,目前仅支持 contacts 导入。用户上传 CSV 文件后,系统创建 DataImport 记录并自动触发 DataImportJob 异步处理。DataImport 跟踪导入状态(pending → processing → completed/failed)、已处理记录数、错误信息,并可附加 import_file(源 CSV)和 failed_records(失败记录 CSV)。
用户操作流程
- 管理员在联系人页面点击"导入",上传 CSV 文件
- 系统创建 DataImport 记录(
data_type: 'contacts'),附上import_file after_create_commit触发DataImportJob.set(wait: 1.minute).perform_later(等待文件上传到云存储)- Job 解析 CSV → 查找/创建联系人(支持 identifier/email/phone_number 去重合并)
- 处理完成后更新
processed_records/total_records/status - 失败记录保存为
failed_recordsCSV 附件 - 发送导入完成/失败通知邮件给管理员
涉及的API端点
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/v1/accounts/:account_id/contacts/import |
上传 CSV 导入联系人 |
涉及的数据模型+关键字段
- DataImport(
data_imports表):id(bigint, PK)data_type(string, NOT NULL) — 导入类型(目前仅'contacts')status(integer, default: pending) — 状态枚举:pending(0), processing(1), completed(2), failed(3)total_records(integer) — 总记录数processed_records(integer) — 成功处理记录数processing_errors(text) — 处理错误描述account_id(bigint, NOT NULL)- 附件:
has_one_attached :import_file,has_one_attached :failed_records - 关联:
belongs_to :account - 验证:
data_typeinclusion{ in: ['contacts'] } - 回调:
after_create_commit :process_data_import→ 延迟1分钟触发 DataImportJob
12. DataImportJob + ContactManager(导入处理流程)
功能描述
DataImportJob 是异步 CSV 导入处理器,使用 DataImport::ContactManager 执行联系人查找/去重/创建。流程:解析CSV → 查找已有联系人(按 identifier → email → phone_number 优先级) → 合并属性 → 批量创建 → 标签关联 → 失败记录导出 → 邮件通知。
核心逻辑
-
DataImportJob(
app/jobs/data_import_job.rb):- 队列:
low - 重试:
retry_on ActiveStorage::FileNotFoundError, wait: 1.minute, attempts: 3 - 流程:
- 更新
status: :processing - 解析 CSV →
ContactManager.build_contact逐行处理 - 每行提取 labels,校验是否在账户已批准标签内
- 不合法标签行 → 加入
rejected_contacts - 合法行 → 构建联系人属性(name, email, phone_number, identifier, custom_attributes 等)
- 批量导入联系人(
Contact.import,batch_size: 1000) - 批量应用标签(
ActsAsTaggableOn::Tagging.import) - 保存失败记录 CSV 为
failed_records附件 - 发送
AdministratorNotificationsMailer.contact_import_complete或contact_import_failed
- 更新
- 队列:
-
DataImport::ContactManager(
app/services/data_import/contact_manager.rb):- 查找优先级:
identifier → email → phone_number - 合并策略:
update_contact_with_merged_attributes— 去重时合并 identifier/name/phone_number/email/custom_attributesformat_phone_number— 自动加+前缀
from_email— 使用 Contact scope 查询邮箱find_or_initialize_contact— 如找不到则初始化新联系人
- 查找优先级:
13. Webhook(账户级Webhook)
功能描述
Webhook 是 Chatwoot 的账户级事件推送模型。管理员可在账户或 Inbox 级别创建 Webhook,订阅特定事件(conversation_status_changed, message_created 等),当事件发生时由 WebhookListener 触发 WebhookJob 投递 payload 到指定 URL。Webhook 支持 account_type(账户级)和 inbox_type(Inbox级)两种类型,每个 Webhook 包含 secret 用于 HMAC 签名验证。
用户操作流程
- 管理员在设置页创建 Webhook,填写 URL、名称、订阅事件列表
- 系统自动生成 Secret,验证 URL 格式和订阅事件合法性
- 事件发生时 → WebhookListener 触发 → WebhookJob 异步推送
- 推送使用 HMAC-SHA256 签名(
x-chatwoot-signatureHeader)
涉及的API端点
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/v1/accounts/:account_id/webhooks |
列出账户 Webhook |
| POST | /api/v1/accounts/:account_id/webhooks |
创建 Webhook |
| PATCH | /api/v1/accounts/:account_id/webhooks/:id |
更新 |
| DELETE | /api/v1/accounts/:account_id/webhooks/:id |
删除 |
涉及的数据模型+关键字段
- Webhook(
webhooks表):id(bigint, PK)name(string) — Webhook 名称url(text) — 推送 URL(account_id + url 联合唯一)secret(string) — HMAC 签名密钥(WebhookSecretable)subscriptions(jsonb) — 订阅事件数组webhook_type(integer, default: account_type) — 类型枚举:account_type(0), inbox_type(1)account_id(integer) — 所属账户inbox_id(integer, nullable) — 所属 Inbox(仅 inbox_type)- 关联:
belongs_to :account,belongs_to :inbox, optional: true - Concern:
WebhookSecretable - 验证:
url格式(http/https URI regex);subscriptions必须是数组且所有事件在ALLOWED_WEBHOOK_EVENTS内
ALLOWED_WEBHOOK_EVENTS
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
14. WebhookSecretable(签名密钥机制)
功能描述
WebhookSecretable 是为 Webhook 和 AgentBot 提供签名密钥的 concern。使用 has_secure_token :secret 自动生成密钥,并支持加密存储(encrypts :secret,依赖 Chatwoot.encryption_configured?)。提供 reset_secret! 方法用于密钥轮换。
核心逻辑
module WebhookSecretable
extend ActiveSupport::Concern
included do
has_secure_token :secret
encrypts :secret if Chatwoot.encryption_configured?
end
def reset_secret!
regenerate_secret
reload
end
end
- 包含此 concern 的模型:Webhook、AgentBot
- 签名使用:Webhooks::Trigger 中
OpenSSL::HMAC.hexdigest('SHA256', secret, body)→ 生成x-chatwoot-signatureHeader
15. Webhooks::Trigger(Webhook投递引擎)
功能描述
Webhooks::Trigger 是 Chatwoot 所有 Webhook 推送的核心执行引擎。负责构建 HTTP 请求、设置签名 Header、执行请求、处理失败和重试。支持三种 webhook_type:account_webhook、inbox_webhook、agent_bot_webhook。
核心逻辑
- 请求构建:
SafeFetch.fetch(url, method: :post, body: payload.to_json, headers: request_headers)- Headers:
Content-Type: application/json,Accept: application/json X-Chatwoot-Delivery— delivery_id(UUID)x-chatwoot-signature— HMAC-SHA256 签名(使用 secret + body)
- 超时:
webhook_timeout(根据 webhook_type 区分:agent_bot 默认更长) - 重试机制:
RetryableError— AgentBot 场景下 HTTP 429/500 触发重试- AgentBots::WebhookJob:
retry_on RetryableError, wait: 3.seconds, attempts: 3 - 失败处理:
handle_failure(error)→ 日志记录
- 三种 Job:
WebhookJob(queue: medium)— account/inbox webhookAgentBots::WebhookJob(queue: high)— agent_bot webhook,支持重试- 两者均调用
Webhooks::Trigger.execute
16. InstallationConfig(平台级配置)
功能描述
InstallationConfig 是 Chatwoot 的平台级全局配置模型,存储在数据库中,通过 GlobalConfig 缓存层提供高效读取。每个配置项由 name(唯一键)和 serialized_value(jsonb)组成。配置项分两类:locked(不可通过 API 修改)和 editable(可通过 Super Admin API 修改)。部分配置修改后需要重启应用(RESTART_REQUIRED_CONFIG_KEYS)。
关键配置项
| 配置名 | 说明 | 类型 |
|---|---|---|
ENABLE_ACCOUNT_SIGNUP |
是否允许自助注册 | boolean |
ENABLE_SAML_SSO_LOGIN |
是否启用 SAML SSO | boolean(修改前校验是否有 SAML 用户) |
CAPTAIN_OPEN_AI_API_KEY |
Captain AI LLM 密钥 | string(需重启) |
CAPTAIN_OPEN_AI_ENDPOINT |
Captain AI LLM Endpoint | string(需重启) |
CAPTAIN_OPEN_AI_MODEL |
Captain AI LLM 模型名 | string(需重启) |
LANGFUSE_BASE_URL / PUBLIC_KEY / SECRET_KEY |
Langfuse 可观测配置 | string(需重启) |
OTEL_PROVIDER |
OpenTelemetry Provider | string(需重启) |
DISPLAY_MANIFEST |
是否展示 app manifest | boolean |
涉及的数据模型+关键字段
- InstallationConfig(
installation_configs表):id(bigint, PK)name(string, NOT NULL, UNIQUE) — 配置键名serialized_value(jsonb, NOT NULL) — 配置值(serialize YAML,默认{})locked(boolean, default: TRUE, NOT NULL) — 是否锁定(锁定项不可通过 API 编辑)created_at,updated_at(datetime)- 索引:
index_installation_configs_on_name(UNIQUE),index_installation_configs_on_name_and_created_at(UNIQUE) - Scope:
editable→where(locked: false) default_scope→order(created_at: :desc)before_validation :set_lock— 新建时默认锁定after_commit :clear_cache— 修改后清除 GlobalConfig Redis 缓存- 验证:
validates :name, presence: true;saml_sso_users_check— 关闭 SAML SSO 前检查是否有 SAML 用户
涉及的API端点
| 方法 | 路径 | 说明 |
|---|---|---|
| Super Admin CRUD | /super_admin/installation_configs |
管理后台管理 InstallationConfig(全量 CRUD) |
涉及的业务逻辑
- value accessor —
InstallationConfig#value读serialized_value[:value];InstallationConfig#value=写{ value: ... } - GlobalConfig 缓存 — 通过 Redis $alfred 缓存,1天过期,fallback 到数据库
- GlobalConfigService.load(key, default) — 先查 GlobalConfig 缓存,再 fallback ENV,最后创建 InstallationConfig 记录
- 配置修改需要重启的标记 —
RESTART_REQUIRED_CONFIG_KEYS数组
17. GlobalConfig + GlobalConfigService(配置缓存层)
功能描述
GlobalConfig 是 InstallationConfig 的 Redis 缓存读取层,通过 $alfred(Redis 连接)缓存配置值,默认1天过期。当 InstallationConfig 修改时,after_commit :clear_cache 自动清除缓存,确保读取到最新值。GlobalConfigService 提供便捷方法,支持 ENV fallback 和自动创建 InstallationConfig。
GlobalConfig 核心逻辑
- 缓存键:
V1:GLOBAL_CONFIG:{config_key} - 读取流程:
- 查 Redis 缓存 → 如有直接返回
- 缓存不存在 → 查 InstallationConfig DB → 写入 Redis(1天过期)
- 类型转换:通过 ConfigLoader 加载 general_configs 元数据,对 boolean 类型做
ActiveModel::Type::Boolean.new.cast - clear_cache:扫描
$alfred.keys("V1:GLOBAL_CONFIG:*")并逐个 expire(0)
GlobalConfigService 核心逻辑
- load(key, default):
GlobalConfig.get(key)→ 如有值返回- fallback
ENV.fetch(key) { default } InstallationConfig.where(name: key).first_or_create(value: env_value, locked: false)GlobalConfig.clear_cache→ 下次读取走 DB
- account_signup_enabled? —
load('ENABLE_ACCOUNT_SIGNUP', 'false')转 boolean
跨模块交互关系
PlatformApp ──1:1──→ AccessToken (认证)
PlatformApp ──1:N──→ PlatformAppPermissible (授权)
↕ polymorphic
├── Account
├── User
└── AgentBot
AgentBot ──1:1──→ AccessToken (Bot API认证)
AgentBot ──1:1──→ Secret (Webhook签名)
AgentBot ──1:N──→ AgentBotInbox → Inbox (监听绑定)
AgentBot ──1:N──→ PlatformAppPermissible (Partner授权)
AgentBot ──1:N──→ AssignedConversations (assignee)
AgentBotListener ──→ AgentBots::WebhookJob → Webhooks::Trigger
Webhook ──1:1──→ Secret (HMAC签名)
WebhookListener ──→ WebhookJob → Webhooks::Trigger
DashboardApp ──1:N──→ Account
DashboardApp ──1:1──→ User (创建者)
DataImport ──1:1──→ Account
DataImport ──1:1──→ ImportFile (ActiveStorage)
DataImport ──1:1──→ FailedRecords (ActiveStorage)
DataImportJob ──→ DataImport::ContactManager → Contact
InstallationConfig ──→ GlobalConfig (Redis缓存) ──→ GlobalConfigService (ENV fallback)
GoChat 实现建议
| 模块 | 优先级 | 实现要点 |
|---|---|---|
| AccessToken + AccessTokenable | P0 | 多态令牌,支持 PlatformApp 和 AgentBot 两种 owner;has_secure_token 生成唯一 token |
| PlatformApp + Permissible | P1 | Partner API 认证主体;多态授权矩阵;建议 Go 中用 interface + 泛型实现 polymorphic |
| PlatformController 鉴权 | P1 | Token → PlatformApp 解析 → Permissible 校验;建议中间件链实现 |
| AgentBot + AgentBotInbox | P1 | Bot 模型核心;AccessToken + Secret 双令牌;account_id nullable 支持全局 Bot |
| AgentBotListener | P2 | 事件驱动推送;建议 EventBus + Handler 模式 |
| AgentBots::WebhookJob | P2 | 异步推送 + 重试;建议消息队列 + 指数退避 |
| Webhook + WebhookSecretable | P1 | HMAC-SHA256 签名验证;WebhookJob 异步推送;account/inbox 两种 scope |
| Webhooks::Trigger | P2 | 统一推送引擎;签名 + 超时 + 重试 + 错误处理 |
| DashboardApp | P3 | iframe 扩展;content schema 校验;前端侧边栏 iframe 渲染 |
| DataImport | P2 | CSV 异步导入;联系人去重合并;标签批量关联;进度追踪 |
| InstallationConfig | P1 | 平台级配置 DB 存储;Redis 缓存层;ENV fallback;locked/editable 分类 |
| GlobalConfig | P2 | Redis 缓存 + DB fallback;类型转换;after_commit 清缓存 |