Files
im_server/docs/IM-Kafka接入联调测试文档.md
T

1128 lines
46 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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: <unix_seconds>
X-Nonce: <random>
X-Signature: <hmac_sha256_hex>
```
预期:
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...` 格式。