포스트

UI Flow Specification 시리즈 2편: 실전 패턴(제안)

UI Flow Specification 시리즈 2편: 실전 패턴(제안)

들어가며

1편에서 UI Flow Specification(UI Flow Spec)을 “Use Case와 구현 사이의 간극을 메우는 프론트엔드 실무 템플릿”으로 제안했습니다. 이번 글은 그 템플릿을 코드와 바로 연결하는 실전 패턴을 정리합니다.

용어 주석: 본 글에서 사용하는 ‘UI Flow Specification’은 업계 표준 용어가 아니라, 필자가 Use Case와 구현 사이의 간극을 메우기 위해 제안하는 실무 템플릿입니다. 유사 산출물로는 UI/UX Spec, Interaction Spec, Statechart, Acceptance Criteria 등이 있습니다.

핵심 요약

  • UI Flow Spec → 상태 머신/쿼리/구조로 매핑하면 코드와 1:1 연결이 쉬워집니다.
  • Storybook/E2E와 연결하면 UI Flow Spec이 곧 테스트/데모 시나리오가 됩니다.
  • 내용은 학습/제안 단계이며, 팀 컨텍스트에 맞춰 가볍게 시작하는 것을 권장합니다.

UI Flow Spec → 코드 변환 패턴

패턴 1: 상태 머신(XState)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import { createMachine } from 'xstate';

/** UI Flow Specification: 상품 구매 (Based on Use Case #12) */
export const productPurchaseMachine = createMachine({
  id: 'productPurchase',
  initial: 'idle',
  states: {
    idle: { on: { PURCHASE: 'loading' } },
    loading: {
      invoke: {
        src: 'checkStock',
        onDone: { target: 'paymentReady', actions: 'setProduct' },
        onError: { target: 'error', actions: 'setError' }
      }
    },
    paymentReady: {
      on: { SUBMIT_PAYMENT: 'processing', CANCEL: 'idle' }
    },
    processing: {
      invoke: {
        src: 'processPayment',
        onDone: { target: 'success' },
        onError: { target: 'paymentFailed' }
      }
    },
    success: { type: 'final' },
    error: {},
    paymentFailed: { on: { RETRY: 'paymentReady' } }
  }
});
  • UI Flow Spec의 상태/전이/이벤트를 그대로 머신으로 옮깁니다.
  • Spec의 시나리오 번호를 주석으로 남기면 테스트와 상호참조가 편합니다.

패턴 2: TanStack Query + 상태 관리

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Step 1: 재고 확인
const stockQuery = useQuery({
  queryKey: ['stock', productId],
  queryFn: checkStock,
  enabled: false,
});

// Step 2: 결제 처리
const paymentMutation = useMutation({
  mutationFn: processPayment,
  onSuccess: () => {
    toast.success('결제 완료!');
    router.push('/order-complete');
  },
  onError: (error: any) => {
    if (error.code === 'INSUFFICIENT_STOCK') toast.error('재고 부족');
  }
});

// UI Flow Spec의 Step을 함수로 캡슐화
const handlePurchase = async () => {
  const stock = await stockQuery.refetch();
  if (stock.data?.available) paymentMutation.mutate(paymentData);
};
  • Spec의 단계(LOADING → PAYMENT_READY → PROCESSING → SUCCESS)를 쿼리/뮤테이션 라이프사이클과 정렬합니다.
  • UI 피드백(토스트/라우팅)은 Spec의 “시스템 반응”을 기준으로 구현합니다.

패턴 3: Feature-Sliced Design(FSD)로 구조화

1
2
3
4
5
6
7
8
9
10
11
12
13
14
src/
  features/
    product-purchase/           # UI Flow Spec = Feature 단위와 1:1
      model/
        use-purchase-flow.ts    # 훅/상태
        purchase-machine.ts     # XState 머신(선택)
      ui/
        PurchaseButton.tsx      # Step 1
        PaymentModal.tsx        # Step 2
        SuccessAnimation.tsx    # Step 3
      api/
        purchase-api.ts
      spec/
        ProductPurchase.uiflow.md
  • 파일 체계에 Spec을 함께 두면(PR 동시 리뷰, 변경 이력, 동기화)이 쉬워집니다.

디자인/테스트 도구와의 연계

Storybook: 상태별 Story 매핑

1
2
3
4
5
6
7
export default { title: 'Features/ProductPurchase', component: ProductPurchase };
export const Idle = () => <ProductPurchase state="idle" />;
export const Loading = () => <ProductPurchase state="loading" />;
export const PaymentReady = () => <ProductPurchase state="paymentReady" />;
export const Processing = () => <ProductPurchase state="processing" />;
export const Success = () => <ProductPurchase state="success" />;
export const Error = () => <ProductPurchase state="error" />;
  • UI Flow Spec의 각 상태를 Story로 고정하면 디자이너/QA와 소통이 쉬워집니다.

Playwright: 시나리오 기반 E2E

1
2
3
4
5
6
7
8
test('UI Flow Spec: 상품 구매 - 정상 플로우', async ({ page }) => {
  await page.goto('/product/123');                 // Step 1: IDLE
  await page.click('button:has-text("구매하기")'); // Step 2: LOADING
  await expect(page.getByRole('dialog')).toBeVisible(); // PAYMENT_READY
  await page.fill('[name="cardNumber"]', '1234-5678-9012-3456');
  await page.click('button:has-text("결제")');     // PROCESSING → SUCCESS
  await expect(page.getByText('결제가 완료되었습니다')).toBeVisible();
});
  • 테스트의 Given/When/Then을 Spec의 상태/전이/피드백과 1:1로 맞춥니다.

오늘부터 실천하기(체크리스트)

  • 현재 진행 중인 복잡 UI 1개 선택
  • UI Flow Spec으로 상태/전이/피드백을 1시간 내 작성
  • XState 또는 TanStack Query로 최소 기능 구현(2시간)
  • Storybook 상태 스토리와 Playwright E2E 1개씩 추가(1시간)

한계와 주의

  • Use Case는 구현 독립적 문서이며, UI 디테일은 의도적으로 범위 밖입니다.
  • UI Flow Spec은 이를 보완하는 실무 템플릿이므로, 팀/제품 맥락에 맞춰 간소화/확장하세요.
  • 접근성/성능/보안 등은 별도의 가이드와 함께 검토가 필요합니다.

마치며

학습/제안 단계에서 시작하는 작은 실험이 팀 커뮤니케이션과 품질 개선으로 이어질 수 있다고 기대합니다. 피드백과 사례 제보를 환영합니다.

다음 글 예고

  • 사례 A: 다단계 회원가입 UI Flow Spec
  • 사례 B: 실시간 협업(문서 편집) UI Flow Spec
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.