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,105 @@
# 红娘双端最小联动闭环实施计划
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 打通红娘 Web 分配、小程序服务对象详情与服务记录、Web 查看结果的第一阶段闭环。
**Architecture:** 复用现有 Spring Boot 红娘模块、Vue 管理端和微信小程序原生页面。以 `matchmaker_assignments` 作为数据范围事实来源,以服务端 API 作为状态事实来源,前端只负责展示和提交操作。
**Tech Stack:** Java 21、Spring Boot 3.x、PostgreSQL、MyBatis-Plus、Vue 3、TypeScript、微信小程序原生 JavaScript/WXML/WXSS。
**Spec:** `docs/superpowers/specs/2026-10-12-matchmaker-dual-client-integration-design.md`
## Global Constraints
- 普通红娘只能访问本人有效分配对象。
- 红娘不能代替用户 Like、Pass、接受活动意向或确认开启聊天。
- PostgreSQL 是 Source of Truth,前端缓存不能覆盖服务端状态。
- 联系方式默认拒绝,未完成授权不得返回完整手机号、微信号和详细地址。
- 不增加依赖,不新建微服务,不改动无关领域。
- 所有新增业务逻辑先写失败测试,再写最小实现。
### Task 1: 固化端点和数据范围测试
**Files:**
- Modify: `backend/src/test/java/com/danyang/match/platform/matchmaker/*` 现有红娘测试
- Create: `backend/src/test/java/com/danyang/match/platform/matchmaker/MatchmakerServiceDetailScopeTest.java`
- Create: `backend/src/test/java/com/danyang/match/platform/matchmaker/MatchmakerFollowupScopeTest.java`
**Interfaces:**
- Consumes: `ServiceAssignmentPolicy`、`MatchmakerServiceService`、现有 `MatchmakerAssignment` 测试夹具。
- Produces: 可证明“本人有效分配允许、其他红娘/失效分配拒绝”的测试契约。
- [ ] Step 1: 写测试:同一服务对象在有效分配给当前红娘时详情和跟进允许;换成其他红娘、撤销或过期时拒绝。
- [ ] Step 2: 运行单测,确认因现有服务详情/跟进调用路径缺少或未覆盖断言而失败。
- [ ] Step 3: 仅补齐服务层调用现有 `ServiceAssignmentPolicy` 的最小授权检查和统一错误映射。
- [ ] Step 4: 重新运行新增测试及现有 `MatchmakerReferralPhase13Test`、`MatchmakerAssignmentPermissionTest`。
- [ ] Step 5: 记录端点和数据范围结论到阶段报告。
### Task 2: 补齐小程序服务对象详情页面
**Files:**
- Create: `miniapp/pages/matchmaker-service-detail/matchmaker-service-detail.js`
- Create: `miniapp/pages/matchmaker-service-detail/matchmaker-service-detail.wxml`
- Create: `miniapp/pages/matchmaker-service-detail/matchmaker-service-detail.wxss`
- Create: `miniapp/pages/matchmaker-service-detail/matchmaker-service-detail.json`
- Modify: `miniapp/app.json`
- Modify: `miniapp/pages/matchmaker-workbench/matchmaker-workbench.js`
**Interfaces:**
- Consumes: `GET /operator/matchmaker/services/{id}`、`GET /operator/matchmaker/services/{id}/history`、`POST /operator/matchmaker/services/{id}/followup`。
- Produces: 从工作台分配卡片进入详情、查看授权字段、查看历史和提交服务记录。
- [ ] Step 1: 写页面契约测试或静态守卫,验证页面已注册、请求只使用服务 ID、没有联系方式和代操作按钮。
- [ ] Step 2: 运行守卫确认当前页面目录缺失导致失败。
- [ ] Step 3: 实现最小详情页:加载、空状态、失败、无权限、历史列表和记录表单。
- [ ] Step 4: 记录提交成功后重新拉取详情和历史;失败保留表单输入;重复提交由提交锁阻止。
- [ ] Step 5: 运行小程序现有页面守卫和 WXML/WXSS 编译检查。
### Task 3: 统一 Web 服务详情和跟进查看
**Files:**
- Modify: `admin-web/src/modules/matchmaker/MatchmakerManagementView.vue`
- Create or modify: `admin-web/src/api/*` only if现有 `get/post` 无法复用
- Modify: `backend/src/main/java/com/danyang/match/platform/matchmaker/controller/MatchmakerOperatorController.java` only when Task 1 proves endpoint缺失
**Interfaces:**
- Consumes: Task 1 的详情、历史和范围契约。
- Produces: Web 在本人授权范围内查看服务记录和最新服务状态。
- [ ] Step 1: 写前端行为测试/契约守卫,验证列表点击详情时只传服务 ID,范围错误显示统一提示。
- [ ] Step 2: 运行测试确认当前管理页没有服务详情和跟进查看入口。
- [ ] Step 3: 增加最小抽屉或弹窗,显示服务状态、最近跟进和必要摘要。
- [ ] Step 4: 分配、转交、撤销、结束后刷新当前 Tab,不保留旧对象状态。
- [ ] Step 5: 运行 `admin-web` 类型检查和构建。
### Task 4: 跨端刷新和权限失效处理
**Files:**
- Modify: `miniapp/pages/matchmaker-workbench/matchmaker-workbench.js`
- Modify: `miniapp/pages/matchmaker-service-detail/matchmaker-service-detail.js`
- Modify: `miniapp/utils/api.js`
- Modify: `admin-web/src/api/client.ts` only if现有错误处理不能统一
**Interfaces:**
- Consumes: Task 1-3 的端点和错误契约。
- Produces: 页面显示始终以最新服务端状态为准,权限失效时清理敏感缓存并返回工作台。
- [ ] Step 1: 写请求层测试,验证 401/403/资源失效不会静默吞掉,并能被页面识别。
- [ ] Step 2: 运行测试确认当前请求层行为不足。
- [ ] Step 3: 增加最小的刷新、提交锁、权限失效跳转和非敏感缓存清理。
- [ ] Step 4: 验证 Web 与小程序写操作后都重新读取服务端数据。
- [ ] Step 5: 运行小程序请求层测试和 Web 构建。
### Task 5: 第一阶段验收与文档
**Files:**
- Create: `docs/Phase-matchmaker-dual-client-Completion-Report-2026-10-12.md`
- Modify: `docs/STATUS.md` only for已验证状态
- Modify: `docs/governance/open-questions.md` only for未确认联系授权细节
- [ ] Step 1: 运行后端红娘相关测试、前端构建和小程序静态/编译守卫。
- [ ] Step 2: 以两个红娘账号和一个普通用户账号执行分配、查看、记录、撤销和越权场景。
- [ ] Step 3: 将每项结果标记为 `PASS`、`PARTIAL`、`FAIL` 或 `NOT_VERIFIED`。
- [ ] Step 4: 只有所有 P0 场景通过才将第一阶段标为 `PASS`,否则保留 `PARTIAL` 或 `FAIL`。
- [ ] Step 5: 输出剩余风险和第二阶段依赖,不自动进入下一阶段。
@@ -0,0 +1,75 @@
# 爱在丹阳三端演示收口执行计划
> 执行方式:在当前会话按 executing-plans 逐项执行,每项记录证据;阶段结束输出 Completion Report。
**Goal:** 使用现有运营演示数据,确认管理端、红娘小程序与用户小程序形成可重复演示的业务闭环。
**Architecture:** 沿用现有 Vue 管理端、原生微信小程序和 Spring Boot 模块化单体。三端共享后端与 PostgreSQL,以实际请求和落库结果验证联动。
**Tech Stack:** Vue 3、TypeScript、Vite、微信小程序、Java 21、Spring Boot、PostgreSQL、Docker Compose。
**Spec:** `docs/superpowers/specs/2026-10-12-matchmaker-dual-client-integration-design.md` 与用户最新品牌、编号和审批导航指令。
## 执行边界
- 优先使用运营管理端已有演示数据;不清库、不重新生成整库演示数据。
- 最新品牌为“爱在丹阳”,标语为“爱在丹阳 原来是你”;保留已确认字体。
- 联系授权审批归入“红娘服务”,不单独新增一级导航。
- 展示编号按最新指令核对:12 位字母与数字,红娘示例 HN2026101301;不因展示编号要求直接替换关联主键。
- 不代用户 Like,不放宽 Required,不越权读取咨询正文或联系方式。
- 历史 PASS 不替代本轮实测;无法执行的项记为 NOT_VERIFIED。
- 只修复验收发现的问题;数据库变更、扩大产品范围等另行明确边界。
## 任务 1:确认最新前端部署与品牌渲染
涉及:`admin-web/public/brand/logo-mark.png`、`admin-web/src/layouts/MainLayout.vue`、`admin-web/src/views/LoginView.vue`;部署配置仅检查 `infrastructure/docker-compose*.yml`。
- [x] 核对当前 Docker 容器、Compose 项目和运行端口,确认实际提供 /admin/ 的服务。
- [x] 比对运行服务与本地最新构建的 Logo、CSS;发现旧镜像后重建并仅更新管理端服务。
- [x] 检查 Logo 请求 HTTP 200、PNG 类型及透明通道;核对页面使用最新资源。
- [ ] 在 1366×768 和 1920×1080 检查登录页、顶部栏、展开/折叠侧栏:无方形底色、主体完整、对齐正常(待用户在浏览器完成目视确认)。
- [x] 保存请求、容器文件哈希和构建证据。既有背景 CSS 构建警告已记录,未影响本次 Logo 资源发布。
验收:正在运行的页面呈现新 Logo 和品牌文案;不存在旧资源或渲染异常。
## 任务 2:演示数据、编号与统计一致性
涉及检查:`admin-web/src/modules/user/`、`admin-web/src/modules/matchmaker/`、`admin-web/src/layouts/MainLayout.vue`、`backend/src/main/java/com/danyang/match/platform/`;报告记录抽样结果。
- [x] 从现有数据选定一名红娘、两名服务用户和一名审批操作员,使用脱敏编号建立验收记录。
- [x] 对比管理端接口与红娘工作台接口的展示编号、姓名、服务状态和分配关系;`/operator/matchmaker/assignments/my` 已在代码中正确使用。
- [x] 核对用户、红娘、管理员等对外展示编号的长度、格式、唯一性;当前演示账号和 12 个演示用户展示编号均为 12 位且唯一。
- [x] 核对工作台顶部统计改为服务记录实时计算;当前管理范围实测为今日 2 单、待处理 3 单。
- [x] 待审核资料改为审核统计接口 `pending + processing`,审核完成后从工作台同步减少;不再使用固定 Demo 数字。
验收:同一对象三端一致,编号可读且唯一,统计可追溯到同一组演示数据。
## 任务 3:逐条业务闭环复验
涉及检查:红娘服务管理页面、`miniapp/pages/matchmaker-workbench/`、服务详情/转介/推荐页面和相应后端接口;复用 `tests/miniapp/matchmaker_*` 与现有后端测试。
- [ ] 管理端分配服务 → 红娘端出现对象 → 查看详情 → 新增跟进 → 管理端记录回写。
- [ ] 提交完成服务 → 按现有确认规则完成 → 管理端状态与统计更新;不跳过已确认的用户确认步骤。
- [ ] 发起推荐 → 用户端查看并自行处理 → 红娘端推荐进展更新;不以推荐直接创建聊天。
- [ ] 发起转介 → 有权接收人员处理 → 两端状态一致,非本人范围默认拒绝。
- [ ] 红娘申请联系授权 → 管理端“红娘服务”内审批 → 用户单独确认 → 限时可用 → 撤销后拒绝披露。
- [ ] 用另一名红娘或无权限操作员尝试访问上述对象,确认无越权及敏感字段泄露。
- [ ] 每条记录操作前后状态、接口结果、脱敏对象编号和界面证据;重复操作不新增重复业务记录。
验收:每条链路均有可复查结果;页面有入口、可操作、落库且另一端可看到变化。
## 任务 4:回归、演示预案与阶段报告
输出:`docs/Phase-demo-closeout-Completion-Report-2026-10-13.md`、`docs/DEMO-WALKTHROUGH-2026-10-13.md`;根据本轮证据更新 `docs/STATUS.md` 的当前结论,不删除历史。
- [ ] 在 backend 执行 `mvn test`,记录总数、失败、错误、跳过数。
- [ ] 在 admin-web 执行 `pnpm run type-check` 和 `pnpm run build`。
- [ ] 按项目现有命令执行小程序类型检查、结构守卫及本阶段相关行为测试。
- [ ] 对本次修改执行 `git diff --check`;不运行带 --fix 的全仓 lint。
- [ ] 整理演示顺序、账号角色、入口、预期结果、必要截图和出错恢复办法,不在文档保存密码或密钥。
- [ ] 验证演示数据保留且容器正常;只在明确服务范围和恢复方式后开展必要重启验证。
- [ ] 出具逐项 PASS/PARTIAL/FAIL/NOT_VERIFIED 与演示 GO/CONDITIONAL GO/NO-GO;演示通过不等于生产上线通过。
## 后续独立阶段
演示验收结束后,再按既有 Phase 24~26 执行真实用户 UAT、运营素材替换和生产部署验收。真实微信环境、域名/HTTPS、备份恢复及正式上线检查不能用演示数据验证代替。本计划不包含未批准的死代码退役或全项目重构。
@@ -0,0 +1,214 @@
# 全平台业务展示编号统一实施计划
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 让所有面向用户或跨角色展示的人员、任务、活动和业务记录 ID 使用 13 位稳定业务编号,并确保 Web、小程序和运营 API 的展示一致。
**Architecture:** 保留 PostgreSQL UUID 主键、外键、权限与路由寻址;为公开展示实体持久化业务编号。以 PostgreSQL 原子计数器按前缀和上海日期分配编号,在实体创建事务中写入;后端 DTO 同时提供内部 ID 与公开展示字段,前端只渲染公开字段。
**Tech Stack:** Java 21、Spring Boot、MyBatis-Plus、PostgreSQL、Flyway、Vue 3、TypeScript、微信原生小程序、Node.js 行为测试、Docker Compose。
**Spec:** `docs/superpowers/specs/2026-10-14-global-public-id-design.md`
## Global Constraints
- 公开编号严格使用 `2 位大写字母前缀 + Asia/Shanghai YYYYMMDD + 3 位序号`,共 13 位。
- 用户 `YH` 按注册日和性别分别排名,男性序号奇数、女性序号偶数;红娘 `HN`,其他工作人员 `GL`,任务 `RW`,活动 `HD`。
- UUID 主键、外键、JWT subject、数据范围、权限校验、幂等语义和既有 UUID API 路由保持不变。
- 推荐对象、被推荐人、被举报人和活动参与者统一展示用户 `YH` 编号。
- 任意用户可见页面、弹窗、导出和小程序不得渲染原始 UUID;不可用中文占位掩盖接口漏字段,必须修 DTO/查询。
- 不覆盖或回滚开始任务前工作区的任何修改;只提交本计划涉及的新改动。
- 不添加第三方依赖;后端唯一编号由 PostgreSQL 并发安全地产生。
---
## 文件结构与责任
- `backend/src/main/resources/db/migration/V060__add_global_public_display_ids.sql`:为业务实体增加公开编号列/计数器,并为现存数据确定性回填和建立唯一索引。
- `backend/src/main/java/com/danyang/match/platform/shared/id/`:编号前缀、长度、日期与原子分配服务;只新增小型领域工具,不重构 UUID 基础设施。
- 各领域 Entity、Mapper、Service、DTO:在创建事务中写入公开编号;查询以 JOIN 取关联用户/操作员的展示编号。
- `backend/src/test/java/com/danyang/match/platform/shared/id/` 与领域测试:格式、奇偶、并发、迁移、DTO 白名单和越权行为测试。
- `admin-web/src/modules/`:替换直接渲染 UUID 的列、详情、表单和导出;交互继续传内部 ID。
- `miniapp/pages/` 与 `miniapp/services/`:只显示公开编号,动作请求继续用内部 ID。
- `docs/DEMO-VALIDATION-2026-10-13.md`:追加编号回填与双端展示验收证据,不改写历史记录。
## Task 1: 建立全仓公开 ID 展示清单与锁定测试
2026-10-14 执行结果:模板/关键动态文案盘点与检查器已完成,清单见 `../specs/2026-10-14-global-public-id-display-inventory.md`。检查器 7 项自检 PASS;114 个模板发现 31 个审查候选,全局展示检查仍 FAIL。Java 响应行为覆盖测试移至 Task 3,避免仅断言源码字符串。预约 YY 前缀待用户确认后进入迁移实现。
**Files:**
- Create: `backend/src/test/java/com/danyang/match/platform/shared/id/PublicDisplayIdCoverageTest.java`
- Create: `tests/public-id-display-coverage.cjs`
- Inspect: `admin-web/src/modules/`、`miniapp/pages/`、各模块 Controller/DTO/Mapper、Flyway 迁移
- [ ] **Step 1: 建立清单和失败测试**
清单至少逐项记录:实体、UUID 列/关系、创建入口、API DTO、管理端页面、用户小程序页面、编号前缀、是否包含既有用户隐私权限。覆盖 `users`、`operators`、`activities`、`review_tasks`、`reports`、`matchmaker_services`、`matchmaker_recommendations`、`matchmaker_contact_authorizations`、`matchmaker_assignments`、`matchmaker_followups`、转介实体,以及搜索中发现的任何其他实际展示 UUID 的实体。
守卫测试扫描已登记的 Web Vue 与小程序 WXML/TS/JS 文件,拒绝把 `operatorId`、`userId`、`targetUserId`、`activityId`、`serviceId`、`recommendationId` 等内部 UUID 直接插值到可见模板;允许它们用于事件、路由和 API 参数。测试对明确的 display 字段白名单断言。
- [ ] **Step 2: 运行测试确认暴露当前差距**
Run: `node tests/public-id-display-coverage.cjs`
Expected: FAIL,报告仍直接显示 UUID 的具体文件与模板位置。
- [ ] **Step 3: 固化清单与覆盖测试**
将前置检查清单保存到 `docs/superpowers/specs/2026-10-14-global-public-id-display-inventory.md`;确认每个展示 ID 均映射到规格中已有前缀。若发现需新增前缀或改变既有 API 路由参数,暂停后续实现并修订规格等产品确认。
- [ ] **Step 4: 运行测试**
Run: `node tests/public-id-display-coverage.cjs`
Expected: 检查器自检 PASS;展示扫描在遗留问题修复前保持 FAIL,不将已知问题豁免为全局 PASS。
## Task 2: 编号分配器、字段迁移和历史回填
**Files:**
- Create: `backend/src/main/resources/db/migration/V060__add_global_public_display_ids.sql`
- Create: `backend/src/main/java/com/danyang/match/platform/shared/id/PublicDisplayId.java`
- Create: `backend/src/main/java/com/danyang/match/platform/shared/id/PublicDisplayIdAllocator.java`
- Create: `backend/src/main/java/com/danyang/match/platform/shared/id/PublicDisplayIdMapper.java`
- Modify: `backend/src/main/java/com/danyang/match/platform/user/UserDisplayNumber.java`
- Modify: 相关 entity,至少 `User.java`、`Operator.java`、`Activity.java`、审核/举报/红娘相关 entity
- Create: `backend/src/test/java/com/danyang/match/platform/shared/id/PublicDisplayIdTest.java`
- Create: `backend/src/test/java/com/danyang/match/platform/shared/id/PublicDisplayIdAllocatorTest.java`
- Modify: `backend/src/test/java/com/danyang/match/platform/deployment/MigrationValidationTest.java`
- Modify: `backend/src/test/resources/schema-h2.sql`
- [ ] **Step 1: 编写编号格式和分配器失败测试**
测试 `YH20261014001`、`YH20261014002` 的用户奇偶规则,普通记录格式 `RW20261014001`;非法前缀、日期、序号、用户性别、序号越过 999 必须拒绝。PostgreSQL mapper 测试以并发任务申请同一前缀同一天的编号,断言数量一致且全部唯一;禁止使用 `COUNT(*) + 1`。
- [ ] **Step 2: 运行定向测试确认失败**
Run: `cd backend; mvn -Dtest=PublicDisplayIdTest,PublicDisplayIdAllocatorTest test`
Expected: FAIL,因编号工具和 mapper 尚未实现。
- [ ] **Step 3: 添加持久化编号字段与回填**
新增迁移为清单内公开实体添加 `display_id`(用户沿用 `display_number`,工作人员沿用 `display_id`),建立 `public_display_id_counters(prefix, local_date, sequence_group, last_sequence)` 计数器表。迁移按 `Asia/Shanghai` 注册/创建日期及稳定次序回填:用户按实名性别分别排名并写入男奇女偶尾号;工作人员按角色决定 `HN/GL`;任务 `RW`;活动 `HD`;其余业务表按规格与覆盖清单中的前缀分表排名。回填完成后设置非空和部分唯一约束;软删除记录也保留其编号唯一性,不得复用。初始化计数器到每组已使用的最大序号。
- [ ] **Step 4: 实现原子分配器**
Mapper 使用 PostgreSQL 原子 UPSERT:普通编号按 `sequence_group=''` 每次加 1;用户编号按 `sequence_group=gender` 分别加 2,男性首值 1、女性首值 2。更新前检查生成值不超过 999;无返回值时抛明确容量异常。日期由 `Clock` 注入并按 `Asia/Shanghai` 转换。`UserDisplayNumber` 调整为接受已分配奇偶序号且支持三位尾号,避免自行计数。
- [ ] **Step 5: 运行后端定向测试与迁移验证**
Run: `cd backend; mvn -Dtest=PublicDisplayIdTest,PublicDisplayIdAllocatorTest,MigrationValidationTest test`
Expected: PASS;并发下无重复编号,迁移在空 H2 测试结构与 PostgreSQL 演示数据库验证通过。
## Task 3: 后端创建写入与展示 DTO 收口
**Files:**
- Modify: 各展示实体的 Mapper/Service/Controller/DTO,按 Task 1 清单逐项列出
- Modify: `backend/src/main/java/com/danyang/match/platform/matchmaker/mapper/MatchmakerContactAuthorizationMapper.java`
- Modify: `backend/src/main/java/com/danyang/match/platform/matchmaker/service/ContactAuthorizationService.java`
- Modify: `backend/src/main/java/com/danyang/match/platform/matchmaker/service/MatchmakerManagementService.java`
- Modify: 活动、审核、举报、审计、转介等清单中 Mapper 查询和响应 DTO
- Create: `backend/src/test/java/com/danyang/match/platform/shared/id/PublicDisplayIdResponseTest.java`
- Modify: 对应领域测试与 `backend/src/test/resources/schema-h2.sql`
- [ ] **Step 1: 为创建流程写回归测试**
对每类清单实体调用真实 Service 创建入口,断言同事务持久化 UUID 主键和正确前缀的公开编号;模拟编号分配失败,断言领域实体未写入。用户和工作人员 API 输出同时断言 `id` 仍为既有 UUID、`displayNumber/displayId` 是业务编号。
- [ ] **Step 2: 运行测试确认失败**
Run: `cd backend; mvn -Dtest=PublicDisplayIdResponseTest,MatchmakerContactAuthorizationTest,MatchmakerManagementReadTest test`
Expected: 新增编号断言失败,既有权限测试保持可执行。
- [ ] **Step 3: 接入创建事务与关联编号查询**
对每个实体创建 Service,在已有 `@Transactional` 中先分配编号再 insert;操作员编号依实际角色用 `HN/GL`。Mapper 查询只额外 JOIN 公开编号字段;DTO 增加语义明确的 `displayId`/`displayNumber` 和关联对象 `operatorDisplayId`、`userDisplayNumber`、`targetUserDisplayNumber`。contact authorization 不再把底层 `operatorId/userId` 作为展示字段使用。
推荐对象、被举报人、活动参与者和审核对象关联到 user profile 时,复用 `users.display_number`;查询必须保留现有数据范围、用户隐私白名单和防探测条件。列表只补展示字段,不扩大查询可见范围。
- [ ] **Step 4: 检查未覆盖 API 和 UUID 响应泄漏**
运行后端静态覆盖测试和针对 Controller JSON 的响应断言;确认审计记录实体引用只在有权限且可映射时返回业务编号,否则返回实体类型脱敏说明。搜索所有列表 DTO 对 UUID 的输出使用,逐项按清单修复,不修改内部写请求。
- [ ] **Step 5: 运行相关后端回归**
Run: `cd backend; mvn -Dtest=PublicDisplayId*,MatchmakerContactAuthorizationTest,MatchmakerAssignmentA1Test,MatchmakerManagementReadTest,Activity*,Review*,Report*,MigrationValidationTest test`
Expected: PASS;既有权限、事务、隐藏/软删除与错误语义不变。
## Task 4: 管理端只展示业务编号
**Files:**
- Modify: `admin-web/src/modules/matchmaker/MatchmakerManagementView.vue`
- Modify: `admin-web/src/modules/activity/ActivityInterestView.vue`
- Modify: `admin-web/src/modules/activity/ActivityCheckinView.vue`
- Modify: `admin-web/src/modules/operator/OperatorManagementView.vue`
- Modify: `admin-web/src/modules/audit/AuditLogView.vue`
- Modify: Task 1 清单识别的用户、举报、安全、审核、报名、活动、联系授权、转介等视图
- Modify: 对应 API 类型定义与 service adapter
- Modify: `tests/public-id-display-coverage.cjs`
- [ ] **Step 1: 为目标页面写展示行为测试**
使用虚拟 API fixture 分别提供 UUID 与展示编号;渲染断言应见 `HN...`、`YH...`、`HD...`、`RW...` 等展示编号且不见 UUID,点击详情/审批/筛选后请求仍携带原内部 UUID。
- [ ] **Step 2: 修复模板和交互控件**
表格/详情使用 DTO 的公开编号字段;推荐对象输入改为可搜索用户选择器,按公开用户编号和允许公开的基础资料搜索,提交时仍传选中对象内部 UUID。若缺展示编号,展示“编号待生成”并在接口测试中判为缺陷,不允许回退 UUID。
- [ ] **Step 3: 更新覆盖守卫并运行管理端检查**
Run: `cd admin-web; pnpm run type-check; pnpm run build; cd ..; node tests/public-id-display-coverage.cjs`
Expected: 类型检查、构建和 ID 展示守卫 PASS。
## Task 5: 小程序只展示业务编号
**Files:**
- Modify: Task 1 清单中用户卡片、活动详情/报名/签到、红娘工作台/服务详情/推荐进展、举报与安全、个人资料/认证等页面
- Modify: 必要的 `miniapp/services/*.js` response adapter
- Modify: `miniapp/types/index.ts` 与 `miniapp/types/index.d.ts` 的展示字段
- Create: `tests/miniapp/public_id_display_behavior_test.cjs`
- Modify: `tests/public-id-display-coverage.cjs`
- [ ] **Step 1: 写小程序字段展示失败测试**
使用接口响应 fixture 注入 `id/userId/targetUserId` UUID 和对应 `displayId/displayNumber`,断言 WXML 页面绑定展示字段、服务跳转和 Like/Pass/报名/举报动作仍提交 UUID;无展示编号时不把 UUID 作为空态回退值。
- [ ] **Step 2: 修正响应类型和页面绑定**
更新 TS 声明和各页面 WXML/JS,让列表、详情、确认弹窗、活动页面和举报确认中的公开文本只用业务编号;保留内部 ID 用于请求和路由。
- [ ] **Step 3: 运行小程序行为与结构检查**
Run: `node tests/miniapp/public_id_display_behavior_test.cjs; node tests/public-id-display-coverage.cjs; pnpm --dir miniapp run type-check`
Expected: PASS;另运行项目现有 WXML/WXSS 结构守卫和 matchmaker/活动相关测试。
## Task 6: 全量迁移、运行验收和文档证据
**Files:**
- Modify: `docs/DEMO-VALIDATION-2026-10-13.md`
- Modify: `docs/STATUS.md`
- Inspect: `infrastructure/docker-compose.yml`、运行中的 danyang Docker 服务
- [ ] **Step 1: 执行完整后端测试及迁移检查**
Run: `cd backend; mvn test`
Expected: 记录总数、失败、错误、跳过;全部失败/错误为 0。PostgreSQL 演示库迁移完成,检查每表编号无空值、无重复、长度正确,用户奇偶规则正确,计数器不小于已分配最大尾号。
- [ ] **Step 2: 执行 Web、小程序回归**
Run: `cd admin-web; pnpm run type-check; pnpm run build; cd ..; pnpm --dir miniapp run type-check; node tests/public-id-display-coverage.cjs`
Expected: 全部 PASS;执行现有小程序结构与相关行为测试。
- [ ] **Step 3: 演示环境 HTTP 和页面检查**
以演示账号读取联系授权、红娘服务/推荐、用户、活动、审核、举报接口,逐类抽查 UUID 与业务编号关系;确认权限拒绝样本仍拒绝。检查浏览器常用视图及微信开发者工具小程序核心页,页面无 UUID 可见文本,动作正常。
- [ ] **Step 4: 记录证据并完成阶段报告**
在 `docs/DEMO-VALIDATION-2026-10-13.md` 追加编号格式、各类数量、重复检测、旧号映射、测试输出摘要和目视验收结果;在 `docs/STATUS.md` 仅追加当前结论,不覆盖历史状态。运行 `git diff --check`,最终报告逐项 `PASS/PARTIAL/FAIL/NOT_VERIFIED`。
## 完成门禁
- 六个任务均有实现与独立测试证据;不得因前端隐藏列而遗漏后端公开 DTO。
- 演示 PostgreSQL 中公开编号检查 SQL 返回 0 空值(仅规格明确允许的未实名用户可空)、0 重复、0 格式错误。
- 联系授权截图展示 `HN...` 与 `YH...`;跨模块推荐、举报和活动同一用户编号相同。
- 所有 UUID 保留作内部键但不出现在面向用户的可见文本、导出或通知。
- 若既有客户端依赖公开 UUID 字段作为用户输入,应提供公开编号解析适配并做兼容测试;权限判断仍基于解析后的 UUID。
- 最终说明未执行的微信真机验收或不可执行测试,不将历史测试结果写成本轮证据。
@@ -0,0 +1,131 @@
# V1.1 下一阶段验证与发布准备计划
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 在现有微信真机、前端门禁和后端 916 项全量测试通过的基础上,补齐真实数据库并发、完整业务闭环、通知数据一致性和发布前冒烟验证。
**Architecture:** 保持模块化单体和 PostgreSQL Source of Truth。测试分为 H2 单元/集成测试、Docker PostgreSQL 真实数据库测试、运行中服务冒烟和人工 UAT 四层,任何一层的结果独立记录,不互相替代。
**Tech Stack:** Java 21、Spring Boot 3、Maven、PostgreSQL、Docker Compose、Vue 3、微信原生小程序、Edge。
**Spec:** `docs/善缘丹阳 V1.1 客户需求基线增量开发与修复计划.md`、`docs/善缘丹阳 V1.1 数据库与API增量设计.md`、`docs/STATUS.md`。
## Global Constraints
- 不清理、回滚或覆盖现有未提交改动。
- 不修改已通过真机验收的业务流程,除非新增验证复现出根因。
- PostgreSQL 是 Source of Truth;H2 只用于快速测试,不能替代真实数据库证据。
- Maven 测试容器继续使用阿里云镜像和 `--dns 223.5.5.5 --dns 114.114.114.114`,不关闭 TLS 校验。
- 管理端页面验收使用已安装的 Edge,不安装 Chrome/Chromium。
- 测试账号、密码和 Token 只通过环境变量注入,不写入仓库和日志。
---
### Task 1: 真实 PostgreSQL 并发测试
**Files:**
- Inspect: `backend/src/test/java/com/danyang/match/platform/concurrent.ConcurrentTests.java`
- Modify: `backend/src/test/java/com/danyang/match/platform/concurrent.ConcurrentTests.java`
- Modify: `backend/src/test/resources/application-test.yml`(仅在测试 profile 需要新增 PostgreSQL 开关时)
- Test evidence: `.mimosa/postgres-concurrency-test.log`
**Interfaces:**
- Consumes: Docker Compose PostgreSQL、现有服务层接口和测试数据清理机制。
- Produces: `CI=true` 下可执行的 Like 并发和活动容量竞争测试;成功数、重复 Match 数和超容量数有数据库查询断言。
- [ ] **Step 1: 复核现有并发测试是否只是内存计数。**
- 确认测试使用真实 service/mapper、事务和 PostgreSQL 表,而不是 `AtomicInteger` 结果模拟。
- [ ] **Step 2: 建立隔离测试数据。**
- 每个测试使用唯一 run id;结束时按 run id 删除关系、活动报名和 Match 数据。
- [ ] **Step 3: 用 Docker PostgreSQL 执行并发测试。**
- 命令:`docker compose -f infrastructure/docker-compose.yml up -d postgres`
- 命令:`docker run --rm ... mvn -s /tmp/settings.xml -B -Dtest=ConcurrentTests -Denv=postgres test`
- [ ] **Step 4: 验证边界。**
- 断言同一对用户最终最多一个 active Match;活动 approved 数不超过 capacity;失败操作有明确错误码。
- [ ] **Step 5: 保存报告并更新 `docs/STATUS.md`。**
### Task 2: 完整注册到牵手 E2E
**Files:**
- Inspect: `backend/src/test/java/com/danyang/match/platform/core/CoreE2ETest.java`
- Modify: `backend/src/test/java/com/danyang/match/platform/core/CoreE2ETest.java`
- Test evidence: `.mimosa/core-e2e-postgres-test.log`
**Interfaces:**
- Consumes: 微信登录模拟 provider、实名认证、资料审核、推荐、Like、双向 Match、聊天和成功牵手服务。
- Produces: 一个真实 PostgreSQL 事务闭环测试,覆盖状态迁移和关键权限断言。
- [ ] **Step 1: 将 `@Disabled` 占位测试拆成真实步骤。**
- [ ] **Step 2: 每一步先断言数据库状态,再调用下一步。**
- [ ] **Step 3: 增加负向断言。**
- 未审核资料不能进入推荐;未 Mutual 不能聊天;单方成功牵手确认不能完成。
- [ ] **Step 4: 在 PostgreSQL profile 执行并保存日志。**
- [ ] **Step 5: 仅在完整链路通过后移除 `@Disabled`,否则保留并将状态标记为 `NOT_VERIFIED`。**
### Task 3: 通知数据转换告警治理
**Files:**
- Inspect: `backend/src/main/java/com/danyang/match/platform/notification/mapper/NotificationMapper.java`
- Inspect: `backend/src/test/java/com/danyang/match/platform/notification/*`
- Modify: 对应测试夹具或 schema 文件;只有复现业务根因时才修改生产代码。
- Test evidence: `.mimosa/notification-fixture-test.log`
**Interfaces:**
- Consumes: `notifications.user_id` 的实际 PostgreSQL/H2 类型和通知 mapper 参数类型。
- Produces: 不再出现 `u-notif-guard` 这类类型转换告警;通知幂等、落库和查询断言保持通过。
- [ ] **Step 1: 对照 Flyway PostgreSQL schema 和 `schema-h2.sql` 的 user_id 类型。**
- [ ] **Step 2: 定位夹具使用字符串 ID 的测试用例。**
- [ ] **Step 3: 优先修正测试夹具为合法 UUID;若业务确实支持非 UUID,再修正 mapper 类型契约。**
- [ ] **Step 4: 重跑通知相关测试和全量 Maven 测试。**
- [ ] **Step 5: 在报告中区分“日志告警已消除”和“业务通知真实发送”两种结论。**
### Task 4: 运行中服务发布前冒烟
**Files:**
- Use: `tests/public-id-web-live.cjs`
- Use: `tests/admin-dashboard-behavior.cjs`
- Use: `scripts/miniapp-compile-check.mjs`
- Create: `.mimosa/release-smoke-20261015.log`
- Update: `docs/STATUS.md`
**Interfaces:**
- Consumes: Docker 中运行的 backend、PostgreSQL、Redis、nginx、admin-web;Edge 浏览器。
- Produces: 登录、首页统计、红娘服务、联系授权审批、公开编号、未登录 401、关键页面导航的可复现结果。
- [ ] **Step 1: 备份演示库并记录 Flyway 版本。**
- [ ] **Step 2: 重启整套 Docker 服务并检查健康端点。**
- [ ] **Step 3: 用 Edge 执行管理端页面验收。**
- [ ] **Step 4: 执行 API 冒烟并记录状态码、响应 success/code,不记录 Token。**
- [ ] **Step 5: 验证服务重启后登录、编号查询和工作台统计仍可用。**
### Task 5: 用户 UAT 与发布决策
**Files:**
- Use: `docs/STATUS.md`
- Use: `docs/PENDING_DECISIONS.md`
- Create: `docs/RELEASE-READINESS-2026-10-15.md`
**Interfaces:**
- Consumes: 微信真机复验、Edge 管理端冒烟、后端和前端测试报告。
- Produces: `GO`、`CONDITIONAL GO` 或 `NO-GO` 决策,以及剩余 P0/P1 清单。
- [ ] **Step 1: 由用户在微信开发者工具复验红娘登录、工作台、服务详情、跟进、完成服务、联系授权审批。**
- [ ] **Step 2: 使用演示数据走一遍用户确认服务 → 管理端完成服务 → 统计回写闭环。**
- [ ] **Step 3: 核对首页数字是否来自接口,而非静态展示。**
- [ ] **Step 4: 记录未完成项:第三方开放、限流阈值、真实微信支付/实名服务等范围外能力继续保持 `NOT_IMPLEMENTED` 或 `NOT_VERIFIED`。**
- [ ] **Step 5: 形成发布决策;没有真实 PostgreSQL 并发和完整 E2E 证据时不得给出正式生产 GO。**
## 暂不执行的范围
- 不实现第三方 API Key/OAuth、开放 OpenAPI、调用配额或新的支付能力;这些属于已登记的范围扩张决策。
- 不安装 Chrome/Chromium,不用浏览器替代微信真机验收。
- 不进行大规模重构、分支清理或未授权数据库数据改写。
## 推荐执行顺序
1. Task 3(先消除测试夹具告警)
2. Task 1(真实 PostgreSQL 并发)
3. Task 2(完整 E2E)
4. Task 4(运行中服务冒烟)
5. Task 5(用户 UAT 与发布决策)
@@ -0,0 +1,124 @@
# V1.1 可发布条件实施计划
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 在不扩大业务范围的前提下,完成丹阳公益婚恋平台 V1.1 的发布前验证,并输出可复现的 `GO`、`CONDITIONAL GO` 或 `NO-GO` 决策。
**Architecture:** 保持模块化单体、PostgreSQL Source of Truth 和现有 Docker Compose。验证分为代码测试、真实 PostgreSQL、运行中服务、人工 UAT、运维发布五层;任一层的结果不替代其他层。
**Tech Stack:** Java 21、Spring Boot 3、PostgreSQL 16、Redis、Docker Compose、Vue 3、微信原生小程序、Edge、Maven 阿里云镜像。
**Spec:** `docs/superpowers/plans/2026-10-15-next-phase-validation-roadmap.md`、`docs/STATUS.md`、`AGENTS.md`。
## Global Constraints
- 不清理、回滚或覆盖现有未提交修改。
- 不把 H2、内存模拟、Mock 微信或演示 Seed 结果写成生产验收证据。
- 不安装 Chrome/Chromium;管理端使用 Edge。
- 测试账号、密码、Token 只通过环境变量注入,不写入仓库或日志。
- 不修改生产业务逻辑,除非真实验证复现出根因并完成回归测试。
- 不执行不可逆数据库清理;所有演示数据操作前先备份。
---
### Task 1:发布基线与环境确认
**Files:**
- Inspect: `git status`、`infrastructure/docker-compose.yml`、`.env.example`、`docs/PENDING_DECISIONS.md`
- Create: `.mimosa/release-baseline-20261015.log`
- Modify: `docs/STATUS.md`
**Interfaces:**
- Produces:当前提交/工作区、Flyway 版本、容器健康状态、配置缺口清单。
- [ ] 检查工作区,不修改既有未提交文件。
- [ ] 检查 `.env` 必需变量是否存在,仅输出变量名,不输出值。
- [ ] 启动或复用完整 Docker 演示栈,确认 PostgreSQL、Redis、后端、管理端、Nginx 健康。
- [ ] 备份演示数据库并记录 Flyway 版本。
- [ ] 将缺失项分为代码可执行项和必须由用户/运营提供的条件。
验收:环境健康、备份文件存在、无敏感值进入日志。
### Task 2:真实 PostgreSQL 并发门禁
**Files:**
- Inspect/Modify:`backend/src/test/java/com/danyang/match/platform/concurrent.ConcurrentTests.java`
- Inspect/Modify:`backend/src/test/resources/application-test.yml`
- Create:`.mimosa/postgres-concurrency-test.log`
**Interfaces:**
- Consumes:隔离 PostgreSQL 数据库、真实 Service/Mapper。
- Produces:Like 并发无重复 active Match;活动报名/审核不超过容量;失败有明确业务错误。
- [ ] 为每次测试生成唯一 run id 和隔离用户/活动数据。
- [ ] 将内存 `AtomicInteger` 模拟替换为真实 Service/Mapper 调用。
- [ ] 执行同一目标的并发 Like 和超容量活动报名/审核。
- [ ] 查询 PostgreSQL 结果,断言重复 Match 为 0、approved 数不超过 capacity。
- [ ] 清理本次 run id 数据并保留日志。
验收:真实 PostgreSQL 测试通过;否则标记 `NOT_VERIFIED`,不得给正式生产 GO。
### Task 3:完整业务闭环 E2E
**Files:**
- Inspect/Modify:`backend/src/test/java/com/danyang/match/platform/core/CoreE2ETest.java`
- Create:`.mimosa/core-e2e-postgres-test.log`
**Interfaces:**
- Consumes:微信 Mock Provider、实名/资料审核、推荐、Like、双向 Match、聊天、牵手服务。
- Produces:真实 PostgreSQL 下可复现的注册到牵手闭环和负向权限断言。
- [ ] 拆解现有 `@Disabled` 占位测试。
- [ ] 每个步骤先查询数据库状态,再进入下一步。
- [ ] 增加未审核资料不能推荐、未 Mutual 不能聊天、单方确认不能完成的负向断言。
- [ ] 在隔离 PostgreSQL 数据库执行并保存日志。
- [ ] 只有完整链路通过才移除 `@Disabled`;否则保留并标记 `NOT_VERIFIED`。
验收:主流程和负向流程均通过。
### Task 4:运行中服务与前端发布冒烟
**Files:**
- Use:`tests/public-id-web-live.cjs`
- Use:`tests/admin-dashboard-behavior.cjs`
- Use:`scripts/miniapp-compile-check.mjs`
- Create:`.mimosa/release-smoke-20261015.log`
- Modify:`docs/STATUS.md`
**Interfaces:**
- Consumes:完整 Docker 栈、Edge、微信开发者工具。
- Produces:登录、工作台、红娘服务、授权审批、公开编号、401、重启恢复证据。
- [ ] 执行后端健康、管理端 `/admin/`、未登录 401 和公开编号 API 冒烟。
- [ ] 用 Edge 验证管理端登录、工作台统计、红娘服务、服务详情、跟进、完成服务、联系授权审批。
- [ ] 用演示数据走用户确认服务到管理端完成服务的闭环,核对统计回写。
- [ ] 重启后端和前端服务,重复登录、工作台和编号查询。
- [ ] 运行小程序编译检查并由用户在微信开发者工具/真机完成红娘端关键路径复验。
验收:核心页面、接口和重启恢复均通过。
### Task 5:生产配置、备份恢复和人工发布条件
**Files:**
- Inspect:`infrastructure/docker-compose.prod.yml`、`infrastructure/scripts/backup.sh`、`infrastructure/scripts/restore.sh`、`docs/legal/privacy-policy.md`、`docs/security/PIA.md`
- Create:`docs/RELEASE-READINESS-2026-10-15.md`
- Modify:`docs/STATUS.md`
**Interfaces:**
- Produces:发布条件矩阵、剩余 P0/P1、最终 `GO/CONDITIONAL GO/NO-GO`。
- [ ] 验证生产配置关闭 Mock 微信、演示 Seed、Debug、Swagger,并使用注入密钥。
- [ ] 执行加密备份和干净环境恢复演练,记录数据库校验结果。
- [ ] 验证 HTTPS、域名、监控、日志、回滚目标和端口暴露。
- [ ] 核对隐私政策法务确认、微信小程序审核、运营真实内容和待决策项。
- [ ] 形成发布决策:全部 P0 通过才允许 `GO`;有人工条件未完成则 `CONDITIONAL GO`;真实数据库/E2E/安全门禁缺失则 `NO-GO`。
验收:发布报告包含每项证据、负责人、阻塞原因和下一步。
## 执行顺序
1. Task 1:基线和环境
2. Task 2:真实 PostgreSQL 并发
3. Task 3:完整 PostgreSQL E2E
4. Task 4:运行中服务和人工验收
5. Task 5:生产门禁和发布决策
@@ -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 实测。