Files
gochat/docs/requirements/M11-enterprise-features.md
2026-06-04 15:44:48 +08:00

35 KiB
Raw Permalink Blame History

M11: 企业版功能(Enterprise Features

模块概述

本模块覆盖 Chatwoot 企业版专属功能,包括:SLA 策略与应用(SlaPolicy + AppliedSla + SlaEvent)、审计日志(AuditLog)、自定义角色权限系统(CustomRole)、组织/公司管理(Company)、坐席容量策略(AgentCapacityPolicy + InboxCapacityLimit)、语音通话(Call + Voice 系列 Service)、SAML SSO 单点登录(AccountSamlSettings)、SidekiqCron 定时任务调度。这些功能在社区版基础上增强了合规、安全、权限精细化、组织管理和语音通信能力。


功能1SLA 策略管理(SlaPolicy CRUD + 应用到对话)

  • 功能描述:账户级 SLAService Level Agreement)策略管理。管理员可创建 SLA 策略,设定首响时间(FRT)、下次响应时间(NRT)、解决时间(RT)阈值,并将策略绑定到对话。系统通过定时 Job 定期评估 SLA 是否达标/违规,并自动生成 SlaEvent 通知。
  • 用户操作流程(UI交互步骤)
    1. 进入 Settings → SLA 页面
    2. 点击"Add SLA Policy",填写名称、描述
    3. 设定三个时间阈值:first_response_time_threshold(首响)、next_response_time_threshold(下次响应)、resolution_time_threshold(解决),单位为秒
    4. 可勾选"only_during_business_hours",仅在工作时间内计算 SLA
    5. 保存后,可在 Inbox 设置中将 SLA 策略绑定到收件箱,新进入的对话自动应用该 SLA
    6. 对话列表中可查看 SLA 状态标识(active/hit/missed/active_with_misses
  • 涉及的API端点 + 请求/响应格式
    • GET /api/v1/accounts/{account_id}/sla_policies — 获取 SLA 策略列表
    • POST /api/v1/accounts/{account_id}/sla_policies — 创建 SLA 策略
      • 请求:{ sla_policy: { name: "Standard SLA", description: "...", first_response_time_threshold: 300, next_response_time_threshold: 600, resolution_time_threshold: 86400, only_during_business_hours: false } }
      • 响应:策略对象 { id, name, description, first_response_time_threshold, next_response_time_threshold, resolution_time_threshold, only_during_business_hours, account_id }
    • GET /api/v1/accounts/{account_id}/sla_policies/{id} — 获取单个 SLA 策略
    • PUT /api/v1/accounts/{account_id}/sla_policies/{id} — 更新 SLA 策略
    • DELETE /api/v1/accounts/{account_id}/sla_policies/{id} — 删除 SLA 策略(异步通过 DeleteObjectJob
  • 涉及的数据模型 + 关键字段
    • SlaPolicy(表 sla_policies):
      • id (bigint, PK)
      • name (string, not null) — 策略名称
      • description (string) — 策略描述
      • first_response_time_threshold (float) — 首响时间阈值(秒)
      • next_response_time_threshold (float) — 下次响应时间阈值(秒)
      • resolution_time_threshold (float) — 解决时间阈值(秒)
      • only_during_business_hours (boolean, default false) — 仅在工作时间计算
      • account_id (bigint, not null, FK)
    • AppliedSla(表 applied_slas):
      • id (bigint, PK)
      • sla_status (integer, enum) — active(0)/hit(1)/missed(2)/active_with_misses(3)
      • account_id (bigint, not null, FK)
      • sla_policy_id (bigint, not null, FK)
      • conversation_id (bigint, not null, FK)
      • 唯一索引:(account_id, sla_policy_id, conversation_id)
    • SlaEvent(表 sla_events):
      • id (bigint, PK)
      • event_type (integer, enum) — frt(0)/nrt(1)/rt(2)
      • meta (jsonb) — 事件元数据
      • account_id, applied_sla_id, conversation_id, inbox_id, sla_policy_id (bigint, FK)
    • 关联:SlaPolicy has_many :conversations, :applied_slasAppliedSla has_many :sla_eventsAppliedSla belongs_to :sla_policy, :conversation, :account
  • 涉及的业务逻辑(service层)
    • Sla::EvaluateAppliedSlaService — 核心 SLA 评估逻辑:
      • 依次检查 FRT/NRT/RT 三个阈值
      • 首响检查:conversation.created_at + sla_policy.first_response_time_threshold,对比首条回复时间
      • 下次响应检查:等待客户回复后,对比等待时间 + 阈值
      • 解决时间检查:对话创建时间 + 阈值
      • 达标时调用 handle_hit_sla,违规时调用 handle_missed_sla 生成 SlaEvent
    • Sla::TriggerSlasForAccountsJobSla::ProcessAccountAppliedSlasJobSla::ProcessAppliedSlaJob — 定时评估链路,遍历所有 active/active_with_misses 状态的 AppliedSla
    • rake sla:apply_to_conversations — 批量给已有对话应用 SLA 策略的迁移任务
  • 涉及的自动化/规则/事件
    • 对话创建时,如 Inbox 绑定了 SLA 策略,自动创建 AppliedSlaconversation callback
    • SlaEvent 创建后自动发送通知(after_create_commit :create_notifications
    • 对话 resolve 后,EvaluateAppliedSlaService 判断 SLA 是否最终达标
  • 涉及的权限/Policy
    • SlaPolicyPolicyindex/show → administrator || agentcreate/update/destroy → administrator
  • GoChat 实现要点
    • SLA 三种阈值(FRT/NRT/RT)是核心概念,需要完整建模
    • 定时评估 Job 需要设计好调度频率(Chatwoot 每5分钟通过 TriggerScheduledItemsJob 触发)
    • only_during_business_hours 需要结合 M3 的 BusinessHours 计算
    • AppliedSla 状态机:active → active_with_misses → hit/missed

功能2:审计日志(AuditLog

  • 功能描述:企业版审计日志,基于 audited gem 记录账户内关键资源的变更操作(创建/更新/删除),包括变更内容、操作人、IP 地址等。管理员可在审计日志页面按时间倒序查看所有变更记录,用于合规审计和安全追溯。
  • 用户操作流程(UI交互步骤)
    1. 账户需启用 audit_logs feature flag
    2. 进入账户设置 → Audit Logs 页面
    3. 可按时间倒序浏览所有变更记录(每页15条)
    4. 每条记录显示:操作类型(action)、被审计对象(auditable_type + auditable_id)、变更内容(audited_changes)、操作人(username/email)、IPremote_address)、时间戳
  • 涉及的API端点 + 请求/响应格式
    • GET /api/v1/accounts/{account_id}/audit_logs — 获取审计日志(分页)
      • 请求参数:page(页码)
      • 响应:审计记录列表,含 action, auditable_type, auditable_id, audited_changes, username, remote_address, request_uuid, created_at, associated_type, associated_id
  • 涉及的数据模型 + 关键字段
    • Enterprise::AuditLog(继承 Audited::Audit,表 audits):
      • id (bigint, PK)
      • action (string) — 操作类型:create/update/destroy
      • auditable_type (string) — 被审计对象类型(Account/Inbox/User/AccountUser 等)
      • auditable_id (bigint) — 被审计对象 ID
      • audited_changes (jsonb) — 变更内容
      • associated_type (string) — 关联对象类型(通常是 Account)
      • associated_id (bigint) — 关联对象 ID
      • user_id (bigint) — 操作人 ID
      • username (string) — 操作人邮箱(自动填充)
      • remote_address (string) — IP 地址
      • request_uuid (string) — 请求唯一标识
      • version (integer) — 版本号
      • comment (string)
      • user_type (string)
      • created_at (datetime)
    • Enterprise::AuditLogafter_save 时自动补充 associated_type/associated_id/username
  • 涉及的业务逻辑(service层)
    • 通过 audited gem 的 audited 声明自动记录变更,无需独立 service
    • 各模型通过 concern 声明审计范围:
      • Enterprise::Audit::Accountaudited except: :updated_at, on: [:update]
      • Enterprise::Audit::Inboxaudited associated_with: :account, on: [:create, :update]
      • Enterprise::Audit::AccountUseraudited only: [:availability, :role, :account_id, :inviter_id, :user_id], on: [:create, :update], associated_with: :account
      • Enterprise::Audit::Useraudited only: [:availability, :display_name, :email, :name](手动记录登录/登出)
      • Enterprise::Audit::Conversationaudited only: [], on: [:destroy](仅记录删除)
      • 其他:AutomationRule, Webhook, Macro, AgentBot, Team, TeamMember, InboxMember 等均有审计 concern
    • 全局配置:config/initializers/audited.rbconfig.audit_class = 'Enterprise::AuditLog'
  • 涉及的自动化/规则/事件
    • 模型变更时自动写入 audits 表(audited gem callback
    • Enterprise::AuditLog.after_save :log_additional_information — 自动补充关联信息和操作人邮箱
  • 涉及的权限/Policy
    • Api::V1::Accounts::AuditLogsController — 仅 administrator 可访问(before_action :check_admin_authorization?
    • 需要账户启用 audit_logs feature flag
  • GoChat 实现要点
    • 审计日志需基于变更追踪机制(类似 audited gem),在核心模型上声明审计字段
    • 需记录操作人、IP、变更内容、时间戳
    • 分页查询接口,按时间倒序排列
    • associated_type/associated_id 用于按账户维度聚合审计记录
    • feature flag 控制审计功能的启用

功能3:自定义角色权限系统(CustomRole)

  • 功能描述:企业版自定义角色系统,允许管理员在账户级创建自定义角色,定义细粒度权限列表,并将角色分配给 AccountUser。自定义角色扩展了默认的三级角色体系(administrator/agent/supervisor),使权限控制更灵活。
  • 用户操作流程(UI交互步骤)
    1. 进入 Settings → Custom Roles 页面
    2. 点击"Add Role",填写角色名称、描述
    3. 从权限列表勾选所需权限
    4. 创建后可在 Agent Management 中将此角色分配给坐席
    5. 坐席权限将基于其 CustomRole 的 permissions 列表生效
  • 涉及的API端点 + 请求/响应格式
    • GET /api/v1/accounts/{account_id}/custom_roles — 获取自定义角色列表
    • POST /api/v1/accounts/{account_id}/custom_roles — 创建自定义角色
      • 请求:{ custom_role: { name: "Sales Agent", description: "...", permissions: ["conversation_manage", "contact_manage"] } }
      • 响应:角色对象 { id, name, description, permissions, account_id }
    • GET /api/v1/accounts/{account_id}/custom_roles/{id} — 获取单个角色
    • PUT /api/v1/accounts/{account_id}/custom_roles/{id} — 更新角色
    • DELETE /api/v1/accounts/{account_id}/custom_roles/{id} — 删除角色
  • 涉及的数据模型 + 关键字段
    • CustomRole(表 custom_roles):
      • id (bigint, PK)
      • name (string) — 角色名称
      • description (string) — 角色描述
      • permissions (text array, default []) — 权限列表
      • account_id (bigint, not null, FK)
    • 可用权限列表(PERMISSIONS 常量):
      • conversation_manage — 管理所有对话
      • conversation_unassigned_manage — 管理未分配对话并可认领
      • conversation_participating_manage — 管理自己参与的对话
      • contact_manage — 管理联系人
      • report_manage — 管理报表
      • knowledge_base_manage — 管理知识库
    • 关联:CustomRole has_many :account_users, dependent: :nullify
    • Enterprise::AccountUser 扩展:permissions 方法返回 custom_role.permissions + ['custom_role'](当有自定义角色时),否则返回默认角色权限
  • 涉及的业务逻辑(service层)
    • 无独立 serviceCRUD 在 controller 完成
    • 权限合并逻辑在 Enterprise::AccountUser#permissions
    • 删除 CustomRole 时,关联的 AccountUser 的 custom_role_id 设为 NULLnullify),回归默认角色权限
  • 涉及的自动化/规则/事件
    • AccountUser 权限检查时,如存在 custom_role 则优先使用其 permissions 列表
    • CustomRole 删除后,AccountUser 自动回退到默认角色
  • 涉及的权限/Policy
    • CustomRolePolicy:所有操作(index/show/create/update/destroy)仅 administrator 可执行
  • GoChat 实现要点
    • 权限列表需设计为可扩展的枚举/常量体系
    • AccountUser 需支持 custom_role_id 外键
    • 权限合并逻辑:CustomRole.permissions + 默认角色权限
    • 删除角色时注意 nullify 而非 restrict_with_error
    • 当前6项权限可能需要扩展(如 automation_manage、inbox_manage 等)

功能4:组织/公司管理(Company)

  • 功能描述:企业版组织管理功能,允许账户创建"公司"(Company)实体,将联系人按组织分组。每个公司有名称、域名、描述、自定义属性,支持头像和 favicon 自动获取。联系人可归属于公司,系统可根据联系人邮箱域名自动关联公司。
  • 用户操作流程(UI交互步骤)
    1. 进入 Contacts → Companies 页面(需启用 companies feature flag
    2. 点击"Add Company",填写名称、域名、描述
    3. 可上传公司头像
    4. 如填入域名,系统自动获取 favicon
    5. 创建后可将联系人手动归属到该公司
    6. 系统也可根据联系人邮箱自动关联(业务邮箱检测 → 域名匹配 → 自动建公司)
    7. 在公司详情页可查看关联联系人列表、活动时间线
  • 涉及的API端点 + 请求/响应格式
    • GET /api/v1/accounts/{account_id}/companies — 获取公司列表(分页25条/页,支持排序/过滤)
    • GET /api/v1/accounts/{account_id}/companies/search?q=xxx — 搜索公司(按名称/域名)
    • POST /api/v1/accounts/{account_id}/companies — 创建公司
      • 请求:{ company: { name: "Acme Corp", domain: "acme.com", description: "...", additional_attributes: {}, custom_attributes: {} } }
      • 响应:公司对象 { id, name, domain, description, contacts_count, last_activity_at, additional_attributes, custom_attributes, account_id }
    • GET /api/v1/accounts/{account_id}/companies/{id} — 获取单个公司
    • PUT /api/v1/accounts/{account_id}/companies/{id} — 更新公司(custom_attributes 为 merge 逻辑)
    • DELETE /api/v1/accounts/{account_id}/companies/{id} — 删除公司(仅 administrator
    • DELETE /api/v1/accounts/{account_id}/companies/{id}/destroy_custom_attributes — 删除指定自定义属性
    • POST /api/v1/accounts/{account_id}/companies/{id}/avatar — 上传/更新头像
  • 涉及的数据模型 + 关键字段
    • Company(表 companies):
      • id (bigint, PK)
      • name (string, not null, 最大255字符) — 公司名称
      • domain (string, 可选, 同账户下唯一) — 公司域名
      • description (text, 最大限制) — 公司描述
      • contacts_count (integer) — 关联联系人数(counter cache
      • last_activity_at (datetime) — 最后活动时间
      • additional_attributes (jsonb) — 附加属性
      • custom_attributes (jsonb) — 自定义属性(merge 语义)
      • account_id (bigint, not null, FK)
      • 唯一索引:(account_id, domain) WHERE domain IS NOT NULL
    • 关联:Company has_many :contacts, dependent: :nullifyCompany include Avatarable
  • 涉及的业务逻辑(service层)
    • Companies::BusinessEmailDetectorService — 检测邮箱是否为业务邮箱(排除 disposable/free provider),用于自动关联判断
    • Companies::ContactMembershipService — 公司-联系人关联管理:
      • assign(contact:) — 将联系人归属公司,更新 company.last_activity_at
      • remove(contact:) — 移除联系人归属
    • Contacts::CompanyAssociationService — 自动根据邮箱域名关联公司:
      • 检测是否为业务邮箱 → 提取域名 → find_or_create_by(domain) → 自动归属
    • Company model
      • after_create_commit :fetch_favicon — 域名存在时异步获取 favicon
      • record_activity_at!(timestamp) — 滚动更新 last_activity_at5分钟间隔去重)
      • search_by_name_or_domain(query) — 名称/域名搜索 scope
  • 涉及的自动化/规则/事件
    • 创建公司时如有域名,自动获取 favicon
    • 联系人创建/更新时,如邮箱为业务邮箱,自动关联对应公司
    • last_activity_at 滚动更新(ACTIVITY_ROLLUP_INTERVAL = 5分钟)
  • 涉及的权限/Policy
    • CompanyPolicyindex/search/show/create/update → 所有账户用户;destroy → 仅 administrator
  • GoChat 实现要点
    • Company 是联系人分组维度,需与 Contact 模型建立 belongs_to 关系
    • custom_attributes 需支持 merge 语义(更新时合并而非替换)
    • domain 唯一约束(同账户下)需注意 NULL domain 不参与唯一检查
    • 自动关联逻辑:邮箱域名 → 业务邮箱检测 → find_or_create Company → assign Contact
    • contacts_count counter cache 需维护
    • 需启用 companies feature flag

功能5:坐席容量策略(AgentCapacityPolicy + InboxCapacityLimit

  • 功能描述:企业版坐席容量策略,用于限制每个坐席在特定收件箱中的最大同时处理对话数。管理员创建容量策略,设定排除规则(如超过N小时的老对话不计入容量、特定标签对话不计入),并为策略关联收件箱及各自的对话上限。
  • 用户操作流程(UI交互步骤)
    1. 进入 Settings → Agent Capacity Policies 页面
    2. 点击"Add Policy",填写策略名称、描述
    3. 设定排除规则:exclude_older_than_hours(超时老对话排除)、excluded_labels(特定标签对话排除)
    4. 为策略关联收件箱,并设定每个收件箱的 conversation_limit(对话上限)
    5. 将策略分配给坐席(AccountUser.agent_capacity_policy_id
  • 涉及的API端点 + 请求/响应格式
    • GET /api/v1/accounts/{account_id}/agent_capacity_policies — 获取容量策略列表
    • POST /api/v1/accounts/{account_id}/agent_capacity_policies — 创建容量策略
      • 请求:{ agent_capacity_policy: { name: "Standard Capacity", description: "...", exclusion_rules: { exclude_older_than_hours: 24, excluded_labels: ["spam"] } } }
      • 响应:策略对象 { id, name, description, exclusion_rules, account_id }
    • GET /api/v1/accounts/{account_id}/agent_capacity_policies/{id} — 获取单个策略
    • PUT /api/v1/accounts/{account_id}/agent_capacity_policies/{id} — 更新策略
    • DELETE /api/v1/accounts/{account_id}/agent_capacity_policies/{id} — 删除策略
  • 涉及的数据模型 + 关键字段
    • AgentCapacityPolicy(表 agent_capacity_policies):
      • id (bigint, PK)
      • name (string, 最大255字符, not null) — 策略名称
      • description (text) — 策略描述
      • exclusion_rules (jsonb, not null) — 排除规则:
        • exclude_older_than_hours — 超过N小时的活跃对话不计入容量
        • excluded_labels — 带特定标签的对话不计入容量
      • account_id (bigint, not null, FK)
    • InboxCapacityLimit(表 inbox_capacity_limits):
      • id (bigint, PK)
      • agent_capacity_policy_id (bigint, not null, FK)
      • inbox_id (bigint, not null, FK)
      • conversation_limit (integer, not null, ≥ 0) — 该收件箱的对话上限
      • 唯一索引:(agent_capacity_policy_id, inbox_id)
    • 关联:
      • AgentCapacityPolicy has_many :inbox_capacity_limits, :inboxes (through), :account_users (dependent: :nullify)
      • AccountUser 增加 agent_capacity_policy_id 外键
  • 涉及的业务逻辑(service层)
    • 无独立 serviceCRUD 在 controller 完成
    • 容量计算逻辑(在自动分配系统中使用):
      • 遍历坐席的所有 inbox_capacity_limits
      • 计算每个收件箱的活跃对话数(排除规则过滤)
      • 判断是否达到上限
  • 涉及的自动化/规则/事件
    • 删除策略时,关联的 AccountUser 的 agent_capacity_policy_id 被设为 NULL
    • 容量策略在自动分配时作为坐席可分配判断依据
  • 涉及的权限/Policy
    • AgentCapacityPolicyPolicy:所有操作仅 administrator 可执行
  • GoChat 实现要点
    • exclusion_rules 作为 jsonb 存储,灵活支持扩展
    • InboxCapacityLimit 是策略和收件箱的中间表,需唯一约束
    • 容量计算需排除规则过滤(超时对话 + 标签排除)
    • 与自动分配系统(M5)深度集成
    • AccountUser 需增加 agent_capacity_policy_id 字段

功能6:语音通话(Call + Voice Services

  • 功能描述:企业版语音通话功能,支持通过 Twilio 和 WhatsApp 两种通话提供商进行语音通话。支持呼入/呼出通话,基于 Twilio Conference 实现坐席接听/拒接/挂断,通话状态实时更新,支持录音和转录。呼出通话在对话中创建 voice_call 类型消息气泡。
  • 用户操作流程(UI交互步骤)
    1. 呼出通话:在联系人详情页点击"Call",选择语音收件箱 → 系统发起 Twilio/WhatsApp 通话
    2. 呼入通话:客户拨打 Twilio 号码 → 系统创建 Call + 对话 → 坐席看到 ringing 状态
    3. 坐席接听:点击接听按钮 → 通话状态变为 in_progress → 坐席被自动分配到对话
    4. 通话结束:任一方挂断 → 状态变为 completed/no_answer/failed → 记录时长
    5. 录音/转录:通话完成后可查看录音和转录文本
  • 涉及的API端点 + 请求/响应格式
    • POST /api/v1/accounts/{account_id}/contacts/{contact_id}/calls — 发起呼出通话
      • 请求:{ inbox_id: 1, conversation_id: 42 }(可选关联现有对话)
      • 响应:{ conversation_id, inbox_id, call_sid, conference_sid }
    • POST /api/v1/accounts/{account_id}/whatsapp_calls/initiate — WhatsApp 呼出
    • GET /api/v1/accounts/{account_id}/whatsapp_calls/{id} — 获取通话详情
    • POST /api/v1/accounts/{account_id}/whatsapp_calls/{id}/accept — 接听
    • POST /api/v1/accounts/{account_id}/whatsapp_calls/{id}/reject — 拒接
    • POST /api/v1/accounts/{account_id}/whatsapp_calls/{id}/terminate — 挂断
    • POST /api/v1/accounts/{account_id}/whatsapp_calls/{id}/upload_recording — 上传录音
    • Twilio Webhook 端点:
      • POST /twilio/voice/{phone}/status — 通话状态回调
      • POST /twilio/voice/{phone}/call_twiml — TwiML 响应
      • POST /twilio/voice/{phone}/conference_status — 会议状态回调
      • POST /twilio/voice/{phone}/recording_status — 录音状态回调
  • 涉及的数据模型 + 关键字段
    • Call(表 calls):
      • id (bigint, PK)
      • direction (integer, enum) — incoming(0)/outgoing(1)
      • status (string, default "ringing") — ringing/in_progress/completed/no_answer/failed
      • provider (integer, enum) — twilio(0)/whatsapp(1)
      • duration_seconds (integer) — 通话时长(秒)
      • end_reason (string) — 结束原因
      • started_at (datetime) — 开始时间
      • transcript (text) — 转录文本
      • meta (jsonb) — conference_sid, twilio_conference_sid, recording_sid, parent_call_sid, initiated_at, ended_at
      • provider_call_id (string, not null) — 提供商侧通话 ID(唯一约束)
      • accepted_by_agent_id (bigint) — 接听坐席 ID
      • account_id, contact_id, conversation_id, inbox_id, message_id (bigint, FK)
      • recording (ActiveStorage attachment) — 录音文件
      • TERMINAL_STATUSES = completed/no_answer/failed
    • 关联:Call belongs_to :account, :inbox, :conversation, :contact, :message (optional), :accepted_by_agent (User, optional)
  • 涉及的业务逻辑(service层)
    • Voice::OutboundCallBuilder — 呼出通话构建:
      • 事务性创建 ContactInbox → Conversation → Call → Message(voice_call)
      • 通过 inbox.channel.initiate_call 发起 Twilio 通话
    • Voice::InboundCallBuilder — 呼入通话构建:
      • 查找或创建 ContactInbox → Contact → Conversation → Call → Message
      • 支持并发防重复(RecordNotUnique 处理)
    • Voice::StatusUpdateService — 通话状态更新:
      • Twilio 状态映射:queued/initiated/ringing → ringing; in-progress/answered → in_progress; completed → completed; busy/no-answer → no_answer; failed/canceled → failed
    • Voice::CallStatus::Manager — 通话状态机管理:
      • 处理状态更新,记录 started_at/duration_seconds
      • 通话结束时更新 meta、时长
      • 触发 message.touch 使前端实时更新
    • Voice::Conference::Manager — 会议事件处理:
      • conference-start → ringing; participant-join → in_progress + 自动分配坐席; participant-leave → 处理离开; conference-end → finalize
      • 坐席接听时自动 claim_for_user + auto_assign_conversation
    • Voice::Provider::Twilio::ConferenceService — Twilio 会议管理:
      • ensure_conference_sid, mark_agent_joined, end_conference
      • claim_call + assign_conversation(首次接听获胜)
    • Voice::Provider::Twilio::TokenService — 生成 Twilio Access TokenJWT+ Voice Grant
    • Voice::CallMessageBuilder — 创建/更新 voice_call 类型消息:
      • content_type: 'voice_call', 包含 call_id/call_sid/call_source/call_direction/status
    • Voice::RecordingStatusService — 处理 Twilio 录音回调,异步附件化录音文件
    • Whatsapp::CallService — WhatsApp 通话操作(accept/reject/terminate
    • Whatsapp::IncomingCallService — WhatsApp 呼入处理
    • Whatsapp::CallPermissionReplyService — WhatsApp 通话权限回复
  • 涉及的自动化/规则/事件
    • 通话创建时自动在对话中插入 voice_call 消息气泡
    • 坐席接听时自动 claim_call + auto_assign(如对话无现有 assignee
    • 通话结束时更新 duration_seconds、transcript
    • 录音状态回调异步处理附件
    • Twilio Conference 事件实时驱动状态更新
  • 涉及的权限/Policy
    • 呼出通话:需 authorize contact (:show) + inbox (:show),且 inbox 需启用 voice
    • WhatsApp 通话:需确保 calling_enabled + SDP offer + contact phone
  • GoChat 实现要点
    • 通话模型需支持多 providerTwilio/WhatsApp)和方向(呼入/呼出)
    • 状态机:ringing → in_progress → completed/no_answer/failed
    • Conference 模式:坐席和客户通过会议桥连接
    • 录音附件化处理需异步
    • 通话消息(voice_call content_type)与对话系统集成
    • Twilio Access Token 生成(JWT + VoiceGrant
    • 需 feature flag 控制 voice 通话功能启用

功能7SAML SSO 单点登录(AccountSamlSettings

  • 功能描述:企业版 SAML 2.0 单点登录,允许账户配置 SAML IdP 参数,用户通过企业身份提供商(如 Okta、Azure AD)登录 Chatwoot。支持角色映射(SAML 属性 → Chatwoot 角色),创建/更新 SAML 配置后自动将账户用户 provider 转为 saml。
  • 用户操作流程(UI交互步骤)
    1. 管理员进入 Settings → SAML SSO 页面(需启用 saml feature flag + 全局 ENABLE_SAML_SSO_LOGIN
    2. 填写 IdP 参数:SSO URL、CertificateX509)、IdP Entity ID
    3. SP Entity ID 自动生成(基于 FRONTEND_URL + account_id
    4. 可配置 role_mappingsSAML 属性 → Chatwoot 角色)
    5. 保存后,账户的登录页面出现 SAML 登录按钮
    6. 用户点击 SAML 登录 → 重定向到 IdP → 认证成功后回调 Chatwoot
    7. SamlUserBuilder 查找或创建用户,关联到账户
  • 涉及的API端点 + 请求/响应格式
    • GET /api/v1/accounts/{account_id}/saml_settings — 获取 SAML 配置
    • POST /api/v1/accounts/{account_id}/saml_settings — 创建 SAML 配置
      • 请求:{ saml_settings: { sso_url: "https://idp.example.com/saml/sso", certificate: "X509 cert string", idp_entity_id: "idp_entity", role_mappings: { "admin" => "administrator" } } }
      • 响应:SAML 配置对象
    • PUT /api/v1/accounts/{account_id}/saml_settings — 更新配置
    • DELETE /api/v1/accounts/{account_id}/saml_settings — 删除配置(重置用户 provider 为 email
  • 涉及的数据模型 + 关键字段
    • AccountSamlSettings(表 account_saml_settings):
      • id (bigint, PK)
      • sso_url (string, not null) — IdP SSO URL
      • certificate (text, not null) — X509 证书(需验证有效性)
      • idp_entity_id (string, not null) — IdP Entity ID
      • sp_entity_id (string) — SP Entity ID(自动生成)
      • role_mappings (json) — SAML 角色映射配置
      • account_id (bigint, not null, FK, 唯一)
    • 关联:AccountSamlSettings belongs_to :accountAccount has_one :saml_settings
  • 涉及的业务逻辑(service层)
    • SamlUserBuilder — SAML 认证后用户构建:
      • 查找已有用户(by email)→ 如用户属于账户则直接登录
      • 不属于账户则抛出 AuthenticationFailed
      • 新用户创建时设置 provider: 'saml', uid, 自动确认邮箱
      • 角色映射:根据 SAML 属性 + role_mappings 配置分配 AccountUser 角色
    • Enterprise::DeviseOverrides::OmniauthCallbacksController — SAML 认证回调处理:
      • redirect_callbacks → SAML provider 时走 omniauth_success
      • handle_saml_auth → 检查 SAML 是否启用 → SamlUserBuilder → 登录/错误处理
      • 支持 mobile 和 web 两种 RelayState 处理
    • AccountSamlSettings
      • certificate_must_be_valid_x509 — 验证证书格式
      • certificate_fingerprint — 计算证书指纹
      • set_sp_entity_id — 自动生成 SP Entity IDFRONTEND_URL/saml/sp/{account_id}
      • after_create_commit :update_account_users_provider — 创建后将用户 provider 转为 saml
      • after_destroy_commit :reset_account_users_provider — 删除后重置为 email
  • 涉及的自动化/规则/事件
    • SAML 配置创建后,账户用户 provider 自动转为 'saml'
    • SAML 配置删除后,用户 provider 重置为 'email'
    • SP Entity ID 自动生成
    • 证书有效性验证
  • 涉及的权限/Policy
    • AccountSamlSettingsPolicy:所有操作仅 administrator 可执行
    • 需启用 saml feature flag + 全局 ENABLE_SAML_SSO_LOGIN
  • GoChat 实现要点
    • 需集成 SAML 2.0 协议(可参考 ruby-saml 或类似库)
    • X509 证书验证和指纹计算
    • SP Entity ID 自动生成逻辑
    • 用户查找/创建/角色映射需事务性处理
    • Omniauth 回调流程适配
    • 账户级 SAML 配置(每个账户独立 IdP)
    • role_mappings 灵活映射 SAML 属性到 Chatwoot 角色

功能8SidekiqCron 定时任务调度

  • 功能描述Chatwoot 使用 sidekiq-cron gem 管理 Sidekiq 定时任务。通过 config/schedule.yml 定义任务计划,在服务启动时自动加载并持久化到 Redis。定时任务涵盖系统巡检、SLA 评估触发、IMAP 邮件收取、数据清理、报表生成等。
  • 用户操作流程(UI交互步骤)
    • 此功能为后台运维功能,无用户 UI 交互
    • 管理员可在 Sidekiq Web UI/sidekiq/cron)查看和管理定时任务
  • 涉及的数据模型 + 关键字段
    • 无独立数据模型,任务定义存储在 config/schedule.yml 和 Redis 中
  • 核心定时任务列表
    • trigger_scheduled_items_job — */5 * * * *(每5分钟)— 触发 SLA 评估等调度任务
    • trigger_hourly_scheduled_items_job — 0 * * * *(每小时)— 低频定时任务触发
    • trigger_imap_email_inboxes_job — */1 * * * *(每分钟)— IMAP 邮件收取
    • internal_check_new_versions_job — 0 0 * * *(每日 00:00 UTC)— 版本检查 + 日级调度
    • remove_stale_contact_inboxes_job — 30 22 * * *(每日 22:30 UTC)— 清理过期 ContactInbox
    • remove_stale_redis_keys_job — 30 22 * * *(每日 22:30 UTC)— 清理过期 Redis Key
    • SLA 相关:通过 TriggerScheduledItemsJobSla::TriggerSlasForAccountsJob 链路触发
  • 涉及的业务逻辑
    • config/initializers/sidekiq.rb — Sidekiq 服务启动时:
      • 加载 config/schedule.yml
      • Sidekiq::Cron::Job.load_from_hash! — upsert 任务并清理已删除条目
      • 显式清理 legacy 动态任务(如 bulk_auto_assignment_job
    • TriggerScheduledItemsJob — 核心调度入口,每5分钟执行,触发 SLA 评估等子任务
    • Internal::TriggerDailyScheduledItemsJob — 日级调度
    • Internal::TriggerHourlyScheduledItemsJob — 小时级调度
  • 涉及的自动化/规则/事件
    • 服务启动时自动加载 schedule.yml 到 Redis
    • 部署时自动清理已删除的 schedule 条目
    • 任务执行日志(Sidekiq logger
  • GoChat 实现要点
    • 如使用 Go 实现,需设计定时任务调度框架(可参考 cron 表达式 + 分布式锁)
    • SLA 评估链路:定时触发 → 遍历账户 → 遍历 AppliedSla → EvaluateAppliedSlaService
    • 任务需要幂等性(防止重复执行)
    • 需考虑分布式环境下的任务竞争(Redis 锁 / DB 锁)
    • 任务配置建议外部化(YAML / DB 配置),支持动态调整
    • 清理类任务(stale data)需在低峰时段执行

模块间依赖关系

依赖模块 依赖说明
M1-Account SLA/CustomRole/Company/AgentCapacityPolicy/SAML 均属于 Account 级别;AuditLog 的 associated 关联 Account
M3-Conversation SLA AppliedSla/SlaEvent 关联 ConversationCall 关联 Conversation
M4-Contact Company 关联 Contactbelongs_to);Call 关联 ContactCompanyAssociationService 自动关联
M5-Team/Assignment AgentCapacityPolicy 与自动分配系统集成;Call 接听时 auto_assign_conversation
M2-Inbox SlaPolicy 绑定到 InboxInboxCapacityLimit 关联 InboxCall 关联 InboxVoice 需 Inbox 启用 voice
M6-Automation Audit 审计 AutomationRule 变更
M8-Notification SlaEvent 创建后发送通知
BusinessHours SLA only_during_business_hours 依赖工作时间计算

Feature Flags 依赖

Feature Flag 所属功能 说明
audit_logs AuditLog 控制审计日志功能启用
companies Company 控制组织管理功能启用
saml SAML SSO 控制 SAML 单点登录启用
voice(隐含) Call/Voice 控制语音通话功能启用
sla(隐含) SLA 控制 SLA 功能启用

企业版功能全景总结

Chatwoot 企业版功能通过 Feature Flags 逐项控制启用,每个功能模块独立可配。核心设计模式:

  1. Concern 扩展Enterprise::Concerns::Account 通过 included 块注入 has_many :sla_policies, :custom_roles, :agent_capacity_policies, :companies, :calls, has_one :saml_settings 等关联
  2. Policy 红线:所有企业版功能的写操作(create/update/destroy)均需 administrator 权限
  3. 审计追踪Enterprise::AuditLog 继承 Audited::Audit,全局配置审计类,核心模型通过 concern 声明审计范围
  4. Feature Flag 门控:每个企业版功能都有对应的 feature flagcontroller 层 before_action 检查
  5. 定时调度:SLA 评估等周期性任务通过 SidekiqCron + TriggerScheduledItemsJob 链路触发
  6. 异步处理SLA 评估、录音附件、favicon 获取等均通过 Sidekiq Job 异步执行