全部文档

服务通知

- 系统找用户:工作区邀请、加入申请结果、好友申请等产品事件发生时,用户在 「消息」 里能看到 固定入口「服务通知」,不必记得去某个模块里翻。

来源 docs/core-mechanisms/服务通知.md

状态:规格已确认(2026-05-25)。

真值:用户可见能力见 docs/产品规格.md §4.7;本文供设计与实现对照。

表述:界面与帮助文案用用户表达;表名、API、会话类型等实现术语仅在本文 §6~§8 给出。


1. 目标

  • 系统找用户:工作区邀请、加入申请结果、好友申请等产品事件发生时,用户在 「消息」 里能看到 固定入口「服务通知」,不必记得去某个模块里翻。
  • 与聊天分离:服务通知 不是 同事私聊、 不是 业务智能体对话、 不是 帮助智能体问答;形态接近微信 「服务通知」——以 系统代发的说明 + 可点操作 为主。
  • 可信、可审计:通知正文来自 服务端模板(或结构化字段渲染),默认不 用大模型现场编造事件内容,避免「助手幻觉成已批准/已拒绝」。

1.1 非目标(首期不做)

  • 不替代短信/邮件 验证码 通道(仍走 OTP)。
  • 不要求用户与服务通知 日常闲聊;可选二期支持「帮我汇总最近通知」类 只读摘要 问答。
  • 不默认做浏览器 Push、企业微信/钉钉等 站外推送(列为三期扩展)。
  • 不把协作详情页(工作区协作内的横幅、我的申请列表)删掉——服务通知负责 触达,各模块仍保留 处理界面

2. 与现有能力的关系

现有能力用户以为实际 today与服务通知关系
帮助智能体问产品怎么用未选工作区/引导场景的可对话助手并列:帮助 = 你问我答;服务通知 = 系统找你说
消息(AI 对话)所有「消息」chat_sessions 助手回复未读 + 20s 轮询服务通知 并入消息入口,但 单独分组/置顶
联络同事/群聊im_* 未读不进顶栏角标好友申请等待 迁入 服务通知触达,处理仍在联络
工作区协作邀请与申请仅打开该页才有横幅/侧栏列表邀请/申请 结果 由服务通知推送;页内 UI 保留

3. 产品决策(已确认,2026-05-25)

#主题结论
1用户可见名称固定称 「服务通知」;消息列表中图标/标题一致,不随工作区变化
2是否「智能体」产品上是固定入口;实现上可用 session_kind=notification + 系统 persona,占用用户「我的智能体」配额;走用户智能体 Runtime 自由生成
3是否可回复首期不可回复(只读时间线);二期可选「问:我漏了什么」只读摘要
4知识文档不使用 三层知识目录注入;模板 + 动作链接即可
5未选工作区仍投递 账号级通知(邀请、好友申请等);消息入口仍可见服务通知
6与 §4.6 统一对话列表 UI 长期可合并,但 会话类型 必须区分 notification vs direct vs agent chat
7已读进入服务通知会话即更新已读水位;顶栏「消息」角标 = AI 未读 + 服务通知未读 +(后期)IM 未读
8保留时长至少 90 天 可查(实现可配置);用户 不可删单条(首期),避免误删审批凭证

4. 用户可见体验

4.1 入口

  • 顶栏「消息」:未读角标包含 服务通知未读条数(可与 AI 未读合并显示总数,进入后分开展示来源)。
  • 消息模块列表服务通知 固定 置顶(在帮助智能体、各业务智能体、会话列表之上或独立分组首项)。
  • 副标题/预览:展示 最新一条 通知摘要(如「「研发部」邀请你加入工作区」)。

4.2 会话内

  • 时间线:卡片式或气泡式均可,但视觉上 弱对话感(系统发送、灰底/图标区分)。
  • 每条通知含

- 标题(一句结论) - 说明(可选,模板填充) - 时间 - 主操作按钮(如「查看邀请」「去工作区协作」)—— 使用 mindlink://action/…(扩展白名单,见 §5.2)

  • 无输入框(首期);底部可放「前往工作区协作查看全部待办」类静态链接。

4.3 与各模块分工

场景服务通知做什么用户仍去哪处理
收到工作区邀请推送「xxx 邀请你加入「yyy」」工作区协作 / 通知内「接受/拒绝」若一期不做则仅跳转
加入申请已批准/拒绝推送结果工作区协作「我的申请」
有人申请加入你的工作区推送给 管理员工作区协作「加入申请」审批
好友申请推送「xxx 想加你为好友」联络

5. 通知类型(事件清单)

5.1 一期(建议首批实现)

事件类型(实现 id)触达对象用户可见标题示例主操作
workspace.invitation.received被邀请人{邀请人} 邀请你加入工作区「{工作区名}」去处理(协作页 / 接受拒绝)
workspace.invitation.accepted邀请人{对方} 已加入工作区「{工作区名}」打开工作区
workspace.join_request.submitted工作区管理员{申请人} 申请加入「{工作区名}」去审批
workspace.join_request.approved申请人你已加入工作区「{工作区名}」`打开工作区
workspace.join_request.rejected申请人「{工作区名}」暂未能通过你的加入申请`查看说明 / 协作页
workspace.join_request.cancelled工作区管理员{申请人} 已撤回加入申请(可选)无

5.2 动作链接(扩展白名单)

在现有 docs/core-mechanisms/帮助动作链接.md 白名单上 增量 注册,例如:

action用户结果
module.workspace打开工作区协作
workspace.invitation.accept?id=…接受邀请(带 id,服务端校验)
workspace.invitation.decline?id=…拒绝邀请
workspace.join_request.review?id=…打开协作页并定位到该申请
module.im打开联络

安全:与帮助链接相同——仅白名单;带 id 的操作须 二次校验 当前用户权限。

5.3 二期及以后(占位)

  • im.friend_request.received / accepted
  • agent.train_job.completed / failed
  • workspace.member.removed(被移出工作区)
  • workflow.task.assigned / workflow.task.cancelled(工作流待办;已实现)
  • 管理员广播(企业公告,可选)

6. 消息形态与文案规则

6.1 模板优先

  • 每条通知存 event_type + payload(JSON);展示时 服务端或前端 用模板渲染中文标题/正文。
  • 模板版本化(template_version),便于改文案不重写历史。
  • 禁止 把通知正文交给 LLM 生成(除二期明确的「摘要问答」且须标注「由助手整理,以详情页为准」)。

6.2 与用户表达对齐

  • 工作区邀请加入申请,不用 workspace_idjoin_request 作主语。
  • 编号类信息放 详情/折叠,不占标题首屏。

6.3 去重与合并

  • 同一 dedupe_key(如 invitation:{id})在 pending 态 更新 而非重复刷屏。
  • 可选:同一工作区多条申请 合并为「你有 3 条加入申请待处理」(二期)。

7. 未读、同步与实时性

建议
未读计数按通知消息 created_at > last_read_at;与 chat 未读 分表统计,API 可合并
前端刷新短期:轮询(与现有 20s 对齐或独立 30s);中期:SSE/WS 通知事件
离线用户下次登录拉取 GET /notifications 或会话历史即可

8. 实现模型(草案)

以下为研发对照,不是 对用户文案。

8.1 数据(示意)

方案 A(推荐首期):独立表 + 固定会话

notification_messages
  id, user_id, event_type, dedupe_key,
  title, body, payload_json,
  action_primary_json,   -- { "label", "action", "params" }
  read_at NULL,
  created_at

每用户一条 chat_sessions 或等价 notification_inbox 指针,用于消息 UI 挂载;session_kind = 'notification'

方案 B:直接写入 chat_messagesrole=system —— 易与助手消息混淆,不推荐

8.2 API(示意)

方法路径说明
GET/api/v1/notifications分页列表(含未读数)
GET/api/v1/notifications/unread-count顶栏角标
POST/api/v1/notifications/read标记已读(进入会话或全部已读)
GET/api/v1/chat/unread-summary扩展:增加 notification_unread 字段(或独立汇总接口由前端合并)

写入:仅在 业务 handler 成功提交事务后 调用 notify.Emit(ctx, event),避免「通知发了但业务失败」。

8.3 与「通知智能体」实现关系

  • 产品名:服务通知(入口)
  • 实现 persona(可选):user_agents.is_system=1agent_kind=notification不可删除 实例,或 无 agent 记录 仅用固定 UI 壳
  • Runtime:通知写入 不调用 POST /chat / 流式 LLM;与帮助智能体、业务智能体 隔离

9. 与统一对话(§4.6)的演进

flowchart LR
  subgraph now [当前]
    M[消息模块 chat]
    H[帮助智能体]
    I[联络 im]
    W[协作页内横幅]
  end

  subgraph target [目标]
    U[统一消息入口]
    U --> N[服务通知 置顶只读]
    U --> H2[帮助 / 智能体 / 同事会话]
    N --> Actions[mindlink://action]
  end

  M --> U
  I --> U
  W --> N
  • 短期:在现有 消息模块 增加 服务通知 置顶会话,不必等 IM 全量合并。
  • 长期GET /im/conversations 与通知 inbox 同一列表组件,用 conversation.kind / notification 过滤 Tab。

10. 分期与验收

10.1 一期(MVP)

范围:§5.1 六类工作区事件 + 置顶入口 + 未读进顶栏 + 动作跳转协作页。

验收(用户可执行)

  1. 用户 A 邀请 B → B 在 消息 → 服务通知 收到条目,顶栏角标 +1。
  2. B 打开服务通知 → 角标清除(或按条已读策略)。
  3. 点击「去处理」→ 进入工作区协作并能看到对应邀请/申请。
  4. 管理员批准加入申请 → 申请人在服务通知收到「已加入」;协作页「我的申请」状态一致。
  5. 通知正文与数据库事实一致, LLM 参与生成。

10.2 二期

  • 好友申请迁入;通知内 接受/拒绝(少跳转)。
  • 「最近通知摘要」只读问答(可选,单独开关)。
  • 合并未读 API;IM 未读进顶栏。

10.3 三期

  • 站外 Push / 邮件摘要;管理员公告。

11. 风险与约束

风险缓解
与帮助智能体混淆固定名称、固定置顶、无输入框、视觉区分
重复通知dedupe_key + 状态机(pending → resolved)
权限泄露通知 payload 不含 secrets;动作链服务端校验
性能异步写入(事务后 goroutine/队列);列表分页

12. 参考


*评审通过后:在 产品规格.md 增加用户可见 §;在 实施计划.md / 实施验收.md 挂阶段与用例;实现前再开 API 字段级契约页(可选)。*