跳转至

Contacts 字段设计

目的:对照 Contacts UI 设计和数据指标需求,逐字段分析数据来源,确定 PhoneBook

字段放置原则: PhoneBook 表的定位是客户级别的判定和标记,尽量不重复存储其他表已有的数据。

通话数据 → 查 call-analysis Lead 数据 → 查 LeadTracking-v2 SMS 数据 → 查 MessageStore / Conversations 客户级别的聚合判定(温度、意图、分类、分配、标签) → 存 PhoneBook

分析范围说明:本次改版已对生命周期的 Lead 阶段进行了全面的数据源分析和字段设计。Member 和 Churned 阶段暂未进行详细分析(见 1.3、1.4 标注),因此文档中涉及这两个阶段的字段多为预留或待定状态,后续迭代再细化。


一、Contacts 信息分析

1.1 通用信息(所有 Stage 共用)

类别 字段
身份信息 姓名、电话、邮箱、性别、地址、工作、生日/年龄、作息模式
生命周期 stage 生命阶段、state 活跃状态
运营信息 分配给谁、员工备注、自定义标签、doNotContact (DNC)
活动数据 来源渠道、获取时间、首次尝试联系时间、首次触达时间、通话次数、短信次数、最后活动时间
联系偏好 联系响应模式、最佳联系时段、偏好联系渠道
健身画像 核心需求、感兴趣的课程类型、偏好时段、健身经验(含过往经历)、当前运动习惯、关注点、健康状况
通讯记录 SMS 内容、通话录音(音频回放)、逐句对话记录(Conversation Data,分 Speaker + 时间戳)、语音信箱、系统备注(System Note,如 Lead 提交、预约等系统事件)
AI通话分析 通话摘要:AI 摘要、本次是否需要跟进(followupneeded)、跟进原因(followupreasons) · 关键信息:主分类、子分类、次要话题、通话结果分类、是否获取信用卡、营收优先级 · 通话详情:接听结果、通话方向、通话时长、客户电话、来电方名称、通话时间、接听员工、通话状态、客户类型
AI跨通话分析 客户摘要(customerSummary)、是否需要跟进(actionNeeded,跨通话综合判断)、建议动作列表(suggestedActions,List,每个 action 内含 priority)、建议截止时间(suggestedFollowUpBy)

1.2 Lead 专属信息(仅 stage = Lead 时适用)

类别 字段
Lead 跟进 leadStatus、temperature
Lead 分析 意向等级、提交次数
消费决策 预算区间、价格敏感度、决策风格、决策周期
决策障碍 objections(客户犹豫中的顾虑:价格贵、要和家人商量、时间不确定等)
条件性拒绝原因 rejectionReasons(客户已明确拒绝的原因:太远、已有会籍、时间冲突等)

1.3 Member 专属信息(仅 stage = Member 时适用)

本次改版暂不涉及 Member 阶段,以下内容仅作规划参考,不纳入当前分析和实现范围。

类别 字段
Member 状态 memberStatus(Onboarding / Active / At-risk / VIP)
合同信息 购买套餐、签约日期、合同周期、到期日
使用行为 到课频率、偏好课程、偏好教练、社交活跃度、最后到课日期、连续缺课天数
附加消费 私教课、附加服务、商品购买
客户价值 LTV(累计贡献收入)、CAC(获客成本)、ROI(投资回报率)、消费频次+金额
体测进展 入会体测、阶段体测、目标达成率
续费分析 续费意愿、续费障碍(价格涨幅/使用频率低/体验不满等)、合同到期预警、历史续费次数、上次续费价格变动
推荐裂变 推荐人数、NPS 评分、是否愿意推荐
流失风险 流失风险等级、满意度

⚠️ 合同信息、使用行为、客户价值、附加消费、体测进展依赖会员管理 / 排课签到 / 交易系统,V1 暂无数据源。

1.4 Churned 专属信息(仅 stage = Churned 时适用)

本次改版暂不涉及 Churned 阶段,以下内容仅作规划参考,不纳入当前分析和实现范围。

类别 字段
流失原因 流失原因(价格/距离/服务不满/竞品/生活变化等)
流失画像 竞品去向、回归可能性
回归画像 回归动机、期望变化、可接受条件

二、Contacts 字段数据分析和设计

2.1 身份信息

对应 1.1 身份信息:姓名、电话、邮箱、性别、地址、工作、生日/年龄、作息模式

# 字段 是否已有数据源 数据源 字段名 类型 存入 PhoneBook 说明
1 姓名 LeadTracking-v2 firstName / lastName String 是,冗余存储便于列表排序和搜索 拼接显示;头像取首字母生成彩色圆圈
2 电话 LeadTracking-v2 / call-analysis phone String 是,作为 PK E.164 格式,PhoneBook 主键
3 邮箱 LeadTracking-v2 leadContactEmail String 否,查询时从 LeadTracking-v2 读取 -
4 性别 gender String 是,预留字段 V1 暂无数据源
5 地址 address String 是,预留字段 V1 暂无数据源
6 工作 occupation String 是,预留字段 V1 暂无数据源
7 生日/年龄 birthday String 是,预留字段 V1 暂无数据源
8 作息模式 dailyRoutine String 是,预留字段 V1 暂无数据源

⚠️ 第 4-8 项在 V1 中暂无数据源,PhoneBook 表预留字段位置。未来可能的写入方式:AI 从通话内容中提取、员工手动录入、或对接第三方 CRM/表单系统。

2.2 生命周期

对应 1.1 生命周期:stage 生命阶段、state 活跃状态 详细定义见 客户生命周期管理

# 字段 是否已有数据源 数据源 字段名 类型 存入 PhoneBook 说明
1 Lifecycle Stage - lifecycleStage String 枚举:lead / member / churned / unknown
2 Lifecycle State - lifecycleState String 枚举:active / frozen / terminal

现有数据源分析

数据库中有两个近似字段,但都不直接等同于"生命阶段(lifecycleStage)":

  1. LeadTracking-v2 leadType(值:Web LeadOnline Intro 等)— 这是 Lead 的来源渠道,描述客户从哪个入口进来,不是生命阶段。归入后续运营信息分析。
  2. call-analysis customer_type(值:prospective_client / existing_member / other)— 这是 AI 对单通电话的判定,表示本次通话中对方是潜在客户还是现有会员。它是单次通话粒度的,不是客户级别的状态。

lifecycleStage 判定逻辑

触发条件 数据源
lead 凡是从 LeadTracking-v2 进来的联系人,除了 leadStatus 为 converted 的,都是 lead LeadTracking-v2 存在该 phone 的记录
member LeadTracking-v2 的 leadStatus 变为 converted LeadTracking-v2 leadStatus(当前尚未落库,待实现)
churned 会员流失 ⏳ 需要外部数据源(如会员管理系统),待定
unknown 打错电话、陌生来电等无法判定身份的号码 call-analysis customer_type = other 可作为信号;员工确认身份后可转为 lead + active

员工可手动覆盖系统判定。

lifecycleState 判定逻辑

Lead 阶段的 State 可从 leadStatus 推导;Member 和 Churned 阶段的 State 判定逻辑在生命周期管理文档中已有清晰定义,待对应数据源接入后即可实现。

Stage State leadStatus 数据源
Lead active New, Attempted, Connected, Booked, Showed, Trialed, Converted LeadTracking-v2 leadStatus(待落库)
Lead frozen Bad Timing LeadTracking-v2 leadStatus(待落库)
Lead terminal Not Interested, Unreachable, Lost Contact, Neglected LeadTracking-v2 leadStatus(待落库)
Member active ⏳ 待会员管理系统数据接入
Churned frozen / active / terminal ⏳ 待会员管理系统数据接入

Stage × State 的完整组合和流转路径见 客户生命周期管理 §2.4

2.3 运营信息

对应 1.1 运营信息:分配给谁、员工备注、自定义标签、doNotContact (DNC)

# 字段 是否已有数据源 数据源 字段名 类型 存入 PhoneBook 说明
1 Owner owner String 负责跟进该联系人的员工姓名;员工手动分配或系统自动轮转
2 员工备注 notes String 员工手动录入的备注信息
3 自定义标签 tags String Set 员工自定义标签,用于分组筛选
4 DNC doNotContact Boolean 是否禁止联系;标记后系统停止一切主动触达。来源:AI 从通话/短信内容中识别 DNC 信号后写入,或员工手动标记

说明:运营信息全部为员工操作产生的数据,当前数据库中没有现成数据源,均为 PhoneBook 新字段。

为什么叫 Owner:沿用 CRM 行业惯例(Salesforce 叫 OwnerId,HubSpot 叫 Contact Owner)。Owner 不绑定具体角色——Lead 阶段的 Owner 可能是 BDR,Member 阶段可能是客户经理,Churned 阶段可能是留存专员,通用性更好。当前 owner 存储员工姓名(String),暂无独立的 Owner 表。未来如果做任务分配功能,可能会建立独立的 Owner 表存储员工详细信息(姓名、角色、门店归属等),届时可改为 ownerId 作为外键关联。call-analysis 中有 staff_name 字段(接听员工姓名),但这是单通电话的接听人,不等同于 Owner——owner 是客户级别的责任归属,由管理层分配。

2.4 活动数据

对应 1.1 活动数据:来源渠道、获取日期、首次尝试联系时间、首次触达时间、通话次数、短信次数、最后活动时间

# 字段 是否已有数据源 数据源 字段名 类型 存入 PhoneBook 说明
1 来源渠道 source String 指 Lead 从哪个广告平台来(Facebook / Instagram / Google 等),当前无数据源
2 获取时间 LeadTracking-v2 receivedAt acquiredAt String ISO 8601;该客户首次进入系统的时间
3 首次尝试联系时间 firstAttemptedAt String ISO 8601;员工首次尝试联系该客户的时间(不论是否接通)。LeadTracking-v2 和 PhoneBook 都存储
4 首次触达时间 firstConnectedAt String ISO 8601;员工首次真正接通/产生双向沟通的时间。判定依据待定(可选方案:call_state = human_conversation);仅首次写入,已有值不覆盖。LeadTracking-v2 和 PhoneBook 都存储
5 通话次数 callCount Number call-analysis 中没有此字段,每条记录只是一通电话。PhoneBook 预计算存储,通话管道写入 call-analysis 时同步对 PhoneBook 原子递增
6 短信次数 smsCount Number 同上,SMS 管道写入时同步对 PhoneBook 原子递增
7 最后活动时间 lastActivityAt String ISO 8601;PhoneBook 新字段,每次新通话或 SMS 写入时自动更新为当前时间, LeadTracking-v2 和 PhoneBook 都存储

说明:除来源渠道外,其余字段均有现成数据源,但源数据分散在多个表且粒度为单条记录。PhoneBook 存储的是客户级别的聚合值(如 callCount 是总次数,lastActivityAt 是最新时间),由各数据管道在写入源表时同步更新 PhoneBook。

关于 LeadTracking-v2 leadType:该字段值为 Web LeadOnline Intro,描述的是 Lead 表单的提交类型(网页留资 vs 线上预约体验课),不是来源渠道。真正的来源渠道(Facebook / Instagram / Google / Walk-in / 转介绍等)需要对接广告平台或 CRM 系统,当前 LeadTracking-v2 中没有存储。leadType 已在 2.2 生命周期中分析过,不属于活动数据。

关于 LeadTracking-v2 receivedAt:当前数据库中同一号码存在多条记录(未去重),receivedAt 记录的可能是最近一次提交时间,这是不对的。Lead 入库管道首先应去重,重复提交的数据不再存入,这样 receivedAt 才是真正的首次获取时间。

为什么 PhoneBook 叫 acquiredAt 而不是 receivedAt:LeadTracking-v2 的字段叫 receivedAt(收到 Lead 表单),但 PhoneBook 改名为 acquiredAt,原因:"acquired" 更通用——walk-in、主动来电等 non-Lead 路径客户不是 "received" 来的.

为什么 PhoneBook 要保留自己的时间字段:活动数据中的 4 个时间字段(acquiredAtfirstAttemptedAtfirstConnectedAtlastActivityAt)在 LeadTracking-v2 和 PhoneBook 中都存储。原因有二:

  1. 非 Lead 路径客户没有 LeadTracking-v2 记录:walk-in、主动来电、转介绍等场景下客户直接进入系统,不经过 Lead 提交流程。这类客户的时间数据无法从 LeadTracking-v2 获取,只能由 PhoneBook 自身记录。
  2. PhoneBook 是客户级别的统一视图:即使是 Lead 路径客户,PhoneBook 也需要自己的时间字段来支撑列表排序、筛选、温度衰减等功能,避免每次都跨表查询 LeadTracking-v2。

2.5 联系偏好

对应 1.1 联系偏好:联系响应模式、最佳联系时段、偏好联系渠道

# 字段 是否已有数据源 数据源 字段名 类型 存入 PhoneBook 说明
1 联系响应模式 reachability String AI 从历史通话和 SMS 中归纳的响应特征,如 "首次通常不接,短信回复率高"、"来电秒接"
2 最佳联系时段 bestTimeToReach String AI 分析历史成功接通/回复的时间分布,如 "weekday 10:00-12:00"、"evening after 6pm"
3 偏好联系渠道 preferredChannel String 枚举:call / sms / either;AI 根据渠道响应率推导,或员工手动标记

数据源分析

三个字段当前都没有直接数据源。原始信号分散在 call-analysis(接通率、通话时段、call_state)和 MessageStore(回复率、回复时段)中,需要跨多条记录聚合分析才能得出结论。

写入方式:Layer 2 Daily Batch AI 写入(与 aiSummaryactionNeededsuggestedActions 同一管道)。员工可手动覆盖。

字段 AI 推导逻辑 数据来源
reachability 分析历史交互模式:接通率、首次 vs 多次尝试、SMS 回复速度 call-analysis(call_state、callResult)+ MessageStore(回复时间差)
bestTimeToReach 统计历史成功接通/回复的时间分布,取 Top 时间窗口 call-analysis(callStartTime + callstate = humanconversation)
preferredChannel 对比 call 接通率 vs SMS 回复率,取响应率更高的渠道 call-analysis(接通次数/总拨打次数)+ MessageStore(回复条数/总发送条数)

2.6 健身画像

对应 1.1 健身画像:核心需求、感兴趣的课程类型、偏好时段、健身经验(含过往经历)、当前运动习惯、关注点

# 字段 是否已有数据源 数据源 字段名 类型 存入 PhoneBook 说明
1 核心需求 fitnessGoal String 客户的健身目标,如 "减重"、"增肌"、"康复训练"、"保持体能"
2 感兴趣的课程类型 classInterests String Set 感兴趣的课程,如 {"yoga", "tread 50", "strength training"}
3 偏好时段 preferredTime String 偏好的上课/到店时段,如 "weekday morning"、"weekend afternoon"
4 健身经验 fitnessExperience String 过往健身经历,如 "3 years CrossFit"、"complete beginner"、"former member at another gym"
5 当前运动习惯 exerciseHabits String 当前的运动习惯,如 "runs 3x/week"、"no regular exercise"、"home workouts"
6 关注点 fitnessConcerns String Set 客户的顾虑或关注点,如 {"injury history", "schedule flexibility", "intimidation"}
7 健康状况 healthConditions String Set 身体限制/健康状况,影响训练方案和课程推荐,如 {"hypertension", "knee injury", "diabetes", "pregnancy", "back pain"}

数据源分析

七个字段当前都没有直接数据源。但 call-analysis 的 executive_summary 中已经包含健身相关信号(如 "tread 50 class"、"first class experience"、"membership pricing"),只是以自然语言形式散落在摘要中,未被结构化提取。

写入方式:Layer 2 Daily Batch AI 写入。AI 从该客户所有通话的 transcript + executive_summary + SMS 内容中提取健身画像信息,结构化后写入 PhoneBook。员工可手动补充或覆盖。

字段 AI 提取逻辑 数据来源
fitnessGoal 从对话中识别客户的健身目标表述 call-analysis(transcript、executive_summary)+ MessageStore
classInterests 提取客户提到或预约过的课程类型 call-analysis(executivesummary、primarysubcategory)+ MessageStore
preferredTime 从预约行为和对话中推导偏好时段 call-analysis(executive_summary 中的时间提及)+ MessageStore
fitnessExperience 从对话中识别过往健身经历的描述 call-analysis(transcript)
exerciseHabits 从对话中识别当前运动习惯的描述 call-analysis(transcript)
fitnessConcerns 从对话中识别客户顾虑和担心 call-analysis(transcript、executive_summary)+ MessageStore
healthConditions 从对话中识别客户提到的身体状况、伤病史、慢性病 call-analysis(transcript);员工手动补充优先级更高

2.7 通讯记录

对应 1.1 通讯记录:SMS 内容、通话录音(音频回放)、逐句对话记录(Conversation Data,分 Speaker + 时间戳)、语音信箱、系统备注

⚠️ 与 2.1–2.6 不同:通讯记录是原始事件流不存入 PhoneBook。通过统一的 ActivityLog 索引表按时间倒序渲染为 Communication Timeline。

数据源概览

记录类型 原始数据源 当前状态
通话录音 call-analysis → S3 音频文件 ✅ 28,275 条录音已下载至 S3
语音信箱 call-analysis(isVoicemail = true)→ S3 音频 ✅ 20,224 条语音信箱
逐句对话记录 call-analysis → S3 transcript JSON ⏳ 语音信箱转录完成 765 条;双向对话转录管道已启动但未完成(27,620 条 pending)
SMS 内容 MessageStore ❌ 表尚未创建
系统备注 各业务管道触发写入 ❌ 待建

ActivityLog — 统一 Timeline 索引表 已废弃

架构决策 (2026-03-09):不再建独立 ActivityLog DynamoDB 表

结论:计划将 call-analysis、MessageStore、LeadTracking-v2 全量迁移到 Neon PostgreSQL 后,用 UNION ALL VIEW 替代 ActivityLog。

原因:ActivityLog 的唯一动机是 DynamoDB 无法跨表查询。PostgreSQL 原生支持 UNION ALL + ORDER BY + LIMIT,三张表的时间线在数据库层合并,无需预建索引表。

替代方案:在 Neon 中创建 contact_timeline VIEW(calls UNION ALL sms_messages UNION ALL leads),每张表加 (phone, created_at DESC) 索引。预期延迟 <50ms。

参考:GitLab 在 PostgreSQL 上明确禁止 polymorphic events 表,采用分表 + UNION ALL;HubSpot 用分表 JOIN 而非独立 timeline 表。

以下为原始设计(保留供参考,不实施)。


原设计背景:通讯记录分散在多个源表(call-analysis、MessageStore、系统操作),如果 Timeline UI 每次加载都要查多张表再合并排序,查询复杂且性能差。ActivityLog 作为预建索引,让 UI 只查一张表就能拿到所有事件的时间线。

原设计工作方式:各数据管道在写入源表的同时,同步写入一条轻量索引记录到 ActivityLog。每条记录只存展示摘要 + 源表引用键,不重复存储完整数据。

表设计

字段 类型 说明
phone String PK,客户手机号(E.164)
timestamp#eventId String SK,事件时间 + 唯一 ID,保证时间排序且不冲突
type String 事件类型:call / sms / system
summary String 展示摘要,如 "Outbound · 66s · Call connected"
ref String 源表引用键(通话为 telephonySessionId,SMS 为 messageId,系统备注无 ref)
direction String inbound / outbound(仅 call / sms);UI 用左右布局区分:inbound 显示在左侧(客户发起),outbound 显示在右侧(员工发起)
metadata Map 类型相关的轻量摘要数据(见下方)

metadata 示例

// type = "call"
{ "duration": 66, "callResult": "Call connected", "call_state": "human_conversation", "staff": "Lucas", "hasRecording": true }

// type = "sms"
{ "status": "delivered", "preview": "Hi, thanks for your interest..." }

// type = "system"
{ "event": "owner_changed", "detail": "Owner assigned: Lucas" }

写入方式

触发场景 type 写入时机
通话管道 call 写入 call-analysis 时同步写入
SMS 管道 sms 写入 MessageStore 时同步写入
Lead 入库 system LeadTracking-v2 写入时同步写入
员工操作 system PhoneBook 字段变更(Owner、DNC、Tag、Stage)时写入
CRM 回调 system 未来 CRM 对接后写入

查询方式:Timeline UI 查询 ActivityLog(PK=phone,SK 倒序),一次查询拿到所有事件。用户点击某条记录展开详情时,根据 ref 去源表(call-analysis / MessageStore)加载完整数据(录音、转录、完整短信等)。

系统备注(System Note,待建)

人工或系统触发的操作事件,在 Timeline 中穿插显示,帮助员工了解客户旅程的关键节点。不包含 AI 通话分析推导出的信息(那些属于 2.8/2.9)。

# 事件类型 触发场景 说明
1 Lead 提交 LeadTracking-v2 写入时 "New lead submitted via Facebook — Web Lead"
2 Owner 变更 PhoneBook owner 更新时 "Owner assigned: Lucas"
3 DNC 手动标记 员工手动标记/取消 "Marked as Do Not Contact" / "DNC removed"
4 Tag 变更 员工手动添加/移除 "Tag added: VIP" / "Tag removed: Hot Lead"
5 Stage 手动变更 员工手动调整 "Stage changed: Lead → Member"

CRM 对接后扩展(当前无数据源,未来接入 CRM 系统后可增加):

# 事件类型 触发场景 说明
6 会籍变更 CRM 回调 "Membership purchased: Elite Plan" / "Membership cancelled"
7 预约创建/取消/改期 CRM 回调 "Intro class booked for Mar 5, 2026 10:00 AM"
8 课程签到 CRM 回调 "Checked in: Tread 50 @ 9:00 AM"
9 付款事件 CRM 回调 "Payment processed: $59.00" / "Payment failed"

说明:系统备注直接以 type=system 写入 ActivityLog,不需要独立的源表——ActivityLog 本身就是系统备注的存储位置。各业务管道在执行操作时(Lead 入库、员工改 Owner/DNC/Tag/Stage、CRM 回调等)同步写入一条 type=system 记录。

2.8 AI 通话分析(Per-Call)

对应 1.1 AI通话分析:通话摘要(AI 摘要、followupneeded、followupreasons)· 关键信息(主分类、子分类、次要话题、通话结果分类、是否获取信用卡、营收优先级)· 通话详情(接听结果、通话方向、通话时长等)

⚠️ 与 2.7 一样,不存入 PhoneBook。这些是 call-analysis 表中每通电话的 AI 分析字段,存储在 call-analysis DynamoDB + S3。用户在 Timeline(ActivityLog)中点击某通电话,通过 reftelephonySessionId)查询 call-analysis 获取完整分析数据并展示。

2.9 AI 跨通话分析(Cross-Call)

对应 1.1 AI跨通话分析:客户摘要(customerSummary)、是否需要跟进(actionNeeded,跨通话综合判断)、建议动作、建议截止时间、建议优先级

⚠️ 与 2.7/2.8 不同:2.9 字段存入 PhoneBook。这是 Layer 2(Daily Batch)读取该客户所有通话的 2.8 分析数据后,跨通话聚合生成的客户级别判断。

# 字段 字段名 类型 存入 PhoneBook 说明
1 客户摘要 customerSummary String 综合该客户所有通话和 SMS 生成的整体画像摘要,如 "Prospective client interested in Tread 50, visited once, price-sensitive, prefers morning slots. Follow-up twice but no booking yet."
2 是否需要跟进 actionNeeded Boolean 跨通话综合判断。区别于 2.8 的 follow_up_needed(单通电话级别):即使最近一通电话说 "no",但综合历史通话模式仍可能判定为 "yes"
3 建议动作列表 suggestedActions List<{action, reason, priority, priorityReason}> AI 建议的下一步操作列表,每个元素包含 action、reason、priority、priorityReason
4 建议截止时间 suggestedFollowUpBy ISO 8601 DateTime AI 建议的跟进最晚时间,系统用此判定任务 Upcoming / Due / Overdue。详见 触发规则 §4.1

数据源分析

四个字段当前都没有数据源,均为 PhoneBook 新字段。

写入方式:Layer 2 Daily Batch AI 写入。每日批量读取该客户在 call-analysis 中的所有通话记录(2.8 字段)+ MessageStore 中的 SMS 记录,综合分析后写入 PhoneBook。员工可手动覆盖。

与 2.5/2.6 的关系:2.5(联系偏好)、2.6(健身画像)也是 Layer 2 写入的 PhoneBook 字段,但它们提取的是具体的结构化数据(偏好时段、健身目标等)。2.9 产出的是高层判断:这个客户整体情况如何(customerSummary)、是否需要行动(actionNeeded)、具体做什么(suggestedActions,每个 action 内含 priority)、最晚什么时候做(suggestedFollowUpBy)。

2.10 Lead 跟进(Lead 专属)

对应 1.2 Lead 跟进:leadStatus、temperature

⚠️ 仅在 lifecycleStage = Lead 时适用,同时存入 PhoneBook + LeadTracking-v2

# 字段 是否已有数据源 数据源 字段名 类型 存入 PhoneBook 说明
1 Lead 状态 leadStatus String 枚举(12 选 1):new / attempted / connected / booked / showed / trialed / converted / unreachable / lost_contact / neglected / bad_timing / not_interested。完整定义见 Lead Funnel 与 Status 汇总
2 Lead 温度 temperature String 枚举(4 选 1):hot / warm / cold / unscored。基于时间衰减 + 互动事件自动计算,员工可手动覆盖。完整规则见 Lead Temperature

写入方式

字段 写入方式
leadStatus 系统自动流转(通话管道 + AI 识别)+ 员工手动覆盖。前 4 步(new→attempted→connected→booked)由 Lead-Outcome-Mapper 自动推进;终态由温度冷却触发或 AI 识别+员工确认
temperature 系统自动计算(时间衰减 + 互动升温)+ 员工手动覆盖(最高优先级)
temperature 含义 响应窗口
hot 高意向 / 刚互动(Day 0–1) 当天
warm 有意向但不紧急(Day 2–5) 2–3 天内
cold 跟进窗口已过(Day 5+) 停止主动跟进,等待升温事件
unscored 数据不足,无法评分 按来源排序

关于 DuplicateInvalid Number:不属于 leadStatus——它们是数据质量判定,与跟进状态是两个独立维度。应在 LeadTracking-v2 中以独立字段标记(如 isDuplicateisValidNumber),不写入 PhoneBook,用于计算有效率等指标。

2.11 Lead 分析(Lead 专属)

对应 1.2 Lead 分析:意向等级、提交次数

⚠️ 仅在 lifecycleStage = Lead 时适用,同时存入 PhoneBook + LeadTracking-v2

# 字段 是否已有数据源 数据源 字段名 类型 存入 PhoneBook 说明
1 意向等级 purchaseIntent String 枚举:high / medium / low。AI 综合通话内容判断客户购买意向强度
2 提交次数 submissionCount Number 同一手机号提交 Lead 表单的次数,反映客户兴趣强度。由 Lead 入库管道计算并写入

写入方式

字段 AI 推导逻辑 数据来源
purchaseIntent 从对话中识别购买信号强度:主动询价/预约 = high,犹豫/收集信息 = medium,明确拒绝/兴趣极低 = low call-analysis(transcript、executive_summary)+ MessageStore
submissionCount 统计 LeadTracking-v2 中同一 phone 的记录数 LeadTracking-v2(COUNT by phone)

关于 submissionCount:LeadTracking-v2 中没有现成的提交次数字段,但同一手机号确实存在多条记录(5,078 条记录中有 678 个手机号重复提交,最多达 11 次)。Lead 入库管道在写入时统计同一 phone 的记录数,写入 LeadTracking-v2,同步更新 PhoneBook。

2.12 消费决策(Lead 专属)

对应 1.2 消费决策:预算区间、价格敏感度、决策风格、决策周期

⚠️ 仅在 lifecycleStage = Lead 时适用,同时存入 PhoneBook + LeadTracking-v2

# 字段 是否已有数据源 数据源 字段名 类型 存入 PhoneBook 说明
1 预算区间 budgetRange String 客户表述的可接受价格范围,如 "$50-100/month"、"under $200"
2 价格敏感度 priceSensitivity String 枚举:high / medium / low。AI 从对话中判断客户对价格的关注程度
3 决策风格 decisionProcess String 如 "需要和家人商量"、"当场决定型"、"需要多次沟通"
4 决策周期 decisionTimeline String 客户表述的预期决策时间,如 "this week"、"next month"、"not sure"

写入方式:Layer 2 Daily Batch AI 写入。AI 从通话 transcript + SMS 中提取消费决策信号,结构化后写入 PhoneBook。员工可手动补充或覆盖。

字段 AI 提取逻辑 数据来源
budgetRange 识别客户提到的价格/预算相关表述 call-analysis(transcript)+ MessageStore
priceSensitivity 分析客户对价格的反应强度和频率 call-analysis(transcript、executive_summary)
decisionProcess 识别客户的决策模式描述 call-analysis(transcript)
decisionTimeline 识别客户表述的时间预期 call-analysis(transcript)+ MessageStore

2.13 决策障碍(Lead 专属)

对应 1.2 决策障碍:objections

⚠️ 仅在 lifecycleStage = Lead 时适用,同时存入 PhoneBook + LeadTracking-v2

# 字段 是否已有数据源 数据源 字段名 类型 存入 PhoneBook 说明
1 决策障碍 objections String Set 客户犹豫中的顾虑标签,如 {"price concerns", "schedule conflicts", "need to discuss with family"}

写入方式:员工手动输入 或 AI 从通话中自动提取。

2.14 条件性拒绝原因(Lead 专属)

对应 1.2 条件性拒绝:rejectionReasons

⚠️ 仅在 lifecycleStage = Lead 时适用,同时存入 PhoneBook + LeadTracking-v2

# 字段 是否已有数据源 数据源 字段名 类型 存入 PhoneBook 说明
1 拒绝原因 rejectionReasons String Set 客户已明确拒绝的原因标签,如 {"too far", "already has membership", "moving away"}

写入方式:AI 从通话中识别明确拒绝信号后写入,员工确认或手动标记。

objections vs rejectionReasons 的区别

  • objections:客户还在犹豫,有挽回空间("太贵了" → 可以介绍优惠方案)
  • rejectionReasons:客户已明确拒绝,挽回可能性低("太远了" → 无法改变地理位置)

rejectionReasons 仅在 leadStatus = bad_timing 时适用——客户因具体条件拒绝(太远、时间冲突、已有会籍等),条件可能变化。not_interested 是无条件拒绝,不记录具体原因。


三、PhoneBook 最终表设计

主表 (PhoneBook-{env})

跳过 2.7(通讯记录)和 2.8(AI 通话分析)——它们不存入 PhoneBook,通过 ActivityLog 索引表查询。email 不存入 PhoneBook,查询时从 LeadTracking-v2 读取;邮箱反查客户使用辅助表 PhoneBook-EmailMapping

# 字段 类型 说明 来源 详见
1 phone String (PK) E.164 格式,全局唯一客户标识 自动
2 orgId String 所属组织 ID 自动
3 siteId String 所属门店 自动
4 firstName String Lead 入库管道;员工可覆盖 2.1
5 lastName String Lead 入库管道;员工可覆盖 2.1
6 gender String 性别 V1 预留 2.1
7 address String 地址 V1 预留 2.1
8 occupation String 工作 V1 预留 2.1
9 birthday String 生日 V1 预留 2.1
10 dailyRoutine String 作息模式 V1 预留 2.1
11 lifecycleStage String lead / member / churned / unknown 系统自动判定 + 员工覆盖 2.2
12 lifecycleState String active / frozen / terminal 从 leadStatus 推导(Lead 阶段) 2.2
13 owner String 负责跟进的员工姓名 员工手动 / 系统轮转 2.3
14 notes String 员工手写备注 员工手动 2.3
15 tags String Set 自定义标签,用于分组筛选 员工手动 2.3
16 doNotContact Boolean DNC 标记,全渠道停止触达 AI 识别 + 员工手动 2.3
17 source String 来源渠道(Facebook / Instagram / Google 等) 创建时写入,不覆盖 2.4
18 acquiredAt String (ISO) 客户首次进入系统的时间 Lead 入库管道 2.4
19 firstAttemptedAt String (ISO) 首次尝试联系时间(不论是否接通) 通话管道首次写入 2.4
20 firstConnectedAt String (ISO) 首次真正接通时间 通话管道首次写入 2.4
21 callCount Number 通话总次数 通话管道 ADD +1 2.4
22 smsCount Number 短信总条数 SMS 管道 ADD +1 2.4
23 lastActivityAt String (ISO) 最后活动时间(任何互动都更新) 通话/Lead/SMS 管道 2.4
24 reachability String 联系响应模式 Layer 2 AI;员工可覆盖 2.5
25 bestTimeToReach String 最佳联系时段 Layer 2 AI;员工可覆盖 2.5
26 preferredChannel String call / sms / either Layer 2 AI;员工可覆盖 2.5
27 fitnessGoal String 核心需求(减重、增肌等) Layer 2 AI;员工可覆盖 2.6
28 classInterests String Set 感兴趣的课程类型 Layer 2 AI;员工可覆盖 2.6
29 preferredTime String 偏好上课时段 Layer 2 AI;员工可覆盖 2.6
30 fitnessExperience String 过往健身经历 Layer 2 AI;员工可覆盖 2.6
31 exerciseHabits String 当前运动习惯 Layer 2 AI;员工可覆盖 2.6
32 fitnessConcerns String Set 关注点/顾虑 Layer 2 AI;员工可覆盖 2.6
33 healthConditions String Set 身体限制/健康状况 Layer 2 AI;员工手动优先 2.6
34 customerSummary String 综合所有通话和 SMS 的整体画像摘要 Layer 2 AI 2.9
35 actionNeeded Boolean 跨通话综合判断是否需要跟进 Layer 2 AI 2.9
36 suggestedActions List<{action, reason, priority, priorityReason}> AI 建议的下一步操作列表,每个元素包含 action、reason、priority、priorityReason Layer 2 AI 2.9
37 suggestedFollowUpBy String (ISO) AI 建议的跟进最晚时间 Layer 2 AI 2.9
38 leadStatus String 12 选 1:new / attempted / connected / booked / showed / trialed / converted / unreachable / lostcontact / neglected / badtiming / not_interested 系统自动 + 员工覆盖;双写 LeadTracking-v2 2.10
39 temperature String hot / warm / cold / unscored 时间衰减 + 互动升温;双写 LeadTracking-v2 2.10
40 purchaseIntent String high / medium / low Layer 2 AI;双写 LeadTracking-v2 2.11
41 submissionCount Number 同一手机号提交 Lead 表单的次数 Lead 入库管道;双写 LeadTracking-v2 2.11
42 budgetRange String 可接受价格范围 Layer 2 AI;双写 LeadTracking-v2 2.12
43 priceSensitivity String high / medium / low Layer 2 AI;双写 LeadTracking-v2 2.12
44 decisionProcess String 决策风格(需要和家人商量、当场决定型等) Layer 2 AI;双写 LeadTracking-v2 2.12
45 decisionTimeline String 预期决策时间 Layer 2 AI;双写 LeadTracking-v2 2.12
46 objections String Set 犹豫中的顾虑标签 员工手动 / AI 提取;双写 LeadTracking-v2 2.13
47 rejectionReasons String Set 明确拒绝的原因标签 AI 识别 + 员工确认;双写 LeadTracking-v2 2.14

共 47 个字段(系统 3 + 身份 7 + 生命周期 2 + 运营 4 + 活动 7 + 联系偏好 3 + 健身画像 7 + AI 跨通话 4 + Lead 跟进 2 + Lead 分析 2 + 消费决策 4 + 决策障碍 1 + 条件性拒绝 1)

GSI 索引

索引名 PK SK 用途
orgId-temperature-index orgId temperature 按组织筛选温度
siteId-temperature-index siteId temperature 按门店 + 温度筛选
orgId-lifecycleStage-index orgId lifecycleStage 按类型筛选(Lead / Member / Unknown)
orgId-lastActivityAt-index orgId lastActivityAt 按组织查客户,最近活跃排前
siteId-lastActivityAt-index siteId lastActivityAt 按门店查客户,最近活跃排前

共 5 个 GSI

辅助表

PK 字段 用途
PhoneBook-EmailMapping-{env} email email, phone 邮箱反查客户(email 不存入 PhoneBook 主表)
PhoneBook-Alias-{env} aliasPhone aliasPhone, primaryPhone 旧号码映射到主号码
ActivityLog-{env} phone + timestamp#eventId 见 2.7 统一 Timeline 索引表 已废弃,迁移 PostgreSQL 后用 UNION ALL VIEW 替代

独立表(非 PhoneBook 字段,但 Contacts 页面依赖)

用途 详见
ActivityLog-{env} 统一 Timeline 索引 已废弃,迁移 PostgreSQL 后用 contact_timeline VIEW 替代 2.7
call-analysis-{env} 通话原始数据 + Per-Call AI 分析结果 2.7 / 2.8
MessageStore-{env} SMS 原始数据(待建) 2.7
LeadTracking-v2-{env} Lead 表单提交数据,与 PhoneBook Lead 字段双向同步 2.10–2.14

四、不存入 PhoneBook 的展示数据

以下数据在 Contacts 页面中展示,但不存入 PhoneBook 表,由 API 从其他表实时获取:

展示内容 查询来源 查询方式
Email LeadTracking-v2 leadContactEmail
Lead 提交类型 (leadType) LeadTracking-v2 leadType(Web Lead / Online Intro)
Communication Timeline ActivityLog → Neon contact_timeline VIEW UNION ALL 跨 calls / sms_messages / leads 表,ORDER BY created_at DESC LIMIT 50
Per-Call AI 分析(摘要、分类、跟进等) call-analysis(迁移后 Neon calls 表) 通过 telephonySessionId 查询
Transcript(逐句对话记录) S3 JSON 通过 call-analysis s3AnalysisPath 获取
SMS 完整内容 MessageStore(迁移后 Neon sms_messages 表) 通过 messageId 查询
通话录音(音频回放) S3 音频 通过 call-analysis recordingUrl 获取

五、写入管道

# 管道 触发时机 写入 PhoneBook 字段 同步写入
1 通话管道 每通电话处理完成 callCount++, lastActivityAt, firstAttemptedAt(首次), firstConnectedAt(首次接通) ActivityLog 不再需要,PostgreSQL 直接查 calls
2 Lead 入库管道 每条新 Lead 写入 firstName, lastName, acquiredAt(首次), submissionCount, lastActivityAt ActivityLog 不再需要,PostgreSQL 直接查 leads
3 SMS 管道 每条短信处理完成 smsCount++, lastActivityAt ActivityLog 不再需要,PostgreSQL 直接查 sms_messages
4 Lead 状态管道 leadStatus 变更时 leadStatus, lifecycleStage, lifecycleState LeadTracking-v2
5 Layer 2 Daily Batch 每天凌晨 AI 批处理 customerSummary, actionNeeded, suggestedActions, suggestedFollowUpBy, reachability, bestTimeToReach, preferredChannel, 2.6 健身画像 7 字段, purchaseIntent, 2.12 消费决策 4 字段, objections, rejectionReasons LeadTracking-v2(Lead 字段)
6 Layer 3 On-Demand 员工点 Refresh AI customerSummary(刷新)
7 员工手动操作 员工在 UI 中编辑 owner, notes, tags, doNotContact, temperature, + 任何 AI 字段可覆盖 ActivityLog 不再需要,PostgreSQL system_events 表记录变更审计

管道设计原则:

  1. 写入轻量化:管道 1-3 只写计数器和时间戳(原子 ADD + SET),单次写入成本极低
  2. 数据一致性:PhoneBook 不冗余存储明细数据(call 详情、SMS 内容),避免与源表不一致
  3. AI 管道集中:Layer 2 一次性写入所有 AI 提取字段(联系偏好 + 健身画像 + 跨通话分析 + Lead 分析 + 消费决策 + 决策障碍/拒绝),减少写入次数
  4. 双写同步:Lead 专属字段(2.10–2.14)同时写入 PhoneBook + LeadTracking-v2,保证两张表数据一致

六、Contacts 页面结构

Contacts 页面由三个核心区域组成,通过两种视图模式切换布局:

6.1 三大区域

区域 功能 核心交互
名单列表 Contact List 以表格形式展示所有联系人,支持排序、筛选、搜索 点击行 → 选中联系人,右侧面板同步更新
用户详情 Contact Detail 展示选中联系人的身份信息、跟进状态、AI 分析结果 查看/编辑联系人属性,快速了解客户全貌
通讯记录 Communication Log 按时间线展示该联系人的所有沟通事件(SMS、通话、语音信箱、系统备注) 浏览历史互动,展开通话详情

6.2 两种视图模式

列表模式(默认)                          详情模式(点击展开)
┌──────────────────┬──────────┐      ┌──────────┬──────────────────┐
│                  │ 用户详情  │      │ 用户详情  │                   │
│   名单列表        │          │      │          │   通讯记录         │
│  (Contact List)  ├──────────┤  →   │ (Detail  │ (Communication   │
│                  │ 通讯记录  │      │  Panel)  │      Log)        │
│                  │          │      │          │                  │
└──────────────────┴──────────┘      └──────────┴──────────────────┘
  • 列表模式:左侧为名单表格(主区域),右侧侧边栏上下排列用户详情和通讯记录
  • 详情模式:左侧为用户详情面板(完整展示),右侧为通讯记录(全屏展开),名单列表隐藏

6.3 通讯记录 Communication Log 详细结构

按日期分组的时间线,每条事件根据类型有不同的展示样式:

6.3.1 事件类型

类型 样式 内容
SMS 💬 SMS 人名 + 时间 + SMS 内容
Call 📞 Call 人名 + 时间 + AI 摘要 + 音频播放器
Voicemail 📞 Voicemail 人名 + 时间 + 语音文本 + 语音信箱播放器
System Note 🕐 System Note 人名 + 时间 + 系统事件描述(如 "Lead received from website contact form")

通讯记录卡片左右位置规则:

  • 左侧:客户发起的信息(客户来电、客户发送的SMS、 客户的Voicemail)
  • 右侧:系统/门店发起的信息(门店外呼、门店发送的SMS、门店的Voicemail、System Note)

6.3.2 通话卡片(Call Card)

通话卡片默认展示以下信息:

区块 内容
头部 员工名 + 时间 + 通话类型标签(Call)
AI 摘要 本次通话的 executive_summary(如 "Called prospect. No answer. Left voicemail with intro class times and $12 offer.")
音频播放器 通话录音回放,显示时长进度
展开按钮 Hide/Show Details,点击可展开下方详细信息

6.3.3 通话展开详情(Hide/Show Details)

点击通话卡片的展开按钮后,按 AI 分析结论 → 通话元数据 → 原始对话 的顺序展示:

1. Key Information(AI 分析结论)

字段 说明
Category 主分类(Sales、Revenue Impacting 等)
Subcategory 子分类(Intro Outreach、Intro Booking 等)
Other Category 次要话题
Revenue Priority 营收优先级(low / medium / high)
Outcome 通话结果分类(no_answer、attempted 等)
Credit Card 是否获取信用卡

2. Call Details(通话元数据)

字段 说明
Call Result 接听结果(No Answer、Call Connected 等)
Direction 通话方向(Outbound / Inbound)
Duration 通话时长
Customer Phone 客户电话
Caller Name 来电方名称(门店名)
Date/Time 通话时间
Staff Member 接听/拨打员工
Call State 通话状态(voicemail / human_conversation)
Customer Type 客户类型(newlead / prospectiveclient 等)

3. Transcript(原始对话)

Conversation Data:逐句对话记录,分 Speaker 标注 + 时间戳,Speaker 1(系统/客户)和 Speaker 2(员工)交替展示

6.4 信息展示分布

基于「一、客户信息分析」的分类,将每类信息分配到三个区域:

信息类别 名单列表 Contact List 用户详情 Contact Detail 通讯记录 Comm Log
身份信息 姓名、电话、邮箱、性别、年龄 全部(姓名、电话、邮箱、性别、地址、工作、生日/年龄、作息模式)
生命周期 stage stage + state
运营信息 分配给谁、备注(截断预览)、DNC 全部(分配、备注完整、标签、DNC)
活动数据 获取时间、首次尝试联系时间、首次触达时间、通话/短信次数、最后活动时间 全部(来源渠道、获取时间、首次尝试联系时间、首次触达时间、通话/短信次数、最后活动时间)
联系偏好 联系响应模式、最佳联系时段、偏好联系渠道
健身画像 核心需求、感兴趣的课程类型、偏好时段、健身经验(含过往经历)、当前运动习惯、关注点、健康状况
通讯记录 时间线事件卡片(System Note / SMS / Call / Voicemail)
AI通话分析 通话卡片:AI 摘要 + 音频播放器;展开详情:Key Information + Call Details + Transcript
AI跨通话分析 是否需要跟进 客户摘要、是否需要跟进、建议动作
Lead 专属 leadStatus、temperature 全部(leadStatus、temperature、意向等级、提交次数、消费决策、决策障碍、条件性拒绝)
Member 专属 待定 待定
Churned 专属 待定 待定

设计逻辑:

  • 名单列表:只放可排序/可筛选的客户级别关键列,用于快速扫描和批量操作
  • 用户详情:完整的客户画像,是名单列表的超集;列表模式下摘要展示,详情模式下完全展开
  • 通讯记录:按日期分组的时间线,展示四种事件类型(System Note / SMS / Call / Voicemail);点击通话卡片弹出详情弹窗