Files
Jyotisha/docs/tasks/TASK-self-edit-avatar-menu-20260928.md
T

9.7 KiB
Raw Blame History

TASK · 星盘档案可编辑本人、各页头像弹账户菜单、我的报告去掉提示(2026-09-28)

基线与依赖

  • 串行:本单改 frontend/src/app/(app)/page.tsx,必须等 TASK-birth-sky-polish-20260928(分支 codex/birth-sky-pacing-20260928)由 Claude 验收并推上 staging 之后再开工。开工时 git fetch origin --prune,以当时的 origin/staging 为基线,SHA 写进 PROGRESS。
  • 分支 / 工作树:codex/self-edit-avatar-menu-20260928 / .worktrees/self-edit-avatar-menu-20260928。
  • 进度记录:docs/tasks/PROGRESS-self-edit-avatar-menu-20260928.md。
  • BUG 编号:开工时核对 docs/BUG_HISTORY.md 最大号。polish 单占用 BUG-1080,本单从 BUG-1081 起;若开工时已被占用,顺延并在 PROGRESS 写明。

事实(Claude 2026-09-28 在 origin/staging 核实;行号按符号定位)

  1. 全站没有任何地方能改本人的出生资料(回归):
    • ab6c55f8(星盘档案 P1,2026-09-25)的提交说明写「/people replaces the settings chart pane」:设置弹窗里原来的星盘资料块被 /people 取代,首页那块表单(chart-library-panel.tsx)随后在 d08ffdc0 作为「没有引用」的文件删掉。
    • components/people/people-page.tsx:只有 role === "other" 有「编辑」按钮;本人那一格只显示「本人不能删除」。常量 SELF_GENDER_NOTE 上方注释写「本人 has no edit view here」。
    • 设置 → 个人资料(components/profile-panel.tsx)只能改头像和性别。
    • 服务端能力还在:PATCH /api/account,由 lib/account-profile-patch.ts 的 accountProfilePatchSchema 校验,要求改出生资料时必须同时提交 birth_time_source。
    • 首页 hook use-profile-onboarding.ts 里的 saveProfile 已经没有任何 UI 调用。page.tsx 只从 hook 里解构出它,并没有用。
    • 能证明这是漏掉而不是有意:生时校正的用户文案 declaredWindowLockedReply(lib/rectification-agentic/user-copy.ts)里写着「请先到资料里改出生时间」,但用户找不到这个地方。
    • 星盘档案任务书 TASK-people-archive-p1-20260924 D1 写的是「户主本人也是其中一个,统一列表、统一操作;户主不可删」,并没有说「本人不可编辑」。
  2. 除首页外点头像直接回首页(是当初的设计,不是代码写错):
    • components/app-sidebar.tsx 页脚:只有首页通过 registerShellControls 注册了 controls,这时才渲染 Menu.Root 账户菜单;其他页走只读分支,是一个 AppLink href="/",注释写「The account menu and its dialogs live on /」。
    • 出处:侧栏统一单(BUG-744~746);BUG_HISTORY 里写过「次级页点头像应当跳回首页而不是没反应」。
  3. 「我的报告」页顶部有一段说明和一行统计:components/personal-report/personal-report-center.tsx 的 .report-center-hero,内容是「有填报到分钟的出生时间即可生成……你无需停留等待。」和「共 N 份 · 已完成 N 份 · ……」。

决策记录(产品 2026-09-28)

  1. 本人在 /people 可以编辑:和他人使用同一张 ChartProfileForm,保存走本人原来的 PATCH /api/account。本人仍然不能删除。
    • 这推翻了 people-page.tsx 里「本人 has no edit view here」的做法。
  2. 所有页面点头像都弹出同一个账户菜单,推翻侧栏统一单里「次级页头像 = 回首页链接」的约定:
    • 切换主题:在当前页直接生效(ThemePreferenceMenu 本来就不依赖首页)。
    • 「个人资料」「通用设置」「账户与点数」「退出登录」:在首页照旧直接打开弹窗;在其他页跳到首页,并自动打开对应的弹窗。
    • 不把弹窗搬到每一页(那样首页首屏会多一个加载态,违反 AGENTS §6「揭幕后不得出现加载」),留作以后评估。
  3. 「我的报告」去掉整个顶部说明区:说明段和统计行都删。页面从「报告记录」列表开始。生成按钮的 title 悬停提示不动。

硬红线

  1. 本人出生资料只经 PATCH /api/account 写入,并照 accountProfilePatchSchema 提交 birth_time_source。不得把本人写进 chart_profiles,不得在客户端伪造 active_* 或校正结果字段。
  2. page.tsx 行数不增长;Home() 的 useState / useRef 数不增长。新逻辑放进 hooks/ 或 lib/ 或组件;删掉 page.tsx 里已经没人用的 saveProfile 解构。
  3. 首页仍是 ○ Static;首屏 gzip ±2%;揭幕后不出现 spinner / 骨架。
  4. 账户菜单只有一份实现(同一个 Menu.Popup),不准复制出第二份菜单。
  5. 改既有断言写「原值 / 新值 / 原因」三栏;动组件前先 grep frontend/tests/ 里按源码文本断言的合同测试(sidebar-contract.test.ts、people-archive-view.test.tsx、personal-report-entry.test.ts 等)。
  6. 不改表、不加迁移、不加依赖。隐私:测试只用虚构资料。

任务分解

S1 · 本人可在星盘档案编辑(BUG-1081)

  • people-page.tsx:本人也有「编辑」按钮,位置同他人;编辑视图复用 ChartProfileForm(显示岁差与性别,和他人一致)。本人的编辑视图没有删除区。
  • 保存:把 use-profile-onboarding.ts 里 saveProfile 用到的持久化逻辑(persistProfile 及其载荷构造)抽成 lib/ 里的纯函数或小 hook,供 /people 调用;首页若已不再需要 saveProfile,从 hook 和 page.tsx 一起删掉。
    • 保存成功后,刷新 /people 列表里的本人数据,并让用到本人资料的缓存失效(侧栏、当前人物、星盘页),和编辑他人后的做法一致。执行方先查清编辑他人时刷新了哪些,照做。
    • 出生资料一改,照原 saveProfile 的做法重置 birthTimeConsultationConsent 这类依赖出生资料的本地状态。首页重新挂载时会从 /api/account 重新读取,这一点要核实。
    • 失败时在表单里提示,文案对照 VOICE。
  • 「性别在设置 → 个人资料里改」这句小字:表单里已经能改性别,删掉。
  • 验收:
    • 测试:本人有「编辑」按钮;本人编辑视图无删除;保存调用 PATCH /api/account 且带 birth_time_source;不写 chart_profiles;失败有提示。
    • BUG-1081 写全:现象、触发、根因(ab6c55f8 取代设置里的资料块时漏了本人编辑)、修复、验证、防复发(加一条合同测试:全站至少有一个本人出生资料编辑入口),并说明旧测试为什么没拦住。

S2 · 各页头像弹出账户菜单

  • app-sidebar.tsx:只读分支不再渲染 AppLink href="/",改成和首页同一个 Menu.Root。菜单项的回调在没有 controls 时改成跳转:/?account=profile|general|billing|logout。
    • 余额「N 点」:只读模式下若拿不到 credits,这一格不显示数字,不要显示 0。
  • 首页:写一个类似 NewChatDeepLink 的小组件或 hook,读取一次 ?account= 意图,在账户就绪后打开对应弹窗,然后用 history.replaceState 去掉这个参数(刷新或后退都不会再弹)。放在 page.tsx 之外,page.tsx 只接一行线。
    • 未登录时参数无效,照常走登录。
  • 验收:
    • 测试:只读模式渲染菜单而不是链接;四个菜单项在只读模式各自跳到对应的 ?account=;首页读取意图后打开对应弹窗并清掉参数;非法值忽略。
    • sidebar-contract.test.ts 里锁「只读 = 链接到 /」的断言按新行为改写,三栏说明。
    • 无头 Chrome:在 /people 视口 1280×800 与 390×844 各截一张菜单展开图,放 scratchpad,路径写进 PROGRESS。

S3 · 我的报告去掉顶部说明区

  • personal-report-center.tsx:删 .report-center-hero 整段,以及只给它用的 hasGenerating / latestReady 计算(先确认没有别处在用)。globals.css 里只给它用的样式一并删。
  • personal-report-entry.test.ts 的 “global report copy …” 测试:对 reportCenterSource 的四条 match 改成 doesNotMatch(锁住不再出现),三栏说明。对 componentSource 的断言不动。
  • 验收:报告页首屏直接是「报告记录」;测试通过。

S4 · 文档

  • frontend/DESIGN.md:侧栏页脚在各页的行为;/people 本人可编辑;报告页顶部。
  • frontend/docs/VOICE.md:新增或删除的文案。
  • CHANGELOG.md:一条。
  • docs/BUG_HISTORY.md:BUG-1081。
  • docs/testing/self-edit-avatar-menu-20260928.md(新建真机清单):
    • 在 /people 改本人出生时间,回首页,再打开星盘页核对已更新;
    • 在 /chart、/people、/reports、/ephemeris 各点一次头像,菜单都弹出;点「账户与点数」跳首页并打开点数弹窗;刷新后不再弹;
    • 在次级页切换主题,立即生效;
    • 我的报告顶部没有说明段。

验证

  • tsc --noEmit 0 错;npm run lint 0 error。
  • npm test 全量:与基线比测试名清单,不得有测试名消失;失败清单与基线逐条同名(无 Docker 的 24 条)。
  • rm -rf .next && next build:/ 仍 ○ Static;首屏 gzip 与基线同口径对比,在 ±2% 内(同一脚本在基线与交付各建一次)。
  • python3 -m pytest tests/test_repo_privacy_markers.py -q。

让步顺序

  1. S2 的余额数字在只读模式下可以不显示。
  2. S2 跳转后打开弹窗若和首页揭幕时序冲突,可以等揭幕完成后再打开,但不得加等待态。
  3. S1 本人可编辑、S3 删除说明区不可让步。

交付

  • 按 S1 / S2 / S3+S4 分提交,不推送;由 Claude 独立验收后快进推 staging。