# 通知第二批开发验证记录:删除、多选与回收站 日期:2026-10-28。状态:**开发验证通过,尚非完整发布验收**。仅后端、测试和必要文档;未改前端,未提交、推送、触发 Jenkins 或发布,未修改线上数据库。 ## 1. 实现范围 - 通知以 `deleted_at` 软删除;支持单条/批量移入回收站、单条/批量恢复和回收站分页。不存在永久删除、清空、自动过期清理或历史操作页面。 - 删除只影响当前用户的通知,不取消面试,不删除投递/Offer,也不影响对方收到的通知。 - 原正常列表不再展示软删除通知,条目仍保持第一批九个字段;回收站增加 `deletedAt`,按删除时间、ID 倒序。 - 原未读通知删除后不计数;恢复保留 read/readAt,原未读重新计数。全部已读只处理正常列表。 - 批量请求原始长度 1~100,ID 必须为 JSON 正整数,去重后返回 requested 和实际 changed 数量。任何越权或不存在 ID 导致整批失败,无部分成功。 - 单条及批量操作使用行锁,批量按 ID 升序加锁;单条已读也使用行锁,避免并发删除被陈旧实体覆盖而复活。全部已读条件更新只写 read/readAt,排除回收站。 - 原个人数据导出仍按原归属全量查询,软删除并不等于物理清除。账号注销清理范围不因本模块改变。 ## 2. 文件范围 本批共 21 文件;相对第一批已验收的 13 文件,重叠 5 文件,合并后共 **29 文件**。准确路径和 SHA256 以证据目录清单为准。 | 文件组 | 用途 | |---|---| | Notification.java / NotificationRepository.java | 删除时间、正常/回收站分页、排除删除项的计数、行锁与条件已读更新 | | NotificationService.java / NotificationController.java | 五个新接口、批量原子性和权限、删除/恢复幂等、保持原通知关联视图 | | NotificationBatchRequest.java / NotificationBatchResult.java / NotificationChangeResult.java | 严格正整数数组和数量上限、去重数量/实际变化结果 | | NotificationTrashResponseDoc.java | 回收站分页及 deletedAt 的运行时契约 | | V64__notification_recycle_bin.sql | 新增可空 deleted_at 与用户/删除时间/ID 索引,不改旧迁移或回填历史数据 | | NotificationServiceTest.java | 适配正常列表过滤、加锁已读、条件全部已读 | | NotificationTrashIntegrationTest.java | JWT 过滤链下 HTTP 语义、参数、权限、幂等、分页、批量原子性与并发 | | NotificationTrashMySqlIntegrationTest.java | 相同套件在真实 MySQL 上执行,可指定 8.4 或 5.7.36 | | NotificationTrashMySqlMigrationTest.java | 双 MySQL V63→V64、旧数据与历史校验和、幂等及 validate | | CompanyResumeDownloadIntegrationTest.java / UnifiedRegistrationIntegrationTest.java / ProfileImageIntegrationTest.java / WorkExperienceOptimizationSecurityIntegrationTest.java | 同步五个新认证操作带来的现有契约计数,未跳过或削弱权限断言 | | docs/openapi-rc.json / docs/verify_openapi.py | 221 paths / 271 operations,新增结构、认证、批量约束及无永久删除约束 | | 本记录 / notification-trash-frontend-handover-20261028.md | 验证边界及前端对接 | ## 3. 已执行及证据 证据目录:`D:\Acceptance\qsp-notification-trash-20261028-a1`。 | 验证 | 实际结果 | |---|---| | 最终 9 类定向测试 | **117 tests / 0 failures / 0 errors / 0 skipped**,Maven 退出码 0 | | 真实 MySQL 8.4 通知套件 | **22/22**,完整认证过滤链 + MockMvc,不冒充实际端口 JAR 黑盒 | | 真实 MySQL 5.7.36 通知套件 | **22/22**,同上;Hibernate 对 5.7 支持范围有警告,实际专项无失败 | | V63→V64 真实双库迁移 | **2/2**:旧通知字段及 read/readAt 不变,deleted_at 初始 NULL,索引正确,历史 checksum 不变,二次迁移 0、validate 成功 | | 静态与 Spring 测试运行时契约 | **221 paths / 271 operations**,路径方法集一致,五个新操作身份/鉴权及四个请求/响应模型一致 | | 静态校验器反向变异 | **10/10 拒绝**:缺鉴权、错误 operationId、空数组、超限、字符串/零 ID、必填约束、缺删除时间及正常列表内部字段泄露 | | git diff --check | 本批与合并通知文件范围检查,无空白错误 | 关键日志:`targeted-final.log`、`mysql84-run1.log`、`mysql57-run1.log`、`migration-contract-run1.log`。最终定向 XML 归档在 `final-test-xml/`,双库通知套件各自保存 `mysql84-tests.xml` / `mysql57-tests.xml`,不会以后一轮覆盖冒充两轮证据。 计数修正后实际通过:企业简历下载 19 项、统一身份注册 13 项、头像 18 项、AI 权限 9 项。禁止将本批定向通过当作这些模块的完整发布验收。 开发过程中静态契约补丁首次生成使用系统输出编码,导致新标签中文损坏;静态校验已拒绝该结果。改用 UTF-8 重新生成后通过,最终契约与运行时一致。没有通过修改全局序列化、关闭鉴权或跳过测试来消除失败。 ## 4. 未执行及发布边界 以下均为 **NOT EXECUTED**:本批合并基线的完整 `mvn clean verify`、同次打包 JAR 的真实端口 HTTP 黑盒、仅重启 JAR 的持久化、前端左滑/长按/跳转实机联调、线上部署。 第一批 `D:\Acceptance\qsp-notification-full-20261028-a1` 的全量/JAR 结果仅覆盖第一批冻结源码。本次新增 V64 和五个接口,不能复用第一批 JAR 或将旧 PASS 视为合并基线也通过。 本批不操作已有业务容器;专项使用 Testcontainers 创建的临时隔离数据库,自动停止清理。没有删除已有数据卷或验收报告。旧迁移内容、原仓库 HEAD/暂存区及非本批起始文件哈希保持不变,详情见机器摘要。 交接文档:`docs/notification-trash-frontend-handover-20261028.md`,结构为“接口与字段 → 左滑/多选/回收站流程 → 权限与错误处理 → 联调验收”。没有需要新增授权才能完成的本批编码问题;若后续需要永久删除或自动保留期限,应另立需求,不能自行增加。 下一步:以 `combined-whitelist.json` 的 **29 文件合并基线**建立独立副本,完整构建成功后锁定同次 JAR,验证删除/恢复、权限、并发、契约和重启,再决定发布。当前工作区不能按第一批旧 13 文件清单直接发布。