20 KiB
M001 SourceMessage Inbox 邮件来源入口 PRD
文档信息
| 项目 | 内容 |
|---|---|
| 文档版本 | 0.1 |
| 日期 | 2026-07-06 |
| 状态 | 草稿 |
| 适用范围 | TH Hotel 项目邮件来源入口、邮件历史查询、邮件原文读取能力 |
| 主要读者 | 产品、后端、前端、测试、后续协作 agent |
已确认结论
- 历史邮件范围:第一阶段只查询“本项目已经接收并落库过的邮件”,不主动拉取上线前邮箱历史邮件。
- 邮件唯一标识:AgentBus 返回
source.external_message_id,对应单封邮件外部唯一 ID。 - 邮件链标识:AgentBus 返回
source.external_conversation_id,对应邮件会话或邮件链 ID。 - AgentBus frame
id和session_id只表示 AgentBus 推送帧和连接会话,不能等同于邮件 ID 或邮件链 ID。 - 正文图片和附件:AgentBus 返回的是已经处理过的新 URL,且 URL 长期有效。
- 本项目第一阶段不下载附件、不转存文件、不重新生成媒体 URL、不做 URL 刷新机制。
- 邮件原文读取能力是平台通用能力,不按“内部人员 / 业务人员”拆成两套能力,而是按权限、场景、审计和数据最小化原则管控。
- 邮件原文后续在哪个功能或哪个前端页面展示暂时待定,但平台侧应先把能力和数据边界设计清楚。
1. Executive Summary
本项目需要建设 SourceMessage Inbox 邮件来源入口,用于接收 AgentBus 推送的邮件 JSON,并把它沉淀为本项目可查询、可去重、可追溯、可扩展的来源事实。该能力为后续 AI 识别、人工处理、Case / Task 流程提供稳定输入,但第一阶段不直接做 AI 抽取、不自动创建业务任务、不自动回复客户,也不直接调用外部业务系统。平台同时需要提供受控的邮件原文读取能力,后续具体页面由业务功能决定。
2. Problem Statement
谁有这个问题
- 业务处理人员:后续需要确认某封邮件是否已经进入系统,并在具体业务流程中查看邮件原文或上下文。
- 系统运维 / 管理人员:需要排查 AgentBus 是否成功推送、是否重复投递、payload 是否解析失败。
- 后续 AI / 业务流程:需要一个稳定、可审计的来源输入,而不是直接依赖 AgentBus 原始 DTO。
当前问题
如果 AgentBus 邮件 JSON 只被临时消费,或者直接进入 AI / Case / Task 业务流程,会带来以下问题:
- 历史邮件不可查,无法确认邮件是否已经进入系统。
- 重复投递难以幂等处理,可能导致重复任务或重复业务动作。
- AgentBus 协议细节会污染业务模块,后续更换来源方式成本高。
- 邮件原文、HTML、正文图片、附件 URL 如果缺少统一管控,容易在列表、日志、错误响应或前端页面里过度暴露。
- 后续 AI 识别和人工处理缺少统一来源事实,审计链路不完整。
为什么痛
- 业务影响:邮件是后续业务流程的起点,入口不稳定会影响 Case 匹配、任务生成、人工复核和追溯。
- 工程影响:入口层和业务层耦合过深,会让后续接入 Microsoft Graph、IMAP、Webhook、手工导入等来源变困难。
- 安全影响:原文、HTML、图片和附件 URL 都可能包含客户信息,需要统一权限、审计和最小化返回策略。
证据
- 已有 AgentBus 对接文档确认 Outlook 邮件 payload 包含
source.external_message_id、source.external_conversation_id、body.html、body.text、inline_images[]、attachments[]等字段。 - 已有后端规范要求 AgentBus 实时入口必须先写 SourceMessage Inbox;后续如需调用 SuperAgent,必须通过入库后的受控异步 dispatch / outbox 链路完成,不直接生成 MessageEvent、Evidence、Case、Task、Operation 或 Receipt。
- 🔶 Assumption:业务人员后续会在某些业务功能中查看邮件原文,但具体功能和页面还未确定。
3. Target Users & Personas
Primary Persona:业务处理人员
- 角色:酒店业务流程中的处理人员,例如预订、客服或后续明确的部门角色。
- 目标:在处理具体业务时,能够查看相关邮件原文和附件信息,理解客户真实意图。
- 痛点:如果只能看到摘要,遇到复杂邮件、转发链、附件说明时可能无法做准确判断。
- 当前行为:业务人员可能通过其他方式直接查看邮箱原文;本项目后续需要把原文读取能力接入业务流程。
Secondary Persona:系统运维 / 管理人员
- 角色:负责排查 AgentBus 接入、消息落库、重复投递、失败 payload 的技术或管理人员。
- 目标:确认系统是否收到邮件、是否重复、是否解析失败、失败原因是否安全可见。
- 痛点:如果没有入站记录和幂等状态,排查只能依赖外部日志或临时样本。
System Persona:后续 AI / 业务流程
- 角色:后续的 AI 识别流程、人工复核流程、Case / Task 编排流程。
- 目标:使用稳定的 SourceMessage ID 和受控内容读取能力,而不是直接依赖 AgentBus 原始 payload。
- 痛点:如果来源事实不稳定,后续业务对象无法可靠追溯到原始邮件。
4. Strategic Context
业务目标
- 建立邮件作为业务流程起点的稳定入口。
- 为后续 AI 识别、人工确认、Case / Task 流程提供可追溯来源。
- 保持低耦合和高可维护性,避免把 AgentBus 协议绑定到业务流程里。
为什么现在做
当前项目还处于需求和规范阶段,尚未大量生成前后端代码。此时先确定 SourceMessage Inbox 的产品边界、数据边界和安全边界,可以降低后续重构成本。
5. Solution Overview
方案概述
建设平台级 SourceMessage Inbox 能力。AgentBus Adapter 接收邮件 JSON 后,先通过统一捕获端口保存为来源事实。后续所有查询、原文读取、AI 处理、业务处理都围绕本项目内部 SourceMessage ID 展开。
AgentBus 邮件 JSON
// 外部消息入口,负责把邮件 payload 推送给本项目
→ integrations.messaging.agentbus
// AgentBus 适配层:解析 AgentBus frame,提取稳定字段,不做业务判断
→ platform.message SourceMessage Capture
// 平台消息捕获能力:做幂等、落库、状态记录、安全摘要生成
→ SourceMessage Inbox
// 邮件来源事实:可查询、可追溯、不可直接等同于业务任务
→ 后续受控读取 / AI 识别 / 人工处理
// 后续流程只依赖内部 SourceMessage ID 和平台接口
核心能力
- 邮件入站捕获:接收 AgentBus 邮件 JSON 并保存来源事实。
- 幂等去重:同一酒店、同一 provider、同一 channel、同一外部邮件 ID 不重复建记录。
- 历史查询:查询本项目已经接收并落库过的邮件。
- 邮件链查询:按
externalConversationId查询同一邮件链下的记录。 - 安全摘要:列表只返回主题摘要、发件人展示值、时间、状态、短摘要等受控展示信息。
- 原文读取:提供统一受控接口读取 text、HTML、正文图片 URL、附件 URL。
- 媒体引用保存:保存 AgentBus 已处理好的长期有效媒体 URL,不下载、不转存、不刷新。
- 扩展来源:后续可以接入 Microsoft Graph、IMAP、Webhook、手工导入等来源。
数据模型边界
source_message_inbox
// 邮件来源索引表:保存单封邮件的外部 ID、邮件链 ID、来源、状态、摘要和幂等信息
source_message_payload
// 原始载荷表:保存 AgentBus 推来的规范 JSON,用于追溯、排查和后续重新处理
source_message_body
// 邮件正文表:保存 text/html 正文。列表不直接返回正文,原文读取接口按权限返回
source_message_media
// 邮件媒体引用表:保存 AgentBus 已处理好的长期有效 URL,包括正文图片和附件,不保存二进制文件
source_message_inbox 字段说明
| 字段 | 中文说明 |
|---|---|
id |
本项目内部 SourceMessage ID,后续业务流程使用该 ID 关联来源邮件 |
hotelId |
酒店或业务上下文 ID,避免不同酒店邮件 ID 冲突 |
provider |
来源提供方,例如 AGENTBUS |
channel |
来源渠道,例如 EMAIL |
externalMessageId |
外部邮件系统中的单封邮件唯一 ID,对应 AgentBus source.external_message_id |
externalConversationId |
外部邮件系统中的邮件链 / 会话 ID,对应 AgentBus source.external_conversation_id |
providerFrameId |
AgentBus frame ID,用于排查推送帧,不作为邮件唯一 ID |
providerSessionId |
AgentBus session ID,用于排查连接会话,不作为邮件链 ID |
payloadSha256 |
规范 JSON 的哈希值,用于排查 payload 是否变化 |
captureStatus |
捕获状态,例如 RECEIVED、FAILED |
receivedAt |
邮件来源接收时间,优先取 AgentBus payload received_at;缺失时使用本项目接收时间 |
sourceSentAt |
邮件来源发送时间,如果 payload 提供则保存 |
senderSummary |
发件人展示值,业务人员需要识别真实发件人,当前只清理首尾空白不打码 |
subject |
邮件主题 |
safeSnippet |
邮件安全摘要,不能包含完整正文、HTML、附件 URL 或敏感凭证 |
推荐幂等键:
hotelId + provider + channel + externalMessageId
// 同一业务上下文、同一来源、同一渠道、同一封外部邮件只保存一次
source_message_payload 字段说明
| 字段 | 中文说明 |
|---|---|
inboxId |
所属 SourceMessage Inbox 记录 |
payloadJson |
AgentBus 规范 JSON 原始载荷 |
payloadSha256 |
payload 哈希,用于一致性检查 |
schemaVersion |
payload 结构版本,AgentBus 有提供则保存,否则使用本项目捕获版本 |
source_message_body 字段说明
| 字段 | 中文说明 |
|---|---|
inboxId |
所属 SourceMessage Inbox 记录 |
contentType |
正文类型,例如 TEXT、HTML、MIXED |
textBody |
纯文本正文,用于摘要、搜索和 AI 处理更安全 |
htmlBody |
HTML 原文,前端展示前必须做 sanitize |
bodySha256 |
正文哈希,用于排查正文是否变化 |
source_message_media 字段说明
| 字段 | 中文说明 |
|---|---|
inboxId |
所属 SourceMessage Inbox 记录 |
mediaType |
媒体类型:INLINE_IMAGE 表示正文内图片,ATTACHMENT 表示附件 |
fileName |
文件名,附件一般有,正文图片可能为空 |
contentType |
文件 MIME 类型,例如 image/png、application/pdf |
sizeBytes |
文件大小,AgentBus 有返回则保存,没有则为空 |
externalUrl |
AgentBus 返回的长期有效访问 URL,只能通过受控详情接口返回 |
externalMediaId |
AgentBus 或邮件系统中的媒体 ID,有则保存,便于排查和追溯 |
接口能力边界
GET /api/source-messages
// 邮件历史列表:只返回安全摘要,不返回完整正文、HTML、附件 URL
GET /api/source-messages/{id}
// 邮件详情摘要:返回来源字段、状态、主题、摘要、邮件链 ID 等,不默认返回原文
GET /api/source-messages/{id}/original
// 邮件原文读取:按权限返回 textBody、htmlBody、正文图片 URL 和附件 URL
GET /api/source-messages?externalConversationId=...
// 邮件链查询:按外部邮件链 ID 查询本项目已接收的同链邮件
权限建议:
SOURCE_MESSAGE_READ
// 邮件来源记录读取权限:允许查看列表和摘要详情
SOURCE_MESSAGE_ORIGINAL_READ
// 邮件原文读取权限:允许读取正文、HTML、正文图片 URL 和附件 URL
6. Success Metrics
Primary Metric
- 邮件入库可靠性:合法 AgentBus 邮件 payload 能稳定保存为
RECEIVEDSourceMessage Inbox。 - 🔵 Open Question:第一阶段是否需要量化目标,例如测试环境 100% 合法样本入库成功。
Secondary Metrics
- 重复投递去重成功率:重复外部邮件不会重复创建 SourceMessage。
- 查询可用性:可以按时间、状态、外部邮件 ID、外部邮件链 ID 查询本项目已接收邮件。
- 原文读取可控性:只有具备
SOURCE_MESSAGE_ORIGINAL_READ权限的调用方可以读取原文和媒体 URL。
Guardrail Metrics
- 列表接口、普通详情接口、日志、错误响应不得暴露完整正文、HTML、附件 URL、Token 或 Secret。
- AgentBus 实时入口不得在 WebSocket 回调内直接创建 Case、Task、Operation、Receipt 或客户回复;M007 SuperAgent 自动分发也必须以 SourceMessage 入库后的异步 dispatch 为边界。
7. User Stories & Requirements
Epic Hypothesis
我们相信建设 SourceMessage Inbox 邮件来源入口,可以让本项目稳定保存、查询和追溯 AgentBus 邮件来源事实,因为业务流程需要一个不依赖 AgentBus DTO 的内部起点。成功标准是合法邮件可入库、重复邮件可幂等、已入库邮件可查询、邮件原文可按权限读取。
Story 1:接收并保存 AgentBus 邮件 JSON
As a 系统
I want to 把 AgentBus 推送的邮件 JSON 保存为 SourceMessage Inbox
so that 后续业务流程可以基于本项目内部来源记录继续处理
Acceptance Criteria:
- Given AgentBus 推送合法邮件 JSON
When 系统处理该 JSON
Then 系统保存一条RECEIVEDSourceMessage Inbox 记录 - Given payload 包含
source.external_message_id
When 系统保存记录
ThenexternalMessageId保存该单封邮件外部唯一 ID - Given payload 包含
source.external_conversation_id
When 系统保存记录
ThenexternalConversationId保存该邮件链 ID - Given payload 包含正文、正文图片和附件 URL
When 系统保存记录
Then 系统保存正文和媒体引用,但不下载、不转存、不刷新 URL
Story 2:重复投递保持幂等
As a 系统运维 / 管理人员
I want to 系统识别重复投递的同一封邮件
so that 不会产生重复来源记录和后续重复业务处理
Acceptance Criteria:
- Given 已存在相同
hotelId + provider + channel + externalMessageId的记录
When 系统再次收到该邮件 payload
Then 系统不创建新的 SourceMessage Inbox - Given 重复投递 payload 与原 payload 内容不同
When 系统识别到同一外部邮件 ID
Then 系统不覆盖原始 payload,并保留可排查的安全状态或摘要
Story 3:查询已接收邮件历史
As a 具备邮件来源读取权限的用户或系统
I want to 查询本项目已经接收并落库的邮件历史
so that 我可以确认邮件是否已经进入系统
Acceptance Criteria:
- Given 系统中已有 SourceMessage Inbox
When 调用邮件历史列表接口
Then 返回分页列表和安全摘要 - Given 调用方按
externalMessageId查询
When 邮件已存在
Then 返回对应邮件摘要记录 - Given 调用方按
externalConversationId查询
When 同一邮件链已有多封邮件
Then 返回本项目已接收的同链邮件记录 - Given 列表返回结果
Then 不包含完整正文、HTML、附件 URL、Token 或 Secret
Story 4:按权限读取邮件原文
As a 具备邮件原文读取权限的调用方
I want to 通过统一接口读取邮件原文、正文图片和附件 URL
so that 后续业务功能可以在需要时展示完整邮件上下文
Acceptance Criteria:
- Given 调用方具备
SOURCE_MESSAGE_ORIGINAL_READ权限
When 调用邮件原文读取接口
Then 返回textBody、htmlBody、inlineImages[]、attachments[] - Given 调用方不具备
SOURCE_MESSAGE_ORIGINAL_READ权限
When 调用邮件原文读取接口
Then 系统拒绝访问 - Given 原文接口返回
htmlBody
Then 接口说明必须标注前端展示前需要 sanitize - Given 原文接口返回媒体 URL
Then 只返回 AgentBus 已处理的长期有效 URL,不返回 Token 或后端 Secret - Given 发生原文读取
Then 系统应记录访问审计,至少包含调用方、SourceMessage ID、访问时间和访问场景
8. Out of Scope
第一阶段不包含:
- 主动拉取上线前邮箱历史邮件。
- 下载附件、转存对象存储、重新生成图片或附件 URL。
- URL 过期刷新机制,因为当前已确认 AgentBus 返回 URL 长期有效。
- AI 抽取、意图识别、Case 匹配、Task 创建、Operation、Receipt。
- 自动回复客户、自动发送 ACK 或
task.result。 - 具体业务前端页面设计。原文读取能力先作为平台接口能力沉淀,页面位置后续再定。
- 真实客户邮件样本入库测试。测试夹具必须使用合成数据。
未来可考虑:
- 接入 Microsoft Graph、IMAP、Webhook、手工导入等其他来源。
- 全文检索和更复杂的邮件链展示。
- 原文访问审批、敏感字段遮罩、附件预览策略。
- SourceMessage Replay 到 MessageEvent / Evidence。
9. Dependencies & Risks
Dependencies
- AgentBus payload 字段稳定性:依赖
source.external_message_id、source.external_conversation_id、body.text、body.html、inline_images[]、attachments[]。 - 权限体系:需要后续确认
SOURCE_MESSAGE_READ和SOURCE_MESSAGE_ORIGINAL_READ如何落到角色。 - 审计体系:需要记录原文读取行为,具体表结构可与平台审计能力统一设计。
- HTML 安全展示:前端展示 HTML 前必须 sanitize,后端接口文档也要明确该约束。
Risks & Mitigations
- Risk:AgentBus 字段变更导致映射失败。
Mitigation:保存原始 payload,字段映射失败也落FAILED记录和安全错误摘要。 - Risk:重复投递 payload 内容不同,覆盖原始事实会破坏追溯。
Mitigation:幂等命中后不覆盖原 payload,差异通过安全摘要或后续 attempt 记录表达。 - Risk:邮件原文或媒体 URL 在列表、日志、错误响应中过度暴露。
Mitigation:列表只返回安全摘要;原文接口独立权限;日志和错误响应脱敏。 - Risk:业务模块直接依赖 AgentBus DTO。
Mitigation:业务模块只依赖 SourceMessage ID 和平台接口;AgentBus DTO 只留在integrations.messaging.agentbus。 - Risk:HTML 原文直接渲染带来安全问题。
Mitigation:前端展示前 sanitize;必要时使用受控容器和链接安全策略。
10. Open Questions
| 问题 | 负责人 | 状态 |
|---|---|---|
第一个 checkpoint 是否直接实现 /api/source-messages/{id}/original 原文读取接口,还是只写接口契约并后置实现? |
产品 / 后端 | Open |
SOURCE_MESSAGE_READ 和 SOURCE_MESSAGE_ORIGINAL_READ 第一阶段如何映射到角色? |
产品 / 后端 | Open |
| 原文读取审计是否使用独立表,还是复用后续统一审计能力? | 后端 | Open |
| HTML sanitize 主要在前端完成,还是后端也提供清洗后的安全 HTML? | 前端 / 后端 | Open |
| 是否需要第一阶段支持按正文摘要关键字搜索,还是只按 ID、时间、状态、邮件链查询? | 产品 | Open |
PRD Self-Assessment
Strongest Section
数据边界和安全边界较清晰:已经明确 AgentBus 字段、邮件唯一 ID、邮件链 ID、媒体 URL 长期有效、原文读取权限和列表最小化返回策略。
Weakest Section
成功指标和角色权限仍需细化。当前只有定性验收标准,缺少真实环境中的量化目标和角色映射。
Top Assumptions to Validate
| # | Assumption | Section | Risk if Wrong | Proposed Validation |
|---|---|---|---|---|
| 1 | 业务人员后续会在某些功能中查看邮件原文,但页面位置未定 | Section 2 / 8 | 如果不需要展示原文,原文接口优先级可能过高 | 与业务流程设计一起复核 |
| 2 | AgentBus 媒体 URL 长期有效 | Section 5 / 8 | 如果 URL 后续变为临时 URL,需要增加刷新或代理机制 | 与 AgentBus 提供方确认并记录 |
| 3 | 第一阶段不需要全文搜索 | Section 10 | 如果业务排查强依赖搜索,查询体验不足 | 需求评审时确认查询条件 |
Recommended Next Step
先确认第一个 checkpoint 范围:是否把原文读取接口纳入第一阶段实现。确认后,再把本 PRD 拆成用户故事和后端实现计划。