- 新增 .planning/phases/03-dialog-feedback/03-01-SUMMARY.md(plan 完成总结) - STATE.md 更新:Phase 3 进度 1/3,milestone 整体 71%(5/7 plan) - ROADMAP.md 更新:Plan 03-01 标记完成(commit 7065d73),Phase 3 进度 1/3 - REQUIREMENTS.md 更新:CRED-FE-05 反馈通道前置打通(完整闭环依赖 03-02) 任务原子提交:feat 7065d73(app/layout.tsx)
136 lines
6.5 KiB
Markdown
136 lines
6.5 KiB
Markdown
---
|
||
phase: 03-dialog-feedback
|
||
plan: 01
|
||
subsystem: ui
|
||
tags: [next.js, react, sonner, toast, root-layout]
|
||
|
||
# Dependency graph
|
||
requires:
|
||
- phase: 02-rbac-entry
|
||
provides: app/ai-model/page.tsx 占位 Dialog(toast 反馈接入点上游)
|
||
provides:
|
||
- RootLayout 顶层挂载 Sonner Toaster portal,全局 toast.success/error 调用从 dead code 转为可见反馈
|
||
- 修复仓库 9 处 toast 调用静默失败的 pre-existing 问题
|
||
affects:
|
||
- 03-02-dialog-feedback(凭据槽位 Dialog 抽离 + RHF/Zod + Sonner toast 反馈)
|
||
- 后续任何依赖 toast 反馈的 phase / plan
|
||
|
||
# Tech tracking
|
||
tech-stack:
|
||
added: [] # Sonner 已在 deps(^1.7.1),未引入新依赖
|
||
patterns:
|
||
- "RootLayout 全局 portal 挂载点:第三方 client component 直接渲染在 RSC layout 的 <body> 内(无需 layout.tsx 自身 'use client')"
|
||
|
||
key-files:
|
||
created: []
|
||
modified:
|
||
- "app/layout.tsx(+5 / -1 行;第 3 行 import + 第 18-21 行 <body> 块)"
|
||
|
||
key-decisions:
|
||
- "挂载位置选 <body> 内 {children} 之后:保证所有路由 children 渲染完成后 Toaster portal 仍位于 body 顶层"
|
||
- "不给 RootLayout 加 'use client':components/ui/sonner.tsx 已 'use client',RSC layout 直接渲染 client child 即可"
|
||
- "不挂 Radix Toast Toaster(components/ui/toaster):本 phase 锁定 Sonner 单一通道(CONTEXT D-Toast 决策)"
|
||
- "不新增 ThemeProvider:sonner.tsx:9 useTheme() 已有 fallback 'system',无 ThemeProvider 也能跑"
|
||
|
||
patterns-established:
|
||
- "全局 portal 挂载样板:在 RootLayout <body> 内、{children} 之后追加 portal 元素(Toaster / Modals / 全局 overlay 等通用此结构)"
|
||
|
||
requirements-completed: [CRED-FE-05] # 部分进度 — 本 plan 仅修复 Toaster 挂载前置;CRED-FE-05 完整闭环依赖 03-02 提交反馈接入
|
||
|
||
# Metrics
|
||
duration: ~1min
|
||
completed: 2026-05-08
|
||
---
|
||
|
||
# Phase 3 Plan 01:RootLayout 挂载 Sonner Toaster Summary
|
||
|
||
**在 `app/layout.tsx` `<body>` 末尾挂载 Sonner `<Toaster />`,修复仓库 9 处 `toast(...)` 调用因 portal 未挂载而全部静默失败的 pre-existing dead code 问题**
|
||
|
||
## Performance
|
||
|
||
- **Duration:** ~1 分钟
|
||
- **Started:** 2026-05-08T04:25:14Z
|
||
- **Completed:** 2026-05-08T04:26:12Z
|
||
- **Tasks:** 1 / 1
|
||
- **Files modified:** 1
|
||
|
||
## Accomplishments
|
||
|
||
- RootLayout 顶层注入 `<Toaster />`,全局 `toast.success(...)` / `toast.error(...)` 命令式调用从 dead code 转为屏幕可见反馈
|
||
- 修复 Phase 1+2 累计 9 处现存 `toast(...)` 调用静默失败的 pre-existing bug
|
||
- Phase 3 业务功能(提交反馈 toast)的硬前置打通;为 03-02 的 Dialog 抽离 + RHF/Zod + Sonner 接入扫清 portal 障碍
|
||
- 不引入新依赖:sonner@^1.7.1 已在 package.json,4 个 lockfile 全部 0 行 diff
|
||
|
||
## Task Commits
|
||
|
||
每个 task 原子提交:
|
||
|
||
1. **Task 1:在 RootLayout 挂载 Sonner Toaster** - `7065d73` (feat)
|
||
|
||
## Files Created/Modified
|
||
|
||
- `app/layout.tsx` - 第 3 行新增 `import { Toaster } from '@/components/ui/sonner'`;第 17-21 行 `<body>` 块由单行 `<body>{children}</body>` 改为多行结构,`{children}` 之后追加 `<Toaster />`(共 +5 / -1 行)
|
||
|
||
## 具体行号映射
|
||
|
||
| 改动点 | 原内容 | 新内容 | 行号 |
|
||
|--------|--------|--------|------|
|
||
| import 块新增 | (无) | `import { Toaster } from '@/components/ui/sonner'` | 第 3 行 |
|
||
| `<body>` 块 | `<body>{children}</body>` | `<body>\n {children}\n <Toaster />\n</body>` | 第 17-21 行 |
|
||
|
||
## Decisions Made
|
||
|
||
- **挂载位置 `<body>` 内 `{children}` 之后**:Toaster 是顶层 portal,需在所有 children 之后挂载以确保 z-index / DOM 顺序正确;放在 `<body>` 内而不是 `<html>` 顶层,遵循 Sonner 官方推荐
|
||
- **保留单引号风格**:现有 `import './globals.css'` 用单引号,新增 import 沿用单引号保持文件内一致;与 plan body 描述一致(plan 的 `<verify>` grep pattern 使用双引号是 verify 脚本风格不一致,与实际写入内容无关)
|
||
- **不给 RootLayout 加 `"use client"`**:components/ui/sonner.tsx 顶部已 `"use client"`,RSC layout 直接渲染 client child 即可,无需整个 RootLayout 客户端化
|
||
- **不挂第二个 Radix Toast Toaster**:本 phase 锁定 Sonner 单一通道(CONTEXT.md D-Toast 决策),避免双 Toaster 系统并存
|
||
|
||
## Deviations from Plan
|
||
|
||
None — plan executed exactly as written。所有「严格约束」全部遵守:
|
||
- 未挂 Radix Toast `<Toaster />`
|
||
- 未新增 ThemeProvider / next-themes 包装
|
||
- 未改 metadata / html lang / globals.css import 顺序
|
||
- 未给 RootLayout 加 `"use client"`
|
||
- 本 plan 唯一改动 `app/layout.tsx` 的 task,未挂任何其他 provider
|
||
|
||
## Issues Encountered
|
||
|
||
无。Plan 描述精确(仅 1 个 task,2 处精确改动),verify 段除 grep 引号风格与 write 内容不一致这一非阻塞风格差异外,全部命中。
|
||
|
||
## 验证结果
|
||
|
||
| 验证项 | 期望 | 实际 | 结论 |
|
||
|--------|------|------|------|
|
||
| A 段 tsc 反向断言 | `npx tsc --noEmit` 输出过滤后 0 条指向 `app/layout.tsx` | 0 条命中 | ✅ 通过 |
|
||
| B 段 import grep | 命中 1 行 `from '@/components/ui/sonner'` | 第 3 行命中 | ✅ 通过 |
|
||
| B 段 `<Toaster />` grep | 命中 1 行 `<Toaster />` | 第 20 行命中 | ✅ 通过 |
|
||
| C 段 lockfile diff | `git diff --stat HEAD -- package.json *.lock` 输出 0 行 | 0 行 | ✅ 通过 |
|
||
| D 段 lint | 项目无 `.eslintrc*`,沿用 Phase 1+2 判定(不阻塞) | 跳过 | ✅ 沿用判定 |
|
||
|
||
`npx tsc --noEmit` 整体存量错误 67 条与本 plan 改动文件零相关(沿用 Phase 1+2 判定),未引入指向 `app/layout.tsx` 的新错误。
|
||
|
||
## User Setup Required
|
||
|
||
无 — 本 plan 不引入新依赖、不需要环境变量、不需要外部服务配置。
|
||
|
||
## Next Phase Readiness
|
||
|
||
- ✅ Sonner Toaster portal 已在全局挂载,Phase 3 Plan 02 可以放心调 `toast.success(...)` / `toast.error(...)`
|
||
- ✅ 4 个 lockfile 未动,下游 plan 不需重装依赖
|
||
- ⏭️ 下一步:执行 Plan 03-02(CredentialSlotDialog 组件抽离 + RHF/Zod 表单 + Sonner 提交反馈,落地 CRED-FE-04 + 闭环 CRED-FE-05)
|
||
- ⚠️ 本 plan 单独无法跑通端到端 toast 反馈(需 Plan 03-02 联动验证),属于硬前置类 plan 的预期形态
|
||
|
||
## Self-Check: PASSED
|
||
|
||
- ✅ `app/layout.tsx` 存在且包含改动(第 3 行 import + 第 17-21 行 `<body>` 块)
|
||
- ✅ commit `7065d73` 存在于 git log(`git log --oneline -1` 命中)
|
||
- ✅ tsc 反向断言通过(0 条新错误指向 app/layout.tsx)
|
||
- ✅ lockfile 0 diff(不引入新依赖)
|
||
|
||
---
|
||
|
||
*Phase: 03-dialog-feedback*
|
||
*Plan: 01*
|
||
*Completed: 2026-05-08*
|