# IM Kafka 接入联调测试文档 > 关联文档:[IM Kafka 接入方案](./IM-Kafka接入方案.md)、[IM Kafka 接入范围识别](./IM-Kafka接入范围识别.md)、[IM Kafka 基础表 SQL](./sql/IM-Kafka基础表SQL.sql) > 适用范围:Admin/HotGo 与 IM Server 通过 Kafka 和内部只读 API 联调。 > 当前约定:Admin 只访问 `hotgo`,IM Server 只访问租户库;跨系统写操作走 Kafka,跨系统查询走内部只读 API。 ## 1. 联调目标 1. 验证 Kafka 基础生产、消费、幂等、重试、死信能正常工作。 2. 验证 Admin 后台操作通过 `im.admin.command` 投递到 IM Server,并通过 `im.admin.command.result` 返回最终状态。 3. 验证 IM Server 私聊/群聊消息异步落库、缓存失效、死信处理、用户治理命令全部可用;文件生命周期和工作台事件同步落库。 4. 验证 Admin 与 IM Server 不跨库直连:Admin 查询租户业务数据走 IM 内部 API;IM 查询 hotgo 配置走 Admin 内部 API。 5. 验证 Kafka 异常情况下不会产生重复业务结果,且失败可重试、可进入死信、可人工重放。 ## 2. 环境准备 ### 2.1 服务与依赖 | 组件 | 要求 | | --- | --- | | MySQL | `hotgo` 控制库、租户库如 `tinode` 已创建并可连接。 | | Redis | IM Server 已配置 Redis,用于在线状态、短状态、热缓存和跨节点 fanout。 | | Kafka | Topic 已创建或允许自动创建;建议测试环境显式创建。 | | OSS | 文件上传下载仍走 OSS,文件元数据和生命周期小流量动作同步处理。 | | Admin/HotGo | 已接入 Kafka producer/consumer、outbox、内部配置查询接口。 | | IM Server | 已启用 Kafka、内部 Admin Query API、Admin Internal Config Client。 | ### 2.2 Kafka Topic | Topic | 方向 | 用途 | | --- | --- | --- | | `im.admin.command` | Admin -> IM | 后台群治理、用户治理、死信处理命令。 | | `im.admin.command.result` | IM -> Admin | 后台命令执行结果。 | | `im.config.event` | Admin -> IM | 租户配置、字典、第三方配置变更通知。 | | `im.cache.invalidate` | Admin/IM -> IM | 跨节点缓存失效。 | | `im.message.persist` | IM -> IM | 私聊消息异步落库。 | | `im.group.message.persist` | IM -> IM | 群聊消息异步落库。 | | `im.audit.event` | IM -> Admin/HotGo | 跨系统审计事件。 | | `im.dead.letter` | IM -> Admin/告警 | 消费失败死信。 | 说明:`im.message.push` 已规划但本轮不联调,离线 Push Kafka 化仍在增强项中。 ### 2.3 数据库准备 租户库必须执行: ```sql SOURCE docs/sql/IM-Kafka基础表SQL.sql; ``` 重点确认租户库存在: | 表 | 用途 | | --- | --- | | `im_kafka_consume_log` | 消费幂等、重试状态。 | | `im_kafka_dead_letters` | 死信记录与人工处理状态。 | | `im_messages` | 私聊消息存储。 | | `im_group_messages` | 群聊消息存储。 | | `im_filemsglinks` | 私聊附件引用。 | | `im_group_files` | 群文件和群附件引用。 | | `im_system_notifications` | 工作台等系统通知。 | | `im_business_events_outbox` | WS 业务事件投递队列。 | Admin/HotGo 侧需具备: | 表/能力 | 用途 | | --- | --- | | `im_admin_commands` | Admin 操作单,记录后台操作 `pending/running/succeeded/failed/dead`。 | | `im_admin_outbox` | Admin outbox,与操作单同事务写入,可靠发送 Kafka。 | | `im_kafka_dead_letter_events` | Admin 消费 `im.dead.letter` 后落 HotGo,用于告警和排障。 | | Admin 配置表/字典表 | 为 `/internal/im-config/*` 提供数据源。 | Admin/HotGo 侧需执行: ```sql SOURCE server/storage/data/generate/im_kafka_admin_tables.sql; SOURCE server/storage/data/generate/im_kafka_event_tables.sql; SOURCE server/storage/data/generate/im_kafka_command_menu.sql; SOURCE server/storage/data/generate/im_dead_letter_menu.sql; SOURCE server/storage/data/generate/im_kafka_audit_menu.sql; ``` ### 2.4 IM Server 配置 `tinode.conf` 或 Docker 环境变量: ```json { "kafka": { "enabled": true, "brokers": ["127.0.0.1:9092"], "client_id": "im-server", "consumer_group": "im-server", "allow_auto_topic_creation": false, "max_retry_count": 3 }, "internal_api": { "enabled": true, "time_window_seconds": 300, "services": { "hotgo-admin": { "secret": "same-secret", "allow": ["admin_query"] } } }, "admin_internal_api": { "enabled": true, "base_url": "http://hotgo-admin:8080", "service_name": "im-server", "secret": "same-secret", "timeout_ms": 3000 } } ``` ### 2.5 Admin/HotGo 配置 Admin 需要: 1. Kafka producer 发送 `im.admin.command`、`im.config.event`、`im.cache.invalidate`。 2. Kafka consumer 消费 `im.admin.command.result`、`im.dead.letter`。 3. 内部接口客户端调用 IM `/internal/admin-query/*`。如果 IM API 前缀为 `/v1`,Admin 配置 `imInternalApi.baseUrl` 应包含 `/v1`,例如 `http://im-server:6060/v1`。 4. 内部接口服务端提供 IM `/internal/im-config/*`。 5. 内部接口签名与 IM 一致。 HMAC 签名请求头: | Header | 说明 | | --- | --- | | `X-Service-Name` | 调用方服务名,如 `hotgo-admin` 或 `im-server`。 | | `X-Timestamp` | Unix 秒级时间戳。 | | `X-Nonce` | 一次性随机串。 | | `X-Signature` | HMAC-SHA256 hex 签名。 | 签名文本: ```text METHOD + "\n" + RequestURI + "\n" + BodySHA256Hex + "\n" + Timestamp + "\n" + Nonce ``` ### 2.6 Admin 与 IM Server 分工 | 模块 | Admin/HotGo 负责 | IM Server 负责 | | --- | --- | --- | | 库访问边界 | 只访问 `hotgo` 控制库,不直连租户库。 | 只访问租户库,不直连 `hotgo`。 | | 后台写操作 | 写 Admin 操作单和 Admin outbox,生产 `im.admin.command`。 | 消费命令、执行租户业务、回传 `im.admin.command.result`。 | | 后台查询 | 通过 IM `/internal/admin-query/*` 查询租户业务数据。 | 提供白名单只读查询接口,统一 HMAC 鉴权。 | | IM 配置读取 | 提供 `/internal/im-config/*`。 | 通过 Admin 内部配置接口读取租户、注册、第三方配置。 | | Kafka 死信 | 消费 `im.dead.letter`,展示告警和处理入口。 | 记录死信,提供查询接口,消费处理命令。 | | 审计 | 消费 `im.audit.event` 并同步落 HotGo 审计表。 | 关键业务动作生产跨系统审计事件,不在 IM 内部消费落库。 | ### 2.7 IM 内部查询接口矩阵 Admin 调用以下接口时统一使用 `GET /v1/internal/admin-query/tenants/{tenant_code}/...`,如果部署未配置 `/v1` 前缀,则以实际 IM HTTP 前缀为准。 P0 核心页面: | 接口 | 用途 | | --- | --- | | `/users` | 用户列表。 | | `/users/{user_id}` | 用户详情。 | | `/users/{user_id}/devices` | 用户设备列表。 | | `/groups` | 群列表。 | | `/groups/{topic}` | 群详情和治理配置。 | | `/groups/{topic}/members` | 群成员分页列表。 | | `/groups/{topic}/join-requests` | 入群申请列表。 | | `/groups/{topic}/invitations` | 群邀请列表。 | | `/groups/{topic}/announcements` | 群公告列表。 | | `/groups/{topic}/mutes` | 群禁言列表。 | | `/groups/{topic}/admin-logs` | 群管理日志。 | | `/groups/{topic}/files` | 群文件列表。 | | `/files` | 文件列表。 | | `/files/{file_id}` | 文件详情。 | | `/files/{file_id}/links` | 文件引用列表。 | | `/kafka/dead-letters` | Kafka 死信列表。 | | `/kafka/dead-letters/{dead_id}` | Kafka 死信详情。 | P1/P2 运营和完整隔离页面: | 接口 | 用途 | | --- | --- | | `/audit-logs`、`/audit-logs/{id}` | 审计日志列表和详情。 | | `/realname-verifications`、`/realname-verifications/{id}` | 实名审核列表和详情。 | | `/abuse-reports`、`/abuse-reports/{id}` | 举报工单列表和详情。 | | `/reports/abuse/{report_id}/target` | 举报目标快照。 | | `/feedback-submissions`、`/feedback-submissions/{id}` | 意见反馈列表和详情。 | | `/outbox/business-events`、`/outbox/group-events` | 业务 Outbox 和群 Outbox 列表。 | | `/outbox/business-events/{id}`、`/outbox/group-events/{id}` | Outbox 详情。 | | `/org/departments`、`/org/members` | 组织部门和组织成员。 | | `/workbench/apps` | 工作台应用配置。 | | `/dashboard/summary` | 租户任务看板摘要。 | | `/feedback-config`、`/mailbox-config` | 反馈配置、总经理信箱配置。 | | `/abuse-reasons`、`/app-releases` | 举报原因、App 发布策略。 | 列表接口统一验收 `items/total/page/per_page`,详情接口统一验收 `code=0,data={...}`。用户 ID、雪花 ID、`seq_id`、`dead_id` 等大整数或长 ID 建议按字符串处理,避免前端丢精度。 ### 2.8 Admin 内部配置接口矩阵 IM Server 调 Admin 时统一使用 HMAC 签名,Admin 需提供: | 接口 | 用途 | | --- | --- | | `GET /internal/im-config/tenants/by-code/{tenant_code}` | 按租户编码查询租户。 | | `GET /internal/im-config/tenants/by-id/{tenant_id}` | 按租户 ID 查询租户。 | | `GET /internal/im-config/tenants?state=active&limit=1000` | 拉取启用租户列表。 | | `GET /internal/im-config/registration/sms` | 读取注册短信配置。 | | `GET /internal/im-config/third-party/{group}?keys=a,b` | 读取 OSS、文件安全、声网、极光等第三方配置。 | 联调时需要特别确认 OSS 和文件安全配置已经从 Admin 字典项返回,IM 不再依赖本地硬编码。 ### 2.9 Admin Command 事件矩阵 | 事件类型 | 业务 | | --- | --- | | `group.profile.update` | 后台修改群资料。 | | `group.governance.update` | 后台修改群治理配置。 | | `group.admin.set`、`group.admin.remove` | 设置或取消群管理员。 | | `group.member.mute`、`group.member.unmute` | 成员禁言或解禁。 | | `group.member.remove` | 移除群成员。 | | `group.owner.transfer` | 转让群主。 | | `user.ban`、`user.unban` | 用户封禁和解封。 | | `user.freeze`、`user.unfreeze` | 用户冻结和恢复。 | | `user.device.kick` | 踢指定设备。 | | `user.logout_all` | 全端登出。 | | `user.account.cancel`、`user.account.delete` | 注销或删除账号。 | | `kafka.dead_letter.ignore` | 忽略死信。 | | `kafka.dead_letter.resolve` | 标记死信已解决。 | | `kafka.dead_letter.replay` | 重放死信。 | 所有 Admin Command 都必须带 `event_id`、`tenant_code`、`event_type`、`biz_type`、`biz_id`、`payload.command_id`、`payload.actor_user_id`。Admin 不应把 Kafka 投递成功当成业务成功,最终状态以 `im.admin.command.result` 为准。 ## 3. 通用验收规则 每个 Kafka 用例都必须检查: 1. Kafka 原始事件 `event_id` 全局唯一,同一事件重复投递不会重复产生业务副作用。 2. `tenant_code` 能正确路由到目标租户库。 3. 消费成功后 `im_kafka_consume_log.status=succeeded`。 4. 消费失败后 `retry_count` 增加,并按 `retry_backoff_ms` 重试。 5. 超过上限后写入 `im_kafka_dead_letters`,并投递 `im.dead.letter`。 6. Admin Command 成功、失败、死信都必须回传 `im.admin.command.result`。 7. 业务结果、审计事件、日志里的 `trace_id/event_id/biz_id` 可串联排查。 ## 4. 联调用例 ### TC-KAFKA-001 基础启动与 Topic 连通 目标:验证 Admin 和 IM 都能连接 Kafka,IM 消费者全部启动。 步骤: 1. 启动 Kafka、Redis、MySQL。 2. 启动 Admin/HotGo。 3. 启动 IM Server。 4. 查看 IM 日志应出现 Kafka enabled,且无 consumer 启动错误。 5. Admin 在「IM管理 -> Kafka命令」点击「发送缓存失效测试」,或调用 `POST /admin/imKafkaCommand/cacheInvalidate`,发送一条无业务副作用的测试 `im.cache.invalidate` 事件。 预期: 1. IM 成功消费测试事件。 2. `im_kafka_consume_log` 写入一条 succeeded 记录。 3. 无死信。 ### TC-KAFKA-002 内部接口鉴权成功 目标:验证 Admin 调 IM 内部查询接口签名通过。 请求: ```http GET /v1/internal/admin-query/tenants/default/users/usrxxx X-Service-Name: hotgo-admin X-Timestamp: X-Nonce: X-Signature: ``` 预期: 1. HTTP 200。 2. 响应 `code=0`。 3. 返回用户基础资料。 ### TC-KAFKA-003 内部接口鉴权失败 目标:验证内部接口拒绝错误签名、过期时间戳、重复 nonce。 步骤: 1. 使用错误 secret 调用 `/internal/admin-query/*`。 2. 使用超过时间窗的 timestamp 调用。 3. 使用同一 nonce 重复调用两次。 预期: 1. 错误 secret 返回 401。 2. 过期 timestamp 返回 401。 3. 重复 nonce 第二次返回 401。 4. 业务数据不泄露。 ### TC-KAFKA-004 IM 调 Admin 配置查询 目标:验证 IM 通过 Admin `/internal/im-config/*` 获取 hotgo 配置。 步骤: 1. 开启 IM `admin_internal_api.enabled=true`。 2. Admin 提供以下接口: - `GET /internal/im-config/tenants/by-code/default` - `GET /internal/im-config/tenants/by-id/1` - `GET /internal/im-config/tenants?state=active&limit=1000` - `GET /internal/im-config/registration/sms` - `GET /internal/im-config/third-party/im_third_party?keys=...` 3. 重启 IM。 4. 执行登录、上传、文件安全配置读取等动作。 预期: 1. IM 优先请求 Admin 内部配置接口。 2. Admin 验签通过并返回必要字段。 3. IM 本地功能正常。 4. Admin 接口异常时,IM 可回落旧 DB 适配器,日志有 warn。 说明:Admin `/internal/im-config/*` 是内部服务接口,不带 `/admin` 后台前缀。 ### TC-KAFKA-005 Admin 群资料修改命令 目标:验证后台群资料修改通过 Kafka 到 IM。 Admin 发送: ```json { "event_id": "admin:group:profile:update:001", "tenant_code": "default", "source_service": "hotgo-admin", "target_service": "im-server", "event_type": "group.profile.update", "biz_type": "group_admin", "biz_id": "grpxxx", "payload": { "command_id": "cmd-group-profile-001", "actor_user_id": "usrAdmin", "topic": "grpxxx", "version": 1, "profile": { "name": "新群名称", "description": "新群描述", "avatar_file_id": "file_xxx" } } } ``` 预期: 1. IM 更新群业务表。 2. `im.admin.command.result` 返回 `status=succeeded`。 3. C 端在线群成员收到业务刷新事件或可重新拉取看到新资料。 4. 消费日志 succeeded。 5. 审计事件已投递。 ### TC-KAFKA-006 Admin 群治理配置 目标:验证后台修改入群审批、全员禁言、成员上传、私聊、邀请开关。 事件类型:`group.governance.update` Payload: ```json { "command_id": "cmd-group-govern-001", "actor_user_id": "usrAdmin", "topic": "grpxxx", "version": 2, "governance": { "join_approval": true, "mute_all": true, "member_upload_files": false, "member_private_chat": false, "member_invite": false } } ``` 预期: 1. 群设置版本递增或与业务规则一致。 2. 新配置对成员发送、上传、邀请等入口生效。 3. Admin 收到成功结果。 ### TC-KAFKA-007 Admin 群成员治理 目标:验证管理员设置、取消、禁言、解禁、移除成员、转让群主。 事件类型: | 命令 | 预期 | | --- | --- | | `group.admin.set` | 成员角色变为 admin。 | | `group.admin.remove` | 成员角色恢复 member。 | | `group.member.mute` | 成员禁言生效。 | | `group.member.unmute` | 成员禁言解除。 | | `group.member.remove` | 成员离群,不能继续收发该群消息。 | | `group.owner.transfer` | 群主变更,旧群主权限调整。 | 每条命令都检查: 1. 租户库业务表状态正确。 2. 在线 C 端收到状态变化。 3. Admin 操作单从 running 变为 succeeded。 4. 重复发送同一 `event_id` 不重复执行。 ### TC-KAFKA-008 用户封禁与解封 目标:验证 Admin 可通过 Kafka 封禁/解封用户。 封禁事件: ```json { "event_id": "admin:user:ban:001", "tenant_code": "default", "event_type": "user.ban", "biz_type": "user_governance", "biz_id": "usrxxx", "payload": { "command_id": "cmd-user-ban-001", "actor_user_id": "usrAdmin", "user_id": "usrxxx", "reason": "违规" } } ``` 步骤: 1. 目标用户保持在线。 2. Admin 发送 `user.ban`。 3. 目标用户尝试继续发消息。 4. 目标用户重新登录。 5. Admin 发送 `user.unban`。 6. 目标用户重新登录。 预期: 1. 封禁后用户状态为 `susp`。 2. 在线会话被踢下线。 3. 封禁期间登录被拒绝。 4. 解封后状态为 `ok`,可正常登录。 5. 两条命令均回传 result。 ### TC-KAFKA-009 用户冻结与恢复 目标:验证冻结/恢复账号命令。 事件类型:`user.freeze`、`user.unfreeze` 预期: 1. `user.freeze` 设置用户状态 `susp` 并踢下线。 2. `user.unfreeze` 恢复用户状态 `ok`。 3. 重复投递同一 `event_id` 不重复产生额外副作用。 ### TC-KAFKA-010 踢指定设备 目标:验证只踢指定设备,不影响同账号其他设备。 前置: 1. 同一用户使用两个设备登录,设备 ID 分别为 `device-a`、`device-b`。 事件: ```json { "event_id": "admin:user:device:kick:001", "tenant_code": "default", "event_type": "user.device.kick", "biz_type": "user_governance", "biz_id": "usrxxx:device-a", "payload": { "command_id": "cmd-device-kick-001", "actor_user_id": "usrAdmin", "user_id": "usrxxx", "device_id": "device-a", "reason": "后台踢设备" } } ``` 预期: 1. `device-a` 对应会话被踢。 2. `device-b` 保持在线。 3. `device-a` 推送设备记录被删除。 4. Admin 收到 `evicted_sessions` 数量。 ### TC-KAFKA-011 全端登出 目标:验证后台让用户所有设备退出登录。 事件类型:`user.logout_all` 预期: 1. 用户所有在线会话被踢。 2. 用户状态不改变。 3. 用户可重新登录。 ### TC-KAFKA-012 注销与删除账号 目标:验证 Admin 可注销或删除租户内账号。 事件类型: | 命令 | 预期 | | --- | --- | | `user.account.cancel` | 默认软删除,`hard=true` 时硬删除。 | | `user.account.delete` | 按硬删除处理。 | 步骤: 1. 目标用户在线。 2. Admin 发送注销命令。 3. 查询用户状态。 4. 尝试重新登录。 预期: 1. 用户会话被踢。 2. 用户相关 Topic 被停止。 3. 用户被删除或标记 `del`。 4. 登录失败。 5. Admin 收到 result。 ### TC-KAFKA-013 私聊消息异步落库 目标:验证 Kafka 开启时私聊消息通过 `im.message.persist` 落库。 步骤: 1. 用户 A 与用户 B 建立私聊。 2. A 发送带 `x-im-client-mid` 的私聊消息。 3. 查询 Kafka `im.message.persist`。 4. 查询租户库 `im_messages`。 5. A 使用同一 `x-im-client-mid` 重复发送。 预期: 1. A 立即收到服务端 ack 和 `seq_id`。 2. `seq_id` 为 BIGINT/int64。 3. 消费成功后 `im_messages` 有一条记录。 4. 重复发送不重复落库。 5. 消费日志 succeeded。 ### TC-KAFKA-014 群聊消息异步落库 目标:验证群消息写入 `im_group_messages`,不混入私聊表。 步骤: 1. 创建群并加入至少两个成员。 2. 成员发送群消息。 3. 查询 `im_group_messages`。 4. 查询 `im_messages`。 5. 重连客户端按 Topic seq 拉取消息。 预期: 1. 群消息只写 `im_group_messages`。 2. `seq_id` 单调增长,类型为 BIGINT/int64。 3. 客户端补偿拉取成功。 4. 24 小时热消息可进入 Redis 热缓存。 ### TC-KAFKA-015 消息消费失败重试 目标:验证 `im.message.persist` 消费失败可重试并最终成功。 步骤: 1. 临时制造租户库写入失败,如锁表或停止库连接。 2. 发送消息。 3. 恢复数据库。 4. 等待重试。 预期: 1. `im_kafka_consume_log.retry_count` 增加。 2. 未超过重试上限时不进入死信。 3. 数据库恢复后消息最终落库。 4. 状态变为 succeeded。 ### TC-KAFKA-016 文件上传完成事件 目标:验证文件上传完成后不再产生 `im.file.lifecycle` Kafka 事件。 步骤: 1. 客户端上传文件到 OSS。 2. 上传完成后查询租户库文件记录。 3. 确认 Kafka topic 中没有 `im.file.lifecycle` 依赖。 预期: 1. 文件字节流只进入 OSS。 2. 上传完成后的文件记录已同步落库。 ### TC-KAFKA-017 消息附件绑定 目标:验证消息落库后附件引用同步绑定。 步骤: 1. 上传图片或文件。 2. 发送带附件的私聊消息。 3. 发送带附件的群聊消息。 4. 查询附件引用表。 预期: 1. 私聊附件写入 `im_filemsglinks`。 2. 群聊附件写入 `im_group_files`。 3. 重复消费不重复绑定。 4. 文件 ACL 与业务引用可追踪。 ### TC-KAFKA-018 群文件登记与删除 目标:验证群文件业务由 HTTP 接口同步落库。 步骤: 1. 群内登记文件。 2. 查询 `im_group_files`。 3. 删除群文件。 4. 检查生命周期事件和审计事件。 预期: 1. 群文件登记成功。 2. 删除状态正确。 3. 文件事件可用于后续回收/合规删除。 ### TC-KAFKA-019 工作台会议事件 目标:验证会议创建、更新、取消、提醒、参会响应产生工作台事件。 步骤: 1. 创建会议。 2. 修改会议。 3. 发送提醒。 4. 参会人响应。 5. 取消会议。 预期: 1. 每个动作同步写 `im_system_notifications`。 2. 同步写 `im_business_events_outbox`。 3. 在线 C 端收到系统通知或红点刷新。 Admin 连通性补充:工作台事件不再走 Kafka,真实会议、日报/月报、信箱业务结果以 IM Server 对应业务用例为准。 ### TC-KAFKA-020 日报/月报事件 目标:验证日报、月报提交和催办事件。 步骤: 1. 创建日报草稿。 2. 保存并提交日报。 3. 管理员催办日报。 4. 创建、提交、重开月报。 预期: 1. 通知目标用户正确。 2. 工作台红点或系统通知可被客户端看到。 ### TC-KAFKA-021 总经理信箱事件 目标:验证总经理信箱提交事件和审计。 步骤: 1. 用户提交信箱内容。 2. 检查同步生成的通知/业务事件。 3. Admin 后台生成处理单。 预期: 1. 提交成功后有工作台事件。 2. 审计事件包含用户、租户、业务 ID。 3. Admin 可基于事件处理。 ### TC-KAFKA-022 配置事件失效 目标:验证 Admin 配置变更后 IM 清理进程内缓存。 事件类型: | 事件 | 预期 | | --- | --- | | `tenant.updated` | 清租户缓存。 | | `tenant.status.changed` | 清租户缓存。 | | `tenant.limits.updated` | 清租户配置缓存。 | | `tenant.features.updated` | 清租户功能缓存。 | | `dictionary.updated` | 清字典/第三方配置缓存。 | | `third_party.updated` | 清第三方配置缓存。 | | `registration.config.updated` | 清注册短信配置缓存。 | 步骤: 1. Admin 修改配置。 2. 发送 `im.config.event`。 3. IM 再次读取对应配置。 预期: 1. IM 消费成功。 2. 下次读取不使用旧缓存。 3. 可从 Admin 内部配置接口重新获取新值。 ### TC-KAFKA-023 通用缓存失效 目标:验证 `im.cache.invalidate` 可按 namespace 删除缓存。 示例事件: ```json { "event_id": "cache:user:001", "tenant_code": "default", "event_type": "cache.redis_object.invalidate", "biz_type": "cache", "biz_id": "user:usrxxx", "payload": { "tenant_code": "default", "tenant_id": 1, "namespace": "user", "keys": ["usrxxx"] } } ``` 预期: 1. 用户 Redis 对象缓存被删除。 2. 后续查询重新读 MySQL 或 Admin 内部配置接口。 3. 消费幂等。 ### TC-KAFKA-024 群热消息缓存失效 目标:验证群热消息可按 Topic 或 seq range 失效。 事件: ```json { "event_id": "cache:group-hot:001", "tenant_code": "default", "event_type": "cache.group_hot_messages.invalidate", "biz_type": "cache", "biz_id": "grpxxx", "payload": { "tenant_id": 1, "namespace": "group_hot_messages", "topic": "grpxxx", "ranges": [{"low": 100, "hi": 120}] } } ``` 预期: 1. 指定群热消息范围失效。 2. 客户端再次拉取时能从最终存储补偿。 ### TC-KAFKA-025 死信生成 目标:验证不可恢复错误进入死信。 步骤: 1. Admin 发送不存在用户或非法 payload 的命令。 2. 或临时制造持续失败直到超过最大重试。 3. 查询 `im_kafka_dead_letters`。 4. 消费 `im.dead.letter`。 预期: 1. 死信表出现记录。 2. 死信 Topic 有 `kafka.dead_letter.created`。 3. Admin 操作单收到 `status=dead` 的 result。 4. 死信记录包含原始 envelope、reason、error、retry_count。 ### TC-KAFKA-026 死信查询 目标:验证 Admin 可通过 IM 内部 API 查询死信。 请求: ```http GET /v1/internal/admin-query/tenants/default/kafka/dead-letters?status=dead&limit=50 GET /v1/internal/admin-query/tenants/default/kafka/dead-letters/{dead_id} ``` 预期: 1. 列表返回摘要,不返回超大 envelope。 2. 详情返回原始 envelope。 3. 支持 `status/biz_type/biz_id/event_type/cursor/limit` 过滤。 ### TC-KAFKA-027 死信忽略与解决 目标:验证 Admin 可通过 Kafka 命令处理死信状态。 事件类型: ```json { "event_type": "kafka.dead_letter.ignore", "payload": { "command_id": "cmd-dead-ignore-001", "actor_user_id": "usrAdmin", "dead_id": "evt_dead_xxx", "note": "测试死信忽略" } } ``` 预期: 1. `ignore` 后死信状态为 `ignored`。 2. `resolve` 后死信状态为 `resolved`。 3. Admin 收到 result。 4. 审计事件已投递。 ### TC-KAFKA-028 死信重放 目标:验证死信可人工重放。 步骤: 1. 修复导致死信的业务数据或配置。 2. Admin 发送 `kafka.dead_letter.replay`。 3. 观察原 Topic 是否重新收到 envelope。 4. 查询死信记录和消费日志。 预期: 1. IM 将死信改为 `pending_replay`。 2. 删除原 `im_kafka_consume_log`。 3. 按原 `source_topic` 重投 envelope。 4. 重投成功后死信状态为 `replayed`,`replay_count` 增加。 5. 原业务消费者重新处理并成功。 ### TC-KAFKA-029 审计事件 目标:确认 IM Server 对跨系统审计仍生产 `im.audit.event`,由 Admin/HotGo 消费后同步落审计表。 覆盖: 1. 群治理命令。 2. 用户治理命令。 3. 文件生命周期。 4. 工作台状态变化。 5. 死信生成和处理。 预期: 1. IM Server 生产 `im.audit.event`。 2. Kafka consumer 启动日志中没有 IM 侧审计事件 consumer。 3. Admin/HotGo 消费审计事件并同步写入审计表。 ### TC-KAFKA-030 IM 侧 Kafka 生产失败 目标:验证 IM 侧 Kafka 直接生产失败时不会产生 DB outbox,调用方收到发送失败。 预期: 1. Kafka 停止时 IM 不写 `im_kafka_outbox`,消息发送返回失败。 2. 恢复后客户端可重新发送。 3. 重复发送依赖 `client_mid` 和消费日志保持幂等。 4. 不重复产生业务副作用。 ## 5. Admin 侧联调检查清单 | 检查项 | 验收标准 | | --- | --- | | 操作单 | 每个后台写操作先写 hotgo 操作单。 | | Admin outbox | 操作单与 outbox 同事务写入。 | | Command 生产 | `event_id/idempotency_key/tenant_code/biz_id` 稳定可追踪。 | | Result 消费 | `im.admin.command.result` 能更新操作单状态。 | | 死信消费 | `im.dead.letter` 能生成告警或待处理记录。 | | 审计 | 消费 `im.audit.event`,同步落 HotGo 审计表。 | | 配置接口 | `/internal/im-config/*` 支持 IM HMAC 调用。 | | 查询客户端 | 调 IM `/internal/admin-query/*` 带签名并处理 401/403/404/5xx。 | | 页面状态 | 后台页面显示 pending/running/succeeded/failed/dead,不把 Kafka 发送成功当业务成功。 | ## 6. IM Server 侧联调检查清单 | 检查项 | 验收标准 | | --- | --- | | Kafka 启动 | producer、consumer 正常启动,IM 侧无 DB outbox worker。 | | 租户路由 | `tenant_code` 能路由到正确租户库。 | | 消费幂等 | 重复 `event_id` 不重复执行业务。 | | 重试 | 可重试错误按退避时间重试。 | | 死信 | 超过上限或不可重试错误进入死信并回 result。 | | Admin Query API | 内部接口验签、鉴权、nonce 防重放生效。 | | Admin Config Client | 可从 Admin 拉租户、注册、第三方配置。 | | 用户治理 | 封禁/冻结踢下线,解封/恢复可登录,设备踢出只影响指定设备。 | | 群治理 | 群资料、角色、禁言、移除、转让群主全部生效。 | | 消息落库 | 私聊写 `im_messages`,群聊写 `im_group_messages`。 | | 文件生命周期 | 文件记录、附件引用、群文件同步落到正确业务表。 | | 工作台事件 | 同步生成系统通知和 WS 业务事件。 | | 审计 | IM 生产 `im.audit.event` 给 Admin/HotGo,IM 本地不消费审计 topic。 | ## 7. 回归用例 1. Kafka 关闭时,IM 基础登录、私聊、群聊、文件上传下载仍可用。 2. Redis 异常时,Kafka 消费不应 panic;允许热缓存和 nonce 校验降级按配置表现。 3. Admin 内部配置接口不可用时,IM 本地旧 DB 读取兜底可用。 4. IM 内部查询接口关闭时,Admin 查询应收到 404,不泄露数据。 5. 同一用户在多端登录,`user.device.kick` 只踢指定设备,`user.logout_all` 踢全部设备。 6. 同一 Admin Command 重复发送 3 次,业务只成功一次,结果可重复查询。 7. 群消息高并发发送时 `seq_id` 单调递增且无重复。 8. 文件上传后未发送消息,不应产生错误附件引用。 9. 工作台事件目标用户为空时,不应产生错误通知。 10. 死信重放失败后应再次进入死信,不覆盖原处理痕迹。 ## 8. 联调问题定位 | 现象 | 优先排查 | | --- | --- | | Admin 操作一直 pending | Admin outbox 是否成功投递;`queue.driver` 是否为 `kafka`;Kafka broker 是否可用。 | | Admin 操作一直 running | Admin 是否消费 `im.admin.command.result`;IM 是否收到 command;`event_id` 是否重复卡在 processing。 | | IM 消费失败 | 查 `im_kafka_consume_log.last_reason/last_error` 和 IM 日志 `event_id`。 | | 进入死信 | 查 `im_kafka_dead_letters.envelope/last_error`,修复后用重放命令。 | | 用户没有被踢下线 | 查目标 `user_id` 是否是 IM 用户 ID;是否连接在当前 IM 节点;跨节点踢人是否需要后续 Redis fanout 扩展。 | | 群治理未生效 | 查 `topic/version/actor_user_id` 是否正确,目标用户是否为群成员。 | | 消息未落库 | 私聊查 `im.message.persist`,群聊查 `im.group.message.persist` 是否消费成功,以及 `im_kafka_consume_log.last_reason/last_error`。 | | 附件未绑定 | 查消息是否带附件,以及同步绑定逻辑是否返回错误。 | | 内部 API 401 | 查 secret、签名文本、RequestURI、timestamp、nonce 是否一致。 | | 配置没有刷新 | 查是否发送 `im.config.event` 或 `im.cache.invalidate`,IM 是否清理了对应 namespace。 | ## 9. 联调完成标准 1. 本文所有 P0/P1 用例通过:Kafka 基础、Admin Command、用户治理、群治理、消息异步落库、文件生命周期同步处理、工作台同步处理、缓存失效、死信。 2. Admin 操作单状态闭环可视化:pending -> running -> succeeded/failed/dead。 3. IM 租户库无重复业务记录,Kafka 消费日志无异常堆积。 4. 死信可查询、可忽略、可解决、可重放。 5. Admin 与 IM 均不跨库直连,内部查询接口鉴权通过。 6. 离线 Push Kafka 化未纳入本次验收,继续按增强项跟进。 ## 10. 本地 Docker 联调记录 ### 10.1 2026-08-27 冒烟联调 本轮不是全量联调,只完成本地 Docker 环境启动和 Kafka/内部接口主链路冒烟。后续仍需按第 4 章逐条补齐。 联调环境: | 组件 | 地址/容器 | 结果 | | --- | --- | --- | | MySQL | `relaxed_cori:3306`,宿主机 `127.0.0.1:3306` | 已连接,本地库包含 `hotgo`、`tinode`。 | | Redis | `brave_blackburn:6379`,宿主机 `127.0.0.1:6379` | 已连接。 | | Kafka | `im-local-kafka:9092`,宿主机 `127.0.0.1:19092` | 已创建联调 Topic。 | | IM Server | `im-local-im:6060`,宿主机 `127.0.0.1:6060` | healthy,Kafka consumer 已启动。 | | Admin/HotGo | `im-local-admin:8000`,宿主机 `127.0.0.1:8000` | healthy,Kafka consumer 已启动。 | 说明:本地已有 Kafka 容器 `kafka:9092` 的 `advertised.listeners=localhost:9092`,Docker 内服务会回连自身 localhost,故本轮单独启动 `im-local-kafka` 用于容器联调。 本轮已测: | 用例/链路 | 测试内容 | 结果 | 证据 | | --- | --- | --- | --- | | TC-KAFKA-001 | Kafka Topic 创建,IM consumer 启动。 | 通过 | IM 日志显示 `im.admin.command`、`im.config.event`、`im.cache.invalidate`、`im.message.persist`、`im.group.message.persist` consumer started。 | | TC-KAFKA-002 | Admin -> IM 内部查询 HMAC。 | 通过 | `GET /internal/admin-query/tenants/default/users?page=1&per_page=1` 返回 `code=0`,`total=29`。 | | TC-KAFKA-004 | IM -> Admin 内部配置 HMAC。 | 通过 | `GET /internal/im-config/tenants?limit=1000&state=active` 返回 `code=0` 和 default 租户。 | | TC-KAFKA-008/011 | `user.logout_all` 后台用户治理命令。 | 通过 | `tinode.im_kafka_consume_log` 中 `local-logout-fixed-*` 状态为 `succeeded`。 | | TC-KAFKA-023 | `im.cache.invalidate` 通用缓存失效。 | 通过 | `local-cache-*` 写入 `im_kafka_consume_log`,状态 `succeeded`,IM 日志显示 `kafka cache invalidate applied`。 | | TC-KAFKA-025 | 非法 `user.logout_all` 进入死信。 | 通过 | `local-logout-*` 状态为 `dead`,`im_kafka_dead_letters` 写入 `MALFORMED_COMMAND`。 | | TC-KAFKA-029 | 用户治理审计事件。 | 通过 | IM 生产 `im.audit.event`,Admin/HotGo 消费后同步落审计表。 | 本轮发现并处理: | 问题 | 现象 | 处理 | | --- | --- | --- | | Admin Docker 前端构建失败 | `pnpm run build` 非 TTY 环境报 `ERR_PNPM_ABORTED_REMOVE_MODULES_DIR_NO_TTY`。 | Admin `Dockerfile` 增加 `ENV CI=true`。 | | Admin Kafka 版本配置不兼容 | Admin 启动时报 `invalid version 2.0.0.0`。 | 本地联调配置临时改为 `version: "2.0.0"`。 | | IM 启动缺少 UID key | IM 报 `crypto/xtea: invalid key size 0`。 | Docker 启动显式传入 `UID_ENCRYPTION_KEY`、`API_KEY_SALT`、`AUTH_TOKEN_KEY`。 | | HotGo 表前缀不一致 | Admin 内部配置接口错误查询 `hg_im_tenant`,但 IM 业务/配置表正式表名应保持 `im_tenant`。 | 联调时暴露的是 Admin 查询/ORM 表名前缀问题;正式方案必须修 Admin 侧表名映射或 DAO 前缀逻辑,不能新增 `hg_im_*` 兼容表。 | | Admin result 消费格式不兼容 | Admin 消费 `im.admin.command.result` 报 `IM命令结果缺少command_id`。 | Admin consumer 已兼容 Kafka Envelope + payload 格式。 | | Admin 审计表前缀不一致 | Admin 消费 `im.audit.event` 后错误查询 `hg_im_audit_events`,正式表名应保持 `im_audit_events`。 | Admin/HotGo 同步写审计表时,仍需保证所有 `im_*` 业务表不加 `hg_` 前缀。 | 本轮未覆盖,后续继续: | 范围 | 待测内容 | | --- | --- | | 群治理 | 群资料、治理配置、管理员设置/取消、成员禁言/解禁、移除成员、转让群主。 | | 用户治理完整集 | `user.ban`、`user.unban`、`user.freeze`、`user.unfreeze`、`user.device.kick`、注销/删除账号。 | | 消息异步落库 | 私聊 `im_messages`、群聊 `im_group_messages`、`seq_id` BIGINT、重复 `client_mid` 幂等。 | | 文件生命周期 | 上传完成、附件绑定、群文件登记/删除、OSS 元数据和引用表。 | | 工作台事件 | 会议、日报/月报、总经理信箱、红点/系统通知投递。 | | 死信闭环 | 死信查询、忽略、解决、重放,以及重放后二次成功/失败。 | | Kafka 生产失败 | Kafka 停止/恢复时,确认 IM 不写 `im_kafka_outbox`,接口/WS 返回发送失败,恢复后可重新发送。 | | Admin 页面 | 操作单状态从 pending/running 到 succeeded/failed/dead 的页面联调。 | ### 10.2 2026-08-27 完整后端链路联调 本轮在本地 Docker 环境继续补齐 Kafka 后端链路联调。覆盖方式以 Kafka 直接投递、内部 HTTP HMAC 调用、MySQL 业务表/消费日志核验为主;Admin 前端页面点击未做浏览器人工验收,页面层需要后续按菜单再走一遍。 联调环境延续 10.1: | 组件 | 地址/容器 | 结果 | | --- | --- | --- | | MySQL | `relaxed_cori:3306` | 正常。 | | Redis | `brave_blackburn:6379` | 正常。 | | Kafka | `im-local-kafka:9092`,宿主机 `127.0.0.1:19092` | 正常;Outbox 用例中曾停止并恢复。 | | IM Server | `im-local-im:6060` | 已重建为包含本轮修复的 `im-local-server:dev`,当前 healthy。 | | Admin/HotGo | `im-local-admin:8000` | 当前 healthy;Kafka 断开时曾 fatal 退出,见问题记录。 | 本轮通过项: | 用例/范围 | 覆盖内容 | 结果 | 证据 | | --- | --- | --- | --- | | TC-KAFKA-003 | IM 内部查询接口未签名访问。 | 通过 | `GET /internal/admin-query/...` 未带签名返回 401 `AUTH_REQUIRED`。 | | TC-KAFKA-004 | Admin 内部配置接口签名成功/失败。 | 通过 | 未签名返回 401;签名访问 `/internal/im-config/tenants?limit=1&state=active` 返回 default 租户。 | | TC-KAFKA-005 | 后台群资料修改。 | 通过 | `group.profile.update` 消费 `succeeded`,`im_group_settings.name/description/version` 更新。 | | TC-KAFKA-006 | 后台群治理配置。 | 通过 | `group.governance.update` 消费 `succeeded`,`join_approval/mute_all/member_*` 更新。 | | TC-KAFKA-007 | 群管理员、禁言、移除、转让群主。 | 通过 | `group.admin.set/remove`、`group.member.mute/unmute/remove`、`group.owner.transfer` 均有成功消费记录;`im_group_members/im_group_mutes` 状态变更正确。 | | TC-KAFKA-008 | 用户封禁与解封。 | 通过 | `user.ban/user.unban` 消费 `succeeded`,用户最终恢复 `state=0`。 | | TC-KAFKA-009 | 用户冻结与恢复。 | 通过 | `user.freeze/user.unfreeze` 消费 `succeeded`,用户最终恢复 `state=0`。 | | TC-KAFKA-010 | 踢指定设备。 | 通过 | `user.device.kick` 消费 `succeeded`,不存在设备按幂等成功处理。 | | TC-KAFKA-011 | 全端登出。 | 通过 | `user.logout_all` 消费 `succeeded`。 | | TC-KAFKA-012 | 注销与删除账号。 | 通过 | `user.account.cancel/user.account.delete` 使用本地测试账号验证,消费 `succeeded`。 | | TC-KAFKA-013 | 私聊消息异步落库。 | 通过 | `message.persist.p2p` 消费 `succeeded`,`im_messages` 写入测试消息。 | | TC-KAFKA-014 | 群聊消息异步落库。 | 通过 | `im.group.message.persist` 消费 `message.persist.group`,`im_group_messages` 写入测试群消息。 | | TC-KAFKA-016 | 文件上传完成事件。 | 通过 | 文件上传完成不再走 Kafka。 | | TC-KAFKA-017 | 消息附件绑定。 | 通过 | 群聊附件绑定写入 `im_group_files`;私聊附件绑定修复后写入 `im_filemsglinks`。 | | TC-KAFKA-018 | 群文件登记与删除生命周期。 | 通过 | 群文件登记/删除同步落库。 | | TC-KAFKA-019 | 工作台会议事件。 | 通过 | 同步写入 `im_system_notifications` 和 `im_business_events_outbox`。 | | TC-KAFKA-022 | 配置事件失效。 | 通过 | `dictionary.updated` 消费 `succeeded`。 | | TC-KAFKA-023 | 通用缓存失效。 | 通过 | `cache.redis_object.invalidate` 消费 `succeeded`。 | | TC-KAFKA-024 | 群热消息缓存失效。 | 通过 | `cache.group_hot_messages.invalidate` 消费 `succeeded`。 | | TC-KAFKA-025 | 死信生成。 | 通过 | 故意发送非法 `user.logout_all`,消费状态 `dead`,写入 `im_kafka_dead_letters`。 | | TC-KAFKA-026 | 死信查询。 | 通过 | `/internal/admin-query/tenants/default/kafka/dead-letters` 和详情接口返回 200。 | | TC-KAFKA-027 | 死信忽略与解决。 | 通过 | `kafka.dead_letter.ignore/resolve` 消费 `succeeded`,死信状态变为 `ignored/resolved`。 | | TC-KAFKA-028 | 死信重放。 | 通过 | `kafka.dead_letter.replay` 消费 `succeeded`,死信状态变为 `replayed`,`replay_count=1`。 | | TC-KAFKA-029 | 审计事件。 | 通过 | `im.audit.event` 投递给 Admin/HotGo,消费侧同步落审计表。 | | TC-KAFKA-030 | IM Kafka Outbox 可靠投递。 | 通过 | Kafka 停止时 outbox `pending -> failed`;Kafka 恢复并重启 IM 后 `failed -> sent`,下游消费成功。 | 本轮消费统计: | 口径 | 数量 | | --- | ---: | | `codex_it_*` 和本轮修复验证事件总数 | 38 | | 成功消费 | 35 | | 故意制造死信 | 3 | | 修复后仍卡 processing | 0 | 代表性事件: | 类型 | Event ID | | --- | --- | | 用户治理批次 | `codex_it_110224_*` | | 群成员移除复测 | `codex_it_remove_110302_271b2ff6` | | 私聊/群聊消息落库 | `codex_it_msg_110432_*`、`codex_it_msg_110434_*` | | 私聊附件修复验证 | `codex_it_fix_p2p_attach_b93a9a4b` | | 工作台事件 | `codex_it_evt_110730_workbench_meeting_created_b764faa3` | | Outbox 断 Kafka 恢复 | `codex_it_outbox_7f52e221` | | 死信处理 | `codex_it_dead_111524_*`、`codex_it_dead_111528_*`、`codex_it_dead_111531_*` | 本轮发现并处理: | 问题 | 影响 | 处理结果 | | --- | --- | --- | | 私聊附件绑定触发 IM panic | `file.attachments.bind` 对私聊消息调用 `store.Files.LinkAttachments(tenantID, "", msgId, attachments)` 时,空 topic 进入 `types.GetTopicCat(topic)` 导致 `slice bounds out of range`,IM 退出。 | 已修复 `server/store/store.go`:仅当 `topic != ""` 时判断 `TopicCatMe`;重建 IM 后复测私聊附件绑定成功,`im_filemsglinks` 写入。 | | Kafka 停止时 Admin 进程 fatal 退出 | Outbox 断 Kafka 用例中停止 `im-local-kafka` 后,Admin consumer 报 `client has run out of available brokers` 并 `FATA` 退出。 | 已记录为 Admin 侧待修复问题:Kafka consumer 断 broker 不应 fatal,应退避重连。 | | Kafka 停止/恢复后 IM consumer 自动恢复不稳定 | Kafka 恢复后,IM 仍 healthy,但消费端未立即消费新探针;重启 IM 后积压事件被补偿消费。 | 已记录为 IM 侧增强/修复项:Kafka reader 断 broker 后需要自动重建 reader 并继续消费。 | | 备用群业务快照不一致 | 对 `grpEC7ddYMoI5s` 执行 `group.member.remove` 返回 `RESOURCE_NOT_FOUND` 并进入死信。 | 换用业务表已确认成员的 `grpgvTd1mFvM2M` 后移除成功;前一次作为死信生成用例保留。 | 未做或需要人工补充: | 范围 | 说明 | | --- | --- | | Admin 前端页面点击 | 本轮验证了后端接口、Kafka 生产消费和数据库状态;未使用浏览器逐个菜单点选操作单页面、死信页面、审计页面。 | | 真实客户端 WS 在线通知 | 后台命令会生成业务事件/系统通知;本轮未启动真实 C 端 WebSocket 客户端观察 UI 实时刷新。 | | Admin 查询迁移状态 | 本轮验证 IM Server 内部查询接口可用,但 Admin 查询侧尚未全部切换到内部查询 API,页面查询隔离需要后续迁移。 | | 离线 Push | 按既定范围仍放在未实现增强项,本轮不验收。 | ### 10.3 2026-08-27 内部查询 API 双向联调 本轮在本地 Docker 环境重建 `im-local-server:dev` 和 `im-local-admin:dev` 后,对 Admin 查询 IM Server、IM Server 查询 Admin 两个方向做 HMAC 内部接口联调。IM Server 使用本地 MySQL `tinode`,Admin 使用本地 MySQL `hotgo`;Admin 本地联调容器为了避开队列消费者 Kafka 版本解析退出问题,临时使用 `disk` 队列驱动,不影响本节 HTTP 内部接口结论。 双向接口结果: | 方向 | 接口/范围 | 结果 | 证据 | | --- | --- | --- | --- | | Admin -> IM Server | `/internal/admin-query/tenants/default/users?page=1&per_page=3` | 通过 | 返回 200,首条 `user_id=1565659909440147456`,JSON 类型为 number。 | | Admin -> IM Server | `/internal/admin-query/tenants/default/users/{user_id}` | 通过 | 使用数据库 BIGINT 用户 ID 查询详情返回 200。 | | Admin -> IM Server | `/internal/admin-query/tenants/default/users?user_id={user_id}` | 通过 | 使用数据库 BIGINT 用户 ID 过滤列表返回 200。 | | Admin -> IM Server | `/internal/admin-query/tenants/default/groups/grpgvTd1mFvM2M` | 通过 | 返回 200,`owner_id=1565659909045882880`,JSON 类型为 number。 | | Admin -> IM Server | `/internal/admin-query/tenants/default/groups/grpgvTd1mFvM2M/members` | 通过 | 返回 200,成员 `user_id/joined_by` 均为数据库 BIGINT number。 | | Admin -> IM Server | `/internal/admin-query/tenants/default/kafka/dead-letters?limit=1` | 通过 | 返回 200。 | | Admin -> IM Server | 未签名请求 | 通过 | 返回 401,提示 `internal signature required`。 | | IM Server -> Admin | `/internal/im-config/tenants?limit=1&state=active` | 通过 | 返回 200,租户 `default`,业务库 `tinode`。 | | IM Server -> Admin | `/internal/im-config/tenants/by-code/default` | 通过 | 返回 200,租户 `default`,业务库 `tinode`。 | | IM Server -> Admin | `/internal/im-config/registration/sms` | 通过 | 返回 200,`enabled=true`。 | | IM Server -> Admin | `/internal/im-config/third-party/oss?keys=endpoint,bucket,access_key_id` | 通过 | 返回 200,配置 map 正常返回。 | | IM Server -> Admin | 未签名请求 | 通过 | 返回 401。 | 运行时链路也已确认:`im-local-im` 启动后持续通过 Docker 网络访问 `im-local-admin:8000/internal/im-config/tenants?limit=1000&state=active`,Admin 日志显示每 2 秒一次返回 200,说明不是只通过脚本单独打通。 本轮发现并处理: | 问题 | 影响 | 处理结果 | | --- | --- | --- | | Admin `/internal/im-config/registration/sms` HTTP 200 但业务 `code=53` | IM Server 查询注册短信开关时会拿到业务失败响应。 | 已修复 Admin 控制器扫描目标,将 `g.Map` 改为 `*entity.SysConfig`,重建 Admin 后复测返回 `code=0`。 | | Admin 本地容器入口模板缺少新增内部接口配置 | 使用默认入口脚本会覆盖完整 `config.yaml`,导致内部接口密钥配置丢失。 | 本地联调改为挂载完整临时配置并直接启动 `./hotgo`;正式镜像建议同步补齐 `config.template`。 | | Admin 本地 Kafka 队列版本解析退出 | Admin 启动队列消费者时 `invalid version 2.0.0.0`,进程 fatal。 | 本地 HTTP 联调临时切到 `disk` 队列驱动;Kafka consumer 退避重连和版本配置仍按增强项跟进。 | | Admin 租户表查询仍出现 `hg_im_tenant` | 默认数据库前缀 `hg_` 会污染 `im_tenant/im_tenant_config` 这类 IM 公共表查询。 | 已修复 Admin `imtenant.RegistryDB()`:自动建立/使用 `Prefix` 为空的 `imRegistry` 连接;重建 Admin 后日志确认查询 `hotgo.im_tenant`,不再访问 `hg_im_tenant`。 | ID 口径结论:IM Server 外部聊天协议仍使用 `usr...`;Admin 内部管理/查询接口统一使用数据库 BIGINT/int64,查询返回和写命令入参不再混用 Tinode `usr...` 格式。