Skip to content

[WIP] Add first-run onboarding flow for new installs - #453

Open
ujiro99 wants to merge 4 commits into
mainfrom
feat/onboarding-flow-refinements
Open

[WIP] Add first-run onboarding flow for new installs#453
ujiro99 wants to merge 4 commits into
mainfrom
feat/onboarding-flow-refinements

Conversation

@ujiro99

@ujiro99 ujiro99 commented Aug 24, 2026

Copy link
Copy Markdown
Owner

Summary

  • New-install onboarding flow (Steps 1-4: Search, AiPrompt, LinkPreview, Customize) guiding users through the select → command → result pattern
  • Onboarding tab close now routes through the background script (BgCommand.closeTab) so hasShownOnboarding is persisted before the tab closes
  • All 14 locale messages.json files updated with the onboarding strings

Redesign pass

  • Shared OnboardingLayout (brand header, 4-segment progress + counter, fixed-position Skip) replaces per-step chrome and the old per-step spotlight overlay with a constant vignette so nothing shifts between screens
  • Persistent select → command → result OnboardingRail reinforces the mental model across Steps 1-3 and the value-shown payoff screens
  • Step1/2's sample text now demonstrates the drag-to-select gesture at runtime (useSelectionDemo, measured via Range.getClientRects() so it's correct across all 14 locales' line-wrapping, not hardcoded pixel keyframes)
  • Actionable buttons (solid fill) are now visually distinct from decorative/state elements (tinted fill) throughout
  • Step4 shows both the real settings-panel commands and Command Hub suggestions side by side (no outbound link mid-onboarding); Step5 ends with a canvas-confetti celebration and closes to "try it now" as the primary action
  • Onboarding CSS moved off Onboarding.module.css onto Tailwind (tailwind.config.js keyframes + utility classes)
  • New e2e-only screenshot tool (e2e/onboarding-shots.spec.ts, CAPTURE=1 yarn test:e2e onboarding-shots) using a ?step=&phase= dev-only override in useOnboardingState to capture every step/phase across locales for design review

Closes #452

Test plan

  • tsc --noEmit passes
  • yarn lint passes (0 errors)
  • yarn test:run passes (1057 tests, including new onboardingProgress / useSelectionDemo coverage)
  • yarn build / yarn build:e2e pass
  • Captured and visually reviewed screenshots of every step/phase in ja / en-US / de
  • Manually verify the onboarding tab opens on first install, walk through Steps 1-4, and confirm Skip/Close both close the tab without reopening onboarding on next load

🤖 Generated with Claude Code

https://claude.ai/code/session_01WaFfYLgE9pcwo3wSwEeG8D

ujiro99 and others added 2 commits August 24, 2026 19:42
Guides new users through the popup menu, AI prompt command, and link
preview right after install via a dedicated onboarding tab, with a
final Customize/Complete screen that persists hasShownOnboarding so
it only runs once.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019NHfjgYsFbd7tPbEdQSg4p
…d Hub link

Add a slow-blink hint on Step1 while waiting for the user to return from
the search command's tab, short pattern captions on Steps 1-3 to reinforce
the select-command-result mental model, and a Command Hub link on Step4.
Also route onboarding tab close through the background script (closeTab)
so the settings write completes before the tab closes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017QRxn2pRzMCWvf9nK2w7Kq
@codecov

codecov Bot commented Aug 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 23.97755% with 948 lines in your changes missing coverage. Please review.
✅ Project coverage is 45.54%. Comparing base (7e0fb4d) to head (5cd3492).

Files with missing lines Patch % Lines
.../components/onboarding/steps/StepSearchCommand.tsx 0.00% 114 Missing ⚠️
.../src/components/onboarding/steps/StepCustomize.tsx 0.00% 100 Missing ⚠️
...on/src/components/onboarding/useOnboardingState.ts 0.00% 93 Missing ⚠️
...omponents/onboarding/steps/StepAiPromptCommand.tsx 0.00% 89 Missing ⚠️
...nsion/src/components/onboarding/OnboardingRail.tsx 0.00% 70 Missing ⚠️
...rc/components/onboarding/steps/StepLinkPreview.tsx 0.00% 65 Missing ⚠️
...ion/src/components/onboarding/OnboardingLayout.tsx 2.08% 47 Missing ⚠️
...src/components/onboarding/OnboardingTargetText.tsx 0.00% 45 Missing ⚠️
...n/src/components/onboarding/steps/StepComplete.tsx 0.00% 41 Missing ⚠️
...nsion/src/components/onboarding/OnboardingPage.tsx 0.00% 40 Missing ⚠️
... and 16 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #453      +/-   ##
==========================================
- Coverage   46.57%   45.54%   -1.04%     
==========================================
  Files         239      263      +24     
  Lines       25710    26957    +1247     
  Branches     2053     2111      +58     
==========================================
+ Hits        11975    12278     +303     
- Misses      13735    14679     +944     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@claude

claude Bot commented Aug 24, 2026

Copy link
Copy Markdown

コードレビュー

新規インストール時のオンボーディングフロー追加、お疲れ様です。全体的にステップの状態管理(OnboardingStep / StepPhase)やIPC経由のタブクローズなど、既存の設計パターンを踏襲していて読みやすい実装だと思います。特に useOnboardingState.tsskip() が「設定の永続化を待ってからタブを閉じる」ことを明示的にコメントで説明している点は良い設計判断です。

以下、気になった点を挙げます。

1. StepComplete の Close ボタンで hasShownOnboarding の保存を待たずにタブを閉じてしまう(バグの疑い)

  • packages/extension/src/components/onboarding/steps/StepComplete.tsx:17-19
    useEffect(() => { complete() }, [complete])complete() を呼んでいますが、await していません。
  • packages/extension/src/components/onboarding/useOnboardingState.ts:79-84
    const complete = useCallback(() => {
      sendOnboardingEvent(ANALYTICS_EVENTS.ONBOARDING_COMPLETE, {...})
      markFinished()  // ← await していない
    }, [markFinished])
    markFinished() 内部の Settings.update("hasShownOnboarding", () => true)useOnboardingState.ts:66)は chrome.storage.sync への書き込みで非同期です。
  • StepComplete.tsx:38 の Close ボタンは onClick={() => closeOnboardingTab()} で、complete() の完了を待たずに即座にタブクローズのIPC(BgCommand.closeTab)を送ります。

つまり、skip()useOnboardingState.ts:73-77)では

const skip = useCallback(async () => {
  sendOnboardingEvent(ANALYTICS_EVENTS.ONBOARDING_SKIP, { step })
  await markFinished()
  await closeOnboardingTab()
}, [step, markFinished])

と明示的に「設定の書き込み完了を待ってからタブを閉じる」設計にしているにもかかわらず、StepComplete の Close ボタンだけはこのパターンから外れています。ユーザーがStepComplete表示直後に素早くCloseを押すと、hasShownOnboarding=true の書き込みが完了する前にタブが閉じられる可能性があります(chrome.storage.sync への書き込みはデバウンス処理もあり packages/extension/src/services/storage/index.ts:12,35-46 で10msの遅延が入っています)。

対応案としては、StepComplete の Close ボタンも skip() と同様に await complete() してから closeOnboardingTab() を呼ぶ形に統一するのが良さそうです。

2. hasShownOnboarding がどこからも読み取られていない

  • chrome.runtime.onInstalledpackages/extension/src/background_script.ts:468-475)でオンボーディングタブを開く条件は details.reason === chrome.runtime.OnInstalledReason.INSTALL のみで、hasShownOnboarding の値は一切参照されていません。
  • リポジトリ全体を検索しても、hasShownOnboarding を読み取って何かを分岐させている箇所が見当たりませんでした(書き込みのみ)。
  • USER_STATSchrome.storage.syncpackages/extension/src/services/storage/index.ts:56-62, 96-99)に保存されるため、同じGoogleアカウントで同期している状態で再インストールした場合などに意味を持ちそうですが、onInstalled 内で先に Settings.reset()background_script.ts:472)が呼ばれてデフォルト値(hasShownOnboarding: false)に戻ってしまうため、結局オンボーディングは毎回表示されるように見えます。

PR概要に「hasShownOnboarding を永続化するので一度しか実行されない」とありますが、現状のコードではこのフラグが実質的に「書くだけで読まれない」状態になっているようです。将来的な用途(オプション画面からの再表示制御など)のための先行実装であれば問題ありませんが、意図通りかどうか確認をお願いします。

3. テストカバレッジ

  • packages/extension/src/components/onboarding/ 配下(useOnboardingState.tsOnboardingPage.tsxsteps/*.tsx など、今回追加された約10ファイル)に対する単体テストが一つも見当たりません。特に useOnboardingState.ts はステップ遷移・スキップ・完了処理などロジックが集中しているので、優先的にテストを追加する価値がありそうです。
  • background_script.ts:73-84 で新規追加された closeTab ハンドラ(レスポンスをタブ削除の前に返す、という順序が重要な実装)についても、background_script.test.ts 内に専用のテストケースが見当たりませんでした。既存の IN-01IN-04 同様のテストを追加しておくと、将来のリファクタ時に順序が壊れるのを防げます。

4. その他(軽微)

  • StepSearchCommand.tsx:30commands?.find((c) => c.title === "Google") はタイトル文字列でのマッチングです。defaultSettings.ts を確認したところ、全14ロケールで "Google" という同一タイトルの検索コマンドが含まれていることを確認できたので現状は問題ありませんが、将来ユーザーがコマンドタイトルを変更した場合や、タイトルの表記が変わった場合には吹き出し(callout)の対象要素が見つからなくなります(コマンド実行自体の検知は COMMAND_TYPE.SEARCH ベースなので、フローが完全に止まるわけではなく演出上の見た目のみの影響です)。

良かった点

  • 全14ロケールの messages.jsononboarding_* キーが過不足なく追加されていることを確認しました(各ロケール27キーで一致)。
  • executor.ts / useDetectLinkCommand.ts からの dispatchCommandExecuted 発火は executor.test.ts でテストされており、オンボーディングのイベント検知の土台部分はカバーされています。
  • コメントで設計判断の理由(なぜ window.close() ではなく背景スクリプト経由か、なぜ response をタブ削除前に返すか等)が丁寧に書かれており、今後のメンテナンス性が高いです。

🤖 このレビューはClaude Codeによって自動生成されました。

ujiro99 and others added 2 commits August 25, 2026 13:09
…orcement

Replace the per-step spotlight overlay with a constant vignette, add a
persistent select-command-result progress rail, demonstrate the drag-to-
select gesture at runtime (locale-proof via Range.getClientRects), and
distinguish actionable buttons from decorative state with fill/tint. Move
CSS off Onboarding.module.css onto Tailwind, and add a canvas-confetti
celebration on the completion screen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WaFfYLgE9pcwo3wSwEeG8D
@claude

claude Bot commented Aug 26, 2026

Copy link
Copy Markdown

コードレビュー: #453 初回インストール向けオンボーディングフロー追加

大規模な機能追加(新規ファイル約30個、全14ロケールのmessages.json更新)ですが、既存パターン(BgCommandIpcuseSettingsSender型など)に沿った実装になっており、全体的に品質は高いと感じました。テストカバレッジも新規ロジック(onboardingProgress, useSelectionDemo, background_scriptのIN-03/04など)にきちんと付与されています。細かい指摘・確認事項を以下にまとめます。

1. StepPhase.WAIT_SELECTION が未使用 (軽微)

packages/extension/src/types/onboarding.ts:17

WAIT_SELECTION = "wait_selection",

リポジトリ全体を検索しても、この値を参照している箇所が定義以外に見当たりませんでした。将来のステップ追加を見越した定義であれば問題ありませんが、現時点では未使用コードになっているので、使う予定がなければ削除、使う予定があればコメントでその旨を残すと良さそうです。

2. Step*Commandのコールアウト対象要素をポーリングで探索している (StepSearchCommand.tsx:53-68, StepAiPromptCommand.tsx:47-63)

const find = () => {
  if (cancelled) return
  const elm = document.querySelector(`[data-command-id="${...}"]`)
  if (elm) {
    setCalloutElm(elm)
  } else {
    window.setTimeout(find, 150)
  }
}

ポップアップメニューが何らかの理由(例: コマンド無効化、DOM未マウント)で永久に描画されないケースだと、cancelledがtrueになるまで(=phaseが変わるかアンマウントされるまで)150ms間隔でポーリングし続けます。実害は小さいですが、MutationObserverを使う方が「ポーリングし続ける」よりも堅牢かもしれません(必須の修正ではなく将来的な改善案です)。

3. StepSearchCommand.tsx:15 コマンドをタイトル文字列で検索

const googleCommand = commands?.find((c) => c.title === "Google")

defaultSettings.tsを確認したところ、CMD_GOOGLEtitleは全ロケール共通で"Google"固定(ローカライズされていない)なので、現状は問題なく動作します。ただし、将来Googleコマンドのタイトルがローカライズされたり、コマンドが並び替え/複製されたりした場合に壊れやすい検索方法です。onboardingCommand.tsのAIプロンプトコマンドのように、Google検索コマンド側にも固定IDを振ってidで検索する方が堅牢だと思います(テストで担保されているわけではないので気づきにくい箇所です)。

4. StepCompletecomplete()がawaitされていない (StepComplete.tsx:22-24, useOnboardingState.ts:79-84)

useEffect(() => {
  complete()
}, [complete])
const complete = useCallback(() => {
  sendOnboardingEvent(ANALYTICS_EVENTS.ONBOARDING_COMPLETE, {...})
  markFinished()  // Settings.update(...) は非同期だが await されない
}, [markFinished])

skip()ではhasShownOnboardingの書き込みをcloseOnboardingTab()呼び出し前に明示的にawaitしていますが(コメントにもその意図が書かれています)、complete()側は書き込み完了を待たずに終わります。実際にタブを閉じるのはユーザーが「閉じて使ってみる」ボタンを押した時点なので通常は書き込みが間に合いますが、もしユーザーが完了画面表示直後にタブをネイティブに閉じる(ブラウザのタブ×ボタンなど、closeOnboardingTab()を経由しない操作)と、hasShownOnboardingの永続化が間に合わない可能性があります。実害は小さい(次回以降オンボーディングが自動再表示されるトリガーがOnInstalledReason.INSTALLのみのため)ですが、skipとの非対称性は意図的か確認したいところです。

5. OnboardingConfettiのreduced-motion判定について (OnboardingConfetti.tsx)

disableForReducedMotionオプションの代わりに独自のusePrefersReducedMotionを使っている設計判断とその理由(matchMedia('(prefers-reduced-motion)')が値なしだと常にtrueになる問題を回避)がコメントで明確に説明されており、良い実装だと思います。MV3のCSP制約に対するuseWorker: falseの説明も含め、この辺りのコメントは非常に丁寧で読みやすかったです。

6. i18nメッセージのdescriptionフィールドがenロケールにのみ存在

en/messages.jsonは新規追加の全キーにdescriptionが付与されていますが、他13ロケールには付与されていません。Chrome拡張のmessages.jsonの仕様上、翻訳作業用のメタデータなので動作への影響はありませんが、既存の構造と一致しているか(他の既存キーもenのみdescriptionを持つ運用なのか)念のため確認だけしておくと良さそうです。おそらく既存の運用ルールに沿っているだけだと思います。

良かった点

  • background_script.tscloseTab実装(response()chrome.tabs.remove()より先に呼ぶことで、閉じられるタブ自身がレスポンスを待っている競合状態を回避する設計)とそのコメントは明快で、既存のgetTabId/getActiveTabIdパターンとも整合しています。
  • useSelectionDemo.tsbuildKeyframesが実測(Range.getClientRects())ベースでロケール非依存になっている点、およびそのロジックが純粋関数として切り出されテスト(useSelectionDemo.test.ts)されている点は良い設計です。
  • onboardingEvents.tsによるイベント経由の疎結合設計(executor.ts/useDetectLinkCommand.tsはオンボーディングの存在を知らなくて良い)は、コア機能への影響を最小限に抑えた良いアプローチです。
  • hasShownOnboardingのマイグレーション(ImportExport.tsx, enhancedSettings.ts, settings.ts, storage/index.ts)が一通りのレイヤーで漏れなく更新されています。

セキュリティ面では、dangerouslySetInnerHTMLやユーザー入力の直接埋め込みは見当たらず、問題ありませんでした。パフォーマンス面も、ResizeObserverRange.getClientRects()の利用は妥当な範囲で、大きな懸念はありません。

以上、大きな問題は見当たらず、上記の軽微な点をご検討いただければと思います。

@ujiro99 ujiro99 changed the title Add first-run onboarding flow for new installs [WIP] Add first-run onboarding flow for new installs Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PRD:初回オンボーディングによるTTV短縮

1 participant