清理: - 删除 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 相关修改
30 KiB
30 KiB
M6: 自动化与模板(Automation / Macro / CannedResponse)
模块概述
本模块覆盖 Chatwoot 的自动化规则(AutomationRule)、宏操作(Macro)、模板消息(CannedResponse)、自动化事件监听(AutomationRuleListener)及执行引擎(ActionService / ConditionsFilterService)等功能。核心目标是让客服团队基于事件触发自动执行预定义操作、批量处理对话、以及快速复用预置消息模板,减少重复工作并提升响应效率。
功能1:自动化规则 CRUD(AutomationRule)
- 功能描述:在账户级别创建、编辑、克隆、删除自动化规则。规则由 事件触发器(event_name)+ 条件(conditions)+ 动作(actions) 三要素构成。当指定事件发生且条件匹配时,系统自动执行预定义的动作序列。规则支持激活/停用切换(active 字段)。
- 用户操作流程(UI交互步骤):
- 进入 Settings → Automation 页面
- 点击 "Add Automation Rule" 按钮
- 填写规则名称(name)、描述(description)
- 选择触发事件(event_name):conversation_created / conversation_updated / conversation_opened / conversation_resolved / message_created
- 配置条件(conditions):选择属性键、比较运算符、值,以及条件间的逻辑运算符(AND/OR)
- 配置动作(actions):选择动作类型及参数(如发送消息内容、指定坐席/团队ID等)
- 可选上传附件(作为 send_attachment 动作的素材)
- 保存规则,默认 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_createdconditions(jsonb, default '{}', not null) — 条件数组,每项包含attribute_key,filter_operator,values,query_operatoractions(jsonb, default '{}', not null) — 动作数组,每项包含action_name,action_paramsactive(boolean, default true, not null) — 是否激活created_at,updated_at(datetime)
- 关联:
belongs_to :account,has_many_attached :files(ActiveStorage 附件) - 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)
- Controller 层直接 CRUD,但创建/更新时通过
- 权限控制:
- AutomationRulePolicy:所有操作(index/create/show/update/clone/destroy)均要求
@account_user.administrator?,仅管理员可管理自动化规则
- AutomationRulePolicy:所有操作(index/create/show/update/clone/destroy)均要求
- 涉及的自动化/规则/事件:
- 规则自身即为自动化核心,详见功能4(AutomationRuleListener)
- 条件变更后触发
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_operator(AND/OR)组合。 - 条件属性分类:
- 会话属性(conversations):
status(text) — 对话状态,运算符:equal_to / not_equal_toassignee_id(text) — 坐席ID,运算符:equal_to / not_equal_to / is_present / is_not_presentinbox_id(text) — 收件箱ID,运算符:equal_to / not_equal_to / is_present / is_not_presentteam_id(number) — 团队ID,运算符:equal_to / not_equal_to / is_present / is_not_presentpriority(text) — 优先级,运算符:equal_to / not_equal_todisplay_id(Number) — 对话显示ID,运算符:equal_to / not_equal_tocampaign_id(Number) — 营销活动ID,运算符:equal_to / not_equal_tolabels(labels) — 标签,运算符:contains / does_not_contain / is_present / is_not_presentbrowser_language(text, additional_attributes) — 浏览器语言,运算符:equal_to / not_equal_toconversation_language(text, additional_attributes) — 对话语言,运算符:equal_to / not_equal_toreferer(text, additional_attributes) — 来源URL,运算符:equal_to / contains / does_not_containcreated_at(date) — 创建时间,运算符:days_before / is_less_than / is_greater_thanlast_activity_at(date) — 最后活动时间,运算符:days_before / is_less_than / is_greater_thanmail_subject(text, additional_attributes) — 邮件主题,运算符:contains / does_not_contain
- 联系人属性(contacts):
name(text_case_insensitive) — 联系人姓名,运算符:equal_to / not_equal_to / contains / does_not_containphone_number(text) — 电话号码,运算符:equal_to / not_equal_to / contains / does_not_containemail(text) — 邮箱,运算符:equal_to / not_equal_to / contains / does_not_contain / is_present / is_not_presentidentifier(text) — 身份标识,运算符:equal_to / not_equal_to / contains / does_not_containcountry_code(text) — 国家代码,运算符:equal_to / not_equal_tocity(text) — 城市,运算符:equal_to / contains / does_not_containcompany_name(text) — 公司名称,运算符:equal_to / contains / does_not_containlabels(labels) — 联系人标签,运算符:contains / does_not_contain / is_present / is_not_presentcreated_at(date) — 创建时间,运算符:days_before / is_less_than / is_greater_thanlast_activity_at(date) — 最后活动时间blocked(boolean) — 是否已阻断
- 消息属性(messages):
message_type(text) — 消息类型,运算符:equal_to / not_equal_toprivate_note(text) — 内部备注,运算符:equal_to / not_equal_to / contains / does_not_containcontent(text) — 消息内容,运算符:equal_to / contains / does_not_contain
- 自定义属性:支持通过
custom_attribute_definitions表定义的自定义属性,attribute_model支持contact_attribute/conversation_attribute等模型
- 会话属性(conversations):
- 条件匹配逻辑:
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)
- 功能描述:自动化规则和宏共享一套动作系统,动作定义在
actionsjsonb 字段中,每项包含action_name和action_params。执行引擎通过send(action_name, action_params)动态调用对应方法。基础动作由ActionService提供,自动化规则和宏各自覆写部分方法。 - 动作类型清单:
- AutomationRule 专有 actions_attributes(
AutomationRule#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_ATTRS(
Macro::ACTIONS_ATTRS):- 与 AutomationRule 大部分相同,但无
send_email_to_team - 增加
add_private_note,send_attachment,send_webhook_event assign_agent特殊处理:支持'self'参数,自动替换为当前执行用户ID
- 与 AutomationRule 大部分相同,但无
- 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)— 异步发送邮件转录
- AutomationRule 专有 actions_attributes(
- 自动化规则执行 vs 宏执行差异:
- AutomationRules::ActionService:
- 消息/备注的
sender为 nil(自动化系统发出),content_attributes包含automation_rule_id send_email_to_team:遍历团队,通过TeamNotifications::AutomationNotificationMailer发送,并检查邮件速率限制send_webhook_event:payload 包含event: "automation_event.{event_name}"Current.executed_by = rule(标记执行来源为规则)
- 消息/备注的
- Macros::ExecutionService:
- 消息/备注的
sender为当前用户,无automation_rule_id标记 assign_agent支持'self'→ 替换为@user.idsend_webhook_event:payload 包含event: "macro.executed"Current.user = user(标记执行来源为用户)
- 消息/备注的
- 共同点:均继承
ActionService,执行时@conversation.reload确保最新状态,动作错误不中断(rescue + ChatwootExceptionTracker),ensure { Current.reset }
- AutomationRules::ActionService:
- 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— 消息创建时触发(含消息对象和变更属性)
- 事件处理流程:
- 对话事件(
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
- 排除由自动化自身触发的事件(
- 消息事件(
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交互步骤):
- 进入 Settings → Macros 页面
- 点击 "Add Macro" 按钮,填写名称(name)
- 选择可见性(visibility):personal(仅自己)或 global(全账户)
- 配置动作序列(actions):同自动化规则的动作定义格式
- 可选上传附件
- 保存宏
- 在对话列表中选择多个对话,点击 "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 角色强制设为 personal,administrator 可设为 global
- 宏执行:
- Controller 调用
::MacrosExecutionJob.perform_later(@macro, conversation_ids: params[:conversation_ids], user: Current.user)— 异步 Job MacrosExecutionJob(queue: medium):遍历conversation_ids,对每个对话创建Macros::ExecutionService.new(macro, conversation, user).performMacros::ExecutionService继承ActionService,遍历macro.actions执行每项动作(详见功能3)
- Controller 调用
- 动作校验:
validate :json_actions_format
- 可见性控制:
- 权限控制:
- MacroPolicy:
index?/create?— 所有角色均可show?— global 宏所有人可见,personal 宏仅创建者可见update?/destroy?— global 宏仅 administrator,personal 宏仅创建者(author?)execute?— global 宏所有人可执行,personal 宏仅创建者可执行
- MacroPolicy:
- 涉及的自动化/规则/事件:
- 宏执行后产生的对话变更可能触发 AutomationRuleListener 事件(但
Current.executed_by不是 AutomationRule,所以不会被防循环机制阻断) Current.user在执行期间设为调用者,ensure { Current.reset }清除
- 宏执行后产生的对话变更可能触发 AutomationRuleListener 事件(但
- 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交互步骤):
- 进入 Settings → Canned Responses 页面
- 点击 "Add Canned Response" 按钮
- 填写 short_code(快捷码)和 content(模板内容)
- 保存后在对话输入框中输入 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: true,short_code 同账户唯一
- 搜索逻辑:
- 权限控制:
- CannedResponse 无独立 Policy 文件,继承 BaseController 的
check_authorization(通过Current.account隔离数据) - 所有角色均可使用模板消息
- CannedResponse 无独立 Policy 文件,继承 BaseController 的
- 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 机制可简化为:条件校验失败时标记规则状态为
inactive或needs_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 表定义 |