UAT 走查(docs/UAT-WALKTHROUGH-2026-09-23.md)发现 4 项硬阻塞,本次闭环其中 3 项 (#2 微信登录、#5 照片直传不在本轮范围),并顺带修掉走查中新发现的跨端字段契约缺陷。 后端 - #6 推荐恒空:新增 MatchScoringService 作为唯一评分事实源(复用 UserPreference 既有 10 维权重,零新造常量);RecommendationEngineService.calculateScore/generateReasons 由 桩(return 50.0)改为委托;MatchEligibilityService 3 处桩全部去雷。此前 50 < 阈值 60 → GET /recommendations 恒返回空数组。 - #4 保存即失败:updateProfile / updateBasicProfile / savePreference 改为 「无则插入、有则更新」。注意 UserPreference 实体 @TableId=id 与库主键 user_id 不一致 (V037 后补的可空列),故按 user_id 定位更新而非 updateById(后者会静默不更新)。 gender / birth_date 为 NOT NULL 且向导不采集,缺失时从已通过实名认证的 user_identities 补齐,仍缺则抛 400 业务拒绝,不再让 DataIntegrityViolationException 渲染成 500。 GET /me/profile 的 preferences 补回 5 个此前未返回字段(regionPriority / maritalPriority / minEducationCode / educationPriority / childrenPriority)。 - #8 越权端点:POST /activities/{id}/interests/confirm 不再直调「建 Match 原语」 RelationshipService.confirmActivityInterest,改为与 /activities/{id}/mutual/* 同一条 二阶段同意链路(createMutualConsent + confirmConnection),单方调用不再可能建 Match (INV-014 / INV-015)。 - #10 文档不一致:MatchmakerController 类注释更正(operator 端点实际在 /operator/matchmaker)。 - 存量 500 家族:RuntimeExceptionThrowGuardTest 的正则只认 throw new RuntimeException(, 而 17 处裸抛写作 orElseThrow(() -> new RuntimeException(...)),整体绕过守卫(CI 全绿却 仍有 500 家族缺陷)→ 17 处全量改为 GlobalExceptionHandler.BusinessException; 守卫扩为「整段代码 + 该形态」,并加自检断言防止守卫退化成恒真空断言。 小程序(跨端字段名 / 取值契约) - 字段名对齐后端规范名:hasChildren→childrenStatus、occupationCategory→occupationCode、 workRegion→workRegionCode、ageMin/ageImportance→minAge/agePriority、 educationAccepted/maritalStatusAccepted→minEducationCode/maritalStatuses。 此前字段名对不上,后端读不到 → 字段被静默丢弃。 - 取值修 4 类违反 DB CHECK(写入直接 500)的项:has→yes;high_school→senior_high、 phd→doctor(chk_profile_edu);occasional→sometimes(chk_profile_smoking/drinking)。 - 预填改读服务端真实字段:此前读 profile.hasChildren / occupationCategory / workRegion, 而服务端返回的是 childrenStatus / occupationCode / workRegionCode → 表单永远回填不上。 - profile-confirm 完成度改为直接采用服务端 profileCompletion(AGENTS 第 9 条:DB 是 Source of Truth),废弃原先 22 条「读服务端不存在字段」的本地猜测式断言。 - 择偶条件页新增「展示形态 ↔ 服务端规范形态」适配器(toApiPayload / fromApiPayload)。 测试与门禁 - 新增 MatchScoringServiceTest、RecommendationEngineServiceBehaviorTest、 ProfileSaveUpsertBehaviorTest、ActivityInterestConfirmConsentBehaviorTest 与 ui-tests/miniapp-profile-contracts.mjs(桩 stores,真跑三个页面的事件处理与 onNext, 断言提交负载用规范字段名与枚举码)。 - MIN_GUARDS 21→23(并修正上一轮漏改:该值当时仍为 21,与守卫数不符,使「数量下限」 保护形同虚设)。 - 负向注入实测:把 #6 评分改回桩 50.0、#4 改回恒 insert、#8 改回绕开二阶段、并注入 orElseThrow 形态裸异常 → 4 个守卫全部变红(含精确定位到 RecommendationEngineService.java:282)。 - 后端:795 tests / 0 failures / 3 skipped;UI 守卫 23/23;语种审计 0 命中;tsc 通过; wcc/wcsc 真编译 88 WXSS + 86 WXML / 0 失败。 仍未修(需产品/数据决策,见报告 8.3) - regionScope 需 GB/T 2260 单值区划码,而小程序选项含「镇江其他辖区」这类非单值项 → 不臆造区划码(该约束默认 preferred 软约束,不误过滤); - occupationPreference 后端无对应列;settlementPreference 后端无取值字典。
80 lines
7.1 KiB
Markdown
80 lines
7.1 KiB
Markdown
# Phase 26 — 上线前 13 项手动验证清单
|
||
|
||
> 用途:V1.1 进入 **UAT / 生产上线** 前,由 **运营 / 产品 / 运维** 人工逐项确认的清单。
|
||
> 本清单只覆盖「上线前必须肉眼或真机确认」的项;自动化回归已由 CI 覆盖
|
||
> (后端 `mvn verify` 757 绿 / E2E 65 passed / UI 契约 22/22 / 真编译 WXSS 88+WXML 86)。
|
||
>
|
||
> 判据纪律(沿用项目一贯要求):**断言 ≠ 证据**。`✅ 已完成` 类文档声明一律以
|
||
> 「当前代码 + 测试 + 人工验收」为准。本清单每项都给出 **可执行的验证方式**,
|
||
> 不靠口头确认。
|
||
>
|
||
> 关联决策:`docs/PENDING_DECISIONS.md`(13 项产品待确认)、`docs/governance/open-questions.md`。
|
||
> 冒烟脚本:`infrastructure/scripts/smoke-test.sh`(自动化子集)。
|
||
|
||
> ⛔ **2026-09-23 走查结论:本清单第 2/4/5/6 项为硬阻塞,当前不具备上线条件。**
|
||
> 详见 `docs/UAT-WALKTHROUGH-2026-09-23.md`(含源码证据 + 本地栈运行时实测 + 容器异常栈)。
|
||
> 摘要:微信登录无真实 `code2session`(仅 Mock);资料/择偶条件**保存即失败**(409/500);
|
||
> 照片直传后**不落库**、不可见;推荐列表**恒空**(评分函数为桩,恒 50 < 阈值 60)。
|
||
> 以上均逃过 757 后端测试 + 65 E2E + 22 UI 守卫(测试盲区)。**修复并复测前不得按本清单放行。**
|
||
|
||
---
|
||
|
||
## 验证总表
|
||
|
||
| # | 验证项 | 验证方式 | 通过标准 | 负责方 | 关联决策 / 配置 |
|
||
|---|--------|----------|----------|--------|------------------|
|
||
| 1 | 部署栈存活 | `bash infrastructure/scripts/smoke-test.sh` | live/ready/version 全 200;postgres/redis/seaweedfs 就绪 | 运维 | — |
|
||
| 2 | 微信小程序登录链路 | 真机「善缘丹阳」小程序微信授权登录 | 返回 `accessToken`+`refreshToken`,进入首页;token 过期触发重新登录 | 产品+运营 | 微信 appid/secret 生产配置;`WECHAT_APP_SECRET` 已填 |
|
||
| 3 | 运营端登录与越权隔离 | 管理后台 `/admin/` 用 seed 账号登录;尝试越权访问用户端资源 | 登录成功;运营 token 不能进入用户端(`hasRole("USER")` 兜底) | 运营 | 运营账号仅 seed 创建(迁移无 operator 种子) |
|
||
| 4 | 用户资料与择偶条件读写 | 小程序「我的 → 编辑资料 / 择偶条件」保存并回读 | 保存 2xx 且落库正确;下拉选项**全中文简体**(本次中文化成果) | 产品 | 见第 9 项 |
|
||
| 5 | 照片上传(SeaweedFS 直传) | 小程序上传头像/相册,上传后打开查看 | presigned PUT 直传成功、GET 下载字节一致;`MINIO_PUBLIC_ENDPOINT` 对外可达 | 运维 | prod `MINIO_PUBLIC_ENDPOINT`(ingress 域名) |
|
||
| 6 | 推荐 / 匹配核心链路 | 首页推荐 → Like / Pass → 互选双确认 → 开聊 | 推荐列表中文标签正确;Match/会话建立;Block 优先 | 产品 | 推荐阈值 `matching.recommendation.minScore`(技术默认 60,OQ-MATCH-001);照片上限 `profile.photo.maxCount`(技术默认 6,OQ-PROFILE-001) |
|
||
| 7 | 即时聊天(WebSocket) | 互选成功后双方发文本消息 | 握手鉴权、消息实时下行、历史可拉取;图片经安全检测 | 产品 | — |
|
||
| 8 | 活动全链路 | 浏览多类型活动 → 报名 → 运营审核 → 签到码核销 | 报名/审核/签到全通;互选活动双确认建 Match+会话 | 运营 | 服务站开放时间(待确认);活动意向端点语义(见 OQ) |
|
||
| 9 | 婚恋咨询 / 婚前辅导 | 申请 → 分配 → 排期 → 跟进 → 完成(四态) | 状态机合法迁移;counselor 仅见指派数据;manager 见摘要不见正文 | 运营 | 咨询资质要求、预约时段规则(待确认) |
|
||
| 10 | 公益红娘转介 | 红娘建立服务关系 → 推荐 / 转介 | 归属校验生效;不能替非本人负责用户操作、不能自荐 | 运营 | — |
|
||
| 11 | 内容 / 反诈 / 课堂 / 服务站 | 运营端 Banner+文章 CRUD、服务站公告;用户端展示 | 内容发布/下架正确;Banner 不外链;服务站公告可见 | 运营 | Banner 最大活跃数量(OQ-BANNER-001,代码暂无限制,需定值) |
|
||
| 12 | 管理端驾驶舱口径真实 | 管理后台数据统计页 | 漏斗/安全卡显示**真实值**(非硬编码 0);与汇总表同源 | 产品 | 有效交友匹配报送口径(待确认) |
|
||
| 13 | 合规与备份 | ① 未认证 401 / 越权 403 / 非法枚举 400;② 敏感访问有审计;③ 注销后数据保留 ≥36 个月;④ 数据库备份可恢复演练 | 4 项均达成;保留期配置 `account.data-retention-months=36` | 运维+产品 | 数据保留期(2026-09-19 产品确认下限 36 个月);本地资格佐证保留期限(待确认) |
|
||
|
||
---
|
||
|
||
## 执行说明
|
||
|
||
### 1. 部署栈存活(自动化)
|
||
```bash
|
||
export BASE_URL="https://你的生产域名"
|
||
bash infrastructure/scripts/smoke-test.sh
|
||
```
|
||
脚本断言 `live / ready / version` 与关键匿名接口应 401;任一 FAIL 即退出 1。
|
||
带 token 的子集(推荐/匹配/聊天等需登录链路)在提供 `OPERATOR_TOKEN` 后展开,
|
||
未提供时明确打印「需人工真机验证」,**不做假绿**。
|
||
|
||
### 2~13. 人工链路(真机 / 管理端)
|
||
- **小程序**:用真机微信账号走「善缘丹阳」小程序,逐项核对页面文案**全中文简体**
|
||
(重点:我的页 → 择偶条件 → 子女下拉;详情页学历/职业/婚姻/子女状态标签)。
|
||
- **管理端**:浏览器开 `/admin/`,用 seed 运营账号逐模块走查;数据统计页核对数字真实性。
|
||
- **合规**:抽查 `/api/v1/operator/audit-logs`(或对应审计接口)确认敏感访问被记录;
|
||
数据库做一次备份恢复演练。
|
||
|
||
### 上线前配置核对(必填,部署时)
|
||
| 配置项 | 位置 | 说明 |
|
||
|--------|------|------|
|
||
| `WECHAT_APP_SECRET` | 后端环境变量 / secret | 生产微信 secret,不得留空 |
|
||
| `MINIO_PUBLIC_ENDPOINT` | `infrastructure/docker-compose.prod.yml` | 对外可达的 SeaweedFS 网关域名(presigned URL host),缺省 `http://seaweedfs:8333` 仅容器内通 |
|
||
| `JWT_ACCESS_SECRET` / `JWT_REFRESH_SECRET` | 后端环境变量 | 生产必须用强随机值,且与微信登录验签密钥分离(2026-09-22 已修复 refresh 用错密钥) |
|
||
| `ENCRYPTION_KEY` | 后端环境变量 | 身份证等敏感字段加解密密钥 |
|
||
| HTTPS 证书 | ingress / 反向代理 | 证书到期须纳入监控(部署文档第七十五章) |
|
||
| 限流(若启用) | 后端配置 | `RATE_LIMITED`/429 已就位,是否启用及阈值待产品确认 |
|
||
|
||
---
|
||
|
||
## 不计入本清单(需产品拍板,非技术阻塞)
|
||
- 人脸核验 Provider 选型(`identity.liveness.provider` 默认 `none`,Feature Flag 控制)
|
||
- 本地资格佐证触发策略 / 文件保留期限(需合规审核)
|
||
- 匹配报送口径、Banner 活跃上限、咨询资质/预约时段、服务站开放时间
|
||
- 第三方开放(API Key / OAuth / 限流配额 / OpenAPI 发布)—— 范围扩张,待决策
|
||
|
||
> 以上在 `docs/PENDING_DECISIONS.md` 逐项跟踪;未确认不影响「核心功能可上线」,
|
||
> 但相关默认值(阈值 60、照片 6 张等)应以产品正式确认值替换并落 `decision-register.md`。
|