轻松聘AI开发
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

7.8 KiB

N07 消息撤回与会话一致性:独立代码复验与真实 MySQL/Docker 验收

日期:2026-09-10 分支:feat/message-recall 结论:PASS(真实 MySQL/Docker 黑盒已完成;可进入精确暂存检查点)

1. Git 基线与边界

  • 当前分支:feat/message-recall。
  • HEAD:dbd27e6 feat: enhance candidate scoring explanations。
  • 验收开始及结束时暂存区均为空;既有 N07 修改、历史脚本、日志、JSON、SQL、xlsx 和 .env 均保留。
  • git diff --check:通过;迁移目录没有 V1–V40 修改。
  • N07 唯一新增迁移:V41__message_recall.sql。
  • 未执行 git add -A、commit、push、reset、restore、checkout、clean;未删除或移动历史文件。

2. 自动化独立复验

命令 Tests run Failures Errors Skipped 结果
N07 定向测试 30 0 0 0 BUILD SUCCESS
消息与邀约关联回归 80 0 0 0 BUILD SUCCESS
mvn clean verify 1601 0 0 0 BUILD SUCCESS

python docs\\verify_openapi.py 通过,静态 OpenAPI 为 173 paths / 211 operations。

3. 代码审查

  • 状态机:PASS。V41 CHECK 仅允许 SENT/RECALLED;条件更新包含 messageId、conversationId、senderUserId、SENT、expectedVersion;正文固定占位、recalledAt 非空、version 仅递增一次;重复撤回幂等且不重复成功审计。
  • 权限与归属:PASS。真实 HTTP 中原发送者成功,另一成员/非成员/ADMIN/跨会话为 403/2002,匿名为 401,会话/消息不存在分别为 404/8305、404/8306,超时为 409/8307。
  • 并发与事务:PASS。H2 独立事务测试以及真实 HTTP 两个并发请求均无 500;同消息最终 version=1、恰好一条成功审计;不同消息并发各自成功。
  • 依赖注入:PASS。生产目录不存在 messageViewMapper == null、objectMapper == null、new MessageViewMapper()、new ObjectMapper() 兜底。
  • 审计隐私:PASS。真实 MySQL MESSAGE_RECALLED 行 ip_address/user_agent 均为 NULL,details 为合法 JSON 且字段严格为 messageId,conversationId,conversationType,status,requestId。
  • DTO/查询结构:PASS。撤回及分页路径使用白名单 DTO;会话与成员固定查询、消息分页固定查询、message_reads 一次批量查询,无逐消息 exists/find。
  • 副作用:PASS。目标消息仅发生 SENT→RECALLED、占位正文、recalledAt、version+1;message_reads、conversation_members、candidate_dimension_scores、notifications、风险表内容和 version 均未改变。

4. Docker、MySQL、Flyway 与启动

  • Docker Engine:Server 29.6.2;MySQL 8.4.11、Redis 7.4、RabbitMQ 3.13 容器均 healthy。未重建、删除容器或 volume。
  • 真实 Flyway 查询:最新三条为 V41 message recall success=1、V40 enterprise talent invitations success=1、V39 enterprise talent discovery success=1;无失败迁移、无 N07 之外迁移。
  • SHOW CREATE TABLE messages:status 默认 SENT、recalled_at 可空、version 默认 0,CHECK 仅允许 SENT/RECALLED,既有外键与 idx_messages_conversation_created 保留;无消息历史表。
  • 使用 mvn clean verify 生成的 JAR、dev 配置并保持 ddl-auto=validate 启动,日志出现 Started MyDreamjobApplication,无 Flyway/schema-validation 错误。
  • GET /api/v1/health:HTTP 200,status=UP。
  • 本轮启动的应用 PID 4412(后续边界复验重启为 PID 21168)均在验收结束后正常停止;8080 已恢复空闲。Docker 未停止。

5. 真实 HTTP 主链路与权限

  • DIRECT:真实发送、列表、撤回、重复撤回全部 200;撤回后 status=RECALLED、正文为固定占位、recalledAt 非空、version 0→1,重复请求不再增加 version 或审计;senderUserId 按既有语义保留。
  • TALENT_INVITATION:真实发送、撤回、列表全部 200;仅返回 senderScope,不返回 senderUserId、学生 ID或 candidateKey;会话详情和会话列表中的 TALENT_INVITATION 项不返回 createdBy;撤回后正文为固定占位。
  • 权限配对结果:原发送者 200/200;另一成员 403/2002;非成员 403/2002;ADMIN 403/2002;匿名 401/401;跨会话 403/2002;不存在会话 404/8305;不存在消息 404/8306;超时 409/8307。
  • 递归 JSON 脱敏:DIRECT 撤回/列表、TALENT_INVITATION 撤回/列表及会话详情中的 TALENT_INVITATION 项均未发现原正文、senderUserId(TALENT)、studentUserId、candidateKey、联系方式、IP/UA、凭据等禁止字段。

6. 并发、时间与 message_reads

  • 真实 MySQL HTTP 并发:同一消息两请求均 200,最终 version=1、单条审计;两条不同消息并发均 200、各 version=1、各一条审计。
  • 时间:H2 正式测试覆盖 0 秒、1:59、恰好 2:00 成功及超过 2:00 最小单位失败;真实 MySQL HTTP 119 秒返回 200/200、120 秒返回 409/8307(数据库状态分别为 RECALLED/SENT),创建后立即撤回也成功。边界表达式保持 capturedNow <= createdAt.plusMinutes(2)。
  • 已有 message_reads 行在撤回后仍存在(精确查询=1);撤回消息不计入 unreadCount(精确查询=0),消息仍保留时间线,未新增第二条 read 行。

7. 查询预算与 EXPLAIN

  • 使用真实 MySQL performance_schema.events_statements_summary_by_digest 测量正式 HTTP 列表路径,夹具规模 1、20、50 条消息:每次均为 messages=2、message_reads=1、conversations=1、conversation_members=1,查询数不随消息量线性增长。
  • 真实 EXPLAIN FORMAT=JSON:消息分页使用 idx_messages_conversation_created、access=ref、无 filesort/temporary;message_reads 使用 reader 索引、成员校验使用 uk_conv_members;条件撤回使用 PRIMARY、access=range;未读查询使用消息索引和 uk_message_reads。未新增索引。
  • 说明:该 EXPLAIN 为当前验收数据的代表性计划;更大生产数据量的容量/延迟压测仍需后续授权,不以固定查询数替代性能结论。

8. RabbitMQ 与副作用

RabbitMQ ping 成功;queue.sms.verification、queue.notification、queue.audit、queue.notification.dlq 均真实存在,ready=0、unacked=0。N07 撤回未产生新增消息、通知、短信或邮件。

目标消息撤回前后稳定摘要证明:除目标消息允许的四项状态变化和一条白名单 MESSAGE_RECALLED 审计外,message_reads、会话、成员、评分快照、通知、风险治理表内容与 version 不变。

9. OpenAPI

  • 静态:173 paths / 211 operations,verify_openapi.py 通过。
  • 运行时:GET /api/v1/v3/api-docs 返回 173 paths / 211 operations,与静态计数一致;撤回无 requestBody,200 响应引用 ApiResponseMessageResponse,分页响应引用 ApiResponseMessagePageResponse。
  • 未新增编辑、删除、批量撤回、恢复接口;TALENT_INVITATION 的条件性 senderScope 脱敏由真实 JSON 验证。

10. PASS/FAIL/SKIP 与剩余风险

  • PASS:自动化、V41 迁移与 schema validation、启动/健康、权限、DIRECT/TALENT_INVITATION 脱敏、并发、审计隐私、message_reads/unread、只读副作用、查询预算、EXPLAIN、RabbitMQ、静态/运行时 OpenAPI。
  • FAIL:0。
  • SKIP:0 个核心验收项。生产级更大规模容量压测和持续运行监控不属于本轮黑盒范围,需独立性能验收,但不构成当前 N07 功能阻断。
  • 不允许把本报告扩展为对 V1–V40 其他业务的全面生产保证;仅确认 N07 变更边界。

11. 最终判定

PASS:N07 独立代码复验和真实 MySQL/Docker 黑盒全部通过,可以进入精确暂存检查点。

本报告不包含数据库密码、JWT、测试账号密码、手机号、邮箱或原消息正文。验收数据仅使用本轮唯一前缀并已按精确 ID 清理;历史验收文件未删除或移动。