Files
nocobase-mcp/docs/superpowers/specs/2026-07-24-team-crm-query-design.md
T

409 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 团队 CRM 查询与项目追踪设计
## 目标
在保持现有只读 CRM MCP 和受控项目写入兼容的前提下,增加:
- 基于 CRM 正式团队关系的查询;
- 团队与成员双层客户、跟进和项目统计;
- 长期未跟进客户查询,并明确标注当前 NocoBase 不支持的闭环能力;
- 客户归属、实际记录人、参与人员等角色的明确区分;
- CRM 项目完整跟进时间线;
- 北京时间、完整分页、稳定 JSON 解析和数据质量提示。
本设计以 2026-07-24 从目标 NocoBase 读取的集合和字段元数据为依据。元数据盘点未读取或修改业务记录。
## 已确认的数据模型
### 团队与用户
团队集合为 `t_team_management`(团队管理)。
| 业务含义 | 字段 | 类型 | 目标 |
| --- | --- | --- | --- |
| 团队名 | `f_team_name` | string | - |
| 团队负责人 | `tdgl_manager` | belongsToMany | `users` |
| 团队成员 | `tdgl_team_members` | belongsToMany | `users` |
`users` 中存在反向关系:
- `yh_belong_teams`:所属团队;
- `yh_managed_team`:管理的团队;
- `yh_status`:员工状态。
员工状态中已确认:
| 标签 | 内部值 |
| --- | --- |
| 正式员工 | `nkluuumb1r1` |
| 实习生 | `n7cnn29kzo1` |
| 已离职 | `bpsfm63uc8i` |
| 交接中 | `yv6pkhjxtfz` |
| 临时员工 | `4g6m1y5uy1s` |
“正式团队成员”定义为:
1. 用户出现在团队的 `tdgl_team_members` 关系中;
2. 用户的 `yh_status` 等于 `nkluuumb1r1`。
负责人可以有多人,不应在 MCP 中强制压缩为单个负责人。
系统另有 `departments` 树形部门集合。部门和 CRM 团队是两套不同关系,首版团队查询以 `t_team_management` 为准,不用部门关系替代团队关系。
### 客户角色
客户集合为 `t_nt3pjadelqi`。
| 字段 | 标题 | 建议语义 |
| --- | --- | --- |
| `kehu_manage_person` | 管理人 | 管理或权限相关人员,不代表客户归属 |
| `kehu_followup_person` | 跟进人 | 客户归属人员 |
| `kehu_lookup_people` | 可查看人 | ACL 可见人员,不代表业务协同 |
| `createdBy` | 创建人 | 数据创建者,不代表客户负责人 |
上述前三个字段均可能包含多人。客户归属以 `kehu_followup_person` 为准。MCP 不应将
`kehu_manage_person` 或 `kehu_lookup_people` 计为客户归属或协同贡献,也不应把
`createdBy` 当作客户负责人。
由于 `kehu_followup_person` 是多值关系,接口使用复数 `customer_owners`,不能从列表
顺序推断唯一主负责人。
### 跟进角色与分类
跟进集合为 `t_07667a5evtr`。
| 字段 | 标题 | 建议语义 |
| --- | --- | --- |
| `createdBy` | 创建人 | 跟进记录提交人 |
| `gjjl_followup_person` | 参与跟进人员 | 明确的参与人员 |
| `gjjl_client` | 客户 | 关联客户 |
| `gjjl_client_contacts` | 客户联系人 | 关联联系人 |
| `f_gjjl_projects` | 相关项目 | 关联 CRM 项目 |
| `f_srysmjkwfq1` | 跟进时间 | 业务发生时间 |
| `gjjl_followup_type` | 跟进类型 | 沟通方式 |
| `f_19iplxz0nds` | 跟进内容 | 跟进正文 |
| `f_hskl7gjvos9` | 状态 | 记录状态 |
已确认的跟进方式:
- 邮件
- 电话
- 视频会议
- 拜访/请客
- 审厂/来访
- 论坛/大会
- 代理跟进情况代填
已确认的跟进状态为“审批中、OK、迟交、无效”。它更接近记录审批或提交质量状态,不能直接解释为下一步事项的完成状态。
首版角色输出必须同时保留:
- `record_creator`:`createdBy`,只表示记录提交人;
- `participants`:`gjjl_followup_person`;
- `customer_owners`:关联客户的 `kehu_followup_person`;
- `customer_management_users`:关联客户的 `kehu_manage_person`,仅作为补充信息;
- `team_managers`:命中团队的 `tdgl_manager`。
`createdBy` 不一定是实际跟进人,因此不得用于实际跟进贡献统计。实际跟进贡献只按
`gjjl_followup_person` 统计;多人参与时每位参与人各获得一次参与贡献,同时团队总跟进
记录按记录 ID 去重。`record_creator` 仅用于审计和数据质量检查。
### CRM 项目
CRM 项目集合为 `t_projects`,与现有 MCP 项目写入使用同一集合。
已确认关系:
- 客户:`f_projects_client` / 外键 `client_ID`;
- 联系人:`f_projects_contacts`;
- 跟进记录:`f_projects_followup_records`;
- 项目进展:`f_projects_progress`;
- 项目情况更新:`f_u28gm9h2uzl`;
- 附件:`f_projects_attachments`。
项目进展为:
- 询价阶段
- 已报价
- 送样
- 已定点
- SOP
- 终止
项目情况更新集合为 `t_qxeepjvi39s`,包含:
- 项目:`f_k37rbpi4vye`;
- 更新日期:`f_6g9fw5oqef9`;
- 更新内容:`f_ei16g0ihwwd`;
- 附件:`f_6pk5pv17i27`;
- 创建人:`createdBy`。
当前没有独立的报价、样品、测试或定点事件集合映射。首版只能使用项目阶段和项目情况更新正文展示这些信息,不能可靠统计每类业务事件的数量或状态。
### 另一套项目管理模型
系统还存在:
- `market_pm`(项目管理);
- `project_updates`(项目节点)。
这套模型有项目负责人、预计完成时间、项目状态,以及节点负责人、节点状态和节点预计完成时间,但没有已确认的客户关系,也没有与 `t_projects` 的关联字段。
因此:
- `t_projects` 是 CRM 项目查询的权威来源;
- `market_pm` / `project_updates` 作为独立的任务型项目模型;
- 在没有稳定关联键之前,两套项目不得按名称自动合并;
- 如后续需要统一展示,返回值必须带 `project_source`,例如 `crm` 或 `management`。
## 当前数据模型缺口
跟进记录中没有已确认的以下结构化字段:
- 下一步事项;
- 事项责任人;
- 截止日期;
- 完成状态;
- 完成时间;
- 优先级;
- 风险类型。
因此“逾期未完成事项”和“无下一步的重点项目”不能仅凭现有跟进记录准确计算。
本项目不得修改 NocoBase 数据模型,因此不新增行动项集合,也不增加跟进字段。以下能力
明确跳过:
- 精确查询逾期未完成事项;
- 按行动项完成状态统计;
- 权威判断跟进是否存在下一步;
- 权威判断下一步责任人和截止日期。
不从跟进正文推断权威的下一步、风险或逾期状态。
报价、样品、测试等完整链路同样需要结构化事件模型。项目阶段只能表示当前状态,不能还原每次状态变化的时间和责任人。
## 配置扩展
建议在 `config.json` 增加以下可配置映射,默认值采用本次确认字段:
```json
{
"timezone": "Asia/Shanghai",
"teams": {
"resource": "t_team_management",
"idField": "id",
"nameField": "f_team_name",
"managerField": "tdgl_manager",
"memberField": "tdgl_team_members",
"userStatusField": "yh_status",
"formalUserStatusValue": "nkluuumb1r1"
},
"roles": {
"customerOwnerField": "kehu_followup_person",
"customerManagementField": "kehu_manage_person",
"customerViewerField": "kehu_lookup_people",
"followupCreatorField": "createdBy",
"followupParticipantField": "gjjl_followup_person"
},
"crmProjects": {
"contactField": "f_projects_contacts",
"followupField": "f_projects_followup_records",
"updateField": "f_u28gm9h2uzl",
"updateResource": "t_qxeepjvi39s",
"updateProjectField": "f_k37rbpi4vye",
"updateDateField": "f_6g9fw5oqef9",
"updateContentField": "f_ei16g0ihwwd"
}
}
```
不设计或预留会写入 NocoBase 的闭环字段。相关能力在 MCP capability 中明确标为不可用。
## MCP 工具设计
### 团队发现
```text
list_teams(query?, include_members=false, formal_members_only=true)
resolve_team(query)
get_team(team_id, include_members=true, formal_members_only=true)
```
团队解析规则与负责人解析一致:无匹配或多匹配返回结构化候选结果,不静默选择。
### 查询工具兼容扩展
现有工具保留原参数,并增加:
```text
list_customers(..., team?, team_id?)
list_followups(..., team?, team_id?, project_id?, followup_type?, record_status?)
crm_overview(..., team?, team_id?)
```
`team` 和 `team_id` 不得同时提供。团队过滤使用正式成员 ID 集合,客户和跟进分别应用对应角色关系,不能把“团队客户”和“团队实际跟进”混成同一口径。
### 团队统计
```text
team_crm_overview(
team,
date_from?,
date_to?,
formal_members_only=true,
include_member_breakdown=true
)
```
建议返回:
```json
{
"team": {},
"period": {},
"totals": {
"assigned_customers": 0,
"owned_customers": 0,
"followup_records": 0,
"active_customers": 0,
"active_projects": 0
},
"by_member": [],
"by_customer": [],
"by_followup_type": [],
"by_project_stage": [],
"contribution_basis": {
"participant": "gjjl_followup_person"
}
}
```
同一条多人参与的跟进:
- 团队总量只计一次;
- 成员贡献中每位参与人各计一次;
- 返回 `unique_followups` 和 `participation_count`,防止将两种口径混淆。
### 项目追溯
```text
get_project(project_id, include_contacts=true, include_followups=true)
get_project_timeline(project_id, date_from?, date_to?)
list_projects(customer_id?, team?, stage?, updated_since?)
```
时间线事件来源:
- 项目创建与阶段;
- 项目情况更新;
- 关联跟进记录;
- 联系人;
- 附件元数据。
每个事件返回 `event_type`、`occurred_at`、`actors`、`source_resource` 和 `source_id`。
### 长期未跟进客户
现有模型可以支持:
```text
list_stale_customers(team?, owner?, inactive_days=30, as_of?)
```
该工具仅依据客户最后一次有效跟进时间计算。以下工具不实现:
- `list_action_items`
- `list_overdue_action_items`
不得以跟进记录的“迟交”状态代替行动项逾期状态。
## 时间、分页与统计规则
### 北京时间
- 服务内部使用带时区的 `datetime`;
- NocoBase UTC 时间转换到 `Asia/Shanghai`;
- `dateOnly` 保持日期不做时区偏移;
- 输出统一为 ISO 8601,例如 `2026-07-24T15:30:00+08:00`;
- 响应增加 `"timezone": "Asia/Shanghai"`。
### 分页
保持现有 `limit`、`offset` 参数兼容,但修复任意 offset:
- 不再直接用 `offset // limit + 1` 近似;
- 读取覆盖目标窗口的底层页并在服务层精确切片;
- 返回 `limit`、`offset`、`total`、`has_more`、`next_offset`;
- 内部全量统计循环读取所有页;
- 设置独立的最大扫描记录数和超时保护,超过时返回明确的截断警告。
### 聚合
- 团队总量按记录 ID 去重;
- 成员贡献保留参与次数;
- 所有聚合返回统计口径;
- “无效”跟进不计入有效贡献;“审批中、OK、迟交”保留并分别展示;
- 不再使用固定 50 个分组作为完整统计结果。
## JSON 与元数据稳定性
`nb` 输出解析需要支持 stdout 混入非 JSON 日志的情况:
1. 继续设置 `NB_CLI_LOG_DISABLED=1` 和 `NB_SKIP_STARTUP_UPDATE=1`;
2. 首先尝试对完整 stdout 执行 `json.loads`;
3. 失败时使用 `json.JSONDecoder.raw_decode` 定位完整顶层 JSON 对象;
4. 仅接受唯一、完整的 JSON 对象;
5. 其余文本作为已脱敏诊断信息,不进入正常 MCP 数据;
6. 无法可靠定位时返回 `nb_invalid_json`,不返回部分业务数据;
7. API Token 必须同时从命令、stdout 和 stderr 中脱敏。
## 数据质量提示
查询响应增加统一的 `data_quality_warnings`,包括:
- 客户有多个归属跟进人;
- 跟进没有参与人员,无法归属实际贡献;
- 跟进没有客户或项目;
- 项目更新没有业务日期;
- 项目阶段有变化但没有结构化事件记录;
- 团队成员不是正式员工;
- 统计因扫描上限被截断。
## 兼容与实施顺序
### 第一阶段:基础稳定性
- 北京时间转换;
- 精确分页和全量聚合;
- JSON 日志混入容错;
- 统一响应元数据和测试。
### 第二阶段:团队查询
- 团队配置、解析和成员发现;
- 客户与跟进增加团队过滤;
- 分离客户归属跟进人、管理人、记录创建人和参与人员;
- 团队整体与成员贡献统计。
### 第三阶段:CRM 项目时间线
- CRM 项目只读查询;
- 关联客户、联系人、跟进和项目情况更新;
- 长期未跟进客户查询。
现有工具名、参数和默认紧凑输出保持兼容。新字段只做增量添加;团队和项目查询工具为新工具。现有 stdio 模式继续只读,HTTP 写入范围仍只限当前项目字段和附件操作。
## 已确认业务决策
1. 客户归属以 `kehu_followup_person`(跟进人)为准。
2. `createdBy` 不一定是实际跟进人,只作为记录提交人展示。
3. 不修改 NocoBase 数据模型;现有模型不支持的闭环能力直接跳过。
## 实施时采用的默认口径
1. 实际跟进贡献按 `gjjl_followup_person`(参与跟进人员)统计。
2. 正式成员只包含 `yh_status = nkluuumb1r1`,排除实习、离职、交接中和临时员工。
3. `t_projects` 作为 CRM 项目权威表;不与 `market_pm` 按名称自动合并。
4. 团队统计默认排除“无效”跟进;“审批中、OK、迟交”保留并分别展示。
5. 长期未跟进默认阈值为 30 天,允许调用方覆盖。