Files
gochat/docs/requirements/M12-platform-and-integration.md
T
2026-06-04 15:44:48 +08:00

34 KiB
Raw Blame History

M12 平台与集成 — Chatwoot 功能梳理文档

基于 Chatwoot 源码深度阅读 + CodeGraph 上下文梳理
生成日期:2026-05-22
参照仓库:chatwoot-reference
模块覆盖:PlatformApp · AgentBot · DashboardApp · DataImport · Webhook · AccessToken认证 · InstallationConfig


目录

  1. PlatformApp(平台应用 / Partner API
  2. PlatformAppPermissible(权限授权)
  3. Platform API 路由体系
  4. AccessToken 与 AccessTokenableAPI令牌认证)
  5. AccessTokenAuthHelper(令牌鉴权中间件)
  6. AgentBot(智能机器人)
  7. AgentBotInboxBot-Inbox绑定)
  8. AgentBotListenerBot事件监听)
  9. AgentBots::WebhookJobBot Webhook投递)
  10. DashboardApp(仪表盘扩展应用)
  11. DataImport(数据导入)
  12. DataImportJob + ContactManager(导入处理流程)
  13. Webhook(账户级Webhook
  14. WebhookSecretable(签名密钥机制)
  15. Webhooks::TriggerWebhook投递引擎)
  16. InstallationConfig(平台级配置)
  17. GlobalConfig + GlobalConfigService(配置缓存层)

1. PlatformApp(平台应用 / Partner API

功能描述

PlatformApp 是 Chatwoot 为第三方合作伙伴(Partner)提供的平台级 API 认证主体。每个 PlatformApp 拥有一个 AccessToken,通过该令牌可调用 Platform API(独立于普通 Account API),实现对用户、账户、AgentBot、AccountUser 等资源的 CRUD 管理。PlatformApp 与被操作资源之间通过 PlatformAppPermissible 多态关联授权——只有被授权的资源才能被该 PlatformApp 访问/修改。

用户操作流程

  1. Super Admin 在后台创建 PlatformApp,系统自动生成 AccessToken
  2. 第三方系统持有该 AccessToken,通过 api_access_token Header 调用 Platform API
  3. PlatformController 验证令牌 → 解析出 PlatformApp → 校验 Permissible 授权范围
  4. 通过授权校验后,第三方可操作被授权的 Account / User / AgentBot 等资源
  5. 第三方可通过 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 执行邮箱渠道迁移

涉及的数据模型+关键字段

  • PlatformAppplatform_apps 表):
    • id (bigint, PK)
    • name (string, NOT NULL) — 应用名称
    • created_at, updated_at (datetime)
    • 关联:has_many :platform_app_permissibles, dependent: :destroy_async
    • Concerninclude AccessTokenable(创建时自动生成 AccessToken
    • 验证:validates :name, presence: true

涉及的业务逻辑

  • PlatformApp 创建时AccessTokenable concern 的 after_create :create_access_token 自动创建 AccessToken
  • PlatformControllerapp/controllers/platform_controller.rb):全局鉴权基类
    • ensure_access_token — 从 Header 中解析 api_access_token
    • set_platform_app — 从 AccessToken owner 解析出 PlatformApp,否则返回 401
    • validate_platform_app_permissible — 校验当前资源是否在 Permissible 授权范围内
  • 各子 Controller:继承 PlatformController,在 create 操作时自动创建 Permissible 授权关系

2. PlatformAppPermissible(权限授权)

功能描述

PlatformAppPermissible 是 PlatformApp 与被授权资源之间的多态授权桥梁。每个 Permissible 记录代表"某 PlatformApp 可以操作某资源"。资源类型可以是 Account、User、AgentBot 等。创建用户/账户/AgentBot 时,子控制器会自动为 PlatformApp 添加 Permissible 记录。

涉及的数据模型+关键字段

  • PlatformAppPermissibleplatform_app_permissibles 表):
    • id (bigint, PK)
    • platform_app_id (bigint, NOT NULL) — 所属 PlatformApp
    • permissible_id (bigint, NOT NULL) — 被授权资源 ID
    • permissible_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#createfind_or_create_by(permissible: @resource)
    • AccountsController#createfind_or_create_by(permissible: @resource)
    • AgentBotsController#createfind_or_create_by(permissible: @resource)
  • 查询授权资源
    • AccountsController#index → 查询 where(permissible_type: 'Account') 并 includes permissible
    • AgentBotsController#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 与 AccessTokenableAPI令牌认证)

功能描述

AccessToken 是 Chatwoot 中多态令牌模型,服务于两类场景:① PlatformApp 的 Partner API 鉴权;② AgentBot 的 Bot API 鉴权。AccessToken 通过 AccessTokenable concern 自动创建——任何包含此 concern 的模型在创建后自动生成一条 AccessToken 记录。Token 通过 has_secure_token 生成,唯一且不可预测。

涉及的数据模型+关键字段

  • AccessTokenaccess_tokens 表):
    • id (bigint, PK)
    • owner_type (string) — 令牌所属者类型(PlatformApp / AgentBot
    • owner_id (bigint) — 令牌所属者 ID
    • token (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 的模型:PlatformAppAgentBot

Token 再生成

  • AgentBotsController#reset_access_token — 调用 @agent_bot.access_token.regenerate_token
  • has_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/conversationstoggle_status, toggle_typing_status, toggle_priority, create, update, custom_attributes
    • api/v1/accounts/conversations/messagescreate
    • api/v1/accounts/conversations/assignmentscreate
  • 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)。

用户操作流程

  1. 管理员在 Agent Bot 设置页创建 AgentBot,填写名称、描述、outgoing_url
  2. 系统自动生成 AccessToken + Secret
  3. 管理员将 Bot 绑定到 InboxAgentBotInbox),Bot 开始监听该 Inbox 的对话事件
  4. 事件触发 → AgentBotListener 收集该 Inbox 的 Bot → 通过 AgentBots::WebhookJob 将 payload 推送到 outgoing_url
  5. 外部 Bot 服务处理后,通过 AccessToken 鉴权调用 Account API 回写消息/更新会话状态
  6. 管理员也可将 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

涉及的数据模型+关键字段

  • AgentBotagent_bots 表):
    • id (bigint, PK)
    • name (string) — Bot 名称
    • description (string) — Bot 描述
    • outgoing_url (string) — Webhook 推送 URL
    • bot_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_async
      • has_many :inboxes, through: :agent_bot_inboxes
      • has_many :messages, as: :sender, dependent: :nullify
      • has_many :platform_app_permissibles, as: :permissible, dependent: :destroy
      • has_many :assigned_conversationsforeign_key: assignee_agent_bot_id
      • belongs_to :account, optional: true
    • Concern
      • AccessTokenable — 自动创建 AccessToken
      • Avatarable — 支持头像
      • WebhookSecretable — 自动生成 Secret(可加密)
    • Scopeaccessible_to(account)where(account_id: [nil, account.id])
    • 方法:
      • push_event_data(inbox){ id, name, avatar_url, type: 'agent_bot' }

涉及的业务逻辑

  • AgentBotPolicy — index/show 需 administrator 或 agentcreate/update/destroy/reset_access_token/reset_secret/avatar 仅 administrator
  • AgentBotPresenteraccess_token 方法:仅当 Current.account.id == account_id 时返回 token(跨账户不暴露令牌)
  • AvatarFromUrlJob — 支持 avatar_url 参数远程拉取头像

7. AgentBotInboxBot-Inbox绑定)

功能描述

AgentBotInbox 是 AgentBot 与 Inbox 之间的绑定关系模型。每个绑定记录表示"某 Bot 监听某 Inbox"。支持 active/inactive 状态控制,允许管理员在不删除绑定的情况下暂停 Bot 对某 Inbox 的监听。account_id 由 Inbox 自动继承。

涉及的数据模型+关键字段

  • AgentBotInboxagent_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. AgentBotListenerBot事件监听)

功能描述

AgentBotListener 是事件驱动的 Bot Webhook 推送监听器,继承 BaseListener。监听对话和消息相关事件,将 payload 推送给与 Inbox 绑定的 Bot。Bot 来源分两种:① Inbox 绑定的活跃 Bot(AgentBotInbox.active);② 会话的 assignee Botconversation.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 Botconversation.assignee_agent_bot
    • Inbox 绑定的活跃 Botinbox.agent_bot,仅当 agent_bot_inbox.active?
    • 去重合并
  • 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::WebhookJobBot Webhook投递)

功能描述

AgentBots::WebhookJob 是 AgentBot 专用的 Webhook 推送 Job,继承 WebhookJob,队列优先级为 high。支持 RetryableErrorHTTP 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 仪表盘侧边栏。

用户操作流程

  1. 管理员在设置页创建 DashboardApp,填写 title 和 iframe URL 列表
  2. 系统验证 content 格式(必须是数组,每个元素包含 type:'frame' + 合法 http/https URL
  3. DashboardApp 创建后关联到创建者和所属账户
  4. 仪表盘侧边栏渲染时加载该账户的所有 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 删除

涉及的数据模型+关键字段

  • DashboardAppdashboard_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)。

用户操作流程

  1. 管理员在联系人页面点击"导入",上传 CSV 文件
  2. 系统创建 DataImport 记录(data_type: 'contacts'),附上 import_file
  3. after_create_commit 触发 DataImportJob.set(wait: 1.minute).perform_later(等待文件上传到云存储)
  4. Job 解析 CSV → 查找/创建联系人(支持 identifier/email/phone_number 去重合并)
  5. 处理完成后更新 processed_records / total_records / status
  6. 失败记录保存为 failed_records CSV 附件
  7. 发送导入完成/失败通知邮件给管理员

涉及的API端点

方法 路径 说明
POST /api/v1/accounts/:account_id/contacts/import 上传 CSV 导入联系人

涉及的数据模型+关键字段

  • DataImportdata_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_filehas_one_attached :failed_records
    • 关联:belongs_to :account
    • 验证:data_type inclusion { in: ['contacts'] }
    • 回调:after_create_commit :process_data_import → 延迟1分钟触发 DataImportJob

12. DataImportJob + ContactManager(导入处理流程)

功能描述

DataImportJob 是异步 CSV 导入处理器,使用 DataImport::ContactManager 执行联系人查找/去重/创建。流程:解析CSV → 查找已有联系人(按 identifier → email → phone_number 优先级) → 合并属性 → 批量创建 → 标签关联 → 失败记录导出 → 邮件通知。

核心逻辑

  • DataImportJobapp/jobs/data_import_job.rb):

    • 队列:low
    • 重试:retry_on ActiveStorage::FileNotFoundError, wait: 1.minute, attempts: 3
    • 流程:
      1. 更新 status: :processing
      2. 解析 CSV → ContactManager.build_contact 逐行处理
      3. 每行提取 labels,校验是否在账户已批准标签内
      4. 不合法标签行 → 加入 rejected_contacts
      5. 合法行 → 构建联系人属性(name, email, phone_number, identifier, custom_attributes 等)
      6. 批量导入联系人(Contact.importbatch_size: 1000
      7. 批量应用标签(ActsAsTaggableOn::Tagging.import
      8. 保存失败记录 CSV 为 failed_records 附件
      9. 发送 AdministratorNotificationsMailer.contact_import_completecontact_import_failed
  • DataImport::ContactManagerapp/services/data_import/contact_manager.rb):

    • 查找优先级:identifier → email → phone_number
    • 合并策略:
      • update_contact_with_merged_attributes — 去重时合并 identifier/name/phone_number/email/custom_attributes
      • format_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_typeInbox级)两种类型,每个 Webhook 包含 secret 用于 HMAC 签名验证。

用户操作流程

  1. 管理员在设置页创建 Webhook,填写 URL、名称、订阅事件列表
  2. 系统自动生成 Secret,验证 URL 格式和订阅事件合法性
  3. 事件发生时 → WebhookListener 触发 → WebhookJob 异步推送
  4. 推送使用 HMAC-SHA256 签名(x-chatwoot-signature Header

涉及的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 删除

涉及的数据模型+关键字段

  • Webhookwebhooks 表):
    • id (bigint, PK)
    • name (string) — Webhook 名称
    • url (text) — 推送 URLaccount_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
    • ConcernWebhookSecretable
    • 验证: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 的模型:WebhookAgentBot
  • 签名使用:Webhooks::Trigger 中 OpenSSL::HMAC.hexdigest('SHA256', secret, body) → 生成 x-chatwoot-signature Header

15. Webhooks::TriggerWebhook投递引擎)

功能描述

Webhooks::Trigger 是 Chatwoot 所有 Webhook 推送的核心执行引擎。负责构建 HTTP 请求、设置签名 Header、执行请求、处理失败和重试。支持三种 webhook_typeaccount_webhookinbox_webhookagent_bot_webhook

核心逻辑

  • 请求构建
    • SafeFetch.fetch(url, method: :post, body: payload.to_json, headers: request_headers)
    • HeadersContent-Type: application/json, Accept: application/json
    • X-Chatwoot-Delivery — delivery_idUUID
    • x-chatwoot-signature — HMAC-SHA256 签名(使用 secret + body
  • 超时webhook_timeout(根据 webhook_type 区分:agent_bot 默认更长)
  • 重试机制
    • RetryableError — AgentBot 场景下 HTTP 429/500 触发重试
    • AgentBots::WebhookJobretry_on RetryableError, wait: 3.seconds, attempts: 3
    • 失败处理:handle_failure(error) → 日志记录
  • 三种 Job
    • WebhookJobqueue: medium)— account/inbox webhook
    • AgentBots::WebhookJobqueue: high)— agent_bot webhook,支持重试
    • 两者均调用 Webhooks::Trigger.execute

16. InstallationConfig(平台级配置)

功能描述

InstallationConfig 是 Chatwoot 的平台级全局配置模型,存储在数据库中,通过 GlobalConfig 缓存层提供高效读取。每个配置项由 name(唯一键)和 serialized_valuejsonb)组成。配置项分两类: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

涉及的数据模型+关键字段

  • InstallationConfiginstallation_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)
    • Scopeeditablewhere(locked: false)
    • default_scopeorder(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 accessorInstallationConfig#valueserialized_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}
  • 读取流程
    1. 查 Redis 缓存 → 如有直接返回
    2. 缓存不存在 → 查 InstallationConfig DB → 写入 Redis1天过期)
  • 类型转换:通过 ConfigLoader 加载 general_configs 元数据,对 boolean 类型做 ActiveModel::Type::Boolean.new.cast
  • clear_cache:扫描 $alfred.keys("V1:GLOBAL_CONFIG:*") 并逐个 expire(0)

GlobalConfigService 核心逻辑

  • load(key, default)
    1. GlobalConfig.get(key) → 如有值返回
    2. fallback ENV.fetch(key) { default }
    3. InstallationConfig.where(name: key).first_or_create(value: env_value, locked: false)
    4. 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 两种 ownerhas_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 fallbacklocked/editable 分类
GlobalConfig P2 Redis 缓存 + DB fallback;类型转换;after_commit 清缓存