Contacts Specification

Contacts 是"一个号码 = 一个客户"的中心化档案表。本文档定义前端 Contacts 页面展示的所有数据及其来源。

完整版字段分析见 Contacts 字段设计


数据来源分类

前端 Contacts 页面的数据来自 4 种来源

来源说明
① contacts 表直接存储在 contacts 表中的字段,直读即可
② contact_timeline 表从 timeline 事件聚合/查询
③ 跨表派生(calls / leads / messages)从其他表 SQL 查询派生
④ API 层计算不存 DB,API 运行时计算

一、contacts 表(直读)

字段名和类型以 callytics-common/src/db/schema/contacts.ts 为准。

写入者说明

写入者含义
代码数据管道自动写入(通话管道、Lead 管道、SMS 管道)
aiAI 分析写入(Pipeline 1 Per-Call / Pipeline 2 Contact Analysis)
ai+代码AI 分析 + 规则映射共同决定
ai+员工AI 可写入,员工可覆盖
员工仅员工通过 UI 手动操作

字段清单(27 个)

#前端展示位置前端展示名字段类型写入者说明
1Table + ProfilePhonephonetext (PK)代码E.164 格式,复合 PK 之一
2不展示franchiseIdtext (PK)代码所属品牌(franchise 级多租户隔离)
3不展示siteIdtext (PK)代码所属门店(RingCentral providerAccountId)
4Table + ProfileContactfirstNametext代码名(与 lastName 拼接显示)
5Table + ProfileContactlastNametext代码姓(与 firstName 拼接显示)
6Table + Profile + Summary Bar + FilterStagelifecycleStagetextai+代码lead / member / churned / unknown
7不展示lifecycleStatetextai+代码active / frozen / terminal
8Table + ProfileNotesnotestext员工备注(Profile 中为可编辑 textarea)
9Table + FilterDNCdoNotContactbooleanai+员工DNC 标记,全渠道停止触达
10Table + ProfileCardhasCardOnFileboolean代码客户是否有信用卡信息存档
11Table + ProfileLast ActivitylastActivityAttimestamp代码最后活动时间(任何互动都更新)
12Table + Filter + ProfileFollow-up / Action NeededactionNeededbooleanai是否需要跟进(Table 列名 Follow-up,Profile 展示名 Action Needed)
13不展示actionNeededReasontextai为什么需要行动(数据存储但前端不展示)
14aProfileSuggested ActionsuggestedActions[].actionjsonbaiAI 建议操作,多条用分号分隔展示
14bProfilePrioritysuggestedActions[].priorityjsonbai取所有建议中最高优先级,单个 badge(High / Medium / Low)
14c不展示suggestedActions[].reasonjsonbai为什么建议这个操作(数据存储但前端不展示)
14d不展示suggestedActions[].priorityReasonjsonbai为什么是这个优先级(数据存储但前端不展示)
15Table + Filter + Profile + Pipeline BarLead StatusleadStatustextai前端展示 9 个:New / Attempted / Connected / Booked / Bad Timing / Not Interested / Unreachable / Lost Contact / Neglected。Showed / Trialed / Converted 后端存储但前端不展示。当 lifecycleStage='lead' 时,Profile 顶部显示 Lead Pipeline 进度条(New → Attempted → Connected → Booked),当前状态高亮
16不展示leadStatusReasontextai为什么是这个状态(数据存储但前端不展示)
17ProfileLead ObjectionsleadObjectionsjsonbai犹豫中的顾虑标签(amber 标签展示,仅 leadStatus = Connected / Booked 时显示)
18ProfileLead Rejection ReasonsleadRejectionReasonsjsonbai条件性拒绝的原因标签(red 标签展示,仅 leadStatus = Bad Timing 时显示)
19ProfilePurchase IntentpurchaseIntenttextaihigh / medium / low(仅 Lead)
20不展示purchaseIntentReasontextai为什么是这个意向等级(数据存储但前端不展示)
21aProfileGoalgoals[].goaljsonbai客户目标(仅 Lead)
21b不展示goals[].reasonjsonbai为什么判断是这个目标(数据存储但前端不展示)
22ProfileCustomer SummarycustomerSummarytextai综合所有通话和 SMS 的整体画像摘要
23不展示lastContactAnalysisAttimestamp代码Pipeline 2 最后分析时间(cooldown gate 内部使用)
24不展示doNotContactUpdatedBytext代码DNC 来源:staff / ai / system(TCPA 合规审计)
25Table + Filter + ProfileOpen ComplainthasOpenComplaintbooleanai+代码当前是否有未解决投诉
26Table + ProfileAcquiredcreatedAttimestamp代码首次创建时间 = 客户进入系统时间
27不展示updatedAttimestamp代码最后更新时间(Drizzle 自动刷新)

不展示说明

所有 Reason 类数据后端存储但前端不展示,供 AI 内部追溯使用,未来可考虑以 tooltip 或展开方式呈现:

  • 不展示的独立字段(7 个):#7 lifecycleState、#13 actionNeededReason、#16 leadStatusReason、#20 purchaseIntentReason、#23 lastContactAnalysisAt、#24 doNotContactUpdatedBy、#27 updatedAt
  • 不展示的 jsonb 内部属性(3 个)suggestedActions[].reasonsuggestedActions[].priorityReasongoals[].reason
  • 不展示的 leadStatus 枚举值(3 个)showedtrialedconverted — 当前系统无线下数据(门店签到、课程管理、POS),V1 暂不支持

二、contact_timeline 表(事件查询)

前端展示位置前端展示名查询方式event_type
Table + ProfileLast ComplaintMAX(occurred_at)contact.complaint_opened

三、跨表派生(calls / leads / messages)

前端展示位置前端展示名来源表查询方式
ProfileFirst AttemptedcallsMIN(start_time) WHERE contact_phone=? AND direction='Outbound'
ProfileFirst ConnectedcallsMIN(start_time) WHERE contact_phone=? AND call_state='human_conversation'
TableCallscallsCOUNT(*) WHERE contact_phone=? AND direction='Outbound'
TableSMSmessagesCOUNT(*) WHERE from/to_phone_number=?
ProfileCommunication Logcalls + messages通话和 SMS 记录按时间倒序合并展示

四、前端计算(不存 DB)

Lead Temp 不存数据库,前端根据 contacts.createdAt + contacts.leadStatus + 固定阈值直接判断:

leadStatus判断逻辑结果
new / attemptednow - createdAt ≤ 1 天🔥 Hot
new / attemptednow - createdAt ≤ 5 天☀️ Warm
neglected / unreachablenow - createdAt > 5 天❄️ Cold
其他(connected / booked / bad_timing / not_interested / lost_contact)固定, Connected 及之后由 Task 系统管理,温度不再适用。详见 Lead TemperatureN/A

温度仅在 pre-contact 阶段适用。neglectedunreachable 是温度系统的终态(温度冷掉后自动判定),固定 Cold。