Files
danyang-match/docs/governance/open-questions.md
T
WorkBuddy 3caf5f8816 feat(matchmaker,referral): ZC-MM-005 统一数据范围与字段隐私(DEC-MATCHMAKER-005/§5.2 落地)
依据《善缘丹阳 V1.1 红娘角色权限正式决策与开发规则》DEC-MATCHMAKER-005 最小必要原则
与 §5.2 字段级隐私,ZC-MM-005 范围=「读接口行级数据范围统一接入判定器 + 字段白名单 +
组长团队脱敏统计」。承接 ZC-MM-002 落地的 matchmaker_assignments 事实源与
ServiceAssignmentPolicy 判定器。

E1 双轨切纯判定器(不留回退):
- assertServiceAccess 纯化(删 assigned_operator_id 回退分支),判定器成唯一事实源
- getServiceDetail 删 viewerIsOwner 双态与「非负责人脱敏详情」整段

E2 非负责人防探测 404:
- ServiceAssignmentPolicy.assertActiveAssignmentOrNotFound:无生效分配→先落
  DATA_SCOPE_DENIED 审计再抛 NOT_FOUND(响应 404),存在性不可枚举,
  与「查无此单」响应体逐字段一致(MM-PRIVACY-001)

E3 字段白名单显式化 + 用户隐私开关:
- 抽取 assembleMatchmakerUserProfile:仅 7 键(displayName/gender/age 派生/regionName/
  educationCode/occupationCode/maritalStatus),无 birthDate 原值/详细地址/手机号/微信/
  身份证;接 UserPrivacySettings.showOccupation(缺省全放行)

E4 死端点清理:
- 删除 GET /operator/matchmaker/my-services(operatorId 误当 user_id、恒空、前后端零调用),
  替代路径 /operator/matchmaker/assignments/my;C 端 /matchmaker/services 与
  counseling myServices 保留

P1 残留收口(读/写路径仍信任废弃 assigned_operator_id 残留列,与 E1 同类洞):
- P1-1 运营端推荐列表:MatchmakerRecommendationMapper.findByOperatorId 改 join
  生效分配(active+expires),撤/结后不再可见
- P1-2 dashboard 三计数:count*ByOperator 改 join 生效分配 + COUNT(DISTINCT) 防重,
  end/revoke 后不再计入(DEC-002 规则7)
- P1-3 转介授权:ReferralService.assertMatchmakerServesUser 切
  serviceAssignmentPolicy.assertActiveAssignment(DATA_SCOPE_DENIED 审计 + 403),
  删残留列查询 findActiveByOperatorAndUser

新端点(组长团队脱敏统计):
- GET /operator/matchmaker/team/statistics(@PreAuthorize matchmaker.team.assign):
  本组织 active 分配数/按红娘分组/在岗红娘数,纯计数无用户 PII;org 边界
  IS NOT DISTINCT FROM(NULL=NULL 平台直属)

P2-4 operatorName 脱敏决策:保留不脱敏(§5.2 字段分类:红娘姓名=团队范围内
工作人员标识非用户 PII;组长统计本团队工作量属管理职责),依据登记
docs/governance/open-questions.md OQ-MATCHMAKER-002(RESOLVED)

死代码清理:getOperatorServices(零调用)+ MatchmakerServiceMapper.findByOperatorId
(残留列查询,调用清零)删除;C 端 MatchmakerService 遗留信任残留列按豁免未动(006/007 退役)

测试:
- MatchmakerDataScope005Test(13 用例):MM-PRIVACY-001/002、MM-AUTH-001/003 读侧、
  MM-LIFECYCLE-001 读侧、P1-1/2/3 残留收口负向(撤/结后推荐不可见/计数归零/转介 403)、
  防探测逐字段一致、showOccupation 三态
- MatchmakerFieldPrivacyGuardTest(3 用例):字段白名单源码扫描 + 无导出端点锁定
- MatchmakerReferralPhase13Test 转介口径收紧(IllegalStateException→AccessDeniedException)
- 负向注入自证(P1-3 残留列变异→判红→恢复复绿)

验证:定向 73/73;全量 851/851(3 预存 skip);UI 契约 24/24。
2026-10-10 11:51:15 +08:00

91 lines
5.6 KiB
Markdown
Raw 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.
# 开放问题 — open-questions.md
> **版本**:V1.0.1 配置与规则纠偏基线 · **生效**:2026-09-20 · **owner**:产品负责人
> 未决项在此登记;**产品正式确认后**移入 `decision-register.md`,并同步更新
> `config-register.md` 的「产品正式确认」列与 `PENDING_DECISIONS.md`。
> 状态:`TBD`(待产品裁决)/ `IN_PROGRESS` / `RESOLVED`。
---
## OQ-IDENTITY-001 · 是否在正式运营阶段启用人脸/活体核验?
- **状态**:TBD
- **当前技术默认**:canonical 键 `identity.liveness.enabled`(V051 起为 `feature_flag_overrides` 唯一正式键;实现字段 `livenessEnabled`)= `false`,provider = `none`
- **说明**:活体**不是 V1.1 首发强制规则**。默认关闭时不得阻断实名主流程、不得误提示「必须人脸」。
开关已接真实业务判定点(`GET /verification/liveness-status` → `enhancedVerified`),消除「假开关」。
是否启用、选用哪家合规第三方 Provider(选型未定)由产品/合规裁决。
- **关联**:`IdentityPolicy`、`UserIdentity.livenessVerificationStatus`、V016、V051。
## OQ-PROFILE-001 · 用户最多可上传多少张个人照片?
- **状态**:TBD
- **当前技术默认**:`profile.photo.maxCount = 6`(头像 + 生活照合计)
- **说明**:6 仅作为技术默认值,**必须保持配置化**(已配置化 + 服务器端强校验 + 并发安全)。
不得写死;产品确认正式值后改配置即可,无需改代码。
- **关联**:`ProfileProperties` / `ProfilePolicy` / `PhotoService.ensureWithinPhotoLimit`。
## OQ-MATCH-001 · 推荐最低评分阈值最终采用多少?
- **状态**:TBD
- **当前技术默认**:`matching.recommendation.minScore = 60`(`match.default-score-threshold`)
- **说明**:60 **不代表产品正式确认**。阈值已配置化;推荐记录自 V050 起携带
`threshold_snapshot` + `rule_version`,未来 60→65 可追溯历史推荐依据。
前端不得把 score/threshold 包装为「匹配成功率 / 合适概率」等对外承诺。
- **关联**:`MatchRuleConfigProperties` / `MatchingPolicy` / V050。
## OQ-LOCAL-ELIG-001 · 本地资格佐证文件保留期限?
- **状态**:TBD(需合规审核)
- **当前技术默认**:`features.localEvidenceRetentionDays = 365`(可配置,非永久)
- **说明**:与「注销后 36 个月数据保留」(LOCKED)是**两套独立机制**。
配套清理作业尚未实现(已挂 Phase 22 运维任务,Phase-04 报告 :46 登记)。
## OQ-SERVICE-LOC-001 · 善缘服务站正式开放时间?
- **状态**:TBD
- **当前实现**:`service_locations.opening_hours_text` 自由文本(数据驱动、非硬编码),
种子值「周一至周五 9:00-17:00 / 周六 9:00-12:00」。属产品文案决策,挂起不动代码。
## OQ-COUNSEL-001 · 咨询人员实际资质要求 / 预约时段规则?
- **状态**:TBD
- **当前实现**:代码中**无资质字段/校验**(现状即「无资质要求」安全默认);预约时段为自由输入
+ 运营手工确认(无自动时段校验,不违反 AGENTS #12)。未来需资质/自动时段才需产品出规则并配置化。
## OQ-BANNER-001 · Banner 最大活跃数量?
- **状态**:TBD(**真缺口**)
- **当前实现**:代码**无**该限制,仅 demo seed 里一个从未被读取的死值 `banner.maxActiveCount='5'`
(`system_configs` 为死表,0 个 Java 读取点)。需产品定值后**实现** active-count 校验。
## OQ-ANALYTICS-001 · 有效交友匹配正式报送口径?
- **状态**:TBD
- **当前实现**:`match.effective` 为 `PROVISIONAL` 保守近似(`min(有真人消息会话, Match 总数)`),
文档已标「禁止对外」。建议口径(Mutual Match + Two-Way Chat)未实现;升 `OFFICIAL` 前需产品裁决。
## OQ-MATCHMAKER-002 · 组长团队统计 perMatchmakerCounts 的 operatorName 是否脱敏?
- **状态**:RESOLVED(ZC-MM-005 收口 P2-4,team-lead 裁定 2026-10-10)
- **裁定**:红娘姓名(operatorName)**保留、不脱敏**。依据:
1. 对照《决策》§5.2 字段分类:红娘姓名属「本人/团队范围内的工作人员标识」,**非用户 PII**
(§5.2 禁放的是 phone/mobile/wechat/idNumber 等用户敏感数据);
2. 功能权限矩阵「查看脱敏服务统计:组长=团队范围」+ DEC-MATCHMAKER-002 红娘组长职责
(团队内进度与工作量管理)—— 组长统计本团队工作量属管理职责;
3. 组长已可经 `GET /assignable-matchmakers` 拿到同批红娘姓名,此字段**非新增泄露面**
(管理范围 ≠ 用户敏感数据)。
- **代码落点**:`MatchmakerAssignmentService#teamStatistics` 方法注释已写明该决策依据;
本登记防止后人误判「统计含姓名=越权」。产品如日后要求组长统计姓名脱敏(如仅显示昵称/工号),
需回到本项重新裁决并同步改 `countActiveGroupByOperator` 查询与前端渲染。
## OQ-THIRD-PARTY-* · 第三方开放 / 平台化遗留(7 项)
- **状态**:TBD(范围扩张,需产品决策,本轮未擅自实施)
- 详见 `PENDING_DECISIONS.md`「第三方开放 / 平台化遗留待决策项」:第三方凭据机制、限流是否真实生效、
OpenAPI 对外发布面、`POST /activities/{id}/interests` 语义、第三方调用审计与配额计量、
敏感字段脱敏边界(第三方场景)、幂等键 TTL 是否按调用方分级。
---
*最后更新: 2026-09-20 — 登记 OQ-IDENTITY/PROFILE/MATCH-001 及本地资格保留期、服务站时间、咨询资质、Banner 数量、报送口径、第三方开放遗留。*