7.9 KiB
家谱创建首批 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 白名单测试
测试固定以下请求:
await client.createGenealogy({
genealogyName: '汤氏家谱',
surname: '汤',
regionCode: '511622',
coverOssId: '2062179707935264769',
legacyField: 'drop'
});
await client.applyToGenealogy(genealogyId, {
applicantName: '申请人',
phone: '<测试联系电话>',
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:
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:
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: 写失败的创建行为测试
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:
node --test tests/genealogy-entry-pages.test.js
Expected: FAIL,纯函数不存在。
- Step 3: 最小实现纯函数
严格构造 AppGenealogyCreateBody,可选空值省略,不读取页面外字段。
- Step 4: 运行 GREEN
Run:
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:
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: 实现页面初始化和提交
初始化顺序:
- 校验登录态。
- 调用
genealogyQuota()并展示真实额度。 RegionPages初始化三级地区。UploadPages通过data-upload-target把封面上传结果写入隐藏coverOssId。- 提交前同步表单、构造并校验 body。
- 使用
writePending阻止重复提交。 - 调用
createGenealogy(body)。 - 规范化响应并跳转到真实家谱主页。
401 清登录态;403 保留登录态;业务错误显示在表单状态区域。
- Step 4: 运行 GREEN
Run:
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:
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、控制台错误和提交前校验。不得为测试消耗真实创建额度;除非用户明确授权,不执行最终创建写操作。