docs: plan genealogy creation first batch
This commit is contained in:
@@ -0,0 +1,258 @@
|
||||
# 家谱创建首批 Implementation Plan
|
||||
|
||||
> **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:** 在约一小时的首批施工中冻结剩余家谱生命周期 PC 请求契约,并把 `profile-create-family.html` 从 pending 预览改成可用的真实创建家谱页面。
|
||||
|
||||
**Architecture:** `utils/ApiClient.js` 唯一拥有请求路径和 body 白名单;`public/js/genealogy-entry-pages.js` 扩展家谱创建的纯构造、校验、响应规范化和页面初始化;现有 `region-pages.js` 负责三级地区选项,`upload-pages.js` 负责生成 `coverOssId`。创建成功后只使用响应中的稳定 `genealogyId` 跳转到家谱主页。
|
||||
|
||||
**Tech Stack:** 静态 HTML、原生 JavaScript UMD、Axios、Node `node:test`。
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- 后端 `D:\WorkSpace\Java\Genealogy` 全程只读。
|
||||
- 只调用 `/genealogy/pc/**`,不调用 APP 或后台管理接口。
|
||||
- 不允许用户手填家谱 ID、申请 ID、用户 ID 或 OSS ID。
|
||||
- 每个生产行为必须先有失败测试并实际运行 RED。
|
||||
- 每个阶段完成后运行聚焦测试并更新 `docs/PC接口对接规划.md`。
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 冻结家谱生命周期 ApiClient 契约
|
||||
|
||||
**Files:**
|
||||
- Modify: `tests/api-client-contract.test.js`
|
||||
- Modify: `utils/ApiClient.js`
|
||||
|
||||
**Interfaces:**
|
||||
- Produces:
|
||||
- `createGenealogy(body)`
|
||||
- `applyToGenealogy(genealogyId, body)`
|
||||
- `myGenealogyJoinApplies()`
|
||||
- `pendingGenealogyJoinApplies(genealogyId)`
|
||||
- `auditGenealogyJoinApply(genealogyId, applyId, body)`
|
||||
- `cancelGenealogyJoinApply(applyId)`
|
||||
|
||||
- [ ] **Step 1: 写失败的路径和 body 白名单测试**
|
||||
|
||||
测试固定以下请求:
|
||||
|
||||
```js
|
||||
await client.createGenealogy({
|
||||
genealogyName: '汤氏家谱',
|
||||
surname: '汤',
|
||||
regionCode: '511622',
|
||||
coverOssId: '2062179707935264769',
|
||||
legacyField: 'drop'
|
||||
});
|
||||
|
||||
await client.applyToGenealogy(genealogyId, {
|
||||
applicantName: '申请人',
|
||||
phone: '19100000000',
|
||||
relationDesc: '族亲',
|
||||
applyReason: '申请加入',
|
||||
inviterUserId: 'drop-without-safe-source'
|
||||
});
|
||||
|
||||
await client.auditGenealogyJoinApply(genealogyId, applyId, {
|
||||
status: '1',
|
||||
auditRemark: '资料一致',
|
||||
legacyField: 'drop'
|
||||
});
|
||||
```
|
||||
|
||||
断言:
|
||||
|
||||
- 创建请求为 `POST /genealogy/pc/genealogies`,只保留 `genealogyName/surname/regionCode/ancestralHall/originPlace/addressDetail/coverOssId/intro/visibility/joinMode`。
|
||||
- 加入请求为 `POST /genealogy/pc/genealogies/{genealogyId}/join-applies`,本轮安全 PC 页面只保留 `applicantName/phone/relationDesc/applyReason`,不发送没有安全来源的 `inviterUserId`。
|
||||
- 我的申请、待审核、审核和撤销使用后端 PC Controller 的完整路径。
|
||||
- 审核 body 只保留 `status/auditRemark`。
|
||||
- 所有 path ID 拒绝不安全数字。
|
||||
|
||||
- [ ] **Step 2: 运行 RED**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
node --test --test-name-pattern "genealogy lifecycle" tests/api-client-contract.test.js
|
||||
```
|
||||
|
||||
Expected: FAIL,新方法尚不存在。
|
||||
|
||||
- [ ] **Step 3: 最小实现方法和白名单**
|
||||
|
||||
使用现有 `request()`、`pickDefined()` 和 `toRequiredPathId()`;不增加兼容别名或 APP fallback。
|
||||
|
||||
- [ ] **Step 4: 运行 GREEN**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
node --test tests/api-client-contract.test.js
|
||||
node --check utils/ApiClient.js
|
||||
```
|
||||
|
||||
Expected: PASS。
|
||||
|
||||
---
|
||||
|
||||
### Task 2: 家谱创建纯行为
|
||||
|
||||
**Files:**
|
||||
- Modify: `tests/genealogy-entry-pages.test.js`
|
||||
- Modify: `public/js/genealogy-entry-pages.js`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: `createGenealogy(body)`、`genealogyQuota()`
|
||||
- Produces:
|
||||
- `buildGenealogyCreateBody(values)`
|
||||
- `validateGenealogyCreateBody(body)`
|
||||
- `normalizeCreatedGenealogy(item)`
|
||||
- `buildCreatedGenealogyUrl(item)`
|
||||
|
||||
- [ ] **Step 1: 写失败的创建行为测试**
|
||||
|
||||
```js
|
||||
assert.deepEqual(GenealogyEntryPages.buildGenealogyCreateBody({
|
||||
genealogyName: ' 汤氏家谱 ',
|
||||
surname: ' 汤 ',
|
||||
regionCode: '511622',
|
||||
ancestralHall: '',
|
||||
coverOssId: '2062179707935264769',
|
||||
visibility: '1',
|
||||
joinMode: '1',
|
||||
manualId: 'drop'
|
||||
}), {
|
||||
genealogyName: '汤氏家谱',
|
||||
surname: '汤',
|
||||
regionCode: '511622',
|
||||
coverOssId: '2062179707935264769',
|
||||
visibility: '1',
|
||||
joinMode: '1'
|
||||
});
|
||||
```
|
||||
|
||||
同时断言:
|
||||
|
||||
- 缺少谱名、姓氏或地区时返回明确校验错误。
|
||||
- `visibility` 只允许 `0/1/2`,`joinMode` 只允许 `0/1/2`。
|
||||
- `coverOssId` 必须是安全字符串 ID;没有文件可省略。
|
||||
- 额度 `createRemaining <= 0` 时阻止提交。
|
||||
- 创建响应必须有稳定 `genealogyId`、谱名和姓氏。
|
||||
- 跳转地址只能由响应 ID 产生:`profile-family-home.html?genealogyId=...`。
|
||||
|
||||
- [ ] **Step 2: 运行 RED**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
node --test tests/genealogy-entry-pages.test.js
|
||||
```
|
||||
|
||||
Expected: FAIL,纯函数不存在。
|
||||
|
||||
- [ ] **Step 3: 最小实现纯函数**
|
||||
|
||||
严格构造 `AppGenealogyCreateBody`,可选空值省略,不读取页面外字段。
|
||||
|
||||
- [ ] **Step 4: 运行 GREEN**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
node --test tests/genealogy-entry-pages.test.js
|
||||
node --check public/js/genealogy-entry-pages.js
|
||||
```
|
||||
|
||||
Expected: PASS。
|
||||
|
||||
---
|
||||
|
||||
### Task 3: 开放创建家谱页面
|
||||
|
||||
**Files:**
|
||||
- Modify: `profile-create-family.html`
|
||||
- Modify: `public/js/genealogy-entry-pages.js`
|
||||
- Modify: `tests/genealogy-entry-pages.test.js`
|
||||
- Modify: `tests/pending-pages.test.js`
|
||||
- Modify: `tests/security-upload-scope.test.js`
|
||||
- Modify: `tests/pc-scope.test.js`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: Task 1 和 Task 2、`RegionPages`、`UploadPages`
|
||||
- Produces: `initGenealogyCreatePage()`
|
||||
|
||||
- [ ] **Step 1: 写失败的页面测试**
|
||||
|
||||
断言页面:
|
||||
|
||||
- 不再包含 `data-feature-status="pending"` 和 `pending-pages.js`。
|
||||
- 加载 `region-pages.js`、`md5.js`、`upload-pages.js` 和 `genealogy-entry-pages.js`。
|
||||
- 存在隐藏 `coverOssId` 与文件选择控件,不能手填 OSS ID。
|
||||
- 不存在 `genealogyId/applyId/inviterUserId` 输入。
|
||||
- 表单只包含后端创建 DTO 字段和地区选择辅助字段。
|
||||
- 创建按钮、状态区域和额度区域可由脚本控制。
|
||||
|
||||
- [ ] **Step 2: 运行 RED**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
node --test tests/genealogy-entry-pages.test.js tests/pending-pages.test.js tests/security-upload-scope.test.js tests/pc-scope.test.js
|
||||
```
|
||||
|
||||
Expected: FAIL,页面仍 pending 且缺上传/初始化行为。
|
||||
|
||||
- [ ] **Step 3: 实现页面初始化和提交**
|
||||
|
||||
初始化顺序:
|
||||
|
||||
1. 校验登录态。
|
||||
2. 调用 `genealogyQuota()` 并展示真实额度。
|
||||
3. `RegionPages` 初始化三级地区。
|
||||
4. `UploadPages` 通过 `data-upload-target` 把封面上传结果写入隐藏 `coverOssId`。
|
||||
5. 提交前同步表单、构造并校验 body。
|
||||
6. 使用 `writePending` 阻止重复提交。
|
||||
7. 调用 `createGenealogy(body)`。
|
||||
8. 规范化响应并跳转到真实家谱主页。
|
||||
|
||||
401 清登录态;403 保留登录态;业务错误显示在表单状态区域。
|
||||
|
||||
- [ ] **Step 4: 运行 GREEN**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
node --test tests/genealogy-entry-pages.test.js tests/api-client-contract.test.js tests/pending-pages.test.js tests/security-upload-scope.test.js tests/pc-scope.test.js
|
||||
node --check public/js/genealogy-entry-pages.js
|
||||
```
|
||||
|
||||
Expected: PASS。
|
||||
|
||||
---
|
||||
|
||||
### Task 4: 首批收口
|
||||
|
||||
**Files:**
|
||||
- Modify: `docs/PC接口对接规划.md`
|
||||
- Modify: `docs/superpowers/plans/2026-07-29-genealogy-create-first-batch.md`
|
||||
|
||||
- [ ] **Step 1: 更新契约和阶段状态**
|
||||
|
||||
记录 `AppGenealogyCreateBody`、`AppGenealogyVo`、额度、权限、上传派生字段、加入申请 ApiClient 契约及仍未开放的加入 UI。
|
||||
|
||||
- [ ] **Step 2: 聚焦和全量验证**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
node --test tests/api-client-contract.test.js tests/genealogy-entry-pages.test.js tests/pending-pages.test.js tests/security-upload-scope.test.js tests/pc-scope.test.js
|
||||
npm test
|
||||
git -c safe.directory=D:/WorkSpace/Web/jiapu diff --check
|
||||
```
|
||||
|
||||
Expected: 全部 PASS。
|
||||
|
||||
- [ ] **Step 3: 浏览器验证并报告**
|
||||
|
||||
使用真实账号验证创建页登录态、额度、地区加载、无手填 ID、控制台错误和提交前校验。不得为测试消耗真实创建额度;除非用户明确授权,不执行最终创建写操作。
|
||||
@@ -23,8 +23,8 @@
|
||||
|
||||
- `POST /genealogy/pc/genealogies`
|
||||
- `GET /genealogy/pc/genealogies/quota`
|
||||
- `GET /genealogy/pc/region/provinces`
|
||||
- `GET /genealogy/pc/region/children/{parentCode}`
|
||||
- `GET /genealogy/pc/region/children?parentCode=0`
|
||||
- `GET /genealogy/pc/region/children?parentCode={regionCode}`
|
||||
|
||||
请求只提交 `AppGenealogyCreateBody`:
|
||||
|
||||
@@ -153,4 +153,3 @@
|
||||
5. VIP:套餐选择、订单白名单、待支付边界、无伪支付。
|
||||
6. 家谱主页与权限入口:overview、上下文传播、唯一成员管理入口。
|
||||
7. 更新 pending/PC scope/navigation 测试,运行全量测试并使用真实账号验证无家谱和有数据分支;没有测试数据时明确记录未覆盖,不制造记录。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user