page.tsx still owns the chat main chain, but the first product surfaces now live in their own modules so later splits can land without editing the 4k-line Home. Source-lock tests follow the moved tokens; the orphan user-data contract is aligned and added to the quick gate. Co-authored-by: Cursor <cursoragent@cursor.com>
8.0 KiB
PROGRESS · 拆分首页巨石组件·第一批(2026-09-01)
工作树:.worktrees/home-split-20260901
分支:codex/home-split-20260901(跟踪 origin/staging)
基线:origin/staging @ 85589005(任务书提交;产品代码与 P2a ce6a8a7e 相同)
不要写成 PROGRESS.md。本轮未提交、未推送。
度量
| 项 | 拆前 85589005 |
拆后 | 说明 |
|---|---|---|---|
frontend/src/app/page.tsx 行数 |
4766 | 3505 | 目标 ≤3000,未达标 |
useState( |
26 | 26 | 见下方 overlay 说明 |
useEffect( |
20 | 20 | 拉取/重试 effect 仍在 Home |
/ 路由 |
○ Static |
○ Static |
webpack next build |
| 首屏 JS gzip -9 | 500262 B = 488.5 KB | 501315 B = 489.6 KB | +1053 B / +0.21%(±2% 内) |
| 前端测试 | 2427 | 2427 | fail=0 skipped=0(见验证) |
未达标原因:聊天主链路(composer / transcript / send / 停止与恢复 / 引导对话)按任务书本批不动。抽走的是 helpers + 星盘库/合盘面板 + starter/每日星语。剩余约 505 行要等第二批。
useState 未下降:otherProfileDraft / editingChartId / otherChartRelationship / editingSelfChart 仍留在 Home。AccountDialogOverlay 在关闭时 return null,把独占 state 下移进面板会在关弹窗时丢掉未保存草稿,属于行为变化,本轮禁止。handlers(saveOtherChart 等)已随 JSX 进面板,state 经显式 props 传入。
任务 0 · 孤儿契约测试
tests/test_supabase_user_data_contract.py 对齐现状源码(性质保留:浏览器不直写 profiles / chat_sessions,账户 PATCH 仍拒数组,合盘仍走 postPython("/api/chart"))。任务书写的三处之外,同一文件里还有过期 token,一并换成现码并在上方注释原值:
- 首页不再
.from("profiles")/.from("chat_sessions"),锁fetch("/api/account"/fetch("/api/sessions" - 账户 PATCH:
accountProfilePatchSchema.safeParse+z.object({(account-profile-patch.ts) - 文案「添加其他人的星盘」
- 合盘:
postPython("/api/chart", selfPayload)/partnerPayload - 用户消息:
messages: questionAlreadyPresent ? preservedMessages : [...preservedMessages, { role: "user", text: question }] - 中断路径:源码已无
await persistSession(interruptedSession);停止文案「正在停止回答并申请退回本次点数…」
搬家后该文件改读 _home_surface()(page.tsx + 抽出文件拼接),正则/token 未改。
scripts/run_quality_gate.py 的 CORE_PYTEST_TARGETS 已列入此文件,注释写明前端搬家轮必须带着它跑。
pytest tests/test_supabase_user_data_contract.py tests/test_daily_and_rectification_entrypoints.py -q → 12 passed。
任务 1–3 · 搬家
新文件(实现从 page.tsx 原样搬出,加 export):
| 文件 | 行 | 内容 |
|---|---|---|
frontend/src/lib/home-types.ts |
254 | 类型、空资料、themes、storage 键常量 |
frontend/src/lib/home-profile.ts |
323 | 地点/资料/标签/readProfile/upsertSelfChart |
frontend/src/lib/home-cloud-sync.ts |
499 | 云端 fetch、登录跳转、每日星语读写 |
frontend/src/components/birth-location-fields.tsx |
40 | BirthLocationFields |
frontend/src/components/profile-fields.tsx |
38 | ProfileFields |
frontend/src/components/onboarding-chat-message.tsx |
28 | OnboardingChatMessage |
frontend/src/components/chart-library-panel.tsx |
269 | 星盘库 + 合盘卡/历史/他人表单 |
frontend/src/components/starter-home.tsx |
159 | starter hero / 每日星语 / 生时入口 / 主题卡 |
page.tsx 仍 "use client"、import "@/app/site-styles"、const BirthTimeRectification = dynamic(...)。新组件未 import 全局样式。无 context/store、无手写 useCallback/useMemo、未重开 React Compiler。
本人星盘表单仍 onSubmit={saveProfile}(面板 prop 名就是 saveProfile)。starter 回调 prop 保持原标识符:startDailyStarlanguageConsultation、openRectificationFromHomepage、startSuggestedConsultation。
合同测试路径(同一 token,只换读取面)
共用拼接件 frontend/tests/home-surface.ts:page.tsx + 上表抽出文件。Python 侧 _home_surface() / 显式 concat 同理。
| 测试 | 原路径 | 新路径 |
|---|---|---|
birth-place-picker.test.ts |
src/app/page.tsx |
homeSurface(BirthPlacePicker 在 birth-location-fields.tsx) |
birth-time-consultation-consent.test.ts |
page.tsx |
homeSurface(readProfile 在 home-profile.ts) |
character-remaining-contract.test.ts |
page.tsx |
homeSurface(姓名字数 aria-describedby 在 profile-fields.tsx) |
chart-library-other-profile.test.ts |
page.tsx |
homeSurface |
chat-navigation-a11y-contract.test.ts |
page.tsx |
homeSurface |
chat-session-authority.test.ts |
page.tsx |
homeSurface |
chat-session-url.test.ts |
page.tsx |
homeSurface |
chat-session-write.test.ts |
page.tsx |
homeSurface(fetch("/api/sessions" 在 home-cloud-sync.ts) |
composer-isolation-contract.test.ts |
page.tsx |
homeSurface(pendingConsultationStorageKey 在 home-types.ts) |
consultation-entrypoint.test.ts |
page.tsx |
homeSurface(starter 卡在 starter-home.tsx) |
consultation-recovery.test.ts |
page.tsx |
homeSurface |
daily-starlanguage.test.ts |
page.tsx |
homeSurface |
membership-page.test.ts(home 段) |
page.tsx |
homeSurface(LoginRedirectError 在 home-cloud-sync.ts) |
onboarding-presentation.test.ts |
page.tsx |
homeSurface |
rectification-agentic-entry.test.ts |
page.tsx |
homeSurface |
settings-mvp-contract.test.ts renderProfile |
page.tsx 切片 |
homeSurface(切片标记仍在 page.tsx) |
settings-mvp-contract.test.ts 星盘库表单 |
page.tsx 的 renderChartLibrary→renderGeneral 切片 |
chart-library-panel.tsx(切片里只剩 <ChartLibraryPanel />,token 已搬走) |
starter-questions.test.ts |
page.tsx |
homeSurface |
tests/test_supabase_user_data_contract.py |
PAGE.read_text() |
_home_surface() |
tests/test_daily_and_rectification_entrypoints.py |
PAGE |
PAGE + starter-home.tsx + home-cloud-sync.ts |
tests/test_birth_time_journey_contract.py 网页引导条 |
page.tsx |
page.tsx + home-profile.ts(reported_birth_time / active_birth_time) |
未改断言语义。锁聊天主链路、且 token 仍在 page.tsx 的测试继续只读 page.tsx(如 site-style-isolation-contract、composer/sidebar 壳、rectification-lazy-loading)。
验证
./node_modules/.bin/tsc --noEmit:通过。npm test:2427 条。并发下 2 条 Docker 库测 flake(admin-database/model-configuration-security,database migration failed/Connection terminated unexpectedly)。--test-concurrency=1重跑这 8 条:pass 8 fail 0。与产品搬家无关。skipped=0。./node_modules/.bin/next build --webpack:┌ ○ /。本树node_modules仍是指向session-url-20260901的符号链接,默认 Turbopack 会拒。gzip 口径:预渲染index.html引用的/_next/static/**.js去重后gzipSynclevel 9。基线用同 SHA 干净 worktree 同口径对照。- 行为抽查:无登录态,未在浏览器点星盘库增删改、合盘、starter 入口、每日星语。由合同测试覆盖。
明确未做 / 未修
- 聊天主链路第二批再拆。
- popstate 回默认会话未走
selectSession(任务书决策 4)。 tests/test_session_management_entrypoints.py::test_archiving_never_calls_the_delete_endpoint仍锁已删除的setArchivedSessionIds(P2a 遗留,不在CORE_PYTEST_TARGETS,本轮不顺手修)。tests/test_birth_time_journey_contract.py::test_web_onboarding_uses_the_deterministic_free_journey在 mastra 断言'entry_mode: entryMode'上仍红(与搬家无关、不在 quick gate);本轮只补了page.tsx侧 token 路径。- 未改
.gitea/workflows/**。未提升main。