# https://github.com/sree-sanak/minty 项目说明书

生成时间：2026-05-11 23:57:10 UTC

## 目录

- [项目介绍](#page-introduction)
- [快速开始](#page-quick-start)
- [项目文件结构](#page-file-structure)
- [架构总览](#page-architecture-overview)
- [AI 后端配置](#page-ai-backend)
- [数据源导入](#page-data-sources)
- [联系人合并与去重](#page-contact-merging)
- [数据存储结构](#page-data-storage)
- [MCP 代理集成](#page-mcp-integration)
- [网络查询系统](#page-network-query)

<a id='page-introduction'></a>

## 项目介绍

### 相关页面

相关主题：[快速开始](#page-quick-start), [架构总览](#page-architecture-overview)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/sree-sanak/minty/blob/main/README.md)
- [ARCHITECTURE.md](https://github.com/sree-sanak/minty/blob/main/ARCHITECTURE.md)
- [CHANGELOG.md](https://github.com/sree-sanak/minty/blob/main/CHANGELOG.md)
- [RELEASING.md](https://github.com/sree-sanak/minty/blob/main/RELEASING.md)
- [hermes/minty-network-memory/SKILL.md](https://github.com/sree-sanak/minty/blob/main/hermes/minty-network-memory/SKILL.md)
</details>

# 项目介绍

## 概述

Minty 是一个本地优先的人脉网络记忆系统，旨在帮助用户从多个通讯渠道（WhatsApp、Telegram、邮件、日历、LinkedIn 等）汇总联系人信息，构建统一的人脉知识图谱，并通过 AI 驱动的自然语言查询能力实现"记住所有人"的愿景。

该系统完全本地化运行，不依赖任何云端 API，采用本地 AI 模型（Ollama）或本地 Claude Code CLI 进行智能分析，确保用户数据的隐私安全。资料来源：[README.md]()

## 核心特性

| 特性 | 描述 |
|------|------|
| 多源数据整合 | 支持 WhatsApp、Telegram、Gmail、日历、LinkedIn 等多种数据源的导入与同步 |
| 本地 AI 驱动 | 使用 Ollama 或 Claude Code CLI，完全离线运行，无云端依赖 |
| 智能匹配 | 跨来源自动合并重复联系人，消除数据孤岛 |
| 自然语言查询 | 通过 MCP 协议支持自然语言的人脉搜索 |
| 关系热度追踪 | 自动计算联系人亲密度与互动频率，识别关系衰减信号 |
| 定期回顾 | 生成"失联联系人"提醒与重连建议 |

资料来源：[README.md](), [ARCHITECTURE.md]()

## 系统架构

### 整体架构

```mermaid
graph TD
    A[数据源] --> B[sources/ 导入层]
    B --> C[data/<source>/ 原始数据]
    C --> D[crm/merge.js 合并]
    D --> E[data/unified/ 统一存储]
    E --> F[AI 推理层]
    E --> G[CRM Web UI]
    E --> H[MCP Server]
    
    B1[WhatsApp] --> B
    B2[Telegram] --> B
    B3[Gmail/Email] --> B
    B4[Calendar] --> B
    B5[LinkedIn] --> B
    B6[Slack] --> B
```

### 核心模块说明

| 模块 | 文件 | 功能描述 |
|------|------|----------|
| 导入层 | `sources/*/import.js` | 各数据源的独立导入器，写入 `data/<source>/` |
| 数据合并 | `crm/merge.js` | 加载各来源数据，进行规范化、去重，写入 `data/unified/contacts.json` 和 `interactions.json` |
| 匹配算法 | `crm/match.js` | 跨来源联系人匹配逻辑，遵循 `MATCHING.md` 规范 |
| 数据模式 | `crm/schema.js` | `Contact` 和 `Interaction` 的规范数据结构定义 |
| 查询 CLI | `crm/query.js` | 命令行工具：`npm run stats`、`npm run search` |
| 自然语言查询 | `crm/network-query.js` | "Ask"视图，支持自然语言提问 |
| 重连建议 | `crm/reconnect.js` | 识别"关系衰减"联系人并生成重连草稿 |
| AI 适配器 | `crm/ai.js` | 本地 Claude Code CLI / Ollama 适配器，无云端 API |
| 数据陈旧检测 | `crm/staleness.js` | 标记陈旧联系人数据，供 UI 告警使用 |
| 同步守护进程 | `crm/sync.js` | 监视 `data/<source>/export/` 目录，自动触发导入器 |
| 高层功能 | `calendar.js`, `digest.js`, `meeting-debrief.js`, `goal-retro.js`, `life-events.js` | 基于统一存储的高级功能 |
| 工具函数 | `crm/utils.js` | 电话/邮箱/姓名规范化、评分辅助、内存联系人索引 |

资料来源：[ARCHITECTURE.md]()

### 数据模型

系统使用两个核心数据结构：

**Contact（联系人）**
- 基本信息：姓名、电话、邮箱、组织、职位
- 来源追踪：`sources` 字段记录每个来源的具体数据
- 关系评分：`relationshipScore` 基于互动频率计算
- 亲密度：`warmth` 指标反映关系深度
- 最后联系：`daysSinceContact` 计算天数

**Interaction（互动记录）**
- 时间戳与来源
- 内容摘要：`subject`、`body`
- 互动类型：会议、消息、通话等

资料来源：[crm/schema.js](), [ARCHITECTURE.md]()

## 数据源支持

### 支持的来源

| 数据源 | 状态 | 导入方式 |
|--------|------|----------|
| WhatsApp | 生产就绪 | 扫码认证、Session 自动恢复 |
| Telegram | 生产就绪 | Bot Token 认证 |
| Gmail/Email | 生产就绪 | Microsoft Graph API (OAuth) |
| Google Calendar | 生产就绪 | Google Calendar API |
| LinkedIn | 实验性 | CSV 导入 + 即将支持自动同步 |
| Slack | 生产就绪 | Workspace Token |
| SMS | 生产就绪 | iOS 备份解析 |
| WhatsApp Business | 生产就绪 | iOS 备份解析 |

每个数据源独立运行，写入 `data/<source>/` 目录。统一存储由 `crm/merge.js` 从各来源重建。

资料来源：[README.md](), [ARCHITECTURE.md]()

## 启动方式

### 服务模式（推荐）

```bash
# 基础服务
npm run service

# 指定用户 UUID
MINTY_USER_UUID=abc npm run service

# 启用定期 GBrain 导出
MINTY_GBRAIN_EXPORT=1 npm run service
```

服务模式以无头守护进程运行，无 Web UI，适合长期部署。

### Web UI 模式

```bash
npm run crm
```

启动后在浏览器访问 `http://localhost:3456`，可浏览联系人、配置数据源、进行 QA 测试。

### Agent 原生模式

```bash
# 初始化演示数据
npm run seed:demo

# 自然语言查询
CRM_DATA_DIR=./data-demo npm run agent -- "who can help with crypto insurance"

# 启动 MCP 服务器
CRM_DATA_DIR=./data-demo npm run mcp
```

MCP 服务器可注册到 OpenClaw 或 Hermes，实现智能体对人脉网络的自然语言访问。

### 快速网络查询

```bash
npm run network:search -- "investors in fintech"
npm run network:changes
npm run network:reconnect
npm run service:status
```

资料来源：[README.md]()

## MCP 工具接口

Minty 提供四个核心 MCP 工具：

| 工具 | 功能 | 示例参数 |
|------|------|----------|
| `search_network` | 自然语言搜索人脉网络 | `{"query": "investors in London", "limit": 5}` |
| `person_context` | 查询特定联系人详情 | `{"person": "Alice Müller", "limit": 3}` |
| `workflow_brief` | 生成目标导向简报 | `{"goal": "Find EU partners", "limit": 5}` |
| `source_health` | 检查数据源健康状态 | `{"source": "telegram"}` |

这些工具通过 `scripts/minty-mcp-server.js` 暴露，是系统的工具接口规范。

资料来源：[hermes/minty-network-memory/SKILL.md]()

## 版本与发布

### 当前版本

最新稳定版本信息记录在 `CHANGELOG.md` 中，采用语义化版本号 `MAJOR.MINOR.PATCH`。

### 发布流程

1. **版本决策**：查看 `CHANGELOG.md` 的 `Unreleased` 部分，确定版本号
2. **更新 CHANGELOG**：将 `## [Unreleased]` 替换为 `## [X.Y.Z] - YYYY-MM-DD`
3. **升级 package.json**：
   ```bash
   npm version X.Y.Z --no-git-tag-version
   ```
4. **提交**：
   ```bash
   git add CHANGELOG.md package.json package-lock.json
   git commit -m "release: vX.Y.Z"
   ```
5. **打标签推送**：
   ```bash
   git tag vX.Y.Z
   git push origin main
   git push origin v.X.Y.Z
   ```

发布工作流自动验证标签与 `package.json` 的一致性，并从 `CHANGELOG.md` 提取发布说明创建 GitHub Release。

### 热修复流程

对于安全或生产级问题：

1. 从标签分支：`git checkout -b hotfix/X.Y.Z+1 v.X.Y.Z`
2. 修复代码
3. 按标准发布流程升级 PATCH 版本
4. 必要时将修复 cherry-pick 回 main 分支

资料来源：[RELEASING.md]()

## 技术要求

| 要求 | 规格 |
|------|------|
| Node.js 版本 | Node 20 + 22 |
| 包管理器 | npm |
| 可选依赖 | Playwright（LinkedIn 自动同步）、csv-parse |
| AI 后端 | Ollama（qwen2.5:7b 等模型）或 Claude Code CLI |

所有 AI 输出（洞察、摘要、重连草稿、查询排名）均为预计算并缓存于 `data/unified/*.json`，Web 服务器读取静态文件，请求时无 API 调用。

资料来源：[README.md](), [CHANGELOG.md]()

## 数据隐私与许可

- **数据存储**：所有数据本地存储于 `data/` 目录
- **隐私保护**：支持匿名化导出（`npm run gbrain:export`），避免原始联系人/消息泄露
- **许可协议**：采用 **AGPL-3.0** 许可证，开源且允许商业使用
- **商业授权**：如需在专有产品中嵌入 Minty，可申请商业许可

资料来源：[README.md]()

## 贡献指南

欢迎贡献代码。贡献者请先阅读：

- [CONTRIBUTING.md](./CONTRIBUTING.md) — 贡献流程规范
- [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md) — 行为准则
- [SECURITY.md](./SECURITY.md) — 安全报告流程

### 开发者入门

| 任务 | 起点 |
|------|------|
| 添加新数据源 | 复制 `sources/telegram/`，参照文件布局 |
| 改进匹配算法 | 阅读 `crm/MATCHING.md`，修改 `crm/match.js`，添加测试 fixture |
| UI 开发 | 编辑 `crm/ui.html.js` 和 `crm/server.js`，重启 `npm run crm` |
| 性能优化 | 关注 `crm/merge.js` 路径，参考 `tests/integration/` 的性能测试 |

资料来源：[ARCHITECTURE.md]()

## 项目愿景

Minty 的核心目标是构建一个"永不遗忘的人脉记忆系统"。系统通过持续整合用户的通讯数据，自动识别联系人关系的变化，并在关键时刻提供智能化的回顾与行动建议。长期愿景是让用户能够专注于建立和维护有意义的人际关系，而不是记忆细节。

项目路线图详见 [VISION.md](./VISION.md)。

资料来源：[README.md]()

---

<a id='page-quick-start'></a>

## 快速开始

### 相关页面

相关主题：[项目介绍](#page-introduction), [数据源导入](#page-data-sources)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/sree-sanak/minty/blob/main/README.md)
- [ARCHITECTURE.md](https://github.com/sree-sanak/minty/blob/main/ARCHITECTURE.md)
- [CONTRIBUTING.md](https://github.com/sree-sanak/minty/blob/main/CONTRIBUTING.md)
- [hermes/minty-network-memory/SKILL.md](https://github.com/sree-sanak/minty/blob/main/hermes/minty-network-memory/SKILL.md)
- [sources/_shared/progress.js](https://github.com/sree-sanak/minty/blob/main/sources/_shared/progress.js)
</details>

# 快速开始

Minty 是一个本地优先的关系管理系统，旨在帮助用户从多个数据源（WhatsApp、Telegram、Email、LinkedIn 等）聚合联系人信息，并通过 AI 能力提供关系洞察。本页将引导您完成 Minty 的安装、配置和首次使用。

---

## 环境要求

| 组件 | 要求 |
|------|------|
| Node.js | v20 或 v22 |
| 操作系统 | macOS、Linux、Windows（WSL 推荐） |
| 存储空间 | 取决于数据量，建议预留 1GB+ |
| 网络 | 仅在配置 AI 后端时需要（可选） |

资料来源：[README.md:1-10]()

---

## 安装步骤

### 1. 克隆仓库

```bash
git clone https://github.com/sree-sanak/minty.git
cd minty
```

### 2. 安装依赖

```bash
npm install
```

此命令安装所有必要的 Node.js 依赖包，包括数据处理、加密、Web 服务等模块。

### 3. 安装 Git Hooks（可选但推荐）

```bash
npm run hooks:install
```

此命令启用预推送 Preflight 检查，确保代码在推送前通过基础测试。

资料来源：[CONTRIBUTING.md:1-15]()

---

## 运行模式

Minty 支持三种运行模式，适用于不同的使用场景：

### 模式概览

| 模式 | 命令 | 端口 | 适用场景 |
|------|------|------|----------|
| 常驻服务 | `npm run service` | 后台运行 | 生产环境、长期运行 |
| Web UI | `npm run crm` | 3456 | 浏览器管理联系人 |
| Agent 模式 | `npm run agent` | - | 与 OpenClaw/Hermes 集成 |

资料来源：[README.md:20-35]()

### 常驻服务模式（推荐）

常驻服务以无头守护进程方式运行，持续同步数据：

```bash
# 默认模式
npm run service

# 指定用户 UUID
MINTY_USER_UUID=abc npm run service

# 同时运行周期性 GBrain 导出
MINTY_GBRAIN_EXPORT=1 npm run service
```

服务模式会在后台监控 `data/<source>/export/` 目录中的用户导入文件，并自动触发导入流程。资料来源：[ARCHITECTURE.md:1-30]()

### Web UI 模式

启动本地 Web 服务器，通过浏览器管理联系人：

```bash
npm run crm
```

访问 `http://localhost:3456` 打开 Minty CRM 界面。Web UI 采用单页应用（SPA）架构，所有前端代码位于 `crm/ui.html.js` 中。

> 注意：Web UI 读取的是预计算和缓存的静态文件（`data/unified/*.json`），无需在请求时调用 AI API。

资料来源：[CONTRIBUTING.md:10-12]()

### Agent 原生模式

适用于与 OpenClaw、Hermes 或 Claude Code 等 AI Agent 集成：

```bash
# 初始化演示数据
npm run seed:demo

# 执行网络查询
CRM_DATA_DIR=./data-demo npm run agent -- "who can help with crypto insurance"

# 启动 MCP 服务器
CRM_DATA_DIR=./data-demo npm run mcp
```

注册 `scripts/minty-mcp-server.js` 作为本地 stdio MCP 服务器后，Agent 可直接调用以下工具：

- `search_network` - 自然语言网络搜索
- `person_context` - 查询特定联系人的上下文
- `workflow_brief` - 生成目标导向简报
- `source_health` - 检查数据源健康状态

资料来源：[hermes/minty-network-memory/SKILL.md:1-50]()

---

## 快速网络查询

以下命令适用于快速查询，无需启动完整服务：

```bash
# 自由形式搜索
npm run network:search -- "investors in fintech"

# 通信模式变化
npm run network:changes

# 渐行渐远的关系（需要重新联系）
npm run network:reconnect

# 检查服务健康状态
npm run service:status
```

资料来源：[README.md:36-42]()

---

## 数据源配置

Minty 支持多个可选数据源，每个源独立导入，按需启用：

| 数据源 | 导入方式 | 说明 |
|--------|----------|------|
| WhatsApp | `npm run whatsapp` | 首次需扫描 QR 码 |
| Telegram | `sources/telegram/import.js` | 导出 Telegram 数据 |
| Email | Microsoft Graph API | 支持 Outlook/Exchange |
| SMS | 平台特定 | 读取本地短信记录 |
| LinkedIn | ZIP 包导入 | 导出 LinkedIn 数据 |
| Google Contacts | 同步 | Google 账户联系人 |
| Slack | 导出 | 导出 Slack 消息历史 |

资料来源：[README.md:45-60]()

### WhatsApp 快速配置

```bash
npm run whatsapp
```

首次运行时显示 QR 码，用 WhatsApp 手机应用扫描后即可连接。后续运行自动恢复会话。

---

## AI 后端配置

Minty 采用预计算 AI 策略，所有 AI 输出（洞察、摘要、重新联系草稿）存储在 `data/unified/*.json` 中，Web 服务器直接读取静态文件，无运行时 API 调用。

### Claude Code CLI（默认）

如果系统 PATH 中存在 `claude` 命令，Minty 自动使用此后端：

```bash
# 验证 Claude Code 可用性
claude --version
```

> 注意：Claude Code 后端会将提示词（包含联系人消息片段）发送至 Anthropic 服务器。

资料来源：[README.md:100-115]()

### Ollama（完全离线）

配置本地 Ollama 模型：

```bash
# 在 .env 文件中设置
AI_BACKEND=ollama

# 推荐模型
ollama run qwen2.5:7b
```

Ollama 模式完全离线运行，适合对数据隐私有高要求的用户。

---

## 数据目录结构

所有数据存储在本地 `data/` 目录中（已被 Git 忽略）：

```
data/
├── whatsapp/         # WhatsApp 聊天和联系人
├── telegram/         # Telegram 导出数据
├── email/            # Email 账户数据
├── sms/              # 短信数据
├── linkedin/         # LinkedIn 导出（ZIP + CSV）
├── google-contacts/  # Google 联系人
├── slack/            # Slack 导出
└── unified/          # 合并后的统一视图
    ├── contacts.json       # 统一联系人
    ├── interactions.json  # 互动时间线
    └── match_overrides.json # 匹配规则覆盖
```

可通过环境变量覆盖数据目录：

```bash
CRM_DATA_DIR=./custom-data-dir npm run service
```

资料来源：[ARCHITECTURE.md:40-70]()

---

## 同步状态监控

### 服务状态检查

```bash
npm run service:status
```

### 单源进度查询

每个导入器通过 `sources/_shared/progress.js` 记录同步进度：

```javascript
// 进度数据结构
{
  step: 'init' | 'messages' | 'contacts' | 'done',
  message: string,
  current: number,
  total: number,
  itemsProcessed: number,
  errors: string[],
  startedAt: ISO8601 timestamp,
  updatedAt: ISO8601 timestamp
}
```

API 端点：

- `GET /api/sources/:key/progress` - 单个数据源进度
- `GET /api/sync/progress` - 所有源同步进度

资料来源：[sources/_shared/progress.js:1-40]()

---

## 完整工作流程

```mermaid
graph TD
    A[安装 Minty] --> B[选择运行模式]
    B --> C[配置数据源]
    C --> D[运行导入]
    D --> E[合并数据<br/>merge.js]
    E --> F[交叉匹配<br/>match.js]
    F --> G[预计算 AI 洞察]
    G --> H[访问数据]
    
    C --> C1[WhatsApp]
    C --> C2[Telegram]
    C --> C3[Email]
    C --> C4[LinkedIn]
    
    H --> H1[Web UI<br/>localhost:3456]
    H --> H2[Agent 查询<br/>MCP]
    H --> H3[CLI 查询<br/>network:*]
```

---

## 下一步

| 任务 | 参考文档 |
|------|----------|
| 添加新数据源 | [ARCHITECTURE.md - 添加新导入器](ARCHITECTURE.md) |
| 改进联系人匹配 | [crm/MATCHING.md](crm/MATCHING.md) |
| Web UI 开发 | 修改 `crm/ui.html.js` |
| 性能优化 | `tests/integration/` 集成测试 |
| 测试运行 | `npm test` |

---

## 常见问题

### Q: 首次运行报错 "csv-parse not found"？

确保 `csv-parse` 依赖已安装：

```bash
npm install csv-parse
```

此问题在 v0.3.2 中已修复。

资料来源：[CHANGELOG.md:1-20]()

### Q: 如何验证安装正确？

```bash
npm test
```

运行完整单元测试套件（747 个测试）。

### Q: 数据隐私如何保证？

所有数据存储在本地 `data/` 目录，无遥测、无分析、无电话-home。详见 [SECURITY.md](SECURITY.md)。

---

## 许可证

Minty 采用 **AGPL-3.0** 许可证发布。详情见 [LICENSE](LICENSE)。

如需在专有产品中嵌入 Minty，可申请商业许可：开一个 Issue 联系我们。

---

<a id='page-file-structure'></a>

## 项目文件结构

### 相关页面

相关主题：[项目介绍](#page-introduction), [架构总览](#page-architecture-overview)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [ARCHITECTURE.md](https://github.com/sree-sanak/minty/blob/main/ARCHITECTURE.md)
- [crm/server.js](https://github.com/sree-sanak/minty/blob/main/crm/server.js)
- [crm/staleness.js](https://github.com/sree-sanak/minty/blob/main/crm/staleness.js)
- [sources/_shared/progress.js](https://github.com/sree-sanak/minty/blob/main/sources/_shared/progress.js)
- [sources/email/import.js](https://github.com/sree-sanak/minty/blob/main/sources/email/import.js)
- [sources/google-contacts/sync-hermes.js](https://github.com/sree-sanak/minty/blob/main/sources/google-contacts/sync-hermes.js)
- [crm/review-server.js](https://github.com/sree-sanak/minty/blob/main/crm/review-server.js)
- [README.md](https://github.com/sree-sanak/minty/blob/main/README.md)
</details>

# 项目文件结构

## 概述

Minty 是一个个人关系管理系统（Personal CRM），用于聚合来自多个通讯平台的数据，构建统一的人际关系视图。项目采用模块化架构，将数据导入、合并、搜索和服务层分离，便于扩展和维护。

资料来源：[ARCHITECTURE.md]()

## 顶层目录结构

```
minty/
├── crm/                    # 核心 CRM 服务层
├── sources/                # 各平台数据导入器
├── hermes/                 # Hermes 工作流集成
├── scripts/                # 工具脚本
├── data/                   # 运行时数据目录（gitignored）
├── docs/                   # 文档
└── package.json
```

## 核心模块详解

### crm/ — 核心服务层

CRM 层负责数据合并、API 服务和前端渲染，是整个系统的中枢。

| 文件 | 职责 |
|------|------|
| `server.js` | HTTP API 服务器，处理所有 `/api/*` 路由 |
| `index.js` | 入口文件，路由分发 |
| `merge.js` | 多源数据标准化、去重、合并 |
| `match.js` | 跨源匹配算法 |
| `schema.js` | Contact 和 Interaction 的规范数据模型 |
| `query.js` | CLI 工具：`npm run stats`、`npm run search` |
| `network-query.js` | 自然语言查询接口 |
| `reconnect.js` | 关系淡化检测与草稿生成 |
| `ai.js` | AI 适配器（本地 Claude Code / Ollama） |
| `staleness.js` | 数据新鲜度评估 |
| `sync.js` | 监听 `data/<source>/export/` 目录变化 |
| `calendar.js` | 日历集成 |
| `digest.js` | 每周摘要生成 |
| `meeting-debrief.js` | 会议复盘 |
| `goal-retro.js` | 目标回顾 |
| `life-events.js` | 人生大事记录 |
| `utils.js` | 电话/邮箱/姓名标准化，评分辅助 |
| `review-server.js` | 匹配审核服务器（人工确认） |

资料来源：[ARCHITECTURE.md]()

### sources/ — 数据导入器

每个数据源独立运行，向 `data/<source>/` 目录写入 JSON 文件。

```
sources/
├── _shared/                # 共享工具
│   └── progress.js         # 统一的进度追踪
├── whatsapp/               # WhatsApp 导入器
├── telegram/               # Telegram 导入器
├── email/                  # Email 导入器（Microsoft Graph）
├── google-contacts/        # Google Contacts 同步
├── linkedin/               # LinkedIn CSV 解析
├── sms/                    # 短信导入
└── slack/                  # Slack 导入
```

#### 进度追踪机制

`sources/_shared/progress.js` 提供原子化的进度文件写入：

```javascript
// 导入器启动时调用
P.startProgress(DATA_DIR, 'email', { step: 'init', message: 'Connecting…' });

// 导入过程中更新
P.updateProgress(DATA_DIR, 'email', { 
    step: 'messages', 
    message: 'Fetching via Microsoft Graph…' 
});
```

进度文件格式（`.progress.json`）包含：step、message、current、total、itemsProcessed、errors、startedAt、updatedAt。

资料来源：[sources/_shared/progress.js:1-50]()

#### Email 导入器

`sources/email/import.js` 支持两种认证方式：

1. **Microsoft Graph API** — 使用 `EMAIL_ACCESS_TOKEN` 和 `EMAIL_TOKEN_TYPE=microsoft`
2. **通用 OAuth** — 通过 `EMAIL_ACCESS_TOKEN` 环境变量

导入结果写入 `data/email/` 目录，包含消息和联系人。

资料来源：[sources/email/import.js:50-80]()

#### Google Contacts 同步

`sources/google-contacts/sync-hermes.js` 实现基于身份（邮箱/电话）的联系人合并：

```javascript
function mergeByIdentity(contacts) {
  const byKey = new Map();
  for (const contact of contacts) {
    const key = contact.emails[0] || contact.phones[0] || ...;
    // 合并重复联系人
  }
  return [...byKey.values()];
}
```

资料来源：[sources/google-contacts/sync-hermes.js:30-45]()

### data/ — 运行时数据目录

数据目录结构如下（受 `CRM_DATA_DIR` 环境变量控制）：

```
data/
├── whatsapp/           chats.json, contacts.json, metadata.json, profile_pics/
├── linkedin/           export/ (用户上传的 ZIP) + 解析后的 CSV
├── telegram/           result.json + 解析结果
├── email/              按账户分文件夹
├── sms/                按平台分文件夹
├── google-contacts/    同步数据
├── unified/            合并后的统一视图
│   ├── contacts.json       # 唯一联系人列表
│   ├── interactions.json   # 交互时间线
│   └── match_overrides.json # 手动匹配覆盖
└── goals/              目标数据
```

资料来源：[ARCHITECTURE.md]()

### hermes/ — 工作流集成

`hermes/minty-network-memory/` 包含 Hermes 工作流的技能定义，暴露以下 MCP 工具：

| 工具 | 功能 |
|------|------|
| `search_network` | 自然语言网络搜索 |
| `person_context` | 单个联系人上下文查询 |
| `workflow_brief` | 目标导向的联系人推荐 |
| `source_health` | 数据源健康状态检查 |

资料来源：[hermes/minty-network-memory/SKILL.md]()

### scripts/ — 工具脚本

| 脚本 | 用途 |
|------|------|
| `minty-mcp-server.js` | MCP 服务器入口 |
| `sync-labels.js` | GitHub 标签同步 |
| `seed-dev-data.js` | 开发数据生成 |

资料来源：[README.md]()

## 数据流程架构

```mermaid
graph TD
    subgraph 用户操作
        A[运行导入器] --> B[source/import.js]
    end
    
    subgraph 源数据层
        B --> C[data/&lt;source&gt;/]
        C --> D[whatsapp/]
        C --> E[email/]
        C --> F[telegram/]
        C --> G[linkedin/]
    end
    
    subgraph 合并层
        H[crm/merge.js] --> I[标准化]
        I --> J[去重匹配]
        J --> K[构建时间线]
        H -.-> L[data/unified/]
    end
    
    subgraph 服务层
        M[crm/server.js] --> N[REST API]
        M --> O[crm/query.js]
        M --> P[crm/network-query.js]
    end
    
    subgraph 前端
        Q[crm/ui.html.js] --> N
        R[Hermes Agent] --> S[MCP Tools]
    end
    
    L --> M
```

## API 路由概览

`crm/server.js` 提供的主要 REST 端点：

| 方法 | 路由 | 功能 |
|------|------|------|
| GET | `/api/contacts` | 获取联系人列表 |
| GET | `/api/contacts/:id` | 获取单个联系人 |
| GET | `/api/interactions` | 交互时间线 |
| GET | `/api/sync/progress` | 同步进度 |
| GET | `/api/sources/:key/progress` | 单源进度 |
| GET | `/api/goals` | 目标列表 |
| GET | `/api/goals/:id/pipeline` | 目标联系人管道 |
| GET | `/api/goals/:id/retro` | 目标回顾 |
| GET | `/api/export` | 导出数据 |
| POST | `/api/export` | 创建加密备份 |

资料来源：[crm/server.js:200-280]()

## 数据新鲜度管理

`crm/staleness.js` 实现数据新鲜度检测：

```javascript
function getStalenessMessage(source, days) {
    if (days === null) return `${label} has never synced`;
    if (days === 0) return `${label} synced today`;
    if (days <= 7) return `${label} synced ${days} days ago`;
    if (days <= 30) return `${label} export is ${days} days old — refresh?`;
    return `${label} export is ${days} days old — data may be outdated`;
}
```

新鲜度等级：
- **高**：最近 7 天有同步
- **中**：7-30 天未同步
- **低**：超过 30 天或从未同步

资料来源：[crm/staleness.js:1-50]()

## 贡献者指南

### 新增导入器

1. 复制简单导入器模板（如 `sources/telegram/`）
2. 写入 `data/<your-source>/`
3. 在 `crm/merge.js` 中添加合并步骤

### 匹配算法改进

1. 阅读 `crm/MATCHING.md` 规范
2. 修改 `crm/match.js`
3. 在 `tests/` 添加测试用例

### UI 开发

- 编辑 `crm/ui.html.js` 修改 SPA
- 编辑 `crm/server.js` 调整路由
- 重启 `npm run crm` 以热更新

资料来源：[ARCHITECTURE.md]()

## 环境变量配置

| 变量 | 默认值 | 说明 |
|------|--------|------|
| `CRM_DATA_DIR` | `./data` | 数据根目录 |
| `EMAIL_EXPORT_DIR` | - | Email 导出目录 |
| `EMAIL_ACCESS_TOKEN` | - | Graph API 令牌 |
| `MINTY_USER_UUID` | - | 用户 UUID |
| `AI_BACKEND` | `claude` | AI 后端（ollama/claude） |

## 模块依赖关系

```mermaid
graph LR
    subgraph 数据源
        A[WhatsApp] --> G[merge.js]
        B[Email] --> G
        C[Telegram] --> G
        D[LinkedIn] --> G
    end
    
    G --> H[unified/contacts.json]
    G --> I[unified/interactions.json]
    
    H --> J[server.js]
    I --> J
    
    J --> K[ui.html.js]
    J --> L[MCP Server]
    J --> M[CLI Query]

---

<a id='page-architecture-overview'></a>

## 架构总览

### 相关页面

相关主题：[项目介绍](#page-introduction), [AI 后端配置](#page-ai-backend), [数据存储结构](#page-data-storage)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [ARCHITECTURE.md](https://github.com/sree-sanak/minty/blob/main/ARCHITECTURE.md)
- [crm/server.js](https://github.com/sree-sanak/minty/blob/main/crm/server.js)
- [crm/schema.js](https://github.com/sree-sanak/minty/blob/main/crm/schema.js)
- [crm/staleness.js](https://github.com/sree-sanak/minty/blob/main/crm/staleness.js)
- [sources/_shared/progress.js](https://github.com/sree-sanak/minty/blob/main/sources/_shared/progress.js)
- [sources/email/import.js](https://github.com/sree-sanak/minty/blob/main/sources/email/import.js)
- [hermes/minty-network-memory/SKILL.md](https://github.com/sree-sanak/minty/blob/main/hermes/minty-network-memory/SKILL.md)
</details>

# 架构总览

## 项目概述

Minty 是一个本地优先的 CRM 系统，用于聚合来自多个数据源的联系人与交互记录，并通过本地 AI（Claude Code CLI 或 Ollama）生成洞察和关系评分。项目完全离线运行，所有数据存储在本地 `data/` 目录，无遥测、无分析、无云端同步。资料来源：[README.md](https://github.com/sree-sanak/minty/blob/main/README.md)

## 核心模块架构

项目采用模块化架构，主要分为三个顶层目录：

| 模块 | 路径 | 功能描述 |
|------|------|----------|
| **crm/** | `crm/` | 应用主程序 + 确定性的 AI 检索引擎 |
| **sources/** | `sources/` | 每个数据源的独立导入器 |
| **scripts/** | `scripts/` | CLI/MCP 入口点，供 OpenClaw、Hermes 等 agent 调用 |

资料来源：[README.md](https://github.com/sree-sanak/minty/blob/main/README.md)

```
crm/        # 应用核心 + 检索引擎
scripts/    # CLI/MCP 入口
sources/    # 数据源导入器
ee/         # 预留商业功能
data/       # 本地数据（gitignored）
docs/       # 文档 + ADR
tests/      # 单元/集成/e2e 测试
```

## CRM 模块详细架构

CRM 模块是系统的核心，包含以下关键文件：

| 文件 | 功能 |
|------|------|
| `ui.html.js` | 单页应用外壳（HTML/CSS/JS 合一模板） |
| `merge.js` | 加载各源数据、规范化、去重、写入 `unified/contacts.json` 和 `interactions.json` |
| `match.js` | 跨源匹配算法，读取 MATCHING.md 规范 |
| `schema.js` | Contact 和 Interaction 的规范记录格式 |
| `query.js` | CLI 工具：`npm run stats`、`npm run search` |
| `network-query.js` | 自然语言"Ask"视图 |
| `reconnect.js` | "渐行渐远的人"界面 + 草稿生成 |
| `ai.js` | 本地 Claude Code CLI / Ollama 适配器，无云端 API |
| `staleness.js` | 标记陈旧联系人数据 |
| `sync.js` | 监听 `data/<source>/export/` 目录变化并触发导入器 |
| `calendar.js`、`digest.js`、`meeting-debrief.js`、`goal-retro.js`、`life-events.js` | 基于统一存储构建的高级界面 |
| `utils.js` | 电话/邮箱/姓名规范化、评分辅助函数、内存联系人索引 |

资料来源：[ARCHITECTURE.md](https://github.com/sree-sanak/minty/blob/main/ARCHITECTURE.md)

### 数据模型（Schema）

系统定义了规范的联系人与交互记录格式：

```javascript
// Contact 核心结构
{
  id: string,
  name: string,
  phones: string[],
  emails: string[],
  sources: { [sourceName]: sourceData },
  relationshipScore: number,
  daysSinceContact: number,
  activeChannels: string[],
  // ...
}

// Interaction 核心结构
{
  id: string,
  timestamp: string,
  source: string,
  body: string,
  subject: string,
  participants: string[],
  // ...
}
```

修改数据模型时，应首先编辑 `schema.js`，其余模块随之更新。资料来源：[ARCHITECTURE.md](https://github.com/sree-sanak/minty/blob/main/ARCHITECTURE.md)

## 数据流架构

数据生命周期端到端流程如下：

```mermaid
graph TD
    A["用户运行导入器"] --> B["源导入器<br/>sources/<src>/..."]
    B --> C["data/<source>/*.json<br/>每源记录"]
    C --> D["crm/merge.js"]
    D --> E["规范化手机/邮箱/姓名"]
    D --> F["跨源去重<br/>crm/match.js, MATCHING.md"]
    D --> G["构建统一交互时间线"]
    E --> H["data/unified/contacts.json"]
    F --> H
    G --> I["data/unified/interactions.json"]
    
    H --> J["crm/server.js<br/>REST API"]
    I --> J
    J --> K["ui.html.js<br/>单页应用"]
    
    J --> L["ai.js<br/>Claude Code CLI / Ollama"]
    L --> M["生成洞察、评分、摘要"]
    M --> H
```

资料来源：[ARCHITECTURE.md](https://github.com/sree-sanak/minty/blob/main/ARCHITECTURE.md)

## 导入器（Sources）架构

每个数据源是独立的导入模块，写入 `data/<source>/` 目录。统一存储由 `crm/merge.js` 重建。

### 支持的数据源

| 数据源 | 路径 | 说明 |
|--------|------|------|
| WhatsApp | `data/whatsapp/` | chats.json, contacts.json, metadata.json, profile_pics/ |
| LinkedIn | `data/linkedin/` | 用户上传的 ZIP 包 + 解析后的 CSV |
| Telegram | `data/telegram/` | result.json + 解析结果 |
| Email | `data/email/` | 按账户分文件夹 |
| SMS | `data/sms/` | 按平台分文件夹 |
| Google Contacts | `data/google-contacts/` | 同步数据 |
| 统一存储 | `data/unified/` | contacts.json, interactions.json, match_overrides.json |

资料来源：[ARCHITECTURE.md](https://github.com/sree-sanak/minty/blob/main/ARCHITECTURE.md)

### 导入器进度追踪

所有导入器使用统一的进度文件 `.progress.json`，包含标准字段：

```javascript
{
  source: string,        // 数据源标识
  step: string,          // 当前步骤
  message: string,       // 状态消息
  current: number,       // 当前进度
  total: number,         // 总数
  itemsProcessed: number,
  errors: string[],
  startedAt: string,     // ISO 时间戳
  updatedAt: string      // ISO 时间戳
}
```

进度操作函数位于 `sources/_shared/progress.js`：

- `startProgress(dataDir, source, initial)` — 初始化进度
- `updateProgress(dataDir, source, patch)` — 更新进度
- `readProgress(dataDir, source)` — 读取进度

资料来源：[sources/_shared/progress.js](https://github.com/sree-sanak/minty/blob/main/sources/_shared/progress.js)

### 添加新导入器

添加新数据源的步骤：

1. 复制简单导入器作为模板（如 `sources/telegram/import.js`）
2. 遵循其文件布局
3. 写入 `data/<your-source>/`
4. 在 `crm/merge.js` 中添加合并步骤

资料来源：[ARCHITECTURE.md](https://github.com/sree-sanak/minty/blob/main/ARCHITECTURE.md)

## API 路由体系

`crm/server.js` 提供完整的 REST API，所有接口前缀为 `/api/`：

| 方法 | 路径 | 功能 |
|------|------|------|
| GET | `/api/contacts` | 获取联系人列表 |
| GET | `/api/contacts/:id` | 获取单个联系人详情 |
| GET | `/api/contacts/:id/interactions` | 获取联系人交互记录 |
| GET/POST | `/api/export` | 导入/导出数据 |
| GET | `/api/digest` | 周报摘要 |
| GET | `/api/goals` | 目标列表 |
| POST | `/api/goals/:id/assign` | 分配联系人到目标 |
| GET | `/api/goals/:id/pipeline` | 目标漏斗视图 |
| GET | `/api/goals/:id/retro` | 目标回顾 |
| GET | `/api/meetings/debriefs/pending` | 待处理会议总结 |
| GET/POST | `/api/meetings/:id/debrief` | 会议总结 |
| GET | `/api/sources/:key/progress` | 数据源同步进度 |
| GET | `/api/sync/progress` | 全部数据源进度 |
| GET | `/api/notifications` | 通知列表 |
| POST | `/api/notifications/:type/dismiss` | 忽略通知 |
| GET | `/api/meta` | 元信息（demo 模式、数据目录等） |

资料来源：[crm/server.js](https://github.com/sree-sanak/minty/blob/main/crm/server.js)

## 数据陈旧性检测

`crm/staleness.js` 负责检测数据新鲜度，提供两种检测维度：

### 数据源级别陈旧性

| 陈旧天数 | 严重程度 | 消息 |
|----------|----------|------|
| 从未同步 | warning | `{label} 从未同步` |
| 0 天 | info | `{label} 今天已同步` |
| 1 天 | info | `{label} 昨天已同步` |
| ≤7 天 | info | `{label} {n} 天前同步` |
| ≤30 天 | warning | `{label} 导出已 {n} 天 — 需要刷新？` |
| >30 天 | error | `{label} 导出已 {n} 天 — 数据可能已过时` |

### 联系人数据置信度

根据来源新鲜度计算联系人数据置信级别：

| 级别 | 条件 |
|------|------|
| high | 有活跃交互且来源新鲜 |
| medium | 有交互但部分来源陈旧 |
| low | 无交互或无来源数据 |

资料来源：[crm/staleness.js](https://github.com/sree-sanak/minty/blob/main/crm/staleness.js)

## AI 后端架构

Minty 刻意避免运行时 LLM 费用，支持两种本地后端：

| 后端 | 配置 | 说明 |
|------|------|------|
| **Claude Code CLI** | 默认（无配置） | 调用 `claude --print`，已登录用户免费使用 |
| **Ollama** | `AI_BACKEND=ollama` | 完全离线，支持 qwen2.5:7b 等本地模型 |

AI 输出（洞察、摘要、重新联系草稿、查询排名）预计算并缓存于 `data/unified/*.json`，Web 服务器读取这些静态文件。资料来源：[README.md](https://github.com/sree-sanak/minty/blob/main/README.md)

## MCP 集成（Hermes）

Minty 提供 MCP（Model Context Protocol）服务器供 AI Agent 使用，位于 `scripts/minty-mcp-server.js`：

| 工具 | 功能 |
|------|------|
| `search_network` | 自然语言网络搜索 |
| `person_context` | 查询特定联系人详情 |
| `workflow_brief` | 生成目标导向简报 |
| `source_health` | 检查数据源健康状态 |

```javascript
// 使用示例
{
  "query": "investors in London who know about AI",
  "limit": 5
}
```

Minty 与 Hermes 集成的就绪级别：

| 级别 | 要求 |
|------|------|
| Demo-ready | `npm run seed:demo` + `npm run mcp` 可用 |
| Dogfood-ready | `npm run memory:refresh` 成功，无直接联系方式输出 |
| Hermes-native | 技能已安装，MCP 服务器已注册 |

资料来源：[hermes/minty-network-memory/SKILL.md](https://github.com/sree-sanak/minty/blob/main/hermes/minty-network-memory/SKILL.md)

## 性能优化要点

大数据集场景下的性能瓶颈通常在合并路径，优化策略：

| 场景 | 建议 |
|------|------|
| 大量联系人 | 优化 `crm/merge.js` 中的去重算法 |
| 跨源匹配 | 改进 `crm/match.js` 的 MATCHING.md 规则 |
| UI 响应 | 缓存预计算的 AI 输出 |
| 测试 | 使用 `tests/integration/` 的 fixture 性能测试 |

资料来源：[ARCHITECTURE.md](https://github.com/sree-sanak/minty/blob/main/ARCHITECTURE.md)

## 贡献指南

### 开发环境启动

```bash
npm run crm        # 启动 CRM 服务器（热重载）
npm run seed:demo  # 生成演示数据
npm run test       # 运行测试套件
```

### 代码修改优先级

1. **修改数据模型** → 首先编辑 `schema.js`
2. **添加新导入器** → 复制 `sources/telegram/import.js` 模板
3. **改进匹配算法** → 编辑 `crm/match.js`，添加 `tests/` fixture
4. **UI 工作** → 编辑 `crm/ui.html.js` 和 `crm/server.js`

资料来源：[ARCHITECTURE.md](https://github.com/sree-sanak/minty/blob/main/ARCHITECTURE.md)

---

<a id='page-ai-backend'></a>

## AI 后端配置

### 相关页面

相关主题：[架构总览](#page-architecture-overview), [网络查询系统](#page-network-query)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [ARCHITECTURE.md](https://github.com/sree-sanak/minty/blob/main/ARCHITECTURE.md) — 项目架构总览
- [crm/server.js](https://github.com/sree-sanak/minty/blob/main/crm/server.js) — 服务器端实现
- [hermes/minty-network-memory/SKILL.md](https://github.com/sree-sanak/minty/blob/main/hermes/minty-network-memory/SKILL.md) — 网络记忆技能配置
- [crm/agent-source-health.js](https://github.com/sree-sanak/minty/blob/main/crm/agent-source-health.js) — 数据源健康检查
- [sources/_shared/progress.js](https://github.com/sree-sanak/minty/blob/main/sources/_shared/progress.js) — 导入进度追踪
- [crm/staleness.js](https://github.com/sree-sanak/minty/blob/main/crm/staleness.js) — 数据新鲜度检测

> 注：本页所需的部分文件（如 `crm/digest.js`、`crm/evidence-patches.js`、`.env.example`）在当前检索上下文中未找到，以下内容基于已获取的源码片段进行概述。

</details>

# AI 后端配置

## 概述

Minty 项目采用**本地优先的 AI 策略**，不依赖任何云端 API 服务。AI 功能通过 `crm/ai.js` 模块实现，该模块作为适配器，同时支持 **Claude Code CLI** 和 **Ollama** 两种本地推理引擎。

资料来源：[ARCHITECTURE.md]()

## 架构设计

### AI 适配器架构

```mermaid
graph TD
    A[用户请求] --> B[crm/server.js]
    B --> C{AI 引擎选择}
    C -->|Claude Code CLI| D[claude-code-adapter]
    C -->|Ollama| E[ollama-adapter]
    D --> F[本地 Claude Code 进程]
    E --> G[本地 Ollama 服务]
    F --> H[结构化响应]
    G --> H
    H --> I[UI 层渲染]
```

资料来源：[ARCHITECTURE.md]()

### 设计原则

| 原则 | 说明 |
|------|------|
| **本地化** | 所有 AI 推理在本地执行，无云端数据传输 |
| **隐私优先** | 联系人数据和交互内容不离开用户设备 |
| **离线可用** | 依赖 Ollama 或 Claude Code CLI 的本地安装 |
| **无供应商锁定** | 支持切换不同的本地推理引擎 |

资料来源：[ARCHITECTURE.md]()

## MCP 工具集成

### 网络记忆工具

Minty 通过 MCP（Model Context Protocol）暴露网络记忆能力，供 AI Agent 调用：

```json
{
  "tools": {
    "search_network": "自然语言搜索联系人",
    "person_context": "查询特定人物的关系上下文",
    "workflow_brief": "生成目标导向的人物简报",
    "source_health": "检查数据源健康状态"
  }
}
```

资料来源：[hermes/minty-network-memory/SKILL.md]()

### 工具调用示例

```json
// 搜索网络
{ "query": "investors in London who know about AI", "limit": 5 }

// 人物上下文查询
{ "person": "Alice Müller", "limit": 3 }

// 目标简报生成
{ "goal": "Find EU crypto insurance distribution partners", "limit": 5 }

// 数据源健康检查
{ "source": "telegram" }
```

资料来源：[hermes/minty-network-memory/SKILL.md]()

## 数据源健康检查

### 健康状态等级

AI 后端在执行查询前会评估数据源的可信度：

| 状态 | 描述 | AI 可用性 |
|------|------|----------|
| `ready` | 数据源正常、可回答问题 | ✅ 可用 |
| `stale` | 数据较旧（超过 7 天未同步） | ⚠️ 有限可用 |
| `limited` | 存在警告（无联系人、无证据等） | ⚠️ 有限可用 |
| `blocked` | 显式请求不可用的数据源 | ❌ 不可用 |
| `error` | 同步错误 | ❌ 不可用 |

资料来源：[crm/agent-source-health.js]()

### 健康检查流程

```mermaid
graph TD
    A[接收源过滤请求] --> B[验证源标识符]
    B --> C{源有效?}
    C -->|否| D[标记 invalid_source]
    C -->|是| E[遍历每个数据源]
    E --> F[统计联系人数]
    F --> G[统计交互记录数]
    G --> H[获取最后同步时间]
    H --> I{新鲜度判断}
    I -->|fresh| J[status: ready]
    I -->|stale| K[status: stale]
    I -->|unknown| L[status: limited]
    J --> M[生成警告列表]
    K --> M
    L --> M
    D --> M
    M --> N[返回 answerable 状态]
```

资料来源：[crm/agent-source-health.js]()

## 导入进度追踪

AI 功能依赖高质量的数据导入，进度系统为导入过程提供实时反馈：

### 进度状态模型

```javascript
{
    source: String,           // 数据源标识符
    step: String,             // 当前步骤
    message: String,          // 人类可读消息
    current: Number,          // 当前处理项
    total: Number,            // 总项数
    itemsProcessed: Number,   // 已处理项数
    errors: Array,            // 错误列表
    startedAt: ISO8601,       // 开始时间
    updatedAt: ISO8601        // 更新时间
}
```

资料来源：[sources/_shared/progress.js]()

### API 端点

| 端点 | 方法 | 描述 |
|------|------|------|
| `/api/sources/:key/progress` | GET | 获取指定数据源的导入进度 |
| `/api/sync/progress` | GET | 获取所有数据源的同步进度 |

资料来源：[ARCHITECTURE.md]()

## 数据新鲜度检测

### 新鲜度阈值

| 条件 | 状态 | 阈值 |
|------|------|------|
| 24 小时内同步 | 新鲜 | `fresh` |
| 7 天内同步 | 可接受 | `stale` |
| 超过 7 天 | 过期 | `outdated` |

资料来源：[crm/staleness.js]()

### 警告消息示例

```javascript
"Google Contacts  export is 14 days old — data may be outdated"
"Telegram has never synced"
"LinkedIn synced today"
```

资料来源：[crm/staleness.js]()

## 摘要生成与目标回顾

### 每周摘要功能

服务器端 `handleGetDigest` 处理器读取预生成的摘要文件：

```javascript
function handleGetDigest(req, res, params, paths) {
    try { json(res, JSON.parse(fs.readFileSync(paths.digest, 'utf8'))); }
    catch { json(res, null); }
}
```

资料来源：[crm/server.js]()

### 目标关联人物排名

AI 系统根据目标关键词对联系人进行相关性排序：

```javascript
goalSections = goals.map(goal => {
    const ranked = rankContactsForGoal(contacts, goal.text, 5);
    return {
        goalId: goal.id,
        goalText: goal.text,
        contacts: ranked.map(c => ({
            id: c.id,
            name: c.name,
            company: c.sources?.linkedin?.company || null,
            goalRelevance: c.goalRelevance,
            meetingBrief: ins ? ins.meetingBrief : null,
        }))
    };
});
```

资料来源：[crm/server.js]()

## 敏感信息保护

### 数据脱敏机制

进度追踪模块内置敏感信息过滤：

```javascript
function redactErrorText(value) {
    return String(value)
        .replace(/^\s*at\s+[^\n]+/gm, '[redacted-stack]')
        .replace(/(["'`])[^"'`\n]*[\\/][^"'`\n]*\1/g, '$1[redacted-path]$1')
        .replace(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi, '[redacted-email]')
        .replace(/\bauthorization\s*[:=]\s*Bearer\s+[^\s,;]+/gi, '[redacted-credential]')
        // ... 更多脱敏规则
}
```

资料来源：[sources/_shared/progress.js]()

### 脱敏规则表

| 模式 | 替换结果 |
|------|----------|
| 邮箱地址 | `[redacted-email]` |
| Bearer 令牌 | `Bearer [redacted-credential]` |
| API 密钥 | `[redacted-credential]` |
| 文件路径 | `[redacted-path]` |
| 堆栈跟踪 | `[redacted-stack]` |

资料来源：[sources/_shared/progress.js]()

## 快速开始

### 前置要求

1. 安装 **Node.js 20+**
2. 安装 **Claude Code CLI** 或 **Ollama**
3. 配置数据源导入

### 验证 AI 配置

```bash
# 启动 MCP 服务器
npm run mcp

# 验证网络记忆功能
npm run agent -- "investors in London"
```

资料来源：[hermes/minty-network-memory/SKILL.md]()

## 故障排查

| 问题 | 可能原因 | 解决方案 |
|------|----------|----------|
| AI 返回空结果 | 数据源未同步 | 运行 `npm run sync` |
| 源健康检查失败 | 缺少数据源配置 | 检查 `.env` 配置 |
| 连接超时 | Ollama 服务未启动 | 启动 `ollama serve` |
| 权限错误 | Claude Code CLI 未授权 | 运行 `claude` 完成认证 |

## 相关文档

- [架构总览](./ARCHITECTURE.md)
- [数据源导入](./SOURCES.md)
- [匹配算法](./MATCHING.md)
- [发布流程](./RELEASING.md)

---

<a id='page-data-sources'></a>

## 数据源导入

### 相关页面

相关主题：[联系人合并与去重](#page-contact-merging), [数据存储结构](#page-data-storage), [快速开始](#page-quick-start)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [sources/whatsapp/export.js](https://github.com/sree-sanak/minty/blob/main/sources/whatsapp/export.js)
- [sources/linkedin/import.js](https://github.com/sree-sanak/minty/blob/main/sources/linkedin/import.js)
- [sources/telegram/import.js](https://github.com/sree-sanak/minty/blob/main/sources/telegram/import.js)
- [sources/email/import.js](https://github.com/sree-sanak/minty/blob/main/sources/email/import.js)
- [sources/google-contacts/import.js](https://github.com/sree-sanak/minty/blob/main/sources/google-contacts/import.js)
- [sources/sms/import.js](https://github.com/sree-sanak/minty/blob/main/sources/sms/import.js)
- [sources/_shared/progress.js](https://github.com/sree-sanak/minty/blob/main/sources/_shared/progress.js)
</details>

# 数据源导入

数据源导入是 Minty CRM 的核心功能模块，负责从多种外部平台收集联系人信息和交互记录。每个数据源（Source）都是独立的导入单元，遵循统一的数据写入规范，最终输出到 `data/<source>/` 目录下的结构化 JSON 文件。

## 系统架构

### 导入器层级结构

```
┌─────────────────────────────────────────────────────────────┐
│                    sources/ 目录结构                          │
├─────────────────────────────────────────────────────────────┤
│  whatsapp/export.js        实时 Web 端导入                   │
│  linkedin/import.js        LinkedIn ZIP 压缩包导入           │
│  linkedin/connect.js        LinkedIn 自动同步（实验性）        │
│  telegram/import.js        Telegram JSON 导出导入             │
│  email/import.js            Gmail/IMAP 邮件导入               │
│  google-contacts/import.js Google 通讯录 OAuth 导入           │
│  sms/import.js              短信平台导出导入                  │
│  apollo/enrich.js           Apollo 联系人丰富化（可选）        │
├─────────────────────────────────────────────────────────────┤
│  _shared/progress.js       统一的进度追踪模块                │
└─────────────────────────────────────────────────────────────┘
```

所有导入器共享 `sources/_shared/progress.js` 中的进度追踪机制，确保 UI 层能够统一展示各数据源的同步状态。

资料来源：[ARCHITECTURE.md]()

### 数据流向

```mermaid
graph TD
    A[用户启动导入器] --> B[数据源平台]
    B --> C[源数据获取]
    C --> D[数据解析与标准化]
    D --> E[data/&lt;source&gt;/]
    E --> F[crm/merge.js]
    F --> G[data/unified/]
    G --> H[统一联系人视图]
    G --> I[交互时间线]
```

资料来源：[ARCHITECTURE.md]()

## 支持的数据源

| 数据源 | 导入模式 | 认证方式 | 增量支持 | 入口命令 |
|--------|----------|----------|----------|----------|
| WhatsApp | 实时监听 | QR 码配对 | ✅ | `npm run whatsapp` |
| LinkedIn | 一次性 | 官方数据导出 ZIP | ❌ | `npm run linkedin` |
| LinkedIn Sync | 实验性 | 自动化登录 | ✅ | `npm run linkedin:connect` |
| Telegram | 一次性 | 官方 JSON 导出 | ❌ | `npm run telegram` |
| Email/Gmail | 增量 | OAuth 2.0 / IMAP | ✅ | OAuth 流程 |
| Google Contacts | 增量 | OAuth 2.0 | ✅ | OAuth 流程 |
| SMS | 一次性 | 平台导出格式 | ❌ | `npm run sms` |
| Apollo | 可选 | API 密钥 | - | 手动触发 |

资料来源：[ARCHITECTURE.md]()

## 进度追踪机制

### 统一进度文件

每个导入器在运行时会向其数据目录写入 `.progress.json` 文件，记录当前导入进度。

```json
{
  "source": "whatsapp",
  "step": "messages",
  "message": "正在同步 15/32: 产品团队群",
  "current": 15,
  "total": 32,
  "itemsProcessed": 2847,
  "startedAt": "2025-01-15T10:30:00.000Z",
  "updatedAt": "2025-01-15T10:35:22.456Z"
}
```

资料来源：[sources/_shared/progress.js:1-80]()

### 进度步骤定义

| step 值 | 含义 | 典型 message 示例 |
|---------|------|---------------------|
| `init` | 初始化 | "Starting…" |
| `contacts` | 正在同步联系人 | "Loading contacts…" |
| `messages` | 正在同步消息/交互 | "Syncing 15/32: 群组名" |
| `merging` | 合并到统一存储 | "Merging into unified store" |
| `done` | 完成 | "Import complete" |
| `error` | 错误 | 错误信息摘要 |

资料来源：[sources/_shared/progress.js:50-70]()

### 进度状态计算

进度文件中的 `active` 状态由 `step !== 'done' && step !== 'error'` 派生而来，用于前端判断同步是否仍在进行中。

## WhatsApp 导入

WhatsApp 导入器是唯一采用实时监听模式的源，使用 `whatsapp-web.js` 库通过 WebSocket 连接手机端应用。

### 核心流程

1. **首次运行**：显示 QR 码，用户需在 WhatsApp 手机端扫描
2. **会话恢复**：后续运行自动复用已存储的会话凭证
3. **增量同步**：仅拉取上次同步后的新消息

```javascript
// 关键参数
WHATSAPP_MSG_LIMIT=500  // 单次最多获取消息数（环境变量）
```

资料来源：[crm/server.js:150-180]()

### 输出文件结构

```
data/whatsapp/
├── chats.json        // 聊天列表元数据
├── contacts.json     // 联系人信息
├── metadata.json     // 同步会话信息
├── profile_pics/     // 头像缓存目录
└── .progress.json    // 进度文件
```

## LinkedIn 导入

### ZIP 导出模式

1. 用户在 LinkedIn 网站请求数据导出（Settings → Data Privacy → Get a copy of your data）
2. 选择 **Connections** 和 **Messages** 选项
3. 下载 ZIP 文件后拖入 Sources 视图，或指定目录：

```bash
LINKEDIN_EXPORT_DIR=/path/to/extracted npm run linkedin
```

### 自动同步模式（实验性）

该模式通过自动化浏览器操作实现 ToS 边界附近的登录抓取：

- 使用 headful 浏览器首次登录获取凭证
- 凭证缓存后以 headless 模式复用
- 状态存储在 `data/linkedin/` 目录

资料来源：[ARCHITECTURE.md]()

## Telegram 导入

Telegram 导出采用官方 Desktop 客户端的 JSON 格式。

### 导出步骤

1. Telegram Desktop → Settings → Advanced → Export Telegram Data
2. 选择 **Personal chats** 和 **Contacts**
3. 格式选择 **JSON**
4. 将 `result.json` 放入 Sources 视图

```bash
TELEGRAM_EXPORT_FILE=/path/to/result.json npm run telegram
```

### 解析能力

- 个人聊天记录
- 群组消息（含参与者列表）
- 联系人信息

## Email/Gmail 导入

### OAuth 认证流程（推荐）

1. 用户在 Sources 视图点击 "Connect Gmail"
2. 使用 Google OAuth Device Flow 完成授权
3. 权限范围为只读访问

需要配置以下环境变量：

```
GOOGLE_CLIENT_ID=<your-client-id>
GOOGLE_CLIENT_SECRET=<your-client-secret>
```

### IMAP 备选方案

支持任意提供商的 IMAP 协议：

```bash
EMAIL_HOST=imap.gmail.com
EMAIL_PORT=993
EMAIL_USER=your-email@gmail.com
EMAIL_PASS=app-password
```

## Google Contacts 导入

通过 Google People API 进行 OAuth 增量同步，自动获取用户通讯录中的：

- 姓名
- 电话号码
- 邮箱地址
- 组织信息（公司、职位）
- 地址信息

## SMS 导入

SMS 导入器解析平台导出的 XML 格式数据，支持：

- 普通短信（SMS）
- 多媒体消息（MMS）
- 通话记录（Call Log）

### 解析数据类型

| 类型 | 字段 | 说明 |
|------|------|------|
| SMS/MMS | `body`, `direction`, `timestamp` | 消息内容和方向 |
| MMS | `hasMedia`, `contactName` | 含媒体标识 |
| Call Log | `callKind`, `duration` | 通话类型和时长 |

资料来源：[sources/sms/import.js:60-100]()

## Apollo 联系人丰富化

Apollo 是一个可选的付费数据丰富服务，用于增强现有联系人的公开信息：

- 公司位置
- 职业头衔
- Twitter 链接
- 职业履历

此模块独立于主导入流程，需手动触发：

```bash
node sources/apollo/enrich.js
```

## 数据合并

### merge.js 核心职责

所有导入器完成后，运行 `crm/merge.js` 执行统一合并：

1. **数据标准化**：统一电话、邮箱、姓名的格式
2. **跨源去重**：识别同一人的不同来源记录
3. **构建交互时间线**：聚合所有源的交互事件

```bash
node crm/merge.js
```

### 输出文件

```
data/unified/
├── contacts.json          // 统一联系人记录
├── interactions.json      // 聚合交互事件
├── match_overrides.json   // 手动匹配覆盖
└── group-memberships.json  // 群组关系
```

资料来源：[ARCHITECTURE.md]()

## 环境变量配置

| 变量名 | 适用源 | 用途 |
|--------|--------|------|
| `CRM_DATA_DIR` | 全局 | 数据根目录 |
| `WHATSAPP_MSG_LIMIT` | WhatsApp | 单次消息拉取上限 |
| `LINKEDIN_EXPORT_DIR` | LinkedIn | ZIP 解压路径 |
| `TELEGRAM_EXPORT_FILE` | Telegram | JSON 导出文件路径 |
| `GOOGLE_CLIENT_ID` | Gmail/Contacts | OAuth 客户端 ID |
| `EMAIL_*` | Email | IMAP 连接参数 |

## 命令速查

| 命令 | 功能 |
|------|------|
| `npm run whatsapp` | 启动 WhatsApp 导入器 |
| `npm run linkedin` | 启动 LinkedIn ZIP 导入器 |
| `npm run telegram` | 启动 Telegram 导入器 |
| `npm run sms` | 启动 SMS 导入器 |
| `npm run crm` | 启动 CRM 服务端（含同步 API） |

## 贡献指南

### 添加新导入器

1. 复制现有简单导入器作为模板（如 `sources/telegram/import.js`）
2. 遵循目录结构：`data/<source>/` 写入 JSON 文件
3. 使用 `sources/_shared/progress.js` 报告进度
4. 在 `crm/merge.js` 中添加对应的合并逻辑

资料来源：[ARCHITECTURE.md]()

### 性能优化

当数据集较大时，合并路径通常是性能瓶颈。建议使用 `tests/integration/` 中的基于 fixture 的性能测试进行验证。

---

<a id='page-contact-merging'></a>

## 联系人合并与去重

### 相关页面

相关主题：[数据源导入](#page-data-sources), [数据存储结构](#page-data-storage)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [crm/match.js](https://github.com/sree-sanak/minty/blob/main/crm/match.js)
- [crm/merge.js](https://github.com/sree-sanak/minty/blob/main/crm/merge.js)
- [crm/identity-candidates.js](https://github.com/sree-sanak/minty/blob/main/crm/identity-candidates.js)
- [crm/MATCHING.md](https://github.com/sree-sanak/minty/blob/main/crm/MATCHING.md)
- [crm/schema.js](https://github.com/sree-sanak/minty/blob/main/crm/schema.js)
- [sources/_shared/progress.js](https://github.com/sree-sanak/minty/blob/main/sources/_shared/progress.js)
</details>

# 联系人合并与去重

## 概述

联系人合并与去重是 Minty CRM 的核心功能之一，负责将来自不同数据源（如 Email、LinkedIn、Telegram、Google Contacts 等）的联系人记录整合为统一视图。当用户从多个平台导入数据时，同一个人可能在不同来源中以不同的名字、电话或邮箱形式出现，合并系统通过智能匹配算法识别这些重复记录并将其合并，同时保留各来源的原始信息。

该模块在架构中处于数据处理的核心位置——所有数据源的导入完成后，最终都会经过合并流程生成 `data/unified/contacts.json` 和 `data/unified/interactions.json`，为上层业务功能（如目标追踪、会议总结、人生事件识别）提供统一的联系人数据源。资料来源：[ARCHITECTURE.md]()

## 核心组件

Minty 的联系人合并与去重系统由以下几个核心文件组成：

| 组件文件 | 职责 | 关键功能 |
|---------|------|---------|
| `crm/merge.js` | 数据合并主入口 | 加载各源数据、规范化、写入统一存储 |
| `crm/match.js` | 跨源匹配算法 | 根据规则识别潜在重复联系人 |
| `crm/identity-candidates.js` | 身份候选生成 | 生成待匹配的联系人候选对 |
| `crm/MATCHING.md` | 匹配规则规范文档 | 定义匹配逻辑与置信度标准 |
| `crm/schema.js` | 数据模型定义 | 规范 Contact 和 Interaction 的数据结构 |

资料来源：[ARCHITECTURE.md]()

## 数据流架构

```mermaid
graph TD
    A[数据源导入] --> B[sources/email/import.js]
    A --> C[sources/linkedin/import.js]
    A --> D[sources/telegram/import.js]
    A --> E[sources/google-contacts/import.js]
    
    B --> F[data/&lt;source&gt;/]
    C --> F
    D --> F
    E --> F
    
    F --> G[crm/merge.js]
    G --> H[match.js 匹配算法]
    H --> I[match_overrides.json 人工干预]
    I --> G
    
    G --> J[data/unified/contacts.json]
    G --> K[data/unified/interactions.json]
    
    J --> L[上层业务功能]
    K --> L
    
    L --> M[calendar.js 会议追踪]
    L --> N[goal-retro.js 目标回顾]
    L --> O[life-events.js 人生事件]
    L --> P[digest.js 周报摘要]
```

## 数据模型

### Contact 统一数据结构

合并后的联系人记录包含以下核心字段：

```javascript
{
  id: string,                    // 唯一标识符
  name: string,                  // 规范化的姓名
  phones: string[],              // 电话号码数组
  emails: string[],              // 邮箱数组
  sources: {                     // 各来源的原始数据
    [sourceName]: {
      name?: string,
      phones?: string[],
      emails?: string[],
      company?: string,
      position?: string,
      // ... 其他来源特定字段
    }
  },
  relationshipScore: number,      // 关系评分 0-100
  daysSinceContact: number,       // 最后联系天数
  activeChannels: string[],      // 活跃联系方式
  interactionCount: number       // 交互次数
}
```

资料来源：[crm/schema.js]()

### Interaction 交互记录结构

```javascript
{
  id: string,
  contactId: string,
  source: string,
  timestamp: string,
  type: 'message' | 'meeting' | 'call' | 'email',
  subject?: string,
  body?: string,
  participants?: string[]
}
```

## 匹配算法详解

### 匹配置信度等级

系统采用三级置信度体系判断两个联系人记录是否指向同一人：

| 置信度 | 说明 | 处理方式 | 资料来源 |
|--------|------|---------|---------|
| **confirmed** | 多个高置信度信号完全吻合 | 自动合并，无需人工确认 | [crm/MATCHING.md]() |
| **likely** | 存在多个支持信号，证据充分 | 自动合并，打印统计信息 | [crm/MATCHING.md]() |
| **possible** | 存在一些匹配信号但不够确定 | 跳过合并，列入待审查列表 | [crm/MATCHING.md]() |

### 匹配信号类型

匹配算法考察以下信号维度：

**强信号（权重高）：**
- 邮箱地址完全匹配
- 电话号码完全匹配
- 多个联系方式组合匹配

**中强信号（权重中）：**
- 姓名相似度（编辑距离）
- 公司名称匹配
- LinkedIn 个人资料 URL 匹配

**辅助信号（权重低）：**
- 地理位置一致性
- 职业/职位相似度
- 共同交互事件

### 匹配输出示例

```json
[
  {
    "confidence": "confirmed",
    "ids": ["c_0001", "c_0012"],
    "reason": "邮箱地址完全一致",
    "sources_linked": ["email", "linkedin"]
  },
  {
    "confidence": "likely",
    "ids": ["c_0003", "c_0088"],
    "reason": "姓名完全匹配，公司一致，LinkedIn 位置匹配",
    "sources_linked": ["whatsapp", "linkedin"]
  },
  {
    "confidence": "possible",
    "ids": ["c_0105", "c_2341"],
    "reason": "名字匹配但该名字非常常见；缺少其他佐证信号",
    "sources_linked": ["whatsapp", "linkedin"]
  }
]
```

资料来源：[crm/MATCHING.md]()

## 合并流程

### 标准合并流程

```mermaid
graph LR
    A[运行各数据源导入器] --> B[npm run email<br/>npm run telegram<br/>npm run linkedin]
    
    B --> C[生成各源原始数据]
    C --> D[运行 merge.js]
    
    D --> E{存在 match_overrides?}
    E -->|是| F[加载人工干预配置]
    E -->|否| G[跳过覆盖加载]
    
    F --> H[按 confirmed/likely<br/>强制合并指定记录]
    G --> I[执行匹配算法]
    
    H --> J[生成统一联系人列表]
    I --> J
    
    J --> K[写入 unified/contacts.json]
    J --> L[写入 unified/interactions.json]
    
    K --> M[生成匹配统计报告]
    L --> M
```

### 关键配置：match_overrides.json

当自动匹配算法无法准确判断，或用户希望手动指定某些记录的合并关系时，可通过 `match_overrides.json` 进行干预：

```json
{
  "confirmed": [
    { "ids": ["c_0001", "c_0012"], "reason": "用户确认为同一人" }
  ],
  "likely": [
    { "ids": ["c_0003", "c_0088"], "reason": "邮箱前缀相同且公司一致" }
  ],
  "possible": [
    { "ids": ["c_0105", "c_2341"], "reason": "待进一步核实" }
  ]
}
```

**覆盖规则处理逻辑：**

| 覆盖类型 | 算法行为 |
|---------|---------|
| confirmed | 无论算法结果如何，强制将两条记录合并为同一联系人 |
| likely | 将两条记录合并，但在统计报告中标注为"人工确认" |
| possible | 跳过自动合并，标记为需人工审查（通过 `npm run review`） |

资料来源：[crm/MATCHING.md]()

## 合并执行命令

### 基本合并命令

```bash
# 标准合并流程
node crm/merge.js

# 带详细输出
npm run merge

# 仅检查匹配状态（不写入）
npm run match:dry-run
```

### 完整导入与合并流程

```bash
# 1. 导入各数据源
npm run email          # 导入 Email 数据
npm run telegram       # 导入 Telegram 数据
npm run linkedin       # 导入 LinkedIn 数据

# 2. 执行合并
node crm/merge.js

# 3. 查看统计
npm run stats
```

### 审查待定匹配

对于置信度为 "possible" 的匹配记录，系统提供交互式审查界面：

```bash
npm run review
```

该命令会列出所有待审查的匹配对，用户可选择确认或拒绝每一条匹配。

资料来源：[crm/MATCHING.md]()

## 匹配状态管理

### 进度追踪

合并过程中，系统会通过 `sources/_shared/progress.js` 模块追踪处理进度：

```javascript
P.startProgress(DATA_DIR, 'merge', { step: 'init', message: '开始合并…' });
P.updateProgress(DATA_DIR, 'merge', { step: 'matching', message: '执行匹配…', current: 5, total: 10 });
P.updateProgress(DATA_DIR, 'merge', { step: 'merging', message: '合并记录…' });
```

进度文件存储在 `data/.progress/merge.json`，包含以下字段：

| 字段 | 类型 | 说明 |
|------|------|------|
| step | string | 当前处理阶段 |
| message | string | 状态消息 |
| current | number | 当前进度 |
| total | number | 总任务数 |
| startedAt | string | ISO 时间戳 |
| updatedAt | string | ISO 时间戳 |
| errors | array | 错误列表 |

### 错误处理

系统内置敏感信息过滤机制，防止在错误日志中泄露凭据或个人信息：

```javascript
function redactErrorText(value) {
    return String(value)
        .replace(/^\s*at\s+[^\n]+/gm, '[redacted-stack]')
        .replace(/(["'`])[^"'`\n]*[\\/][^"'`\n]*\1/g, '$1[redacted-path]$1')
        .replace(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi, '[redacted-email]')
        .replace(/\bauthorization\s*[:=]\s*Bearer\s+[^\s,;]+/gi, '[redacted-credential]');
}
```

资料来源：[sources/_shared/progress.js]()

## 数据新鲜度与置信度

### 联系人数据置信度评估

系统会根据数据来源和最后同步时间计算每条联系人的数据置信度：

| 置信度等级 | 条件 | 说明 |
|-----------|------|------|
| high | 多个活跃来源 + 最近同步 | 数据完整可靠 |
| medium | 单个活跃来源 + 最近同步 | 基本可靠 |
| low | 无交互记录或数据过旧 | 需手动核实 |

```javascript
function getContactDataConfidence(contact, syncState, now = Date.now()) {
    const activeSources = Object.keys(contact.sources || {}).filter(s => contact.sources[s]);
    if (activeSources.length === 0) return { level: 'low', reason: '无来源数据' };
    // ... 更多评估逻辑
}
```

资料来源：[crm/staleness.js]()

### 陈旧数据警告

系统会自动检测数据新鲜度并生成警告：

| 同步状态 | 警告级别 | 用户提示 |
|---------|---------|---------|
| 同步中 | - | - |
| 同步成功（< 24h） | - | "数据最新" |
| 同步成功（1-3天） | warning | "数据可能略旧" |
| 同步成功（> 3天） | error | "数据可能过时" |
| 同步错误 | error | "同步失败，请检查配置" |

## 扩展开发指南

### 添加新的数据源导入器

参考 `sources/telegram/import.js` 的文件结构：

1. 创建 `sources/<new-source>/import.js`
2. 实现数据抓取和标准化逻辑
3. 写入 `data/<new-source>/contacts.json`
4. 更新 `crm/merge.js` 添加新数据源加载
5. 更新 `crm/match.js` 添加新源的匹配规则

### 自定义匹配规则

在 `crm/match.js` 中添加新的匹配信号检测：

```javascript
// 示例：添加公司域名匹配
function matchByEmailDomain(contactA, contactB) {
    const domainsA = contactA.emails.map(e => e.split('@')[1]);
    const domainsB = contactB.emails.map(e => e.split('@')[1]);
    return domainsA.some(d => domainsB.includes(d));
}
```

### 添加测试用例

在 `tests/` 目录创建匹配测试：

```bash
# 运行匹配相关测试
npm test -- --grep "match"

# 添加新测试文件
# tests/match.test.js
```

## 常见问题排查

### 合并后联系人数量异常减少

**可能原因：**
- 匹配规则过于激进，将不应合并的记录错误合并
- match_overrides.json 中存在误配置

**解决方案：**
1. 检查 `data/unified/` 中的合并结果
2. 审阅 `match_overrides.json` 配置
3. 使用 `npm run review` 重新审查匹配决策

### 预期匹配未被识别

**可能原因：**
- 数据源格式不规范（如姓名包含特殊字符）
- 缺少共同信号（如双方从未通过邮件交互）

**解决方案：**
1. 规范化导入数据
2. 在 match_overrides.json 中添加 confirmed 覆盖
3. 手动审查 possible 匹配队列

### 数据新鲜度显示错误

**可能原因：**
- 同步状态文件格式不一致
- 未正确写入 lastSyncAt 字段

**解决方案：**
1. 检查 `data/unified/sync-state.json`
2. 确保各导入器正确更新同步状态
3. 查看 `crm/agent-source-health.js` 诊断输出

## 相关文档

- [匹配规范文档](./MATCHING.md) - 匹配算法的完整技术规范
- [架构概述](./ARCHITECTURE.md) - 项目整体架构说明
- [数据源导入器](../sources/) - 各数据源导入实现详情
- [同步系统](./sync.js) - 自动化数据同步机制

---

<a id='page-data-storage'></a>

## 数据存储结构

### 相关页面

相关主题：[联系人合并与去重](#page-contact-merging), [架构总览](#page-architecture-overview)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [crm/export.js](https://github.com/sree-sanak/minty/blob/main/crm/export.js)
- [crm/sync.js](https://github.com/sree-sanak/minty/blob/main/crm/sync.js)
- [crm/server.js](https://github.com/sree-sanak/minty/blob/main/crm/server.js)
- [crm/merge.js](https://github.com/sree-sanak/minty/blob/main/crm/merge.js)
- [crm/schema.js](https://github.com/sree-sanak/minty/blob/main/crm/schema.js)
- [crm/staleness.js](https://github.com/sree-sanak/minty/blob/main/crm/staleness.js)
- [sources/_shared/progress.js](https://github.com/sree-sanak/minty/blob/main/sources/_shared/progress.js)
- [sources/whatsapp/export.js](https://github.com/sree-sanak/minty/blob/main/sources/whatsapp/export.js)
</details>

# 数据存储结构

## 概述

Minty 项目采用**本地优先（Local-first）**的架构理念，所有数据均存储在用户本地的文件系统中，不依赖任何云端数据库服务。项目的核心设计原则是"**文件系统即数据库**"，数据通过导入器从各个来源收集，经过去重和合并后，形成统一的视图供上层应用使用。资料来源：[ARCHITECTURE.md]()

## 核心设计原则

| 原则 | 说明 |
|------|------|
| 本地优先 | 数据永不离开用户机器，核心功能不涉及任何网络传输 |
| 文件系统即数据库 | 使用 JSON 文件作为持久化存储，无需安装数据库 |
| 增量同步 | 部分导入器支持增量更新，避免重复导出 |
| 原子写入 | 写入操作使用临时文件+重命名确保数据完整性 |
| 可导出加密备份 | 支持生成加密的便携式备份包 |

资料来源：[ARCHITECTURE.md]()

---

## 数据目录布局

```
data/                              # 运行时数据目录（gitignored）
├── whatsapp/                     # WhatsApp 导出数据
│   ├── chats.json               # 聊天记录
│   ├── contacts.json            # 联系人列表
│   ├── metadata.json            # 元数据（包含 last_export_unix）
│   ├── profile_pics/            # 联系人头像
│   └── .progress.json          # 同步进度记录
├── linkedin/                     # LinkedIn 数据
│   ├── export/                  # 用户上传的 ZIP 导出包
│   ├── parsed.csv               # 解析后的 CSV 数据
│   └── .progress.json
├── telegram/                     # Telegram 导出数据
│   ├── result.json
│   └── .progress.json
├── email/                        # 邮件数据（按账户分目录）
│   └── <account>/
├── sms/                          # 短信数据（按平台分目录）
│   └── <platform>/
├── google-contacts/             # Google 通讯录
│   └── .progress.json
├── apollo/                       # Apollo 数据充实（可选）
│   └── .progress.json
└── unified/                      # 合并后的统一数据（核心输出）
    ├── contacts.json            # 统一联系人记录
    ├── interactions.json        # 交互时间线
    ├── insights.json            # AI 洞察结果
    ├── goals.json               # 目标数据
    ├── group-memberships.json    # 群组成员关系
    ├── query-index.json         # 搜索索引
    ├── digest.json              # 摘要数据
    ├── match_overrides.json     # 匹配覆盖规则
    └── .progress.json
```

可通过环境变量 `CRM_DATA_DIR` 覆盖根目录，个别导入器支持各自的导出目录环境变量（如 `*_EXPORT_DIR`）。

资料来源：[ARCHITECTURE.md]()

---

## 数据模型

### Contact（联系人）记录

联系人模型定义在 `crm/schema.js` 中，包含以下核心字段：

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | string | 全局唯一标识符 |
| `source` | string | 数据来源（whatsapp/linkedin/telegram/email 等） |
| `name` | string | 规范化后的姓名 |
| `phones` | string[] | 标准化后的电话号码列表 |
| `emails` | string[] | 标准化后的邮箱列表 |
| `company` | string | 公司名称 |
| `title` | string | 职位 |
| `tags` | string[] | 标签（如 investor、founder） |
| `lastInteraction` | ISO date | 最近一次交互时间 |
| `stale` | boolean | 数据是否过期标记 |

资料来源：[ARCHITECTURE.md]()

### Interaction（交互）记录

交互记录描述与联系人的互动历史：

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | string | 交互唯一标识 |
| `contactId` | string | 关联的联系人 ID |
| `type` | string | 交互类型（message/call/meeting/email） |
| `timestamp` | ISO date | 交互时间 |
| `source` | string | 数据来源 |
| `summary` | string | 交互摘要 |
| `metadata` | object | 附加元数据 |

资料来源：[crm/schema.js]()

---

## 数据流架构

```mermaid
graph TD
    A[用户运行导入器] --> B[源数据导入器<br/>sources/&lt;src&gt;/import.js]
    B --> C[写入数据源目录<br/>data/&lt;source&gt;/]
    
    D[定时或手动触发] --> E[合并进程<br/>crm/merge.js]
    C --> E
    
    E --> F[数据规范化<br/>phones/emails/names]
    F --> G[跨源去重<br/>crm/match.js]
    G --> H[构建统一时间线]
    H --> I[写入统一存储<br/>data/unified/]
    
    I --> J[HTTP 服务器<br/>crm/server.js]
    J --> K[Web UI / API]
    
    I --> L[AI 洞察生成<br/>crm/ai.js]
    L --> I
    
    M[同步监控<br/>crm/sync.js] --> D
    M --> B
```

### 数据生命周期

1. **导入阶段**：用户运行导入器，将数据从各平台导出并写入 `data/<source>/`
2. **合并阶段**：`crm/merge.js` 加载各源数据，执行规范化、去重、合并
3. **存储阶段**：结果写入 `data/unified/contacts.json` 和 `interactions.json`
4. **服务阶段**：`crm/server.js` 读取统一存储，通过 HTTP API 提供数据
5. **洞察阶段**：AI 模块基于统一数据生成洞察和摘要

资料来源：[ARCHITECTURE.md]()

---

## 同步与进度追踪

### 进度记录机制

每个导入器使用 `sources/_shared/progress.js` 统一记录同步进度：

| 字段 | 说明 |
|------|------|
| `source` | 数据源标识 |
| `step` | 当前步骤（init/contacts/messages/merging/done/error） |
| `message` | 状态描述 |
| `current` / `total` | 进度数值 |
| `itemsProcessed` | 已处理条目数 |
| `errors` | 错误列表 |
| `startedAt` / `updatedAt` | 时间戳 |
| `error` | 错误详情对象 |

进度文件位置：`data/<source>/.progress.json`

### 原子写入机制

```javascript
function safeWrite(filePath, payload) {
    const tmp = filePath + '.tmp-' + process.pid + '-' + Date.now();
    fs.writeFileSync(tmp, JSON.stringify(payload));
    fs.renameSync(tmp, filePath);
}
```

写入操作先写入临时文件，再原子重命名，确保数据完整性。写入失败不会导致导入器崩溃。

资料来源：[sources/_shared/progress.js]()

### 数据过期检测

`crm/staleness.js` 实现了联系人数据过期检测机制：

| 来源类型 | 过期阈值 |
|----------|----------|
| WhatsApp | 14 天 |
| Email | 30 天 |
| LinkedIn | 90 天 |
| Google Contacts | 60 天 |

检测结果影响 UI 中的警告提示和数据置信度评分。

资料来源：[crm/staleness.js]()

---

## 导出与备份

### 导出包格式

`crm/export.js` 支持生成便携式加密备份：

| 字段 | 说明 |
|------|------|
| `version` | 导出格式版本（当前为 1） |
| `exportedAt` | 导出时间戳 |
| `contacts` | 联系人数据 |
| `interactions` | 交互数据 |
| `insights` | AI 洞察（可选） |
| `goals` | 目标数据（可选） |
| `groupMemberships` | 群组关系（可选） |
| `syncState` | 同步状态 |
| `insightsAt` | 洞察生成时间 |
| `stats` | 统计摘要 |

### 加密方案

| 参数 | 值 | 说明 |
|------|-----|------|
| `SALT_BYTES` | 16 | PBKDF2 盐值长度 |
| `IV_BYTES` | 12 | AES-GCM 初始向量 |
| `TAG_BYTES` | 16 | 认证标签长度 |
| `KDF_ITERS` | 200000 | PBKDF2 迭代次数 |

加密模式使用 **AES-256-GCM**，密钥派生使用 **PBKDF2-SHA256**。

资料来源：[crm/export.js]()

### 导出方式

| 命令 | 说明 |
|------|------|
| `npm run export` | CLI 导出 |
| `GET /api/export` | HTTP API 导出 |
| `POST /api/export` | 带请求体的导出 |

---

## API 接口

| 端点 | 方法 | 说明 |
|------|------|------|
| `/api/sources/:key/progress` | GET | 获取单个数据源进度 |
| `/api/sync/progress` | GET | 获取所有数据源进度 |
| `/api/export` | GET/POST | 导出/加密导出 |

资料来源：[crm/server.js]()

---

## 环境变量配置

| 变量 | 说明 | 默认值 |
|------|------|--------|
| `CRM_DATA_DIR` | 数据根目录 | `./data` |
| `WHATSAPP_EXPORT_DIR` | WhatsApp 导出目录 | `data/whatsapp/export` |
| `LINKEDIN_EXPORT_DIR` | LinkedIn 导出目录 | `data/linkedin/export` |
| `AI_BACKEND` | AI 后端选择 | `claude` / `ollama` |

资料来源：[ARCHITECTURE.md]()

---

## 安全特性

1. **本地优先**：核心功能不包含任何云端 LLM 集成，所有 AI 推理均为本地或用户主动选择
2. **敏感信息脱敏**：进度记录模块包含 `redactErrorText()` 函数，自动脱敏邮箱、凭证、文件路径等敏感信息
3. **加密导出**：可选 AES-256-GCM 加密保护备份数据
4. **增量更新**：WhatsApp 等支持增量导出，减少数据暴露窗口

资料来源：[crm/export.js](), [sources/_shared/progress.js](), [sources/whatsapp/export.js]()

---

<a id='page-mcp-integration'></a>

## MCP 代理集成

### 相关页面

相关主题：[网络查询系统](#page-network-query), [快速开始](#page-quick-start)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [scripts/minty-mcp-server.js](https://github.com/sree-sanak/minty/blob/main/scripts/minty-mcp-server.js)
- [hermes/minty-network-memory/SKILL.md](https://github.com/sree-sanak/minty/blob/main/hermes/minty-network-memory/SKILL.md)
- [README.md](https://github.com/sree-sanak/minty/blob/main/README.md)
- [ARCHITECTURE.md](https://github.com/sree-sanak/minty/blob/main/ARCHITECTURE.md)
- [docs/OPENCLAW_HERMES.md](https://github.com/sree-sanak/minty/blob/main/docs/OPENCLAW_HERMES.md)
</details>

# MCP 代理集成

## 概述

MCP（Model Context Protocol）代理集成是 Minty 项目为 AI 代理提供的标准化接口层。通过 MCP 协议，外部代理系统（如 OpenClaw、Claude Code、Ollama）可以直接调用 Minty 的联系人检索和关系管理能力，无需直接访问底层数据文件。 资料来源：[README.md]()

Minty 采用本地优先架构，所有联系人数据存储在本地 `data/` 目录中，MCP 服务以独立的 stdio 进程运行，确保数据不离开用户的机器。 资料来源：[ARCHITECTURE.md]()

## 核心架构

### 系统组件

```mermaid
graph TD
    subgraph 外部代理 ["外部代理系统"]
        OC[OpenClaw]
        HM[Hermes]
        CC[Claude Code CLI]
    end
    
    subgraph MCP层 ["MCP 协议层"]
        SERVER[scripts/minty-mcp-server.js]
    end
    
    subgraph 核心引擎 ["Minty 核心引擎"]
        RETRIEVAL[crm/agent-retrieval.js]
        MATCH[crm/match.js]
        SEARCH[crm/search.js]
    end
    
    subgraph 数据存储 ["本地数据存储"]
        CONTACTS[data/unified/contacts.json]
        INTERACTIONS[data/unified/interactions.json]
    end
    
    OC --> SERVER
    HM --> SERVER
    CC --> SERVER
    SERVER --> RETRIEVAL
    RETRIEVAL --> MATCH
    RETRIEVAL --> SEARCH
    MATCH --> CONTACTS
    SEARCH --> INTERACTIONS
```

### MCP 服务入口

`scripts/minty-mcp-server.js` 是 MCP 服务的核心入口文件，负责注册所有可用的工具并处理代理请求。服务以 stdio 模式运行，适合与 AI 代理进行本地集成。 资料来源：[hermes/minty-network-memory/SKILL.md]()

## 可用工具

MCP 服务暴露四个核心工具，供外部代理调用：

| 工具名称 | 功能描述 | 主要参数 |
|---------|---------|---------|
| `search_network` | 自然语言网络搜索 | `query`, `limit`, `source`/`sources` |
| `person_context` | 查询特定联系人详情 | `person`, `limit` |
| `workflow_brief` | 生成目标导向简报 | `goal`, `limit` |
| `source_health` | 检查数据源健康状态 | `source`/`sources`/`query` |

### search_network

用于自由形式的网络查询，返回排名靠前的联系人及其关联证据。

```json
{
  "query": "investors in London who know about AI",
  "limit": 5
}
```

支持按来源过滤：

```json
{
  "query": "people I discussed Telegram bots with",
  "source": "telegram",
  "limit": 5
}
```

### person_context

查询特定联系人的详细信息，包括关系上下文、亲密度评分和证据。

```json
{
  "person": "Alice Müller",
  "limit": 3
}
```

### workflow_brief

生成以目标为导向的简报，帮助代理找到能够帮助完成特定任务的人。

```json
{
  "goal": "Find EU crypto insurance distribution partners",
  "limit": 5
}
```

### source_health

在执行来源特定查询前进行预检查，确保数据源处于可用状态。

```json
{ "source": "telegram" }
{ "sources": ["telegram", "slack"] }
{ "query": "who from Telegram knows DeFi?" }
```

## 配置与部署

### 环境变量

| 变量名 | 说明 | 默认值 |
|-------|------|-------|
| `CRM_DATA_DIR` | 数据目录路径 | `./data` |
| `MINTY_USER_UUID` | 用户唯一标识 | 自动生成 |
| `AI_BACKEND` | AI 后端类型 | `claude` |

### AI 后端选择

Minty 支持两种本地 AI 后端：

1. **Claude Code CLI（默认）**：调用 `claude --print` 进行推理，免费但会将提示发送至 Anthropic 服务器
2. **Ollama**：通过设置 `AI_BACKEND=ollama` 启用，支持本地模型如 `qwen2.5:7b`，完全离线运行

资料来源：[README.md]()

### 启动 MCP 服务

```bash
# 基础启动
npm run mcp

# 指定数据目录
CRM_DATA_DIR=./data-demo npm run mcp

# 服务模式（守护进程）
npm run service
MINTY_USER_UUID=abc npm run service
```

## 与外部代理集成

### OpenClaw + Hermes 集成

完整的集成配置文档位于 `docs/OPENCLAW_HERMES.md`。核心步骤包括：

1. 注册 `scripts/minty-mcp-server.js` 为 stdio MCP 服务器
2. 配置代理系统连接到本地 MCP 端点
3. 设置数据目录环境变量

```json
{
  "mcpServers": {
    "minty": {
      "command": "node",
      "args": ["/root/.hermes/workspace/minty/scripts/minty-mcp-server.js"],
      "timeout": 60,
      "connect_timeout": 20
    }
  }
}
```

资料来源：[hermes/minty-network-memory/SKILL.md]()

### Claude Code 代理支持

Claude Code 代理可以直接通过 MCP 工具访问联系人网络：

```bash
CRM_DATA_DIR=./data-demo npm run agent -- "who can help with crypto insurance"
```

### 演示模式

使用演示数据快速验证集成是否正常工作：

```bash
npm run seed:demo
npm run mcp
npm run agent -- "investors in London"
```

资料来源：[README.md]()

## 就绪状态检查

Minty 提供三个就绪级别用于评估集成状态：

| 级别 | 描述 | 验证命令 |
|-----|------|---------|
| Demo-ready | 演示数据可用 | `npm run seed:demo && npm run mcp` |
| Dogfood-ready | 真实本地数据可用 | `npm run memory:refresh` |
| Hermes-native | 完整集成就绪 | `npm run hermes:doctor` |

执行健康检查：

```bash
npm run hermes:doctor
```

资料来源：[hermes/minty-network-memory/SKILL.md]()

## 数据安全与隐私

MCP 服务运行在本地，所有联系人数据存储在用户本地磁盘的 `data/` 目录中。服务不进行遥测、不收集分析数据、不与外部服务器通信。 资料来源：[README.md]()

### 敏感信息处理

在处理联系人数据和生成建议时，MCP 服务会自动过滤以下敏感信息：

- 邮箱地址（显示为 `[redacted-email]`）
- Bearer 令牌和认证凭证
- 文件路径信息
- 堆栈跟踪信息

## 错误处理与调试

### 常见问题排查

| 问题 | 可能原因 | 解决方案 |
|-----|---------|---------|
| MCP 连接超时 | 服务未启动 | 执行 `npm run mcp` |
| 数据源返回空结果 | 数据源过期或未导入 | 执行 `npm run memory:refresh` |
| 认证失败 | 环境变量未设置 | 检查 `AI_BACKEND` 配置 |

### 源健康预检

在执行来源特定查询前，始终建议调用 `source_health` 检查数据源状态：

- **Fresh**：数据最近有更新
- **Evidence-bearing**：有足够的交互证据
- **Stale**：数据过期，需要刷新
- **Empty**：无数据导入

如果数据源状态为 stale 或 empty，应返回诚实的低置信度回答，而非虚构信息。 资料来源：[hermes/minty-network-memory/SKILL.md]()

## 扩展开发

### 添加新工具

在 `scripts/minty-mcp-server.js` 中注册新工具需要：

1. 在工具注册表中添加条目
2. 实现工具处理器函数
3. 更新 `hermes/minty-network-memory/SKILL.md` 中的文档
4. 添加相应的集成测试

### 工具维护契约

`scripts/minty-mcp-server.js` 是暴露 MCP 工具的事实来源（source of truth）。任何添加、移除或重命名工具的 PR 必须同步更新相关文档和技能说明。 资料来源：[hermes/minty-network-memory/SKILL.md]()

## 相关文档

- [Minty 架构概览](./ARCHITECTURE.md)
- [OpenClaw + Hermes 集成指南](./docs/OPENCLAW_HERMES.md)
- [代理检索引擎](./crm/agent-retrieval.js)
- [联系人匹配算法](./crm/match.js)

---

<a id='page-network-query'></a>

## 网络查询系统

### 相关页面

相关主题：[MCP 代理集成](#page-mcp-integration)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [crm/query.js](https://github.com/sree-sanak/minty/blob/main/crm/query.js)
- [crm/network-query.js](https://github.com/sree-sanak/minty/blob/main/crm/network-query.js)
- [crm/query-reasons.js](https://github.com/sree-sanak/minty/blob/main/crm/query-reasons.js)
- [crm/search.js](https://github.com/sree-sanak/minty/blob/main/crm/search.js)
- [crm/hybrid-index.js](https://github.com/sree-sanak/minty/blob/main/crm/hybrid-index.js)
</details>

# 网络查询系统

## 概述

网络查询系统（Network Query System）是 Minty CRM 的核心检索引擎，负责通过自然语言或结构化查询从用户的人际网络中快速定位相关联系人及其交互记录。该系统整合了来自多个数据源（WhatsApp、LinkedIn、Telegram、Email、Google Contacts 等）的统一数据，提供语义化的网络搜索能力，使用户能够以自然对话的方式回答"我和谁讨论过 X 话题"、"在某个活动中见过哪些人"等查询需求。

网络查询系统的设计目标是将散落在不同通讯平台中的碎片化人际关系重新编织成可检索、可分析的网络图谱，支持从简单的人名搜索到复杂的多条件组合查询。资料来源：[ARCHITECTURE.md](https://github.com/sree-sanak/minty/blob/main/ARCHITECTURE.md)

## 架构概览

网络查询系统采用分层架构，从底层到顶层依次为：数据索引层、查询解析层、匹配引擎层和 API 接口层。各层职责明确，通过标准化的数据结构进行通信。

```mermaid
graph TD
    A[用户查询] --> B[查询解析层<br/>query-reasons.js]
    B --> C[自然语言理解<br/>分词/意图识别]
    C --> D[混合索引层<br/>hybrid-index.js]
    D --> E[匹配引擎层<br/>search.js]
    E --> F[结果排序与过滤]
    F --> G[API 接口层<br/>network-query.js]
    G --> H[返回结果]
    
    I[统一数据存储<br/>data/unified/] --> D
    J[交互索引<br/>interactions.json] --> E
```

### 核心组件职责

| 组件 | 文件路径 | 主要职责 |
|------|----------|----------|
| 查询解析 | `crm/query-reasons.js` | 分析查询语句，提取关键词、过滤条件和排序需求 |
| 混合索引 | `crm/hybrid-index.js` | 构建和维护联系人与交互记录的倒排索引 |
| 搜索匹配 | `crm/search.js` | 执行关键词匹配、模糊搜索和相关性评分 |
| 网络查询 | `crm/network-query.js` | 提供自然语言查询接口，处理复杂检索场景 |
| CLI 查询 | `crm/query.js` | 命令行统计和搜索功能 |

资料来源：[ARCHITECTURE.md](https://github.com/sree-sanak/minty/blob/main/ARCHITECTURE.md)

## 查询解析机制

### query-reasons.js — 查询意图分析

`query-reasons.js` 模块负责将用户的自然语言查询转换为结构化的检索条件。该模块通过预定义的正则表达式模式和启发式规则识别查询中的关键成分，包括：

- **人员实体**：查询中提到的人名或公司名称
- **时间范围**：相对时间（"最近一周"、"上个月"）或绝对时间
- **来源过滤**：指定的数据源（telegram、linkedin、email 等）
- **意图类型**：搜索类型（统计信息、联系人列表、交互记录等）

查询解析结果会生成一个结构化的 `query reasons` 对象，包含提取的关键词列表、过滤条件和权重配置，供下游匹配引擎使用。资料来源：[hermes/minty-network-memory/SKILL.md](https://github.com/sree-sanak/minty/blob/main/hermes/minty-network-memory/SKILL.md)

### 查询类型分类

| 查询类型 | 示例 | 处理逻辑 |
|----------|------|----------|
| 自然语言搜索 | "我在伦敦见过的投资人" | 解析实体+来源+时间，组合检索 |
| 来源过滤查询 | "来自 Telegram 的人" | 仅在指定数据源中搜索 |
| 关键词搜索 | "DeFi"、"区块链" | 分词后匹配交互记录 |
| 人员上下文 | "Alice Müller 的相关信息" | 精确匹配 + 关联扩展 |

## 搜索匹配引擎

### search.js — 核心匹配逻辑

`search.js` 是网络查询系统的匹配引擎核心，负责在已索引的数据中执行高效的相似度匹配和相关性排序。

#### 匹配函数实现

匹配引擎支持三种主要的匹配模式：

```javascript
function matches(text, clause) {
    if (clause.kind === 'phrase') return text.toLowerCase().includes(clause.value);
    if (clause.kind === 'prefix') return findPrefix(text, clause.value).length > 0;
    // token: case-insensitive substring match of the full token
    return text.toLowerCase().includes(clause.value);
}
```

- **phrase（短语匹配）**：完整匹配查询短语，区分大小写但忽略大小写差异
- **prefix（前缀匹配）**：匹配以查询词开头的文本片段
- **token（分词匹配）**：对查询词进行分词后逐个匹配

资料来源：[crm/search.js](https://github.com/sree-sanak/minty/blob/main/crm/search.js)

#### 偏移量计算

`matchOffsets` 函数用于计算匹配文本在原始内容中的位置信息，支持高亮显示和上下文提取：

```javascript
function matchOffsets(text, clause) {
    if (clause.kind === 'phrase' || clause.kind === 'token') return findAll(text, clause.value);
    if (clause.kind === 'prefix') return findPrefix(text, clause.value);
    return [];
}
```

#### 结果排序策略

搜索结果按综合评分排序，评分相同时按时间戳降序排列：

```javascript
.sort((a, b) => (b.score - a.score) ||
    ((new Date(b.timestamp || 0).getTime()) - (new Date(a.timestamp || 0).getTime())));
```

评分计算综合考虑以下因素：
- 关键词命中次数
- 匹配模式优先级（精确匹配 > 前缀匹配 > 模糊匹配）
- 时间衰减因子（新近交互优先）
- 关系亲密度（relationshipScore）

#### 主题词提取

`dominantTokens` 函数从文本中提取最具代表性的关键词，用于构建主题索引和支持话题聚合查询：

```javascript
function dominantTokens(text, opts = {}) {
    const freq = {};
    const min = opts.min || 2;
    const topN = opts.topN || 10;
    const words = String(text || '').toLowerCase().match(ALPHA_NUM) || [];
    for (const w of words) {
        if (w.length < 4 || STOP_WORDS.has(w)) continue;
        freq[w] = (freq[w] || 0) + 1;
    }
    return Object.entries(freq)
        .filter(([, n]) => n >= min)
        .sort((a, b) => b[1] - a[1])
        .slice(0, topN)
        .map(([word]) => word);
}
```

该函数自动过滤停用词和长度小于 4 的词汇，并按词频排序返回 Top N 关键词。资料来源：[crm/search.js](https://github.com/sree-sanak/minty/blob/main/crm/search.js)

## 混合索引系统

### hybrid-index.js — 索引构建与管理

`hybrid-index.js` 负责构建和维护联系人与交互记录的混合索引。索引采用倒排结构，支持高效的关键词查询和多维度过滤。

#### 索引数据结构

索引系统维护以下核心数据结构：

1. **联系人索引**：按姓名、公司、职位、标签等字段建立倒排索引
2. **交互索引**：按时间线组织交互记录，支持时间范围查询
3. **来源索引**：按数据源分类，支持来源级别的过滤和健康度检测
4. **主题索引**：基于 `dominantTokens` 提取的主题词构建话题网络

#### 索引构建流程

索引构建是离线过程，通常在数据合并（`merge.js`）完成后执行。构建流程包括：

1. 加载统一数据存储中的 `contacts.json` 和 `interactions.json`
2. 对每个联系人和交互记录进行分词处理
3. 构建各字段的倒排索引
4. 计算关联权重和预评分
5. 持久化索引文件供运行时加载

## 自然语言查询接口

### network-query.js — 对话式查询 API

`network-query.js` 模块提供 MCP（Model Context Protocol）接口，支持通过自然语言进行网络查询。该模块封装了底层的搜索能力，提供面向 AI Agent 的高级查询接口。

#### 核心查询工具

| 工具名称 | 功能描述 | 典型参数 |
|----------|----------|----------|
| `search_network` | 自然语言网络搜索 | `query`, `limit`, `source`/`sources` |
| `person_context` | 人员上下文查询 | `person`, `limit` |
| `workflow_brief` | 目标导向简报生成 | `goal`, `limit` |
| `source_health` | 数据源健康度检查 | `source`/`sources`/`query` |

资料来源：[hermes/minty-network-memory/SKILL.md](https://github.com/sree-sanak/minty/blob/main/hermes/minty-network-memory/SKILL.md)

#### search_network 查询示例

```json
{
  "query": "investors in London who know about AI",
  "limit": 5
}
```

返回结果包含按相关性排序的联系人列表，每个结果包含：
- **证据（evidence）**：匹配依据和上下文片段
- **亲密度（warmth）**：关系评分
- **置信度（confidence）**：数据可信度评估
- **来源诊断（source diagnostics）**：结果来源分析
- **建议操作（suggested actions）**：下一步安全建议

#### person_context 查询示例

```json
{
  "person": "Alice Müller",
  "limit": 3
}
```

返回指定人员的完整关系上下文，包括：
- 关系历史摘要
- 交互亲密度评分
- 最近交互证据
- 数据新鲜度诊断

#### workflow_brief 目标简报

针对特定目标生成人员推荐简报：

```json
{
  "goal": "Find EU crypto insurance distribution partners",
  "limit": 5
}
```

返回结果包含目标相关度最高的联系人列表，每个联系人附带：
- 相关性原因说明
- 数据新鲜度状态
- 安全的下一步行动建议

### 数据源健康度检测

`source_health` 工具在执行网络查询前自动检查各数据源的状态，确保查询结果的可靠性：

```json
{ "source": "telegram" }
```

健康度状态分类：
- **demo-ready**：可用示例数据
- **fresh**：数据源状态正常
- **stale**：数据较旧，可能需要刷新
- **empty**：数据源为空或未初始化
- **unsafe**：数据不可靠，建议修复后再使用

资料来源：[hermes/minty-network-memory/SKILL.md](https://github.com/sree-sanak/minty/blob/main/hermes/minty-network-memory/SKILL.md)

## 命令行查询接口

### query.js — CLI 工具

`query.js` 提供命令行界面的统计和搜索功能，通过以下命令调用：

```bash
npm run stats   # 显示网络统计信息
npm run search  # 执行关键词搜索
```

CLI 查询工具适合快速获取网络概览和批量数据导出场景，支持以下功能：

- 联系人总数和来源分布统计
- 交互记录数量和时间分布
- 关键词搜索并高亮显示结果
- 导出查询结果为 CSV/JSON 格式

资料来源：[ARCHITECTURE.md](https://github.com/sree-sanak/minty/blob/main/ARCHITECTURE.md)

## 数据流与处理管道

### 查询执行完整流程

```mermaid
sequenceDiagram
    participant U as 用户
    participant NQ as network-query.js
    participant QR as query-reasons.js
    participant HI as hybrid-index.js
    participant SE as search.js
    participant DS as 统一数据存储

    U->>NQ: 自然语言查询
    NQ->>QR: 解析查询意图
    QR-->>NQ: 结构化查询条件
    NQ->>HI: 加载/查询索引
    HI->>DS: 获取最新数据
    DS-->>HI: 数据快照
    HI-->>NQ: 候选结果集
    NQ->>SE: 执行匹配评分
    SE-->>NQ: 排序后结果
    NQ-->>U: 返回查询结果
```

### 与其他模块的交互

网络查询系统与以下模块紧密协作：

| 关联模块 | 交互方式 | 数据依赖 |
|----------|----------|----------|
| `merge.js` | 索引更新触发 | 接收合并后的统一数据 |
| `staleness.js` | 健康度查询 | 使用新鲜度数据校准结果权重 |
| `server.js` | HTTP API 封装 | 提供 `/api/search` 等端点 |
| `calendar.js` | 日程数据融合 | 查询中加入日历事件上下文 |

## 数据模型

### 联系人数据结构

网络查询系统处理的联系人记录包含以下关键字段：

| 字段名 | 类型 | 说明 | 可检索性 |
|--------|------|------|----------|
| `id` | string | 唯一标识符 | 精确匹配 |
| `name` | string | 姓名 | 分词匹配 |
| `company` | string | 公司名称 | 前缀匹配 |
| `position` | string | 职位 | 分词匹配 |
| `sources` | object | 各数据源原始数据 | 来源过滤 |
| `relationshipScore` | number | 关系评分 0-100 | 范围过滤 |
| `daysSinceContact` | number | 最近联系天数 | 范围过滤 |
| `activeChannels` | string[] | 活跃联系方式 | 包含匹配 |
| `tags` | string[] | 自定义标签 | 精确匹配 |

资料来源：[AGENTS.md](https://github.com/sree-sanak/minty/blob/main/AGENTS.md)

### 交互记录数据结构

| 字段名 | 类型 | 说明 |
|--------|------|------|
| `id` | string | 交互记录唯一标识 |
| `contactId` | string | 关联联系人 ID |
| `source` | string | 数据来源（whatsapp/telegram/email等） |
| `timestamp` | ISO string | 交互时间 |
| `type` | string | 交互类型（message/call/meeting） |
| `body` | string | 交互内容正文 |
| `subject` | string | 主题（邮件场景） |

## 性能优化策略

### 索引优化

网络查询系统采用以下索引优化策略：

1. **增量更新**：仅对变更的联系人/交互记录重新索引
2. **压缩存储**：使用倒排列表压缩减少磁盘占用
3. **缓存预热**：服务器启动时预加载高频查询索引
4. **分片加载**：按数据源分片懒加载，平衡内存占用

### 查询优化

1. **早停规则**：达到目标结果数后提前终止匹配
2. **缓存复用**：相同查询条件的结果缓存复用
3. **结果分页**：避免一次性加载大量结果
4. **评分截断**：对低分结果进行截断过滤

## 使用场景示例

### 场景一：查找特定领域联系人

**查询**：查找讨论过 DeFi 话题的 Telegram 联系人

```json
{
  "query": "DeFi",
  "sources": ["telegram"],
  "limit": 10
}
```

系统会：
1. 解析关键词 "DeFi"
2. 在 Telegram 数据源中检索
3. 匹配交互记录中的 DeFi 相关内容
4. 按相关性评分和时间排序返回

### 场景二：人员关系探索

**查询**：获取特定人员的完整关系上下文

```json
{
  "person": "Bob Chen",
  "limit": 5
}
```

返回结果包含该人员的所有交互证据、最近联系时间、共同话题等上下文信息。

### 场景三：目标导向搜索

**查询**：为特定目标寻找相关联系人

```json
{
  "goal": "Find potential co-founders for AI startup",
  "limit": 10
}
```

系统综合分析所有联系人的背景、交互历史和话题相关性，生成目标相关度排序列表。

## 总结

网络查询系统是 Minty CRM 智能化能力的核心体现，通过整合多源数据、构建混合索引和提供自然语言接口，使用户能够以直观的方式探索和利用自己的人际网络。该系统具有以下核心特点：

- **多源聚合**：统一检索散落在各平台的交互数据
- **语义理解**：支持自然语言查询和意图识别
- **智能排序**：综合相关度、时效性、亲密度多维度评分
- **健康感知**：自动检测数据源状态，保证结果可靠性
- **MCP 兼容**：提供标准化的 AI Agent 接口支持

通过 `network-query.js`、`search.js`、`query-reasons.js` 和 `hybrid-index.js` 等模块的协作，网络查询系统为用户提供了从简单关键词搜索到复杂目标导向探索的完整检索能力。

---

---

## Doramagic 踩坑日志

项目：sree-sanak/minty

摘要：发现 14 个潜在踩坑项，其中 1 个为 high/blocking；最高优先级：安装坑 - 来源证据：Audit person-only filters for channel/broadcast/list contacts。

## 1. 安装坑 · 来源证据：Audit person-only filters for channel/broadcast/list contacts

- 严重度：high
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：Audit person-only filters for channel/broadcast/list contacts
- 对用户的影响：可能影响升级、迁移或版本选择。
- 建议检查：来源问题仍为 open，Pack Agent 需要复核是否仍影响当前版本。
- 防护动作：不得脱离来源链接放大为确定性结论；需要标注适用版本和复核状态。
- 证据：community_evidence:github | cevd_806464769ad247cd93162d66f18c8d51 | https://github.com/sree-sanak/minty/issues/86 | 来源讨论提到 node 相关条件，需在安装/试用前复核。

## 2. 身份坑 · 仓库名和安装名不一致

- 严重度：medium
- 证据强度：runtime_trace
- 发现：仓库名 `minty` 与安装入口 `imap` 不完全一致。
- 对用户的影响：用户照着仓库名搜索包或照着包名找仓库时容易走错入口。
- 建议检查：在 npm/PyPI/GitHub 上确认包名映射和官方 README 说明。
- 复现命令：`npm install imap`
- 防护动作：页面必须同时展示 repo 名和真实安装入口，避免用户搜索错包。
- 证据：identity.distribution | github_repo:1217893833 | https://github.com/sree-sanak/minty | repo=minty; install=imap

## 3. 安装坑 · 来源证据：Replace README screenshot TODO with privacy-safe demo visual

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：Replace README screenshot TODO with privacy-safe demo visual
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 建议检查：来源显示可能已有修复、规避或版本变化，说明书中必须标注适用版本。
- 防护动作：不得脱离来源链接放大为确定性结论；需要标注适用版本和复核状态。
- 证据：community_evidence:github | cevd_81816548248b4de0a1ace912ebf7ee0e | https://github.com/sree-sanak/minty/issues/97 | 来源讨论提到 npm 相关条件，需在安装/试用前复核。

## 4. 能力坑 · 能力判断依赖假设

- 严重度：medium
- 证据强度：source_linked
- 发现：README/documentation is current enough for a first validation pass.
- 对用户的影响：假设不成立时，用户拿不到承诺的能力。
- 建议检查：将假设转成下游验证清单。
- 防护动作：假设必须转成验证项；没有验证结果前不能写成事实。
- 证据：capability.assumptions | github_repo:1217893833 | https://github.com/sree-sanak/minty | README/documentation is current enough for a first validation pass.

## 5. 维护坑 · 维护活跃度未知

- 严重度：medium
- 证据强度：source_linked
- 发现：未记录 last_activity_observed。
- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。
- 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。
- 防护动作：维护活跃度未知时，推荐强度不能标为高信任。
- 证据：evidence.maintainer_signals | github_repo:1217893833 | https://github.com/sree-sanak/minty | last_activity_observed missing

## 6. 安全/权限坑 · 下游验证发现风险项

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：下游已经要求复核，不能在页面中弱化。
- 建议检查：进入安全/权限治理复核队列。
- 防护动作：下游风险存在时必须保持 review/recommendation 降级。
- 证据：downstream_validation.risk_items | github_repo:1217893833 | https://github.com/sree-sanak/minty | no_demo; severity=medium

## 7. 安全/权限坑 · 存在安全注意事项

- 严重度：medium
- 证据强度：source_linked
- 发现：No sandbox install has been executed yet; downstream must verify before user use.
- 对用户的影响：用户安装前需要知道权限边界和敏感操作。
- 建议检查：转成明确权限清单和安全审查提示。
- 防护动作：安全注意事项必须面向用户前置展示。
- 证据：risks.safety_notes | github_repo:1217893833 | https://github.com/sree-sanak/minty | No sandbox install has been executed yet; downstream must verify before user use.

## 8. 安全/权限坑 · 存在评分风险

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：风险会影响是否适合普通用户安装。
- 建议检查：把风险写入边界卡，并确认是否需要人工复核。
- 防护动作：评分风险必须进入边界卡，不能只作为内部分数。
- 证据：risks.scoring_risks | github_repo:1217893833 | https://github.com/sree-sanak/minty | no_demo; severity=medium

## 9. 安全/权限坑 · 来源证据：Add minimal GitHub Actions smoke CI for npm test

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：Add minimal GitHub Actions smoke CI for npm test
- 对用户的影响：可能影响授权、密钥配置或安全边界。
- 建议检查：来源显示可能已有修复、规避或版本变化，说明书中必须标注适用版本。
- 防护动作：不得脱离来源链接放大为确定性结论；需要标注适用版本和复核状态。
- 证据：community_evidence:github | cevd_d6f1f5066d884d66b52f3e8f51ed0899 | https://github.com/sree-sanak/minty/issues/98 | 来源讨论提到 node 相关条件，需在安装/试用前复核。

## 10. 安全/权限坑 · 来源证据：Avoid returning raw internal error messages from API/UI

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：Avoid returning raw internal error messages from API/UI
- 对用户的影响：可能影响授权、密钥配置或安全边界。
- 建议检查：来源显示可能已有修复、规避或版本变化，说明书中必须标注适用版本。
- 防护动作：不得脱离来源链接放大为确定性结论；需要标注适用版本和复核状态。
- 证据：community_evidence:github | cevd_2974d969ccff4c9b960c16ee12639466 | https://github.com/sree-sanak/minty/issues/44 | 来源讨论提到 npm 相关条件，需在安装/试用前复核。

## 11. 安全/权限坑 · 来源证据：Provision GitHub labels from checked-in labels.json

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：Provision GitHub labels from checked-in labels.json
- 对用户的影响：可能影响授权、密钥配置或安全边界。
- 建议检查：来源显示可能已有修复、规避或版本变化，说明书中必须标注适用版本。
- 防护动作：不得脱离来源链接放大为确定性结论；需要标注适用版本和复核状态。
- 证据：community_evidence:github | cevd_1a3ae522d9a7404691d7e3eb4b70b6b1 | https://github.com/sree-sanak/minty/issues/109 | 来源讨论提到 npm 相关条件，需在安装/试用前复核。

## 12. 安全/权限坑 · 来源证据：Sync failures can mark stale source data as fresh

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：Sync failures can mark stale source data as fresh
- 对用户的影响：可能影响授权、密钥配置或安全边界。
- 建议检查：来源显示可能已有修复、规避或版本变化，说明书中必须标注适用版本。
- 防护动作：不得脱离来源链接放大为确定性结论；需要标注适用版本和复核状态。
- 证据：community_evidence:github | cevd_3bc92d2124c24b978bf799cc9eff9529 | https://github.com/sree-sanak/minty/issues/200 | 来源讨论提到 node 相关条件，需在安装/试用前复核。

## 13. 维护坑 · issue/PR 响应质量未知

- 严重度：low
- 证据强度：source_linked
- 发现：issue_or_pr_quality=unknown。
- 对用户的影响：用户无法判断遇到问题后是否有人维护。
- 建议检查：抽样最近 issue/PR，判断是否长期无人处理。
- 防护动作：issue/PR 响应未知时，必须提示维护风险。
- 证据：evidence.maintainer_signals | github_repo:1217893833 | https://github.com/sree-sanak/minty | issue_or_pr_quality=unknown

## 14. 维护坑 · 发布节奏不明确

- 严重度：low
- 证据强度：source_linked
- 发现：release_recency=unknown。
- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。
- 建议检查：确认最近 release/tag 和 README 安装命令是否一致。
- 防护动作：发布节奏未知或过期时，安装说明必须标注可能漂移。
- 证据：evidence.maintainer_signals | github_repo:1217893833 | https://github.com/sree-sanak/minty | release_recency=unknown

<!-- canonical_name: sree-sanak/minty; human_manual_source: deepwiki_human_wiki -->
