Files
jiapu/docs/superpowers/plans/2026-07-11-family-feed-integration.md
T
2026-07-11 21:36:26 +08:00

7.3 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.openapi2.json 中已交付的 12 个家族圈动态接口接入既有动态页面,并保持未开发的家谱业务不调用不存在的接口。

Architecture: PC.openapi2.json 是接口唯一依据;ApiClient 提供一一对应的私有请求封装,feed-pages.js 只协调页面事件和已定义的接口方法。动态页从 URL 查询参数读取真实 genealogyId,不写入示例家谱 ID。

Tech Stack: 原生 JavaScript、Axios、Node LTS node:test、静态 HTML/CSS。

Global Constraints

  • 所有新增或修改的注释使用清晰中文。
  • 不删除现有页面和样式;不接入尚未出现在 PC.openapi2.json 的业务。
  • 不提交当前工作区:其中含用户已有的未提交修改。
  • 动态读取响应目前只有通用 ListResult/PageResult,页面仅使用 feedIdfeedContent;后端返回缺少这两个字段时展示明确错误,不猜测字段名。

Task 1: 更新接口边界测试和动态请求测试

Files:

  • Modify: tests/api-client-contract.test.js
  • Modify: tests/pc-scope.test.js
  • Create: tests/feed-pages.test.js

Interfaces:

  • Consumes: PC.openapi2.json 的 12 个 /genealogy/pc/genealogies/{genealogyId}/feeds 操作。

  • Produces: 对客户端路径、HTTP 方法、请求体和页面请求体转换的自动化约束。

  • Step 1: 写入失败测试

test('家族圈动态方法使用文档定义的路径和请求体', async () => {
  const calls = [];
  const client = createClientWithRecorder(calls);
  await client.createFeed(900001001, { feedContent: '今天上传一张老照片。' });
  await client.feedCommentsPage(900001001, 7001, { pageNum: 1, pageSize: 10 });
  assert.deepEqual(calls.map((call) => [call.method, call.url]), [
    ['post', '/genealogy/pc/genealogies/900001001/feeds'],
    ['get', '/genealogy/pc/genealogies/900001001/feeds/7001/comments/page']
  ]);
});

test('动态表单只构造 FamilyFeedBody 字段', () => {
  assert.deepEqual(FeedPages.buildFeedBody({
    feedContent: '家谱动态', mediaOssIds: '101,102', status: '0'
  }), {
    feedType: 'text', feedContent: '家谱动态', mediaOssIds: '101,102', status: '0'
  });
});
  • Step 2: 运行失败测试

Run: $env:Path = 'C:\\Program Files\\nodejs;' + $env:Path; npm.cmd test

Expected: 动态方法或 feed-pages.js 尚不存在导致失败。

  • Step 3: 调整范围检查
assert.match(contract, /\/genealogy\/pc\/genealogies\/\{genealogyId\}\/feeds/);
assert.equal(read('profile-feed.html').includes('src="public/js/feed-pages.js"'), true);
assert.equal(read('profile-feed-edit.html').includes('src="public/js/feed-pages.js"'), true);
  • Step 4: 重新运行测试,确认仍处于预期失败状态

Run: $env:Path = 'C:\\Program Files\\nodejs;' + $env:Path; npm.cmd test

Expected: 仅动态实现相关断言失败。

Task 2: 增加 12 个家族圈 API 方法

Files:

  • Modify: utils/ApiClient.js
  • Modify: tests/api-client-contract.test.js

Interfaces:

  • Consumes: genealogyId:number|stringfeedId:number|stringcommentId:number|string

  • Produces: feedsfeedsPagefeedDetailcreateFeedupdateFeeddeleteFeedlikeFeedunlikeFeedfeedCommentsfeedCommentsPagecreateFeedCommentdeleteFeedComment

  • Step 1: 保持失败测试不变

await client.createFeed(900001001, { feedContent: '家谱动态' });
assert.equal(calls[0].url, '/genealogy/pc/genealogies/900001001/feeds');
assert.deepEqual(calls[0].data, { feedContent: '家谱动态' });
  • Step 2: 实现最小路径构造
function feedPath(genealogyId, suffix) {
  return '/genealogy/pc/genealogies/' + encodeURIComponent(genealogyId) + '/feeds' + suffix;
}

createFeed: function (genealogyId, body) {
  return request('POST', feedPath(genealogyId, ''), { body: body });
}
  • Step 3: 运行测试,确认通过

Run: $env:Path = 'C:\\Program Files\\nodejs;' + $env:Path; npm.cmd test

Expected: 动态客户端路径和请求体断言通过。

Task 3: 恢复动态页的真实交互

Files:

  • Create: public/js/feed-pages.js
  • Modify: profile-feed.html
  • Modify: profile-feed-edit.html
  • Modify: tests/feed-pages.test.js

Interfaces:

  • Consumes: GenealogyApi.defaultClient 的 12 个动态方法和 URL 中的 genealogyId、可选 feedId

  • Produces: 动态列表、发布/编辑、点赞/取消点赞、评论查看/发布/删除、动态删除事件。

  • Step 1: 使页面测试失败

assert.equal(FeedPages.getCurrentGenealogyId('?genealogyId=900001001'), '900001001');
assert.equal(FeedPages.getCurrentGenealogyId(''), '');
assert.equal(FeedPages.getFeedId({ feedId: 7001 }), '7001');
  • Step 2: 实现页面数据转换和事件
function buildFeedBody(values) {
  return {
    feedType: 'text',
    feedContent: String(values.feedContent || '').trim(),
    mediaOssIds: trimOrUndefined(values.mediaOssIds),
    status: trimOrUndefined(values.status)
  };
}

列表只读取 feedIdfeedContent,并在缺少其中任一字段时显示“动态响应缺少 feedId 或 feedContent,请联系后端补充 DTO”。编辑页以 feedId 查询详情并调用 updateFeed;列表操作调用点赞、取消点赞、评论、删除接口后重新加载当前页。

  • Step 3: 挂载脚本和契约字段
<textarea id="feedContent" name="feedContent" required></textarea>
<script src="public/js/feed-pages.js"></script>

移除未在 FamilyFeedBody 中定义的“可见范围”提交字段;保持页面布局与既有视觉类名。

  • Step 4: 运行测试,确认通过

Run: $env:Path = 'C:\\Program Files\\nodejs;' + $env:Path; npm.cmd test

Expected: feed-pages.test.js 和已有测试全部通过。

Task 4: 更新文档来源与最终验证

Files:

  • Modify: tests/pc-scope.test.js
  • Modify: PC.openapi.yaml

Interfaces:

  • Consumes: PC.openapi2.json 的接口路径。

  • Produces: 明确标记旧 YAML 不再为接口源,并使静态检查以 JSON 为准。

  • Step 1: 写入失败检查

const contract = JSON.parse(read('PC.openapi2.json'));
assert.ok(contract.paths['/genealogy/pc/genealogies/{genealogyId}/feeds']);
  • Step 2: 标记旧 YAML 失效

PC.openapi.yaml 文件首行写入中文说明:该文件不再作为代码或测试接口源,正式接口源为 PC.openapi2.json。不复制或手改 JSON 中未定义的动态响应 DTO。

  • Step 3: 全量验证

Run: $env:Path = 'C:\\Program Files\\nodejs;' + $env:Path; npm.cmd test

Expected: 全部测试通过,且所有动态页面加载的脚本文件都存在。

Self-review

  • 范围只覆盖最新文档已交付的家族圈动态接口,没有加入家谱创建、成员或世系树接口。
  • 所有请求体字段来自 FamilyFeedBodyFamilyFeedCommentBody
  • 读取响应不使用历史字段兜底,不把未知字段猜成有效数据。
  • 任何 URL 缺少 genealogyId 的页面都会明确提示,不使用硬编码示例 ID。