release: freeze 2026-10-15 validated release baseline
CI/CD Pipeline / UI Contracts (source-structure gates) (push) Canceled after 0s
CI/CD Pipeline / E2E (live stack) (push) Canceled after 0s
CI/CD Pipeline / Backend Build & Test (push) Canceled after 0s
CI/CD Pipeline / Admin Web Build (push) Canceled after 0s
CI/CD Pipeline / Mini Program Compile Check (push) Canceled after 0s
CI/CD Pipeline / Migration Validation (push) Canceled after 0s
CI/CD Pipeline / Test Shell Guard (Phase 23 Gate) (push) Canceled after 0s

This commit is contained in:
WorkBuddy
2026-10-15 09:47:31 +08:00
parent 827c23db1d
commit 3c2b967274
149 changed files with 4324 additions and 348 deletions
@@ -0,0 +1,107 @@
# 善缘丹阳红娘 Web 与小程序端整合设计
**状态:已获用户确认,作为实施基线**
**日期:2026-10-12**
## 1. 目标
在保留现有 V1.1 权限和隐私规则的前提下,打通红娘管理端 Web、红娘工作台小程序与普通用户端之间的服务闭环:
```text
Web 分配服务对象 → 小程序查看任务 → 小程序记录服务 → Web 查看最新结果
```
本设计不新建独立红娘小程序,不重建已有红娘后端模块,不改变用户自主 Like/Pass、活动互选和聊天确认规则。
## 2. 已确认的业务边界
- 普通红娘只能访问本人有效分配的服务对象。
- 服务对象由平台授权人员或红娘组长分配,普通红娘不能认领或转分配。
- 联系用户以平台内通知、服务申请和用户主动渠道为默认方式。
- 电话、线下联系和完整联系方式必须经过独立授权;未确认审批岗位和期限前保持默认拒绝。
- 红娘不能代替用户 Like、Pass、接受活动意向、确认开启聊天或修改关键择偶条件。
- 红娘服务记录只记录公益服务所需信息,修改和受控更正必须留痕。
- PostgreSQL 是业务事实来源,前端缓存和 Redis 不能覆盖业务状态。
## 3. 端职责
### 3.1 管理端 Web
负责服务申请队列、红娘分配/转分配/结束、联系授权审批、活动与转介任务管理、脱敏统计和审计查看。Web 不提供代用户交友操作和普通红娘全站用户检索。
### 3.2 红娘端小程序
负责工作台待办、本人服务对象、授权资料、服务历史、服务记录、候选建议、获授权活动任务、联系授权申请、风险转介和脱敏个人统计。小程序不提供全站搜索、分配管理、敏感资料下载或私人聊天全文。
## 4. 统一业务模型与事实来源
复用现有对象:
- `matchmaker_assignments`:服务范围和当前分配关系事实来源;
- `matchmaker_services`:服务任务;
- `matchmaker_followups`:跟进记录;
- `matchmaker_recommendations`:候选建议;
- 联系授权表:申请、审批、用户确认、撤销和到期;
- 统一通知和审计表:跨端提醒与操作留痕。
所有端点都由后端基于当前身份、权限、有效分配、字段策略和服务目的重新授权。客户端传入的 `userId`、`matchmakerId`、角色名和状态不能作为授权事实。
## 5. 第一阶段范围
第一阶段只实现最小可验证闭环:
1. Web 创建或调整服务分配;
2. 小程序工作台显示本人有效分配;
3. 小程序进入服务对象详情;
4. 小程序查看服务历史并新增服务记录;
5. Web 重新加载后查看服务记录和最新服务状态;
6. 分配结束、撤销、转交或红娘停用后,小程序不能继续访问旧对象;
7. 写操作成功后两端从服务端刷新,不依赖本地状态猜测。
第一阶段不包含实时 WebSocket、移动端分配管理、绩效排行榜、AI 自动决策和新的联系方式开放。
## 6. API 约定
继续使用 `/api/v1` 和统一响应 `{ success, code, message, data }`。第一阶段复用现有接口,必要时补充:
```text
GET /operator/matchmaker/dashboard
GET /operator/matchmaker/assignments/my
GET /operator/matchmaker/services/{id}
GET /operator/matchmaker/services/{id}/history
POST /operator/matchmaker/services/{id}/followup
GET /operator/matchmaker/recommendations
```
资源不属于当前红娘有效服务范围时,服务端按项目统一错误规范拒绝,并写入必要的越权审计;响应不得泄露对象是否存在。
## 7. 状态与联动
服务任务沿用现有状态枚举,语义覆盖待分配、已分配、服务中、等待用户、待下一次跟进、已完成、已撤销、已转分配和已过期。两端不各自定义状态,也不在前端拼接业务状态。
P0 采用 `onShow`、页面切换和写操作后的重新拉取实现可靠联动;通知统一记录未读状态。实时通知作为后续 P1,只用于提醒,不能替代 API 刷新。
## 8. 安全、隐私和错误处理
- 列表、详情、历史、统计、文件和批量接口执行相同数据范围校验。
- 普通红娘默认不能看到完整手机号、微信号、精确地址、完整身份证和原始证明。
- 权限失效时清理对象缓存,提示服务权限已变更并返回工作台。
- 重复提交服务记录必须幂等或被明确拒绝。
- 网络失败时保留未提交表单内容。
- 应用日志和审计日志不得写入令牌、密码、完整身份证号、完整联系方式、原始证明、完整聊天正文或咨询全文。
## 9. 验收标准
- 未授权用户不能进入红娘工作台。
- 普通红娘只能看到本人有效分配对象。
- 修改 URL、`userId`、分页参数不能越权。
- Web 新建分配后小程序刷新可看到对象。
- Web 撤销、结束或转分配后原红娘不能继续查看对象。
- 小程序新增服务记录后 Web 可查看,记录含操作者和时间。
- 推荐不会直接创建 Match 或 Conversation。
- 联系授权未完成审批和用户确认前不返回完整联系方式。
- 关键越权、权限回收、重复提交和敏感字段场景有自动化测试。
## 10. 后续阶段
第一阶段通过后,再实施服务申请回应、候选建议、活动任务、风险转介、未读通知和实时推送。每个阶段单独验收,不自动放宽权限边界。
@@ -0,0 +1,80 @@
# 全平台业务展示编号统一设计
## 背景与目标
用户在联系授权审批页看到红娘与用户 UUID,且管理端、小程序部分页面继续显示底层 UUID。统一全平台用户可见编号,使人员、业务记录和活动在 Web、小程序及运营接口中均可读、稳定、唯一,并保持既有数据关联与权限边界。
## 已确认编号格式
全平台公开展示编号统一为 **13 位 ASCII 字母数字**:`2 位类型前缀 + Asia/Shanghai 日期 YYYYMMDD + 3 位当日序号`。例:`HN20261013001`、`YH20261014002`、`RW20261014001`、`HD20261014001`。
用户编号采用 `YH` 前缀,注册日后按性别分别排名;男性序号为奇数、女性序号为偶数,序号宽度 3 位(男性 001/003/...,女性 002/004/...)。红娘使用 `HN`,其他工作人员使用 `GL`。任务使用 `RW`,活动使用 `HD`。推荐对象和被举报人是用户,因此显示其 `YH` 编号,不另造人员编号。
其他需要在页面展示的业务记录使用独立前缀,首批建议为:红娘服务 `FW`、红娘推荐记录 `TJ`、联系授权 `LX`、服务分配 `FP`、跟进记录 `GJ`、举报记录 `JB`、转介 `ZF`、审核任务 `RW`。实施盘点若发现其他实体已向用户展示其主键,必须列入覆盖矩阵并在编码前确认前缀;不得临时回退显示 UUID。
序号达到 999 时拒绝分配并记录明确错误,不截断、不复用旧编号。编号创建后不可变;用户性别资料更正不重算既有编号。
## 设计决策
### 内部主键与公开编号
- PostgreSQL UUID 主键、外键、JWT subject、数据范围查询、幂等键和内部服务间调用保持不变。
- 每个需要公开展示的实体增加持久化公开编号字段(已存在的 `users.display_number`、`operators.display_id` 保留并扩展格式);所有业务编号设置唯一约束。
- API 面向展示的数据提供明确命名的 `displayId` / `displayNumber` 字段。现有 `id`、`userId` 等 UUID 仅保留为内部资源寻址和向后兼容字段;页面表格、详情、弹窗和导出文案不得渲染这些 UUID。
- 写请求仍使用既有 UUID 路由参数或受保护的内部 ID 字段,避免更改所有外键和既有 API 路由;用户可见的人员选择、搜索和表单输入改用搜索接口解析公开编号到内部用户。
### 编号生成与历史数据
- PostgreSQL 提供按 `prefix + date + sequence_group` 原子递增的编号分配器,以事务级 `INSERT ... ON CONFLICT ... DO UPDATE ... RETURNING`(或等价数据库原子操作)处理并发;普通实体的 `sequence_group` 为空,用户按性别分别计数并以步长 2 产生奇偶序号。应用层不得用 `COUNT(*) + 1` 生成序号。
- 日期统一按 `Asia/Shanghai` 取值。调用方在创建实体的同一事务内取得编号并写入实体;失败整体回滚,唯一约束作为最终并发保护。
- 迁移为所有既有记录回填公开编号。用户按注册日、实名性别和注册时间排名;红娘及工作人员按创建日与稳定主键顺序排名;其他实体按创建时间与 UUID 稳定排序排名。按实体、日期分别编号。
- 用户旧 `YH...`、工作人员旧 `HN.../GL...` 编号更新为新格式;应检查外部可见引用,必要时保留旧编号别名仅供检索,不再用于展示。不得更换 UUID 主键或破坏既有关系。
- 回填前执行冲突和数量预检;迁移必须可在空库和包含现有演示数据的 PostgreSQL 上重复验证。历史回填不可逆展示变化须提供旧号到新号映射证据。
### 展示范围
- 红娘联系授权:红娘列显示 `HN...`,用户列显示 `YH...`。
- 红娘工作台、服务详情、推荐列表、跟进和转介:服务/推荐/跟进/转介记录显示其公开业务编号;申请服务用户、推荐对象、被推荐人始终显示 `YH...`,操作者显示 `HN.../GL...`。
- 活动管理、报名、互选、签到:活动显示 `HD...`;参与者显示 `YH...`。
- 举报、安全与审核:举报记录显示 `JB...`,被举报人、举报人显示 `YH...`;审核工作项显示 `RW...`,工作人员显示 `GL.../HN...`。
- 审计日志若展示实体引用,应显示已解析的业务编号;对无公开编号或权限不足的引用显示中文类型标签和脱敏占位,不暴露 UUID。
- 用户小程序对外展示个人编号、活动编号、红娘服务进度编号时使用对应业务编号;交互调用使用内部 ID,不向用户暴露 UUID。
## 数据流
```text
创建业务对象
-> 数据库原子分配器生成公开编号
-> 与 UUID 主键在同一事务写入
-> API DTO 同时提供内部寻址字段与公开展示字段
-> Web / 小程序只渲染公开字段
-> 用户选择或搜索用公开编号查询,再由后端做权限校验
```
## 安全与兼容
- 公开编号不可作为授权凭证;所有权限校验仍基于认证主体、UUID 关联和现有 DataScope/Capability 规则。
- 不返回敏感资料,不通过编号查询绕过字段脱敏或组织范围。
- 保留旧 API UUID 参数以兼容现有页面和客户端;新增展示字段不改变原 JSON 字段语义。
- 对用户输入的编号严格校验前缀、长度和字符集;未找到、已删除或越权对象使用既有统一错误语义,避免枚举信息泄露。
## 验收标准
1. 公开编号全部满足 `^[A-Z]{2}[0-9]{11}$`,唯一、非空、持久化;新建和历史记录均覆盖。
2. 男性用户当日序号为奇数、女性为偶数;其余编号符合各自前缀和创建日。
3. 并发创建同日同类型记录不会重复编号;达到 999 时明确拒绝。
4. 联系授权截图、管理端业务列表、审核/举报/活动/推荐页面、小程序业务详情无 UUID 展示。
5. 用户编号在推荐对象、被举报人、活动参与者等跨模块场景一致。
6. 既有 UUID 主外键、登录、权限、数据范围、操作请求与旧 API 路由继续工作。
7. 后端测试、迁移验证、管理端类型检查/构建、小程序结构与行为检查通过;演示 Docker 环境完成迁移和 HTTP 抽查。
## 明确不在本次范围
- 不迁移数据库主键类型,不改 JWT subject,不把 UUID 外键改成业务编号。
- 不改变红娘服务、推荐、联系授权、举报、活动和审核的业务状态机或权限规则。
- 不因编号暴露而开放用户搜索、手机号、身份证或任何其他敏感字段。
- 不生成未展示且无业务价值的随机内部记录编号;只对用户可见或跨角色操作中可见的业务实体分配公开编号。
## 实施前置检查
实现前建立“公开 ID 展示清单”:逐项检查后端 DTO/API、管理端模板/表格/导出、小程序模板/文案,以及数据库实体和迁移。清单中的每个公开 ID 必须映射到本设计的编号类型;任何新增前缀或需要改变 API 路由参数的情况应先更新本设计并取得确认。
@@ -0,0 +1,54 @@
# 全平台公开编号覆盖清单
日期:2026-10-14。状态:Task 1 盘点完成;编号实现未完成。
用户已确认择偶条件“下一步”重新编译后目视复验通过。本轮不改变该页面。
## 数据与接口覆盖矩阵
内部主键、关联字段和操作参数继续使用 UUID;以下字段为展示增量,不能作为授权凭证。
| 实体 / 关联 | 创建入口(Service) | 读取与 DTO 覆盖 | Web / 小程序 | 展示编号 | 权限要求 |
|---|---|---|---|---|---|
| users / id | AuthService;IdentityVerificationService 生成用户编号 | UserService、用户列表/详情、推荐与举报关联查询 | 用户管理、用户详情、审核、推荐;个人资料、推荐卡片 | displayNumber / YH | 维持实名、脱敏、DataScope |
| operators / id | OperatorManagementService | 操作员、分配、联系授权、审计与咨询人员查询 | 人员管理、红娘服务;红娘工作台 | displayId / HN 或 GL | 不扩大组织范围 |
| activities / id | ActivityService.createActivity / createActivityFromAdmin | ActivityService、ActivityInterestService、CheckinService | 活动管理、互选、签到;活动详情、转介确认 | displayId / HD | 单向意向保密 |
| review_tasks / id、user_id | ReviewService 及审核任务生产方 | ReviewController、ReviewTaskDetailDTO、用户关联 | ReviewView | displayId / RW;userDisplayNumber / YH | 审核领取、敏感材料权限不变 |
| reports / id、reported_user_id | ReportService | 举报列表/详情、举报用户关联 | ReportCenterView;举报页面 | displayId / JB;reportedUserDisplayNumber / YH | 案件权限与数据范围不变 |
| matchmaker_services / id、user_id、assigned_operator_id | MatchmakerService.submitServiceRequest;MatchmakerServiceService.applyService | MatchmakerManagementService、服务详情/列表 | MatchmakerManagementView;工作台、服务详情、服务进展 | displayId / FW;关联 YH、HN | 仅负责/授权服务 |
| matchmaker_recommendations / id、user_id、target_user_id | MatchmakerService.createRecommendation;MatchmakerServiceService.recommendPartner | 推荐列表、管理端及用户端推荐详情 | 红娘推荐列表;工作台、推荐进展 | displayId / TJ;userDisplayNumber、targetUserDisplayNumber / YH | 不能代用户 Like |
| matchmaker_contact_authorizations / id、operator_id、user_id | ContactAuthorizationService.request | MatchmakerContactAuthorizationMapper 与审批响应 | 联系授权审批(红娘服务下);工作台 | displayId / LX;operatorDisplayId、userDisplayNumber | 手机号仍授权后读取并审计 |
| matchmaker_assignments / id、user_id、operator_id | MatchmakerAssignmentService.create / transfer | 分配查询与红娘工作台 | 分配列表;工作台 | displayId / FP;关联 YH、HN | 分配范围不变 |
| matchmaker_followups / id、service_id、operator_id | MatchmakerServiceService.addFollowup 及其他跟进写入方 | 服务详情跟进列表 | 服务详情;服务进展 | displayId / GJ;关联 FW、HN/GL | 不读取咨询正文 |
| service_appointments / id、user_id、assigned_operator_id | ServiceAppointmentService;ReferralService.referToServiceStation | 预约运营列表与转介历史 Map | ServiceAppointmentView、ReferralManagementView;转介确认 | 预约 displayId / YY **待确认**;转介 referralDisplayId / ZF | 预约所属人员权限不变 |
| activity_registrations / id、activity_id、user_id | ActivityService.registerActivity;ReferralService.referToActivity | 活动报名、转介历史 Map | 活动参与者、转介记录;转介确认 | 关联 HD、YH;转介 referralDisplayId / ZF | 不为未展示的普通报名 ID 新造前缀 |
| MatchmakerService.ReferralRecord(非持久化 Java record) | MatchmakerService.createReferral | 返回值、通知文案;代码注释称有跟进写入,但方法未实际 insert | 服务转介与通知调用链需后续行为验证 | ZF;必须先保证可持久化追溯 | 保持“转介建议,用户自行确认”语义 |
| audit_logs / operator_id、resource_id | AuditLogService | 审计列表、资源编号解析 | AuditLogView | 人员 HN/GL;资源复用已确认编号 | 不可解析/无权限显示类型与脱敏说明 |
| organization / organization_id | 组织管理 | 活动组织列表与人员 orgMap | ActivityManagementView、OperatorManagementView | 建议显示已有机构名称,不新增机构编号 | 组织关系不授予数据权限 |
| 专项服务参与者 / user_id | ServiceProgram 相关创建方 | 参与者列表 | ServiceProgramView | 复用 YH | 数据范围不变 |
## 模板检查证据
执行 `node tests/public-id-display-coverage.cjs --self-check`:7 项 PASS。
执行 `node tests/public-id-display-coverage.cjs`:扫描 114 个 Vue/WXML 模板,31 个审查候选,退出码 1。该 FAIL 是尚未修复的公开编号差距,不能将清单完成写成全局展示 PASS。
确认可见 UUID / UUID 输入集中在:活动签到及互选、红娘推荐及联系授权、审核、举报、预约、转介、专项服务参与者、审计、小程序工作台。具体文件与行号由检查命令即时输出。
人工剔除的名称映射候选:`ContentManagementView` 的 `categoryLabel(row.categoryId)`;`OperatorManagementView` 的 `orgMap[row.organizationId]` 及其组织列有自定义名称模板。检查器保守报告,不能仅因字段含 Id 就认定实际泄露。
额外动态文案差距:`miniapp/pages/referral-confirmation/referral-confirmation.js` 将 `activityId` 作为 detail 文案;`ReferralService.getOperatorName` 在找不到操作员或异常时回退 operatorId;`MatchmakerService.createReferral` 将 referralTarget 拼入通知。需要在后续 DTO/行为测试中处理,模板扫描不能发现这些间接绑定。
编号输入覆盖:推荐用户选择、人工签到用户、互选活动搜索、咨询人员分配、Banner 的站内目标选择。推荐/签到/分配需解析展示编号或使用选项选择器;Banner 可优先按已有活动/文章名称选择并保留内部寻址,不因内部配置键新增无业务意义的编号。
## 实施前待确认的具体增量
建议预约编号 `YY20261014001`。预约与转介分别显示 `YY`、`ZF`:同一预约由红娘发起时具有预约公开号和转介公开号;活动转介使用 ZF,活动本身仍为 HD。无需变更 UUID 路由,也无需新建统一转介表;为已有预约/报名记录增加转介编号字段(仅转介记录非空)。
机构展示名称;无公开编号的审计资源依既有规格显示中文类型和脱敏说明。以上不新增其他前缀。
## 后续验证边界
本轮仅新增盘点与检查工具,未执行数据库迁移、全量后端测试、端到端页面验收。后端覆盖测试应在 Task 3 使用真实响应与创建流程验证,不写仅检查源码字符串的空泛 Java 测试。
迁移前必须验证用户实名性别缺失的处理、旧新号映射、并发与回滚。普通序号 999 可使用,超过 999 拒绝;男性最多 500 个奇号,女性最多 499 个偶号。H2 测试不能代替 PostgreSQL UPSERT 并发与 Flyway 实测。