실전 구현 기록 — SMPay AI 어시스턴트 (2026-08) React 18 + TypeScript + Zustand + TanStack Query 환경 기준


1. 핵심 설계 원칙

"LLM을 직접 호출하지 않는다"

프론트에서 LLM을 직접 호출하면 API Key가 노출된다. 실무에서는 백엔드가 LLM을 호출하고, 프론트는 대화 상태만 관리한다.

사용자 입력 → FE (상태 관리) → BE API 호출 → (BE → LLM) → FE 렌더링

단, 백엔드 없이 순수 FE에서 구현할 경우:


2. 아키텍처 — AI 패널 상태 관리

Zustand Store 설계

AI 패널은 전역 상태로 관리한다. 이유:

// store/useAiPanelStore.ts

export type AiMessage = {
  role: "user" | "assistant";
  content: string;
  options?: {
    label: string;
    value: string;
    variant?: "default" | "outline" | "secondary";
    group?: string; // 같은 group끼리 한 행에 렌더링
  }[];
};

type AiPanelStore = {
  messages: AiMessage[];
  isLoading: boolean;
  resetKey: number; // 증가 시 대화 초기화 useEffect 트리거

  onUserMessage: ((text: string) => void) | null;
  onOptionSelect: ((value: string) => void) | null;

  addMessage: (message: AiMessage) => void;
  setIsLoading: (loading: boolean) => void;
  setOnUserMessage: (handler: ...) => void;
  setOnOptionSelect: (handler: ...) => void;
  reset: () => void;
  restart: () => void; // resetKey 증가
};

핵심 패턴: 핸들러를 store에 등록한다.