10 KiB
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。
- 原生 WebSocket
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¤t_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¤t_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 或文件快照字段中,索引/过滤口径不一致。 - 中文分词、大小写、空格、标点归一化不一致。
- 分页游标与过滤顺序不一致,导致命中项被跳过。
- 热消息、分表消息和历史消息的查询路径不一致。
问题影响
搜索结果不稳定会直接影响聊天记录检索、文件检索、收藏定位和问题复盘。用户明知道某条消息存在,但搜索不到,会被认为是数据丢失。
建议修复方案
第一阶段先做“确定性兜底”,不急于引入复杂搜索引擎:
- 明确搜索字段规范。
- 文本消息:统一提取
content.text、content.txt、content.content、content.title、content.summary、字符串 content。 - 文件消息:统一提取文件名、mime、文件说明、消息文本。
- 链接/名片/合并转发:提取标题、摘要、展示文本。
- 文本消息:统一提取
- 增加
message_search_text生成函数。- 写入消息时生成可搜索文本。
- 老数据可查询时动态 fallback。
- 查询顺序固定。
- 先按用户权限和 topic 过滤可见消息。
- 再按搜索文本匹配。
- 最后按
seq desc或created_at desc分页。
- 中文和符号归一化。
- 至少做大小写归一、前后空格、连续空白压缩、全角半角基础处理。
- 增加回归测试。
- 普通文本、中文关键词、文件名、链接标题、转发快照、撤回/删除消息、分页边界都要覆盖。
第二阶段如果数据量和体验要求更高,再考虑引入专用搜索索引:
- MySQL FULLTEXT/ngram。
- OpenSearch/Elasticsearch。
- 独立
im_message_search_index表,按 topic、seq、search_text 存储轻量索引。
建议改造点
server/im_http.gomessageText和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 | 青少年模式业务限制 | 涉及多个入口和策略口径,需要独立设计和联调,不能只改一个接口。 |