Files
danyang-match/docs/superpowers/specs/2026-10-14-global-public-id-design.md
T
WorkBuddy 3c2b967274
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
release: freeze 2026-10-15 validated release baseline
2026-10-15 09:47:31 +08:00

81 lines
6.9 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.
# 全平台业务展示编号统一设计
## 背景与目标
用户在联系授权审批页看到红娘与用户 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 路由参数的情况应先更新本设计并取得确认。