tasks.md 8.2 KB


description: "Task list for 骑手与用户 IM 即时沟通账号接入"

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

Input: Design documents from /specs/012-im-user-integration/

Prerequisites: plan.md ✅, spec.md ✅, research.md ✅, data-model.md ✅, contracts/ ✅, quickstart.md ✅

Tests: 项目无自动化测试约定,不生成测试任务;验证通过 quickstart.md 手动场景完成。

Organization: 按用户故事分组。注意:本特性 3 个故事围绕同一接口,存在依赖(US3 配置→US1 接口→US2 幂等),按依赖顺序排列。

Format: [ID] [P?] [Story] Description

  • [P]: 可并行(不同文件、无未完成依赖)
  • [Story]: 所属用户故事(US1/US2/US3)
  • 描述含确切文件路径

Phase 1: Setup(数据库变更)

Purpose: info_user 表新增 IM 凭证两列

  • T001 在 updatesql/sql.md 追加 info_user 加列 SQL:ALTER TABLE info_user ADD COLUMN im_api_key VARCHAR(64) DEFAULT NULL COMMENT 'IM平台API密钥';ALTER TABLE info_user ADD COLUMN im_user_id BIGINT DEFAULT NULL COMMENT 'IM平台用户ID';(标注日期 2026-06-23 与用途,不直接执行)

Phase 2: Foundational(阻塞前置,所有故事依赖)

Purpose: 实体字段、映射、配置、外部客户端、返回 VO —— 用户故事开始前必须就绪

⚠️ CRITICAL: 本相位完成前不得开始用户故事

  • T002 [P] ruoyi-system/src/main/java/com/ruoyi/system/domain/InfoUser.java:新增 imApiKey(String) 与 imUserId(Long) 两字段(带 @Excel 注解与注释,IM apiKey / IM userId);该类用 Lombok @Data 自动生成 getter/setter
  • T003 [P] ruoyi-system/src/main/resources/mapper/infouser/InfoUserMapper.xml:在 InfoUserResult resultMap 追加 <result property="imApiKey" column="im_api_key"/><result property="imUserId" column="im_user_id"/>selectInfoUserVo 为 select *,无需改 SQL)
  • T004 [P] ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/ImAccountVo.java:新建返回 VO,含 apiKey(String) 与 imUserId(String,规避前端 Long 精度丢失);用 @Data
  • T005 [P] ruoyi-admin/src/main/resources/application.yml:新增 im 配置段(base-url / ext-token / create-path / timeout-ms),测试值 base-url=https://test-im.abtim-my.com、ext-token=92a88467-6eca-11f1-9dd5-00163e1eec55、create-path=/bot/extCreate、timeout-ms=5000(参考现有 ezpay/newebpay 段风格)【满足 US3 配置集中管理】
  • T006 [P] ruoyi-admin/src/main/java/com/ruoyi/app/utils/im/ImClient.java:新建 @Component@Value 注入 im.base-url/im.ext-token/im.create-path/im.timeout-ms;方法 ImAccountVo createAccount()org.apache.http(仿 NewebPay.postFormRaw)发 POST {base-url}{create-path},请求头带 extToken,设连接/读取超时,解析 fastjson2 响应:code==200 && data.apiKey/userId 非空 → 填充 VO(imUserId 转 String);否则抛 ServiceException【满足 US3 配置注入】

Checkpoint: 数据层 + 外部 IM 客户端就绪,可开始用户故事


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

Goal: APP 调用 POST /infouser/user/im/open,为当前登录用户首次开通 IM 账号并返回凭证

Independent Test: 以未开通用户 token 调用接口 → 返回 apiKey/imUserId 且库中两列成对写入(见 quickstart 场景1)

Implementation for User Story 1

  • T007 [US1] ruoyi-system/src/main/java/com/ruoyi/system/service/IInfoUserService.java:新增方法签名 ImAccountVo openImAccount(Long userId);
  • T008 [US1] ruoyi-system/src/main/java/com/ruoyi/system/service/impl/InfoUserServiceImpl.java:注入 ImClient;实现 openImAccount 首次开通逻辑:getById(userId) → (本期暂不做幂等分支,留 US2)→ imClient.createAccount() 取 VO → updateById 把 apiKey/imUserId 写回用户(成对)→ 返回 VO(注意 imUserId 落库为 Long,VO 用 String)。失败时 ImClient 已抛异常,本层不写库
  • T009 [US1] ruoyi-admin/src/main/java/com/ruoyi/app/user/InfoUserController.java:新增 @PostMapping("/im/open")(复用现有 JwtUtil/request,仿 NewebPayPayController 行121-129):从 request.getHeader("token")new JwtUtil().getusid(token) 解析 userId;为空返回未登录错误;否则调 infoUserService.openImAccount(userId),用 AjaxResult.success(data) 返回 VO

Checkpoint: User Story 1 完整可用 —— 首次开通端到端跑通(幂等性暂缺,由 US2 补齐)


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

Goal: 同一用户重复调用开通接口时,直接返回已有凭证,不重复调用 IM 平台

Independent Test: 同一用户连调两次 → 返回凭证一致,IM 侧仅创建一次(见 quickstart 场景2)

Implementation for User Story 2

  • T010 [US2] ruoyi-system/src/main/java/com/ruoyi/system/service/impl/InfoUserServiceImpl.java:在 openImAccount 开头增加幂等分支——getById(userId) 后若 imApiKey 非空(已有凭证),直接组装并返回现有 VO(imUserId 转 String),不再调用 imClient.createAccount();否则走 T008 首次开通逻辑

Checkpoint: 幂等生效,重复调用安全


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

Goal: IM 域名与 extToken 全部来自配置文件,代码无硬编码,环境切换零改码

Independent Test: 改 yml 域名/令牌 → 重启 → 调用指向新地址(见 quickstart 场景4 间接验证)

实现:US3 由 Foundational T005(yml 配置段)+ T006(@Value 注入)已交付。本相位为合规验证。

  • T011 [US3] 验证:grep 确认 ImClient.java 与全工程无硬编码 IM 域名(test-im.abtim-my.com)或 extToken 明文,均经 @Value("${im.*}") 读取;确认 yml 测试/正式环境可仅改配置切换

Checkpoint: 配置集中管理达标


Phase 6: Polish & Cross-Cutting Concerns

Purpose: 跨故事质量与端到端验证

  • T012 [P] 精度复核:确认 ImAccountVo.imUserId 为 String,且 controller 返回 JSON 中 imUserId 为字符串(19 位不丢精度);确认 InfoUser.imUserId 落库为 Long/BIGINT 不溢出
  • T013 [P] 按 specs/012-im-user-integration/quickstart.md 执行场景 1~5 全部验证并记录结果
  • T014 [P] 回归确认:用户注册相关接口(骑手/商家/普通用户注册)行为与返回结构未被改动

Dependencies & Execution Order

Phase Dependencies

  • Setup (Phase 1): 无依赖,立即开始(T001 仅写 SQL 文件,不执行)
  • Foundational (Phase 2): T002~T006 可并行(不同文件);本相位阻塞所有用户故事
  • US1 (Phase 3): 依赖 Foundational;内部 T007→T008→T009(接口→实现→控制器)
  • US2 (Phase 4): 依赖 US1 的 T008(在已有 service 方法上加幂等分支)
  • US3 (Phase 5): 实现已在 Foundational T005/T006;T011 仅验证
  • Polish (Phase 6): 依赖全部用户故事完成

Within Each User Story

  • 接口签名 → 实现 → 控制器(US1)
  • 幂等分支在首次开通逻辑就绪后追加(US2 依赖 US1)

Parallel Opportunities

  • Foundational T002 / T003 / T004 / T005 / T006 可全部并行(不同文件)
  • Polish T012 / T013 / T014 可并行

Implementation Strategy

MVP First(仅 User Story 1)

  1. Phase 1:写 SQL(T001)
  2. Phase 2:字段+映射+VO+配置+ImClient(T002~T006)
  3. Phase 3:service+controller 首次开通(T007~T009)
  4. STOP 验证:quickstart 场景1(首次开通)+ 场景5(全类型)
  5. 可联调交付

Incremental Delivery

  1. Foundational → 基础就绪
  2. +US1 → 首次开通可用(MVP)
  3. +US2 → 重复调用幂等(健壮性)
  4. +US3 验证 → 配置合规
  5. Polish → 精度/回归/全场景

Notes

  • 数据库变更只写 updatesql/sql.md,不直接执行(项目规范)
  • imUserId 在 VO 中用 String,落库用 Long/BIGINT(防前端 JS 精度丢失 + 容纳 19 位)
  • 复用现有 JwtUtil.getusid(token) 解析用户,不新增鉴权方式
  • 不改动注册流程(用户明确要求)