KEEP-VERIFY/EXTEND 复验(历史 ✅ 不可信;测试覆盖函数 ≠ 覆盖运行时路径)。
逐条核对运行时路径与生产约束后修复 7 处缺陷,其中 3 处「只在真实 PostgreSQL 上炸」。
D1 (Critical, 生产故障)
matchmaker_recommendations.status 代码写 liked/passed/confirmed_mutual,
而 V009 chk_rec_status 只允许 pending_view/viewed/responded 且从未扩展
→ 真实 PG 上用户接受/跳过推荐必崩。测试库未复刻该 CHECK,故长期静默。
D2 (Critical, 生产故障)
控制器缺省 serviceType="recommendation" 不在 chk_matchmaker_service_type
白名单 → 提交红娘服务必崩。
D1+D2 同修于新增 V038__align_matchmaker_status_constraints.sql
(沿用 V018/V020/V025 的 DROP CONSTRAINT IF EXISTS + 重加白名单惯例)。
D3 (High, 越权写)
MatchmakerServiceService.recommendPartner 无 assignedOperatorId 归属校验,
且可把用户推荐给自己 → 补校验 + 禁止自我推荐。
D4 (High, 越权读)
getServiceDetail 无归属校验且返回完整用户资料(userId/description/
userProfile/followups)→ 签名加 requesterId,按调用者返回完整/脱敏视图。
D5 (High, 越权写)
ReferralService 的 userId 取自请求体且零授权校验 → 新增
assertMatchmakerServesUser,在 referToServiceStation/referToActivity 入口
强制校验存在进行中的服务关系。
D6 (High, 生产故障)
MatchmakerFollowupMapper.findByServiceId 只有声明无 @Select
→ Invalid bound statement (not found),getServiceDetail 必崩。
该缺陷由本轮新增测试首次暴露(历史测试从未调用该路径)→ 补 @Select。
D7 (Medium, 契约缺口)
admin-web 5 处 API 缺口(4 条 404 + C 端端点被运营端误用)+ 小程序缺转介服务层
→ 后端补 GET /operator/matchmaker/recommendations 与
GET /referrals/operator/history 两个运营端端点;前端改路径、
assign 改 POST + body operatorId;新增 miniapp/services/referralService.js。
测试保真度
- 测试库补 matchmaker_services/recommendations/followups 三表(此前该模块零真实覆盖),
约束与 V038 对齐;EntityMigrationParityTest 三表移入 REQUIRED_IN_TEST_SCHEMA;
MigrationValidationTest LATEST_MIGRATION 37 → 38。
- 新增 MatchmakerReferralPhase13Test(17 用例,@SpringBootTest 走真实方法路径 + 真实落库)。
- 重写 MatchmakerServiceTest(6 用例):直接解析 db/migration/V*.sql,按文件名顺序应用
DROP CONSTRAINT IF EXISTS + ADD CONSTRAINT 取"最终有效"白名单,并内置解析器自检。
【关键】首版守卫硬编码白名单副本,注入 D1 后仍全绿(对漂移零反应)→ 必须解析真实 DDL。
- 删除 3 处假测试占位(MatchmakerServiceTest.testMatchmakerCannotLike 的 assertTrue(true);
CoreInvariantsTest INV-007 断言的是状态常量、INV-010 亦为 assertTrue(true)),
已如实改名并注明行为验证位置。
负向验证(两轮)
注入 D1(回退 chk_rec_status 白名单)→ 行为守卫 DataIntegrityViolation
+ 常量守卫 Multiple Failures (3 failures) → Tests run: 23, Failures: 1, Errors: 2
/ BUILD FAILURE,守卫有效性得证。缺陷已还原。
全量回归(离线容器,实测)
[WARNING] Tests run: 391, Failures: 0, Errors: 0, Skipped: 3
[INFO] BUILD SUCCESS / Total time: 04:59 min
Phase 12 基线 371 → 391(净 +20)。
报告:docs/Phase-13-V11-Recovery-Completion-Report-2026-09-16.md
Phase 13A 未自动进入,等待用户确认。
54 lines
1.7 KiB
JavaScript
54 lines
1.7 KiB
JavaScript
/**
|
||
* 红娘转介服务(Phase 13)
|
||
*
|
||
* 封装「用户确认转介」的两阶段流程与「我的转介历史」。
|
||
*
|
||
* 关键不变量(AGENTS.md):
|
||
* - 第 5 条:红娘不可替用户操作。转介由红娘发起(运营端),
|
||
* **必须由用户本人在小程序确认** 才算生效 —— 本层只提供用户侧的
|
||
* 确认与查询,不提供任何"代用户确认"的入口。
|
||
* - 转介形成可追踪记录(source=matchmaker_referral + createdByOperatorId + userConfirmedAt)。
|
||
*
|
||
* 后端端点:
|
||
* GET /api/v1/referrals/my-history — 我的转介历史(UserPrincipal)
|
||
* POST /api/v1/referrals/{id}/confirm — 用户确认转介
|
||
*/
|
||
const api = require('../utils/api');
|
||
|
||
/**
|
||
* 我的转介历史(含是否已确认)
|
||
* @returns {Promise<Array<{
|
||
* type: 'service_station'|'activity',
|
||
* id: string,
|
||
* status: string,
|
||
* createdByOperatorId: string,
|
||
* userConfirmedAt: string|null,
|
||
* createdAt: string
|
||
* }>>}
|
||
*/
|
||
function getMyReferralHistory() {
|
||
return api.get('/referrals/my-history');
|
||
}
|
||
|
||
/**
|
||
* 用户确认转介(两阶段流程的第二阶段)
|
||
*
|
||
* ⚠️ 只有转介的目标用户本人可以确认;他人调用后端会拒绝。
|
||
* @param {string} targetId 转介记录 ID(appointmentId 或 registrationId)
|
||
* @param {'service_station'|'activity'} targetType
|
||
* @returns {Promise<{ id: string, status: string, confirmedAt: string }>}
|
||
*/
|
||
function confirmReferral(targetId, targetType) {
|
||
return api.post(
|
||
`/referrals/${encodeURIComponent(targetId)}/confirm`,
|
||
{ targetType },
|
||
undefined,
|
||
`referral-confirm:${targetId}:${targetType}`
|
||
);
|
||
}
|
||
|
||
module.exports = {
|
||
getMyReferralHistory,
|
||
confirmReferral,
|
||
};
|