Files
gochat/docs/requirements/M4-contact-management.md
T
2026-06-04 15:44:48 +08:00

29 KiB
Raw Blame History

M4 联系人管理 — Chatwoot 功能梳理文档

基于 Chatwoot 源码深度阅读 + CodeGraph 上下文梳理
生成日期:2026-05-22
参照仓库:chatwoot-reference


模块概述

本模块覆盖 Chatwoot 的联系人(Contact)全生命周期管理,包括联系人 CRUD、搜索、合并、ContactInbox(联系人-收件箱关联)、CustomAttribute(自定义属性)、CustomFilter(自定义筛选器)、Note(笔记)、Label(标签)以及企业版 Company(公司)功能。核心目标是构建完整的 CRM 体系,让客服团队可以对客户信息进行精细化管理、分类和检索。


1. 联系人 CRUD + 状态管理

联系人创建

  • 功能描述:联系人(Contact)是 Chatwoot CRM 的核心实体,代表一个客户/潜在客户。创建时可指定邮箱、电话、姓名等基本信息,并可同时关联到一个 Inbox(通过 ContactInbox)。联系人通过渠道消息自动创建,也可由坐席手动创建。
  • 用户操作流程
    1. 客户通过渠道(WhatsApp/Facebook/Telegram/WebWidget 等)发消息,系统自动创建联系人 + ContactInbox
    2. 坐席可在 Contacts 页面手动创建联系人(POST /api/v1/accounts/{account_id}/contacts),可同时指定 inbox_idsource_id
    3. CSV 批量导入联系人(POST /api/v1/accounts/{account_id}/contacts/import),仅管理员可操作
    4. 创建后触发 dispatch_create_eventActionCable)和 ip_lookup(如 feature flag 启用)
  • 涉及的API端点
    • POST /api/v1/accounts/{account_id}/contacts — 创建联系人
    • 请求参数:{ name, identifier, email, phone_number, avatar, avatar_url, inbox_id, source_id, additional_attributes: {}, custom_attributes: {} }
    • POST /api/v1/accounts/{account_id}/contacts/import — CSV 导入(管理员)
    • POST /api/v1/accounts/{account_id}/contacts/export — CSV 导出(管理员)
    • 响应:联系人对象 { id, name, email, phone_number, identifier, avatar_url, additional_attributes, custom_attributes, contact_type, blocked, ... }
  • 涉及的数据模型
    • Contactcontacts 表)核心字段:
      • id, name, email, phone_number, identifier, middle_name, last_name, country_code, location, contact_type, blocked
      • additional_attributesjsonb)— 存放 city, company_name, social_* 等扩展信息
      • custom_attributesjsonb)— 存放自定义属性键值对
      • account_id, company_id(企业版), last_activity_at, created_at, updated_at
    • contact_type enumvisitor(0), lead(1), customer(2)
    • 索引:
      • index_contacts_on_account_id_and_contact_type — 按账户+类型查询
      • index_contacts_on_lower_email_account_id — 邮箱大小写不敏感唯一
      • index_contacts_on_name_email_phone_number_identifier — GIN 全文搜索
      • index_contacts_on_nonempty_fields — 过滤有标识信息的联系人
  • 涉及的业务逻辑
    • ContactInboxBuilderapp/builders/contact_inbox_builder.rb):创建联系人时若指定 inbox_id,自动创建 ContactInbox。根据渠道类型智能生成 source_idEmail→邮箱、WhatsApp→去掉+的电话、Twilio→带+的电话、WebWidget/API→UUID
    • Contacts::SyncAttributesapp/services/contacts/sync_attributes.rb):
      • additional_attributes 同步 locationcountry_code 到主字段
      • 自动升级 contact_typevisitor → lead(当有 email/phone/social 信息时)
    • Avatarable concern:自动从 Gravatar 拉取头像(邮箱变更时异步执行)
    • before_validation :prepare_contact_attributes — 清理空属性
    • before_save :sync_contact_attributes — 同步联系人属性
    • after_create_commit :dispatch_create_event, :ip_lookup
    • after_update_commit :dispatch_update_event
    • after_destroy_commit :dispatch_destroy_event
  • 涉及的权限策略
    • ContactPolicyindex?, active?, search?, filter?, show?, create?, update?, contactable_inboxes?, destroy_custom_attributes?, avatar? → 所有坐席可操作;import?, export?, destroy? → 仅管理员
  • 涉及的事件/通知
    • ActionCable:创建/更新/删除事件推送
    • CONTACT_MERGED 事件(合并时触发)

联系人列表 + 排序 + 分页

  • 功能描述:支持按账户获取联系人列表,支持多字段排序和分页。默认只展示有标识信息的"resolved contacts"CRM V2 模式下只展示 lead 类型)。
  • 涉及的API端点
    • GET /api/v1/accounts/{account_id}/contacts — 分页列表(默认 15 条/页)
    • GET /api/v1/accounts/{account_id}/contacts/active — 最近活跃联系人
    • 请求参数:page, sort, include_contact_inboxes
  • 排序支持(Sift gem
    • email, name, phone_number, last_activity_at, created_at, company_name, city, country — 支持 asc/desc
  • resolved_contacts 逻辑
    • 默认模式:WHERE email <> '' OR phone_number <> '' OR identifier <> ''
    • CRM V2 模式:WHERE contact_type = 'lead'
  • 标签过滤:支持 labels 参数(ActsAsTaggableOn tagged_withany: true

联系人搜索

  • 功能描述:对联系人的 name/email/phone_number/identifier 进行 ILIKE 模糊搜索,返回分页结果。
  • 涉及的API端点
    • GET /api/v1/accounts/{account_id}/contacts/search?q=xxx — 搜索
    • 响应包含 has_more 标识(多取一条判断是否还有更多数据)

联系人更新

  • 涉及的API端点
    • PUT /api/v1/accounts/{account_id}/contacts/{id} — 更新联系人
    • 更新时 custom_attributes 和 additional_attributes 采用 merge(合并)策略而非覆盖
    • 支持 avatar_url 参数,从 URL 拉取头像

联系人删除

  • 涉及的API端点
    • DELETE /api/v1/accounts/{account_id}/contacts/{id} — 删除联系人(仅管理员)
    • 删除前检查在线状态(OnlineStatusTracker),在线联系人不可删除
    • 关联的 conversations, contact_inboxes, messages, notes 等通过 dependent: :destroy_async 异步级联删除

联系人头像管理

  • 涉及的API端点
    • DELETE /api/v1/accounts/{account_id}/contacts/{id}/avatar — 删除头像

2. 联系人高级筛选(Filter

筛选器运行

  • 功能描述:基于 Contacts::FilterService,支持多条件组合筛选联系人。筛选条件来自 filter_keys.yml 中的 contact 字段定义 + 自定义属性。支持标准属性、additional_attributes 和自定义属性三种类型。
  • 涉及的API端点
    • POST /api/v1/accounts/{account_id}/contacts/filter — 执行筛选
    • 请求参数:{ payload: { contacts: [ { attribute_key, filter_operator, values, attribute_type, data_type } ... ] } }
  • 筛选字段(filter_keys.yml → contacts
    字段 attribute_type data_type filter_operators
    name standard text_case_insensitive equal_to, not_equal_to, contains, does_not_contain
    phone_number standard text equal_to, not_equal_to, contains, does_not_contain, starts_with
    email standard text_case_insensitive equal_to, not_equal_to, contains, does_not_contain
    identifier standard text_case_insensitive equal_to, not_equal_to
    country_code additional_attributes text_case_insensitive equal_to, not_equal_to
    city additional_attributes text_case_insensitive equal_to, not_equal_to, contains, does_not_contain
    company_name additional_attributes text_case_insensitive equal_to, not_equal_to, contains, does_not_contain
    labels standard labels equal_to, not_equal_to, is_present, is_not_present
    created_at standard date is_greater_than, is_less_than, days_before
    last_activity_at standard date is_greater_than, is_less_than, days_before
    blocked standard boolean equal_to, not_equal_to
    (自定义属性) custom_attribute 对应类型 对应操作符
  • 涉及的业务逻辑
    • Contacts::FilterService 继承 FilterService
      • base_relationaccount.contacts.resolved_contacts
      • 支持 phone_number 特殊处理(自动加 +
      • 支持 country_code 特殊处理(自动 downcase
      • 支持 crm_v2 feature flag
    • FilterService 核心逻辑:解析 filter payload → 逐条件构建 SQL → 组合 query_string + filter_values → 执行查询
    • 自定义属性筛选通过 Filters::CustomAttributeFilterHelper,查询 custom_attribute_definitions 表获取属性定义,动态构建 JOIN + WHERE 条件
  • 涉及的权限策略
    • ContactPolicy filter? → 所有坐席可用

3. 联系人合并(Merge

合并操作

  • 功能描述:将两个联系人合并为一个。base_contact 保留为主联系人,mergee_contact 的数据被合并后删除。合并操作在事务中执行,迁移所有关联数据。
  • 涉及的API端点
    • POST /api/v1/accounts/{account_id}/actions/contact_merge — 合并联系人
    • 请求参数:{ base_contact_id, mergee_contact_id }
  • 涉及的数据模型 + 关键字段:无独立数据模型,纯 Action 类
  • 涉及的业务逻辑
    • ContactMergeActionapp/actions/contact_merge_action.rb):
      1. validate_contacts — 校验两个联系人属于同一账户
      2. merge_conversations — 将 mergee 的所有 Conversation 的 contact_id 改为 base
      3. merge_messages — 将 mergee 作为 sender 的所有 Message 改为 base
      4. merge_contact_inboxes — 将 mergee 的所有 ContactInbox 改为 base
      5. merge_contact_notes — 将 mergee 的所有 Note 改为 base
      6. merge_and_remove_mergee_contact — 合并属性策略:
        • 可合并字段:identifier, name, email, phone_number, additional_attributes, custom_attributes
        • 使用 deep_mergebase_contact 的值优先,mergee 的空值被跳过
        • 合并后删除 mergee_contact
      7. 触发 CONTACT_MERGED 事件(Dispatcher dispatch
  • 涉及的权限策略
    • ContactMergesController 继承 BaseController,需要 check_authorization
  • 注意事项
    • 如果 base_contact.id == mergee_contact.id,直接返回 base_contact(防止重复合并)
    • 合并是事务性操作,失败则回滚

4. ContactInbox(联系人-收件箱关联)

ContactInbox 创建

  • 功能描述ContactInbox 是联系人与收件箱的中间关联表,记录联系人在某个渠道的外部标识(source_id)。一个联系人可以关联多个 Inbox(多渠道联系)。
  • 涉及的API端点
    • POST /api/v1/accounts/{account_id}/contacts/{contact_id}/contact_inboxes — 创建 ContactInbox
    • 请求参数:{ inbox_id, source_id }
  • 涉及的数据模型
    • ContactInboxcontact_inboxes 表)核心字段:
      • id, contact_id, inbox_id, source_id, hmac_verified, pubsub_token
      • 索引:inbox_id + source_id UNIQUE(同一收件箱+source唯一)
      • pubsub_token UNIQUE(用于 ActionCable 推送)
  • 涉及的业务逻辑
    • ContactInboxBuilderapp/builders/contact_inbox_builder.rb):
      • 若已有相同 inbox_id + source_id 的 ContactInbox,直接返回(不重复创建)
      • 若未指定 source_id,根据渠道类型自动生成:
        • Email → 使用 contact.email
        • WhatsApp → 使用 contact.phone_number(去掉 +
        • Twilio SMS → 根据渠道 medium 生成(SMS→带+的电话,WhatsApp→去掉+
        • SMS → 使用 contact.phone_number
        • WebWidget/API → SecureRandom.uuid
      • 支持 hmac_verified 参数(Website 渠道 HMAC 校验标识)
    • valid_source_id_format? — 校验 source_id 格式(使用 RegexHelper
    • current_conversation — 返回该 ContactInbox 的最新对话
    • webhook_data — 包含 contact/inbox/account/current_conversation 的完整推送数据
  • ContactableInboxes(可用收件箱)
    • GET /api/v1/accounts/{account_id}/contacts/{id}/contactable_inboxes — 获取该联系人可以发消息的收件箱列表
    • Contacts::ContactableInboxesService:遍历账户所有 Inbox,根据渠道类型和联系人信息判断可用性:
      • Email → 需要有 email
      • WhatsApp/SMS/Twilio → 需要有 phone_number
      • WebWidget → 需要已有 ContactInbox 且无活跃对话
      • API → 直接可用(可用已有 source_id 或生成 UUID

ContactInbox 清理(Stale Cleanup

  • 功能描述:系统定期清理没有关联对话且创建时间过久的 ContactInbox 和无标识信息的联系人。
  • 涉及的业务逻辑
    • ContactInbox.stale_without_conversations(time_period) — scope 查找无对话的旧 ContactInbox
    • Contact.stale_without_conversations(time_period) — scope 查找无标识、无对话的旧联系人
    • Internal::RemoveStaleContactInboxesJob/Service — 定期清理
    • Internal::RemoveStaleContactsJob/Service — 定期清理

5. CustomAttributeDefinition(自定义属性定义)

自定义属性定义 CRUD

  • 功能描述:自定义属性定义(CustomAttributeDefinition)是账户级别的配置,定义可用于 Contact/Conversation/Company 的扩展字段。每个定义指定属性键、显示名称、显示类型、所属模型等。定义后,对应实体的 custom_attributes jsonb 字段即可存储该键值对。
  • 涉及的API端点
    • GET /api/v1/accounts/{account_id}/custom_attribute_definitions — 按模型类型列出定义
    • GET /api/v1/accounts/{account_id}/custom_attribute_definitions/{id} — 获取单个定义
    • POST /api/v1/accounts/{account_id}/custom_attribute_definitions — 创建定义
    • PUT /api/v1/accounts/{account_id}/custom_attribute_definitions/{id} — 更新定义
    • DELETE /api/v1/accounts/{account_id}/custom_attribute_definitions/{id} — 删除定义
  • 涉及的数据模型
    • CustomAttributeDefinitioncustom_attribute_definitions 表)核心字段:
      • id, attribute_display_name, attribute_description, attribute_key, attribute_display_type, attribute_model, attribute_values(jsonb), default_value, regex_pattern, regex_cue, account_id
      • attribute_model enumconversation_attribute(0), contact_attribute(1), company_attribute(2)
      • attribute_display_type enumtext(0), number(1), currency(2), percent(3), link(4), date(5), list(6), checkbox(7)
      • 索引:attribute_key + attribute_model + account_id UNIQUE
  • 标准属性(不可覆盖)
    • Contact 标准属性:name, email, phone_number, identifier, country_code, city, company_name, created_at, last_activity_at, referer, blocked
    • Conversation 标准属性:status, priority, assignee_id, inbox_id, team_id, display_id, campaign_id, labels, browser_language, country_code, referer, created_at, last_activity_at
    • Company 标准属性:name, domain, description, contacts_count, created_at, updated_at, last_activity_at
  • 涉及的校验
    • attribute_must_not_conflict — attribute_key 不能与标准属性冲突(on :create)
    • normalize_attribute_fields — attribute_key 自动 downcase
    • regex_pattern/regex_cue — 企业版扩展,支持正则校验提示
    • attribute_values — list 类型时存储可选值列表
  • 涉及的业务逻辑
    • after_update :update_widget_pre_chat_custom_fields — 更新时同步到 Widget 的预聊天自定义字段(非 company_attribute
    • after_destroy :sync_widget_pre_chat_custom_fields — 删除时同步
    • 企业版 Enterprise::Concerns::CustomAttributeDefinition
      • after_destroy :cleanup_conversation_required_attributes — 删除定义后清理 account.conversation_required_attributes
  • 涉及的权限策略
    • CustomAttributeDefinitionPolicyindex?, show? → 坐席+管理员;create?, update?, destroy? → 仅管理员

联系人自定义属性操作

  • 涉及的API端点
    • POST /api/v1/accounts/{account_id}/contacts/{id}/destroy_custom_attributes — 删除指定的自定义属性键
    • 请求参数:{ custom_attributes: ["key1", "key2"] }
    • 实际是排除(excluding)指定键,保留其余
    • 更新联系人时通过 custom_attributes: {} 参数 merge 到已有属性

6. CustomFilter(自定义筛选器)

自定义筛选器 CRUD

  • 功能描述:自定义筛选器(CustomFilter)是用户级别的筛选条件保存机制,允许坐席保存常用筛选条件以便快速复用。每个筛选器属于一个用户+账户,可按类型区分(对话/联系人/报告)。
  • 涉及的API端点
    • GET /api/v1/accounts/{account_id}/custom_filters?filter_type=contact — 列出用户的联系人筛选器
    • GET /api/v1/accounts/{account_id}/custom_filters/{id} — 获取单个筛选器
    • POST /api/v1/accounts/{account_id}/custom_filters — 创建筛选器
    • PUT /api/v1/accounts/{account_id}/custom_filters/{id} — 更新筛选器
    • DELETE /api/v1/accounts/{account_id}/custom_filters/{id} — 删除筛选器
  • 涉及的数据模型
    • CustomFiltercustom_filters 表)核心字段:
      • id, name, filter_type, query(jsonb), account_id, user_id
      • filter_type enumconversation(0), contact(1), report(2)
  • 涉及的校验
    • validate_number_of_filters — 每用户每账户最多 Limits::MAX_CUSTOM_FILTERS_PER_USER 个筛选器
  • 创建筛选器请求
    • { custom_filter: { name: "VIP Contacts", filter_type: "contact", query: { contacts: [{ attribute_key: "email", filter_operator: "contains", values: ["@vip.com"] }] } } }

7. Note(笔记)

笔记 CRUD

  • 功能描述:笔记(Note)是联系人级别的内部备忘信息,供坐席记录与客户相关的备注。笔记按创建时间倒序排列。
  • 涉及的API端点
    • GET /api/v1/accounts/{account_id}/contacts/{contact_id}/notes — 列出笔记(倒序)
    • GET /api/v1/accounts/{account_id}/contacts/{contact_id}/notes/{id} — 获取单条笔记
    • POST /api/v1/accounts/{account_id}/contacts/{contact_id}/notes — 创建笔记
    • PUT /api/v1/accounts/{contact_id}/accounts/{account_id}/contacts/{contact_id}/notes/{id} — 更新笔记
    • DELETE /api/v1/accounts/{account_id}/contacts/{contact_id}/notes/{id} — 删除笔记
  • 涉及的数据模型
    • Notenotes 表)核心字段:
      • id, content(text, not null), account_id, contact_id, user_id, created_at, updated_at
      • user_id optional — 可匿名笔记
  • 涉及的业务逻辑
    • before_validation :ensure_account_id — 自动从 contact 取 account_id
    • scope :latestorder(created_at: :desc)
    • 创建时自动注入 user_id: Current.user.id
    • 删除联系人时级联删除(dependent: :destroy_async
    • 合并联系人时笔记迁移到 base_contact

8. Label(标签)

标签 CRUD

  • 功能描述:标签(Label)是账户级别的分类标记,可用于联系人和对话。标签通过 ActsAsTaggableOn 实现多对多关联。标签有颜色、描述、是否在侧边栏显示等属性。
  • 涉及的API端点(账户级别标签管理):
    • GET /api/v1/accounts/{account_id}/labels — 列出标签
    • GET /api/v1/accounts/{account_id}/labels/{id} — 获取标签
    • POST /api/v1/accounts/{account_id}/labels — 创建标签
    • PUT /api/v1/accounts/{account_id}/labels/{id} — 更新标签
    • DELETE /api/v1/accounts/{account_id}/labels/{id} — 删除标签
  • 涉及的数据模型
    • Labellabels 表)核心字段:
      • id, title, color(default "#1f93ff"), description, show_on_sidebar, account_id
      • 索引:title + account_id UNIQUE
  • 涉及的校验
    • titlepresence, formatUNICODE_CHARACTER_NUMBER_HYPHEN_UNDERSCORE),uniquenessscope: account_id
    • before_validation → title 自动 downcase
  • 涉及的业务逻辑
    • acts_as_taggable_on :labels(通过 Labelable concern
    • Labelable concern 方法:
      • update_labels(labels) — 设置标签列表(覆盖)
      • add_labels(new_labels) — 添加标签(追加)
    • after_update_commit :update_associated_models — 标题变更时触发 Labels::UpdateJob,异步更新所有使用旧标签名的 taggings
    • 删除标签时触发 Labels::RemoveAssociationsJob,清理所有 taggings
    • default_scope { order(:title) } — 默认按标题排序

联系人标签操作

  • 涉及的API端点
    • POST /api/v1/accounts/{account_id}/contacts/{contact_id}/labels — 设置/更新联系人标签
    • GET /api/v1/accounts/{account_id}/contacts/{contact_id}/labels — 获取联系人标签列表
    • 请求参数:{ labels: ["vip", "enterprise"] }
    • 使用 LabelConcernmodel.update_labels(permitted_params[:labels])

联系人批量标签操作

  • 涉及的API端点
    • POST /api/v1/accounts/{account_id}/bulk_actions — 批量操作(type=Contact
    • 请求参数:{ type: "Contact", ids: [...], labels: { add: ["vip"] } }
    • Contacts::BulkAssignLabelsService:批量给多个联系人添加标签

9. Company(企业版)

公司 CRUD

  • 功能描述:公司(Company)是企业版功能,代表联系人所属的企业组织。联系人通过 email 域名自动关联到公司,也可手动关联。Company 拥有自己的 custom_attributes、avatar、description 等。
  • 涉及的API端点
    • GET /api/v1/accounts/{account_id}/companies — 公司列表(分页 25 条/页)
    • GET /api/v1/accounts/{account_id}/companies/search?q=xxx — 搜索公司(name/domain
    • GET /api/v1/accounts/{account_id}/companies/{id} — 获取公司详情
    • POST /api/v1/accounts/{account_id}/companies — 创建公司
    • PUT /api/v1/accounts/{account_id}/companies/{id} — 更新公司
    • DELETE /api/v1/accounts/{account_id}/companies/{id} — 删除公司(仅管理员)
    • POST /api/v1/accounts/{account_id}/companies/{id}/destroy_custom_attributes — 删除自定义属性
    • DELETE /api/v1/accounts/{account_id}/companies/{id}/avatar — 删除公司头像
    • ensure_companies_enabled! → feature flag companies 必须启用
  • 涉及的数据模型
    • Companycompanies 表)核心字段:
      • id, name(not null, length limit), domain(unique scope: account_id, 格式校验), description(text, length limit), additional_attributes(jsonb), custom_attributes(jsonb), contacts_count, last_activity_at, account_id
      • 索引:account_id + domain UNIQUE WHERE domain IS NOT NULL
  • 涉及的业务逻辑
    • Company include Avatarable → 支持 avatar + Gravatar
    • before_validation :prepare_jsonb_attributes — 清理 jsonb
    • after_create_commit :fetch_favicon — domain 存在时异步拉取 favicon
    • has_many :contacts, dependent: :nullify — 删除公司时联系人 company_id 设为 NULL
    • scopeordered_by_name, search_by_name_or_domain

公司-联系人关联

  • 涉及的API端点
    • GET /api/v1/accounts/{account_id}/companies/{company_id}/contacts — 公司下的联系人列表
    • GET /api/v1/accounts/{account_id}/companies/{company_id}/contacts/search?q=xxx — 在公司下搜索联系人
    • POST /api/v1/accounts/{account_id}/companies/{company_id}/contacts — 将联系人关联到公司
    • DELETE /api/v1/accounts/{account_id}/companies/{company_id}/contacts/{contact_id} — 从公司中移除联系人
  • 自动关联逻辑
    • Enterprise::Concerns::Contact
      • after_commit :associate_company_from_email, on: [:create, :update], if: :should_associate_company?
      • 条件:email.present? && company_id.nil? && saved_change_to_email? && saved_change_to_email.first.nil?
    • Contacts::CompanyAssociationService
      • 检查邮箱是否为商业邮箱(Companies::BusinessEmailDetectorService
      • 提取域名 → find_or_create_by!(account, domain) 创建或查找公司
      • 公司名称从 additional_attributes.company_name 或域名推导
      • 关联后更新 contact.company_id + Company.contacts_countcounter_cache
      • after_update_commit :record_company_activity — 联系人活跃时更新公司 last_activity_at

10. 批量操作

批量删除联系人

  • 涉及的API端点
    • POST /api/v1/accounts/{account_id}/bulk_actions{ type: "Contact", action_name: "delete", ids: [...] }
    • 权限检查:删除操作需 ContactPolicy destroy?(仅管理员)
  • 涉及的业务逻辑
    • Contacts::BulkActionService → 调度到 Contacts::BulkActionJob
    • delete_requested?Contacts::BulkDeleteServicefind_each(&:destroy!)
  • 涉及的数据模型:无独立模型

11. 导入/导出

CSV 导入

  • 功能描述:支持通过 CSV 文件批量导入联系人。仅管理员可操作。
  • 涉及的API端点
    • POST /api/v1/accounts/{account_id}/contacts/import — 导入 CSV
    • 如企业版未启用联系人导入功能,返回错误

CSV 导出

  • 功能描述:支持将联系人导出为 CSV 文件,异步执行完成后通过邮件发送给管理员。
  • 涉及的API端点
    • POST /api/v1/accounts/{account_id}/contacts/export — 导出
  • 涉及的业务逻辑
    • Account::ContactsExportJob
      • 异步生成 CSV,支持自定义列名
      • Labels 列特殊处理(preload + join taggings
      • 生成后通过 AdministratorNotifications::MailService 发送邮件通知

12. 联系人对话查看

获取联系人的对话

  • 涉及的API端点
    • GET /api/v1/accounts/{account_id}/contacts/{contact_id}/conversations — 获取联系人的所有对话

获取联系人的附件

  • 涉及的API端点
    • GET /api/v1/accounts/{contact_id}/accounts/{account_id}/contacts/{contact_id}/attachments — 获取联系人相关附件

13. 关系图谱总结

Account
  ├── Contact (belongs_to, N:1)
  │     ├── ContactInbox (has_many, N:N through contact_inboxes)
  │     │     ├── Inbox (belongs_to)
  │     │     ├── Conversation (has_many)
  │     │     └── Pubsubable (pubsub_token)
  │     ├── Conversation (has_many)
  │     ├── Message (has_many, as: sender)
  │     ├── Note (has_many)
  │     ├── CsatSurveyResponse (has_many)
  │     ├── Labels (acts_as_taggable_on :labels)
  │     ├── Avatar (has_one_attached)
  │     ├── Company (belongs_to, 企业版, counter_cache)
  │     ├── custom_attributes (jsonb)
  │     └── additional_attributes (jsonb)
  ├── Company (企业版, has_many contacts)
  ├── CustomAttributeDefinition (has_many)
  ├── CustomFilter (has_many)
  └── Label (has_many)

14. 跨模块依赖

依赖模块 依赖内容
M1 账户与用户 Contact/Company/Label/CustomAttributeDefinition 均属于 AccountContactPolicy/CustomAttributeDefinitionPolicy 依赖 AccountUser 角色
M2 收件箱与渠道 ContactInbox 连接 Contact ↔ InboxContactInboxBuilder 根据渠道类型生成 source_idContactableInboxesService 查询可用渠道
M3 对话与消息 Contact has_many ConversationsContact 是 Message 的 polymorphic sender;合并时迁移 Conversation 和 Message
M5 团队与分配 Contact 不直接关联 Team(通过 Conversation 间接关联)
M7 通知与事件 CONTACT_MERGED 事件经 Dispatcher dispatchcontact.create/update/destroy 事件推送 ActionCable

15. GoChat 实现建议

P0(核心必备)

  1. Contact CRUD:联系人创建/读取/更新/删除,含 email/phone/name/identifier 基本字段 + additional_attributes/custom_attributes jsonb
  2. ContactInbox:联系人-收件箱关联,含 source_id,创建时按渠道类型智能生成
  3. Contact 搜索ILIKE 模糊搜索(name/email/phone/identifier
  4. Contact 状态类型visitor/lead/customer 三级进阶,自动升级逻辑
  5. Note CRUD:联系人笔记,含 content + user_id + timestamps

P1(重要增强)

  1. Label 系统:账户级标签 CRUD + 联系人/对话标签关联(可使用简化版 taggable)
  2. Contact 合并base + mergee 合并操作,迁移所有关联数据
  3. Contact 筛选:多条件组合筛选(标准属性 + 自定义属性)
  4. CustomAttributeDefinition:自定义属性定义 CRUDcontact/conversation/company 三类)
  5. CustomFilter:用户级筛选条件保存和复用
  6. 批量操作:批量删除 + 批量标签赋值
  7. ContactableInboxes:查询联系人可用的收件箱列表

P2(企业版扩展)

  1. Company:公司 CRUD + 自动关联(email 域名检测)
  2. Company-Contact:公司下的联系人管理 + 移除关联
  3. Stale Cleanup:定期清理无对话/无标识的 ContactInbox 和 Contact
  4. Contact 导入/导出:CSV 批量导入 + 异步导出邮件通知
  5. regex_pattern/regex_cue:自定义属性正则校验