Files
danyang-match/docs/audits/matchmaker-permission-gap-audit.md
T
WorkBuddy 2d60f7899f docs(audit): ZC-MM-001 红娘角色权限差距审计报告
- 基准:《善缘丹阳 V1.1 红娘角色权限正式决策与开发规则》(DEC-MATCHMAKER-001~006
  全部 LOCKED,A1/B1 已确认)
- 审计范围:backend matchmaker/referral/audit/security/auth、Flyway V001~V052、
  admin-web 红娘页面、现有测试、治理文档;全部结论带文件:行号证据
- 核心结论:A1 分配关系未建模(分配=工单指派)、claim/followup/complete 无归属校验、
  /pending 全局队列对全体红娘可见、无红娘组长角色、模块内越权拒绝不落审计
- P0×5 / P1×6 / P2×6 差距清单 + 可复用模块(CounselingService INV-012 范式、
  DataScopeGuard、recordSensitiveAccess)+ ZC-MM-002~007 实施顺序建议
- 首次建立 docs/audits/ 目录
2026-10-09 22:46:32 +08:00

31 KiB
Raw Blame History

红娘角色权限差距审计(ZC-MM-001)

审计基准:《善缘丹阳 V1.1 红娘角色权限正式决策与开发规则》V1.1(DEC-MATCHMAKER-001006 全部 LOCKED,A1/B1 已确认) 审计日期:2026-10-09 审计执行:架构师(高见远)· software-danyang-mm 团队 · 只读走查,未修改任何业务代码 审计方式:backend matchmaker/referral/audit/security/auth 模块、Flyway V001V052、admin-web 红娘相关页面、现有测试与治理文档。所有结论均给出文件路径+行号或 SQL/代码证据。


0. 审计范围与方法

  • 后端:backend/src/main/java/com/danyang/match/platform/ 下 matchmaker/(controller 2、service 2、entity 3、mapper 3)、referral/(controller 1、service 1)、audit/、shared/security/、auth/、counseling/(对照 INV-012)、review/(对照敏感访问日志范式)。
  • 数据库:backend/src/main/resources/db/migration/ V001~V052 全量中 matchmaker 相关 8 个迁移(V001/V002/V009/V019/V021/V037/V038/V044/V052)。
  • 前端:admin-web/src/modules/matchmaker/MatchmakerManagementView.vue、modules/referral/ReferralManagementView.vue、router/index.ts、layouts/MainLayout.vue。
  • 测试:backend/src/test 中 matchmaker/referral/权限相关 6 个测试类。
  • 治理文档:docs/governance/decision-register.md、open-questions.md、docs/PENDING_DECISIONS.md。
  • 全局检索:matchmaker_assignments、ServiceAssignment、matchmaker_leader、ContactAuthorization 等关键词。

状态标注:【已实现】/【部分实现】/【缺失】/【无法确定】。


1. 现状总览

一句话结论:当前仓库的"红娘"只是一个挂在 matchmaker_services 服务单上的 assigned_operator_id 工单负责人概念——没有独立的服务对象分配关系、没有红娘组长角色、没有统一的数据范围/字段级隐私策略层;工单维度上已做过多轮越权修补(推荐/转介/详情归属校验),但认领、跟进、完结等写接口仍缺归属校验,未分配队列与全局统计对全体红娘可见,审计与权限回收存在系统性缺口。A1 核心未建模,B1 现状上"侥幸安全"(接口本就不返回联系方式)而非"设计安全"。

决策要求 vs 现状对照表

# 决策要求 现状 状态 关键证据
1 DEC-002/A1:服务对象由平台授权人员或红娘组长分配,普通红娘仅访问本人有效分配对象 分配仅体现在 matchmaker_services.assigned_operator_id(服务单指派),无独立分配实体、无 assigned_by/理由/有效期/结束语义;/pending 全局队列对任何 matchmaker.view 持有者可见 缺失(核心) V009 L5-20;MatchmakerOperatorController L32-36;MatchmakerServiceMapper.findSubmitted()
2 DEC-002 规则2:禁止普通红娘认领未分配/他人对象 POST /operator/matchmaker/services/{id}/claim 任何 matchmaker.service 持有者可对任何 assigned 服务接单,无归属校验 缺失 MatchmakerOperatorController L49-56;MatchmakerServiceService.claimService L109-122
3 DEC-002 规则3/6:分配、转分配、撤销、结束留痕;状态机覆盖 仅有 assign/complete/cancel(cancel 无 HTTP 入口,死代码);无转分配、无撤销、无结束原因;分配人(assigned_by)不记录 缺失 MatchmakerServiceService L87-104、L229-237;V009 L11-14
4 DEC-003/B1:默认平台内联系,不暴露完整手机号/微信号/详细地址 红娘侧 DTO/VO 与前端页面均无 phone/wechat/address/idNumber 字段;但也不存在任何联系授权机制(无表、无策略类) 部分实现(结果安全、机制缺失) MatchmakerServiceService.getServiceDetail L329-348;ReferralService 全文;全局检索 ContactAuthorization 无结果
5 DEC-004:红娘不得代替用户 Like/Pass/确认开启聊天/接受活动意向 设计与实现均贯彻"推荐≠Like":推荐仅建 pending_view 记录,Like/Pass 由用户本人端点(UserPrincipal+findByIdAndUser 归属校验)触发;转介确认须用户本人 已实现 MatchmakerService L97-142、L213-258;ReferralService.confirmReferral L139-184;测试 MatchmakerReferralPhase13Test L132-296
6 DEC-005:最小必要 + 数据范围 + 字段隐私 + 有效分配 无 Policy 层;数据范围校验散落且口径不一:recommend/转介有归属校验,claim/followup/complete 无;matchmaker.assign 与 matchmaker.service 语义即"工单指派/工单执行",不是"分配服务对象" 缺失 MatchmakerServiceService L142-151(有)vs L109-122、L186-203、L208-224(无)
7 DEC-006:全程留痕(分配、敏感查看、越权拒绝等) 有 audit 基础设施且授权拒绝有全局监听;但 claim 不审计、敏感详情查看不记 SensitiveAccessLog、模块内归属拒绝不走 DataScopeGuard、分配审计不记 assigned_by/理由 部分实现 AuthorizationAuditListener L25-49;DataScopeGuard 使用方仅 activity/counseling/service_appointment;MatchmakerServiceService.saveAuditLog L395-403(before/after 恒 null)
8 功能权限矩阵:红娘无全站检索/导出/敏感字段 matchmaker 角色仅授 3 权限(view/service/assign),无 user.view、无 data.export;全仓未发现导出端点 已实现(现状合规) V052 L24-28;grep data.export 使用方为 0
9 红娘组长角色 全仓(迁移+代码+前端)无 matchmaker_leader/team_lead 缺失 grep 无结果
10 测试基线 MM-AUTH/CONTACT/ACTION/PRIVACY/AUDIT 仅有"红娘不代替用户操作"(MM-ACTION 方向)与状态白名单守卫测试;无数据范围/联系方式/审计/生命周期场景测试 缺失 MatchmakerReferralPhase13Test、MatchmakerServiceTest(仅常量白名单校验)

2. 分项审计

2.1 当前红娘角色及权限实现

角色与权限定义【部分实现】:

  • matchmaker 角色定义于 V001:('00000000-0000-0000-0000-000000000005', 'matchmaker', '公益红娘', '提供人工婚恋服务', TRUE)(V001 L145)。
  • 三条红娘权限定义于 V001 L161-163:matchmaker.view(020)、matchmaker.assign(021)、matchmaker.service(022)。
  • 角色-权限授权缺口曾真实存在:V052 迁移注释自证——"创建红娘运营账号后发现该角色在 role_permissions 中零条授权,登录后台 403"(V052 L4-12);V052 仅补授 3 条权限(L24-28)。
  • 其余角色授权同样残缺:V044 注释承认"permissions 共 48 条,role_permissions 里 super_admin 只有 18 条;matchmaker 角色为 0 条"(V044 L5-11),V044 只回补了 super_admin,platform_admin/organization_admin 等角色的红娘权限授予状态无法从迁移中确认【无法确定,需查实际库】。注意 PermissionMatrixTest L57-59 期望 platform_admin 拥有 matchmaker.view/assign/service,但迁移中未见对应 INSERT【测试期望与 DB 授权可能漂移】。
  • 红娘组长角色不存在:迁移与代码 grep leader|team_lead 均无结果。

后端接口面【部分实现】:

  • 运营端 MatchmakerOperatorController(/operator/matchmaker,类级 @PreAuthorize("hasAuthority('matchmaker.view')") L19):dashboard(L25)、pending(L32)、assign(L38,matchmaker.assign)、claim(L49,matchmaker.service)、my-services(L58)、recommendations(L69)、services/{id} 详情(L75)、recommend(L87)、followup(L99)、complete(L112)。
  • 用户端 MatchmakerController(/matchmaker):提交申请(L48-58)、我的服务(L60)、推荐列表(L67)、viewed/accept/pass(L73-96)。
  • 转介 ReferralController(/referrals):service-station(L33)/activity(L53) 均 matchmaker.service;confirm(L70)/my-history(L85) 用户本人;operator/history(L99) 按 matchmaker.service。

关键发现:matchmaker.assign 的语义——它是"把服务工单指派给某红娘"(assignService(serviceId, operatorId, organizationId),MatchmakerServiceService L87-104),即工单分派而非决策文档意义上的"服务对象分配"(对用户建立服务关系)。当前系统里"服务对象"就是服务单上的 user_id,分配关系与工单合一,无法表达"同一用户多次/多任务分配、分配历史、到期、撤销"。

已知实现缺陷(非权限但影响验收):

  • countInProgressByOperator 统计 status='processing'(MatchmakerServiceMapper L28-30),而 DB CHECK 白名单只有 in_service(V009 L30-32),工作台 inProgress 恒为 0。
  • cancelService(MatchmakerServiceService L229-237)无任何 Controller 入口,死代码。

2.2 服务对象分配建模

结论:未建模【缺失】。

  • 全仓(backend main + admin-web src + 全部迁移)grep matchmaker_assignments|service_assignment|ServiceAssignment 无结果。
  • 唯一的"分配"载体是 matchmaker_services.assigned_operator_id(V009 L12),字段只有 assigned_operator_id / assigned_at / organization_id,没有 assigned_by、assignment_reason、assignment_scope、expires_at、ended_at、end_reason、status(分配关系状态与服务单状态混用)。
  • /operator/matchmaker/my-services 返回该红娘名下全部服务含历史(MatchmakerServiceMapper.findByOperatorId L36-38,MatchmakerServiceService.getMyServices L68-82),即"我的服务对象 = 工单负责人",非独立分配关系。
  • 认领入口存在:POST /services/{id}/claim 仅需 matchmaker.service(MatchmakerOperatorController L49-56),claimService 只校验状态=assigned,不校验该单是否分配给本人,也不把 assigned_operator_id 改成自己(MatchmakerServiceService L109-122)——任何红娘可以把任何红娘的 assigned 单推进到 in_service。直接违反 DEC-002 规则 2(不能自行认领)。
  • 转分配/撤销/结束:无 transfer/revoke 接口;cancelService 无入口;completeService 无归属校验(L208-224)。

2.3 列表/搜索/详情/导出数据范围一致性

接口 数据范围 判定
GET /pending(L32-36 → findSubmitted Mapper L17-18) 全局:任何 matchmaker.view 持有者可见全库 submitted 申请,含申请人 userId + 需求描述(Service L245-258) ❌ 违反 DEC-002 规则1(不能浏览未分配对象库)、DEC-005
GET /dashboard(L25-30 → L260-276) pendingCount/todayCount/completedCount 为全局统计,inProgress 按本人 ❌ 信息泄露(全局量级)+ 状态口径 bug
GET /my-services(L58-63 → findByOperatorId) 按本人过滤 ✅
GET /recommendations(L69-73 → findByOperatorId) 按本人过滤 ✅
GET /services/{id} 详情(L75-85 → getServiceDetail L301-351) 负责人→完整(含 userProfile 8 字段 + followup 正文);非负责人→仍返回状态、assignedOperatorId、以及该服务的推荐列表(含他人服务的 targetUserId 与推荐理由)(L317-327 对所有调用者装配) ⚠️ 部分修复:比 Phase 13 D4 前好,但非负责人仍可探测任意 serviceId 的存在性与他人推荐内容(违反"响应不得泄露目标用户是否存在");推荐理由是红娘对候选对象的自由文本,可能含隐私
POST /services/{id}/recommend(L87-97 → L142-181) 归属校验(L148-151)+ 不能推给申请人(L153-155) ✅(但推荐对象 targetUserId 由红娘手输,无候选来源,见 2.4)
POST /followup(L99-110 → L186-203) 无归属校验:任何 matchmaker.service 持有者可对任意 serviceId 写跟进正文 ❌ 违反 DEC-005;跟进正文为自由文本敏感写面
POST /complete(L112-118 → L208-224) 无归属校验 ❌
POST /claim(L49-56 → L109-122) 无归属校验 ❌(见 2.2)
转介 POST /referrals/* assertMatchmakerServesUser(ReferralService L45-52 → findActiveByOperatorAndUser Mapper L48-54)要求存在本人名下、该用户的进行中服务 ✅(Phase 13 D5 修复,注释自证修复前可代任意用户创建报名/预约)
导出 全仓未发现任何导出端点(grep `data.export export` 在 main 源码无结果)

按 userId/查询参数越权形态:matchmaker 角色无 user.view(V052 仅 3 权限),无法触达用户管理接口,全站用户检索面关闭;但上述服务单维度参数越权真实存在。

2.4 联系方式暴露(B1)

现状结果层面安全【已实现(被动)】:

  • 红娘侧所有返回 DTO 均为手工 Map 装配:服务详情 userProfile 仅 displayName/gender/age/regionName/educationCode/occupationCode/maritalStatus(MatchmakerServiceService L333-343),无手机号/微信号/详细地址/身份证。
  • 前端 MatchmakerManagementView.vue 表格列仅 userId/serviceType/description/status/createdAt(L7-25)与推荐 userId/targetUserId/reason/status(L29-39);ReferralManagementView.vue 无联系方式字段。grep phone/mobile/wechat/身份证/地址 在两个 view 中均无命中。
  • 转介活动时的 emergencyContactPhoneEnc 是红娘录入的紧急联系人信息(ReferralController L62、ReferralService L111-112),非读取用户联系方式。
  • 无导出接口可绕道获取联系方式(2.3)。

机制层面缺失【缺失】:

  • 全仓无 ContactAuthorization/contact_authorization/线下联系 相关表、实体、策略(grep 无结果)——DEC-003 要求的"电话/线下联系须专项授权"完全没有机制承载,目前是"没有功能所以没有漏洞"。若后续有人补电话/线下功能,无任何护栏。
  • 平台内联系渠道:现有通知仅是单向 notification(notificationService.send/sendAsync),无红娘↔用户平台内会话通道;B1 的"平台内服务申请/回应"仅覆盖转介确认流。

功能缺口:推荐弹窗要求红娘手输 targetUserId(前端 L62"输入被推荐对象的用户ID")——红娘既无全站检索权(正确),也没有任何"从用户已提供的择偶需求/公开池中获取候选"的受控途径,主流程实际不可用【部分实现】。

2.5 红娘代替用户操作(DEC-004)

未发现代替用户决策的接口【已实现】:

  • 红娘推荐只建 MatchmakerRecommendation(status=pending_view),明确注释"这不是替用户 Like!""红娘点创建 Match → 不允许!"(MatchmakerService L97-105),并且有归属校验(L117-121)。
  • Like/Pass 仅由用户本人端点触发:POST /matchmaker/recommendations/{id}/accept|pass(MatchmakerController L81-96)→ acceptRecommendation 用 findByIdAndUser(recommendationId, userId) 归属校验(MatchmakerService L213-222),Pass 同理(L246-255)。
  • 红娘无法以用户身份调用:用户端点走 UserPrincipal,运营端走 OperatorPrincipal(两套 principal 体系,shared/security/principal/),且测试锁定"红娘无法用别人的用户身份接受推荐"(MatchmakerReferralPhase13Test L158-171)。
  • 转介确认(活动/预约)须用户本人 confirmReferral,校验 userId.equals(appt.getUserId())(ReferralService L145-146、L166-167),非本人确认被拒并有测试(MatchmakerReferralPhase13Test L255-269)。
  • 无修改用户择偶条件、同意公开资料的红娘入口(matchmaker 角色无 user 相关权限)。
  • matchmaker.assign 的实际用途 = 指派工单给红娘,不是"代替分配对象做操作";其风险在于指派时 organizationId 参数恒传 null(Controller L46 传 null),且前端弹窗是硬编码假数据(见 2.8)。

⚠️ 唯一灰色点:转介会代替用户创建 activity_registration(status=pending) / service_appointment(status=submitted) 记录(ReferralService L74、L114),但带 source=matchmaker_referral 标记且必须用户本人确认后生效(needsUserConfirmation=true),语义上是"代填草稿、用户确认",与 DEC-004 底线可兼容,但建议在 ZC-MM-004 复核其与"代填关键个人信息"边界的表述。

2.6 审计日志覆盖(DEC-006)

基础设施【已实现】:

  • audit_logs 表 + AuditLog 实体(operatorId/organizationId/action/resourceType/resourceId/beforeData/afterData/ip/userAgent)。
  • sensitive_access_logs + SensitiveAccessLog(operatorId/userId/dataType/reason/accessTarget/accessResult/ip)。
  • AuthorizationAuditListener(L25-49):@PreAuthorize 拒绝自动写 AUTHORIZATION_DENIED(含 IP/UA)→ @PreAuthorize 层的越权拒绝已覆盖。
  • DataScopeGuard.deny(L21-36):写 DATA_SCOPE_DENIED 后抛 403。

matchmaker 模块实际覆盖【部分实现,缺口明确】:

操作 审计现状
分配 assign ✅ MATCHMAKER_ASSIGN(L102),但 beforeData/afterData 恒 null(saveAuditLog L395-403),不记录分配人以外信息(谁指派=principal.id 即 assignOperatorId=被指派红娘,见 Controller L44-46 的参数命名混乱:body.operatorId 是"被分配红娘",操作者是 principal,审计里存的是前者)
认领 claim ❌ 无审计(L109-122 无 saveAuditLog)
推荐 recommend ✅ MATCHMAKER_RECOMMEND(L174)
跟进 followup ✅ MATCHMAKER_FOLLOWUP(L201)
完成 complete ✅ MATCHMAKER_COMPLETE 但 operatorId 传 null(L222)——审计丢失操作者
取消 cancel ❌ 死代码且无审计
查看敏感详情 getServiceDetail ❌ 不写 SensitiveAccessLog、不调 recordSensitiveAccess(对照:ReviewService L470-477 访问本地资格佐证时写 SensitiveAccessLog;AuditLogService.recordSensitiveAccess L74-88 已有现成方法)
模块内归属拒绝(recommend/followup 的 IllegalStateException、ReferralService 的 IllegalStateException) ❌ 不走 DataScopeGuard,不产生 DATA_SCOPE_DENIED;仅裸抛异常 → 服务层越权拒绝不落审计,违反 MM-AUDIT-002
缺失字段 审计无 purpose_code/service_assignment_id/actor_role_snapshot/request_trace_id(DEC-006 第八节字段要求),AuditLog 实体不含这些列

2.7 可复用模块

组件 位置 与 A1/B1 的关系
CounselingService 的 INV-012 判定链路 counseling/service/CounselingService.java L181-200(assign 用条件更新 assignIfPending 防并发)、assertAssigned 模式(L205/232/242 各写接口前置)、GET /counseling/services/operator/assigned(Controller L141-145 → assignedTo) 与 A1 最接近:"只有被分配人可见/可操作" 的完整范式,含权限矩阵注释(L38-48 定义 6 种角色的列表/脱敏/全文视图)。红娘"本人有效分配对象"可直接套此模式
DataScopeGuard shared/security/DataScopeGuard.java L21-36 拒绝+审计一体,activity/counseling/service_appointment 已用;红娘模块的归属拒绝应统一接入
AuthorizationAuditListener shared/security/AuthorizationAuditListener.java @PreAuthorize 拒绝自动审计,MM-AUDIT-002 的 403 层已覆盖
AuditLogService.recordSensitiveAccess + SensitiveAccessLog audit/service/AuditLogService.java L74-88;使用范例 review/service/ReviewService.java L470-477 受限字段/资料查看审计现成方法(matchmaker 详情接口应调用)
MatchmakerServiceMapper.findActiveByOperatorAndUser matchmaker/mapper/MatchmakerServiceMapper.java L48-54 现成的"本人名下+该用户+有效状态"判定 SQL,是未来 ServiceAssignmentPolicy 判定的雏形(状态集含 submitted 待收紧)
OperatorAuthService 权限装载 auth/service/OperatorAuthService.java L98-108(权限集合仅登录时装载进 JWT claims) 权限事实来源;同时是权限回收的风险点(见 P1-7)
用户端归属校验范式 MatchmakerRecommendationMapper.findByIdAndUser + MatchmakerService.acceptRecommendation L213-222 "资源归属=当前主体"校验样板

2.8 前端现状

  • MatchmakerManagementView.vue:服务请求队列 tab 对所有 matchmaker.view 用户展示全库 pending(userId+需求说明,L7-25);分配弹窗红娘下拉是硬编码假数据 operator_wang/operator_chen(L47-50)——分配功能前端不可真实使用;推荐弹窗需手输 targetUserId(L62)。
  • 路由/菜单:router/index.ts L40-41、MainLayout.vue L177-178 权限码已与后端对齐(matchmaker.view / matchmaker.service,V052 注释所述错配已修复)。
  • ReferralManagementView.vue L35 已改走 /referrals/operator/history(契约缺口已修)。

2.9 治理文档现状

  • docs/governance/decision-register.md:grep DEC-MATCHMAKER|matchmaker 无结果【缺失】。
  • docs/governance/open-questions.md:无 matchmaker/电话/线下联系条目【缺失】。
  • docs/PENDING_DECISIONS.md:无 A1/B1/matchmaker 条目【缺失】。
  • docs/audits/ 目录不存在(本报告即首次建立)。

2.10 现有测试

测试 覆盖 缺口
MatchmakerReferralPhase13Test MM-ACTION 方向较完整:推荐不产生 Like/Match(L132-141)、只有用户能 Like(L143)、红娘不能代用户接受(L158-171)、转介归属校验(L288-296)、用户本人确认(L225-269) 不含数据范围/联系方式/审计断言
MatchmakerServiceTest 仅校验常量与 DB CHECK 白名单一致(L94-177),纯守卫测试,无权限断言 —
PermissionMatrixTest 静态 Map 自断言(L25-224 + L229 起),不连接 DB/迁移文件,且期望值(matchmaker 有 user.view=true,L119)与 V052 实际授权(无 user.view)漂移 矩阵不校验真实授权,是"看起来有保护"的假阳性
OperatorEndpointPermissionCoverageTest 机械守卫:确保运营端 Controller 方法有 @PreAuthorize(L10、L43) 只查注解存在性,不校验权限码正确性
SecurityTests / V11InvariantsTest 通用授权拒绝、INV 守卫 无 MM-AUTH/CONTACT/PRIVACY/AUDIT/LIFECYCLE 专属场景

测试基线覆盖判定:MM-ACTION ≈ 部分覆盖;MM-AUTH/MM-CONTACT/MM-PRIVACY/MM-AUDIT/MM-LIFECYCLE ≈ 全部缺失。


3. 可复用模块清单

(按建议采用优先级)

  1. CounselingService INV-012 范式(CounselingService L181-200 条件更新分配、assertAssigned 写接口前置、Controller L141-145 assigned 列表)——A1"本人有效分配对象"的直接模板。
  2. DataScopeGuard(shared/security/DataScopeGuard.java)——归属拒绝统一走 deny()=审计+403。
  3. AuthorizationAuditListener——已有,无需新建。
  4. AuditLogService.recordSensitiveAccess + SensitiveAccessLog(ReviewService L470-477 为使用范例)——受限字段查看审计。
  5. MatchmakerServiceMapper.findActiveByOperatorAndUser——分配有效性判定 SQL 雏形。
  6. OperatorAuthService/JwtAuthFilter 权限装载链——若做权限回收需改造此链路(JWT claims 快照问题)。
  7. 无 MatchmakerPolicy/PrivacyPolicy/ContactAuthorizationPolicy 任何现存实现——需新建。

4. 差距与风险清单(按优先级)

P0(违反 LOCKED 决策,阻断 DoD)

# 差距 违反 影响 证据
P0-1 服务对象分配未建模:无 matchmaker_assignments/独立分配实体,分配=工单指派且无 assigned_by/理由/有效期/结束语义/分配历史 DEC-002 规则6/7、5.1 概念模型 A1 无法落地;分配不可追溯、不可回收、不可过期 V009 L5-20;全仓 grep 无 assignment 实体
P0-2 普通红娘认领入口开放且无归属校验:claim 任意 assigned 单;followup/complete 对任意 serviceId 可写/可完结 DEC-002 规则1/2;DEC-005;MM-AUTH-004 任何红娘可干预他人服务对象、写入跟进内容、变更服务状态 MatchmakerOperatorController L49-56、L99-118;MatchmakerServiceService L109-122、L186-203、L208-224
P0-3 未分配申请队列+全局统计对全体红娘可见(含申请人 userId 与诉求描述) DEC-002 规则1;DEC-005;MM-AUTH-002/PRIVACY-001 精神 普通红娘可浏览"待分配用户库"挑选对象,正面违反 A1 MatchmakerOperatorController L32-36;MatchmakerServiceService L245-258、L260-276;Mapper findSubmitted L17-18
P0-4 无红娘组长角色与团队管理范围概念,assign 权限无范围约束(谁能 assign 只有权限码、无组织/团队边界;organizationId 恒传 null) DEC-002 规则4/5/8 分配权无法收敛到"平台授权人员或组长";跨团队数据范围无依据 MatchmakerOperatorController L38-47(organizationId=null);全仓无 leader 角色
P0-5 服务层归属/范围拒绝不产生审计(不走 DataScopeGuard),claim 无审计、complete 审计丢操作者、分配审计字段残缺 DEC-006;MM-AUDIT-001/002 分配与越权链条不可追溯 MatchmakerServiceService L102/L109-122/L222/L395-403;DataScopeGuard 使用方不含 matchmaker

P1(安全机制缺口,DoD 必补)

# 差距 违反 影响 证据
P1-6 非负责人可读任意服务单脱敏详情+他人推荐列表(targetUserId、推荐理由),泄露存在性与他人服务内容 DEC-005(响应不得泄露目标用户是否存在);MM-PRIVACY-001 横向探测面 MatchmakerServiceService L301-351(L317-327 对非 owner 装配 recommendations)
P1-7 运营权限是登录时 JWT claims 快照(JwtAuthFilter L90-99 直接取 claims),停用/调岗/权限回收后旧 token 有效期内仍放行 DEC-005/006(权限及时回收);MM-LIFECYCLE-001 权限回收延迟=token 剩余有效期 OperatorAuthService L98-108;JwtAuthFilter L90-99
P1-8 受限资料查看无 SensitiveAccessLog(服务详情 userProfile 属受限资料但零记录) DEC-006;MM-AUDIT 方向 敏感读取不可溯源 MatchmakerServiceService L329-348;对照 ReviewService L470-477
P1-9 无统一 Policy 层(MatchmakerPolicy/DataScopePolicy/PrivacyPolicy),范围校验散落且口径不一 DEC-005 判定链要求 后续每加一个接口都可能漏校验(现状已证明) §2.3 表格
P1-10 B1 联系授权机制完全缺失(无表无策略无审批流),当前安全是"功能不存在"而非"有护栏" DEC-003 规则7 一旦有人新增电话/线下功能即裸奔;DoD "无授权电话/线下联系被拒绝" 无承载 grep ContactAuthorization 无结果
P1-11 测试基线缺口:MM-AUTH/CONTACT/PRIVACY/AUDIT/LIFECYCLE 无场景测试;PermissionMatrixTest 与真实授权漂移且自引用 决策文档第十节 回归无保护网 §2.10

P2(质量/体验/治理)

# 差距 影响 证据
P2-12 分配弹窗硬编码假红娘(operator_wang/chen),分配功能前端不可用 主流程断裂 MatchmakerManagementView.vue L47-50
P2-13 推荐对象需手输 userId,无受控候选来源,推荐主流程实际不可用 业务不可用(但不可用方向是安全的) 同上 L62
P2-14 dashboard inProgress 统计用 'processing' 与 DB 白名单 'in_service' 不符,恒为 0 数据失真 MatchmakerServiceMapper L28-30 vs V009 L30-32
P2-15 cancelService 死代码;matchmaker.assign 的 organizationId 参数恒 null 代码卫生 MatchmakerServiceService L229-237;Controller L46
P2-16 治理文档无 DEC-MATCHMAKER/A1/B1 条目;docs/audits 目录此前不存在 治理不同步(ZC-MM-007 范围) §2.9
P2-17 PermissionMatrixTest 期望 platform_admin/reviewer 等角色矩阵,但迁移未定义这些角色的 matchmaker 授权,实际库状态无法确定 授权事实不清 V052 仅授 role 005;V044 仅补 super_admin

5. 仍需后续确认的实现细节(对应决策文档第十一节,仓库现状)

待确认项 仓库现状
电话/线下联系例外批准岗位 无任何授权机制/审批流/岗位模型(grep 无结果);需产品确认后从零建
例外授权是否需用户单独同意及记录方式 无载体;activity_registration/service_appointment 已有 user_confirmed_at+source=matchmaker_referral 的用户确认范式(ReferralService L151-152)可作参考
临时授权有效期限 无 expires_at/有效期字段于任何红娘相关表(matchmaker_services 也没有);matchmaker_recommendations 无过期机制
审计日志/服务摘要保留周期 迁移中未见 audit_logs 的保留/清理策略;account 模块有 DataRetentionService(account/service/DataRetentionService.java)可参考但未覆盖审计日志【保留周期无法确定】
红娘组长可分配的组织/团队边界 organizations 表与 matchmaker_services.organization_id 存在(V009 L11),operator 与组织的关联关系存在于 operator 体系,但"团队/红娘组"概念不存在,边界配置无从谈起
platform_admin/organization_admin 的 matchmaker 权限实际授权 迁移不可证【无法确定,需查演示库】
转介代建 pending 报名/预约与"代填关键信息"边界 见 §2.5 灰色点,建议 ZC-MM-004 复核时与产品确认表述

6. 对 ZC-MM-002~007 实施顺序的建议(仅顺序与依赖)

  1. ZC-MM-002(A1 分配)先行且作为一切的地基:必须先落 matchmaker_assignments 独立分配关系(含 assigned_by/reason/status/expires/ended)+ 红娘组长角色 + 分配状态机。理由:P0-1~P0-4 全部依赖此建模;后续所有数据范围判定都以"有效分配"为事实源。
  2. ZC-MM-005(统一数据范围与字段隐私)紧跟 002:把 claim/followup/complete/pending/dashboard/详情统一接入范围判定(复用 CounselingService INV-012 + DataScopeGuard)。依赖 002 的分配事实源;不先做会继续在旧工单模型上打补丁。
  3. ZC-MM-003(B1 联系规则)与 004(禁止代操作复核)可并行:003 当前主要是"补护栏+固化现状"(关闭暴露面+建立联系授权的拒绝默认),004 主要是复核与测试锁定(现状已基本合规)。两者都不依赖 002 的表结构,但 003 的"平台内服务通知渠道"若要做成会话类功能,建议在 005 稳定后做。
  4. ZC-MM-006(审计与权限回收)在 002/005 之后收口:分配/转交审计、SensitiveAccessLog 接入、模块内拒绝走 DataScopeGuard 都依赖 002 的新实体与 005 的判定点;JWT 权限回收(P1-7)涉及 auth 链路改造,放在业务语义稳定之后风险最小。
  5. ZC-MM-007(治理文档)最后:登记 DEC-MATCHMAKER-001~006 与 A1/B1、open-questions(第十一节五项)、本报告归档于 docs/audits。
  6. 贯穿性建议:每阶段同步补 MM-AUTH/CONTACT/ACTION/PRIVACY/AUDIT/LIFECYCLE 测试基线(当前几乎为零),并把 PermissionMatrixTest 从静态自引用改为对迁移/真实授权的校验——否则 P1-11 的假阳性会掩盖回归。

(审计完毕。本报告由架构师产出、主理人汇编落盘。后续实施需 Owner 授权后按 ZC-MM-002~007 分阶段进行。)