536 lines
36 KiB
Markdown
536 lines
36 KiB
Markdown
# 后端接口缺口与首位成员阻塞清单
|
||
|
||
更新日期:2026-07-24
|
||
适用范围:家谱 APP 前端(`jiapuapp`)与 APP API 合同维护
|
||
|
||
## 目的与边界
|
||
|
||
本文供后端确认接口 owner、DTO 和测试数据,不要求前端猜测字段或用本地数据绕过接口。下文的“需要”分为两种:
|
||
|
||
- **已有接口但不可闭环**:路径和当前参数已存在,需修复服务端行为或补全可消费的 DTO。
|
||
- **缺少业务 owner**:现有 APP OpenAPI 没有该页面所需的读取/写入 operation;需要后端和产品先确定资源归属,再发布合同。
|
||
|
||
除非下文明确写为“当前已声明字段”,字段名、枚举、分页形式和响应结构都由后端在 APP OpenAPI 中一次性定义;前端不会从其他模块、PC 接口或示例数据推断。
|
||
|
||
## 通用请求约束
|
||
|
||
当前已声明的受保护 APP 接口均需要当前测试账号的认证会话和 `clientid` 请求头。若请求体含 `clientId`,其值必须与该 Header 一致。本文不记录真实 token、手机号或生产数据。
|
||
|
||
后端交付一个新 operation 或 DTO 时,请同时在 APP OpenAPI 的 YAML/JSON 中补齐:路径、HTTP 方法、鉴权、所有 path/query/body 参数、成功响应、可预期的 4xx/5xx 业务码及字段必填性。仅有 HTTP 200 而业务 `code` 为失败,不能视为接口成功。
|
||
|
||
## 一、缺少业务 operation 的页面
|
||
|
||
### F10 家族视频:缺视频读取 owner
|
||
|
||
现状:`pages/family/f10-video-list.vue` 已明确关闭。当前 OpenAPI 只声明:
|
||
|
||
```text
|
||
DELETE /genealogy/app/genealogies/{genealogyId}/videos/{videoId}
|
||
```
|
||
|
||
没有视频列表、详情、播放地址或发布 operation。删除接口不能反推出读取和播放合同。
|
||
|
||
当前页面入口可提供的业务上下文只有:
|
||
|
||
| 参数语义 | 来源 | 状态 |
|
||
| --- | --- | --- |
|
||
| `genealogyId` | 页面路由 | 已有,必需 |
|
||
| 当前登录账号 | 认证会话 | 已有,必需 |
|
||
| `clientid` | APP 请求头 | 已有,必需 |
|
||
|
||
请后端/产品先确认视频资源是否归属某个家谱。若是,最小可用的首个 operation 应是“读取该家谱可见视频列表”,并明确:
|
||
|
||
1. 是否分页;若分页,统一选择并声明 `pageNum/pageSize` 或 `cursor/pageSize` 之一,不能让前端猜测。
|
||
2. 每条记录的稳定视频标识,以及当前页面用于渲染列表所需的明确字段和字段类型。
|
||
3. 当前账号无权、资源不存在、空列表的响应语义。
|
||
|
||
视频详情、播放、发布、编辑、评论、点赞和分享目前没有对应页面表单或页面数据模型;若产品要开放这些能力,请为每项单独给出 operation 与 DTO,不要用相册或动态接口兼容代替。
|
||
|
||
### R09 人生大事:缺独立资源与归属定义
|
||
|
||
现状:`pages/records/r09-life-events.vue` 已明确关闭;APP/PC OpenAPI 中都未发现独立“人生事件/life event”资源。
|
||
|
||
从 R02 人物详情跳转 R09 时会传入 `genealogyId` 和 `personId`,但 R09 当前没有读取或写入表单,因此不能从 UI 推断事件到底是“人物专属”还是“家谱公共”。请后端/产品先在以下两种归属中选择一种:
|
||
|
||
| 资源归属 | 最少识别参数 |
|
||
| --- | --- |
|
||
| 人物专属事件 | `genealogyId`、`personId` |
|
||
| 家谱公共事件 | `genealogyId` |
|
||
|
||
归属确定后,请提供对应的列表/详情/创建或编辑 operation(以产品实际要开放的页面为准),并定义事件的必填业务字段、时间字段、排序/分页、权限和错误语义。归属未确定前,前端不会把成长记录、备忘或人物简介映射成人生大事。
|
||
|
||
### N02 消息详情:缺单条详情读取 operation
|
||
|
||
现状:当前已声明:
|
||
|
||
```text
|
||
GET /genealogy/app/notifications
|
||
POST /genealogy/app/notifications/{notificationId}/read
|
||
POST /genealogy/app/notifications/read-all
|
||
```
|
||
|
||
没有单条详情读取 owner,因此 `pages/notification/n02-message-detail.vue` 不展示 fixture 正文,也不从通知字段推断业务跳转。
|
||
|
||
建议后端补一个单条详情读取 operation;具体路径可由后端确定,但其最小输入和输出语义应为:
|
||
|
||
| 位置 | 需要项 |
|
||
| --- | --- |
|
||
| path 参数 | `notificationId`;应与现有“标记已读”接口使用同一通知标识语义 |
|
||
| 请求上下文 | 当前登录账号、`clientid` |
|
||
| 响应必需内容 | 通知标题、完整纯文本正文、发布时间、已读状态,以及供服务端内部定位的稳定通知标识 |
|
||
| 错误语义 | 当前账号无权/通知不存在时应明确失败,不能返回其他账号的通知 |
|
||
|
||
业务跳转不是本次最低需求。若后端未来要返回业务目标,需另行提供受权限约束的 `bizType → 前端路由键 + 必填参数 + 失效语义` 闭合字典;前端不会由 `bizId`、标题或正文猜路由。
|
||
|
||
## 二、已有路径但缺少可安全消费合同的页面
|
||
|
||
### M03 账号与安全:已解除(真实 profile 只读概览)
|
||
|
||
2026-07-26 已用测试账号真实读取 `GET /genealogy/app/auth/profile`。响应含 `phone`、`userNo`、`status`;M03 已接入并只显示本地掩码手机号、账号编号和账号状态。页面不把明文手机号写入路由、日志或缓存。
|
||
|
||
“设备列表”“登录记录”“安全等级”仍没有独立读取 owner,也不属于当前 M03 的数据模型;页面不会展示或推断这些内容。建议后端仍在 Apifox 为 profile 发布明确 DTO;如产品要展示上述资源,应分别定义 operation、字段、权限和保留期。
|
||
|
||
### M05 换绑手机号:已有最终 PUT,但缺可验证的安全链路与读取 DTO
|
||
|
||
当前 OpenAPI 已声明最终写入接口:
|
||
|
||
```text
|
||
PUT /genealogy/app/auth/phone
|
||
```
|
||
|
||
当前已声明的请求参数如下;它们是现状记录,不是前端新增猜测:
|
||
|
||
| 位置 | 字段 | 约束 |
|
||
| --- | --- | --- |
|
||
| Header | `clientid` | 必填 |
|
||
| Body | `clientId` | 必填,必须等于 Header `clientid` |
|
||
| Body | `phone` | 必填,新手机号 |
|
||
| Body | `smsCode` | 必填;当前导出合同为 4 位数字 |
|
||
| 请求上下文 | 当前登录账号 | 必填 |
|
||
|
||
当前 OpenAPI 还声明通用发码接口:
|
||
|
||
```text
|
||
POST /genealogy/app/auth/sms/code
|
||
```
|
||
|
||
其当前 body 必填字段为 `clientId`、`tenantId`、`grantType`、`sceneCode`、`phone`、`validToken`;换绑场景为 `APP_PHONE_CHANGE`。当前 profile 已能只读获取并掩码显示手机号,但没有经过人工确认的换绑专用 TAC/发码/校验闭环;M05 因而继续保持关闭,且不在无人值守时发送短信或换绑。
|
||
|
||
请后端确认并在同一版本交付:
|
||
|
||
1. `APP_PHONE_CHANGE` 的 `validToken` 获取、绑定手机号主体校验、过期和一次性消费语义;如通用发码接口不适合作为换绑 owner,请提供专用 operation,而不是要求前端复用未知场景。
|
||
2. 最终 PUT 成功、验证码错误/过期/重复、手机号已占用、无权限和结果未知时的明确 HTTP 与业务码语义。
|
||
|
||
本问题单只要求合同和人工可控的测试条件,不授权前端执行短信、换绑或其他账号安全写入。
|
||
|
||
## 三、已有接口但被服务端 `code:500` 阻断的成员页面
|
||
|
||
这不是“缺接口”,而是首位成员无法创建导致没有真实 `personId`。阻断请求为:
|
||
|
||
```text
|
||
POST /genealogy/app/genealogies/{genealogyId}/lineage/persons
|
||
```
|
||
|
||
当前已验证的最小请求:
|
||
|
||
| 位置 | 参数 | 值/约束 |
|
||
| --- | --- | --- |
|
||
| Path | `genealogyId` | 可访问的测试家谱 ID |
|
||
| Header | `clientid` | 必填 |
|
||
| 请求上下文 | 当前测试账号 | 必填 |
|
||
| Body | `name` | 当前 `LineagePersonBody` 唯一 required 字段;非空成员姓名 |
|
||
| Body | `generation` | 首位成员固定为整数 `1` |
|
||
|
||
2026-07-26 又从 T04 页面填写了可安全收集的全量资料并真实提交:姓名、人物编号、示例字典值、排序、别名、字辈、生卒日期、生卒地、安葬地、简介、备注;HTTP `200`,业务仍返回 `code:500 / 发生未知异常,请联系管理员`。首位成员不应伪填 `fatherId`、`motherId`、`relationName`;`appUserId` 缺同类型候选映射,头像 `avatarOssId` 仍受 19 位 `ossId` 类型冲突阻断。`sex`、`birthLunar`、`deathLunar`、`personStatus` 虽为可选,但 Apifox 仅称项目字典值、无枚举,页面不能把猜测的代码或农历文本作为正式交互。
|
||
|
||
已复现结果:最小请求与上述全字段页面请求均为 HTTP 层成功、业务响应 `code:500`;随后读取世系树仍为空。
|
||
|
||
请后端处理:
|
||
|
||
1. 查询该请求的异常栈,以及空世系创建首位成员所需的家谱/租户初始化条件。
|
||
2. 修复后使该最小合法请求返回业务成功,并返回可读取的成员结果(至少可取得稳定 `personId`)。
|
||
3. 以同一测试家谱验证后续读取:世系树、成员目录分页、成员详情均能读到该成员。
|
||
4. 若暂不能修复,请提供当前测试账号有访问权限的测试 `genealogyId` 与真实 `personId`,供只读和允许写入的回读验证;不要提供生产数据。
|
||
|
||
解锁范围为 T03–T08、R01–R02:成员详情、首位成员/亲属创建、编辑、排行、成员目录与成员状态等。已有读取/写入路径应在取得真实 `personId` 后按页面顺序验证,不应改成 mock 或本地假成功。
|
||
|
||
## 四、后端回传模板
|
||
|
||
请每个问题按下列项目回复,便于前端不重做已接线部分:
|
||
|
||
```text
|
||
页面/问题:
|
||
资源 owner:
|
||
APP operation(HTTP 方法 + 路径):
|
||
鉴权和 clientid 要求:
|
||
path/query/body 参数(字段、类型、必填、枚举/范围):
|
||
成功响应 DTO(字段、类型、必填):
|
||
错误响应(HTTP 状态 + 业务 code + 可展示文案):
|
||
分页/排序/权限语义(如适用):
|
||
可使用的测试 genealogyId / personId(仅测试数据):
|
||
OpenAPI YAML/JSON 更新版本:
|
||
```
|
||
|
||
前端收到更新后的合同和测试数据后,会先做最小浏览器真实请求,并以服务端成功响应后的列表/详情回读作为验收依据;样式问题另在模拟器复核。
|
||
|
||
## 五、A01 密码登录:已解除
|
||
|
||
2026-07-25 已在桌面版 Apifox 核对并用测试账号直连验证。最新已发布合同如下:
|
||
|
||
| 位置 | 字段 |
|
||
| --- | --- |
|
||
| Header | `clientid` |
|
||
| Body | `grantType=password`、`tenantId`、`phone`、32 位 MD5 `password`;`validToken` 仅在验证中心策略开启时必传 |
|
||
|
||
`clientId` 与 `sceneCode` 不再属于密码登录 body:后端根据 `POST /genealogy/app/auth/login` 绑定 `APP_PASSWORD_LOGIN` 场景。前端先查询 `GET /genealogy/app/auth/verification/password-login/require`;服务端返回 `required:false` 时不伪造滑块或票据,直接提交上述 body;返回 `required:true` 时才完成验证中心 challenge/verify 并提交真实 `validToken`。
|
||
|
||
实际结果:`password-login/require` 返回 `HTTP 200 / code:200 / required:false`;随后密码登录返回 `HTTP 200 / code:200`,响应含 `access_token`。本项不再是后端阻塞。
|
||
|
||
## 六、2026-07-25 Apifox 认证动作合同更新(已接入)
|
||
|
||
Apifox 当前“家谱”项目新增并发布了下列 APP 认证动作接口;本地旧 `APP.openapi.json/yaml` 尚未同步这次导出,不能再作为认证链的 source of truth:
|
||
|
||
```text
|
||
GET /genealogy/app/auth/verification/{operationCode}/require
|
||
POST /genealogy/app/auth/verification/{operationCode}/challenge
|
||
POST /genealogy/app/auth/verification/{operationCode}/verify
|
||
POST /genealogy/app/auth/sms/{operationCode}/code
|
||
```
|
||
|
||
`operationCode` 的已发布枚举为:
|
||
|
||
```text
|
||
password-login | sms-login | register | forgot-password | phone-change | account-deactivate
|
||
```
|
||
|
||
合同要点:
|
||
|
||
| 操作 | Header | path/query/body |
|
||
| --- | --- | --- |
|
||
| 查询策略 | `clientid` | path `operationCode`;query `tenantId`、`subject` |
|
||
| 获取挑战 | `clientid` | path `operationCode`;body `tenantId`、`subject` |
|
||
| 校验挑战 | `clientid` | path 必须与挑战使用同一 `operationCode`;body `tenantId`、`subject`、`challengeId` 和验证码证据 |
|
||
| 发送短信 | `clientid` | path `operationCode`;body `tenantId`、`phone`、`grantType=sms`;仅服务端策略开启时提交 `validToken` |
|
||
|
||
所有新接口都明确禁止前端再提交 `clientId` 或 `sceneCode`;服务端按 APP 路由的当前激活绑定解析验证场景。
|
||
|
||
已做的最小真实验证(仅测试手机号、未发送短信):
|
||
|
||
| 请求 | 结果 |
|
||
| --- | --- |
|
||
| `GET …/verification/APP_SMS_LOGIN/require` | `HTTP 200`,业务 `code:500`:不支持的认证业务动作 |
|
||
| `GET …/verification/sms-login/require` | `HTTP 200`,业务 `code:200`,`required:true`,`TIANAI/SLIDER` |
|
||
| `GET …/verification/password-login/require` | `HTTP 200`,业务 `code:200`,`required:false`,服务端绑定 `sceneCode: APP_LOGIN` |
|
||
|
||
前端已将 A01/A04/A05 的验证、挑战、校验和发码链接到新路径;A01 密码登录使用 `password-login`,策略为 `required:false` 时直接调用最新密码登录 body;返回 `required:true` 时携带真实 `validToken`。短信、注册、找回仍只在服务端返回 `required:true` 后完成 TAC 并携带真实 `validToken`。
|
||
|
||
已用测试账号验证 A01 密码登录的真实成功响应;本轮未发送短信、注册、改密、换绑、退出或执行其他敏感操作。
|
||
|
||
## 七、2026-07-25 桌面 Apifox 复核:仍缺 owner 与分页响应异常
|
||
|
||
以下结论直接来自桌面版 Apifox 当前 APP 目录,前端不以其他资源替代:
|
||
|
||
| 页面 | Apifox 当前 operation | 缺口 |
|
||
| --- | --- | --- |
|
||
| F10 家族视频 | 仅 `DELETE /genealogy/app/genealogies/{genealogyId}/videos/{videoId}` | 缺视频列表、详情、播放地址、发布/上传和编辑 owner |
|
||
| R09 人生大事 | “族务记录”目录仅有成长记录、备忘、亲友记录、功德记录四类 operation | 缺人生事件的列表、详情、创建、编辑、删除 owner |
|
||
| N02 消息详情 | 通知目录只有列表、单条标已读、未读数、全部标已读 | 缺单条消息详情读取 owner |
|
||
|
||
另发现一个后端响应异常,不影响当前 F01(F01 使用非分页 `GET …/feeds`,已真实返回数组),但会使已发布分页 operation 无法使用:
|
||
|
||
```text
|
||
GET /genealogy/app/genealogies/{genealogyId}/feeds/page?pageNum=1&pageSize=20
|
||
```
|
||
|
||
桌面 Apifox 将成功响应声明为 `PageResult`;同一测试账号实际得到 `HTTP 200 / code:200`,却完全省略 `data`。客户端的分页合同需要 `data.rows`(数组)和 `data.total`(整数),因此当前会精确拒绝为分页响应无效,不能把空 envelope 当成空列表。
|
||
|
||
请后端:
|
||
|
||
1. 为 F10、R09、N02 分别提供独立 APP operation 与完整 DTO;不要让前端复用相册、成长记录或通知列表字段。
|
||
2. 修复 `feeds/page` 成功响应,使 `data.rows` 和 `data.total` 与 Apifox `PageResult` 一致;若该 operation 已废弃,请在 Apifox 明确下线,避免保留可调用但无结果的合同。
|
||
|
||
## 八、2026-07-26 真实 H5 图片上传:`ossId` 跨接口类型冲突
|
||
|
||
本项使用测试家谱的 F09「添加照片」页面、浏览器文件选择器和本地真实图片
|
||
`static/assets/foundation/transparent/auth-login-outline.png` 验证;没有使用 mock、fixture 或手工伪造上传回执。
|
||
|
||
实际请求链路均返回 `HTTP 200 / code:200`:
|
||
|
||
```text
|
||
POST /genealogy/app/files/resumable/init
|
||
POST /genealogy/app/files/resumable/chunk
|
||
POST /genealogy/app/files/resumable/complete
|
||
```
|
||
|
||
`complete` 的真实响应为(URL 已省略):
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"data": {
|
||
"fileName": "auth-login-outline.png",
|
||
"ossId": "2081232520259612673"
|
||
}
|
||
}
|
||
```
|
||
|
||
该 `ossId` 是 19 位雪花标识,必须以字符串原样传递。它大于 JavaScript `Number.MAX_SAFE_INTEGER`;转换为 number 会丢失精度。当前照片创建 DTO 却把 `ossId` 声明为 `int64` 数值,F09 无法在不篡改标识的前提下提交:页面已经明确提示并停止在关联业务数据之前。
|
||
|
||
受影响的是所有“上传回执 → 业务表单”页面,而不只是 F09:动态配图、谱文封面、相册封面/照片、家谱封面、礼仪图片、备忘附件等。前端不会把字符串转为不安全 number,也不会提交截断后的 ID。
|
||
|
||
请后端在同一 APP OpenAPI 版本统一文件标识合同:
|
||
|
||
| 位置 | 需要确定的合同 |
|
||
| --- | --- |
|
||
| 上传完成响应 | `ossId` 保持十进制字符串(现网已如此返回),并明确为稳定文件标识 |
|
||
| 所有消费该标识的 APP 请求 DTO | 对应字段统一接受同一十进制字符串;不要在 JSON 中要求前端传 `int64` 数值 |
|
||
| 响应 DTO 与字段示例 | 同步明确字符串类型、正整数词法约束和真实大于 `2^53-1` 的示例 |
|
||
| Apifox 发布内容 | 更新照片创建、封面、附件等所有相关 operation,避免上传接口和业务接口各自定义一套类型 |
|
||
|
||
后端发布统一合同后,请提供仅测试数据可写入的家谱上下文。前端会重新从 F09 页面选择真实文件,完成“上传 → 创建照片 → 相册列表/详情回读”验收;在此之前不会猜测创建照片接口是否私下兼容字符串。
|
||
|
||
## 九、2026-07-26 Apifox 全量复核:贺礼邀约缺少受邀人候选来源
|
||
|
||
桌面 Apifox 当前已发布以下 4 个“贺礼邀约” operation:
|
||
|
||
```text
|
||
PUT /genealogy/app/genealogies/{genealogyId}/ceremonies/{ceremonyId}/invitees
|
||
GET /genealogy/app/genealogies/{genealogyId}/ceremonies/{ceremonyId}/invitations
|
||
PUT /genealogy/app/genealogies/{genealogyId}/ceremonies/{ceremonyId}/invitations/me
|
||
GET /genealogy/app/genealogies/ceremony-invitations/mine
|
||
```
|
||
|
||
其中请求合同已明确,前端不会补猜字段:
|
||
|
||
| operation | 必填参数 | 可选参数 | 备注 |
|
||
| --- | --- | --- | --- |
|
||
| 替换活动受邀人 | path `genealogyId`、`ceremonyId`;body `inviteeUserIds` | 无 | `inviteeUserIds` 是唯一业务用户 ID 的完整数组;空数组表示取消全部尚未响应的邀请 |
|
||
| 查询活动邀请名单 | path `genealogyId`、`ceremonyId` | 无 | 返回邀请记录列表 |
|
||
| 响应当前用户邀请 | path `genealogyId`、`ceremonyId`;body `inviteStatus` | 无 | 枚举仅允许 `ACCEPTED` 或 `DECLINED` |
|
||
| 查询我的活动邀请 | 无业务 path/body | 无 | 当前登录业务用户的有效邀请列表 |
|
||
|
||
当前 `CeremonyInvitationVo` 可读取字段为:`invitationId`、`genealogyId`、`ceremonyId`、`inviteeUserId`、`inviteStatus`(`PENDING` / `ACCEPTED` / `DECLINED` / `CANCELED`)、`inviteVersion`、`deliveredTime`、`readTime`、`responseTime`、`ceremonyTitle`、`ceremonyTime`、`location`、`locationAddress`、`longitude`、`latitude`。这些 ID 均为 `int64`,真实雪花 ID 必须统一允许十进制字符串传递,不能要求 H5 转为不安全的 JavaScript number。
|
||
|
||
### 阻塞点
|
||
|
||
R07 需要的是 `inviteeUserIds`(业务用户 ID),但当前 APP 家谱成员列表没有声明可供选择的业务用户 ID,也没有“可受邀用户候选列表” operation。`memberId`、`lineagePersonId` 和 `inviteeUserId` 是不同资源标识,前端不会用任一个替代另一个,也不会提供让用户手输未知业务 ID 的伪流程。
|
||
|
||
请后端在同一版 APP OpenAPI 中二选一,并提供仅测试数据:
|
||
|
||
1. 在现有“家谱成员列表/选项”成功 DTO 中明确返回稳定的 `appUserId`(或等价字段),并声明该字段就是 `inviteeUserIds` 的合法值;或
|
||
2. 新增“查询活动可邀请用户候选列表” operation,至少返回业务用户 ID、展示名、是否可邀请、不可邀请原因。
|
||
|
||
同时请确认 `int64` 业务用户 ID 在所有 APP JSON 请求/响应中使用十进制字符串合同,避免与第八节 `ossId` 相同的精度丢失问题。候选来源和字符串 ID 合同发布前,前端只接入邀请读取/响应的精确 API 方法,不会把“替换受邀人”伪装成可用页面功能。
|
||
|
||
## 十、2026-07-26 Apifox 路径修正:行政区划
|
||
|
||
桌面 Apifox 当前正式路径为:
|
||
|
||
```text
|
||
GET /genealogy/region/children?parentCode={parentCode}
|
||
GET /genealogy/region/path/{regionCode}
|
||
GET /genealogy/region/search?keyword={keyword}&level={level?}&limit={limit?}
|
||
GET /genealogy/region/{regionCode}
|
||
```
|
||
|
||
其中 `search.keyword` 必填;`search.level`、`search.limit` 可选;其余 `regionCode` path 参数必填,`children.parentCode` 可选。G03 原先错误使用了 `/genealogy/app/region/children`,已改为正式路径并在 H5 浏览器验证省、市、区三级均返回业务 `code:200`。其余 3 个 operation 尚无当前页面交互入口,待桌面 Apifox 补齐可消费的响应 DTO 后按实际页面需求接入;不会以 `additionalProperties` 的导出占位结构猜字段。
|
||
|
||
## 十一、2026-07-26 F03 真实点赞后缺少当前用户状态
|
||
|
||
测试账号通过 F03 动态详情页面执行了一次真实“点赞”(没有执行取消点赞或其他删除操作):
|
||
|
||
```text
|
||
POST /genealogy/app/genealogies/{genealogyId}/feeds/{feedId}/likes
|
||
```
|
||
|
||
该请求返回 `HTTP 200`。随后页面重新读取详情,`likeCount` 从 `0` 变为 `1`,说明服务端已写入点赞;但详情响应没有给出可用的当前用户点赞状态,前端读取到的 `likedByMe` 仍为 `false`/缺失,按钮继续显示“点赞”而不是“取消点赞”。
|
||
|
||
这不是前端可以用本地布尔值补齐的缺口:页面刷新后必须以服务端状态决定下一次应该调用 `POST /likes` 还是 `DELETE /likes`。当前合同会导致重复点击语义不明确,也无法安全展示已点赞状态。
|
||
|
||
请后端在以下 APP 读取 DTO 中统一提供当前登录用户维度的必填布尔字段 `likedByMe`(或同义且明确的字段),并与点赞写入立即一致:
|
||
|
||
```text
|
||
GET /genealogy/app/genealogies/{genealogyId}/feeds
|
||
GET /genealogy/app/genealogies/{genealogyId}/feeds/page
|
||
GET /genealogy/app/genealogies/{genealogyId}/feeds/{feedId}
|
||
```
|
||
|
||
字段必须是 `boolean`,不能以点赞总数、空值或仅他人点赞记录代替。后端发布后,前端会再从 F03 页面验证“点赞 → 详情回读为已点赞 → 仅在用户主动操作时取消点赞”的完整闭环。
|
||
|
||
前端已将缺失/非布尔值保留为“状态未知”,并在 F03 禁用点赞按钮、显示明确原因;不会再把它转换为 `false` 后重复发送点赞请求。
|
||
|
||
## 十二、2026-07-26 谱文分类列表缺少可消费的条目 DTO
|
||
|
||
桌面 Apifox 的正式 operation 为:
|
||
|
||
```text
|
||
GET /genealogy/app/genealogies/{genealogyId}/article-categories
|
||
```
|
||
|
||
请求仅要求 path `genealogyId`(以及认证 `clientid`),成功响应在当前桌面文档中标注为通用 `ListResult`,没有声明列表项字段模型、字段示例或 `categoryId` 的类型。F06 的创建谱文请求可选 `categoryId`,但前端不能在不知道“分类标识”和“分类展示名”字段的情况下把任意对象渲染成选择器。
|
||
|
||
请后端把该 operation 的 `data[]` 明确为具名 DTO,至少包含:
|
||
|
||
| 字段 | 合同要求 |
|
||
| --- | --- |
|
||
| `categoryId` | 稳定分类标识;若为 int64,APP JSON 统一使用十进制字符串 |
|
||
| `categoryName` | 非空展示名称 |
|
||
| `status` / `enabled` | 明确是否允许在新建谱文中选择;若不需要则明确只返回可选项 |
|
||
| `sortOrder` | 可选的稳定排序字段;若服务端已排序则在文档明确 |
|
||
|
||
在条目 DTO 发布前,F06 继续允许按现有创建合同不带 `categoryId` 发布,不会把导出文件里的通用对象或本地硬编码分类当作真实分类数据。
|
||
|
||
## 十三、当前全部已确认阻塞总表
|
||
|
||
本表是当前 APP 136 operation 审计的唯一汇总入口;详情、请求字段和回传模板见本文件对应章节,以及 `APP-136请求参数字段核对表-2026-07-26.md`。这里的“阻塞”不等于前端缺少调用代码:可能是 operation 根本不存在、响应 DTO 无法消费、服务端真实失败,或 H5 不存在安全参数来源。
|
||
|
||
| 编号 | 类别 | operation / 合同 | 影响页面 | 已验证事实 | 后端解除条件 |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| B01 | 缺 operation | 视频仅有 `DELETE /videos/{videoId}` | F10 | 无列表、详情、播放地址、创建、上传、编辑等 owner | 发布视频读取与发布完整 operation/DTO |
|
||
| B02 | 缺 operation | 人生大事无资源 owner | R09 | 族务目录只有成长、备忘、亲友、功德 | 明确人物专属或家谱公共归属后发布列表/详情/写入 DTO |
|
||
| B03 | 缺 operation | 通知仅有列表和标已读 | N02 | 无 `notificationId` 单条详情读取 | 发布单条详情读取及授权/错误语义 |
|
||
| B05 | 安全链路缺失 | `PUT /auth/phone` | M05 | 只有最终 PUT,缺经确认的当前账号读取、TAC/发码闭环 | 发布专用换绑验证合同与读 DTO;敏感写入仍需人工测试许可 |
|
||
| B06 | 服务端异常 | `POST /genealogies/{genealogyId}/lineage/persons` | T03–T08、R01–R02 | 2026-07-26 从 T04 页面分别以最小首位成员数据、以及包含编号/示例字典值/排序/生卒信息/简介备注的全字段资料真实提交,均为 HTTP `200` 但业务 `code:500 / 发生未知异常`,未生成本地或伪造 `personId`;同谱只读 `GET .../lineage/persons/options` 实测 `200 / data: []`,因此也没有可读取的真实人物候选 | 修复最小合法 body,返回并可读取真实 `personId` |
|
||
| B08 | ID 类型冲突 | 上传 complete 与所有消费 `ossId` 的 DTO | F02/F06/F07/F09/G03/G11/R04/R07/R08/R10/T04/M02 | 真实 complete 返回 19 位字符串,消费者声明 `int64` number | APP JSON 统一十进制字符串 `ossId`;同版更新示例与所有消费者 |
|
||
| B09 | 候选 ID 缺失 | `PUT .../ceremonies/{ceremonyId}/invitees` | R06/R07、我的邀请入口 | body 需要 `inviteeUserIds`,现有 member/person DTO 无同类型候选 | 公开 `appUserId` 对应关系或新增可邀请用户候选 operation |
|
||
| B10 | 当前用户状态缺失 | 动态列表/分页/详情 `likedByMe` | F03 | 实际点赞后数量变更,详情未给当前用户布尔状态 | 三个读取 DTO 均返回同步的 required boolean `likedByMe` |
|
||
| B11 | 条目 DTO 缺失 | `GET .../article-categories` | F06 | 只有通用 `ListResult`,无分类 ID/名称/状态/排序字段 | 发布 `categoryId`、`categoryName`、可选状态与排序 DTO |
|
||
| B12 | 页面交互待确认 | 行政区划 path/search/detail | G03/G11 后续回填、搜索 | 2026-07-26 复测已返回 `value`、`label`、`regionCode`、层级等真实条目;但当前产品页面没有搜索/路径回填入口 | 产品确认地区搜索与路径回填交互后接入页面;接口 DTO 不再阻塞 |
|
||
| B13 | 资源语义不能混用 | `members` 与 `lineage/persons` | 成员管理、R06/R07 | `memberId`、`personId`、`appUserId` 是不同资源,当前无独立成员管理页 | 提供成员管理页需求与稳定候选/映射 DTO,不得前端猜代 |
|
||
| B14 | 业务绑定 owner 缺失 | `POST /files/reference` | 所有附件业务 | 需要 `bizTable`、`bizId`、`bizField`,页面没有可信业务表/字段来源 | 后端为各业务资源声明文件绑定 owner,或明确由创建 DTO 原子绑定 |
|
||
| B15 | 枚举/候选缺失 | 多个 body 中的 `sex`、`birthLunar`、`deathLunar`、`personStatus`、`roleType`、`status`、`payType` 等 | T04/T05 及 T/M/G/R/F 写入扩展 | 2026-07-26 复核 `LineagePersonBody`:`birthLunar`、`deathLunar` 的含义是“日期是否农历”的项目字典值,不是农历日期文本;性别和人物状态也都是字典值。导出与桌面 Apifox 只给出示例 `0`,没有 value-label 枚举或字典 options operation,因此不能把输入框、农历日期文本或猜测的 `0/1` 映射留给用户 | 在 operation 详情给出完整 value-label enum,或发布字典 options operation;前端收到确定合同后统一改为选择器,并同步详情页的字典值展示 |
|
||
| B16 | 测试边界,不是接口缺失 | 短信、改密、换绑、注销、退出、删除、审核、支付 | A/M/G/F/R/N 全域 | 当前任务禁止执行这些敏感动作 | 仅在用户另行授权、测试账号与可回收数据齐备后执行真实写入 |
|
||
| B17 | 导出与实际校验冲突 | `POST /genealogy/app/files/resumable/init`(并影响 complete) | F02/F06/F07/F09/G03/G11/R04/R07/R08/R10/T04/M02 | 2026-07-26 真实 H5 上传:省略 `uploadId` 返回“上传ID不能为空”;以导出字段 `fileSize` 替代 `totalSize` 返回“文件大小不能为空”。实际可用请求为 `uploadId + totalSize`;秒传 `instant:true` 会合法返回 `uploadId:null` 与真实 `ossId` | 在桌面 Apifox 与可导出 OpenAPI 中统一请求/响应 DTO、required、示例及秒传分支;明确普通分片与秒传的 `uploadId` 可空规则 |
|
||
|
||
## 十四、真实浏览器请求与返回记录(供后端排查)
|
||
|
||
说明:以下均在测试账号、测试家谱中从 APP 页面发起;未记录账号密码、令牌或完整 `clientid`。所有请求均已携带运行时 `clientid`、测试账号登录态和 `genealogyId=2081191846772518914`。
|
||
|
||
### 1. B06:首位成员创建
|
||
|
||
接口:
|
||
|
||
```text
|
||
POST /genealogy/app/genealogies/2081191846772518914/lineage/persons
|
||
```
|
||
|
||
最小请求(2026-07-26,页面 T04):
|
||
|
||
```json
|
||
{
|
||
"name": "首位成员最小请求验证",
|
||
"generation": 1
|
||
}
|
||
```
|
||
|
||
实际返回:
|
||
|
||
```text
|
||
HTTP 200
|
||
{"code":500,"msg":"发生未知异常,请联系管理员","data":null}
|
||
```
|
||
|
||
页面结果:`保存失败 / 首位成员尚未保存 / 发生未知异常,请联系管理员`。
|
||
|
||
后端称已修复后的复测(2026-07-26,重新登录测试账号后从 T04 提交):
|
||
|
||
```json
|
||
{
|
||
"name": "后端修复验证首位成员",
|
||
"generation": 1
|
||
}
|
||
```
|
||
|
||
返回仍为:
|
||
|
||
```text
|
||
HTTP 200
|
||
{"code":500,"msg":"发生未知异常,请联系管理员","data":null}
|
||
```
|
||
|
||
因此 B06 仍未解除;本次不是会话过期导致的结论。首次请求得到 `code:401` 后已通过 A01 真实密码登录,重试才得到上述业务 `code:500`。
|
||
|
||
全字段诊断请求(同一页面、同一测试家谱;用于验证可选字段是否会改变异常,不是字段字典的最终验收):
|
||
|
||
```json
|
||
{
|
||
"name": "LineageFullBody0726",
|
||
"generation": 1,
|
||
"personNo": "P20260726001",
|
||
"sex": "0",
|
||
"generationName": "FullGen",
|
||
"aliasName": "FullBodyAlias",
|
||
"birthLunar": "1900-01-01",
|
||
"birthPlace": "TestBirthPlace",
|
||
"deathLunar": "2000-01-01",
|
||
"deathPlace": "TestDeathPlace",
|
||
"burialPlace": "TestBurialPlace",
|
||
"biography": "Full body browser submission verification",
|
||
"remark": "test only",
|
||
"personStatus": "0",
|
||
"birthDate": "2026-07-26",
|
||
"deathDate": "2026-07-26",
|
||
"sortOrder": 1
|
||
}
|
||
```
|
||
|
||
实际返回同样为:
|
||
|
||
```text
|
||
HTTP 200
|
||
{"code":500,"msg":"发生未知异常,请联系管理员","data":null}
|
||
```
|
||
|
||
特别说明:该诊断请求暴露出旧页面把 `birthLunar`、`deathLunar` 当作农历日期文本;Apifox 的真实语义是“是否农历”的字典值。不能把这一请求视为正确字典值示例,也不能要求前端据此猜选项。首位成员不应伪填 `fatherId`、`motherId`、`relationName`;`appUserId` 没有同类型候选,`avatarOssId` 被 B08 阻断。
|
||
|
||
随后读取:
|
||
|
||
```text
|
||
GET /genealogy/app/genealogies/2081191846772518914/lineage/persons/options
|
||
HTTP 200 / code:200 / data: []
|
||
```
|
||
|
||
因此 T01 没有成员数据并非前端空白占位:服务端尚未成功写入任何真实成员。
|
||
|
||
### 2. 初次验证记录(历史结果;以 2.1 的复测结论为准)
|
||
|
||
| 编号 | 接口与页面 | 实际请求值/返回值 | 结论 |
|
||
| --- | --- | --- | --- |
|
||
| B07 | `GET /genealogy/app/genealogies/{genealogyId}/feeds/page`,F01/F03 | 已按页面分页参数真实读取;HTTP `200`、业务 `code:200`,但响应没有 Apifox `PageResult` 所需的 `data.rows`、`data.total` | 无法安全分页或把空对象伪装为无动态 |
|
||
| B08 | `POST /genealogy/app/files/resumable/init`,F09 等上传页面 | 省略 `uploadId`:返回“上传ID不能为空”;将 `totalSize` 改为导出字段 `fileSize`:返回“文件大小不能为空”;实际可用字段为 `uploadId`、`fileName`、`fileMd5`、`totalSize`、`totalChunks`、`chunkSize`。秒传返回 `{"uploadId":null,"instant":true,"ossId":"2081232520259612673"}` | 文件服务返回 19 位字符串 ID,而业务 DTO 写 `int64` 数字,前端不能无损作为 JSON 数字提交 |
|
||
| B10 | 动态点赞,F03 | 已真实点赞,点赞数量变化;详情/列表未返回 `likedByMe` | 不能据数量推断当前用户是否已点赞,页面已禁用不确定状态下的再次写入 |
|
||
| B11 | `GET /genealogy/app/genealogies/{genealogyId}/article-categories`,F06 | HTTP `200`、业务 `code:200`、`data: []` | 无分类候选可供选择;同时合同没有分类条目字段定义 |
|
||
| B12 | 行政区划 children,G03/G11 | `GET /genealogy/region/children` 已可真实读取;path/search/detail 没有可消费的条目 DTO 和页面交互归属 | 不猜地区回填字段或新增搜索行为 |
|
||
| B17 | 分片上传初始化,F09 等 | 见 B08 的实际请求和返回;导出与服务端校验字段冲突 | Apifox 与导出必须先统一为唯一合同 |
|
||
|
||
### 2.1 后端称修复后的复测结果(2026-07-26)
|
||
|
||
| 编号 | 复测结果 | 当前结论 |
|
||
| --- | --- | --- |
|
||
| B06 | 重新登录后,T04 最小 body 仍返回 HTTP `200`、业务 `code:500`、`data:null` | 未修复 |
|
||
| B07 | `GET .../feeds/page?pageNum=1&pageSize=20` 现在返回根级 `total:1` 和 `rows:[...]`,不再是空 envelope | 分页数据已出现;但 `likedByMe` 返回字符串 `"1"`,B10 仍未修复 |
|
||
| B08 | F09 从真实图片文件上传到“已上传”成功;保存照片时前端收到真实 19 位文件 ID 后仍报“超出 APP 安全整数范围”,未发出照片创建请求 | 未修复,需统一字符串 `ossId` 合同 |
|
||
| B09 | 礼仪列表可读取,`GET .../ceremonies/{ceremonyId}/invitations` 与 `GET .../ceremony-invitations/mine` 均返回 `data:[]`;没有可提交的 `inviteeUserIds` 候选 | 未修复,仍缺 `appUserId` 候选/映射 |
|
||
| B11 | 谱文分类仍返回 `HTTP 200 / code:200 / data:[]` | 测试谱没有分类;仍需分类 DTO 与可用测试候选才能验证选择/写入 |
|
||
| B12 | `GET /genealogy/region/path/110101`、`GET /genealogy/region/110101`、`GET /genealogy/region/search?keyword=北京&limit=10` 均返回包含 `value`、`label`、`regionCode`、层级等字段的真实数据 | 后端已补齐可消费条目;待产品确认搜索/回填交互后接入页面 |
|
||
|
||
### 3. 未发起写入请求的原因(不是漏测)
|
||
|
||
| 编号 | 接口/功能 | 未发起的原因 | 后端需要提供 |
|
||
| --- | --- | --- | --- |
|
||
| B01 | 视频 F10 | 仅发布删除接口;没有列表、详情、播放、创建、编辑或上传 owner | 完整资源 operation 与 DTO |
|
||
| B02 | 人生大事 R09 | 没有资源 operation | 明确人物或家谱归属后的列表、详情、写入 DTO |
|
||
| B03 | 通知详情 N02 | 只有列表、标已读;没有按 `notificationId` 读取详情 | 单条详情接口及授权语义 |
|
||
| B05/B16 | 短信、改密、换绑、退出、注销、删除、审核、支付 | 属于本轮明确禁止的敏感动作 | 另行授权、测试账号和可回收数据后再测 |
|
||
| B09/B13 | 礼仪受邀人、成员绑定 | 请求需要 `appUserId`,现有 `memberId`、`personId`、`appUserId` 不能互相替代;没有候选映射 | 同类型候选接口或稳定映射 DTO |
|
||
| B14 | 文件业务引用 | 请求需要 `bizTable`、`bizId`、`bizField`,没有页面可信 owner | 各资源的文件绑定归属合同 |
|
||
| B15 | 性别、人物状态、出生/逝世是否农历等 | 需要选择器,但 Apifox 仅给示例 `0`,没有枚举、中文标签或字典 options 接口 | value-label 枚举或字典 options operation |
|
||
|
||
|
||
### 不应误标为阻塞的已完成项
|
||
|
||
- A01 密码登录、G03 创建家谱、家族动态/评论、谱文、相册、亲友往来、礼仪、成长记录、备忘、功德均已做过真实创建后的列表或详情回读。
|
||
- M03 账号与安全已真实读取当前 profile,并仅展示掩码手机号、账号编号和账号状态;设备与登录记录不在当前页面范围内。
|
||
- 4 条行政区划 operation 都已有 API owner;`children` 已在 G03/G11 页面真实读取,其余三条的阻塞是没有可安全消费 DTO/产品交互,不是路径不存在。
|
||
- 136 条 `method + path` 均可在桌面 Apifox 当前目录找到;数量差异不是“导出漏了 path”,而是页面数、功能入口、DTO 和安全参数来源不同。
|