Files
WorkBuddy 438b38d121 V1.0.1 配置与规则纠偏:照片上限配置化+强校验 / 活体开关闭环 / 推荐阈值快照+规则版本化 / governance 三表+漂移审计
根治三类工程治理问题(技术默认值≠产品规则、配置存在但未闭环、文档代码漂移):
- PROFILE-001:profile.photo.maxCount(默认6未确认)+ ProfilePolicy + 服务器端 FOR UPDATE
  并发强校验(PHOTO_LIMIT_EXCEEDED,拒绝先于 S3 不留孤儿)+ 前端 mergeAppConfig 嵌套键修复
- CFG-001/IDENTITY-001:IdentityPolicy + GET /verification/liveness-status 真实判定点
  (默认关不阻断,开则 enhancedVerified 变化,消除假开关)+ 删死 seed livenessVerification.enabled
- MATCH-001:阈值60定为技术默认(消解 PENDING 矛盾)+ V050 recommendation_records.threshold_snapshot
  规则版本化 + 删死重复配置类 MatchConfig
- DOC-001:新增 docs/governance/(config-register/open-questions/decision-register/
  hardcoded-rule-audit/config-drift-audit)
- TEST-001:新增守卫 PhotoLimitGuardTest(8)/IdentityLivenessGuardTest(5)/
  RecommendationThresholdSnapshotGuardTest(4),均经负向注入可红

全量回归 733/0/0/3(基线717+17新增-1删死测试);UI 契约门禁 18/18;STATUS 升 rc.21
2026-09-21 02:05:15 +08:00

91 lines
3.5 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 业务数量参数(规范 §118 App 配置 + AGENTS.md 第 12 条"所有未确认数量参数配置化")
*
* 全部数量限制走配置,禁止页面层硬编码业务常量。
* 实际运行时由 services/appConfigService 从服务端拉取并覆盖默认值(规范 §118)。
* 配置接口失败时使用本文件的安全默认值(规范 §119)。
*/
exports.BUSINESS_LIMITS = {
// 推荐相关
DAILY_RECOMMENDATION_LIMIT: 6, // 每日推荐人数
RECOMMENDATION_PAGE_SIZE: 10, // 推荐分页大小
// 资料相关
MAX_PROFILE_PHOTOS: 6, // 生活照上限
MAX_INTEREST_TAGS: 8, // 兴趣标签上限(规范 §35 不超过 8 个)
MIN_INTRO_LENGTH: 20, // 自我介绍最小字数
MAX_INTRO_LENGTH: 500, // 自我介绍最大字数
MAX_REPORT_LENGTH: 500, // 举报说明最大字数
MAX_FEEDBACK_LENGTH: 500, // 意见反馈最大字数
// 聊天相关
CHAT_IMAGE_ENABLED: false, // V1 默认关闭图片聊天(规范 §76 Feature Flag)
CHAT_MESSAGE_MAX_LENGTH: 1000,
CHAT_HISTORY_PAGE_SIZE: 30, // 聊天历史分页
// 功能开关(规范 §76)
ACTIVITY_ENABLED: true,
MATCHMAKER_ENABLED: true,
ENABLE_RISK_KEYWORD_WARNING: true,
// 后台分页(规范 §82)
PAGE_SIZE_DEFAULT: 20,
PAGE_SIZE_OPTIONS: [20, 50],
// 时长(ms)
TOAST_DURATION: 1500, // 规范 §56:1.5~2 秒
BUTTON_PRESS_FEEDBACK: 120, // 按钮按压反馈时长
// 网络请求
REQUEST_TIMEOUT_MS: 15000,
REQUEST_RETRY_COUNT: 1,
// 联系方式
SUPPORT_CONTACT: '',
};
/**
* 服务端 /app/config 的嵌套结构 → 客户端 UPPER_SNAKE 常量的显式映射。
*
* <p>此前用平铺合并 {@code {...BUSINESS_LIMITS, ...overrides}},命不中嵌套 key
* (服务端返回的是 {@code businessLimits.maxProfilePhotos} / {@code features.x}),
* 导致服务端下发的照片上限 / 推荐阈值等配置<b>从不生效</b> —— 前后端规则漂移
* (V1.0.1 配置纠偏 PROFILE-001 前端侧根因)。现改为按节(section)+ 键显式映射,
* 且仅在「服务端给了该键 && 客户端确有该常量」时才覆盖,缺省回退本地默认值。
*/
const SERVER_SECTION_TO_CLIENT_KEY = {
businessLimits: {
dailyRecommendationLimit: 'DAILY_RECOMMENDATION_LIMIT',
maxProfilePhotos: 'MAX_PROFILE_PHOTOS',
maxInterestTags: 'MAX_INTEREST_TAGS',
selfIntroMaxLength: 'MAX_INTRO_LENGTH',
},
features: {
activityEnabled: 'ACTIVITY_ENABLED',
matchmakerEnabled: 'MATCHMAKER_ENABLED',
imageChatEnabled: 'CHAT_IMAGE_ENABLED',
},
};
/**
* 用服务端返回的配置覆盖默认值(规范 §118)
* @param {object} serverConfig 服务端 /app/config 的完整响应(含 businessLimits / features 等嵌套节)
* @returns {typeof exports.BUSINESS_LIMITS} 合并后的运行时配置
*/
exports.mergeAppConfig = (serverConfig) => {
const merged = { ...exports.BUSINESS_LIMITS };
if (!serverConfig || typeof serverConfig !== 'object') return merged;
for (const [section, keyMap] of Object.entries(SERVER_SECTION_TO_CLIENT_KEY)) {
const src = serverConfig[section];
if (!src || typeof src !== 'object') continue;
for (const [serverKey, clientKey] of Object.entries(keyMap)) {
if (Object.prototype.hasOwnProperty.call(src, serverKey)
&& Object.prototype.hasOwnProperty.call(merged, clientKey)) {
merged[clientKey] = src[serverKey];
}
}
}
return merged;
};