首页
/ LobeHub 入职引导模块系统化 UX 审计实战:一个可复用的 worked example 全解

LobeHub 入职引导模块系统化 UX 审计实战:一个可复用的 worked example 全解

2026-09-07 21:43:56作者:何将鹤

这篇技术指南以 LobeHub 仓库中 ux-audit 技能的官方范例文档(.agents/skills/ux-audit/references/example/onboarding.md)为核心主体,完整还原一次针对整个 Onboarding(首次引导)模块的系统性(systemic)UX 审计:从审计框架与覆盖分层、审计范围界定、模式清单盘点,到亮点沉淀、10 项分级缺陷的定位与定级、规则回灌与工单落地。读完你将掌握一套"以代码静态审计为主、以模式目录为基准、以规则回灌为闭环"的可重复 UX 审计方法论,并看清它在 LobeHub 真实代码库中如何落地。


一、这是一次什么样的审计:系统性(systemic)而非单屏

ux-audit 技能对一次审计只处理一个 surface 有着严格约束(见 SKILL.md),但当目标不是单个页面、而是"一批强相关的相关界面"时,就会升级为 systemic pass。onboarding.md 记录的就是这样一次 2026-07 对整个 Onboarding 模块(首次运行设置,first-run setup)的真实运行。

审计采用三层结构,每层对应独立的程序文件,且有一个铁律:结论必须来自能看见它的那一层

层级 程序文件 干什么 能捕获什么
L1 静态 layer-1-static.md 读代码 缺失的状态/分支(empty/error/retry)、草稿未持久化、模式缺失、结构性问题
L2 视觉 layer-2-visual.md 对渲染结果截图 真实视觉层级与主导控件、间距/对比/对齐、截断/溢出、empty/loading/error 的真实观感、断点、明暗模式
L3 动态 layer-3-dynamic.md 驱动真实用户旅程 + 插桩 进行中/锁定态、强制的错误/空态、step N→N+1 是否成立、焦点/键盘、量化的 CLS/LCP/INP

本次 Onboarding 审计只运行了 L1(静态/代码层),L2/L3 均未执行(本次没有渲染与运行环境)。因此,所有涉及真实按钮主导性、进度条是否渲染的视觉结论都被打上了 pending L2 标签——这正是"一个结论必须由能看到它的层来下"这一 ground rule 的直接体现,详见 coverage matrix

二、审计范围:两个入口背后的三条并行流程

审计首先要做的不是埋头读代码,而是界定 surface 的"类"(class)并列出该类别的应有能力。Onboarding 的表面类对应模式目录中 Getting started 家族(Welcome / Guided Tour / Empty-state-as-onboarding),被审计的是同一族小表面:

流程 路由 屏幕(按顺序) 编排器
公共前缀 /onboarding?step=1|2 Telemetry → ResponseLanguage features/Onboarding/Common/index.tsx
Classic(web/mobile) /onboarding/classic FullName → Interests → [ProSettings] → AgentPicker features/Onboarding/Classic/index.tsx
Agent(web/mobile) /onboarding/agent 单步对话式 features/Onboarding/Agent/index.tsx
Desktop(Electron) /desktop-onboarding?screen= Welcome → [Permissions·mac] → DataMode → Login routes/(desktop)/desktop-onboarding/index.tsx

在当前仓库中可对应定位到:公共前缀与分支切换收敛于 src/features/Onboarding/index.tsx(依据 ?step 查询参数渲染 TelemetryStep 或 ResponseLanguageStep,前缀完成后内联渲染 Classic 分支);Classic 分支的步骤机集中在 Classic/index.tsx(步骤 1=FullName、2=Interests、3=ProSettings、4=AgentPicker);桌面流程则在 DesktopOnboardingsrc/routes/(desktop)/desktop-onboarding/index.tsx 对应的桌面路由下。

审计快照记录的编排关系如下:

  • 公共前缀通过 deriveOnboardingBranchPathbranch.ts:18)汇入 Classic Agent 分支;
  • Agent 分支受构建开关 AGENT_ONBOARDING_ENABLED + 运行时 enableAgentOnboarding + !isDesktop 共同门控;
  • 步骤外壳(step chrome)在 web 端由 routes/onboarding/_layout、桌面端由 routes/(desktop)/desktop-onboarding/_layout 共享。

持久化 / 恢复(健康区): Classic 步骤是服务端持久化的(onboarding.currentStep + finishedAt,见 store/user/slices/onboarding/action.ts),上层叠加了乐观的 localOnboardingStep 与一个合并写队列(coalescing update queue);桌面端通过 resolveInitialScreen(URL → saved → everCompleted → Welcome,见 DesktopOnboarding/resolveInitialScreen.ts)恢复;老用户通过 needsOnboardingselectors.ts)整段跳过。回跳 URL 参数在整个流程中被一路传递(见 src/utils/onboardingRedirect.ts 及其测试 onboardingRedirect.test.ts)。

三、模式清单:用了什么、用得怎么样

审计的基准是 Jenifer Tidwell《Designing Interfaces》的模式语言 + LobeHub ux 技能的执行清单(见 pattern-catalog.mdux skill)。对照下表可以快速看出模式分布的"强区"与"真空区":

模式(家族) 位置 评级 备注
Welcome / Sign-on Telemetry(TelemetryStep.tsx)、桌面 Welcome 有目的性的首屏、打字机开场
Guided Tour / Onboarding(分步) Common + Classic 线性步骤 ⚠️ 有步骤但无进度/Sequence Map(缺陷③)
Sequence Map / 进度 最多 6 个 classic / 4 个 desktop 屏幕,却无 "N of M"(缺陷③)
Escape Hatch(跳过) AgentPicker 跳过;agent 分支模式的布局跳过 ⚠️ 纯 classic 流程直到最后一步前都无法跳过(缺陷⑤)
Deep-linking ?step(web)、?screen(desktop)恢复位置 规范化、可恢复
Empty-state as onboarding AgentPicker 区分空态与错误态(index.tsx:162-167 做得好——但错误态无重试(缺陷④)
Loading Skeleton AgentPicker 骨架、Agent 品牌加载器、桌面 Suspense 项目级加载器,未用 antd Spin
Failure + Retry 桌面 LoginStep 完整 idle/loading/success/error + retry+cancel 典范——其他处应以此为模板
Failure + Retry web 写入步骤 + AgentPicker install/load 缺陷①②④⑥
Progress Indicator / Cancelability 桌面 LoginStep 认证倒计时 + 取消(LoginStep.tsx:293
Prominent "Done" Button 每步一个主按钮贯穿全流程 主导性待 L2 验证
Illustrated Choices Interests 网格、桌面 DataMode

阅读结论: 状态机类工作(桌面 Login、恢复、乐观队列、回调贯穿、Agent bootstrap→classic 降级)已成熟;薄弱点集中在 Feedback(web 写入步骤的失败/重试) 与一个 Navigation 类规范缺口(无进度指示 / Escape Hatch 偏弱)

四、亮点沉淀:"不可回归清单"

该模块最强的地方恰恰是"找缺陷"最容易漏掉的部分——状态机与恢复管道,它们是审计"回灌闭环"里 ✅ 的那一半,也是下一次 onboarding 改动时的"don't regress"清单:

  • ✅ 亮点 —— 桌面 LoginStep 状态机(→ Feedback / Failure+Retry 的 ✅ 范例)。 完整覆盖 idle / loading / success / error,且带 retry + cancel + 认证倒计时,由主进程广播(authorizationSuccessful / Failed / Progress)驱动,并与真实远端配置对齐(见 DesktopOnboarding/steps/LoginStep.tsx)。web 写入步骤(缺陷①②④⑥)应拷贝这个失败重试样板。
  • ✅ 亮点 —— 恢复 / 持久化。 Classic 步骤服务端持久化(onboarding.currentStep + finishedAt),底层是乐观 localOnboardingStep 加一个能扛住快速连续点击的合并写队列(见 action.ts 中通过 #enqueueOnboardingWrite 串行化的写入链);桌面经 resolveInitialScreen(URL → saved → everCompleted → Welcome)恢复;老用户由 needsOnboardingselectors.ts)整段跳过。被中断的引导会在正确步骤重新打开。
  • ✅ 亮点 —— Agent bootstrap 失败时降级到 Classic 而非白屏。 bootstrap 查询失败会重定向进确定性的 classic 流程,而不是把用户困在坏掉的对话里(features/Onboarding/Agent/index.tsx:330-335)——优雅降级到可靠基线。(其姊妹 ErrorBoundary fallbackRender={() => null} 位于 :372,是唯一弱项,见 §5 缺陷⑩。)
  • ✅ 亮点 —— WrapUp 是一个带 finally 的"确认 → 进行中 → 完成"。 WrapUpHint 在结束前跑 confirmModal,并在 finally 中重置 loadingWrapUpHint.tsx:35-52)——这正是语言门写入(缺陷①)缺失的形状。
  • ✅ 亮点 —— Callback-URL 贯穿。 注册目标被暂存、历经整个多步流程、结束时消费,并经过安全重定向守卫(utils/onboardingRedirectAgentPickerStep/index.tsx:114)——首次绕行后把用户送回原目的地。当前仓库中该能力可从 onboardingRedirect.tsLayout/index.tsxstashOnboardingCallbackUrl(search) 调用看到。
  • AgentPicker 空态-错误态之分。 failedToLoadempty 分别渲染(AgentPickerStep/index.tsx:162-167)——"错误≠空"做对了(缺失的重试是缺陷④,而非对该区分的否定)。可恢复、规范化的深链(?step / ?screen)。

五、体验缺陷(已排序分级)

① ResponseLanguage —— 公共前缀门写入无失败路径 → 永久卡死步骤 🔴

handleNext 先置 isNavigating=true,然后 await setSettings({ general: { responseLanguage } }) 无 try/catch/finally(审计快照的 ResponseLanguageStep.tsx:37-43)。而这次写入正是 commonStepsCompleted 的唯一信号(selectors.tscommonStepsCompleted 只检查 responseLanguage 是否已写入)。若写入被拒(如网络抖动),onNext 永不触发、isNavigating 永不复位 → Send 与 Back 永远 disabled,无错误、无重试:用户被锁死在语言屏,进不了产品。门控整个流程的那一次写入,恰恰是零失败处理的那一次。

值得补充的仓库复核:当前代码中 ResponseLanguageStep.tsx 已将 setSettings 写入包进 try/catch,失败时置 hasError、复位 isNavigatingRef/isNavigating,并渲染 responseLanguage.saveFailed 错误文案——说明该缺陷在审计后已得到修复,这也正是审计落地价值的一个直接证据。

② AgentPicker —— agent 安装失败被吞掉,引导却照常完成 🔴

handleContinueinstallMarketplaceAgents 包在 catch { console.error } 里,然后照样走 finish('continue') → finishOnboarding() → navigate 离开(AgentPickerStep/index.tsx:135-140)。用户亲手挑选的 agents 静默安装失败,最终落在一个缺少这些 agents 的应用里却毫无提示——最后一步的全部意义可能不可见地失效。仓库复核:steps/AgentPickerStep/index.tsx 中该 catch-and-continue 逻辑仍然存在。

③ 任何流程都没有进度 / Sequence Map —— surface-class 基准(Navigation)🟠

Classic 最多连续 6 屏(telemetry→language→fullname→interests→[prosettings]→agentpicker),desktop 也有 3–4 屏;两者都不显示 "Step N of M" 或进度条——模块内唯一的 <Steps> 只是 Telemetry/Welcome 里的装饰性功能列表current={null}TelemetryStep.tsx:82WelcomeStep.tsx:72)。而同类成熟产品(Notion / Linear / Slack / Vercel 的设置向导)普遍展示总长度与当前位置。用户无法判断引导还要多久。(待 L2 确认真实渲染。)

④ AgentPicker 错误态无重试 🟠

模板加载失败时只渲染一段裸的 agentMarketplace.picker.failedToLoad 文案(AgentPickerStep/index.tsx:160-167),没有 Reload。空态与错误态确实被正确区分(好),但最后一步的核心能力丢失后,只能靠 Skip 放弃来恢复。

⑤ FullName 必填、classic 流程到最后一步前无 Escape Hatch 🟠

FullNameStep 唯一的向前控件是 SendButton,非空名字前一直 disabledFullNameStep.tsx:74),无 Skip / 无名下一步;布局层的 Skip 链接只在 agent 分支模式下渲染(_layout/index.tsx:45-50)。因此纯 classic 流程强迫用户走完 telemetry/language/fullname/interests/prosettings 直到 AgentPicker 都无跳过。类规范:可选资料步骤应可跳过,身份设置不应硬阻塞首次进入。

⑥ 资料写入是 fire-and-forget,无失败反馈 🟡

FullName(FullNameStep.tsx:34)、Interests(InterestsStep.tsx:72)、Telemetry(TelemetryStep.tsx:35)调用 updateFullName/updateInterests/updateGeneralConfig不 await、不 catch,随即 onNext()。store action 是异步的(common/action.ts:54,59),但各步骤无视了这个 promise:服务端持久化失败是静默的,值丢失而流程继续前进。(乐观 store 只是软化显示,不保证持久性。)仓库复核:FullNameStep.tsx 当前 handleNext 仍是"调用 updateFullName(value.trim()) 后立即 onNext()",未 await。

⑦ 步骤内草稿不跨刷新持久化 🟡

输入的姓名(FullName)与自定义兴趣(Interests)只存在于本地 useState,仅 Next 时才提交。步骤级恢复可用(服务端 currentStep),但步骤中途刷新会丢失未发送输入。

⑧ 步骤同步失败被吞掉 🟡

internal_processStepUpdateQueue 对服务端写入只 console.erroronboarding/action.ts:91-93)。若步骤持久化持续失败,恢复点会悄然不前且无人告知用户(低危:下一步时自愈)。

⑨ ComposioServerList 拉取无 loading/error 面 🟡

useFetchUserComposioConnections(true) 驱动各应用的连接状态,但网格始终渲染静态 COMPOSIO_APP_TYPESComposioServerList/index.tsx:14-37);连接拉取失败会静默地把所有集成显示为未连接——"加载失败"被读成"什么都没连"。非死路(可选步骤)。(逐项渲染待 L2。)

⑩ Agent 对话子树失败 → 白屏 🟡

对话被包在 <ErrorBoundary fallbackRender={() => null}> 中(Agent/index.tsx:372),chat 子树一旦抛出就渲染——无错误、无重试。Agent 流程为换取丰富性付出了更大的单轮失败面;它值得一个可见错误 + 恢复(或复用上面那个 bootstrap-error → Classic 降级路径)。该问题在 Agent-vs-Classic 对比中被暴露。

六、技能反馈:审计如何反哺规则库(回灌闭环)

回灌闭环有两个半边——缺陷打磨某条清单项的 ❌ 例子,亮点打磨其 ✅ 例子。本次运行两半边都落了地:

  • 新 ❌ 规则落地:Grow §5.2 —— 多步流程要显示进度并保持可跳过。 分步流程(>2 步)必须 (a) 展示进度/步骤指示器(位置 + 总数)、(b) 让非必需步骤可跳过并提供始终可见的 escape hatch;同时镜像进 SKILL.md 的 Quick review。❌ 例子即缺陷③ + ⑤(模块内唯一的 <Steps> 是装饰性的,current={null})。对应规则现可在 ux/references/grow.md 的 §5.2 看到。
  • 既有规则强化 + 新 ✅ 例子落地:Feedback §4.2 现在同时覆盖"被 await 的门控写入"——它必须在 finally 中复位 in-progress 标记并在 catch 时提供重试,否则一次失败写入会永久禁用前进控件。❌ 例子:缺陷①。✅ 例子:带 retry + cancel 的桌面 LoginStep 状态机——它现在成为清单引用的正面模型。对应规则见 ux/references/feedback.md 的 §4.2。
  • 既有规则得到验证(补充了新的 ❌ 引用例):§4.2(②④⑥⑧⑨⑩)、§3.5(②⑥)、Edit §2.1(⑦)、Read §1.1 error-as-empty(⑨)、Escape Hatch(⑤)。
  • 方法论回灌:Agent-vs-Classic 之问催生了一条新的 ux-audit 基本规则——"比较两个变体时:胜者是一个结果性(outcome)判定,而非工艺性(craft)判定",并在覆盖率矩阵中新增 A/B-winner 行,用本模块自己的失误作为 ❌ 自省例。这条规则本身已写入 SKILL.md 的 ground rule:winner 判定必须由 L3/analytics 裁决,L1/L2 只能比较机制,不能宣布赢家。

七、待办:L2 视觉 + L3 动态验证清单

审计对任何无法由 L1 定论的结论都留了明确的后验任务,而非妄下结论:

  • L2 —— 确认无进度指示器渲染(③);确认每一步主按钮都是主导控件(全步骤 pending-L2);AgentPicker 的 empty/error/loading 真实渲染可区分(④);ComposioServerList 逐项连接/错误渲染(⑨);暗色 + 窄屏。
  • L3 —— 对 ResponseLanguage 的 setSettings 写入强制断网以实况确认卡死步骤(①);强制 installMarketplaceAgents reject 并确认静默完成(②);强制 AgentPicker 模板加载失败并确认无重试死路(④);完整走一遍 classic 确认前进动能 + 无跳过(⑤);测量步骤切换的 INP / CLS。

八、结果落地:从发现到工单队列

发现最终落地为 LOBE-11138("Onboarding UX Audit",挂靠在 UX-audit 父任务 LOBE-11078 之下),拆分为以下子问题;类规范缺口(③⑤)同时回灌进 ux 的 Grow §5.2,await-write 规则(①)则回灌进 Feedback §4.2(见第六节):

子问题 发现 类型
LOBE-11154 ① language-gate 卡死步骤(加 finally + retry) bug 🔴
LOBE-11155 ②④ AgentPicker:安装失败静默完成 + 加载失败无重试 bug 🔴
LOBE-11156 ③ 进度 / Sequence Map 缺失 bug + 回灌
LOBE-11157 ⑤ FullName 必填 / 无 escape hatch bug + 回灌
LOBE-11158 ⑥⑦⑧⑨ fire-and-forget 写入 / 草稿丢失 / 静默步骤同步 / composio 状态 bug 🟡
未归档 ⑩ Agent 对话 ErrorBoundary → 白屏(并入 LOBE-11155 或新建) bug 🟡

九、把这个方法论搬到你的模块

onboarding.md 的可复用之处不在于"Onboarding 有什么问题",而在于它的审计姿势,六步闭环可直接迁移:

  1. 定类:先命名 surface 的类与同类产品规范(Getting-started 家族、设置向导、OAuth 同意页……),写下"应有能力清单"再审计——纯代码审计对"从没构建过的能力"天然失明;
  2. 跑 L1:按模式目录逐项对照状态(empty/error/retry、进度、escape hatch、深链、骨架屏),每项结论都必须给 file:line 证据;
  3. 分层裁决:视觉/运行期结论一律标注 pending L2/L3,绝不拿 L1 去 tick L2 的结论;
  4. 沉淀 ✅:把状态机、持久化、降级路径等强项写进"don't regress"清单;
  5. 给缺陷定级排序:按能否困住用户(🔴 卡死/不可见失败)→ 类规范缺失(🟠)→ 静默降级(🟡)排序,每条都要能说出"用户在哪个界面、点哪个按钮、看到什么";
  6. 回灌 + 建工单:好例子磨亮清单的 ✅,缺陷磨亮 ❌,并同步到 issue 队列。

本仓库的 ux-audit 技能目录还提供了一整组其他模块的同类 worked example(settings、chat、home、profile、tasks、topic、stats 等,见 .agents/skills/ux-audit/references/example),以及 layer-1/2/3 三层程序文件。若你在 LobeHub 中负责某一屏的体验质量,完全可以直接对照这份清单与模式目录复跑一遍——这就是仓库文档化该技能想让你获得的标准化审计能力。

文中涉及 Agent 分支与部分 _layout 的细节来自 2026-07 审计快照;若与当前 src/features/Onboarding 目录结构存在出入(如公共前缀现收敛于 index.tsx、桌面引导集中于 src/features/DesktopOnboarding),请以仓库最新代码为准——审计记录的价值正在于它给出了可复核的起点与可跟踪的修复轨迹。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
594
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
916
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
516
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388