# 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 暂无支付主链路,先预留统一错误码和策略接口,后续支付接口接入时强制调用。 | 建议新增统一返回: ```json { "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 平台版本检查接口缺失 ### 现状 当前版本检查接口为: ```http 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 平台枚举。平台建议统一为: ```text ios, android, web ``` Web 响应建议保持与移动端同结构: ```json { "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. 消息搜索召回稳定性待复核 ### 现状 当前接口为: ```http 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 | 青少年模式业务限制 | 涉及多个入口和策略口径,需要独立设计和联调,不能只改一个接口。 |