Files
im_server/docs/IM-剩余问题修复方案.md
T

10 KiB
Raw Blame History

IM 剩余问题修复方案

整理时间:2026-09-18

本文记录当前暂未完成的三个后端问题:青少年模式业务限制、Web 平台版本检查、消息搜索召回稳定性。

更新记录:

  • 2026-09-18:P1 第一阶段已处理 Web 平台版本检查与消息搜索召回兜底;青少年模式已完成第一阶段策略层、夜间通话限制和消息内容过滤接入,剩余支付守护、好友/群邀请、Push 等全链路限制继续按 P2 增强。

1. 青少年模式业务限制未强制执行

现状

当前后端已经具备青少年模式的基础状态能力:

  • GET /v1/im/settings/youth-mode 可返回 enabled、policy_version、restrictions、restriction_items。
  • POST /v1/im/settings/youth-mode/enable 和 disable 已完成开启、关闭和独立密码校验链路。
  • im_youth_mode_settings 已保存用户维度的启用状态、策略版本、限制项和密码状态。

第一阶段已将 night_quiet 接入音视频呼叫发起限制,将 content_filter 接入消息发送前内容安全审核,并把这两项 restriction_items[].enforced 改为 true。payment_guard 以及好友申请、群邀请、系统通知/Push 等更大范围入口仍未完整接入。

问题影响

如果只保存开关、不做服务端限制,客户端隐藏入口不能形成安全边界。用户可以通过旧客户端、重新安装、直接调用接口或构造 WebSocket 消息绕过限制。

建议修复方案

建议将青少年模式拆成一个统一策略检查层,例如 imYouthPolicy 或 impolicy/youth,所有关键入口调用同一套判断逻辑。

第一阶段建议先落这几个限制:

限制项 建议拦截点 修复方式
night_quiet 深夜免打扰 发消息、音视频呼叫、系统通知/Push 服务端读取用户青少年状态和当前时间段,限制指定时段内发起呼叫或降低通知等级。
content_filter 内容过滤 发文本、发链接、上传后发布文件、资料/群资料修改 复用现有内容安全/风险审核能力;命中高风险时拒绝或进入审核状态。
payment_guard 支付守护 充值、购买、付费功能入口 当前 IM 暂无支付主链路,先预留统一错误码和策略接口,后续支付接口接入时强制调用。

建议新增统一返回:

{
  "code": 30005,
  "reason": "YOUTH_MODE_RESTRICTED",
  "message": "restricted by youth mode",
  "details": {
    "restriction": "night_quiet",
    "policy_version": 1
  }
}

建议改造点

  • server/im_http.go
    • HTTP 发消息、转发、收藏转发、好友申请、群邀请、音视频相关接口前置检查。
    • youthModeRestrictionItems 中已真正接入的规则将 enforced 改为 true。
  • server/topic.go
    • 原生 WebSocket {pub} 保存消息前执行相同策略,避免绕过 HTTP。
  • server/store/store.go
    • 增加按用户读取青少年模式的轻量缓存,短 TTL 即可。
  • docs/IM-青少年模式前后端对接文档.md
    • 补充哪些接口会返回 YOUTH_MODE_RESTRICTED。

验收建议

  • 开启青少年模式后,旧客户端直接发消息不能绕过限制。
  • HTTP 和 WebSocket 两条链路限制结果一致。
  • 关闭青少年模式后限制即时解除。
  • restriction_items[].enforced 只对已经服务端强制执行的规则返回 true。

当前处理状态

已新增统一策略判断 imYouthModePolicyDecision。当前行为:

  • night_quiet:青少年模式开启且带该限制时,22:00-06:00 发起音视频呼叫返回 YOUTH_MODE_RESTRICTED。
  • content_filter:普通 WS 消息发送前进入内容安全审核,文本、文件名、链接 URL 等可展示内容会参与提取。
  • payment_guard:仍为预留项,返回 enforced=false,后续支付或付费功能接入时再强制调用。

2. Web 平台版本检查接口缺失

现状

当前版本检查接口为:

GET /v1/im/app/releases/latest?platform=ios|android&current_version=1.0.0&channel=stable

当前实现和文档主要覆盖 ios、android。Web 客户端如果调用 platform=web,会因为平台枚举未支持而无法得到可用版本配置。

问题影响

Web 端无法统一读取版本策略、升级提示、最低支持版本和发布说明。后续如果 Web 端需要灰度、强刷、维护提示或版本兼容控制,只能靠前端硬编码。

建议修复方案

将 web 加入 App Release 平台枚举。平台建议统一为:

ios, android, web

Web 响应建议保持与移动端同结构:

{
  "current_version": "1.0.0",
  "has_update": false,
  "force_update": false,
  "platform": "web",
  "channel": "stable",
  "latest_version": "1.0.0",
  "min_supported_version": "1.0.0",
  "update_type": "none",
  "package_url": "",
  "store_url": "",
  "release_notes": "当前已是最新版本。",
  "remind_after_seconds": 0
}

Web 没有安装包时,package_url 和 store_url 可以为空;如果需要强刷或维护提示,可通过 update_type=required 和 release_notes 传达。

建议改造点

  • server/im_http.go
    • 放开 platform=web 参数校验。
    • 保持 current_version 必传。
  • server/db/mysql/adapter.go 或 App Release 相关存储实现
    • 确认 im_app_releases.platform 没有限制 web。
    • 如数据库通过字典/配置初始化版本记录,需要补默认 Web 记录。
  • docs/IM-App版本更新前后端对接文档.md
    • 补充 Web 平台示例。
  • docs/IM-前后端对接文档.md
    • 将 platform=ios|android 更新为 ios|android|web。

验收建议

  • platform=web&current_version=1.0.0&channel=stable 返回 200。
  • platform=invalid 仍返回参数错误。
  • Web 无更新、推荐更新、强制更新三类数据都能按同一结构返回。

当前处理状态

已在 serveIMAppReleaseLatest 放开 platform=web,并补充 Web 平台单元测试。对接文档已同步更新为 ios|android|web。

3. 消息搜索召回稳定性待复核

现状

当前接口为:

GET /v1/im/topics/{topic}/messages/search?q=&type=text&cursor=
GET /v1/im/topics/{topic}/messages/search?type=file&q=&cursor=

现有后端已经能返回 seq、from、ts、snippet、matches、snapshot、availability 等字段。但问题清单中仍记录了“部分明显应该命中的关键词搜索返回空结果”的现象。该问题目前属于待复核项,可能来源包括:

  • 搜索范围只覆盖部分消息内容字段,没有覆盖所有文本来源。
  • 结构化消息中正文可能存在于 content.text、content.txt、content.title、content.summary、Drafty 或文件快照字段中,索引/过滤口径不一致。
  • 中文分词、大小写、空格、标点归一化不一致。
  • 分页游标与过滤顺序不一致,导致命中项被跳过。
  • 热消息、分表消息和历史消息的查询路径不一致。

问题影响

搜索结果不稳定会直接影响聊天记录检索、文件检索、收藏定位和问题复盘。用户明知道某条消息存在,但搜索不到,会被认为是数据丢失。

建议修复方案

第一阶段先做“确定性兜底”,不急于引入复杂搜索引擎:

  1. 明确搜索字段规范。
    • 文本消息:统一提取 content.text、content.txt、content.content、content.title、content.summary、字符串 content。
    • 文件消息:统一提取文件名、mime、文件说明、消息文本。
    • 链接/名片/合并转发:提取标题、摘要、展示文本。
  2. 增加 message_search_text 生成函数。
    • 写入消息时生成可搜索文本。
    • 老数据可查询时动态 fallback。
  3. 查询顺序固定。
    • 先按用户权限和 topic 过滤可见消息。
    • 再按搜索文本匹配。
    • 最后按 seq desc 或 created_at desc 分页。
  4. 中文和符号归一化。
    • 至少做大小写归一、前后空格、连续空白压缩、全角半角基础处理。
  5. 增加回归测试。
    • 普通文本、中文关键词、文件名、链接标题、转发快照、撤回/删除消息、分页边界都要覆盖。

第二阶段如果数据量和体验要求更高,再考虑引入专用搜索索引:

  • MySQL FULLTEXT/ngram。
  • OpenSearch/Elasticsearch。
  • 独立 im_message_search_index 表,按 topic、seq、search_text 存储轻量索引。

建议改造点

  • server/im_http.go
    • messageText 和 messageSearchPayload 的提取逻辑继续收口,保证响应与查询使用同一文本口径。
  • server/db/mysql/adapter.go 或消息查询实现
    • 检查 TenantMessageSearch 的 SQL 过滤条件和分页顺序。
    • 确认群消息分表 im_group_messages_YYYYMM 与私聊消息表搜索路径一致。
  • server/store/types
    • 如新增搜索索引表,补结构体和迁移 SQL。
  • docs/IM-前后端对接文档.md
    • 明确搜索匹配字段、排序规则和 availability 行为。

验收建议

  • 同一 topic 下创建 20 条混合消息,逐条用关键词可搜到。
  • 搜索中文短词、英文大小写、文件名、链接标题均有稳定结果。
  • 翻页时不丢边界记录、不重复。
  • 被删除/撤回消息按 availability 返回或按产品规则隐藏,行为一致。
  • 私聊和群聊搜索结果字段一致。

当前处理状态

已完成第一阶段确定性兜底:私聊和群聊搜索不再只依赖 SQL LIKE 命中消息 JSON 原文,改为先按权限、Topic、类型和游标读取固定窗口,再对结构化文本做统一提取和归一化匹配。当前覆盖文本、文件名、标题、摘要、链接、卡片和转发快照等字段,并补充结构化内容召回测试。

建议排期

优先级 项目 原因
P1 Web 平台版本检查 改动小,边界清楚,适合快速补齐。
P1 消息搜索召回复核 影响用户感知,需要先补测试锁定问题。
P2 青少年模式业务限制 涉及多个入口和策略口径,需要独立设计和联调,不能只改一个接口。