plan.md 6.1 KB

Implementation Plan: 设备信任免绑手机号

Branch: 029-device-trust-phone-bind | Date: 2026-09-20 | Spec: spec.md

Input: Feature specification from /specs/029-device-trust-phone-bind/spec.md

Summary

同一台设备只要验证过一次手机号(短信登录 / 三方短信绑定 / 三方已绑定直登),即建立"设备→手机号"信任;之后该设备上任何未绑定三方身份登录时,返回脱敏手机号 + tempKey 让用户一键确认(免短信),确认后按现有绑定规则完成绑定并签发 token。LINE 网页回调链路通过 state 参数携带设备标识获得同等能力。只改后端,产出前端契约文档。

技术路径:新表 info_user_device(MyBatis-Plus BaseMapper,无 XML)+ 新服务 DeviceTrustService(upsert/查询/脱敏)+ InfoUserController 三接口加 deviceId 入参与 deviceConfirm 分支 + 新接口 oauthDeviceConfirm + LineCallbackController state 解析。临时凭证沿用 oauth:bind: 前缀,新增正交 key oauth:bind:dev:{tempKey} 绑定设备标识,现有解析逻辑零改动。

Technical Context

Language/Version: Java 21(Maven 多模块:ruoyi-admin / ruoyi-system / ruoyi-common)

Primary Dependencies: Spring Boot、MyBatis + MyBatis-Plus(baomidou)、Lombok、RedisCache(Spring Redis)、自写 JwtUtil(HS256 + Redis 会话)、MessageUtils(i18n messages)

Storage: MySQL(新表 info_user_device,DDL 只写 updatesql/sql.md 人工执行);Redis(临时凭证 oauth:bind:*,TTL 5 分钟)

Testing: JUnit 5 + Mockito,测试位于 ruoyi-admin/src/test/java/com/ruoyi/app/user/(沿用 flashdelivery 测试组织方式)。构建命令:临时 JAVA_HOME=%USERPROFILE%\.jdks\graalvm-jdk-21.0.12+7.1mvn -pl ruoyi-admin -am test -Dtest=XxxTest -DfailIfNoSpecifiedTests=false

Target Platform: Linux 服务器部署的 Spring Boot Web 服务(越南用户端 uni-app 的后端)

Project Type: web-service(单体多模块 Maven)

Performance Goals: 与现有登录接口同量级(服务端处理 < 200ms),仅新增 1 次主键查询/写入,无新增外部调用

Constraints: Controller 参数规范(@RequestBody DTO、DTO 无 Bean Validation 注解、校验放 Controller 用 MessageUtils);模块依赖 ruoyi-admin → ruoyi-system;SQL 不直接执行;保留文件原有 CRLF 换行风格

Scale/Scope: 改 3 个 Controller/DTO 既有文件 + 新增 3 个 Java 文件 + 1 个实体/Mapper + SQL + 测试 + 前端契约文档;前端 uni-app 不在范围

Constitution Check

GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.

.specify/memory/constitution.md 为未填写的空模板,无项目级 gates。以下以 CLAUDE.md 项目规范替代核对:

约束 结果
Controller 请求参数规范(DTO + @RequestBody,无 Map 入参,无 Bean Validation 注解) PASS — 新接口用 OAuthDeviceConfirmDto,deviceId 校验在 Controller 内
模块依赖方向 ruoyi-admin → ruoyi-system PASS — 实体/Mapper 放 ruoyi-system,服务/编排放 ruoyi-admin
数据库变更写入 updatesql/sql.md 不直接执行 PASS — 见 tasks
Java 注释安全(块注释无 */ 序列) PASS
已废弃代码清单(不参考不增量修改) PASS — 不触碰 PayController/ZaloPay 等废弃代码
后端 i18n 错误消息走 MessageUtils PASS — 新增消息 key 加到 i18n 资源文件

Phase 1 设计后复核:全部 PASS,无 Complexity Tracking 需要填写的违规项。

Project Structure

Documentation (this feature)

specs/029-device-trust-phone-bind/
├── plan.md              # This file (/speckit-plan command output)
├── research.md          # Phase 0 output (/speckit-plan command)
├── data-model.md        # Phase 1 output (/speckit-plan command)
├── quickstart.md        # Phase 1 output (/speckit-plan command)
├── contracts/
│   └── api-contract.md  # 前端(uni-app)接口契约
└── tasks.md             # Phase 2 output (/speckit-tasks command - NOT created by /speckit-plan)

Source Code (repository root)

ruoyi-admin/src/main/java/com/ruoyi/app/user/
├── InfoUserController.java          # lodeing/oauthLogin/oauthBindPhone 记录设备信任;oauthLogin 新增 deviceConfirm 分支;新接口 oauthDeviceConfirm
├── LineCallbackController.java      # state 解析为 deviceId;未绑定分支查设备信任回跳 deviceConfirm;已绑定路径记录信任
├── dto/
│   ├── OAuthLoginDto.java           # +deviceId
│   ├── OAuthBindDto.java            # +deviceId
│   └── OAuthDeviceConfirmDto.java   # 新增 {tempKey, deviceId}
└── service/
    └── DeviceTrustService.java      # 新增:recordLogin(upsert)/getTrust/maskPhone

ruoyi-admin/src/test/java/com/ruoyi/app/user/
└── service/
    └── DeviceTrustServiceTest.java  # 设备记录/覆盖/脱敏规则
└── DeviceTrustFlowTest.java         # oauthLogin 分支判定 + oauthDeviceConfirm 成功/过期/不匹配/停用路径

ruoyi-system/src/main/java/com/ruoyi/system/
├── domain/InfoUserDevice.java       # 新增实体(@TableName info_user_device)
├── domain/vo/UserDTO.java           # +deviceId
└── mapper/InfoUserDeviceMapper.java # 新增(MP BaseMapper,无 XML,同 InfoUserOauthMapper 模式)

ruoyi-system/src/main/resources/i18n/                                 # 新增消息 key(多语言)
updatesql/sql.md                                                      # 建表 DDL 追加(带日期注释)

Structure Decision: 单体多模块 Maven。数据层(实体/Mapper)按既有模式放 ruoyi-system;业务编排与接口改造全部在 ruoyi-admin 的 app.user 包(登录逻辑现状集中在 InfoUserController,保持就近、surgical);新增 DeviceTrustService 承载可单测的纯逻辑(upsert/查询/脱敏),Controller 只做参数校验与编排。

Complexity Tracking

Fill ONLY if Constitution Check has violations that must be justified

无违规项。