# 项目状态跟踪 — STATUS.md > **2026-09-18 当前有效结论:`V1.1 RECOVERY PHASE 01~22 CLOSED / PHASE 23 PARTIALLY CLOSED / HORIZONTAL HARDENING DONE (HTTP SEMANTICS + IDEMPOTENCY + PORT/ENTRY GUARDS) / UI REDESIGN ACCEPTED BY USER / 669 TESTS GREEN / STOPPED BEFORE PHASE 24 (UAT) — AWAITING USER GO`。** > > 阶段 0(在途收口)、阶段 1(小程序 C 组 + discover 筛选重设计)、阶段 2(管理端 Vue 新框架适配)、阶段 3(CapabilityService 独立化)、阶段 4(双端总验收)全部完成。三端构建通过、**13/13 契约全绿**(阶段 4 验收时点值;当前 UI 契约门禁为 **14/14**)、核心 11 页面**全部 TS-only(11/11)**。**UI 重设计首批 11 页已于 2026-09-16 通过用户验收(结论:基本达标)**;`/me/*` 前后端契约同轮收敛,17 个 404 调用已恢复。**Phase 08(Like / Match / Block)、Phase 09(Text Chat)、Phase 10(Image & Chat Safety)、Phase 11(Notification)、Phase 12(Relationship Progress)、Phase 13(公益红娘转介)、Phase 13A(婚恋咨询与婚前辅导)、Phase 14(多类型公益活动)、Phase 15(活动报名、审核与签到)、Phase 16(活动互选与双方开启沟通确认)、Phase 17(举报与风控)、Phase 18(申诉)、Phase 19(统一运营后台 + 用户端公益服务页面)、Phase 20(Analytics 数据统计与管理驾驶舱)复验已关闭**,十四轮共修复 130+ 处真实缺陷(含 3 处隐藏编译缺陷),并各自补齐测试保真度与守卫。**Phase 21、22 复验已关闭(2026-09-18)**;**Phase 23 为「部分关闭」(2026-09-18)** —— 已清除 44 个 `pass` 空壳与 14 个只断言常量的假不变量测试,新增 4 个经负向注入验证的真实行为守卫与空壳阻断闸门,后端回归 655 全绿;但 **E2E 进入 CI 因需「活栈供给方式」基础设施决策而列为遗留,故不宣布「失败为零可进入 UAT」**。**Phase 23B(E2E 测试基建重建,33→49 passed)、HTTP 语义检修(失败响应携带真实状态码)、幂等键检修(`Idempotency-Key` 30 端点落地,V045/V046)均已于 2026-09-18 完成**,后端全量回归 **669 / 0 failures / 0 errors / 3 skipped**。**管理端入口已收敛到 `/admin/` 子路径(vite base + router base + 三处 nginx 接线),staging 端口 13521;UI 契约门禁 14/14 全绿。Phase 24(UAT)启动需用户确认。** 最后更新: 2026-09-18 — 分支 `main`(`feat-ui-v11` 保留为冗余锚点) ## 当前唯一有效状态 | 当前有效项 | 状态 | 证据 | |---|---|---| | Phase 01~06 Recovery | 已完成 | 各 Phase Completion Report;38+9+3+4+21 后端专项通过 | | Phase 07 V1.1 首页业务与找对象 | **业务+UI 已通过用户验收**(2026-09-16) | HomeApplicationService 真实聚合;CapabilityService 独立化;discover 筛选完整重设计(5 chip + 4 section + 底部抽屉 + 滚动定位高亮);UI 按 2026-09-13 规格重新实现,11 页经用户验收通过 | | **Phase 08 V1.1 Like / Match / Block** | **已完成**(2026-09-16) | KEEP-VERIFY 复验。修复 3 处真实缺陷:① `DiscoverService.searchUsers` 无查看者身份 → INV-004「搜索不可见」整体失效;② 详情路径无 Block 判断;③ `RelationshipService.like()` 把 `"liked"` 当 match source 写库 → 违反 `V003 chk_match_source`(H2 测试库无该约束故长期静默)。新增 `DiscoverBlockInvisibilityIntegrationTest`(9 用例,含反向拉黑);`schema-h2.sql` 补齐生产约束与 `user_profiles`;负向验证确认守卫会红。报告:`docs/Phase-08-V11-Recovery-Completion-Report-2026-09-16.md` | | **Phase 09 V1.1 Text Chat** | **已完成**(2026-09-16) | KEEP-VERIFY 复验。修复 4 处真实缺陷:① WebSocket 下行整条链路是死代码(无握手鉴权/无 userId 写入/`sendToUser` 零调用点)→ 新增 `ChatHandshakeInterceptor` + 落库后推 `message.new`;② Unmatch 不联动会话 + 发消息只校验会话状态 → 解除后仍可发消息 → 新增 `assertMatchAlive` + `MatchController.unmatch` 联动;③ `RelationService.block` 调静态 `MatchService.unmatch`(只改内存态)→ Block 后 Match 未落库;④ 聊天四个接口无成员校验 → IDOR。新增 `ChatPhase09IntegrationTest`(11 用例)+ `ChatWebSocketHandlerTest`(7 用例);负向验证 3 处守卫精准变红。报告:`docs/Phase-09-V11-Recovery-Completion-Report-2026-09-16.md` | | **Phase 10 V1.1 Image & Chat Safety** | **已完成**(2026-09-16) | KEEP-VERIFY 复验。**Gate 通过**。修复 2 处缺陷:① **D1(Critical,生产故障)** `PhotoService.uploadAndSave` 魔数校验因 `new byte[n]` 从不读取流而**恒失败** → 本地资格佐证上传 100% 失败;且 image-only MIME 在 local_eligibility 后无条件执行致 PDF 被挡 → 改为 `readNBytes` 真读取 + MIME 按 photoType 分流 + PDF 跳过图片魔数;② **D2(Low)** `ChatSafetyService` 把命中的高风险词写入 warn 日志 → 改为不记具体词汇。**推翻旧报告**「伪装恶意图片被拒(Magic Number校验)」与「EXIF清理预留(stripExif占位,符号不存在)」两声明。新增 `PhotoUploadValidationTest`(6 用例,`MockMultipartFile` 真走校验链路)+ 负向验证精准变红。报告:`docs/Phase-10-V11-Recovery-Completion-Report-2026-09-16.md` | | **Phase 11 V1.1 Notification** | **已完成**(2026-09-16) | KEEP-VERIFY 复验。Gate 部分通过。修复 3 处缺陷:① **D3(Critical,生产故障)** `NotificationService` 全部 10 种通知传入复合 type(`appointment_submitted`/`counseling_assigned`/`le_verified` 等),违反生产 `chk_notification_type`(仅允许短名)→ 真实 PG 上**全部落库失败**,Phase 11 核心交付不可用;测试库未复刻该约束故长期静默 → type 归一为白名单短名 + 测试库补约束;② **D1(High)** 幂等仅靠 SELECT-then-INSERT 无 DB 兜底 → 新增 `V036__add_notification_idempotency_index.sql`(partial unique index);③ **D2(Medium)** 婚前辅导排期通知零调用 + 管理端排期路径完全不发通知 → 接线并按 service_type 分流。新增测试 12 用例(含**真实调用模板方法**的 type 守卫)。报告:`docs/Phase-11-V11-Recovery-Completion-Report-2026-09-16.md` | | 阶段 0 在途收口 | 已完成 | 56 个改动分类提交为 7 个 commit;Git 清零;Flyway 实际 V036 已登记 | | 阶段 1 小程序 C 组 + discover | 已完成 | C 组 content/anti-fraud/service-station 迁 TS 唯一源;discover 筛选从参数到 UI 完整重写 | | 阶段 2 管理端 Vue 适配 | 已完成 | 18 modules + 22 routes + vue-tsc 全绿 + vite build 11.68s | | 阶段 3 CapabilityService 独立化 | 已完成 | New `capability` 模块:CapabilityService(getCapabilities + 公共判断方法)+ CapabilityController(GET /api/v1/capabilities);HomeApplicationService 完全委托 | | 阶段 4 双端总验收 | **已完成**(2026-09-14) | 三端构建全绿 + 13/13 契约全绿 + 源码健康检查通过;验收报告见 docs/superpowers/plans/2026-09-14-phase4-acceptance-report.md | | Flyway 迁移 | V001~V046 | V028~V046 已纳入 STATUS;V037 为 Phase 12 新增(实体列与生产迁移对齐,23 表 50 列);V038 为 Phase 13 新增(`matchmaker_recommendations.status` + `matchmaker_services.service_type` 的 CHECK 白名单扩展);V039 为 Phase 13A 新增(counseling 幂等键 + 三个 CHECK 白名单显式固化);V042 为 Phase 19 新增(`service_location_announcements` 服务站临时公告表);V043 为 Phase 20 新增(授予 `data_viewer` / `platform_admin` 的 `analytics.view`);V045 为幂等键检修新增(`idempotency_records` 通用幂等表 + 唯一索引 `uk_idempotency_scope`);V046 修正其 `actor_id` 列类型(VARCHAR → uuid) | | Backend 全量回归 | **已清偿**(最新:2026-09-18 **669 / 0 failures / 0 errors / 3 skipped / BUILD SUCCESS**) | 离线容器(`danyang-match-backend-test`)`mvn -o test` 实测;**2026-09-18 幂等键检修订正后为 669**(HTTP 语义检修 664 → 幂等检修 +5:`GlobalExceptionHandlerTest` 3→6、新增 `IdempotencyDeclarationGuardTest` 2)。历史:2026-09-17 Phase 20 为 648;含 `CanonicalRouteContractTest`、`ChatContractJsonTest`、`MeRouteContractTest`、`DiscoverBlockInvisibilityIntegrationTest`、`ChatPhase09IntegrationTest`、`ChatWebSocketHandlerTest`、`PhotoUploadValidationTest`、`NotificationPhase11IntegrationTest`、`NotificationTemplateTypeGuardTest`、`NotificationPrivacyCopyTest`、`EntityMigrationParityTest`、`RelationshipProgressPhase12Test`、`HomePremaritalGuidancePhase12Test`、`MatchmakerReferralPhase13Test`、`MatchmakerServiceTest`、`ReportAndRiskPhase17IntegrationTest`、`AppealPhase18IntegrationTest`(Phase 18 新增 15 例:申诉真实落库+审计、仅 ban/suspend 可申诉、幂等、**Gate A 通过只解除目标处置**、**Gate B 拒绝维持原处置**、原子认领唯一赢家、二次处理被拒、escalate 后可再决策、appealType 白名单/一致性/缺省推导、证据字段映射、软删过滤、Feature Flag 关闭拦截)、`MetricCatalogGuardTest`(11)、`AnalyticsMetricsPhase20IntegrationTest`(21)、`AnalyticsSoftDeleteGuardTest`(4)、`AnalyticsPermissionGrantTest`(6)、`LocalEligibilityStatusVocabularyGuardTest`(9)、`ApiResponseCodeHttpStatusTest`(6)、`SecurityPathCoverageTest`(2)、`IdempotencyDeclarationGuardTest`(2) | | 路由/字段契约收敛 | **已完成**(2026-09-15) | 字段:会话 `target*` + `sentAt` + `relationStatus`(commit `687a156`);路径:采用 2026-09-14 canonical(`/likes` `/passes` `/blocks` `/matches`,缘分保留 `/relations/fate/*`),旧路径与 `success` 桩实现已移除;裁决由 `CanonicalRouteContractTest` 锁定 | | `/me/*` 路径族 | **已完成**(2026-09-16) | 小程序按 REST 规范(§16 / §22-§40 / §80 / §83-§84)调用 `/me/*`,后端此前**无 `/me` 基路径**致 17 个调用 404。新增 `MeController` 委托既有 service 暴露规范路径,旧路径全部保留,小程序三条历史写法(`/me/privacy-settings`、`/me/photos/{id}/main`、`/me/appeals`)一并兼容;由 `MeRouteContractTest` 锁定 | | Admin Web | **验证通过** | 2026-09-14 阶段 4:vue-tsc ✅、vite build ✅ 11.68s;18 modules 齐全;壳层+工作台通过参考图 QA | | Miniapp | **验证通过** | 2026-09-16:tsc ✅;**11 核心页全部 TS-only(11/11)**;首批 11 页于 2026-09-16 通过用户验收;discover 筛选重设计已通过 DevTools 验证 | | UI 契约测试 | **14/14 通过**(2026-09-18) | 统一执行器 `scripts/run-ui-contracts.mjs`,**已接入 CI**(job `ui-contracts`);历史:2026-09-16 为 13 项,此后新增端口一致性与 `/admin/` 子路径守卫 | | Git 工作区 | **已清零** | 阶段 0~4 共 24+ commit 可追溯;`git status --porcelain` 0 行 | | 核心待清债务 | 0 项 | 已全部清偿:3 页 JS→TS 迁移、backend 全量回归(420 tests)、DevTools 真机截图留档(2026-09-14)、`/me/*` 路径族收敛(2026-09-16)、实体↔生产迁移漂移修复(V037/V038/V039,2026-09-16/17) | | UAT / RC / Production | **Phase 01~22 复验关闭;Phase 23 部分关闭;停在 Phase 24(UAT)门前** | 后端 **669 / 0 failures / 0 errors / 3 skipped**;UI 契约门禁 **14/14**;管理端入口收敛至 `/admin/` 子路径(staging 13521);HTTP 语义 + 身份收敛 + 幂等键三轮横向加固完成。**Phase 24 启动需用户确认** | > **下一阶段计划(唯一)**:`docs/superpowers/plans/2026-09-18-phase23-closeout-and-uat-readiness.md` > —— 批 1 快速收尾(ui-tests 接入 CI)/ 批 2 Phase 23 剩余(E2E 实现 + CI 串联,**需基础设施决策**)/ > 批 3 代码级遗留清偿 / 批 4 UAT 就绪(**需用户协作**)/ 批 5 Phase 25-26 前置登记。 --- ## 版本演进 | 版本 | 日期 | 说明 | |------|------|------| | 1.0.0-RC.2 | 2026-09-01 | V1.0 核心功能冻结 | | 1.1.0-dev | 2026-09-08 | V1.1 基线搭建启动(Phase 01 进行中) | | 1.1.0-rc.3 | 2026-09-16 | Phase 08~12 复验关闭;新增 V037 对齐实体↔生产迁移;全量回归 371 tests 全绿 | | 1.1.0-rc.4 | 2026-09-16 | Phase 13 复验关闭(公益红娘转介,修复 7 处缺陷);新增 V038 扩展 matchmaker CHECK 白名单;全量回归 **391 tests** 全绿 | | 1.1.0-rc.5 | 2026-09-17 | Phase 13A 复验关闭(婚恋咨询与婚前辅导,9 处缺陷 + 4 处测试基建缺陷);新增 V039;全量回归 **420 tests** 全绿 | | 1.1.0-rc.6 | 2026-09-17 | Phase 14 复验关闭(多类型公益活动,11 处后端缺陷 + 3 处前端契约缺陷 + 2 处测试保真度缺陷);新增 `ActivityManagementView` 动态表单;全量回归 **450 tests** 全绿 | | 1.1.0-rc.7 | 2026-09-17 | Phase 15 复验关闭(活动报名/审核/签到,16 处缺陷:含**签到码一生成即作废**、**取消后永远无法再报名**两处必崩;3 处测试保真度);新增 V040 `activity_staff_assignments` 与 `ActivityCheckinView` 签到工作台;全量回归 **474 tests** 全绿 | | 1.1.0-rc.8 | 2026-09-17 | Phase 16 复验关闭(活动互选与双方开启沟通确认,7 处缺陷 + 1 处隐藏编译缺陷 + 1 处测试保真度:含**双确认后根本不建 Match/会话(Gate 缺陷)**、**Phase 15 提交态引用未定义 `reopenEpisode` 致模块不编译("474 绿"为假象)**、**INV-006 单向意向泄露**、**复用/新建 Match 后缺会话**;统一双实现到 `RelationshipService.confirmActivityInterest`;新增 V041 `expires_at`+`match_id`;新建 `ActivityMutualConsentServiceTest`(7 用例);全量回归 **481 tests** 全绿 | | 1.1.0-rc.9 | 2026-09-17 | Phase 17 复验关闭(举报与风控,6 处真实缺陷:含**D1 测试库缺 reports/risk_events/risk_actions 三表致风控/举报真实 DB 路径零覆盖(必崩级盲区)+ ReportServiceTest 假绿**、**D3 敏感访问(查看他人风险画像/举报)无审计(AGENTS.md #8)**、**D4 审计缺 ip/userAgent**、**D5 findByUserId 未过滤软删**、**D2 人工标记无审计**、**D6 javax→jakarta 隐藏编译缺陷 + risk_events 漏 updated_at**);补齐三表并移出白名单入 REQUIRED_IN_TEST_SCHEMA;新增 `AuditLogService.recordSensitiveAccess` 并接线三端点;新增 `ReportAndRiskPhase17IntegrationTest`(7 用例);全量回归 **488 tests** 全绿 | | 1.1.0-rc.10 | 2026-09-17 | Phase 18 复验关闭(申诉,8 处真实缺陷:含**D1 测试库缺 appeals 表 + AppealServiceTest 6 处 assertTrue(true) 假绿 → 申诉真实 DB 路径零覆盖**、**D2 escalate 向 operator 发用户通知撞 notifications.user_id→users(id) FK → PG 上升级 100% 失败**、**D3 appealType 未校验生产 chk_appeal_type**、D4 escalated 死胡同、D5 processAppeal 先读后写并发竞态、D6 三处查询漏软删过滤、D7 硬编码 resolved、D8 证据字段契约 evidenceFileIds);补 appeals 表并移出白名单入 REQUIRED_IN_TEST_SCHEMA;新增原子认领 `markReviewingIfProcessable`;新增 `AppealPhase18IntegrationTest`(15 用例),删除假绿 `AppealServiceTest`(9 用例);全量回归 **494 tests** 全绿;admin-web `vue-tsc` EXITCODE=0 | | 1.1.0-rc.11 | 2026-09-17 | Phase 19 复验关闭(统一运营后台 + 用户端公益服务页面,修复 25 处真实缺陷:服务站公告整条不可达、服务站越权写、Banner 500、Content 发布死路、ServiceProgram 审批死路等);新增 V042 `service_location_announcements`;全量回归 **602 tests** 全绿 | | 1.1.0-rc.12 | 2026-09-17 | Phase 20 复验关闭(Analytics,口径造假 / 死代码 / 系统性软删缺陷 D12 修复 45 处 / 权限授予脱节);新增 V043 `analytics.view` 授权;指标字典 `docs/ANALYTICS_METRICS.md` + `MetricCatalogGuardTest`;全量回归 **648 tests** 全绿 | | 1.1.0-rc.13 | 2026-09-18 | Phase 21 复验关闭(账户生命周期,6 处缺陷:CLOSED 可登录、注销 TODO 桩 ×2、匿名化死代码等)+ Phase 22 复验关闭(Feature Flag,D-22-A/B 修复;T01~T05 死配置如实登记);全量回归 **657 tests** 全绿 | | 1.1.0-rc.14 | 2026-09-18 | Phase 23 **部分关闭**(44 个 `pass` 空壳清除、4 个真实 INV 行为守卫、空壳阻断闸门);Phase 23B E2E 基建重建(conftest + seed + CI e2e job,本机活栈 33 passed);全量回归 **655 tests** 全绿 | | 1.1.0-rc.15 | 2026-09-18 | HTTP 语义检修(105 处错误响应携带真实状态码,回归 664)→ 身份收敛(运营身份禁入用户端 + PathPattern 守卫)→ 幂等键检修(`Idempotency-Key` 30 端点落地,V045/V046,前端 25 处调用点修正,E2E 49 passed);admin 端口收敛 13520(vite / 文档 / 生产 compose 三处一致);全量回归 **669 / 0 / 0 / 3** 全绿 | | 1.1.0-rc.16 | 2026-09-18 | 管理端入口收敛(承接 rc.15 的端口收敛):staging admin 端口 3001 → **13521**(保持「生产 + 1」,同步 `run-uat.sh` 默认入口);管理端产物改为 **`/admin/` 子路径部署**(vite 构建 base + router history base + 三处 nginx 接线统一为「不剥离前缀」转发);**修复生产 nginx `/admin/` 的假成功**——原 `alias` 指向 `nginx:alpine` 自带默认页目录,访问返回 200 + nginx 欢迎页(比 404 更难发现),已改为 `upstream admin_web` + `proxy_pass` 并以真实两跳容器实测;补修 `run-uat.sh` 被截断的尾部(原文件语法不完整、无法运行)并把 `ADMIN_URL` 接到管理端可达性实测;品牌资源引用统一走 `src/brand.ts` 的 `BASE_URL` 拼接(原 5 处写死根路径,子路径下会裂图),favicon 由不存在的 `/favicon.svg` 改为存在的品牌标;UI 门控 **14/14 绿**,新增端口/入口断言 6 条(全部经负向注入验证) | --- ## 历史基线快照(2026-09-09 及更早,仅供追溯) > **历史记录边界**:以下为 2026-09-09 重新审查前的开发日志快照,**仅用于追溯,不代表当前验收状态**; > 其中的 ✅ / 已完成 / 已部署 / 测试数量 / 运行地址**均不可作为验收证据**,须以对应 Phase 的 > Completion Report 与本文顶部「当前唯一有效状态」为准。 > > 保留为治理痕迹(**已被后续 14 轮 KEEP-VERIFY 复验整体推翻**):当时自述 Git 基线「无 `.git`」、 > Admin Web type-check 3 错误、Miniapp TS 27 错误、Backend「未验证」、V1.1 E2E「1 passed / 26 failed / > 48 errors」、UAT/RC/Production「NO-GO」,以及一张「P01~P26 全部完成 ✅ / 不变量 23/23 ✅ / API 16/16 ✅」的自评表。 > > 原文可从 Git 历史取回:`git log --all -- docs/STATUS.md`。 ## V1.1 当前进度 ### Phase 01~11 — V1.1 首轮实现(2026-09-09 快照) > ⚠️ 本段原为 2026-09-09 期的逐项任务表,其中的 `✅` 是**当时的自评,不构成验收证据**; > 已收敛为索引,结论一律以本文顶部表与「当前 Phase」各节为准。 | Phase | 名称 | 权威结论位置 | |---|---|---| | 01 | V1.1 基线搭建 | `docs/Phase-01-V11-Recovery-Completion-Report-2026-09-09.md` | | 02 | Auth + Operator + RBAC 扩展 | 顶部「当前唯一有效状态」 | | 03 | 实名认证扩展(人脸核验预留) | 同上 | | 04 | Profile + Preference + 本地资格 | 同上(含本地资格声明与审核) | | 05 | 审核模块扩展(本地资格) | 同上 | | 06 | Match Engine 扩展(本地资格 Eligibility) | 同上 | | 07 | V1.1 首页重构 + 找对象 | 2026-09-16 通过用户验收(顶部表 + `Phase-07-…-2026-09-13.md`) | | 08 | Like / Match / Block | 2026-09-16 KEEP-VERIFY 复验关闭 | | 09 | Text Chat | 2026-09-16 KEEP-VERIFY 复验关闭 | | 10 | Image & Chat Safety | 2026-09-16 KEEP-VERIFY 复验关闭 | | 11 | 公益服务通知扩展 | 2026-09-16 KEEP-VERIFY 复验关闭 | ### Phase 14 — 多类型公益活动 ✅ 已完成(2026-09-17 KEEP-VERIFY/EXTEND 复验通过) | 任务 | 状态 | |------|------| | ActivityType 分类 + 按类型报名策略(实名/本地资格/性别名额) | ✅ | | 容量原子扣减(`insertIfCapacityAvailable` / `approveIfCapacityAvailable`) | ✅ 新增 | | `activityType` / `orgRole` 生产 CHECK 白名单校验(D3) | ✅ 新增 | | 多组织关系 + 容量分组落库与回读 | ✅ | | 运营端:`/operator/activities` 建活动改走 V1.1;组织/分组 4 端点;列表补 `activityType` | ✅ | | 用户端:删除 3 个错挂的运营写入端点(双实现) | ✅ | | Miniapp:分类 Tabs code 对齐生产白名单(6 类)+ 类型化卡片 + 差异化资格提示 | ✅ | | Admin:`ActivityManagementView.vue` 类型驱动动态表单 + `/activities` 路由与导航 | ✅ 新增 | | INV-020:组织接口零用户字段;报名列表仅运营端且要求 `activity.view` | ✅ | | 测试库补齐 V023 列/约束 + 三张缺失表;activity 五表移入必选集合 | ✅ | | 测试:`ActivityPhase14Test`(23)+ `ActivityConstraintGuardTest`(9,解析真实 DDL 与前端源码) | ✅ 新增 | | 全量回归 **450 tests 全绿** | ✅ | ### Phase 15 — 活动报名、审核与签到 ✅ 已完成(2026-09-17 KEEP-VERIFY/EXTEND 复验通过) | 任务 | 状态 | |------|------| | **D1 必崩**:签到码一生成即作废(`generate` 写 `"used"` → 扫码 100% 失败)→ 改为 `issued` | ✅ | | 重复签到:原子条件更新 `checkinIfNotCheckedIn` + 幂等返回 `alreadyCheckedIn` | ✅ 新增 | | **D9 必崩**:取消/拒绝后重报名撞 `UNIQUE(activity_id,user_id)` → 复用记录 `reuseIfCapacityAvailable` | ✅ | | 审核/取消原子化:`rejectIfPending` / `cancelIfActive`;取消补审计日志 | ✅ | | 后台报名列表含 pending(原只查 approved,审核页无待审项) | ✅ | | 报名窗口 `registration_start_at` / `registration_end_at` 生效 | ✅ 新增 | | 容量分组真正参与扣减(`incrementIfAvailable` / `decrementIfPositive`) | ✅ 新增 | | 计划项③:V040 `activity_staff_assignments` + 签到/审核数据范围校验(INV-020) | ✅ 新增 | | Admin:`ActivityCheckinView.vue` 签到工作台 + `/activities/checkin` 路由与导航 | ✅ 新增 | | Miniapp:`cancelRegistration` 封装(后端端点存在但前端无入口) | ✅ | | 测试库补齐报名表 UNIQUE + 两个 CHECK;两表移入必选集合;迁移基线 39→40 | ✅ | | 测试:`ActivityPhase15Test`(21)+ `CheckinServiceTest` 假绿改真实守卫(5)+ 约束守卫(2) | ✅ 新增 | | 全量回归 **474 tests 全绿** | ✅ | ### Phase 16 — 活动互选与双方开启沟通确认 ✅ 已完成(2026-09-17 KEEP-VERIFY/EXTEND 复验通过) | 任务 | 状态 | |------|------| | **D1(Critical,Gate 缺陷 · INV-014/015)** 双确认后不建 Match/会话 | ✅ 重写 `confirmConnection` 走 `confirmActivityInterest`,exactly-once(`both_confirmed_at` NULL→非NULL 仅一方赢家建 Match+会话并 `bindMatch`) | | **D2(High,双实现分裂)** 旧/新路径各自为政 | ✅ 统一到 `RelationshipService.confirmActivityInterest`(返回 `matchId` + `priorUnmatch`) | | **D3(High,隐藏编译缺陷 · 必崩级)** Phase 15 引用未定义 `matchMapper.reopenEpisode` | ✅ `MatchMapper` 补 `@Update reopenEpisode`(`WHERE status='unmatched' AND deleted_at IS NULL`);**Phase 15 提交态从未真正编译通过** | | **D4(High,INV-006 泄露)** 本侧未确认即回显对方确认态 | ✅ `getMyConsentStatus` 改 `partnerAccepted = myAccepted && partnerSideAccepted` | | **D5(Medium,缺会话)** 复用/新建 Match 后未显式开启会话 | ✅ `confirmActivityInterest` 显式 `getOrCreateConversation` 并返回 `conversationAutoCreated=true` | | **D6(Medium,测试库零覆盖)** 缺 `activity_mutual_connection_consents` 表 | ✅ `schema-h2.sql` 补表(对齐 V024+V037+V041);`EntityMigrationParityTest` 移入 `REQUIRED_IN_TEST_SCHEMA`;`MigrationValidationTest` 基线 40→41 | | **D7(Medium,无互选测试)** | ✅ 新建 `ActivityMutualConsentServiceTest`(7 用例,走真实方法路径) | | **D8(Medium,断言与 #20 冲突)** `ChatPhase09IntegrationTest:344` 假设每次新建独立会话 | ✅ 改为 `assertEquals`(认可 AGENTS.md #20 复用语义),保留"复用同一消息管线"主断言 | | 负向验证(注释 createMatchAndConversation → 2 用例精准变红并还原) | ✅ 守卫有牙 | | 新增 V041 `expires_at`+`match_id` 迁移 | ✅ | | 全量回归 **481 tests 全绿** | ✅ | > **2026-09-17 复验结论(KEEP-VERIFY/EXTEND)**:历史 ✅ 不可信。活动互选存在**核心 Gate 缺陷**——双确认后根本不建 Match/会话(INV-014/015); > 且 Phase 15 提交态引用未定义的 `reopenEpisode`,**整个模块从未编译通过**,"474 绿"是假象。已统一双实现到 > `RelationshipService.confirmActivityInterest`,修复 7 处缺陷 + 1 处隐藏编译缺陷 + 1 处测试保真度缺陷,新建 7 用例互选测试, > 并经负向验证证明守卫有牙。报告:`docs/Phase-16-V11-Recovery-Completion-Report-2026-09-17.md` ### Phase 17 — 举报与风控 ✅ 已完成(2026-09-17 KEEP-VERIFY/EXTEND 复验通过) | 任务 | 状态 | |------|------| | **D1(Critical,必崩级测试盲区)** `reports`/`risk_events`/`risk_actions` 三表在 H2 缺失 → 风控/举报真实 DB 路径零覆盖;`ReportServiceTest` 全是 `assertTrue(true)` 假绿 | ✅ `schema-h2.sql` 补齐三表(对齐 V012,去外键留 CHECK);`EntityMigrationParityTest` 移出 `TEST_SCHEMA_OPTIONAL_TABLES` 入 `REQUIRED_IN_TEST_SCHEMA` | | **D3(High,敏感访问无审计 · AGENTS.md #8)** 查看他人风险画像/举报详情不记录审计 | ✅ 新增 `AuditLogService.recordSensitiveAccess`;`getReportDetail`/`getUserRiskProfile`/`RiskController.getRiskEvents` 三端点接线 | | **D4(Medium,审计完整性)** `saveAuditLog` 未填 `ip`/`userAgent` | ✅ 增强补全(与 `AuthorizationAuditListener` 同模式取 `RequestContextHolder`) | | **D5(Medium,数据一致性)** `findByUserId` 未过滤 `deleted_at` | ✅ 补 `deleted_at IS NULL`(与 `sumScoreByUserId` 一致) | | **D2(Medium,审计缺失)** `manualFlagRisk` 人工标记无审计 | ✅ 注入 `AuditLogMapper`,写 `MANUAL_FLAG_RISK` | | **D6(隐藏编译缺陷)** `javax.servlet` → Spring Boot 3.x 已迁移 `jakarta.servlet`;`risk_events` 漏 `updated_at` 列 | ✅ 三处 import 改 jakarta;`risk_events` 补 `updated_at` | | 来源接入代码层(detectCounselingRisk/detectAppointmentRisk/detectActivityRisk)运行时已被调用,非假绿 | ✅ 确认(不重写来源逻辑) | | 最小可见(INV-006 同族):后台风险页不暴露无关咨询正文 | ✅ 延续既有约束 | | 负向验证(注释 getReportDetail 敏感访问审计 → D3 守卫精准变红并还原) | ✅ 守卫有牙 | | 新增 `ReportAndRiskPhase17IntegrationTest`(7 用例) | ✅ | | 全量回归 **488 tests 全绿** | ✅ | > **2026-09-17 复验结论(KEEP-VERIFY/EXTEND)**:历史 ✅ 不可信。风控/举报整条真实 DB 路径因测试库缺三表而**零覆盖**,`ReportServiceTest` > 假绿掩盖盲区;且敏感访问(查看他人风险画像/举报)此前**无审计**(违反 AGENTS.md #8 默认拒绝 + 查看需审计)。已修复 6 处真实缺陷 > (含 1 处必崩级测试盲区、1 处隐藏 jakarta 编译缺陷),补齐三表并新增 7 例集成测试,负向验证证明守卫有牙。报告:`docs/Phase-17-V11-Recovery-Completion-Report-2026-09-17.md` ### Phase 18 — 申诉 ✅ 已完成(2026-09-17 KEEP-VERIFY 复验通过) | 任务 | 状态 | |------|------| | **D1(Critical,必崩级测试盲区)** `appeals` 表缺失 + `AppealServiceTest` 9 例中 6 例 `assertTrue(true)` 假绿 → 申诉真实 DB 路径零覆盖 | ✅ 补 `appeals` 表(对齐 V013,去外键留 `chk_appeal_status`/`chk_appeal_type`);移出白名单入 `REQUIRED_IN_TEST_SCHEMA`;删除假绿测试,新建 `AppealPhase18IntegrationTest`(15 例) | | **D2(High,生产故障 · 只在 PG 上炸)** `escalateAppeal` 向 `operatorId` 发用户通知 → 撞 `notifications.user_id → users(id)` FK(operators 与 users 不同表)→ 升级事务整体回滚 | ✅ 移除非法通知;升级后进入后台待办队列由风控员决策 | | **D3(High,生产故障 · 只在 PG 上炸)** `appealType` 未校验 `chk_appeal_type` 白名单 | ✅ 校验白名单 + 必须与处置类型一致;缺省按处置类型推导 | | **D4(Medium,功能死胡同)** `escalated` 无法再处理(后端只收 pending/reviewing;前端按钮仅 pending) | ✅ 后端原子认领放行 escalated;`getPendingAppeals` 返回 pending+escalated;前端放开处理入口 | | **D5(Medium,并发)** `processAppeal` 先读后写无原子守卫 → 并发双处理相互覆盖 | ✅ 新增 `markReviewingIfProcessable` 原子认领,仅赢家继续 | | **D6(Low,一致性)** `findByUserId`/`findPending`/`findByStatusPaged` 未过滤 `deleted_at` | ✅ 三处补 `deleted_at IS NULL` | | **D7(Low)** `approveAppeal` 硬编码 `"resolved"` | ✅ 改用 `Constants.RISK_ACTION_STATUS_RESOLVED` | | **D8(Low,前后端契约)** miniapp 传 `evidenceFileIds`、后端只读 `evidence` | ✅ DTO 增 `evidenceFileIds`,服务层序列化映射进 `evidence` | | 负向验证(误伤其他处置 → Gate 用例精准变红并还原) | ✅ 守卫有牙 | | admin-web `vue-tsc --noEmit` EXITCODE=0 | ✅ | | 全量回归 **494 tests 全绿** | ✅ | > **2026-09-17 复验结论(KEEP-VERIFY)**:历史 ✅ 不可信。申诉整条真实 DB 路径因测试库缺 `appeals` 表而**零覆盖**,`AppealServiceTest` 的 > 6 处 `assertTrue(true)` 假绿恰好掩盖 Gate 四条不变量;且 `escalate` 向 operator 发用户通知会撞 `notifications.user_id → users(id)` FK > (PG 上升级 100% 失败)、`appealType` 未校验生产 CHECK 白名单。已修复 8 处真实缺陷(含 1 处必崩级测试盲区、2 处「只在 PG 上炸」的生产故障), > 补齐 `appeals` 表并新增 15 例集成测试、删除 9 例假绿,负向验证证明 Gate 守卫有牙。报告:`docs/Phase-18-V11-Recovery-Completion-Report-2026-09-17.md` ### Phase 13A — 公益婚恋咨询与婚前辅导(核心链路)✅ 已完成(2026-09-17 KEEP-VERIFY/EXTEND 复验通过) | 任务 | 状态 | |------|------| | V022 counseling_services + counseling_followups 迁移 | ✅ | | **V039 Phase 13A 迁移**(counseling 幂等键 + 三个 CHECK 白名单显式固化) | ✅ 新增 | | `CounselingService`(权威实现,合并孤儿类 `CounselingServiceApp` 后删除) | ✅ 重写 | | 用户端 API:intro / create / list / detail / cancel / companion-confirm | ✅ | | 后台 API:queue / assigned / detail / assign / schedule / start / followup / complete | ✅ 8 端点 | | INV-012 Counselor assigned scope 实现(`assignIfPending` 条件更新防并发覆盖) | ✅ | | INV-013 正文保护(脱敏分层:user/assigned=全文;matchmaker/operator=脱敏;manager=摘要无 followups) | ✅ | | INV-005 伴侣须本人确认 | ✅ | | 合法状态机 `ALLOWED_TRANSITIONS` + `assertTransition` | ✅ 新增 | | 幂等(`idempotencyKey` + `uk_counseling_idem` 唯一索引) | ✅ 新增 | | Miniapp U55-U59 页面(咨询介绍/申请/我的/婚前辅导),字段名对齐后端 + 检查 `success` | ✅ | | Admin `CounselingView.vue` 重写(四态 + 二次确认)+ `/counseling` 路由注册 | ✅ | | 测试:`CounselingPhase13ATest`(25)+ `CounselingConstraintGuardTest`(5) | ✅ 新增 | | 全量回归 **420 tests 全绿** | ✅ | ### Phase 13 — 公益红娘服务转介(2026-09-09 快照) > ⚠️ 该首轮任务表(✅ 为当时自评)已被下方 > 「Phase 13 — 公益红娘转介 ✅ 已完成(2026-09-16 KEEP-VERIFY/EXTEND 复验通过)」取代 —— > 后者记录了复验修复的真实缺陷与永久守卫,**以那节为准**。 ### Phase 12 — 关系状态轻量扩展 ✅ 已完成(2026-09-16 KEEP-VERIFY 复验通过) | 任务 | 状态 | |------|------| | Successful首页服务建议(婚前辅导引导) | ✅ | | GettingToKnow服务建议规则 | ✅ | | Counseling recommendation rules | ✅ | | 成功关系双确认 / 恢复 / 退出 / 历史 Episode / 并发确认 | ✅ 行为测试 14 项 | | getting_to_know 阶段婚前辅导入口引导(计划项 2) | ✅ 已接线 `HomeApplicationService.buildServiceRecommendations` | | 工作人员不能替用户确认成功关系(INV-005) | ✅ 非成员路径断言抛业务异常 | > **2026-09-16 复验结论(KEEP-VERIFY/EXTEND)**:历史 ✅ 不可信,逐条核对运行时路径后修复 4 处缺陷: > - **D1(Critical,生产故障 · 同一族系统性缺陷)** 实体与生产迁移**系统性漂移**:23 张表、50 个列在 > `db/migration` 中根本不存在,而测试库 `schema-h2.sql` 手写了它们 → 全量测试绿 = 假绿。其中 > **11 张表属"INSERT 必崩"级**(缺 `id`/`created_at`/`updated_at`,被 `AutoFillHandler` 强制填充, > 每次写入必进 SQL):`matches`(缺 `episode`/`source_id`/`last_activity_at`/`unmatched_by`/`deleted_at`)、 > `user_preferences`(缺 `id` + 11 个权重列)、`permissions`、`roles`、`consent_records`、`risk_events`、 > `review_reasons`、`match_rule_configs`、`matchmaker_followups`、`matchmaker_recommendations`、 > `user_privacy_settings`。**真实 PG 上 Match 创建、择偶偏好保存、权限/角色写入、同意记录、风险事件 > 全部失败**。修复:新增 `V037__align_entity_columns_with_migrations.sql`(幂等 `ADD COLUMN IF NOT > EXISTS`,含存量数据 `episode` 回填与 `id` 补发)。 > - **D2(High)** `RelationshipService.createMatch` 不写 `episode`/`lastActivityAt`,与 > `MatchService.createOrReuseMatch` 形成**双路径字段填充不一致**;且 `episode` 为 null 时 > `MatchService` 的 `m.getEpisode() + 1` 对 `Integer` **自动拆箱抛 NPE**。修复:两条路径统一按 > AGENTS.md #20 推导 episode,并做 null 兜底。 > - **D3(High)** 测试库缺 `user_identities` 等 7 张表 → `GET /api/v1/home` 在测试环境直接 > `BadSqlGrammar("Table USER_IDENTITIES not found")`,**首页接口零回归覆盖**。修复:补齐 > `user_identities`/`review_tasks`/`local_eligibility_evidences`/`home_banners`/`service_locations`/ > `content_articles`/`activities` 七张表(列对齐生产迁移)。 > - **D4(Medium)** Phase 12 计划项 2 实际**未实现**:`getting_to_know` 分支只产出 `counseling`, > 婚前辅导入口仅在 `matched_successfully` 才出现。修复:`HomeApplicationService.buildServiceRecommendations` > 的 `getting_to_know` 分支补 `premarital` 引导(与 counseling 并列,不互相挤占)。 > - **新增永久守卫** `EntityMigrationParityTest`(5 用例):把「实体字段 ⊆ 生产迁移累积列」与 > 「测试库覆盖关键业务表」固化为**编译后自动可验证的不变量**,并区分「必崩级 / 潜伏级」。经 > **两轮负向验证**证明会变红(第一轮分级过窄已修正:`episode` 由"潜伏级"纠正为"必崩级")。 > - **删除假测试**:`RelationshipStatusServiceTest` 与 `RelationshipStatusServiceDoubleConfirmTest` > 原含 `assertTrue(true); // 占位测试`,对 INV-005 零覆盖(AGENTS.md 明令禁止)→ 已删除占位断言, > 行为验证移至走真实服务方法的 `RelationshipProgressPhase12Test`(14 用例,含并发确认)。 > - 报告:`docs/Phase-12-V11-Recovery-Completion-Report-2026-09-16.md` ### Phase 13 — 公益红娘转介 ✅ 已完成(2026-09-16 KEEP-VERIFY/EXTEND 复验通过) | 任务 | 状态 | |------|------| | 保留红娘服务和人工推荐;任何工作人员不能替用户 Like(INV-005) | ✅ 行为测试 4 项 | | 补齐转介咨询、活动、服务站的用户同意、来源追踪和状态记录 | ✅ 行为测试 6 项 | | 红娘只能看转介状态和必要摘要,不能读取 counseling followup 正文(INV-013) | ✅ 行为测试 3 项 | | 红娘归属校验(推荐/转介不得越权代操作) | ✅ 负向测试 4 项 | > **2026-09-16 复验结论(KEEP-VERIFY/EXTEND)**:历史 ✅ 不可信,逐条核对**运行时路径**与**生产约束**后修复 7 处缺陷: > - **D1(Critical,生产故障)** `matchmaker_recommendations.status` 代码写入 `liked`/`passed`/`confirmed_mutual`, > 而生产 `V009 chk_rec_status` 只允许 `pending_view/viewed/responded` 且从未扩展 → **真实 PG 上用户接受/跳过 > 推荐必崩**(`DataIntegrityViolation`)。测试库 `schema-h2.sql` 未复刻该 CHECK,故长期静默。修复: > `V038__align_matchmaker_status_constraints.sql` 以 `DROP CONSTRAINT IF EXISTS` + `ADD CONSTRAINT` 扩展白名单。 > - **D2(Critical,生产故障)** `MatchmakerController` 缺省 `serviceType="recommendation"` 不在 > `chk_matchmaker_service_type` 白名单 → **提交红娘服务必崩**。修复:同 `V038` 扩展(原 7 值 + > `recommendation`/`referral_counseling`/`referral_activity`/`referral_station`)。 > - **D3(High,越权)** `MatchmakerServiceService.recommendPartner` 无 `assignedOperatorId` 归属校验 → > 任意红娘可替非本人负责的服务发起推荐(并可推荐给自己)。修复:补归属校验 + 禁止自我推荐。 > - **D4(High,越权读)** `getServiceDetail` 无归属校验且返回**完整**用户资料(`userId`/`description`/`userProfile`/ > `followups`)→ 任意红娘可读任意用户敏感详情。修复:签名加 `requesterId`,负责人得完整视图, > 非负责人得脱敏视图(去 `userProfile`/`userId`/`followups`,仅 `followupCount` + `viewerIsOwner=false`)。 > - **D5(High,越权写)** `ReferralService` 的 `userId` 取自**请求体**且**零授权校验** → 任意持 > `matchmaker.service` 权限者可替任意用户发起转介。修复:新增 `assertMatchmakerServesUser`, > 在 `referToServiceStation`/`referToActivity` 入口强制校验"存在进行中的服务关系"。 > - **D6(High,生产故障)** `MatchmakerFollowupMapper.findByServiceId` 只声明方法、**无 `@Select`** → > 运行时 `Invalid bound statement (not found)`,`getServiceDetail` **必崩**。**该缺陷由本轮新增测试首次暴露** > (历史测试从未调用该路径)。修复:补 `@Select`。 > - **D7(Medium,契约缺口)** admin-web 5 处 API 缺口:`/matchmaker/services/operator/queue`、 > `/matchmaker/recommendations/operator`、`PUT /matchmaker/services/{id}/assign`、 > `POST /matchmaker/services/{id}/recommendation`、`/referrals/my-history`(C 端端点被运营端误用)。 > 修复:后端补 `GET /operator/matchmaker/recommendations` 与 `GET /referrals/operator/history` > 两个运营端端点(含 `MatchmakerServiceMapper.findActiveByOperatorAndUser`、 > `MatchmakerRecommendationMapper.findByOperatorId`、`ReferralService.getReferralHistoryByOperator`), > 前端改路径、`assign` 改 `POST` + body `operatorId`;小程序新增 `miniapp/services/referralService.js`。 > - **测试库盲区修复**:`schema-h2.sql` 补 `matchmaker_services`/`matchmaker_recommendations`/ > `matchmaker_followups` 三表(约束与 V038 对齐);`EntityMigrationParityTest` 的 3 张 matchmaker 表 > 从 `TEST_SCHEMA_OPTIONAL_TABLES` 移入 `REQUIRED_IN_TEST_SCHEMA`;`MigrationValidationTest` 基线 37 → 38。 > - **新增永久守卫** `MatchmakerReferralPhase13Test`(17 用例,`@SpringBootTest` 走真实方法路径)+ 重写 > `MatchmakerServiceTest`(6 用例)。**关键教训**:首版常量守卫**硬编码白名单副本**,注入 D1 缺陷后 > **仍全绿**(对漂移零反应)→ 重写为**直接解析 `db/migration/V*.sql`**,按文件名顺序应用 > `DROP CONSTRAINT IF EXISTS` + `ADD CONSTRAINT` 取"最终有效"白名单,并内置解析器自检用例。 > 修正后经**第二轮负向验证**证明会红(`Tests run: 23, Failures: 1, Errors: 2 / BUILD FAILURE`)。 > - **删除假测试**:`MatchmakerServiceTest.testMatchmakerCannotLike` 原为 `assertTrue(true)`; > `CoreInvariantsTest` 的 INV-007 断言的是 `MATCHMAKER_STATUS_*` 常量(名不副实)、INV-010 亦为 > `assertTrue(true)` → 已删除占位、如实改名并注明行为验证位置。 > - 报告:`docs/Phase-13-V11-Recovery-Completion-Report-2026-09-16.md` ### Phase 13A — 婚恋咨询与婚前辅导 ✅ 已完成(2026-09-17 KEEP-VERIFY/EXTEND 复验通过) | 计划项 | 状态 | |------|------| | 计划项 1 Admin Vue 修复 + `/counseling` 路由注册 | ✅ `vue-tsc` EXIT=0 | | 计划项 2 认证主体 userId + 幂等 + 取消 + owner 校验 + 状态迁移 | ✅ 8 用例 | | 计划项 3 条件更新解决并发 + Assigned Service 边界 | ✅ `assignIfPending` + 4 用例 | | 计划项 4 Manager 可摘要不可读正文 | ✅ 7 用例 | | 计划项 5 婚前辅导复用 service type + 伴侣自主确认 | ✅ 4 用例 | | 计划项 6 U55~U59 类型/契约/四态/非医疗化文案 | ✅ 双端 type-check EXIT=0 | > **2026-09-17 复验结论(KEEP-VERIFY/EXTEND)**:历史 ✅ 不可信。counseling 模块存在 > **双实现**——线上权威 `CounselingService`(167 行)**零测试**,唯一被测的 > `CounselingServiceApp`(280 行)是**孤儿类**(无注入点、无端点可达,生产永不执行)。 > 已将其流程合并入 `CounselingService` 并删除孤儿类及仅其使用的 3 个 DTO 与测死代码的测试。 > 修复 **9 处缺陷**: > - **D1(Critical,生产故障 · INV-013 泄露)** 咨询正文 `userRequestSummary` **原文被写入 WARN 日志** > (`CounselingServiceApp:81`,同 Phase 10 D2 一族)。修复:合并后只记 `serviceId` + `riskLevel`。 > - **D2(High,越权)** 申请 `userId` 取自**请求体**而非认证主体 → 可替他人提交申请。 > 修复:Controller 强制 `principal.id()`。 > - **D3(High,并发)** `assignCounselor` 用「先读后写」→ 两管理员并发分配**静默覆盖**。 > 修复:`assignIfPending` 条件更新(`WHERE status='pending' AND assigned_operator_id IS NULL`), > `affectedRows=0` 明确报错。 > - **D4(High,越权读)** `counseling_manager` 经 `getDetail` 可读 `followups` 正文 → > **INV-013 绕过通道**。修复:manager 只加回 `userRequestSummary`,不装配 followups。 > - **D5(Medium)** 无状态机 → 「已完成」可被再取消。修复:`ALLOWED_TRANSITIONS` + `assertTransition`。 > - **D6(Medium,生产故障)** `GET /counseling/services/intro` **后端不存在**,小程序 intro 页 > 100% 无数据(且被 `/services/{id}` 吞掉)。修复:补端点并**声明在变量路径之前**。 > - **D7(Medium,契约)** Admin 调用 5 条不存在的 `/services/operator/*`(404)+ 缺四态。 > 修复:后端补 8 个运营端端点(`@PreAuthorize`),前端整体重写。 > - **D8(Medium,契约)** 小程序字段名错(`userRequestSummary`/`preferredServiceMode`)+ 无幂等 > + `my-counseling` **未检查 `success`**(403 静默空列表)+ 跳转不存在的页 + WXML 内调用方法(非法)。 > - **D9(Medium,测试保真度)** 测试库 counseling 两表**零 CHECK 约束**,`counseling_services` > 未列入 `EntityMigrationParityTest` 任何集合(= 零覆盖)。修复:补 3 个 CHECK + 建 > `counseling_followups` + 两表移入 `REQUIRED_IN_TEST_SCHEMA`。 > - **另修 4 处测试基建缺陷(T1~T4)**:① 守卫因 surefire `${project.basedir}/..` > 指向**仓库根**而**找不到 DDL**(且 `backend/` 是子目录非祖先,回溯也找不到)→ 恒真假绿; > ② 全限定 `@com.baomidou...TableField(exist=false)` **漏解析** → 假漂移警报; > ③ `OperatorEndpointPermissionCoverageTest` 扫到**私有辅助方法**(假阳性); > ④ 两处测试自身逻辑缺陷(陈旧内存快照比较、Instant 纳秒 vs DB 微秒精度)。 > - **负向验证两轮**:① 从 `V039` 移除 `scheduled` → 常量守卫**精准变红** > (证明其解析的是**真实 DDL** 而非副本);② 注入「并发回退先读后写 / manager 读 followups / > 状态机守卫失效」→ **三个用例各自精准变红**。均已还原(`grep -c "NEG-VAL"` = 0)。 > - **全量回归**:`Tests run: 420, Failures: 0, Errors: 0, Skipped: 3 / BUILD SUCCESS`(4:49)。 > 基线 391 → 420(净 +29)。 > - 报告:`docs/Phase-13A-V11-Recovery-Completion-Report-2026-09-17.md` ### V1.1 待实现模块(按 Phase 顺序) | 模块 | 对应 Phase | 状态 | |------|-----------|------| | Home Aggregate API + V1.1首页 | Phase 07 | ✅ 已完成 | | Banner 管理(后端+前端) | Phase 19 | ✅ 已完成(2026-09-17 复验关闭) | | 本地资格声明与审核 | Phase 04~05 | ⏳ 待开发 | | 公益红娘服务转介 | Phase 13 | ✅ 已完成 | | 婚恋咨询 + 婚前辅导(Phase 13A) | Phase 13A | ✅ 已完成(2026-09-17 复验关闭) | | 内容管理(婚恋课堂/反诈) | Phase 19 | ✅ 已完成(2026-09-17 复验关闭) | | 专项公益服务项目 | Phase 19 | ✅ 已完成(2026-09-17 复验关闭) | | 善缘服务站 + 用户端公益服务页面(U37/U49~U54/U60/U61/U64) | Phase 19 | ✅ 已完成(含 V042 临时公告) | | V1.1新增不变量测试(INV-011~020) | Phase 23 | ⚠️ 部分完成(2026-09-18):原 14 个用例全为常量断言(INV-016 断言文章状态、INV-017 为自造字面量重言式);已重写为 12 个,其中 4 个为真实服务行为(INV-013/016/017/019),已过负向注入验证。详见 `docs/Phase-23-V11-Recovery-Completion-Report-2026-09-18.md` | ### 当前运行状态 ``` 管理后台: http://localhost:13520/ (凭证由本地环境变量或安全 Seed 提供) API 网关: http://localhost:8085/api/v1/ PostgreSQL: localhost:5434 (danyang_match) Redis: localhost:6381 MinIO: localhost:9003 (凭证由本地环境变量提供) ``` **管理端端口口径**(2026-09-18 对齐为 13520): | 形态 | 端口 | 说明 | |---|---|---| | admin-web 本地开发(vite) | **13520** | 权威声明在 `admin-web/vite.config.ts`;`strictPort: true`,被占用直接失败而非静默漂移到 13521 | | 生产 admin 容器发布 | **13520** | 声明在 `infrastructure/docker-compose.prod.yml`——**该文件位于 `.gitignore` 的「Secrets and certificates」段,刻意不进版本控制**,故此改动仅在部署机生效;仍绑定 `127.0.0.1`,对外访问走 nginx 80/443 + `/admin/` | | 本地整套栈的管理端入口 | 6688 | admin 容器不发布端口,与 `/api` 同由 nginx 的 6688 暴露(6688 是 nginx 入口,不是纯管理端端口) | | staging admin 容器发布 | 3001 | 为与生产同机共存,staging 全部端口按「生产 + 1」错开(5433/6380/8081/3001);`tests/uat/run-uat.sh` 的 `UAT_ADMIN_URL` 默认指向它 | `ui-tests/ui-document-baseline-contracts.mjs` 钉住「本地开发 / 本文档 / 生产 compose」三者端口一致: 前两处为硬断言;生产 compose 因不在版本控制内,采取「存在才断言」——CI 上该文件不存在, 显式打印 skip 而非假红。 --- ## 当前 Phase ### Phase 14 — 多类型公益活动(核心链路)✅ 已完成 | 任务 | 状态 | |------|------| | V023 activity_type/registration_policy/target_group/industry_scope 字段扩展 | ✅ | | activity_organizations 多组织关联表 | ✅ | | activity_capacity_groups 容量分组表 | ✅ | | Activity Java实体扩展(6个新字段) | ✅ | | ActivityOrganization + ActivityCapacityGroup 实体/Mapper | ✅ | | ActivityService 新增4个V1.1方法 | ✅ | | ActivityController 新增6个API端点 | ✅ | | Constants 新增 ACTIVITY_TYPE_* + ORG_ROLE_* 常量 | ✅ | **Phase 13A(公益婚恋咨询与婚前辅导)— 已完成** ✅ ### Phase 19 — 统一运营后台 + 用户端公益服务页面 ✅ 已完成(2026-09-17 复验关闭) > 复验报告:`docs/Phase-19-V11-Recovery-Completion-Report-2026-09-17.md` > 后端全量回归:`Tests run: 602, Failures: 0, Errors: 0, Skipped: 3 / BUILD SUCCESS` > admin-web:`vue-tsc --noEmit` EXIT=0、`vite build` EXIT=0;小程序:`tsc --noEmit` EXIT=0;ui-tests 14/14 PASS | 任务 | 状态 | |------|------| | V026 内容+专项项目+组织关系表 | ✅ | | V042 善缘服务站「临时公告」表(本轮新建) | ✅ | | ContentService(分类/文章 CRUD + publish/offline) | ✅ | | Content 运营端接口分离(修「发布死路」/「分类停用不可恢复」) | ✅ | | ServiceProgramService(项目CRUD + 成员审批 + 退出/移除/统计) | ✅ | | Banner 运营端(白名单校验 400 而非 500 + 软删过滤 + 禁外链 + 预览) | ✅ | | 善缘服务站运营端(信息维护 + 公告五端点 + 权限下沉方法级) | ✅ | | 预约 IDOR 修复(principal.id() + 归属校验 + DataScopeGuard) | ✅ | | Admin Web 前端(Banner / 内容 / 服务项目 / 服务站公告) | ✅ | | 用户端 U37 四组重构 + U49~U54/U60/U61/U64 页面 | ✅ | **本轮复验修复 25 处真实缺陷**,其中高价值项:服务站公告能力**整条不可达**(Service + 表都在、零端点); 服务站 `create/update` **越权写**(写端点只受 `service_location.view` 保护,`manage` 是从未使用的死权限) 且该控制器**未纳入**权限覆盖守卫;Banner 校验抛 500;Content 发布死路;ServiceProgram 审批死路 / 草稿泄露 / 成员数恒 0 / 退出未实现; 测试库缺 `content_categories` 与 `service_location_announcements`(对应路径零覆盖)。 新增守卫:`ServiceLocationAnnouncementPhase19IntegrationTest`(24) / `ServiceLocationControllerPermissionContractTest`(5) / `ServiceLocationAnnouncementConstraintParityTest`(5)。负向验证 3 处注入 → 4 个用例精准变红并还原(`NEG-VAL` 残留 0)。 ### Phase 20 — Analytics 数据统计与管理驾驶舱 ✅ 已完成(2026-09-17 复验关闭) > 复验报告:`docs/Phase-20-V11-Recovery-Completion-Report-2026-09-17.md` > 指标字典:`docs/ANALYTICS_METRICS.md`(与 `MetricCatalog` 逐条对应) > 后端全量回归:`Tests run: 648, Failures: 0, Errors: 0, Skipped: 3 / BUILD SUCCESS` > admin-web:`vue-tsc --noEmit` EXIT=0;负向验证 2 轮 7 处注入 → 7 用例精准变红,还原后 0 残留 | 任务 | 状态 | |------|------| | P20-T01 指标字典(`MetricCatalog` 36 指标 × 12 字段 + 文档 + 守卫) | ✅ | | P20-T02~T09 User / Review / Recommendation / Match / Chat Started / Matchmaker / Activity / Risk Metrics | ✅ | | P20-T10 Daily Summary(补 days 1~365 边界校验) | ✅ | | P20-T11/T12 Platform Dashboard(统一口径层 `AnalyticsMetricsCalculator`) | ✅ | | P20-T13 Organization Dashboard | ✅(受 `analytics.view` + DataScope;`organization_admin` 待组织维度建模) | | P20-T14 Analytics 权限(V043 打通 `data_viewer` / `platform_admin`) | ✅ | | `GET /operator/analytics/v11-dashboard` 综合接口 | ✅ | **本轮复验修复的真实缺陷(高价值项)**: - **口径造假**:实名人数用 `profile_status != 'rejected'` 冒充(把"资料还在填"算成已实名); Chat Started 直接数会话行数(系统通知计入);Match 不分来源(10 对互选被当 10 对成功引用); Banner 曝光/点击**硬编码 0**(被读成"投了没人点",实为无埋点)。 - **死代码**:活动漏斗**全部硬编码 0**(不是没数据,是根本没有查询)+ 一行把"用户数"当"活动数"的死代码。 - **系统性软删缺陷(D12)**:`BaseEntity.deletedAt` 无 `@TableLogic`、全局无逻辑删除配置 → `selectCount` 把**软删数据全部计入统计且无任何报错**。修复 45 处统计调用(2 轮复验,首轮漏扫 5 处次级路径)。 - **权限授予脱节(Gate ⑩)**:`data_viewer` 角色被定义却**从未授权**(空壳角色); `platform_admin` 因 `id >= '20000000-…'` 条件漏掉 V1.0 老权限段 → **整个模块除 super_admin 外全员 403**。 - **假绿测试**:`AnalyticsServiceTest` = 5×`assertTrue(true)`(零断言),已删除并替换为 21 用例真实 DB 集成测试。 **跨阶段发现**(缺陷本体属 Phase 21,本轮已修 X1~X3): `AccountLifecycleService` 注销时把 `user_identities` 状态域的 `'failed'` 写入本地资格表 → 违反生产 `V017 chk_elig_verify_status` → **真实 PG 上 closeAccount 事务回滚、账号注销 100% 不可用**; `checkCanWithdraw` 的资格拦截用 `submitted`/`pending`(该表永不可能出现的值)→ 死代码。 测试库补齐 `chk_elig_type` / `chk_elig_verify_status` 后立即暴露 `ActivityPhase14Test` 夹具违规。 新增 `LocalEligibilityStatusVocabularyGuardTest`(9)。 ### Phase 21 — 账户生命周期增量 ✅(KEEP-VERIFY 复验关闭,2026-09-18) | 项 | 复验结论 | |------|------| | P21-T01~T05 + checkCanWithdraw(原声明「✅」) | 主体实现存在,但复验发现并修复 **6 处真实缺陷** | | Gate:注销后不能登录 | ❌→✅ `AuthService.checkAccountStatus` 原不拒 `CLOSED` → 已修复 | | Gate:注销后不能聊天 | ❌→✅ `notifyActiveMatches` 原是 TODO 桩 → 已实现关闭 Match + 通知对方 | | Gate:关闭未来服务(活动报名) | ❌→✅ `cancelPendingActivityRegistrations` 原是 TODO 桩 → 已实现 | | Gate:不暴露个人/咨询正文 | ❌→✅ `anonymizeServiceHistory` 已实现却**从未被调用(死代码)** → 已接线;身份证脱敏原是 TODO → 已覆盖占位符;并脱敏 `counseling_followups` 正文 | | 死代码矛盾 | ❌→✅ `closeAccount` 在 blockers 处硬抛异常,使 `cancelXxx` 永远不可达 → 改为信息性日志 + 继续清理 | | 测试保真度 | 删除 7×`assertTrue(true)` 假绿 → 替换为 11 用例真实 DB 集成测试 + 3 用例登录守卫 | | 跨模块防线(既有) | ✅ 推荐引擎 / 匹配资格 / Capability 已拒绝非 `NORMAL`(含 `CLOSED`) | | 后端全量回归 | **650 tests / 0 failures(起点 648,净 +2)** | | 报告 | `docs/Phase-21-V11-Recovery-Completion-Report-2026-09-18.md` | | 遗留(未静默扩权) | ① 红娘服务进行中拦截:数据模型无 `matchmaker_services` 表,仍硬编码 0(TODO);② 数据保留"配置+人工审核"删除流程属产品决策未实现;③ 隐私设置接口仍为 TODO 桩 | ### Phase 22 — 部署运维配置扩展(Feature Flag)✅(KEEP-VERIFY 复验关闭,2026-09-18) | 项 | 复验结论 | |------|------| | 范围 | STATUS 遗留区「Phase 22 部署运维配置扩展」= 7 个 V1.1 Feature Flag + `FeatureFlagController` + 默认值(计划文件 Phase 22 实为 Deployment/Ops 基础设施,另属一块任务,未纳入本 Phase) | | D-22-A(High) | `updateFlag` 仅支持布尔 flag(反射 `getMethod("set"+cap, boolean.class)`)→ 7 个非布尔 flag 经 API 更新必失败;已改为按字段类型分派 boolean/int/String | | D-22-B(Medium) | `body.getOrDefault("value", false)` 缺 value 静默置 false + 非布尔转型崩;已改为缺 value/类型错→400 且不改原值 | | T01–T05 模块开关 | 复验发现 `isCounselingEnabled` / `isPremaritalEnabled` / `isContentEnabled` / `isServiceLocationEnabled` / `isLocalEligibilityEnabled`(模块级)全仓无业务调用点 → **死配置**(暴露但未 gate);不静默扩权,留交各模块 Phase 接线 | | T06 上传策略 | 实测已在 `LocalEligibilityService`(启用开关 + 数量上限)+ `PhotoService`(大小 + 类型)**真强制** ✅ | | T07 私有存储桶 | `counselingAttachmentsPrivate` / `Bucket` 全仓零引用 → **死配置**(存储本就走 `object-storage.bucket-private`);可选增强,遗留 | | yml 声明夸大 | STATUS 称「application.yml 默认配置(15 flag)」——**来源表述错误**(features **不在**基础 `application.yml`),但**内容本身属实**:`application-dev.yml`(`spring.profiles.active: dev`,默认激活)与 `application-docker.yml`(compose 设 `SPRING_PROFILES_ACTIVE: docker`)**均有 `features:` 块且实际生效**(硬证据:dev 的 `chat-image-enabled: true` **覆盖**了 Java 字段默认 `false`)。原复验「4 份 yml 无 `features:` 块 / 默认值仅来自 Java 字段默认」为**误判**,已于 2026-09-18 二次修正;功能不受影响 | | 守卫测试 | 新增 `FeatureFlagControllerTest`(7 用例:21 键全暴露 / 布尔·字符串·整数更新生效 / 未知 flag·缺 value·类型错→400);负向验证(仅布尔缺陷版)恰 2 用例精准变红,还原全绿 | | 全量回归 | **657 tests / 0 failures / 0 errors / 3 skipped(起点 650,净 +7)** | | 报告 | `docs/Phase-22-V11-Recovery-Completion-Report-2026-09-18.md` | | 遗留(未静默扩权) | ① T01–T05 模块开关死配置;② T07 私有桶死配置;③ PUT 仅内存生效(不持久化,计划未要求);④ 计划 Phase 22 Deployment/Ops 基础设施尚未复验 | **Phase 20(Analytics数据统计扩展)— 已完成** ✅ ### Phase 22 — 历史声明块(已作废) > ⚠️ 此处原有**两块 2026-09-09 期的历史声明**(自称「application.yml 默认配置 ✅(15 个 V1.1 flag)/ > application-dev、docker.yml 配置 ✅/T01–T05、T07 ✅」),已被 2026-09-18 的 Phase 22 复验**整体推翻**: > ① 原文所称 `features:` 块**确实存在且生效**,但**不在**基础 `application.yml`,而在 `application-dev.yml` / > `application-docker.yml`(两 profile 均实际生效)—— 复验初判「4 份 yml 无 `features:` 块」**为误判**, > 已于 2026-09-18 二次修正;② T01–T05 模块开关与 T07 私有桶**确实全仓零业务调用点**(死配置),此结论成立。 > ③ 另发现 `AppController#getConfig` 返回**硬编码** features(第二来源),见 Phase 22 报告 D-22-E。 > **唯一有效结论见上方「Phase 22 — 部署运维配置扩展(Feature Flag)✅(KEEP-VERIFY 复验关闭,2026-09-18)」。** > 原文可从 `git log --all -- docs/STATUS.md` 取回。 ### Phase 23 — 可信系统测试重建(REFACTOR)⚠️ 部分关闭(KEEP-VERIFY 复验,2026-09-18) > 下方「Phase 23 — V1.1专项测试 ✅ 已完成」为**历史声明,经实测部分不成立**,以本节为准。 | 项 | 结论 | |---|---| | 报告 | `docs/Phase-23-V11-Recovery-Completion-Report-2026-09-18.md` | | 回归 | **655 tests / 通过 652 / 失败 0 / 错误 0 / 跳过 3**(起点 657,净 −2:原 14 个空转用例合并为 12 个) | | 跳过原因 | `ConcurrentTests` ×2(`@EnabledIfEnvironmentVariable(CI=true)`,「本地并发测试跳过」);`CoreE2ETest` ×1(`@Disabled`「需要完整数据库连接」)—— 均有显式声明,非空壳 | | D-23-A(Critical) | `V11InvariantsTest` 原 14 个用例全为常量断言:INV-016 断言**文章状态**常量(跑错域)、INV-017 是**自造字面量的重言式**(从未调用首页服务)、INV-018/019/020 用无关状态常量冒充权限验证 → 已重写,新增 4 个真实行为守卫(INV-013 脱敏、INV-016 白名单禁外链、INV-017 首页 8 入口顺序、INV-019 内容编辑员零数据)+ `assertBehaviorTestExists` 指针契约 | | D-23-B(High) | `tests/e2e/` **44 个 `pass` 空壳**(4 个文件 100% 为空壳)→ 已移除,改为诚实占位并保留场景清单 | | D-23-C(High) | pytest E2E 套件**整体不可执行**:全仓无 `conftest.py`,约 15 个 fixture 不存在;唯一可执行的 `run_v11_tests.py`(16 用例)需活栈 | | D-23-D(High,遗留) | **CI 未串联 E2E**(计划明确要求)→ 需先决定 CI 活栈供给方式,未在本轮实施 | | D-23-E(Medium) | CI `migration` job 注释称「验证 SQL 语法」但只查文件非空 → 改为真实序列校验(命名/非空/版本号唯一/无缺号),已本地实跑通过 | | 新增闸门 | `scripts/check-no-empty-tests.py`(AST 扫描,阻断 `pass` 空壳与无条件 `skip`)+ CI `test-shell-guard` job | | 遗留 | ① E2E 进入 CI 待基础设施决策;② pytest fixture 体系缺失;③ INV-011 无显式守卫(结构性满足);④ E2E 场景清单待实现(已保留在占位文件头) | | 结论 | **部分关闭**:假覆盖已归零,但 UAT 前 Gate 要求的端到端链路仍未真实执行,**不宜据此宣布可进入 UAT** | --- ### Phase 23 — 专项测试(历史声明块,已作废) > ⚠️ 本节原自称「✅ 已完成」,已被 2026-09-18 复验推翻:原用例中 44 个为 `pass` 空壳、 > 14 个「不变量测试」只断言**常量字符串**。**唯一有效结论见上方「Phase 23 — 可信系统测试重建(REFACTOR) > ⚠️ 部分关闭」与「Phase 23B — E2E 测试基建重建 ✅ 已关闭」。** ### Phase 23B — E2E 测试基建重建(2026-09-18)✅ 已关闭 > 本轮补齐的是 Phase 23 的两条遗留(D-23-C「E2E 整体不可执行」、D-23-D「CI 未串联 E2E」), > 与下方 **「Phase 24 — UAT增量」是不同工作**,不要混为一谈。 | 交付 | 说明 | |---|---| | `tests/e2e/conftest.py` | fixture 体系:ApiClient、`operator_token(username)`、`new_user`、栈探活 | | `pytest.ini` / `tests/e2e/requirements.txt` | 收集范围与依赖 | | `tests/e2e/sql/seed_e2e_operators.sql` | 运营账号自举(**迁移里没有任何 operator 种子**,全新库无账号可登录) | | CI job `e2e` | 起真实栈 → 等就绪 → seed → pytest → 失败阻断 → 清理 | | 8 个 E2E 文件改造 | 消除 import 期 `KeyError`;替换恒真 / 名不副实的断言 | **核心设计**:栈不可达时 `pytest.exit(4)`,**不是 skip** —— skip 会把"未执行"伪装成"通过"。 **验证**:本机真实活栈 **33 passed**;后端全量回归见本节末。 **本轮暴露并修复的真实生产缺陷**(H2 测试库全部零覆盖,只有真 PostgreSQL 才现形): | 编号 | 真相 | |---|---| | D-23B-A | 构建产物残留重复迁移版本号 042 → Flyway 报错 → **应用起不来** | | D-23B-B | 非 UUID path 参数 → 500 且泄漏数据库异常 | | D-23B-C | 6 个 E2E 文件 import 期崩溃 → **从未被执行过** | | D-23B-E | 权限 seed 缺口:`super_admin` 仅 18/48 条、`matchmaker` **0** 条(matchmaker 部分列为遗留) | | D-23B-I | 非法枚举参数 `IllegalArgumentException` 未映射 → 500(应 BAD_REQUEST) | | D-23B-J | `operator does not exist: uuid = character varying` → JDBC 增加 `stringtype=unspecified` | 详见 `docs/Phase-23B-V11-E2E-Infrastructure-Completion-Report-2026-09-18.md`。 ### HTTP 语义检修 — 失败响应携带真实 HTTP 状态码(2026-09-18)✅ 已关闭 起因:Phase 23B 收尾时质疑「HTTP 200 + body.code 这套约定,开放第三方还守得住吗」。 审计后确认**当时就已经是断的**,不是未来风险。 | 发现 | 说明 | |---|---| | 105 处 / 30 个 Controller | `return ApiResponse.error(...)` 不抛异常、不带 `@ResponseStatus` → HTTP 恒为 200 | | 前后端契约已断 | 小程序 `api.js` 的 401/403/429 分支**永远走不到**;token 过期回 403 → 不触发 `onSessionExpired` → **用户卡死** | | 未认证回 403 | `SecurityConfig` 未配 `authenticationEntryPoint`,body 连 `code` 都没有 | | CORS 默认 `*` + `allowCredentials(true)` | 注释却写「默认只允许 localhost」——注释与代码不符 | | 测试覆盖 | 全量测试仅 4 文件 / 15 处断言触及状态码 | 修法:**一处定义、两处应用、业务代码零改动** —— 响应码枚举新增 `httpStatus`(单一真相源)、 异常处理器从枚举读状态、新增 `ResponseBodyAdvice` 覆盖全部直返路径。 验证:E2E **37 passed**(+4 契约用例);后端回归 **662 / 0 / 0 / 3**; 活栈实测 404 / 400 / 401 正确。回归首轮 3 处失败经判定均为**测试断言了旧的错误行为**, 改断言而非改回实现。 遗留(第三方开放,属范围扩张,需产品决策):第三方凭据机制、限流是否真实生效、 OpenAPI 对外发布、调用审计与配额、分页幂等覆盖、脱敏边界。 **同日续做:身份类型与路径规则收敛** | 发现 | 说明 | |---|---| | 运营身份可打进用户端 | 兜底规则是 `authenticated()`,运营 token 完全满足;而 `@AuthenticationPrincipal UserPrincipal` 遇 `OperatorPrincipal` 类型不匹配返回 **null**(Spring 默认 `errorOnInvalidType=false`),全仓 **244 处**使用、**仅 48 处**做 null 检查 → 其余 **NPE → 500** | | PathPattern 陷阱 | 嵌套运营端点(`/counseling/services/operator/**` 等)不能用 `/**/operator/**` 覆盖——`**` 只允许在末尾,写了会抛 `PatternParseException` 且**整个过滤器链 500**(实测 E2E 由 37 passed 直落 33 failed) | | 修法 | 兜底收紧为 `hasRole("USER")`(196 处潜在 NPE 在认证层消解,不补 null 检查)+ 显式枚举 9 个运营前缀 + 新增 `SecurityPathCoverageTest` 机械守卫(防将来新增端点漏配) | 验证:E2E **40 passed**(+3 身份隔离用例);后端回归 **664 / 0 / 0 / 3**。 守卫经负向验证(摘掉 `/content/operator/**` → 恰好 1 用例变红并列出受影响的 6 个端点)。 详见 `docs/HTTP语义检修报告-2026-09-18.md`。 ### 幂等键检修 — `Idempotency-Key` 从「声明」到「兑现」(2026-09-18)✅ 已关闭 起因:HTTP 语义检修收尾时我写下「`Idempotency-Key` 已支持」,随后核对**推翻了自己的结论**—— 后端当时**零处**读取该头。 | 发现 | 说明 | |---|---| | 声明与实现彻底失联 | 规范第八章要求 7 类端点支持幂等键;前端 25 处调用点(8 service + 2 TS 页面)发送该头,**后端 0 处读取** | | **前端那一侧也是坏的** | 原写法 `idempotencyKey: \`like:${Date.now()}\`` —— `Date.now()` 每次调用都变,**就算后端实现了也永远命中不了**。互补的两半,谁也不起作用 | | 唯一真幂等的端点走的不是 header | 只有 counseling 申请靠 body 字段 `idempotencyKey`(V039 `uk_counseling_idem`) | | 两道兜底双双落 500 | `DuplicateKeyException`(并发重复提交的最后防线)与 30 处 `IllegalStateException`(业务状态冲突)均无映射 → 500;而 500 语义是"可重试",**调用方于是重试,制造更多重复** | | **一个错误的安全假设** | 上轮 `D-23B-J` 判定 `stringtype=unspecified` 是"一处解决全局"。本轮 V045 的 `actor_id VARCHAR` 在**同样开着该参数**的 docker profile 下依然抛 `character varying = uuid` → 该参数覆盖不到经类型处理器显式指定类型的参数。**真正的不变量是"列类型必须是 uuid"** | 修法:**一处实现、零业务代码改动、逐端点声明** —— `V045` 建表(`idempotency_records` + 唯一索引 `uk_idempotency_scope`)、`V046` 修正列类型、`IdempotencyInterceptor`(先占位后执行/重放/409)、 `IdempotencyResponseCacheFilter`(缓存响应体供逐字节重放)、`@Idempotent` 声明 30 处、 异常处理器两处新映射(`IllegalStateException` / `DuplicateKeyException` → 409, 且**刻意不映射**其父类 `DataIntegrityViolationException`,因后者含 CHECK 违反应由 500 暴露)。 四个关键设计:**先占位后执行**(靠唯一索引让并发只有一个赢家,不用 SELECT-then-INSERT)、 **失败释放占位**(否则一次瞬时故障把用户永久卡在 409)、**孤儿占位可接管**(进程中断不留死键)、 **作用域含 `actor_id`**(同键不同用户互不干扰)。 前端键改为"**一次未成功的逻辑操作内复用同一把键,成功才释放**",25 处 `Date.now()` 写法全部替换(残留 0)。 验证:E2E **49 passed**(含 `tests/e2e/idempotency_test.py` 7 用例:重放逐字节相同、同键只产生一条记录、 作用域隔离、**5 线程并发同键业务恰好落库一次**、无键重复 Like 不得 500); 后端全量 **669 / 0 / 0 / 3**(首轮 664/1 failure 为有意设计的迁移基线守卫,已按流程抬基线至 46); 小程序 `tsc --noEmit` EXIT=0;UI 契约门控 **14/14**。 **列类型不变量全库扫描**:所有 `*_id VARCHAR` 列中,`actor_id` 是唯一违规(已修); `client_message_id` / `provider_request_id` 为外部 id、`resource_id` / `source_id` 在 Java 侧**零处作查询条件** (已 grep 确认)→ 不存在第二处同类隐患。 **新增机械守卫** `IdempotencyDeclarationGuardTest`(2 用例,经注入变异负向验证,各自精确报出行号): 规范第八章 7 类端点族 + Phase 16 互选链路必须声明 `@Idempotent`;`@Idempotent` 后必须紧跟 `@PostMapping`。 同时**修正一处假绿**:`GlobalExceptionHandlerTest` 原 3 条断言只测 DTO、**一次都没进过处理器**。 **同轮清掉三处同形状问题**(均属"一处声明、另一处不兑现"的复发): 1. **补 `CheckinController` 手工签到的 `@Idempotent`** —— 第 146 章"扫码两次"场景的同类漏标; 2. **CI 上的 E2E 从未真正通过过**(本轮活栈复跑暴露):迁移里**没有任何 operator 种子**、 `DemoDataSeeder` 也不建运营账号,`conftest.admin_token` 却写死 `username="admin"` —— 那是某台开发机手工创建的遗留账号,本机有它所以本地一直绿,CI 全新库没有 → fixture 必然 401。 已改用 seed 创建的 `e2e_admin`(绑 super_admin),并新增 `tests/e2e/fixture_account_guard_test.py` 机械拦住"fixture 只准用 seed 账号"(含"解析失败即失败"断言,防守卫自身静默失效); 3. **`POST /activities/{id}/interests` 契约漂移**:`API_INVENTORY` 记载该端点、前端按此实现, 但后端**从未实现**(Phase 16 已把表达意向合并进 `/activities/{id}/feedback` 的 `interestTargetUserIds`) → 调用必然 404。已更正 `API_INVENTORY` 并按真实端点重列,删除前端死代码链 (`activityService.submitInterests` + `activityStore.submitInterests`,全仓确认无页面调用方), 各留注释说明删除原因与恢复条件。**若产品确认需要独立端点,应先定义语义并补后端实现。** 详见 `docs/幂等键检修报告-2026-09-18.md`。 ### Phase 24 — UAT增量 ✅ 已就绪(测试数据支持) | 任务 | 状态 | |------|------| | P24-T01 Service Station Operator UAT | ✅ 测试数据已就位(stationop账号) | | P24-T02 Counselor UAT | ✅ 测试数据已就位(counselor01账号) | | P24-T03 Counseling Manager UAT | ✅ 角色权限已配置 | | P24-T04 Content Editor UAT | ✅ 角色权限已配置 | | P24-T05 服务站扫码→预约→到场 | ✅ API链路完整 | | P24-T06 咨询申请→服务完成 | ✅ API链路完整 | | P24-T07 婚前辅导申请 | ✅ Miniapp页面U58/U59完整 | | P24-T08 活动双方互选→双方确认→Chat | ✅ API+Miniapp完整 | **备注**:UAT需要人工操作验证,后端API和数据模型已全部就绪。 > ⚠️ 本行原称「Phase 23(V1.1专项测试)— 已完成」,**已被 2026-09-18 复验推翻**:Phase 23 实为**部分关闭**(假覆盖已清除、E2E 入 CI 待基础设施决策),唯一有效结论见上方「Phase 23 — 可信系统测试重建(REFACTOR)」节。 ### Phase 25 — RC内容检查 ✅ 可执行 | 任务 | 状态 | |------|------| | P25-T01~T09 真实素材填充 | ⏳ 待运营提供内容 | | Banner真实素材 | ⏳ 等待运营 | | 服务站真实地址/开放时间 | ✅ 已初始化万善公园站 | | 咨询服务介绍 | ✅ API已就绪 | | 婚前辅导介绍 | ✅ API已就绪 | | 婚恋反诈首批内容 | ⏳ 待运营提供 | | 婚恋课堂首批内容 | ⏳ 待运营提供 | | 关于善缘丹阳 | ⏳ 待运营提供 | | 主办/执行信息 | ⏳ 待运营提供 | ### Phase 26 — Production初始化 ✅ 已完成 | 任务 | 状态 | |------|------| | P26-T01 Seed Content Categories | ✅ (V027) | | P26-T02 Seed Activity Types | ✅ (CHECK约束已定义) | | P26-T03 Seed Service Types | ✅ (CHECK约束已定义) | | P26-T04 创建万善公园服务站 | ✅ (V027) | | P26-T05 初始化Banner | ✅ (V027) | | P26-T06 初始化Feature Flags | ⚠️ **来源纠错 + 部分成立**(2026-09-18 二次修正):`features:` 块实际存在于 `application-dev.yml` / `application-docker.yml`(**不在**基础 `application.yml`)且实际生效(dev 的 `chat-image-enabled: true` 覆盖 Java 默认 `false`)—— 原「4 份 yml 无 features 块」为**误判**;但 10 个模块级 flag(T01–T05 及同类)全仓**零业务调用点**,运维**无法**经开关关闭对应模块(死配置) | | P26-T07 初始化新增Roles/Permissions | ✅ (V015已覆盖) | | P26-T08~T13 Smoke tests | ⏳ 上线前手动验证 | **V027 生产种子数据迁移**已创建,包含: - 4个内容分类(婚恋课堂/反诈/婚前辅导/婚俗新风) - 万善公园服务站基础数据 - 3条首页Banner **Phase 24(UAT增量)— 已就绪** ✅ --- ## 整体进度总结 | Phase范围 | 状态 | |-----------|------| | Phase 01~12 (V1.0基线) | ✅ 已完成 | | Phase 13~22 (V1.1核心增量) | ✅ 已完成 | | Phase 23 (V1.1专项测试) | ⚠️ 部分关闭(2026-09-18):假覆盖已清除 + 4 个真实守卫;E2E 入 CI 待决策 | | Phase 24~26 (UAT/RC/Production) | ⏳ 运营/上线阶段 | ### Phase 24~26 — 明细见上方(本段为重复摘要,已收敛) > Phase 24 / 25 / 26 的逐条任务表见上方「当前 Phase」中的同名小节; > 本段原为它们的简化重复版,已收敛以免同一事实出现两套口径。 ### Admin Web V1.1 模块扩展 ✅ 已完成 | 模块 | 文件 | 说明 | |------|------|------| | Banner管理 | BannerManagementView.vue | CRUD + 上架/下架 | | 内容管理 | ContentManagementView.vue | 分类+文章CRUD + 发布/下架 | | 善缘服务站 | ServiceStationView.vue | 站点信息编辑 | | 服务预约 | ServiceAppointmentView.vue | 确认/完成/取消 | | 专项项目 | ServiceProgramView.vue | CRUD + 成员审批 | | 婚恋咨询 | CounselingView.vue | 分配/排期/跟进/完成 | | 转介记录 | ReferralManagementView.vue | 转介历史查询 | | 路由扩展 | router/index.ts | 7个新菜单+路由 | --- ## V1.1 整体进度总结 | 类别 | 状态 | |------|------| | 数据库迁移 (V001~V027) | ✅ 27个文件 | | 后端 Java API | ✅ 100% 完成 | | Miniapp 页面 (U55~U61) | ✅ 7个新页面 | | E2E 测试 (12个文件) | ✅ 80+用例 | | Invariant 测试 (INV-011~020) | ✅ 10个用例 | | Feature Flag 配置 | ✅ 15个V1.1开关 | | Admin Web V1.1 模块 | ✅ 7个新页面 | | Admin Web 前端开发 | ⏳ 需完善样式和联调 | **V1.1 核心功能 100% 完成,可进入 UAT 验收和上线准备阶段** --- ## 已知限制 | 限制 | 说明 | |------|------| | 人脸核验 | Feature Flag 预留,Provider 未确认 | | 本地资格佐证触发规则 | 待运营确认 | | 微信公众号审核 | 需人工操作 | | SSL证书 | 需人工申请 | | 有效交友匹配报送口径 | 待运营确认 | --- *版本基线: 1.1.0-dev(2026-09-08)— V1.0 核心 100% 就绪,V1.1 增量开发中* --- ## V1.1 本地部署完成(2026-09-09,历史记录) > ⚠️ **历史记录边界**:本节为 2026-09-09 的部署时点记录,其中的测试声明(11/11、25/25、16/16) > **已在后续重新审查中被推翻**,不作为验收证据。当前有效状态见文首「当前有效结论」。 > 本区块在原文件中重复出现三次(内容高度雷同),2026-09-18 文档治理合并为一处。 ### 修复的关键问题 - **CounselingServiceApp 通知 FK 约束** — operator 用户不在 `users` 表,改为检查后再发送通知 - **HomeController 路径重复** — `@RequestMapping("/api/v1/home")` → `"/home"` - **LocalEligibilityController 路径重复** — 同上修复 - **数据库 `updated_at` 列缺失** — 为 18 个 V1.1 表补充 `ALTER COLUMN` - **前端** — `CounselingView` / `ContentManagementView` 截断、路由缺失、侧边栏菜单缺失 ### 为什么这些声明被推翻(保留为治理证据) - E2E 的「16/16」记录**不可复现**,测试文件存在大量空 `pass` —— 这是 Phase 23「可信系统测试重建」的直接起因。 - API 人工测试未证明 Permission、DataScope 和业务闭环,不能作为上线依据。 - 「25/25 PASS」「11/11 PASS」均为当时自报,未附可复现命令与失败处理。 ### 运营阶段遗留(至今不变) - Phase 24: UAT — 需真实用户参与并确认启动 - Phase 25: RC 内容检查 — 需运营团队填充真实内容 - Phase 26: Production Smoke Tests — 13 项手动验证