Files
patbond-doc/docs/development/feature-checklist.md
T
lixi 3ac756fa14 docs: 功能清单同步会话清理任务交付(75 测试)
- auth_sessions 清理任务 (patbond-api@6528a06,保留期即重用检测窗口的设计说明随注释入库)
- 门禁:mkdocs build --strict 通过
2026-09-04 15:47:07 +08:00

9.4 KiB
Raw Blame History

功能完成清单(第一迭代)

目的:直观呈现哪些功能已完成且有自动化测试、哪些部分完成、哪些尚未开始,方便针对性验证与回归。 维护约定:每波工单合入后由执行人更新本清单;状态以 dev 分支 + 门禁全绿为准。 最后更新:2026-09-04(第三波两端合龙 + 工程化补波:patbond-api 6528a06 75 测试、patbond-flutter da25804 30 测试,均门禁全绿;compose 编排冒烟实测通过)

图例: 已完成且已测试 🟡 部分完成/有已知限制 未开始

1. 后端基础设施

功能 状态 自动化测试 说明
Spring Boot 3 / JDK 17 基线(ADR-001 全量门禁 Boot 3.5.16 + Spring Cloud 2025.0.3
移除 NacosFeign 静态地址(ADR-002 AuthApplicationTests 干净检出可启动、可测试
Flyway V1 baselineplatform/identity/media UserPersistenceIntegrationTest.flywayBaselineAppliedOnCleanPostgres16 干净 postgres:18 全量执行;dev 种子默认不加载
Testcontainers postgres:18ADR-006/008 所有 user 模块集成测试 + auth E2E 不依赖本机数据库
统一响应信封 {code,message,data} + 稳定错误码 ApiResponseTest、各 Controller 测试 错误码表见 docs/api/openapi.yaml
跨服务错误码透传(不折叠) ApiErrorDecoderTest + E2E 真实链路 第三波修复两处存量缺陷(ErrorDecoder 未进 Feign 子上下文、JDK HttpURLConnection 读不到 401 错误体),此前真实调用中折叠为 503

2. 用户与凭证(patbond-user

功能 状态 自动化测试 说明
用户注册落库(UUIDv7、bcrypt、软删不可见) UserPersistenceIntegrationTestUserControllerTest 原生 JDBC 读回验证持久性
用户名唯一(citext 大小写不敏感)→ 40900 UserControllerTest.duplicateUsernameCheckIsCaseInsensitive 依赖 DB 约束 + 冲突翻译
手机号唯一 → 40901E.164 校验(DTO 与 DB CHECK 对齐) UserControllerTestdatabaseRejectsNonE164PhoneEvenIfValidationWereBypassed
密码校验(含防账号探测的哑 hash 比对) UserControllerTest.verifyPassword*
登录失败限制(窗口计数→锁定→423/42300) LoginLockoutIntegrationTest3 例)+ E2E 按用户名维度,5 次/15 分钟锁 15 分钟,全部配置项;成功登录重置窗口
GET /api/v1/meBearerRS256 公钥本地验签) MeEndpointTest(5 例:正常/缺失/过期/伪造/垃圾) 响应恰好 {userId, username, phone, createdAt}

3. 认证与会话(ADR-003

功能 状态 自动化测试 说明
POST /api/v1/auth/register(冻结契约 6 字段响应) AuthControllerTest + AuthE2eIntegrationTest.fullAuthVerticalFlow 时间字段 ISO 8601 带时区
POST /api/v1/auth/login(多设备并行会话) 同上 + logoutOnOneDeviceKeepsOtherDevicesLoggedIn
Access tokenJWT RS25615 分钟(配置项) JwtSignerTest5 例) 私钥仅 auth,公钥仅 user;密钥环境变量注入,仓库零密钥材料
Refresh 会话:SHA-256 摘要落 auth_sessions SessionLifecycleIntegrationTest.createSessionStoresSha256DigestNotPlaintext 明文不落库(逐字节断言)
POST /api/v1/auth/refresh:刷新即轮换 + 轮换链 refreshRotatesTokenAndChainsSessions + E2E 旧行 revoked/rotated/replaced_by 三字段断言
旧 refresh 重用 → 40102 + 撤销整个 token family reuseOfRotatedTokenRevokesWholeFamily + E2E 并发轮换同样按重用处理
refresh 过期/未知 → 40102 expiredRefreshTokenIsRejectedunknownRefreshTokenIsRejected
POST /api/v1/auth/logout:仅撤当前会话,幂等 SessionLifecycleIntegrationTest(含跨账号撤销不掉用例)+ E2E 需有效 access token40101 兜底)
会话记录设备信息(X-Device-Id / UA / IP registerForwardsDeviceIdHeaderToTheSessionRecord + 会话落库断言 前端每请求携带 X-Device-Id,为多设备会话列表备数据
access 过期/伪造 → 40101 MeEndpointTestJwtSignerTest、E2E
/internal/** 服务间鉴权(X-Internal-Token InternalAuthFilterTest3 例)+ E2E 无凭证/错误凭证 401;未配置 fail-closed
access token 主动吊销(黑名单) 退出后已签发 access 在剩余 ≤15 分钟内仍有效(jti/sid 已入库备用),见报告 16 §9.1
auth_sessions 过期行清理任务 SessionCleanupIntegrationTest patbond-api@6528a06@Scheduled 定时删除死亡超过保留期(默认 30d,即重用检测窗口)的行,间隔/保留期均配置项

4. API 契约与文档

功能 状态 说明
OpenAPI 3 正式契约(5 公开端点+错误码表+会话/锁定策略) docs/api/openapi.yaml;与冻结稿字段零偏差;新增 42300 已显著标注
后端三波迭代报告 docs/development/iterations/iteration-1/10、16 等)
README 运行手册(密钥生成、环境变量表、新端点) patbond-api/Readme.md

5. 客户端(patbond-flutter

功能 状态 说明
珊瑚橙主题迁移 + 认证基础组件(ADR-005) 第二波已交付(dart format / analyze / test 全绿)
dio API client + 信封解包 + 错误码映射(含 42300) 第三波并行交付(patbond-flutter@8d890c0+da25804,报告 17),基于 mock 验证
Splash/登录/注册页 + secure storage + 登录态恢复 + 真实退出 同上,登录页四态/注册校验 widget 测试锁定
401 单飞刷新拦截器 TokenRefresher 单元测试(刷新单飞、40102 清会话)
与真实后端联调(烟囱测试) 第四波;前置的 compose 编排已就绪(见第 6 节)

跨端核对发现(前端线跟进,后端已按 openapi.yaml 核对全部通过)

  1. UserProfile.fromJsonphone 按非空 String 强转——已修复patbond-flutter@845e92f,phone 改为可空,30 测试全绿)。
  2. 注册请求携带的 Idempotency-Key 后端暂未实现幂等语义(开发计划仅要求帖子/预约类写接口支持);「刷新重放沿用同键」的设计正确,待后端实现后自动受益。
  3. 前端每请求携带的 X-Device-Id 后端已接入 auth_sessions.device_idpatbond-api@8bdaf53)。

6. 工程化

功能 状态 说明
后端集成测试门禁(本地) JAVA_HOME=/usr/lib/jvm/java-17-openjdk ./mvnw clean test75 测试
跨服务真实 HTTP E2E AuthE2eIntegrationTest(同 JVM 双服务 + 真实 postgres:18
docker compose 最小编排(postgres:18 + 两无状态服务容器) patbond-api@ab0265c./deploy/init-secrets.shmvnw -DskipTests packagedocker compose up -d --build;完整冒烟实测通过(register→me→refresh→旧 token 重用 40102→internal 401→logout);用法见 patbond-api/Readme.md
可执行镜像构建(repackage exec jar、非 root 运行) 同上;顺带修复无 starter-parent 时 package 产物不可执行
信封严格化(success 派生字段不再上线) patbond-api@8a79971,信封恰为 {code, message, data}
CI 载体(自动执行门禁) 🟡 .gitea/workflows/ci.yml 已提交(patbond-api@3f6e818,与本地门禁同命令);待服务器启用 Gitea Actions 并注册带 Docker 的 act_runner(前提在文件头注释,需用户操作)

针对性测试速查

# 全量门禁
JAVA_HOME=/usr/lib/jvm/java-17-openjdk ./mvnw clean test

# 只跑会话生命周期 / 锁定 / me 鉴权(user 模块)
JAVA_HOME=/usr/lib/jvm/java-17-openjdk ./mvnw -pl patbond-user -am test \
  -Dtest='SessionLifecycleIntegrationTest,LoginLockoutIntegrationTest,MeEndpointTest' \
  -Dsurefire.failIfNoSpecifiedTests=false

# 只跑跨服务 E2E 纵切(auth 模块;-am 必带,避免 ~/.m2 旧 common 快照)
JAVA_HOME=/usr/lib/jvm/java-17-openjdk ./mvnw -pl patbond-auth -am test \
  -Dtest='AuthE2eIntegrationTest' -Dsurefire.failIfNoSpecifiedTests=false

手动冒烟(两服务本地起好后,密钥与内部 token 配置见 patbond-api/Readme.md):

# 注册 → 拿令牌对
curl -s -X POST http://127.0.0.1:8081/api/v1/auth/register \
  -H 'Content-Type: application/json' \
  -d '{"username":"demo_user","phone":"+8613800138000","password":"secret123"}'

# me(换成上一步返回的 accessToken
curl -s http://127.0.0.1:8082/api/v1/me -H "Authorization: Bearer <accessToken>"

# 刷新(旧 refreshToken 随即失效;再用旧值应得 40102)
curl -s -X POST http://127.0.0.1:8081/api/v1/auth/refresh \
  -H 'Content-Type: application/json' -d '{"refreshToken":"<refreshToken>"}'

# 退出(撤销当前会话)
curl -s -X POST http://127.0.0.1:8081/api/v1/auth/logout \
  -H "Authorization: Bearer <accessToken>" \
  -H 'Content-Type: application/json' -d '{"refreshToken":"<refreshToken>"}'

# /internal 无凭证应 401
curl -s -i http://127.0.0.1:8082/internal/users/by-username/demo_user | head -1