spec.md 8.1 KB

Feature Specification: 骑手与用户 IM 即时沟通账号接入

Feature Branch: 012-im-user-integration

Created: 2026-06-23

Status: Draft

Input: User description: "骑手和用户沟通要使用 im 功能,我们需要调用 im 的功能,让 im 给我们创建用户;用户表绑定 im 创建用户返回的信息;创建用户调用方法 POST https://test-im.abtim-my.com/bot/extCreate,请求头带 extToken;返回 apiKey 与 userId;im 域名和 extToken 放到配置文件。用户创建过程不改动,APP 在用户创建完成后自己触发接口,后端再去调用 im 方法创建 im 账号。"

User Scenarios & Testing (mandatory)

User Story 1 - APP 触发开通 IM 账号 (Priority: P1)

用户在平台注册完成后,APP 主动调用平台提供的「开通 IM 账号」接口。平台后端识别当前登录用户,向 IM 平台发起创建请求,将 IM 平台返回的 apiKey 与 userId 绑定保存到该用户记录中,并把这两个凭证返回给 APP,供 APP 初始化 IM SDK 进行即时沟通。

Why this priority: 这是整个 IM 沟通能力的根基——没有 IM 账号就无法收发任何消息。它是 MVP 的核心切片,其他故事都依赖它。

Independent Test: 可通过"以某用户身份调用开通接口 → 校验用户表 imApiKey / imUserId 已写入 → 校验接口返回了这两个凭证 → IM 平台确实存在该账号"独立验证,交付价值为"用户已具备 IM 身份并可直接聊天"。

Acceptance Scenarios:

  1. Given 一个已登录、尚未开通 IM 账号的用户,When APP 调用「开通 IM 账号」接口,Then 平台成功调用 IM 平台创建账号,用户表 imApiKey / imUserId 被写入非空值,接口返回这两个凭证。
  2. Given IM 平台返回成功(code=200),When 平台处理响应,Then 仅从 data 节点取出 apiKey 与 userId 落库并返回。
  3. Given IM 平台临时不可用或返回失败,When APP 调用开通接口,Then 接口返回明确的失败信息(不写库),APP 可稍后重试。

User Story 2 - 重复开通幂等返回 (Priority: P2)

同一个用户多次调用「开通 IM 账号」接口时,平台不重复在 IM 平台创建账号,而是直接返回该用户已有的 IM 凭证,保证幂等,避免产生重复 IM 账号。

Why this priority: 幂等是接口健壮性的核心保障,避免 APP 重试或网络抖动导致一个用户绑定多个 IM 账号;优先级仅次于首次开通。

Independent Test: 可通过"对同一用户连续调用两次开通接口 → 确认 IM 平台只创建一次、返回的凭证一致"独立验证。

Acceptance Scenarios:

  1. Given 某用户 imApiKey 已存在,When APP 再次调用开通接口,Then 平台直接返回现有凭证,不再次调用 IM 平台创建。
  2. Given APP 因网络问题重复提交,When 并发或连续到达,Then 该用户最终只拥有一组 IM 凭证。

User Story 3 - IM 配置集中管理 (Priority: P3)

IM 平台的访问域名与鉴权令牌(extToken)集中存放于系统配置文件中,由配置统一管理,代码中不硬编码任何 IM 域名或令牌,便于测试环境与正式环境切换。

Why this priority: 支撑性需求,是 P1/P2 正确、安全运行的前提,但属于工程化而非用户可见功能。

Independent Test: 可通过"修改配置文件中的域名/令牌 → 重启 → 确认调用指向新地址"独立验证。

Acceptance Scenarios:

  1. Given 配置文件已配置 IM 域名与 extToken,When 系统启动,Then 平台读取并使用配置值调用 IM 平台,代码内不出现硬编码域名或令牌。
  2. Given 需要从测试环境切换到正式环境,When 仅修改配置文件,Then 无需改动代码即可完成切换。

Edge Cases

  • IM 平台返回 userId 超出普通整数范围(如 19 位长整型)时,存储字段类型如何避免精度丢失?
  • APP 短时间内多次请求开通接口时,系统如何保证幂等(不重复创建、不覆盖已有有效账号)?
  • IM 平台返回 code 非 200(鉴权失败 / 限流 / 服务异常)时,系统如何明确返回失败,便于 APP 重试?
  • IM 平台调用超时(如 > 5 秒)时,是否阻塞接口响应?超时阈值与重试策略是什么?
  • extToken 泄露或过期,系统如何感知与处理?
  • 未登录或 token 失效调用开通接口,系统应拒绝(不产生账号)。
  • 用户删除后,IM 账号是否需要同步注销?(本期范围外,仅记录)

Requirements (mandatory)

Functional Requirements

  • FR-001: 系统 MUST 提供一个独立的「开通 IM 账号」接口,供 APP 在用户注册完成后(或首次需要沟通时)主动调用;用户注册主流程保持不变,不在注册环节内嵌 IM 开通。
  • FR-002: 系统 MUST 通过当前登录 token 解析出 userId 来识别要开通的用户,不接受由 APP 显式传入 userId(防止越权为他人开通)。
  • FR-003: 系统 MUST 调用 IM 平台创建账号(POST {IM域名}/bot/extCreate,请求头带 extToken),将 IM 平台返回的 apiKey 与 userId 绑定保存到用户表对应字段。
  • FR-004: 系统 MUST 通过请求头 extToken 携带鉴权令牌,令牌值与 IM 域名均从配置文件读取,代码中不硬编码。
  • FR-005: 系统 MUST 正确解析 IM 平台返回结构(外层 code/message,内层 data 含 apiKey/userId),仅取 data 节点落库。
  • FR-006: 系统 MUST 在开通成功后将 apiKey 与 imUserId 返回给 APP,供 APP 初始化 IM SDK。
  • FR-007: 接口 MUST 对所有用户类型开放(普通用户 0 / 商家 1 / 骑手 2 / 夜市 3),由 APP 决定调用方;后端不按用户类型限制。
  • FR-008: 系统 MUST 保证幂等——当目标用户已存在 IM 凭证(imApiKey 非空)时,直接返回现有凭证,不再调用 IM 平台创建。
  • FR-009: 当 IM 平台不可用、返回失败或调用超时时,系统 MUST 返回明确的失败结果,且不在用户表写入无效凭证。

Key Entities (include if feature involves data)

  • InfoUser(用户信息): 平台已有用户表。本期新增两个 IM 凭证字段:imApiKey(IM 平台返回的 API 密钥,字符串)与 imUserId(IM 平台返回的用户ID,长整型 BIGINT)。一个用户对应一组 IM 凭证。
  • IM 平台外部账号: 由 IM 平台管理,通过 extCreate 接口创建,对平台而言是不可变的对外凭证,以 apiKey+userId 形式回传绑定。

Success Criteria (mandatory)

Measurable Outcomes

  • SC-001: 100% 的「开通 IM 账号」接口调用(IM 平台可用时)成功为用户写入并返回 IM 凭证。
  • SC-002: 对同一用户重复调用开通接口,IM 平台账号创建次数为 1,重复请求 100% 命中幂等返回。
  • SC-003: 未登录或 token 失效调用开通接口时,100% 被拒绝,不产生任何 IM 账号或写库。
  • SC-004: IM 创建请求平均耗时控制在可接受范围,接口响应不被显著拖慢(如额外开销 < 1 秒)。
  • SC-005: 测试环境与正式环境的 IM 域名/令牌切换,仅需修改配置文件,零代码改动。

Assumptions

  • 用户注册主流程(骑手注册、商家注册、普通用户注册/登录即注册)保持原样,本期完全不动注册相关代码,仅在注册完成后由 APP 自行调用开通接口。
  • IM 平台创建账号接口(extCreate)对同一外部用户具备可接受的重复请求处理;系统侧额外通过「凭证已存在则直接返回」做幂等保护。
  • IM 平台返回的 userId 为长整型,存储字段按 BIGINT 设计以避免精度丢失。
  • extToken 为平台级共享令牌(非单用户级),所有创建请求共用同一令牌。
  • 接口通过项目现有登录鉴权机制识别当前用户(解析 token → userId),不新增鉴权方式。
  • 配置文件采用项目现有 application.yml 风格(参考 ezpay / newebpay 段),新增独立 im 配置段。
  • HTTP 客户端沿用项目现有 org.apache.http 用法(参考 NewebPay 工具类)。