user-journeys
ユーザー体験フローの設計・分析を行うスキルで、カスタマージャーニーマッピング、UX検証、エラー発生時の回復フロー定義をサポートします。ユーザーの行動導線を可視化し、体験上の課題や改善点を特定したい場面で活用できます。
description の原文を見る
User experience flows - journey mapping, UX validation, error recovery
SKILL.md 本文
ユーザージャーニー スキル
実際のユーザー体験を定義・テストするためのスキルです。仕様だけでなく、人がアプリケーション内で実際に取るフローをキャプチャします。
哲学
仕様は機能をテストします。ジャーニーは体験をテストします。
機能はすべての仕様に合格していても、ひどい体験を提供することがあります。ユーザージャーニーは以下をキャプチャします:
- ユーザーが実際にどのようにナビゲートするか(彼らがどのようにすべきかではなく)
- 各ステップでの感情状態(いらいら、混乱、喜び)
- ミスからの回復(ユーザーはミスを犯します)
- 現実世界の条件(低速ネットワーク、中断、気が散ること)
ジャーニードキュメント構造
_project_specs/
├── journeys/
│ ├── _template.md # ジャーニーテンプレート
│ ├── critical/ # 必ず機能するジャーニー(収益、コア価値)
│ │ ├── signup-to-first-value.md
│ │ ├── checkout-purchase.md
│ │ └── login-to-dashboard.md
│ ├── common/ # よくあるユーザーパス
│ │ ├── browse-and-search.md
│ │ ├── update-profile.md
│ │ └── invite-team-member.md
│ └── edge-cases/ # エラー回復、異常なパス
│ ├── payment-failure-retry.md
│ ├── session-timeout-recovery.md
│ └── offline-reconnection.md
ジャーニーテンプレート
# ジャーニー: [名前]
## 概要
| 属性 | 値 |
|-----------|-------|
| **優先度** | Critical / High / Medium |
| **ユーザータイプ** | 新規 / リターン / 管理者 |
| **頻度** | 毎日 / 毎週 / 一度 |
| **成功指標** | コンバージョン率、完了時間、ドロップオフ率 |
## ユーザーゴール
ユーザーが何を達成しようとしているのか?ユーザーの視点から書きます。
> 「私は[目標]したいので、[利点]できます。」
## 前提条件
- ユーザー状態(ログイン済み、サブスクリプション有り、初回訪問)
- データ状態(カートにアイテムがある、チームメンバーがいる)
- 環境(モバイル、デスクトップ、低速接続)
## ジャーニーステップ
### ステップ 1: [エントリーポイント]
**ユーザーアクション:** ユーザーが何をするか
**システムレスポンス:** 彼らが見るべき/経験すべきもの
**成功基準:**
- [ ] ページが2秒以内に読み込まれる
- [ ] プライマリCTAがすぐに表示される
- [ ] ユーザーが次に何をすべきか理解している
**潜在的な摩擦:**
- 読み込みが遅い → スケルトン/ローダーを表示
- CTAが不明確 → コピーのバリエーションをA/Bテスト
---
### ステップ 2: [次のアクション]
**ユーザーアクション:** ...
**システムレスポンス:** ...
**成功基準:**
- [ ] ...
**潜在的な摩擦:**
- ...
---
## エラーシナリオ
### E1: [エラー名]
**トリガー:** このエラーを引き起こすもの
**ユーザーが見るもの:** エラーメッセージ/状態
**回復パス:** ユーザーがトラックに戻る方法
**テスト:** 回復が機能することを検証する方法
## 追跡するメトリクス
- ジャーニー完了時間
- 各ステップでのドロップオフ率
- エラー率と回復率
- ユーザー満足度(調査がある場合)
## E2E テストリファレンス
Playwright テストへのリンク: `e2e/tests/journeys/[name].spec.ts`
クリティカルジャーニー例
サインアップから最初の価値まで
# ジャーニー: サインアップから最初の価値まで
## 概要
| 属性 | 値 |
|-----------|-------|
| **優先度** | Critical |
| **ユーザータイプ** | 新規 |
| **頻度** | 一度 |
| **成功指標** | 5分以内に「aha moment」に到達する% |
## ユーザーゴール
> 「この製品が自分の問題を解決するかどうか確認するために、すぐに試したいです。」
## 前提条件
- サイトへの初回訪問
- アカウントなし
- ランディングページまたは広告から訪問
## ジャーニーステップ
### ステップ 1: ランディングページ
**ユーザーアクション:** 「無料で始める」または「今試す」をクリック
**システムレスポンス:** サインアップフォームが表示される(モーダルまたは新しいページ)
**成功基準:**
- [ ] CTAはスクロールなしで見える
- [ ] 気を散らす要素がない
- [ ] 明確な価値提案が表示されている
**潜在的な摩擦:**
- フォームフィールドが多すぎる → メールとパスワードのみに削減
- ソーシャルログインがない → Google/GitHub オプションを追加
### ステップ 2: アカウント作成
**ユーザーアクション:** メールとパスワードを入力(またはソーシャルログインを使用)
**システムレスポンス:**
- アカウントを作成
- 確認メールを送信(ブロックしない)
- オンボーディングにリダイレクト
**成功基準:**
- [ ] アカウントが3秒以内に作成される
- [ ] メール確認の壁がない(後で確認)
- [ ] 明確な次のステップが示される
**潜在的な摩擦:**
- メールが既に存在 → ログインリンクを提供
- 弱いパスワード → 送信後ではなく、インラインで要件を表示
### ステップ 3: オンボーディング(クイックウィン)
**ユーザーアクション:** 1~2個のセットアップ質問を完了
**システムレスポンス:**
- 体験をパーソナライズ
- 進捗インジケーターを表示
- 最初のアクションへ導く
**成功基準:**
- [ ] 最大3つの質問
- [ ] スキップオプションが利用可能
- [ ] 合計 < 60秒
**潜在的な摩擦:**
- 質問が多すぎる → ユーザーが放棄
- スキップオプションがない → ユーザーが閉じ込められた感覚
### ステップ 4: 最初の価値(Aha Moment)
**ユーザーアクション:** コアアクションを完了(最初のXを作成、最初の結果を表示)
**システムレスポンス:**
- 成功を祝う
- 提供された価値を表示
- 次のステップを提案
**成功基準:**
- [ ] ユーザーがコア価値を経験
- [ ] 完了が報酬的に感じられる
- [ ] 続行するための明確なパス
## エラーシナリオ
### E1: メール既に登録済み
**トリガー:** ユーザーが既存のメールを試す
**ユーザーが見るもの:** 「既にアカウントをお持ちですか?ログインまたはパスワードリセット」
**回復パス:** クリックしてログインまたはリセット
**テスト:** `signup-existing-email.spec.ts`
### E2: ソーシャルログイン失敗
**トリガー:** OAuthプロバイダーエラー
**ユーザーが見るもの:** 「接続できませんでした。メールサインアップを試すか、もう一度試してください。」
**回復パス:** メールサインアップフォームがフォールバックとして表示される
**テスト:** `social-login-failure.spec.ts`
## 追跡するメトリクス
- サインアップ → 最初の価値: ターゲット < 5分
- 各ステップでのドロップオフ
- ソーシャルとメールサインアップの比率
- オンボーディングのスキップ率
チェックアウト購入
# ジャーニー: チェックアウト購入
## 概要
| 属性 | 値 |
|-----------|-------|
| **優先度** | Critical(収益) |
| **ユーザータイプ** | 全員 |
| **頻度** | 可変 |
| **成功指標** | チェックアウト完了率 |
## ユーザーゴール
> 「意外なことなく、素早く安全に支払いたいです。」
## ジャーニーステップ
### ステップ 1: カート確認
**ユーザーアクション:** チェックアウト前にカートを表示
**システムレスポンス:**
- 画像と価格を付きの全アイテムを表示
- 小計、税金、配送を表示
- 明確な「チェックアウト」CTA
**成功基準:**
- [ ] 隠れた手数料が後で明かされない
- [ ] 数量の変更が簡単
- [ ] 保存されたアイテムが表示される
### ステップ 2: チェックアウト開始
**ユーザーアクション:** 「チェックアウト」をクリック
**システムレスポンス:**
- チェックアウトフォームまたは支払いへのリダイレクト
- 進捗インジケーター(ステップ1 / 3)
- 注文概要のサイドバー
**成功基準:**
- [ ] ゲストチェックアウトオプション
- [ ] エクスプレスチェックアウト(Apple/Google Pay)が目立つ
- [ ] ログイン済みの場合、フォームフィールドが事前入力される
### ステップ 3: 支払い
**ユーザーアクション:** 支払い情報を入力
**システムレスポンス:**
- セキュアな入力フィールド(Stripe/支払いプロバイダー)
- リアルタイム検証
- 明確な「支払い $XX」ボタン
**成功基準:**
- [ ] カード検証はインライン、送信後ではない
- [ ] 複数の支払いオプション
- [ ] セキュリティインジケーターが表示される
### ステップ 4: 確認
**ユーザーアクション:** 支払いを送信
**システムレスポンス:**
- 処理インジケーター
- 注文詳細を含む成功ページ
- 確認メール送信
**成功基準:**
- [ ] 5秒以内に確認
- [ ] 注文番号が明確に表示される
- [ ] 次のステップが明確(配送、アクセスなど)
## エラーシナリオ
### E1: 支払い拒否
**トリガー:** カードがプロセッサーに拒否される
**ユーザーが見るもの:** 「支払いが拒否されました。別のカードを試してください。」
**回復パス:**
- 支払いステップに留まる
- 他のフィールドを事前入力
- 代替支払い方法を提供
**テスト:** `payment-declined-recovery.spec.ts`
### E2: チェックアウト中のセッションタイムアウト
**トリガー:** ユーザーが長時間離席
**ユーザーが見るもの:** カートが保持、再認証が必要
**回復パス:**
- クイックログイン
- 同じチェックアウトステップに戻る
- カートの内容は変わらず
**テスト:** `checkout-session-timeout.spec.ts`
Playwright でのジャーニーテスト
ジャーニーテスト構造
// e2e/tests/journeys/signup-to-value.spec.ts
import { test, expect } from '@playwright/test';
test.describe('ジャーニー: サインアップから最初の価値まで', () => {
test.describe.configure({ mode: 'serial' }); // 順番に実行
test('ステップ1: ランディングページに明確なCTAがある', async ({ page }) => {
await page.goto('/');
// スクロールなしでスクロール上のCTAが表示される
const cta = page.getByRole('button', { name: /get started|try free/i });
await expect(cta).toBeVisible();
await expect(cta).toBeInViewport();
});
test('ステップ2: アカウントを素早く作成できる', async ({ page }) => {
await page.goto('/');
await page.getByRole('button', { name: /get started/i }).click();
// 最小限のフィールド
await expect(page.getByLabel('Email')).toBeVisible();
await expect(page.getByLabel('Password')).toBeVisible();
// サインアップを完了
const startTime = Date.now();
await page.getByLabel('Email').fill('newuser@example.com');
await page.getByLabel('Password').fill('SecurePass123!');
await page.getByRole('button', { name: /sign up|create/i }).click();
// オンボーディングにすぐに到達
await expect(page).toHaveURL(/onboarding|welcome|setup/);
expect(Date.now() - startTime).toBeLessThan(5000); // < 5秒
});
test('ステップ3: オンボーディングはスキップ可能', async ({ page }) => {
// ... 新規ユーザーとしてログイン ...
await page.goto('/onboarding');
// スキップオプションが存在
const skipButton = page.getByRole('button', { name: /skip/i });
await expect(skipButton).toBeVisible();
});
test('ステップ4: 5分以内に最初の価値に到達できる', async ({ page }) => {
// 完全なジャーニータイミング
const journeyStart = Date.now();
// ... 完全なジャーニーを完了 ...
// 最初の価値が提供されたことを確認
await expect(page.getByText(/success|created|done/i)).toBeVisible();
// 合計時間チェック
const totalTime = (Date.now() - journeyStart) / 1000 / 60; // 分
expect(totalTime).toBeLessThan(5);
});
});
エラー回復テスト
// e2e/tests/journeys/checkout-recovery.spec.ts
import { test, expect } from '@playwright/test';
test.describe('ジャーニー: チェックアウトエラー回復', () => {
test('支払い拒否から丁寧に回復', async ({ page }) => {
// セットアップ: アイテムをカートに追加、チェックアウトに進む
await page.goto('/products');
await page.getByTestId('add-to-cart').first().click();
await page.getByRole('link', { name: 'Checkout' }).click();
// 拒否される Stripe テストカードを使用
const stripeFrame = page.frameLocator('iframe[name*="stripe"]');
await stripeFrame.getByPlaceholder('Card number').fill('4000000000000002');
await stripeFrame.getByPlaceholder('MM / YY').fill('12/30');
await stripeFrame.getByPlaceholder('CVC').fill('123');
await page.getByRole('button', { name: /pay/i }).click();
// フレンドリーなエラーを確認
await expect(page.getByText(/declined|try another/i)).toBeVisible();
// チェックアウト中に留まることを確認(キックアウトされない)
await expect(page).toHaveURL(/checkout/);
// 別のカードで再試行できることを確認
await stripeFrame.getByPlaceholder('Card number').fill('4242424242424242');
await page.getByRole('button', { name: /pay/i }).click();
// 今度は成功すべき
await expect(page).toHaveURL(/success|confirmation/);
});
test('セッションタイムアウト後カートを保持', async ({ page, context }) => {
// カートにアイテムを追加
await page.goto('/products');
await page.getByTestId('add-to-cart').first().click();
// セッションをクリア(タイムアウトをシミュレート)
await context.clearCookies();
// サイトに戻る
await page.goto('/cart');
// カートが保持されるべき(ローカルストレージまたは回復)
await expect(page.getByTestId('cart-item')).toHaveCount(1);
});
});
ユーザー体験検証
ジャーニーステップごとの UX チェックリスト
## UX 検証チェックリスト
### 明確性
- [ ] ユーザーは自分がどこにいるかを知っている(パンくずリスト、進捗)
- [ ] ユーザーは次に何をすべきかを知っている(明確なCTA)
- [ ] ユーザーは何が起こったかを知っている(フィードバック)
### 速度
- [ ] ページが2秒以内に読み込まれる
- [ ] アクションが3秒以内に完了
- [ ] 長時間の操作に進捗が表示される
### 許容
- [ ] ミスは簡単に元に戻せる
- [ ] エラーは何が悪かったかを説明
- [ ] 回復パスが明確
### アクセシビリティ
- [ ] キーボードナビゲーションが機能
- [ ] スクリーンリーダーが変更をアナウンス
- [ ] フォーカス管理が正しい
- [ ] 色のコントラストが十分
### モバイル
- [ ] タッチターゲット >= 44px
- [ ] 水平スクロールがない
- [ ] フォームが予期せずズームしない
- [ ] 低速 3G で動作
自動化された UX チェック
// e2e/utils/ux-validators.ts
import { Page, expect } from '@playwright/test';
export async function validatePageLoad(page: Page, maxMs = 2000) {
const timing = await page.evaluate(() => {
const nav = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming;
return nav.loadEventEnd - nav.startTime;
});
expect(timing).toBeLessThan(maxMs);
}
export async function validateCTAVisible(page: Page, ctaText: RegExp) {
const cta = page.getByRole('button', { name: ctaText });
await expect(cta).toBeVisible();
await expect(cta).toBeInViewport();
}
export async function validateNoLayoutShift(page: Page) {
const cls = await page.evaluate(() => {
return new Promise<number>((resolve) => {
let clsValue = 0;
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (!(entry as any).hadRecentInput) {
clsValue += (entry as any).value;
}
}
});
observer.observe({ type: 'layout-shift', buffered: true });
setTimeout(() => {
observer.disconnect();
resolve(clsValue);
}, 1000);
});
});
expect(cls).toBeLessThan(0.1); // 良好な CLS スコア
}
export async function validateAccessibility(page: Page) {
// インタラクティブな要素にフォーカスが見えることを確認
const buttons = page.getByRole('button');
const count = await buttons.count();
for (let i = 0; i < Math.min(count, 5); i++) {
await buttons.nth(i).focus();
await expect(buttons.nth(i)).toBeFocused();
}
}
ジャーニーメトリクスダッシュボード
これらのメトリクスでジャーニーの健全性を追跡します:
// lib/journey-metrics.ts
interface JourneyMetric {
journey: string;
step: string;
timestamp: Date;
duration: number;
success: boolean;
userId?: string;
}
// 分析に追跡(PostHog、Mixpanel など)
export function trackJourneyStep(metric: JourneyMetric) {
analytics.track('journey_step', {
journey_name: metric.journey,
step_name: metric.step,
duration_ms: metric.duration,
success: metric.success,
});
}
// アプリでの使用例
const journeyStart = Date.now();
// ... ユーザーがステップを完了 ...
trackJourneyStep({
journey: 'signup_to_value',
step: 'account_creation',
timestamp: new Date(),
duration: Date.now() - journeyStart,
success: true,
});
よくあるジャーニーパターン
段階的開示ジャーニー
ユーザーは最初はシンプルなビューを見て、必要に応じて複雑さが明かされます。
ステップ 1: 基本オプションのみを表示
ステップ 2: 「詳細」はさらにオプションを拡張
ステップ 3: エキスパートモードがすべてをロック解除
ガイド付きセットアップジャーニー
初期設定を通じて新規ユーザーを手引きします。
ステップ 1: ウェルカム + 単一の選択
ステップ 2: コア設定
ステップ 3: オプションの統合(スキップ可能)
ステップ 4: 最初のアクションとガイダンス
ステップ 5: 成功 + トレーニングホイールを削除
回復ジャーニー
ユーザーが失敗または放棄後に戻ります。
ステップ 1: リターンユーザーを認識
ステップ 2: 以前の状態を復元
ステップ 3: 何が起こったかを承認
ステップ 4: 明確な前進パスを提供
ステップ 5: 元のゴールを完了
アンチパターン
- ハッピーパスのみ - 成功だけでなく、エラー回復をテスト
- 仕様駆動型テスト - 機能ではなく、ユーザーゴールをテスト
- 時間を無視 - ジャーニーにかかる時間を測定
- デスクトップのみ - モバイルジャーニーは別途テスト
- 感情を無視 - ユーザーのフラストレーションポイントを考慮
- メトリクスなし - ジャーニー完了とドロップオフを追跡
- 静的なジャーニー - ユーザーの行動の進化に応じて更新
クイックリファレンス
ジャーニー優先度
| 優先度 | 基準 | テスト頻度 |
|---|---|---|
| Critical | 収益、コア価値 | 毎回デプロイ |
| High | 日常的なユーザーアクション | 毎日 |
| Medium | 週次機能 | 毎週 |
| Low | エッジケース | 変更時 |
Package.json スクリプト
{
"scripts": {
"test:journeys": "playwright test e2e/tests/journeys/",
"test:journeys:critical": "playwright test e2e/tests/journeys/critical/",
"test:journeys:report": "playwright show-report"
}
}
ジャーニードキュメントチェックリスト
- ユーザーゴールが明確に述べられている
- すべてのステップが文書化されている
- ステップごとの成功基準
- エラーシナリオがカバーされている
- 回復パスが定義されている
- メトリクスが特定されている
- E2E テストがリンクされている
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- alinaqi
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/alinaqi/claude-bootstrap / ライセンス: MIT
関連スキル
nano-banana-2
inference.sh CLIを通じてGoogle Gemini 3.1 Flash Image Preview(Nano Banana 2)で画像を生成します。テキストから画像を生成する機能、画像編集、最大14枚の複数画像入力、Google Searchグラウンディング機能に対応しています。トリガーワード:「nano banana 2」「nanobanana 2」「gemini 3.1 flash image」「gemini 3 1 flash image preview」「google image generation」
octocode-slides
洗練されたマルチファイル形式のHTMLプレゼンテーションを生成します。6段階のフロー(概要 → リサーチ → アウトライン → デザイン → 実装 → レビュー)で構成されています。各スライドは独立したHTMLファイルとなり、iframeで読み込まれます。「スライドを作成してほしい」「プレゼンテーションを作ってほしい」「HTMLスライドを生成してほしい」「デックを構築してほしい」といった依頼や、ノート・ドキュメント・コードを洗練されたプレゼンテーションに変換する際に使用できます。
gpt-image2-ppt
OpenAIのgpt-image-2を使用して、視覚的に優れたPPTスライドを生成します。Spatial Glass、Tech Blue、Editorial Monoなど10種類のキュレーション済みスタイルに対応し、ユーザーが提供したPPTXファイルを模倣するテンプレートクローンモードも搭載しています。HTMLビューアと16:9形式のPPTXファイルを出力します。プレゼンテーション、スライド、ピッチデック、投資家向けPPT、雑誌風PPTの作成依頼などで活用してください。
nano-banana
Nano Banana PRO(Gemini 3 Pro Image)およびNano Banana(Gemini 2.5 Flash Image)を使用したAI画像生成機能です。以下の場合に活用できます:(1)テキストプロンプトからの画像生成、(2)既存画像の編集、(3)インフォグラフィックス、ロゴ、商品写真、ステッカーなどのプロフェッショナルなビジュアルアセット制作、(4)複数画像での人物キャラクターの一貫性保持、(5)正確なテキスト描画を含む画像生成、(6)AI生成ビジュアルが必要なあらゆるタスク。「画像を生成」「画像を作成」「写真を作る」「ロゴをデザイン」「インフォグラフィックスを作成」「AI画像」「nano banana」またはその他の画像生成リクエストをトリガーとして機能します。
oiloil-ui-ux-guide
モダンでクリーンなUI/UXガイダンス・レビュースキルです。新機能や既存システム(Webアプリ)に対して、実行可能なUI/UX改善提案、デザイン原則、デザインレビューチェックリストが必要な場合に活用できます。CRAP(コントラスト・反復・配置・近接)をベースに、タスクファーストなUX、情報設計、フィードバック・システムステータス、一貫性、affordances、エラー防止・復旧、認知負荷を重視します。モダンミニマルスタイル(クリーン・余白・タイポグラフィ主導)を強制し、不要なテキストを削減、アイコンとしての絵文字を禁止し、統一されたアイコンセットから直感的で洗練されたアイコンを推奨します。
axiom-hig-ref
Apple Human Interface Guidelines リファレンス — 色(セマンティックカラー、カスタムカラー、パターン)、背景(マテリアル階層、ダイナミック背景)、タイポグラフィ(標準スタイル、カスタムフォント、Dynamic Type)、SF Symbols(レンダリングモード、色、多言語対応)、ダークモード、アクセシビリティ、プラットフォーム固有の考慮事項を網羅したガイドラインです。