框架切换:Next.js 16 → Vite 5 + React 19 + React Router 7 状态管理:7 手写 hook → 4 Zustand slice 数据获取:直接 fetch → TanStack Query 5 (15 hooks) 表单:3-step 状态机 → RHF 7 + Zod 测试:0 → 25 单测 + 20 e2e (4 浏览器) Bundle:192 KB gzip (目标 < 300 KB) Lint:49 warning → 0 warning Type:33 any → 0 any S2-T-01 切 Vite 5 + React 19 框架 S2-T-02 Zustand 4 slice 替代 7 手写 hook S2-T-03 TanStack Query 5 + 15 hooks S2-T-04 Vitest + RTL + MSW + Chromatic 配置 S2-T-05 OpenAPI Codegen + Zod schema 复用 S2-T-06 RHF 7 + Zod 重写 FormCard S2-T-07 Playwright 视觉基线 4 浏览器 5 spec S2-T-08 Vite build + bundle < 300KB gzip G1 闸门 (全部通过): - typecheck: 0 error - lint: 0 error 0 warning - test (Vitest): 25/25 passed - test:e2e (Playwright): 20/20 passed - build (Vite): 326 modules 4.14s - codegen:check: OpenAPI types 非占位 Sprint 2 收口报告:SPRINT_2_CLOSEOUT_2026-07-03.md
11 KiB
11 KiB
Sprint 3 任务拆解(W4-5 · 12 人天 · 62 子任务)— V10 选项 B
技术栈:Vite 5 + React 19 + Zustand 4 + TanStack Query 5 + RHF 7 + Zod 目标:5 大 V2 新模块(Share / Query / Review / LLM / Poster)+ Share Link 统计 + Portal 集成 闸门:G2(LLM fallback 4 模实测可切换 + 5 模块端到端跑通) V10 变化:从 22d 缩到 12d(节省 10d = 8 hook 真实化用 TanStack Query 替代 + 5 模块统一模式) PM 决策(2026-07-03):整体重写为新实现;Playwright 视觉回归 + Chromatic 验收
⚠️ V10 关键变化(与 V2 对比)
| 维度 | V2 | V10 选项 B |
|---|---|---|
| useChat 拆 6 子 hook | 1.5d | 0.5d(V10 已用 Zustand 替代,S3 只需补 mock) |
| 真实 sendMessage | 1.0d | 0.5d(TanStack Query mutation + Zod) |
| useAudit + LLM 增强 | 1.5d | 0.75d(Zustand + mutation hook) |
| 5 大新模块 | 14d | 8d(统一 TanStack Query 模式) |
| 视觉回归 | 0d | +1d(V10 Chromatic 验证) |
| 总估时 | 22d | 12d |
0. Sprint 3 概览
| 任务 | 主任务 | 估时 | 子任务数 |
|---|---|---|---|
| T-B-12 | useChatOrchestrator(V10 重写) | 0.5d | 3 |
| T-B-13 | 真实 sendMessage + typing | 0.5d | 3 |
| T-B-14 | 真实 getHistory + 滚动恢复 | 0.5d | 3 |
| T-B-15 | usePlan/useConsultation 真实化 | 0.75d | 4 |
| T-B-16 | useProfile Zustand 版 | 0.5d | 3 |
| T-B-17 | useAudit + LLM 增强(4 模 fallback) | 0.75d | 4 |
| T-B-22 | Share Link API(4 端点) | 0.75d | 4 |
| T-B-23 | Data Query API(3 端点) | 0.75d | 4 |
| T-B-24 | Review Flow API(3 端点) | 0.75d | 4 |
| T-B-25 | Portal API(2 端点) | 0.5d | 3 |
| T-B-26 | LLM Audit Enhance API | 0.75d | 4 |
| T-B-27 | Poster Generate API | 0.5d | 3 |
| T-B-28 | Share Link 统计 + 分享 UI | 1.0d | 5 |
| T-B-29 | Chromatic 视觉回归(S3 增量) | 0.5d | 3 |
| T-B-30 | ESLint 0 warning 守门(V10 重写) | 0.5d | 3 |
| 合计 | 15 任务 | 9.5d + 缓冲 2.5d = 12d | 56 + 6 整合 = 62 |
T-B-12 · useChatOrchestrator(V10 重写 · 0.5d · 3 子任务)⚠️ V10 简化
V10 收益:Sprint 2 已建立 Zustand store + TanStack Query,S3 只需组装编排层
ST-S3-B-12.1 写 chat-fixtures(0.25d)
- 产出:
apps/web/__mocks__/chat-fixtures.ts - 3 套 mock:广东物理 620 / 广东历史 580 / 河北物理 600
ST-S3-B-12.2 写 useChatOrchestrator(0.125d)
- 产出:
apps/web/src/hooks/useChatOrchestrator.ts - 职责:Zustand messages + TanStack Query mutation + Typing 状态机
- V10 收益:从 1.5d(V2 拆 6 子 hook)→ 0.125d
ST-S3-B-12.3 接入 8 个 UI 组件(0.125d)
- 覆盖:MessageList / InputBar / TypingIndicator / PlanCard / ModeIndicator / 等
T-B-13 · 真实 sendMessage + typing(0.5d · 3 子任务)
ST-S3-B-13.1 写 useChatSendMutation(0.25d)
- 封装:
POST /api/chat/send+ SSE 流式响应 - 类型:
z.infer<typeof ChatSendSchema>
ST-S3-B-13.2 写 useTypingState Zustand selector(0.125d)
- 三态:thinking(旋转)/ paused(静止)/ stopped(隐藏)
ST-S3-B-13.3 接入 InputBar 真实点击发送(0.125d)
- 验收:
- 点击发送 → 流式输出 → typing 状态切换正确
any数量 0
T-B-14 · 真实 getHistory + 滚动恢复(0.5d · 3 子任务)
ST-S3-B-14.1 写 useChatHistoryQuery(0.125d)
- 封装:
GET /api/chat/history?sessionId=xxx - 缓存策略:
staleTime: 5min+gcTime: 30min
ST-S3-B-14.2 写滚动恢复 hook(0.25d)
- 产出:
useScrollRecovery(ref, [messages.length]) - 行为:sessionId 变化时滚到底部;用户上滑时不打断
- V10 不变量:UI 1:1 复现(V2 Plan §3.1 L1)
ST-S3-B-14.3 接入 ChatPanel 组件(0.125d)
T-B-15 · usePlan/useConsultation 真实化(0.75d · 4 子任务)
ST-S3-B-15.1 写 usePlanQuery(0.125d)
ST-S3-B-15.2 写 usePlanCreateMutation(0.25d)
ST-S3-B-15.3 写 useConsultationQuery + useConsultationMutation(0.25d)
ST-S3-B-15.4 接入 PlanCard 真实数据(0.125d)
- V10 不变量 C1:PlanCard 3-Tab 切换不重渲染父组件
T-B-16 · useProfile Zustand 版(0.5d · 3 子任务)⚠️ V10 简化
ST-S3-B-16.1 写 useUserStore Zustand(0.25d)
- V10 收益:从 1.0d(V2 真实 useProfile)→ 0.25d
ST-S3-B-16.2 接入 Header 头像/菜单(0.125d)
ST-S3-B-16.3 接入 Settings 页面(0.125d)
T-B-17 · useAudit + LLM 增强(4 模 fallback · 0.75d · 4 子任务)
G2 闸门核心:LLM 4 模(claude / gpt / gemini / deepseek)实测可切换
ST-S3-B-17.1 写 LLM provider 适配器(0.25d)
- 产出:
apps/web/src/lib/llm/provider.ts - 4 provider 类型:
ClaudeProvider/GPTProvider/GeminiProvider/DeepseekProvider - 接口:
enhance(input: AuditInput): Promise<AuditEnhancement>
ST-S3-B-17.2 写 useAuditEnhanceMutation(0.25d)
- 封装:
POST /api/llm/audit-enhance+ provider 选择 - 降级链:claude → gpt → gemini → deepseek
ST-S3-B-17.3 写 useLLMConfig Zustand store(0.125d)
- 状态:currentProvider / fallbackOrder / availableProviders
ST-S3-B-17.4 4 模实测切换(0.125d)
- 验收(G2):
- claude 失败 → 自动降级 gpt
- gpt 失败 → 自动降级 gemini
- 全部失败 → 走 deepseek
- Playwright e2e 覆盖
T-B-22 · Share Link API(4 端点 · 0.75d · 4 子任务)
ST-S3-B-22.1 写 useShareLinkCreate(0.25d)
- 封装:
POST /api/share-link - Schema:
{ planId, expiresIn: 7|30|forever }
ST-S3-B-22.2 写 useShareLinkDelete(0.125d)
- 封装:
DELETE /api/share-link/{id}
ST-S3-B-22.3 写 useShareLinkLatestQuery(0.125d)
- 封装:
GET /api/portal/share-link/latest
ST-S3-B-22.4 写 useShareLinkStatsQuery(0.25d)
- 封装:
GET /api/share-link/{code}/stats - 响应:
{ views, uniqueVisitors, lastAccessedAt }
T-B-23 · Data Query API(3 端点 · 0.75d · 4 子任务)
ST-S3-B-23.1 写 useScoreLineQuery(0.25d)
- 封装:
GET /api/data-query/score-line - 参数:
{ province, year, scoreType }
ST-S3-B-23.2 写 useRankEstimatorQuery(0.25d)
- 封装:
GET /api/data-query/rank-estimator - V10 变化:TanStack Query
select直接转换位次→等效分数
ST-S3-B-23.3 写 useMajorsQuery + useSchoolsQuery(0.25d)
- 封装:
GET /api/data-query/majors+GET /api/data-query/schools
T-B-24 · Review Flow API(3 端点 · 0.75d · 4 子任务)
ST-S3-B-24.1 写 useReviewStartMutation(0.25d)
- 封装:
POST /api/review/start
ST-S3-B-24.2 写 useReviewStatusQuery(0.125d)
- 封装:
GET /api/review/{id}/status - 轮询:
refetchInterval: 3000(审核中)
ST-S3-B-24.3 写 useReviewActionMutation(0.25d)
- 封装:
POST /api/review/action(approve / reject / request_changes) - V10 变化:Zod discriminated union 处理 3 种 action
ST-S3-B-24.4 接入 ReviewPanel UI(0.125d)
T-B-25 · Portal API(2 端点 · 0.5d · 3 子任务)
ST-S3-B-25.1 写 usePortalCWBQuery(0.25d)
- 封装:
GET /api/portal/{token}/cwb(位次查询)
ST-S3-B-25.2 写 usePortalFullPlanQuery(0.125d)
- 封装:
GET /api/portal/{token}/full-plan
ST-S3-B-25.3 写 Portal 入口页面(0.125d)
- UI/交互 1:1:与原型招生门户入口一致
T-B-26 · LLM Audit Enhance API(0.75d · 4 子任务)
ST-S3-B-26.1 写 useAuditEnhanceMutation(0.25d)
- 封装:
POST /api/llm/audit-enhance
ST-S3-B-26.2 写流式响应处理(0.25d)
- V10 关键技术:SSE + ReadableStream + Zustand 增量更新
- 复用:
useChatSendMutation的流式逻辑
ST-S3-B-26.3 写 LLM 结果展示组件(0.125d)
ST-S3-B-26.4 接入 AuditPanel UI(0.125d)
T-B-27 · Poster Generate API(0.5d · 3 子任务)
ST-S3-B-27.1 写 usePosterGenerateMutation(0.25d)
- 封装:
POST /api/poster/generate - 响应:
{ posterUrl, qrCode, expiresAt }
ST-S3-B-27.2 写海报预览组件(0.125d)
- V10 视觉:海报需与原型的视觉风格一致
ST-S3-B-27.3 接入 ShareDialog UI(0.125d)
T-B-28 · Share Link 统计 + 分享 UI(1.0d · 5 子任务)⚠️ V10 加强
V10 加强:5 个子任务覆盖 UI + 统计图表 + 移动端适配
ST-S3-B-28.1 写 ShareDialog 组件(0.25d)
- UI/交互 1:1:与原型分享弹窗一致
- V10 不变量:移动端 48px 触发区
ST-S3-B-28.2 写 QR Code 展示组件(0.125d)
- 依赖:
qrcode.react
ST-S3-B-28.3 写 Stats 统计卡片(0.25d)
- 3 卡片:访问数 / 独立访客 / 最近访问
- 图标:lucide-react
ST-S3-B-28.4 写访问趋势 mini chart(0.25d)
- 依赖:
recharts - V10 收益:Sprint 5 chart 任务的预演
ST-S3-B-28.5 写 e2e:share-link.spec(0.125d)
T-B-29 · Chromatic 视觉回归(S3 增量 · 0.5d · 3 子任务)⚠️ V10 新增
ST-S3-B-29.1 截图新增 5 模块页面(0.25d)
- 页面:ShareDialog / Stats / DataQuery / ReviewPanel / Poster Preview
ST-S3-B-29.2 提交 Chromatic 增量基线(0.125d)
ST-S3-B-29.3 Chromatic diff 阈值告警(0.125d)
- CI:
pnpm chromatic --exit-zero-on-changes
T-B-30 · ESLint 0 warning 守门(V10 重写 · 0.5d · 3 子任务)
V10 关键:S3 完成后 ESLint 必须 0 warning(V2 是 49 warning 缓慢修)
ST-S3-B-30.1 清理 S3 引入的 any(0.25d)
- 验收:
grep -r "any" apps/web/src/0 结果
ST-S3-B-30.2 清理 S3 引入的 unused vars(0.125d)
ST-S3-B-30.3 升级 Sprint 1 临时 warn 规则为 error(0.125d)
- 规则:
@typescript-eslint/no-explicit-any/react-hooks/set-state-in-effect - 目的:阻止 Sprint 4-8 倒退
V10 验收清单(Sprint 3 G2 闸门)
G2 闸门(必须全部通过):
[ ] 5 大新模块端到端跑通(Share / Query / Review / LLM / Poster)
[ ] LLM 4 模实测可切换 + 自动降级
[ ] pnpm typecheck 0 error 0 any
[ ] pnpm lint 0 error 0 warning
[ ] pnpm test 100% 覆盖新增 56 个子任务相关组件
[ ] pnpm test:e2e 5 spec 全绿
[ ] pnpm build bundle < 320KB gzip(+20KB for new modules)
[ ] pnpm chromatic 视觉基线 13 页全提交
[ ] 原型 7 个手写 hook + 1 个 lib/ 全部删除
[ ] ESLint 0 warning(V2 是 49 warning 修 1 整轮)
V10 风险(Sprint 3 特有)
| ID | 风险 | 等级 | 缓解 |
|---|---|---|---|
| V10-S3-R1 | LLM 4 模 provider 适配成本高 | 中 | 抽象统一接口;先实现 1 模,再快速复制 3 模 |
| V10-S3-R2 | SSE 流式响应与 TanStack Query 兼容 | 中 | 用 onMutate + Zustand 增量更新,绕过 React Query 的缓存机制 |
| V10-S3-R3 | 5 新模块并发开发协调 | 中 | 串行实施:T-B-22 → T-B-23 → T-B-24 → T-B-26 → T-B-27 |
| V10-S3-R4 | Chromatic 商业服务配额 | 低 | Sprint 2 已用 1 次,S3 再用 1 次,剩余 8 次给 S4-S8 |
Sprint 3 文档状态:V10 选项 B 重写完成 总工时:12 人天(V2 是 22 人天,节省 10d) 总子任务:62 个(V2 是 70 个) 下一步:Sprint 2 完成后立即启动