diff --git a/docs/工作台迁移对接总结文档.md b/docs/工作台迁移对接总结文档.md new file mode 100644 index 0000000..b952b09 --- /dev/null +++ b/docs/工作台迁移对接总结文档.md @@ -0,0 +1,351 @@ +# 工作台迁移对接总结文档 + +> 更新时间:2026-09-14。本文用于后续开启新的 `im_workbench` 工作树时快速接手,覆盖当前迁移边界、接口、鉴权、中间件配置、Kafka 事件、数据库现状和验收步骤。 + +## 1. 当前结论 + +工作台已从 `im_server` 拆到独立仓库 `im_workbench`,当前阶段只拆服务和接口边界,数据库暂不迁移。工作台接口统一走 `/v1/workbench/*`,由网关分流到 `im_workbench`;登录仍由 `im_server` 负责,登录成功后把 Token 会话写入 Redis,`im_workbench` 从 Redis 校验登录态。 + +当前已完成: + +| 项目 | 状态 | +|---|---| +| 独立 Go 工程 | 已完成,仓库:`/Users/youshunlai/go_workspace/im_workbench` | +| 独立启动 | 已完成,默认监听 `:6061` | +| 新路由 `/v1/workbench/*` | 已完成 | +| Redis Token 鉴权 | 已完成 | +| 工作台 Kafka 事件生产 | 已完成 | +| 测试环境中间件配置 | 已更新 | +| 数据库迁移 | 暂不迁移,仍使用租户库 `tinode` | +| `im_server` 旧工作台代码 | 暂保留,等新服务稳定后再删 | + +最近关键提交: + +| 仓库 | Commit | 说明 | +|---|---|---| +| `im_workbench` | `8b5c5e3` | 兼容当前工作台表结构 | +| `im_workbench` | `c1c1156` | 更新新测试环境中间件配置,修复 Kafka 发布 | + +## 2. 服务边界 + +### 2.1 im_workbench 负责 + +| 模块 | 接口范围 | +|---|---| +| 工作台首页 | `GET /v1/workbench` | +| 组织架构 | `/v1/workbench/organization/*` | +| 考勤 | `/v1/workbench/attendance/*` | +| 会议 | `/v1/workbench/meetings*` | +| 会议笔记 | `/v1/workbench/meeting-notes`、`/v1/workbench/meetings/{id}/notes*` | +| 日报 | `/v1/workbench/reports/daily*` | +| 月报 | `/v1/workbench/reports/monthly*` | +| 总经理信箱 | `/v1/workbench/executive-mailbox/*` | +| 工作台业务事件 | 生产 Kafka 事件到 `im.workbench.event` | + +### 2.2 im_server 继续负责 + +| 能力 | 说明 | +|---|---| +| 登录、注册、Token 签发 | C 端登录仍走 `im_server` | +| Redis 登录态写入 | 登录成功后写 `im:session:token:{sha256(token)}` | +| 文件上传 | 暂由 `/v0/file/u/` 处理,工作台只保存 `file_id` | +| WebSocket 实时下发 | 工作台事件由 `im_server` 消费后转 C 端通知 | +| IM 消息、群、好友、在线状态 | 仍全部留在 `im_server` | + +## 3. 网关路由 + +客户端对外仍访问统一域名,由 Nginx/API Gateway 按路径分流: + +```text +/v0/channels -> im_server +/v0/file/u/ -> im_server +/v1/im/* -> im_server +/v1/workbench/* -> im_workbench +``` + +测试环境域名: + +| 域名 | 用途 | +|---|---| +| `https://api.118im.com` | 后端 API,包含 `/v1/workbench/*` | +| `https://api-test.118im.com` | 测试 API 备用域名 | +| `https://web.118im.com` | Web 前端同源代理 | + +注意:不要再让 `im_server` 代理工作台新接口。新接口应直接进入 `im_workbench`。 + +## 4. 请求鉴权 + +工作台接口和 IM 产品 HTTP 保持同一套公共 Header: + +| Header | 必填 | 说明 | +|---|---|---| +| `Authorization` | 是 | `Bearer {token}` | +| `X-MeetingIM-APIKey` | 是 | 客户端 API Key | +| `X-Tenant-Code` | 是 | 当前租户编码,例如 `default` | +| `X-IM-Schema` | 是 | 当前固定 `1` | +| `X-Request-ID` | 建议必填 | 请求链路 ID | +| `Idempotency-Key` | 写接口必填 | 写操作幂等键 | + +登录态 Redis Key: + +```text +im:session:token:{sha256(token)} +``` + +Redis Value: + +```json +{ + "user_id": 1572927143048908800, + "tenant_id": 1, + "tenant_code": "default", + "device_id": "ios-device-1", + "auth_level": "auth", + "state": "active", + "issued_at": "2026-09-14T10:00:00Z", + "expires_at": "2026-09-14T12:00:00Z" +} +``` + +鉴权流程: + +1. `im_workbench` 校验 `X-MeetingIM-APIKey` 非空或命中配置白名单。 +2. 从 `Authorization` 读取 Bearer Token。 +3. 对 Token 做 `sha256`,查 Redis 登录态。 +4. 校验 `state=active`、未过期。 +5. 校验 Header 的 `X-Tenant-Code` 与登录态 `tenant_code` 一致。 + +测试环境当前可用 API Key 以部署文档为准,最近验证可用的是新测试环境文档中的 `TINODE_API_KEY`。 + +## 5. 测试环境配置 + +配置文件: + +```text +/Users/youshunlai/go_workspace/im_workbench/configs/workbench.test.json +``` + +当前关键配置: + +| 配置 | 值 | +|---|---| +| 服务监听 | `:6061` | +| MySQL | `mysql.118im.com:30306` | +| MySQL 业务库 | `tinode` | +| Redis 数据端口 | `redis.118im.com:30637` | +| Redis Sentinel | `redis.118im.com:30638` | +| Kafka Bootstrap | `kafka.118im.com:30835` | +| Kafka 协议 | `PLAINTEXT` | +| Kafka Topic | `im.workbench.event` | + +说明: + +1. Kafka 测试环境是明文直连,不配置 SASL/TLS。 +2. `im.workbench.event` 已在新 Kafka 集群创建。 +3. Redis 数据 NodePort 可能落到主节点或副本。服务正常读登录态没问题;如果本地要写临时测试 session,可能遇到 `READONLY`,需要通过真正主库入口或先走真实登录链路。 +4. MySQL、Redis 密码不写入本文,按 `im_server/docs/problems/新测试环境部署与中间件连接信息.md` 或部署 Secret 获取。 + +## 6. 本地启动 + +本地开发配置: + +```bash +IM_WORKBENCH_CONFIG=configs/workbench.local.json go run ./cmd/workbench +``` + +连接测试环境配置: + +```bash +IM_WORKBENCH_CONFIG=configs/workbench.test.json go run ./cmd/workbench +``` + +如果只做本地接口调试,可以临时打开开发 Header 鉴权: + +```bash +IM_WORKBENCH_CONFIG=configs/workbench.test.json \ +IM_WORKBENCH_ALLOW_DEV_HEADER_AUTH=true \ +go run ./cmd/workbench +``` + +开发 Header: + +```text +X-User-ID: 1572927143048908800 +X-Tenant-ID: 1 +X-Tenant-Code: default +X-MeetingIM-APIKey: x +X-IM-Schema: 1 +X-Request-ID: {uuid} +``` + +注意:`IM_WORKBENCH_ALLOW_DEV_HEADER_AUTH=true` 只能本地调试使用,测试/生产部署不要开启。 + +## 7. Kafka 事件 + +工作台写操作统一投递: + +```text +Topic: im.workbench.event +``` + +事件体: + +```json +{ + "event_id": "wbe_xxx", + "trace_id": "request-id", + "tenant_id": 1, + "tenant_code": "default", + "actor_user_id": 42, + "module": "meeting", + "action": "meeting.created", + "resource_id": "mtg_xxx", + "target_user_ids": [42, 43], + "title": "会议通知", + "summary": "项目周会", + "occurred_at": "2026-09-14T06:00:00Z", + "data": {} +} +``` + +当前事件范围: + +| 模块 | Action | 触发场景 | +|---|---|---| +| 考勤 | `attendance.record.updated` | 打卡成功 | +| 考勤 | `attendance.appeal.created` | 提交考勤申诉 | +| 会议 | `meeting.created` | 创建会议 | +| 会议 | `meeting.updated` | 修改会议 | +| 会议 | `meeting.canceled` | 取消会议 | +| 会议 | `meeting.response.updated` | 更新参会回执 | +| 会议笔记 | `meeting_note.file.created` | 新增会议笔记文件 | +| 会议笔记 | `meeting_note.file.replaced` | 替换会议笔记文件 | +| 会议笔记 | `meeting_note.file.deleted` | 删除会议笔记文件 | +| 日报 | `daily_report.draft.created` | 创建日报草稿 | +| 日报 | `daily_report.draft.saved` | 保存日报草稿 | +| 日报 | `daily_report.submitted` | 提交日报 | +| 日报 | `daily_report.reminded` | 日报提醒 | +| 月报 | `monthly_report.draft.created` | 创建月报草稿 | +| 月报 | `monthly_report.draft.saved` | 保存月报草稿 | +| 月报 | `monthly_report.submitted` | 提交月报 | +| 月报 | `monthly_report.reopened` | 重开月报 | +| 信箱 | `mailbox.submitted` | 提交总经理信箱 | + +已修复问题:`kafka.Writer` 设置了默认 Topic 后,单条 `kafka.Message` 不再重复设置 Topic,否则 `kafka-go` 会报 `Topic must not be specified for both Writer and Message`。 + +## 8. 数据库现状 + +当前数据库不迁移,`im_workbench` 仍连接租户库 `tinode`。 + +主要表: + +| 表 | 用途 | +|---|---| +| `im_workbench_apps` | 工作台模块 | +| `im_org_departments` | 组织部门 | +| `im_org_members` | 组织成员 | +| `im_org_visibility_overrides` | 组织可见范围 | +| `im_attendance_rules` | 考勤规则 | +| `im_attendance_shifts` | 考勤班次 | +| `im_attendance_records` | 考勤记录 | +| `im_attendance_checkins` | 打卡流水 | +| `im_attendance_appeals` | 考勤申诉 | +| `im_meetings` | 会议 | +| `im_meeting_participants` | 会议参与人 | +| `im_meeting_note_files` | 会议笔记文件引用 | +| `im_daily_reports` | 日报 | +| `im_monthly_reports` | 月报 | +| `im_mailbox_config` | 总经理信箱配置 | +| `im_mailbox_submissions` | 总经理信箱提交 | + +已兼容当前表结构: + +| 表 | 当前结构注意点 | 代码处理 | +|---|---|---| +| `im_org_members` | 成员状态字段是 `employment_state` | 查询时返回为 `status` | +| `im_attendance_rules` | 没有 `appeal_deadline` 字段 | 查询返回 `NULL AS appeal_deadline` | +| `im_mailbox_config` | 没有 `version` 字段 | 用 `notice_updated_at` 派生版本 | + +服务启动不自动建库建表,不执行 DDL。所有建表、改字段、初始化数据都走人工 SQL 审核和发布。 + +## 9. 已验证接口 + +使用新测试环境配置启动本地 `im_workbench`,并开启本地开发 Header 鉴权后,已验证: + +| 接口 | 结果 | +|---|---| +| `GET /v1/workbench` | 200 | +| `GET /v1/workbench/organization/departments` | 200 | +| `GET /v1/workbench/attendance/config` | 200 | +| `GET /v1/workbench/executive-mailbox/config` | 200 | +| `POST /v1/workbench/executive-mailbox/submissions` | 200,Kafka 发布成功 | + +同时执行: + +```bash +go test ./... +``` + +结果通过。 + +## 10. 新工作树接手步骤 + +1. 拉取 `im_workbench` 的 `dev` 分支。 +2. 确认包含提交 `c1c1156` 或更新的提交。 +3. 查看 `configs/workbench.test.json`,确认中间件地址是新测试环境域名,不是旧 VM `64.118.137.182`。 +4. 执行 `go test ./...`。 +5. 本地启动: + +```bash +IM_WORKBENCH_CONFIG=configs/workbench.test.json \ +IM_WORKBENCH_ALLOW_DEV_HEADER_AUTH=true \ +go run ./cmd/workbench +``` + +6. 用开发 Header 调 `GET /v1/workbench`、组织、考勤、信箱配置。 +7. 调一个写接口,例如信箱提交,确认返回 200,并在数据库清理测试数据。 +8. 关闭开发 Header 鉴权,走真实登录 Token 验证网关链路。 +9. 验证公网 `/v1/workbench/*` 路由已经进入 `im_workbench`,并确认网关透传 `Authorization`、`X-MeetingIM-APIKey`、`X-Tenant-Code`、`X-IM-Schema`、`X-Request-ID`。 + +## 11. 待后续处理 + +| 事项 | 说明 | +|---|---| +| 真实登录态联调 | 需要通过 `im_server` 登录后生成 Redis session,再从公网 `/v1/workbench/*` 验证 | +| 网关 Header 透传 | 必须确认 `Authorization` 没被 Nginx/API Gateway 清掉 | +| Redis 写入口 | 数据 NodePort 可能落副本,本地造 session 可能遇到 `READONLY` | +| im_server 消费工作台事件 | `im_server` 消费 `im.workbench.event` 后转系统通知/WS 下发需要继续联调 | +| 工作台数据库迁移 | 现阶段不迁,接口稳定后单独做工作台库迁移 | +| 删除 im_server 旧工作台代码 | 等新服务、网关、前端、通知链路全部稳定后再删 | + +## 12. 常见问题 + +### 12.1 `/v1/workbench` 返回 `AUTH_REQUIRED` + +优先检查: + +1. 是否带 `Authorization: Bearer {token}`。 +2. Redis 是否有 `im:session:token:{sha256(token)}`。 +3. session 是否 `state=active` 且未过期。 +4. `X-Tenant-Code` 是否和 session 中的 `tenant_code` 一致。 +5. 网关是否透传 `Authorization`。 +6. `im_workbench` 是否连到了和 `im_server` 相同的 Redis。 + +### 12.2 写接口返回 `workbench event publish failed` + +优先检查: + +1. Kafka broker 是否为 `kafka.118im.com:30835`。 +2. Kafka 是否为 `PLAINTEXT`,不要配置 SASL。 +3. Topic `im.workbench.event` 是否存在。 +4. 服务代码是否已经包含 Kafka 双 Topic 修复。 + +### 12.3 组织或考勤接口 500 + +优先检查当前表结构是否和代码兼容: + +1. `im_org_members` 使用 `employment_state`,不是 `status`。 +2. `im_attendance_rules` 当前没有 `appeal_deadline`。 +3. `im_mailbox_config` 当前没有 `version`。 + +这些兼容已在当前代码中处理;如果新工作树仍 500,先确认是否拉到最新提交。