jpskill.com
💬 コミュニケーション コミュニティ

user-journeys

User experience flows - journey mapping, UX validation, error recovery

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o user-journeys.zip https://jpskill.com/download/21673.zip && unzip -o user-journeys.zip && rm user-journeys.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/21673.zip -OutFile "$d\user-journeys.zip"; Expand-Archive "$d\user-journeys.zip" -DestinationPath $d -Force; ri "$d\user-journeys.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して user-journeys.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → user-journeys フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

[Skill 名] user-journeys

ユーザージャーニー・スキル

単なる仕様書ではなく、ユーザーがアプリケーション内で実際にたどるフローを定義し、テストするためのものです。


理念

仕様は機能をテストします。ジャーニーは体験をテストします。

機能がすべての仕様を満たしていても、ひどい体験を提供する可能性があります。ユーザージャーニーは以下を捉えます。

  • ユーザーが実際にどのように操作するか(私たちがどうあるべきだと考えるかではなく)
  • 各ステップでの感情状態(不満、混乱、喜び)
  • 間違いからの回復(ユーザーは間違いを犯します)
  • 現実世界の条件(低速ネットワーク、中断、注意散漫)

ジャーニー文書の構造

_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

ジャーニーテンプレート

# Journey: [名前]

## 概要
| 属性 | 値 |
|-----------|-------|
| **優先度** | Critical / High / Medium |
| **ユーザータイプ** | New / Returning / Admin |
| **頻度** | Daily / Weekly / One-time |
| **成功指標** | コンバージョン率、完了までの時間、離脱率 |

## ユーザーの目標
ユーザーは何を達成しようとしていますか?ユーザーの視点から記述してください。

> 「私は[目標]を達成したい。そうすれば[メリット]が得られる。」

## 前提条件
- ユーザーの状態(ログイン済み、サブスクリプションあり、初回訪問)
- データ状態(カートに商品あり、チームメンバーあり)
- 環境(モバイル、デスクトップ、低速接続)

## ジャーニーのステップ

### ステップ 1: [エントリーポイント]
**ユーザーアクション:** ユーザーが行うこと
**システム応答:** ユーザーが見る/体験すること
**成功基準:**
- [ ] ページが2秒未満でロードされる
- [ ] 主要なCTAがすぐに表示される
- [ ] ユーザーが次に何をすべきか理解できる

**潜在的な摩擦:**
- ロード時間が遅い → スケルトン/ローダーを表示する
- CTAが不明確 → コピーのバリエーションをA/Bテストする

---

### ステップ 2: [次のアクション]
**ユーザーアクション:** ...
**システム応答:** ...
**成功基準:**
- [ ] ...

**潜在的な摩擦:**
- ...

---

## エラーシナリオ

### E1: [エラー名]
**トリガー:** このエラーを引き起こすもの
**ユーザーが見るもの:** エラーメッセージ/状態
**回復パス:** ユーザーがどのように軌道に戻るか
**テスト:** 回復が機能することを確認する方法

## 追跡する指標
- ジャーニー完了までの時間
- 各ステップでの離脱率
- エラー率と回復率
- ユーザー満足度(アンケートを実施する場合)

## E2Eテスト参照
Playwrightテストへのリンク: `e2e/tests/journeys/[name].spec.ts`

重要なジャーニーの例

サインアップから最初の価値まで

# Journey: サインアップから最初の価値まで

## 概要
| 属性 | 値 |
|-----------|-------|
| **優先度** | Critical |
| **ユーザータイプ** | New |
| **頻度** | One-time |
| **成功指標** | 5分以内に「アハ体験」に到達した割合 |

## ユーザーの目標
> 「この製品をすぐに試して、自分の問題を解決できるか確認したい。」

## 前提条件
- サイトへの初回訪問
- アカウントなし
- ランディングページまたは広告から来た

## ジャーニーのステップ

### ステップ 1: ランディングページ
**ユーザーアクション:** 「無料で始める」または「今すぐ試す」をクリックする
**システム応答:** サインアップフォームが表示される(モーダルまたは新しいページ)
**成功基準:**
- [ ] CTAがファーストビューに表示される
- [ ] 気を散らす要素がない
- [ ] 明確な価値提案が表示される

**潜在的な摩擦:**
- フォームフィールドが多すぎる → メールアドレスとパスワードのみに減らす
- ソーシャルログインがない → Google/GitHubオプションを追加する

### ステップ 2: アカウント作成
**ユーザーアクション:** メールアドレスとパスワードを入力する(またはソーシャルログインを使用する)
**システム応答:**
- アカウントを作成する
- 確認メールを送信する(ブロックしない)
- オンボーディングにリダイレクトする

**成功基準:**
- [ ] アカウントが3秒未満で作成される
- [ ] メール確認の壁がない(後で確認する)
- [ ] 明確な次のステップが表示される

**潜在的な摩擦:**
- メールアドレスが既に存在する → ログインリンクを提供する
- 弱いパスワード → 送信後ではなく、インラインで要件を表示する

### ステップ 3: オンボーディング(クイックウィン)
**ユーザーアクション:** 1〜2つのセットアップ質問を完了する
**システム応答:**
- 体験をパーソナライズする
- 進捗インジケーターを表示する
- 最初の行動に導く

**成功基準:**
- [ ] 最大3つの質問
- [ ] スキップオプションが利用可能
- [ ] 合計60秒未満

**潜在的な摩擦:**
- 質問が多すぎる → ユーザーが離脱する
- スキップオプションがない → ユーザーが閉じ込められたと感じる

### ステップ 4: 最初の価値(アハ体験)
**ユーザーアクション:** コアアクションを完了する(最初のXを作成する、最初の結果を見る)
**システム応答:**
- 成功を祝う
- 提供された価値を示す
- 次のステップを提案する

**成功基準:**
- [ ] ユーザーがコアバリューを体験する
- [ ] 完了が報われると感じる
- [ ] 継続するための明確なパスがある

## エラーシナリオ

### E1: メールアドレスが既に登録済み
**トリガー:** ユーザーが既存のメールアドレスを試す
**ユーザーが見るもの:** 「既にアカウントをお持ちですか?ログインまたはパスワードをリセットしてください」
**回復パス:** クリックしてログインまたはリセット
**テスト:** `signup-existing-email.spec.ts`

### E2: ソーシャルログインの失敗
**トリガー:** OAuthプロバイダーエラー
**ユーザーが見るもの:** 「接続できませんでした。メールアドレスでサインアップするか、もう一度お試しください。」
**回復パス:** フォールバックとしてメールサインアップフォームが表示される
**テスト:** `social-login-failure.spec.ts`

## 追跡する指標
- サインアップ → 最初の価値: 目標5分未満
- 各ステップでの離脱率
- ソーシャル vs メールサインアップの比率
- オンボーディングでのスキップ率

チェックアウト購入


# Journey: チェックアウト購入

## 概要
| 属性 | 値 |
|-----------|-------|
| **優先度** | Critical (収益) |
| **ユーザータイプ** | 任意 |
| **頻度** | 可変 |
| **成功指標** | チェックアウト完了率 |

## ユーザーの目標
> 「サプライズなしで、迅速かつ安全に支払いを済ませたい。」

## ジャーニーのステップ

### ステップ 1: カートの確認
**ユーザーアクション:** チェックアウト前にカートを見る
**システム応答:**
- すべての商品を画像、価格とともに表示する
- 小計、税金、送料を表示する
- 明確な「チェックアウト」CTA

**成功

(原文がここで切り詰められています)
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

User Journeys Skill

For defining and testing real user experiences - not just specs, but actual flows humans take through your application.


Philosophy

Specs test features. Journeys test experiences.

A feature can pass all specs but still deliver a terrible experience. User journeys capture:

  • How users actually navigate (not how we think they should)
  • Emotional states at each step (frustrated, confused, delighted)
  • Recovery from mistakes (users will make them)
  • Real-world conditions (slow networks, interruptions, distractions)

Journey Documentation Structure

_project_specs/
├── journeys/
│   ├── _template.md              # Journey template
│   ├── critical/                 # Must-work journeys (revenue, core value)
│   │   ├── signup-to-first-value.md
│   │   ├── checkout-purchase.md
│   │   └── login-to-dashboard.md
│   ├── common/                   # Frequent user paths
│   │   ├── browse-and-search.md
│   │   ├── update-profile.md
│   │   └── invite-team-member.md
│   └── edge-cases/               # Error recovery, unusual paths
│       ├── payment-failure-retry.md
│       ├── session-timeout-recovery.md
│       └── offline-reconnection.md

Journey Template

# Journey: [Name]

## Overview
| Attribute | Value |
|-----------|-------|
| **Priority** | Critical / High / Medium |
| **User Type** | New / Returning / Admin |
| **Frequency** | Daily / Weekly / One-time |
| **Success Metric** | Conversion rate, time to complete, drop-off rate |

## User Goal
What is the user trying to accomplish? Write from their perspective.

> "I want to [goal] so that I can [benefit]."

## Preconditions
- User state (logged in, has subscription, first visit)
- Data state (has items in cart, has team members)
- Environment (mobile, desktop, slow connection)

## Journey Steps

### Step 1: [Entry Point]
**User Action:** What the user does
**System Response:** What they should see/experience
**Success Criteria:**
- [ ] Page loads in < 2 seconds
- [ ] Primary CTA is immediately visible
- [ ] User understands what to do next

**Potential Friction:**
- Slow load time → Show skeleton/loader
- Unclear CTA → A/B test copy variations

---

### Step 2: [Next Action]
**User Action:** ...
**System Response:** ...
**Success Criteria:**
- [ ] ...

**Potential Friction:**
- ...

---

## Error Scenarios

### E1: [Error Name]
**Trigger:** What causes this error
**User Sees:** Error message/state
**Recovery Path:** How user gets back on track
**Test:** How to verify recovery works

## Metrics to Track
- Time to complete journey
- Drop-off rate at each step
- Error rate and recovery rate
- User satisfaction (if surveyed)

## E2E Test Reference
Link to Playwright test: `e2e/tests/journeys/[name].spec.ts`

Critical Journey Examples

Signup to First Value

# Journey: Signup to First Value

## Overview
| Attribute | Value |
|-----------|-------|
| **Priority** | Critical |
| **User Type** | New |
| **Frequency** | One-time |
| **Success Metric** | % reaching "aha moment" within 5 min |

## User Goal
> "I want to try this product quickly to see if it solves my problem."

## Preconditions
- First visit to site
- No account
- Came from landing page or ad

## Journey Steps

### Step 1: Landing Page
**User Action:** Clicks "Get Started Free" or "Try Now"
**System Response:** Signup form appears (modal or new page)
**Success Criteria:**
- [ ] CTA visible above fold
- [ ] No distracting elements
- [ ] Clear value proposition visible

**Potential Friction:**
- Too many form fields → Reduce to email + password only
- Social login missing → Add Google/GitHub options

### Step 2: Account Creation
**User Action:** Enters email and password (or uses social login)
**System Response:**
- Creates account
- Sends verification email (don't block on it)
- Redirects to onboarding

**Success Criteria:**
- [ ] Account created in < 3 seconds
- [ ] No email verification wall (verify later)
- [ ] Clear next step shown

**Potential Friction:**
- Email already exists → Offer login link
- Weak password → Show requirements inline, not after submit

### Step 3: Onboarding (Quick Win)
**User Action:** Completes 1-2 setup questions
**System Response:**
- Personalizes experience
- Shows progress indicator
- Leads to first action

**Success Criteria:**
- [ ] Max 3 questions
- [ ] Skip option available
- [ ] < 60 seconds total

**Potential Friction:**
- Too many questions → User abandons
- No skip option → User feels trapped

### Step 4: First Value (Aha Moment)
**User Action:** Completes core action (creates first X, sees first result)
**System Response:**
- Celebrates success
- Shows value delivered
- Suggests next step

**Success Criteria:**
- [ ] User experiences core value
- [ ] Completion feels rewarding
- [ ] Clear path to continue

## Error Scenarios

### E1: Email Already Registered
**Trigger:** User tries existing email
**User Sees:** "Already have an account? Log in or reset password"
**Recovery Path:** Click to login or reset
**Test:** `signup-existing-email.spec.ts`

### E2: Social Login Fails
**Trigger:** OAuth provider error
**User Sees:** "Couldn't connect. Try email signup or try again."
**Recovery Path:** Email signup form shown as fallback
**Test:** `social-login-failure.spec.ts`

## Metrics to Track
- Signup → First Value: Target < 5 min
- Drop-off at each step
- Social vs email signup ratio
- Skip rate on onboarding

Checkout Purchase

# Journey: Checkout Purchase

## Overview
| Attribute | Value |
|-----------|-------|
| **Priority** | Critical (Revenue) |
| **User Type** | Any |
| **Frequency** | Variable |
| **Success Metric** | Checkout completion rate |

## User Goal
> "I want to pay quickly and securely without surprises."

## Journey Steps

### Step 1: Cart Review
**User Action:** Views cart before checkout
**System Response:**
- Shows all items with images, prices
- Shows subtotal, taxes, shipping
- Clear "Checkout" CTA

**Success Criteria:**
- [ ] No hidden fees revealed later
- [ ] Easy to modify quantities
- [ ] Saved items visible

### Step 2: Checkout Start
**User Action:** Clicks "Checkout"
**System Response:**
- Shows checkout form or redirect to payment
- Progress indicator (Step 1 of 3)
- Order summary sidebar

**Success Criteria:**
- [ ] Guest checkout option
- [ ] Express checkout (Apple/Google Pay) prominent
- [ ] Form fields pre-filled if logged in

### Step 3: Payment
**User Action:** Enters payment info
**System Response:**
- Secure input fields (Stripe/payment provider)
- Real-time validation
- Clear "Pay $XX" button

**Success Criteria:**
- [ ] Card validation inline, not after submit
- [ ] Multiple payment options
- [ ] Security indicators visible

### Step 4: Confirmation
**User Action:** Submits payment
**System Response:**
- Processing indicator
- Success page with order details
- Email confirmation sent

**Success Criteria:**
- [ ] Confirmation within 5 seconds
- [ ] Order number clearly visible
- [ ] Next steps clear (shipping, access, etc.)

## Error Scenarios

### E1: Payment Declined
**Trigger:** Card declined by processor
**User Sees:** "Payment declined. Please try another card."
**Recovery Path:**
- Stay on payment step
- Pre-fill other fields
- Offer alternative payment methods
**Test:** `payment-declined-recovery.spec.ts`

### E2: Session Timeout During Checkout
**Trigger:** User away too long
**User Sees:** Cart preserved, re-auth required
**Recovery Path:**
- Quick login
- Return to same checkout step
- Cart contents intact
**Test:** `checkout-session-timeout.spec.ts`

Journey Testing with Playwright

Journey Test Structure

// e2e/tests/journeys/signup-to-value.spec.ts
import { test, expect } from '@playwright/test';

test.describe('Journey: Signup to First Value', () => {
  test.describe.configure({ mode: 'serial' }); // Run in order

  test('Step 1: Landing page has clear CTA', async ({ page }) => {
    await page.goto('/');

    // CTA visible above fold without scrolling
    const cta = page.getByRole('button', { name: /get started|try free/i });
    await expect(cta).toBeVisible();
    await expect(cta).toBeInViewport();
  });

  test('Step 2: Can create account quickly', async ({ page }) => {
    await page.goto('/');
    await page.getByRole('button', { name: /get started/i }).click();

    // Minimal fields
    await expect(page.getByLabel('Email')).toBeVisible();
    await expect(page.getByLabel('Password')).toBeVisible();

    // Complete signup
    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();

    // Should reach onboarding quickly
    await expect(page).toHaveURL(/onboarding|welcome|setup/);
    expect(Date.now() - startTime).toBeLessThan(5000); // < 5 seconds
  });

  test('Step 3: Onboarding is skippable', async ({ page }) => {
    // ... login as new user ...
    await page.goto('/onboarding');

    // Skip option exists
    const skipButton = page.getByRole('button', { name: /skip/i });
    await expect(skipButton).toBeVisible();
  });

  test('Step 4: Can reach first value in < 5 min', async ({ page }) => {
    // Full journey timing
    const journeyStart = Date.now();

    // ... complete full journey ...

    // Verify first value delivered
    await expect(page.getByText(/success|created|done/i)).toBeVisible();

    // Total time check
    const totalTime = (Date.now() - journeyStart) / 1000 / 60; // minutes
    expect(totalTime).toBeLessThan(5);
  });
});

Error Recovery Tests

// e2e/tests/journeys/checkout-recovery.spec.ts
import { test, expect } from '@playwright/test';

test.describe('Journey: Checkout Error Recovery', () => {
  test('recovers from payment decline gracefully', async ({ page }) => {
    // Setup: Add item to cart, go to checkout
    await page.goto('/products');
    await page.getByTestId('add-to-cart').first().click();
    await page.getByRole('link', { name: 'Checkout' }).click();

    // Use Stripe test card that declines
    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();

    // Verify friendly error
    await expect(page.getByText(/declined|try another/i)).toBeVisible();

    // Verify still on checkout (not kicked out)
    await expect(page).toHaveURL(/checkout/);

    // Verify can try again with different card
    await stripeFrame.getByPlaceholder('Card number').fill('4242424242424242');
    await page.getByRole('button', { name: /pay/i }).click();

    // Should succeed now
    await expect(page).toHaveURL(/success|confirmation/);
  });

  test('preserves cart after session timeout', async ({ page, context }) => {
    // Add items to cart
    await page.goto('/products');
    await page.getByTestId('add-to-cart').first().click();

    // Clear session (simulate timeout)
    await context.clearCookies();

    // Return to site
    await page.goto('/cart');

    // Cart should be preserved (local storage or recovered)
    await expect(page.getByTestId('cart-item')).toHaveCount(1);
  });
});

User Experience Validation

UX Checklist per Journey Step

## UX Validation Checklist

### Clarity
- [ ] User knows where they are (breadcrumbs, progress)
- [ ] User knows what to do next (clear CTA)
- [ ] User knows what just happened (feedback)

### Speed
- [ ] Page loads < 2 seconds
- [ ] Actions complete < 3 seconds
- [ ] Progress shown for longer operations

### Forgiveness
- [ ] Mistakes are easy to undo
- [ ] Errors explain what went wrong
- [ ] Recovery path is clear

### Accessibility
- [ ] Keyboard navigation works
- [ ] Screen reader announces changes
- [ ] Focus management correct
- [ ] Color contrast sufficient

### Mobile
- [ ] Touch targets >= 44px
- [ ] No horizontal scroll
- [ ] Forms don't zoom unexpectedly
- [ ] Works on slow 3G

Automated UX Checks

// 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); // Good CLS score
}

export async function validateAccessibility(page: Page) {
  // Check focus visible on interactive elements
  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();
  }
}

Journey Metrics Dashboard

Track journey health with these metrics:

// lib/journey-metrics.ts
interface JourneyMetric {
  journey: string;
  step: string;
  timestamp: Date;
  duration: number;
  success: boolean;
  userId?: string;
}

// Track in your analytics (PostHog, Mixpanel, etc.)
export function trackJourneyStep(metric: JourneyMetric) {
  analytics.track('journey_step', {
    journey_name: metric.journey,
    step_name: metric.step,
    duration_ms: metric.duration,
    success: metric.success,
  });
}

// Example usage in app
const journeyStart = Date.now();
// ... user completes step ...
trackJourneyStep({
  journey: 'signup_to_value',
  step: 'account_creation',
  timestamp: new Date(),
  duration: Date.now() - journeyStart,
  success: true,
});

Common Journey Patterns

Progressive Disclosure Journey

User sees simple view first, complexity revealed as needed.

Step 1: Show basic options only
Step 2: "Advanced" expands more options
Step 3: Expert mode unlocks everything

Guided Setup Journey

Hand-hold new users through initial configuration.

Step 1: Welcome + single choice
Step 2: Core preference
Step 3: Optional integrations (skippable)
Step 4: First action with guidance
Step 5: Success + remove training wheels

Recovery Journey

User returns after failure or abandonment.

Step 1: Recognize returning user
Step 2: Restore previous state
Step 3: Acknowledge what happened
Step 4: Offer clear path forward
Step 5: Complete original goal

Anti-Patterns

  • Happy path only - Test error recovery, not just success
  • Spec-driven testing - Test user goals, not features
  • Ignoring time - Measure how long journeys take
  • Desktop-only - Test mobile journeys separately
  • Skipping emotions - Consider user frustration points
  • No metrics - Track journey completion and drop-off
  • Static journeys - Update as user behavior evolves

Quick Reference

Journey Priorities

Priority Criteria Test Frequency
Critical Revenue, core value Every deploy
High Daily user actions Daily
Medium Weekly features Weekly
Low Edge cases On change

Package.json Scripts

{
  "scripts": {
    "test:journeys": "playwright test e2e/tests/journeys/",
    "test:journeys:critical": "playwright test e2e/tests/journeys/critical/",
    "test:journeys:report": "playwright show-report"
  }
}

Journey Documentation Checklist

  • [ ] User goal clearly stated
  • [ ] All steps documented
  • [ ] Success criteria per step
  • [ ] Error scenarios covered
  • [ ] Recovery paths defined
  • [ ] Metrics identified
  • [ ] E2E test linked