User Journeys

作者 alinaqi72a456e6ccf0无许可证707 个星标收录于 2026年10月8日更新于 2026年10月8日仓库2周前更新

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

AI 生成的概览

记录并测试用户旅程:旅程地图、UX 验证清单、错误恢复路径以及 Playwright 端到端测试。

功能
提供模板与指导,用于在项目规格目录中记录用户旅程,并按关键、常见和边缘情况流程分类。每个旅程涵盖用户目标、前置条件、分步操作、成功标准、摩擦点、带恢复路径的错误场景以及指标。它还提供用于旅程测试和错误恢复测试的 Playwright 测试结构、UX 验证清单和自动化 UX 检查。
适用场景
适用于梳理用户流程、验证用户体验或为应用设计错误恢复的场景。它适合希望同时获得旅程文档与端到端测试、而非仅做功能级规格的团队。
运行要求
仅为说明性内容,不附带脚本。若要按其中的测试指导执行,需要 Playwright 环境、Node.js 项目以及可运行的目标应用,旅程指标部分还可选配分析工具。

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

markdown
# 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 GoalWhat 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 ReferenceLink to Playwright test: `e2e/tests/journeys/[name].spec.ts`

Critical Journey Examples

Signup to First Value

markdown
# 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

markdown
# 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

typescript
// e2e/tests/journeys/signup-to-value.spec.tsimport { 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('[email protected]');    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

typescript
// e2e/tests/journeys/checkout-recovery.spec.tsimport { 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

markdown
## 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

typescript
// e2e/utils/ux-validators.tsimport { 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:

typescript
// lib/journey-metrics.tsinterface 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 appconst 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.

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

Guided Setup Journey

Hand-hold new users through initial configuration.

markdown
Step 1: Welcome + single choiceStep 2: Core preferenceStep 3: Optional integrations (skippable)Step 4: First action with guidanceStep 5: Success + remove training wheels

Recovery Journey

User returns after failure or abandonment.

markdown
Step 1: Recognize returning userStep 2: Restore previous stateStep 3: Acknowledge what happenedStep 4: Offer clear path forwardStep 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

PriorityCriteriaTest Frequency
CriticalRevenue, core valueEvery deploy
HighDaily user actionsDaily
MediumWeekly featuresWeekly
LowEdge casesOn change

Package.json Scripts

json
{  "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

来源与署名

来源:alinaqi/maggy位于skills/user-journeys提交72a456e

许可证: 无许可证

内容归原作者所有。SourceWeft 从公开仓库中收录这些内容。

举报或申请下架