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 后端无取值字典。
77 lines
2.9 KiB
JavaScript
77 lines
2.9 KiB
JavaScript
/**
|
||
* 常量聚合入口(规范 §133 constants 目录)
|
||
*
|
||
* 统一存放 routeNames / statusEnums / permissionCodes / storageKeys / businessLimits,
|
||
* 不让状态字符串散落页面。
|
||
*/
|
||
|
||
const routeNames = require('./routeNames');
|
||
const statusEnums = require('./statusEnums');
|
||
const permissionCodes = require('./permissionCodes');
|
||
const storageKeys = require('./storageKeys');
|
||
const businessLimits = require('./businessLimits');
|
||
const profileLabels = require('./profileLabels');
|
||
|
||
module.exports = {
|
||
// 路由
|
||
ROUTE: routeNames,
|
||
TAB: routeNames.TAB,
|
||
AUTH: routeNames.AUTH,
|
||
ONBOARDING: routeNames.ONBOARDING,
|
||
ONBOARDING_STEPS: routeNames.ONBOARDING_STEPS,
|
||
REVIEW: routeNames.REVIEW,
|
||
MAIN: routeNames.MAIN,
|
||
SETTINGS: routeNames.SETTINGS,
|
||
DETAIL: routeNames.DETAIL,
|
||
OPERATOR: routeNames.OPERATOR,
|
||
buildPath: routeNames.buildPath,
|
||
to: routeNames.to,
|
||
|
||
// 状态枚举
|
||
PROFILE_COMPLETION: statusEnums.PROFILE_COMPLETION,
|
||
PROFILE_REVIEW: statusEnums.PROFILE_REVIEW,
|
||
ACCOUNT_STATUS: statusEnums.ACCOUNT_STATUS,
|
||
RELATIONSHIP_STATUS: statusEnums.RELATIONSHIP_STATUS,
|
||
RELATION_STATUS: statusEnums.RELATION_STATUS,
|
||
RECOMMENDATION_STATE: statusEnums.RECOMMENDATION_STATE,
|
||
ACTIVITY_STATUS: statusEnums.ACTIVITY_STATUS,
|
||
REGISTRATION_STATUS: statusEnums.REGISTRATION_STATUS,
|
||
CHECKIN_STATUS: statusEnums.CHECKIN_STATUS,
|
||
MATCHMAKER_SERVICE_STATUS: statusEnums.MATCHMAKER_SERVICE_STATUS,
|
||
MATCHMAKER_RECOMMENDATION_STATUS: statusEnums.MATCHMAKER_RECOMMENDATION_STATUS,
|
||
CHAT_CONNECTION: statusEnums.CHAT_CONNECTION,
|
||
MESSAGE_SEND_STATUS: statusEnums.MESSAGE_SEND_STATUS,
|
||
PHOTO_STATUS: statusEnums.PHOTO_STATUS,
|
||
CHAT_BUBBLE_TYPE: statusEnums.CHAT_BUBBLE_TYPE,
|
||
REQUEST_ERROR: statusEnums.REQUEST_ERROR,
|
||
BUSINESS_ERROR_CODE: statusEnums.BUSINESS_ERROR_CODE,
|
||
STATUS_BADGE: statusEnums.STATUS_BADGE,
|
||
DANGER_ACTION: statusEnums.DANGER_ACTION,
|
||
mapErrorMessage: statusEnums.mapErrorMessage,
|
||
|
||
// 权限
|
||
USER_PERMISSION: permissionCodes.USER_PERMISSION,
|
||
ADMIN_PERMISSION: permissionCodes.ADMIN_PERMISSION,
|
||
hasPermission: permissionCodes.hasPermission,
|
||
hasAnyPermission: permissionCodes.hasAnyPermission,
|
||
|
||
// 存储
|
||
STORAGE_KEYS: storageKeys.STORAGE_KEYS,
|
||
|
||
// 业务限制
|
||
BUSINESS_LIMITS: businessLimits.BUSINESS_LIMITS,
|
||
mergeAppConfig: businessLimits.mergeAppConfig,
|
||
|
||
// 资料/择偶枚举码 → 中文简体字典(界面不得出现英文枚举码)
|
||
PROFILE_LABELS: profileLabels,
|
||
profileLabelOf: profileLabels.labelOf,
|
||
yesNoLabel: profileLabels.yesNoLabel,
|
||
futureDanyangLabel: profileLabels.futureDanyangLabel,
|
||
MATCHMAKER_SERVICE_STATUS_LABEL: profileLabels.MATCHMAKER_SERVICE_STATUS_LABEL,
|
||
ACCEPT_CHILDREN_OPTIONS: profileLabels.ACCEPT_CHILDREN_OPTIONS,
|
||
MARITAL_OPTIONS: profileLabels.MARITAL_OPTIONS,
|
||
EDUCATION_OPTIONS: profileLabels.EDUCATION_OPTIONS,
|
||
OCCUPATION_OPTIONS: profileLabels.OCCUPATION_OPTIONS,
|
||
regionCodeOf: profileLabels.regionCodeOf,
|
||
};
|