Files
gochat/docs/requirements/M06-automation-and-templates.md
T
rogee 0dabb8cfa5 docs: 整理文档目录结构 — 清理过时文档、归集功能子目录、统一命名规范
清理:
- 删除 34 份过时文档(gap reports/QA临时报告/验收报告/阶段性文档)
- 删除 docs/.hermes/skills 第三方 skills 副本(16 文件)
- 删除 skills-lock.json

目录归集:
- 根目录仅保留 README.md 索引
- product/ — 产品与架构设计(PRD + ARCHITECTURE + P2设计文档 + AI/企业路线图)
- tracking/ — Chatwoot parity 开发跟踪
- requirements/ — M01-M12 模块需求
- plans/ — 历史实现计划
- parity/ — 路由 parity 与前端契约
- qa/ — QA 报告与测试计划
- ops/ — 运维部署

命名规范:
- 全小写 kebab-case,禁止全大写文件名
- product/tracking/ops 用 NN- 序号前缀
- requirements 用 MNN- 两位零填充模块号
- plans/qa 用 YYYY-MM-DD- 日期前缀
- requirements M1-M9 零填充为 M01-M09(修复字典序)

同步更新:
- backend/cmd/route_parity/main.go 路径默认值
- backend/scripts/parity_frontend_smoke.sh 报告路径
- 所有 docs 内部交叉引用
- .gitignore 排除编译产物 (backend/gochat, backend/route_parity)
- 新增迁移 000052/000053
- 前端 WS 相关修改
2026-07-09 14:53:27 +08:00

30 KiB
Raw Blame History

M6: 自动化与模板(Automation / Macro / CannedResponse

模块概述

本模块覆盖 Chatwoot 的自动化规则(AutomationRule)、宏操作(Macro)、模板消息(CannedResponse)、自动化事件监听(AutomationRuleListener)及执行引擎(ActionService / ConditionsFilterService)等功能。核心目标是让客服团队基于事件触发自动执行预定义操作、批量处理对话、以及快速复用预置消息模板,减少重复工作并提升响应效率。


功能1:自动化规则 CRUDAutomationRule

  • 功能描述:在账户级别创建、编辑、克隆、删除自动化规则。规则由 事件触发器(event_name+ 条件(conditions+ 动作(actions 三要素构成。当指定事件发生且条件匹配时,系统自动执行预定义的动作序列。规则支持激活/停用切换(active 字段)。
  • 用户操作流程(UI交互步骤)
    1. 进入 Settings → Automation 页面
    2. 点击 "Add Automation Rule" 按钮
    3. 填写规则名称(name)、描述(description
    4. 选择触发事件(event_name):conversation_created / conversation_updated / conversation_opened / conversation_resolved / message_created
    5. 配置条件(conditions):选择属性键、比较运算符、值,以及条件间的逻辑运算符(AND/OR)
    6. 配置动作(actions):选择动作类型及参数(如发送消息内容、指定坐席/团队ID等)
    7. 可选上传附件(作为 send_attachment 动作的素材)
    8. 保存规则,默认 active=true
  • 涉及的API端点 + 请求/响应格式
    • GET /api/v1/accounts/{account_id}/automation_rules — 获取账户下所有自动化规则
      • 响应:规则列表 [{ id, name, description, event_name, active, conditions, actions, account_id, ... }]
    • POST /api/v1/accounts/{account_id}/automation_rules — 创建规则
      • 请求:{ name, description, event_name, active, conditions: [{ attribute_key, filter_operator, values, query_operator }], actions: [{ action_name, action_params }] }
      • 响应:规则对象
    • GET /api/v1/accounts/{account_id}/automation_rules/{id} — 获取单个规则
    • PUT /api/v1/accounts/{account_id}/automation_rules/{id} — 更新规则(含条件/动作/附件变更)
    • DELETE /api/v1/accounts/{account_id}/automation_rules/{id} — 删除规则
    • POST /api/v1/accounts/{account_id}/automation_rules/{id}/clone — 克隆规则(dup + save
  • 涉及的数据模型 + 关键字段
    • AutomationRule 模型(表 automation_rules):
      • id (bigint, PK)
      • account_id (bigint, not null, FK → accounts)
      • name (string, not null) — 规则名称
      • description (text) — 规则描述
      • event_name (string, not null) — 触发事件:conversation_created / conversation_updated / conversation_opened / conversation_resolved / message_created
      • conditions (jsonb, default '{}', not null) — 条件数组,每项包含 attribute_key, filter_operator, values, query_operator
      • actions (jsonb, default '{}', not null) — 动作数组,每项包含 action_name, action_params
      • active (boolean, default true, not null) — 是否激活
      • created_at, updated_at (datetime)
    • 关联:belongs_to :accounthas_many_attached :filesActiveStorage 附件)
    • Index: index_automation_rules_on_account_id
  • 涉及的业务逻辑(service层)
    • Controller 层直接 CRUD,但创建/更新时通过 AttachmentConcern#validate_and_prepare_attachments 处理附件(blob_ids 转换)
    • 克隆操作:automation_rule.dup + save!(浅拷贝,含 conditions/actions 但不含 attached files
    • 条件格式校验:validate :json_conditions_format / validate :json_actions_format / validate :query_operator_presence / validate :query_operator_value
    • 更新条件后自动触发 reauthorization 检查:after_update_commit :reauthorized!, if: -> { saved_change_to_conditions? }Reauthorizable concern
  • 权限控制
    • AutomationRulePolicy:所有操作(index/create/show/update/clone/destroy)均要求 @account_user.administrator?,仅管理员可管理自动化规则
  • 涉及的自动化/规则/事件
    • 规则自身即为自动化核心,详见功能4AutomationRuleListener
    • 条件变更后触发 Reauthorizable#reauthorized!,通过 Redis 计数器追踪授权错误阈值
  • Gochat 实现建议
    • conditions 和 actions 采用 JSON 存储,需定义明确的 Schema(类似 Chatwoot 的 filter_keys.yml),并在 Go 中实现条件匹配引擎
    • 附件处理需在创建/更新时解析 blob_ids,建议用独立的 AttachmentService
    • 克隆功能需注意 files 附件的处理策略(Chatwoot 目前不拷贝附件)
    • 权限仅限管理员,应复用 Pundit-style 的 RBAC 框架

功能2:自动化条件系统(Conditions

  • 功能描述:自动化规则的条件系统基于 YAML 配置(filter_keys.yml)定义可用的属性、数据类型和比较运算符。条件匹配逻辑由 ConditionsFilterService 实现,支持会话属性、联系人属性、消息属性及自定义属性,条件间通过 query_operatorAND/OR)组合。
  • 条件属性分类
    • 会话属性(conversations
      • status (text) — 对话状态,运算符:equal_to / not_equal_to
      • assignee_id (text) — 坐席ID,运算符:equal_to / not_equal_to / is_present / is_not_present
      • inbox_id (text) — 收件箱ID,运算符:equal_to / not_equal_to / is_present / is_not_present
      • team_id (number) — 团队ID,运算符:equal_to / not_equal_to / is_present / is_not_present
      • priority (text) — 优先级,运算符:equal_to / not_equal_to
      • display_id (Number) — 对话显示ID,运算符:equal_to / not_equal_to
      • campaign_id (Number) — 营销活动ID,运算符:equal_to / not_equal_to
      • labels (labels) — 标签,运算符:contains / does_not_contain / is_present / is_not_present
      • browser_language (text, additional_attributes) — 浏览器语言,运算符:equal_to / not_equal_to
      • conversation_language (text, additional_attributes) — 对话语言,运算符:equal_to / not_equal_to
      • referer (text, additional_attributes) — 来源URL,运算符:equal_to / contains / does_not_contain
      • created_at (date) — 创建时间,运算符:days_before / is_less_than / is_greater_than
      • last_activity_at (date) — 最后活动时间,运算符:days_before / is_less_than / is_greater_than
      • mail_subject (text, additional_attributes) — 邮件主题,运算符:contains / does_not_contain
    • 联系人属性(contacts
      • name (text_case_insensitive) — 联系人姓名,运算符:equal_to / not_equal_to / contains / does_not_contain
      • phone_number (text) — 电话号码,运算符:equal_to / not_equal_to / contains / does_not_contain
      • email (text) — 邮箱,运算符:equal_to / not_equal_to / contains / does_not_contain / is_present / is_not_present
      • identifier (text) — 身份标识,运算符:equal_to / not_equal_to / contains / does_not_contain
      • country_code (text) — 国家代码,运算符:equal_to / not_equal_to
      • city (text) — 城市,运算符:equal_to / contains / does_not_contain
      • company_name (text) — 公司名称,运算符:equal_to / contains / does_not_contain
      • labels (labels) — 联系人标签,运算符:contains / does_not_contain / is_present / is_not_present
      • created_at (date) — 创建时间,运算符:days_before / is_less_than / is_greater_than
      • last_activity_at (date) — 最后活动时间
      • blocked (boolean) — 是否已阻断
    • 消息属性(messages
      • message_type (text) — 消息类型,运算符:equal_to / not_equal_to
      • private_note (text) — 内部备注,运算符:equal_to / not_equal_to / contains / does_not_contain
      • content (text) — 消息内容,运算符:equal_to / contains / does_not_contain
    • 自定义属性:支持通过 custom_attribute_definitions 表定义的自定义属性,attribute_model 支持 contact_attribute / conversation_attribute 等模型
  • 条件匹配逻辑
    • ConditionsFilterService 继承 FilterService,使用 filter_keys.yml 定义运算符合法性
    • 特殊运算符 attribute_changed:检测对话属性是否在当前事件中发生了变更(使用 changed_attributes 参数)
    • 条件间组合:query_operator 支持 AND / OR(最后一个条件无 query_operator
    • 匹配结果:构建 SQL WHERE 条件查询 base_relation(即 Conversation),如果返回记录集非空则条件匹配成功
  • 条件校验逻辑
    • ConditionValidationService:验证每个条件的 attribute_key 是否存在于 filter_keys.yml 或 custom_attribute_definitions 中
    • 验证 filter_operator 是否在该属性允许的运算符列表中
    • 验证 query_operator 是否为 AND / OR 或空
    • 校验失败时触发 authorization_error!Reauthorizable),累计错误达到阈值后标记规则需要重新授权
  • 涉及的service层
    • AutomationRules::ConditionsFilterService — 条件匹配执行
    • AutomationRules::ConditionValidationService — 条件格式校验
    • 继承自 FilterService — 基础过滤引擎
  • Gochat 实现建议
    • 用 Go struct 或配置文件定义 filter_keys,替代 YAML
    • 条件匹配可改为内存计算(不依赖 SQL WHERE),对单条 conversation 对象直接属性比较
    • attribute_changed 运算符需在事件中传递变更属性字典
    • 自定义属性需与 M10(自定义属性模块)联动

功能3:自动化动作系统(Actions)

  • 功能描述:自动化规则和宏共享一套动作系统,动作定义在 actions jsonb 字段中,每项包含 action_nameaction_params。执行引擎通过 send(action_name, action_params) 动态调用对应方法。基础动作由 ActionService 提供,自动化规则和宏各自覆写部分方法。
  • 动作类型清单
    • AutomationRule 专有 actions_attributesAutomationRule#actions_attributes):
      • send_message — 发送公开消息(参数:消息文本)
      • add_label — 添加标签(参数:标签名数组)
      • remove_label — 移除标签(参数:标签名数组)
      • send_email_to_team — 向团队发送邮件通知(参数:{ team_ids, message }
      • assign_team — 分配团队(参数:团队ID数组)
      • assign_agent — 分配坐席(参数:坐席ID数组,支持 'last_responding_agent' 特殊值)
      • remove_assigned_agent — 移除坐席分配
      • remove_assigned_team — 移除团队分配
      • send_webhook_event — 发送 Webhook(参数:URL数组)
      • mute_conversation — 静音对话
      • send_attachment — 发送附件消息(参数:blob_ids 数组)
      • change_status — 改变对话状态(参数:状态值数组)
      • resolve_conversation — 解决对话
      • open_conversation — 打开对话
      • pending_conversation — 设为待处理
      • snooze_conversation — 延迟对话
      • change_priority — 改变优先级(参数:优先级值数组,支持 'nil' 清空)
      • send_email_transcript — 发送对话邮件转录(参数:邮箱数组)
      • add_private_note — 添加内部备注(参数:备注文本)
    • Macro 专有 ACTIONS_ATTRSMacro::ACTIONS_ATTRS):
      • 与 AutomationRule 大部分相同,但无 send_email_to_team
      • 增加 add_private_note, send_attachment, send_webhook_event
      • assign_agent 特殊处理:支持 'self' 参数,自动替换为当前执行用户ID
    • ActionService 基础动作ActionService — 父类):
      • mute_conversation@conversation.mute!
      • snooze_conversation@conversation.snoozed!
      • resolve_conversation@conversation.resolved!
      • open_conversation@conversation.open!
      • pending_conversation@conversation.pending!
      • change_status(status)@conversation.update!(status: status[0])
      • change_priority(priority)@conversation.update!(priority: priority[0])'nil' → nil
      • add_label(labels)@conversation.add_labels(labels)
      • remove_label(labels)@conversation.update(label_list: label_list - labels)
      • assign_agent(agent_ids) — 验证坐席属于 inbox 且已确认后分配(支持 'last_responding_agent', 'nil' 清空)
      • remove_assigned_agent@conversation.update!(assignee_id: nil)
      • assign_team(team_ids) — 验证团队属于 account 后分配(支持 'nil', '0' 清空)
      • remove_assigned_team@conversation.update!(team_id: nil)
      • send_email_transcript(emails) — 异步发送邮件转录
  • 自动化规则执行 vs 宏执行差异
    • AutomationRules::ActionService
      • 消息/备注的 sender 为 nil(自动化系统发出),content_attributes 包含 automation_rule_id
      • send_email_to_team:遍历团队,通过 TeamNotifications::AutomationNotificationMailer 发送,并检查邮件速率限制
      • send_webhook_eventpayload 包含 event: "automation_event.{event_name}"
      • Current.executed_by = rule(标记执行来源为规则)
    • Macros::ExecutionService
      • 消息/备注的 sender 为当前用户,无 automation_rule_id 标记
      • assign_agent 支持 'self' → 替换为 @user.id
      • send_webhook_eventpayload 包含 event: "macro.executed"
      • Current.user = user(标记执行来源为用户)
    • 共同点:均继承 ActionService,执行时 @conversation.reload 确保最新状态,动作错误不中断(rescue + ChatwootExceptionTracker),ensure { Current.reset }
  • Gochat 实现建议
    • 动作执行引擎建议用接口模式(ActionHandler interface),每个 action_name 对应一个 Handler 实现
    • 自动化规则与宏的动作差异(sender 来源、特殊参数)应在 Handler 中通过 context 区分
    • send_webhook_event 需异步队列处理
    • send_email_to_team 需邮件速率限制
    • assign_agent'self' / 'last_responding_agent' / 'nil' 特殊参数需在 Go 中妥善处理

功能4:自动化事件监听(AutomationRuleListener

  • 功能描述AutomationRuleListener 继承 BaseListener,监听 EventBus 中的对话和消息事件,当事件触发时查找匹配的活跃自动化规则并执行条件匹配 + 动作执行。
  • 监听的事件类型
    • conversation_created — 对话创建时触发
    • conversation_updated — 对话更新时触发
    • conversation_opened — 对话打开时触发
    • conversation_resolved — 对话解决时触发
    • message_created — 消息创建时触发(含消息对象和变更属性)
  • 事件处理流程
    1. 对话事件process_conversation_event):
      • 排除由自动化自身触发的事件(performed_by_automation?
      • conversation_created / conversation_opened 事件,检查是否为自动回复场景(ignore_auto_reply_event?),避免自动回复循环
      • 获取 account.automation_rules.active.where(event_name: event_name) 规则列表
      • 对每条规则执行 ConditionsFilterService.new(rule, conversation, { changed_attributes }).perform
      • 条件匹配则执行 AutomationRules::ActionService.new(rule, account, conversation).perform
    2. 消息事件message_created):
      • 排除忽略的消息事件(ignore_message_created_event?
      • 获取 account.automation_rules.active.where(event_name: 'message_created')
      • 条件匹配时传入 { message: message, changed_attributes } 选项
  • 防循环机制
    • performed_by_automation?(event):检查 Current.executed_by 是否为 AutomationRule 实例,避免规则触发规则造成无限循环
    • ignore_auto_reply_event?(event):对自动回复类消息(如 bot 消息、通道自动回复)跳过 conversation_created / conversation_opened 事件
    • ignore_message_created_event?(event):对特定消息类型(如内部备注、bot 消息等)跳过 message_created 事件
  • 规则查找逻辑
    • rule_present?(event_name, account)account.automation_rules.active.where(event_name: event_name).present?
    • current_account_rules(event_name, account)account.automation_rules.active.where(event_name: event_name)
  • 涉及的数据流
    • EventBus → BaseListener → AutomationRuleListener → ConditionsFilterService → ActionService
    • 事件对象 event.data 包含 conversation, message, changed_attributes
  • Gochat 实现建议
    • 事件监听需与 M3(对话/消息模块)的 EventBus 联动
    • 防循环机制至关重要:建议在执行上下文中标记 executed_by 类型,递归执行前检查
    • 自动回复跳过逻辑需根据业务场景精确定义(哪些消息类型应被忽略)
    • 规则查找建议预加载缓存(account → active rules),减少每次事件的数据库查询

功能5:宏操作 CRUD + 执行(Macro

  • 功能描述:宏(Macro)是一种手动触发的批量操作集合,用户可一次对一个或多个对话执行预定义的动作序列。宏支持可见性控制(personal / global),个人宏仅创建者可见可用,全局宏账户内所有人可见。
  • 用户操作流程(UI交互步骤)
    1. 进入 Settings → Macros 页面
    2. 点击 "Add Macro" 按钮,填写名称(name
    3. 选择可见性(visibility):personal(仅自己)或 global(全账户)
    4. 配置动作序列(actions):同自动化规则的动作定义格式
    5. 可选上传附件
    6. 保存宏
    7. 在对话列表中选择多个对话,点击 "Run Macro",选择要执行的宏
  • 涉及的API端点 + 请求/响应格式
    • GET /api/v1/accounts/{account_id}/macros — 获取宏列表(根据可见性过滤)
      • 响应:宏列表 [{ id, name, visibility, actions, account_id, created_by_id, updated_by_id }]
    • POST /api/v1/accounts/{account_id}/macros — 创建宏
      • 请求:{ name, visibility, actions: [{ action_name, action_params }] }
      • 响应:宏对象
    • GET /api/v1/accounts/{account_id}/macros/{id} — 获取单个宏
    • PUT /api/v1/accounts/{account_id}/macros/{id} — 更新宏
    • DELETE /api/v1/accounts/{account_id}/macros/{id} — 删除宏
    • POST /api/v1/accounts/{account_id}/macros/{id}/execute — 执行宏
      • 请求:{ conversation_ids: [1, 2, 3] } — 可同时批量执行多个对话
      • 响应:200 OK(异步执行)
  • 涉及的数据模型 + 关键字段
    • Macro 模型(表 macros):
      • id (bigint, PK)
      • account_id (bigint, not null, FK → accounts)
      • name (string, not null) — 宏名称
      • visibility (integer, default 0) — 可见性枚举:personal(0) / global(1)
      • actions (jsonb, default '{}', not null) — 动作数组
      • created_by_id (bigint, FK → users) — 创建者
      • updated_by_id (bigint, FK → users) — 最后更新者
      • created_at, updated_at (datetime)
    • 关联:belongs_to :account, belongs_to :created_by (class_name: User), belongs_to :updated_by (class_name: User), has_many_attached :files
    • Index: index_macros_on_account_id
  • 涉及的业务逻辑(service层)
    • 可见性控制
      • Macro.with_visibility(user, params):返回 global 宏 + 当前用户的 personal 宏(global.or(personal.where(created_by_id: user.id))
      • Macro#set_visibility(user, params)agent 角色强制设为 personaladministrator 可设为 global
    • 宏执行
      • Controller 调用 ::MacrosExecutionJob.perform_later(@macro, conversation_ids: params[:conversation_ids], user: Current.user) — 异步 Job
      • MacrosExecutionJobqueue: medium):遍历 conversation_ids,对每个对话创建 Macros::ExecutionService.new(macro, conversation, user).perform
      • Macros::ExecutionService 继承 ActionService,遍历 macro.actions 执行每项动作(详见功能3
    • 动作校验validate :json_actions_format
  • 权限控制
    • MacroPolicy
      • index? / create? — 所有角色均可
      • show? — global 宏所有人可见,personal 宏仅创建者可见
      • update? / destroy? — global 宏仅 administratorpersonal 宏仅创建者(author?
      • execute? — global 宏所有人可执行,personal 宏仅创建者可执行
  • 涉及的自动化/规则/事件
    • 宏执行后产生的对话变更可能触发 AutomationRuleListener 事件(但 Current.executed_by 不是 AutomationRule,所以不会被防循环机制阻断)
    • Current.user 在执行期间设为调用者,ensure { Current.reset } 清除
  • Gochat 实现建议
    • 执行改为异步任务队列(类似 MacrosExecutionJob),支持批量对话
    • 可见性控制需在查询层做过滤(global + personal where created_by == user_id
    • agent 角色创建宏时强制 personal 可见性
    • 'self' 参数在 assign_agent 动作中需替换为当前用户ID

功能6:模板消息 CRUD + 搜索(CannedResponse

  • 功能描述:模板消息(CannedResponse)是预定义的快速回复内容,通过 short_code 快速检索。客服人员在对话中输入 short_code 即可快速插入预置内容。模板属于账户级别,同一账户内 short_code 唯一。
  • 用户操作流程(UI交互步骤)
    1. 进入 Settings → Canned Responses 页面
    2. 点击 "Add Canned Response" 按钮
    3. 填写 short_code(快捷码)和 content(模板内容)
    4. 保存后在对话输入框中输入 short_code 即可搜索并插入
  • 涉及的API端点 + 请求/响应格式
    • GET /api/v1/accounts/{account_id}/canned_responses — 获取模板列表
      • 可选参数 search:搜索匹配 short_code 或 content
      • 响应:模板列表 [{ id, short_code, content, account_id }]
    • POST /api/v1/accounts/{account_id}/canned_responses — 创建模板
      • 请求:{ canned_response: { short_code: "hello", content: "Hello, how can I help you?" } }
      • 响应:模板对象
    • PUT /api/v1/accounts/{account_id}/canned_responses/{id} — 更新模板
    • DELETE /api/v1/accounts/{account_id}/canned_responses/{id} — 删除模板
  • 涉及的数据模型 + 关键字段
    • CannedResponse 模型(表 canned_responses):
      • id (serial, PK)
      • account_id (integer, not null, FK → accounts)
      • short_code (string) — 快捷码,同账户下唯一(uniqueness: { scope: :account_id }
      • content (text) — 模板内容
      • created_at, updated_at (datetime)
    • 关联:belongs_to :account
  • 涉及的业务逻辑(service层)
    • 搜索逻辑:CannedResponse#order_by_search(search) — 使用 CASE WHEN 加权排序:
      • short_code 以搜索词开头 → 权重 1.0
      • short_code 包含搜索词 → 权重 0.5
      • content 包含搜索词 → 权重 0.2
      • 结果按权重降序排列
    • 列表搜索:where('short_code ILIKE :search OR content ILIKE :search', search: "%#{search}%") + order_by_search
    • 校验:validates :content, :short_code, :account, presence: trueshort_code 同账户唯一
  • 权限控制
    • CannedResponse 无独立 Policy 文件,继承 BaseController 的 check_authorization(通过 Current.account 隔离数据)
    • 所有角色均可使用模板消息
  • Gochat 实现建议
    • 搜索权重排序可用 Go 的 sort.Slice + 自定义 scoring 函数实现
    • short_code 唯一约束在数据库层 + 应用层双重校验
    • 模板消息属于轻量功能,建议直接 CRUD 无需复杂 service 层
    • 可扩展支持变量插值(如 {{contact.name}}),Chatwoot 当前版本未实现此功能

功能7:自动化执行引擎(AutomationExecution

  • 功能描述:自动化执行引擎是条件匹配 + 动作执行的核心流程,由 AutomationRuleListener 触发,串联 ConditionsFilterService → ConditionValidationService → ActionService 的完整链路。
  • 执行链路图
    EventBus Event (conversation_created/updated/opened/resolved, message_created)
      → AutomationRuleListener#conversation_* / #message_created
        → rule_present?(event_name, account)  // 是否有匹配的活跃规则
        → current_account_rules(event_name, account)  // 获取规则列表
        → ConditionsFilterService.new(rule, conversation, options).perform
          → ConditionValidationService.new(rule).perform  // 校验条件合法性
          → apply_filter / filter_operation  // 构建查询条件
          → base_relation.where(query_string, filter_values)  // SQL 查询匹配
          → perform_attribute_changed_filter  // 变更属性特殊处理
        → (条件匹配) AutomationRules::ActionService.new(rule, account, conversation).perform
          → rule.actions.each { send(action_name, action_params) }  // 动态调用动作
          → ActionService 基础动作 / AutomationRule 覆写动作
    
  • 执行上下文管理
    • Current.executed_by = rule — 标记执行来源(防循环)
    • ensure { Current.reset } — 执行完毕后清除上下文
    • 每个动作执行前 @conversation.reload — 确保对话最新状态
    • 动作错误不中断流程(rescue + ChatwootExceptionTracker.capture_exception
  • Reauthorizable 机制
    • ConditionValidationService 校验失败时,规则被标记 authorization_error!
    • Redis 计数器累计错误次数,超过阈值(AUTHORIZATION_ERROR_THRESHOLD)后标记 reauthorization_required?
    • 条件更新后 after_update_commit :reauthorized! 重新触发授权检查
    • UI 中显示 reauthorization_required? 状态,提示用户重新授权
  • 企业版扩展Enterprise::AutomationRule):
    • 条件属性追加:sla_policy_id
    • 动作属性追加:add_sla
  • Gochat 实现建议
    • 执行链路建议改为异步队列(避免在事件回调中同步执行大量动作)
    • Current 上下文在 Go 中可用 context.Context 传递
    • Reauthorizable 机制可简化为:条件校验失败时标记规则状态为 inactiveneeds_review
    • 企业版扩展(SLA 动作/条件)需与 M8(SLA 模块)联动

跨模块依赖关系

依赖模块 依赖内容 说明
M3 对话与消息 EventBus 事件触发、Conversation/Message 数据模型 自动化监听依赖对话/消息事件
M5 团队与分配 Team/Agent 分配、AutoAssignment 动作中的 assign_team / assign_agent 依赖
M7 标签系统 Label CRUD 动作中的 add_label / remove_label 依赖
M8 SLA(企业版) SLA Policy 企业版条件/动作扩展
M10 自定义属性 CustomAttributeDefinition 条件中的自定义属性匹配
M1 账户与用户 Account/User/AccountUser 数据隔离和权限控制
M2 收件箱 Inbox 模型 条件中 inbox_id、动作中坐席-inbox 归属校验
M9 Webhook WebhookJob 动作中 send_webhook_event 依赖

关键数据表关系图

accounts
  ├── automation_rules (account_id FK)
  │     ├── conditions (jsonb)
  │     ├── actions (jsonb)
  │     └── files (ActiveStorage polymorphic)
  ├── macros (account_id FK)
  │     ├── created_by_id → users
  │     ├── updated_by_id → users
  │     ├── actions (jsonb)
  │     └── files (ActiveStorage polymorphic)
  └── canned_responses (account_id FK)
        ├── short_code (unique within account)
        └── content (text)

完整文件清单

文件路径 职责
app/models/automation_rule.rb 自动化规则模型:条件/动作校验、属性白名单、Reauthorizable
app/models/macro.rb 宏模型:动作校验、可见性枚举、with_visibility 查询
app/models/canned_response.rb 模板消息模型:short_code 唯一、搜索加权排序
app/controllers/api/v1/accounts/automation_rules_controller.rb 自动化规则 CRUD + clone + 附件处理
app/controllers/api/v1/accounts/macros_controller.rb 宏 CRUD + execute + 附件处理
app/controllers/api/v1/accounts/canned_responses_controller.rb 模板消息 CRUD + 搜索
app/services/action_service.rb 基础动作执行引擎(assign_agent/team, label, status, priority 等)
app/services/automation_rules/action_service.rb 自动化规则动作执行:覆写 send_message/add_private_note/send_email_to_team/send_webhook_event
app/services/automation_rules/conditions_filter_service.rb 条件匹配引擎:继承 FilterService,支持 attribute_changed
app/services/automation_rules/condition_validation_service.rb 条件格式校验:验证 attribute_key / filter_operator / query_operator
app/services/macros/execution_service.rb 宏动作执行:覆写 assign_agent(self), send_message, add_private_note, send_attachment, send_webhook_event
app/jobs/macros_execution_job.rb 宏异步执行 Job:批量遍历 conversation_ids
app/listeners/automation_rule_listener.rb 自动化事件监听器:监听 5 种事件,防循环/防自动回复
app/policies/automation_rule_policy.rb 自动化规则权限:仅 administrator
app/policies/macro_policy.rb 宏权限:global/personal 区分,创建者优先
app/mailers/team_notifications/automation_notification_mailer.rb 自动化邮件通知:send_email_to_team 动作的邮件发送
lib/filters/filter_keys.yml 条件属性配置:定义 conversations/contacts/messages 可用属性和运算符
app/models/concerns/reauthorizable.rb 授权错误追踪:Redis 计数 + 阈值 + 重授权提示
enterprise/app/models/enterprise/automation_rule.rb 企业版扩展:追加 sla_policy_id 条件和 add_sla 动作
db/schema.rb automation_rules / macros / canned_responses 表定义