실전 구현 기록 — SMPay AI 어시스턴트 (2026-08) React 18 + TypeScript + Zustand + TanStack Query 환경 기준
프론트에서 LLM을 직접 호출하면 API Key가 노출된다. 실무에서는 백엔드가 LLM을 호출하고, 프론트는 대화 상태만 관리한다.
사용자 입력 → FE (상태 관리) → BE API 호출 → (BE → LLM) → FE 렌더링
단, 백엔드 없이 순수 FE에서 구현할 경우:
process.env.GROQ_API_KEY, NEXT_PUBLIC_ 금지)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에 등록한다.
setOnUserMessage, setOnOptionSelect로 핸들러를 등록AiSidePanel)는 store에서 핸들러를 꺼내 호출만 함