Skip to content

feat: generative-ui#1451

Draft
malangcat wants to merge 2 commits intodaangn:devfrom
malangcat:json-render
Draft

feat: generative-ui#1451
malangcat wants to merge 2 commits intodaangn:devfrom
malangcat:json-render

Conversation

@malangcat
Copy link
Copy Markdown
Contributor

chrome_hdZ25O27kE.mp4
chrome_szzDmNw5Sh

남는 주간 토큰 태울겸 가지고 놀아봤습니다.

계획 단계 프롬프트 히스토리 ❯ json-render를 사용해 seed-design의 컴포넌트들을 사용해 generative ui를 만들고 싶습니다. AskUserQuestion 도구를 사용하여 자세히 인터뷰해주세요.

기술 구현, UI/UX, 엣지 케이스, 우려 사항, 트레이드오프에 대해 질문하세요.
명백한 질문을 하지 마세요, 당신이 고려하지 않았을 수 있는 어려운 부분을
파고드세요.

모든 것을 다룰 때까지 인터뷰를 계속한 다음 완전한 계획을 작성하세요.

● 먼저 코드베이스를 탐색해서 json-render와 seed-design 컴포넌트의 현재 상태를
파악하겠습니다. 그래야 의미 있는 질문을 드릴 수 있습니다.

● 3 Explore agents finished (ctrl+o to expand)
├─ Explore json-render packages · 70 tool uses · 62.8k tokens
│ ⎿ Done
├─ Explore seed-design React components · 43 tool uses · 60.4k tokens
│ ⎿ Done
└─ Explore json-render skills and docs · 43 tool uses · 49.5k tokens
⎿ Done

● 탐색 결과를 종합하면, json-render는 Vercel Labs의 프레임워크로 JSON spec →
React 컴포넌트 트리를 렌더링하는 시스템이고, 현재 seed-design에는 스킬 정의만
있고 실제 통합 코드는 아직 없는 상태입니다. seed-design은 70개+ 컴포넌트를
가진 성숙한 디자인 시스템이고요.

이제 의미 있는 질문을 드리겠습니다.

● ★ Insight ─────────────────────────────────────
json-render + seed-design 통합의 핵심 도전:

  1. seed-design의 compound component 패턴 (e.g., TextField.Root >
    TextField.Input)을 json-render의 flat element tree로 어떻게 매핑할지가
    아키텍처의 핵심 결정점입니다.
  2. seed-design의 StyleProps 시스템 (bg="bg.primary", padding="spacingY.lg")이
    json-render의 prop 스키마와 어떻게 공존할지도 중요한 설계 문제입니다.
  3. 현재 seed-design에는 @seed-design/docs-mcp라는 AI용 MCP 서버가 이미 있어서,
    LLM이 컴포넌트 문서를 조회할 수 있는 인프라가 갖춰져 있습니다.
    ─────────────────────────────────────────────────

좋은 설계를 위해 몇 가지 중요한 질문을 드리겠습니다.

● User answered Claude's questions:
⎿  · 이 generative UI의 주요 사용 시나리오는 무엇인가요? LLM이 실시간으로 UI를
생성하는 챗봇형인지, 아니면 미리 정의된 템플릿 기반인지에 따라 아키텍처가
크게 달라집니다. → LLM 실시간 생성
· 이 패키지의 위치와 배포 범위는 어떻게 되나요? → seed-design 모노레포 내부
· seed-design의 compound component(예: TextField.Root > TextField.Input >
TextField.SuffixIcon)를 json-render의 JSON spec에서 어떻게 표현하고
싶으신가요? 이것이 DX와 LLM 생성 난이도에 직접 영향을 줍니다. → Nested 트리
· 70개+ 컴포넌트 중 초기 지원 범위를 어떻게 잡으시나요? 전체를 한번에 하면
catalog 스키마가 방대해져 LLM의 토큰 사용량과 정확도에 영향을 줍니다. →
핵심 10-15개 + 레이아웃

● 좋습니다. 방향이 명확해지고 있습니다:

  • LLM 실시간 생성 기반 챗봇형 generative UI
  • seed-design 모노레포 내부 패키지
  • Nested 트리 방식으로 compound component 구조 유지
  • 핵심 10-15개 + 레이아웃 컴포넌트로 시작

이제 더 어려운 부분들을 파고들겠습니다.

● User answered Claude's questions:
⎿  · Nested 트리를 선택하셨는데, LLM이 seed-design의 compound component 구조를
정확히 생성하려면 각 컴포넌트의 허용된 children 타입을 알아야 합니다. 예를
들어 TextField.Root 안에는 TextField.Input이나 TextField.PrefixIcon만
들어갈 수 있죠. 이 구조적 제약을 어떻게 보장하시가요? → LLM 프롬프트로 안내
· json-render의 StateStore를 통한 상태 관리가 핵심입니다. 사용자가 생성된
UI와 상호작용할 때(e.g., 폼 입력, 버튼 클릭) 그 결과를 어디로 보내야
하나요? → 아직 잘 모르겠다. json-render/codegen까지 사용해서 디자인 자동화
하는데 쓰고 싶어서 아직 상태관리가 필요한지는 모르겠다
· LLM 스트리밍 중 부분적으로 생성된 spec을 점진적으로 렌더링해야 합니다.
json-render의 SpecStream(JSONL)을 사용하면 토큰이 도착할 때마다 UI가
점진적으로 나타나는데, 중간 상태의 깜박임/레이아웃 시프트 문제를 어떻게
다루시겠습니까? → 청크 단위 렌더링

● 매우 중요한 정보를 얻었습니다! json-render/codegen을 활용한 디자인 자동화가
핵심 목적이라는 점이 아키텍처를 크게 바꿉니다. 단순히 런타임 렌더링이 아니라,
LLM → JSON spec → 실제 코드 생성까지 가는 파이프라인이군요.

codegen 스킬을 확인하고 더 깊이 파고들겠습니다.

● Explore(Explore json-render codegen skill)
⎿  Done (4 tool uses · 31.9k tokens · 17s)
(ctrl+o to expand)

● ★ Insight ─────────────────────────────────────
json-render의 3단계 파이프라인이 핵심:

  1. @json-render/core → 스키마 정의 + LLM 프롬프트 생성 + spec 검증
  2. @json-render/react → JSON spec을 실시간 React 컴포넌트 트리로 렌더링
    (프리뷰)
  3. @json-render/codegen → JSON spec에서 실제 코드 파일 생성 (최종 산출물)

사용자가 원하는 것은 단순 런타임 UI가 아니라 LLM → spec → 프리뷰 + 코드
생성까지 이어지는 디자인 자동화 파이프라인입니다.
─────────────────────────────────────────────────

이해가 깊어졌습니다. 더 핵심적인 질문을 드리겠습니다.

● User answered Claude's questions:
⎿  · codegen으로 생성되는 코드의 최종 목표 형태가 뭔가요? 예를 들어
seed-design 컴포넌트를 import하는 React 컴포넌트 파일을 생성할 때, 어떤
스타일의 코드를 기대하시나요? → Snippet/레지스트리 형태
· 이 도구의 주요 사용자는 누구인가요? 이에 따라 catalog 설계와 프롬프트
전략이 달라집니다. → 내부 개발자
· seed-design에는 이미 rootage YAML에 컴포넌트 스키마(slots, variants,
props)가 정의되어 있습니다. json-render catalog의 Zod 스키마를 이 rootage
스키마에서 자동 생성하면 유지보수가 쉽지만, rootage에는 없는 React 특화
props(children, event handler 등)가 빠집니다. 어떻게 접근하시겠습니까? →
수동 작성

● 핵심 방향이 더 선명해졌습니다:

  • Snippet/레지스트리 형태로 코드 생성 (seed-design CLI의 1차 API)
  • 내부 개발자 대상 (당근 개발자가 빠르게 UI 프로토타이핑)
  • Catalog은 수동 작성 (rootage 자동 생성 대신 정확성 우선)

이제 가장 어려운 부분들을 짚어보겠습니다.

● Explore(Explore snippet registry format)
⎿  Done (24 tool uses · 52.9k tokens · 1m 17s)
(ctrl+o to expand)

● snippet 시스템을 완전히 이해했습니다. 이제 가장 어려운 엣지 케이스와 아키텍처
결정들을 짚겠습니다.

● User answered Claude's questions:
⎿  · 실제 snippet들을 보면 alert-dialog.tsx 같은 것은 forwardRef, displayName,
복잡한 타입 조합, innerDependencies(다른 snippet 참조) 등이 있습니다.
codegen으로 생성할 snippet의 복잡도 수준을 어떻게 설정하시나요? → 조합 수준
· 전체 파이프라인에서 프리뷰(렌더링)의 역할은 무엇인가요? codegen만 있으면
프리뷰 없이 코드만 뽑을 수도 있고, 프리뷰가 있으면 사용자가 수정 요청 후
코드를 내보낼 수도 있습니다. → 프리뷰 필수
· 새로 만드는 패키지의 구체적인 구성을 어떻게 생각하시나요? json-render의
core/react/codegen은 외부 의존성이고, seed-design 측에서는 catalog +
registry + codegen generator를 만들어야 합니다. → 단일 패키지

● 매우 좋습니다. 전체 그림이 거의 완성되었습니다:

LLM → JSON spec → 프리뷰(렌더링) → 수정 → codegen(snippet 코드 생성)

마지막으로 구현의 핵심 엣지 케이스들을 확인하겠습니다.
● User answered Claude's questions:
⎿  · catalog에 등록할 컴포넌트는 snippet 레벨(예: AlertDialog,
TextField)인가요, 아니면 @seed-design/react의 low-level 컴포넌트(예:
Dialog.Root, TextField.Root)인가요? 조합 수준 codegen이라면 snippet 레벨이
더 자연스럽지만, 프리뷰 렌더링 시 snippet을 그대로 React에 쓸 수 있는지가
문제입니다. → Snippet 레벨
· LLM 통합 방식을 어떻게 계획하시나요? 이 패키지가 LLM API를 직접 호출할지,
아니면 프롬프트/스키마만 제공하고 LLM 호출은 소비자에게 맡길지에 따라
패키지 경계가 달라집니다. → Claude API 내장
· 프리뷰 UI는 어디에 위치하나요? seed-design docs 사이트에 통합할지, 독립
앱으로 만들지에 따라 개발 방식이 달라집니다. → examples/에 generative-ui 앱
생성

● 거의 다 파악했습니다. 마지막으로 가장 까다로운 기술적 문제들을 짚겠습니다.

● User answered Claude's questions:
⎿  · Snippet 레벨 catalog의 핵심 문제: snippet은 파일(소스 코드)이지 React
컴포넌트가 아닙니다. json-render/react의 Renderer는 React 컴포넌트
registry가 필요합니다. 프리뷰용 registry를 어떻게 만드시겠습니까? →
Snippet을 React로 wrapping
· 당근 내부 개발자가 사용할 때, API 키 관리와 비용 통제를 어떻게 하시나요?
Claude API를 내장한다면 API 키가 필요하고, 토큰 비용이 발생합니다. →
환경변수
· examples/ 앱의 기술 스택은 뭔가요? → Vite + React

● 모든 핵심 결정이 내려졌습니다. 이제 종합적인 구현 계획을 설계하겠습니다.

● Plan(Design json-render implementation plan)
⎿  Done (64 tool uses · 79.0k tokens · 5m 35s)
(ctrl+o to expand)

● 포괄적인 계획이 나왔습니다. 마지막으로 몇 가지 핵심 snippet 파일을 직접
확인하여 계획의 정확성을 검증하겠습니다.

Read 3 files (ctrl+o to expand)

● Snippet 파일들의 실제 구조를 확인했습니다. 이제 기존 예제 앱의 Vite 설정을
참고하겠습니다.

Searched for 2 patterns, read 2 files (ctrl+o to expand)

● 모든 정보를 확보했습니다. 이제 최종 계획을 ���성하겠습니다.

● Updated plan
⎿  /plan to preview
⎿  PostToolUse:Write hook error ⎿  Failed with non-blocking status
code: /usr/bin/bash: line 1: jq:
command not found

● ★ Insight ─────────────────────────────────────
이 계획의 핵심 아키텍처 결정 3가지:

  1. Catalog은 Snippet 레벨: Dialog.Root 같은 low-level이 아닌 AlertDialog 같은
    snippet 단위로 등록합니다. LLM이 더 쉽게 올바른 구조를 생성할 수 있고, codegen
    출력이 기존 snippet을 그대로 import하는 조합 코드가 됩니다.
  2. 프리뷰 ↔ codegen 이중 경로: 같은 JSON spec에서 두 가지가 나옵니다.
    @json-render/react의 Renderer가 실시간 프리뷰를, @json-render/codegen이
    snippet 코드를 생성합니다. 프리뷰용 registry는 snippet 파일을 React로
    wrapping하여 해결합니다.
  3. Vite alias로 snippet 참조: snippet 소스 파일이 docs/registry/ui/에
    있으므로, 복사 대신 Vite의 resolve.alias로 ~/registry/ui →
    ../../docs/registry/ui를 매핑합니다. 중복 없이 단일 소스를 유지하는 실용적 POC
    전략입니다.
    ─────────────────────────────────────────────────

계획이 완성되었습니다. 인터뷰를 통해 확인한 모든 결정사항을 반영했고, 7개
Phase로 구성된 구체적인 구현 계획을 작성했습니다. 검토 후 승인해주시면 구현을
시작하겠습니다.

● User approved Claude's plan
⎿  Plan saved to: ~.claude\plans\mutable-wondering-star.md · /plan to edit
json-render + seed-design Generative UI 구현 계획

 Context

 seed-design(당근 디자인 시스템)의 snippet/컴포넌트를 활용하여 LLM 기반 
 generative UI를 구현한다. 핵심 파이프라인:

 사용자 프롬프트 → Claude API → JSON spec (스트리밍) → 프리뷰 렌더링 → 수정
 반복 → codegen(snippet 코드 생성)

 내부 개발자가 "회원가입 폼 만들어줘"와 같이 자연어로 요청하면, seed-design
 컴포넌트를 조합한 UI를 실시간 프리뷰하고, 최종적으로 seed-design CLI
 snippet 형식의 코드를 생성한다.

 ---
 결정 사항 요약

 ┌────────────────┬─────────────────────────────────────────────┐
 │      항목      │                    결정                     │
 ├────────────────┼─────────────────────────────────────────────┤
 │ 사용 시나리오  │ LLM 실시간 생성 (챗봇형)                    │
 ├────────────────┼─────────────────────────────────────────────┤
 │ 패키지 위치    │ packages/json-render/ (모노레포 내부)       │
 ├────────────────┼─────────────────────────────────────────────┤
 │ Compound 매핑  │ Nested 트리 (compound 구조 유지)            │
 ├────────────────┼─────────────────────────────────────────────┤
 │ 초기 범위      │ 핵심 ~15개 + 레이아웃                       │
 ├────────────────┼─────────────────────────────────────────────┤
 │ 구조 검증      │ LLM 프롬프트로 안내                         │
 ├────────────────┼─────────────────────────────────────────────┤
 │ 스트리밍 UX    │ 청크 단위 렌더링                            │
 ├────────────────┼─────────────────────────────────────────────┤
 │ Snippet 복잡도 │ 조합 수준 (기존 snippet import + 조합)      │
 ├────────────────┼─────────────────────────────────────────────┤
 │ 프리뷰         │ 필수 (프리뷰 → 수정 → codegen)              │
 ├────────────────┼─────────────────────────────────────────────┤
 │ Catalog 레벨   │ Snippet 레벨 (AlertDialog, TextField 단위)  │
 ├────────────────┼─────────────────────────────────────────────┤
 │ Catalog 소스   │ 수동 작성                                   │
 ├────────────────┼─────────────────────────────────────────────┤
 │ LLM 통합       │ Claude API 내장 (@anthropic-ai/sdk)         │
 ├────────────────┼─────────────────────────────────────────────┤
 │ 프리뷰 UI      │ examples/generative-ui/ (Vite + React)      │
 ├────────────────┼─────────────────────────────────────────────┤
 │ 렌더 매핑      │ Snippet을 React로 wrapping (POC용 상대경로) │
 ├────────────────┼─────────────────────────────────────────────┤
 │ API 키         │ 환경변��� (ANTHROPIC_API_KEY)               │
 ├────────────────┼─────────────────────────────────────────────┤
 │ 코드 출력      │ Snippet/레지스트리 형태                     │
 └────────────────┴─────────────────────────────────────────────┘

 ---
 Phase 1: 패키지 스캐폴딩

 1.1 packages/json-render/package.json

 {
   "name": "@seed-design/json-render",
   "version": "0.0.1",
   "private": true,
   "type": "module",
   "exports": {
     ".": "./src/index.ts",
     "./catalog": "./src/catalog/index.ts",
     "./registry": "./src/registry/index.ts",
     "./generator": "./src/generator/index.ts",
     "./client": "./src/client/index.ts"
   },
   "dependencies": {
     "@json-render/core": "...",
     "@json-render/react": "...",
     "@json-render/codegen": "...",
     "@anthropic-ai/sdk": "...",
     "zod": "..."
   },
   "peerDependencies": {
     "@seed-design/react": ">=1.0.0",
     "@seed-design/css": ">=1.0.0"
   }
 }

 1.2 디렉토리 구조

 packages/json-render/
 ├── package.json
 ├── tsconfig.json
 ├── src/
 │   ├── index.ts
 │   ├── types.ts
 │   ├��─ catalog/
 ��   │   ├── index.ts              # defineCatalog 호출
 │   │   └── schemas/
 │   │       ├── action-button.ts
 │   │       ├── text-field.ts
 │   │       ├── checkbox.ts
 │   │       ├── switch.ts
 │   │       ├── radio-group.ts
 │   │       ├── select-box.ts
 │   │       ├── tabs.ts
 │   │       ├── alert-dialog.ts
 │   │       ├── avatar.ts
 │   │       ├── badge.ts
 │   │       ├── text.ts
 │   │       ├── callout.ts
 │   │       └── layout.ts         # Box, VStack, HStack
 ��   ├── registry/
 │   │   ├── index.ts              # defineRegistry 호출
 │   │   └── components/
 │   │       ├── action-button.tsx
 │   │       ├── text-field.tsx
 │   │       ├── checkbox.tsx
 │   │       ├── switch.tsx
 │   │       ├── radio-group.tsx
 │   │       ├── select-box.tsx
 │   │       ��── tabs.tsx
 │   │       ├── alert-dialog.tsx
 │   │       ├── avatar.tsx
 │   │       ├���─ badge.tsx
 │   │       ├── text.tsx
 │   │       ├── callout.tsx
 │   │       └���─ layout.tsx
 │   ├── generator/
 │   │   ��── index.ts              # generateSnippetCode 메인 export
 │   │   ├── snippet-generator.ts  # spec → JSX 코드 변환
 │   │   ├── import-resolver.ts    # 컴포넌트 → import 경로 매핑
 │   │   └── template.ts           # 코드 템플릿 유틸
 │   └── client/
 │       ├── index.ts              # generateUI 메인 export
 │       ├── prompt-builder.ts     # seed-design 전용 시스템 프롬프트
 ���       └── stream-handler.ts     # 청크 단위 스트리밍

 생성/수정할 파일:
 - packages/json-render/package.json (신규)
 - packages/json-render/tsconfig.json (신규)
 - packages/json-render/src/index.ts (신규)
 - packages/json-render/src/types.ts (신규)

 ---
 Phase 2: Catalog 정의

 seed-design snippet의 props를 Zod 스키마로 정의하고 defineCatalog으로
 조립한다.

 2.1 초기 컴포넌트 목록

 레이아웃 (@seed-design/react 직접):
 - Box - 범용 컨테이너
 - VStack / HStack - Flex 래퍼
 - Text - 타이포그래피

 Snippet (docs/registry/ui/):
 - ActionButton - 액션 버튼 (variant, size, loading, disabled)
 - TextField + TextFieldInput - 텍스트 입력 (label, description,
 errorMessage, required, maxGraphemeCount)
 - Checkbox + CheckboxGroup - 체크박스
 - Switch - 스위치
 - RadioGroup + RadioGroupItem - 라디오
 - TabsRoot, TabsList, TabsTrigger, TabsContent - 탭 (compound)
 - AlertDialogRoot ~ AlertDialogAction - 다이얼로그 (compound)
 - Avatar - 아바타
 - Badge - 뱃지 (@seed-design/react 직접)
 - Callout - 콜아웃

 2.2 스키마 설계 원칙

 1. LLM이 다룰 props만 포함 (ref, fieldRef, rootRef 등 제외)
 2. ReactNode 타입의 display props → z.string() 으로 단순화
 3. 아이콘 props → 제외 (LLM이 아이콘 참조를 생성할 수 없음)
 4. children은 Zod prop이 아닌 spec의 children 배열로 처리

 2.3 핵심 참조 파일

 - docs/registry/ui/action-button.tsx - 단순 snippet 패턴
 - docs/registry/ui/text-field.tsx - 복잡 snippet (compound 내부 구조,
 grapheme 카운터)
 - docs/registry/ui/tabs.tsx - compound snippet (TabsRoot, TabsList,
 TabsTrigger, TabsContent)
 - packages/react/src/components/Text/Text.tsx - 레이아웃 컴포넌트 props

 생성할 파일:
 - src/catalog/schemas/*.ts (13개 스키마 파일)
 - src/catalog/index.ts

 ---
 Phase 3: Registry (프리뷰 렌더링)

 json-render/react의 Renderer가 사용할 React 컴포넌트 registry. 각 snippet
 export를 defineRegistry에 등록한다.

 3.1 Snippet Import 전략

 POC 단계에서 snippet 파일은 docs/registry/ui/에 있으므로, 예제 앱의 Vite
 alias로 해결:
 // vite.config.ts
 resolve: {
   alias: {
     "~/registry/ui": path.resolve(__dirname, "../../docs/registry/ui"),
   }
 }

 Registry 컴포넌트는 ~/registry/ui/*에서 snippet을 import한다.

 3.2 Registry 컴포넌트 패턴

 // registry/components/action-button.tsx
 import type { BaseComponentProps } from "@json-render/react";
 import { ActionButton as SnippetActionButton } from
 "~/registry/ui/action-button";

 export const ActionButton = ({ props, children }: BaseComponentProps) => (
   <SnippetActionButton variant={props.variant} size={props.size} 
 {...props}>
     {children}
   </SnippetActionButton>
 );

 Compound 컴포넌트(Tabs, AlertDialog)는 각 sub-component를 별도 등록.

 3.3 주의사항

 - Snippet 간 의존성: ActionButton → LoadingIndicator, TextField →
 @karrotmarket/react-monochrome-icon 등. 예제 앱의 dependencies에 포함 필요
 - CSS recipes: @seed-design/vite-plugin이 처리 (기존 예제 앱 패턴 참조:
 examples/stackflow-spa/)
 - 타입 경계: json-render의 string props ↔ seed-design의 strict union types
 → registry에서 as any 캐스팅 (POC 허용)

 생성할 파일:
 - src/registry/components/*.tsx (13개 컴포넌트 래퍼)
 - src/registry/index.ts

 ---
 Phase 4: Code Generator

 JSON spec → snippet 형식 .tsx 코드 생성.

 4.1 Import Resolver

 컴포넌트 타입을 import 경로에 매핑:

 ┌───────────────────────────┬────────────────────┬──────────────────┐
 │         컴포넌트          │    Import 경로     │       종류       │
 ├───────────────────────────┼────────────────────┼──────────────────┤
 │ ActionButton              │ ./action-button    │ snippet 상대경로 │
 ├───────────────────────────┼────────────────────┼──────────────────┤
 │ TextField, TextFieldInput │ ./text-field       │ snippet 상대경로 │
 ├───────────────────────────┼────────────────────┼──────────────────┤
 │ TabsRoot, TabsList, ...   │ ./tabs             │ snippet 상대경로 │
 ├───────────────────────────┼────────────────────┼──────────────────┤
 │ Box, VStack, HStack, Text │ @seed-design/react │ 패키지           │
 ├───────────────────────────┼────────────────────┼──────────────────┤
 │ Badge                     │ @seed-design/react │ 패키지           │
 └───────────────────────────┴────────────────────┴──────────────────┘

 4.2 생성 코드 형태

 "use client";

 import { ActionButton } from "./action-button";
 import { TextField, TextFieldInput } from "./text-field";
 import { VStack } from "@seed-design/react";

 export function OrderForm() {
   return (
     <VStack gap="spacingY.md">
       <TextField label="주문자명" required>
         <TextFieldInput placeholder="이름을 입력하세요" />
       </TextField>
       <ActionButton variant="brandSolid">주문하기</ActionButton>
     </VStack>
   );
 }

 4.3 @json-render/codegen 활용

 - collectUsedComponents(spec) → 필요한 컴포넌트 수집
 - traverseSpec(spec, callback) → depth-first 트리 순회
 - serializeProps(props) → JSX 어트리뷰트 직렬화
 - serializePropValue(value) → 개별 값 직렬화

 생성할 파일:
 - src/generator/import-resolver.ts
 - src/generator/template.ts
 - src/generator/snippet-generator.ts
 - src/generator/index.ts

 ---
 Phase 5: Claude API Client

 5.1 프롬프트 빌더

 buildUserPrompt() (from @json-render/core) + seed-design 전용 규칙:
 - spacing token 사용법 (spacingX.xs, spacingY.md 등)
 - compound 구조 규칙 (TextField > TextFieldInput, TabsRoot > TabsList >
 TabsTrigger 등)
 - 텍스트 스타일 값 (title1Bold, bodyL1Regular 등)
 - 한국어 레이블 권장

 5.2 스트리밍

 createSpecStreamCompiler() (from @json-render/core)로 JSONL 청크를 파싱하여
  컴포넌트 단위로 프리뷰 업데이트.

 5.3 메인 API

 export async function generateUI(options: {
   prompt: string;
   currentSpec?: Spec;         // 수정 모드 시 기존 spec
   apiKey?: string;            // default: process.env.ANTHROPIC_API_KEY
   model?: string;             // default: "claude-sonnet-4-20250514"
   onPartialSpec?: (spec: Spec) => void;
 }): Promise<{ spec: Spec; text: string }>

 생성할 파일:
 - src/client/prompt-builder.ts
 - src/client/stream-handler.ts
 - src/client/index.ts

 ---
 Phase 6: 예제 앱

 6.1 구조

 examples/generative-ui/
 ├── package.json
 ├── index.html
 ├── vite.config.ts
 ├── tsconfig.json
 ├── .env.local                  # VITE_ANTHROPIC_API_KEY (gitignored)
 └── src/
     ├── main.tsx
     ├── App.tsx                 # 3패널: Chat / Preview / Code
     ├── components/
     │   ��── ChatInput.tsx       # 프롬프트 입력
     │   ├── PreviewPanel.tsx    # json-render Renderer로 spec 렌더링
     │   └── CodePanel.tsx       # generateSnippetCode 결과 표시
     └── hooks/
         └── useGenerateUI.ts    # React 상태 관리 + API 호출

 6.2 핵심 의존성

 {
   "dependencies": {
     "@seed-design/css": "workspace:*",
     "@seed-design/react": "workspace:*",
     "@seed-design/json-render": "workspace:*",
     "@json-render/core": "...",
     "@json-render/react": "...",
     "@json-render/codegen": "...",
     "@anthropic-ai/sdk": "...",
     "@karrotmarket/react-monochrome-icon": "^1.10.0",
     "react": "^19.2.3",
     "react-dom": "^19.2.3"
   },
   "devDependencies": {
     "@seed-design/vite-plugin": "^1.1.1",
     "@vitejs/plugin-react": "^6.0.0",
     "vite": "^8.0.0",
     "typescript": "^5.9.2"
   }
 }

 6.3 Vite 설정

 import { seedDesignPlugin } from "@seed-design/vite-plugin";
 import react from "@vitejs/plugin-react";
 import path from "path";
 import { defineConfig } from "vite";

 export default defineConfig({
   plugins: [react(), seedDesignPlugin()],
   resolve: {
     alias: {
       "~/registry/ui": path.resolve(__dirname, "../../docs/registry/ui"),
     },
   },
 });

 6.4 앱 플로우

 1. 사용자가 ChatInput에 프롬프트 입력
 2. useGenerateUI → generateUI() 호출 (스트리밍)
 3. 스트리밍 중 onPartialSpec으로 PreviewPanel 실시간 업데이트
 4. 완료 시 CodePanel에 generateSnippetCode(spec) 결과 표시
 5. 수정 요청 → currentSpec + 새 프롬프트로 재생성

 생성할 파일:
 - examples/generative-ui/package.json
 - examples/generative-ui/index.html
 - examples/generative-ui/vite.config.ts
 - examples/generative-ui/tsconfig.json
 - examples/generative-ui/src/main.tsx
 - examples/generative-ui/src/App.tsx
 - examples/generative-ui/src/components/ChatInput.tsx
 - examples/generative-ui/src/components/PreviewPanel.tsx
 - examples/generative-ui/src/components/CodePanel.tsx
 - examples/generative-ui/src/hooks/useGenerateUI.ts

 ---
 Phase 7: 테스트

 7.1 단위 테스트 (Bun test)

 - Catalog 스키마 검증 (catalog.test.ts)
 - Code generator 출력 검증 (generator.test.ts)
 - Import resolver 매핑 검증 (import-resolver.test.ts)

 7.2 통합 테스트

 - Registry 렌더링: 알려진 spec → Renderer → DOM 검증

 7.3 검증 방법

 # 패키지 테스트
 bun test packages/json-render

 # 예제 앱 실��
 cd examples/generative-ui && bun dev

 # 전체 빌드 확인
 bun packages:build

 ---
 구현 순서

 1. 패키지 스캐폴딩 → package.json, tsconfig, index.ts
 2. 레이아웃 catalog → Box, VStack, HStack, Text 스키마 (가장 단순)
 3. 레이아웃 registry → @seed-design/react에서 직접 wrapping (snippet
 불필요)
 4. ActionButton catalog + registry → 가장 단순한 snippet
 5. 나머지 단순 snippet → Badge, Avatar, Switch, Callout
 6. 복합 snippet → TextField, Checkbox, RadioGroup
 7. Compound snippet → Tabs, AlertDialog
 8. Generator → import-resolver → template → snippet-generator
 9. Client → prompt-builder → stream-handler → generateUI
 10. 예제 앱 → Vite 설정 → 하드코딩 spec으로 프리뷰 검증 → Claude API 연동 →
  CodePanel
 11. 테스트 작성

 ---
 주의사항 / 리스크

 1. @json-render/ 패키지 설치*: 이 패키지들이 npm에 공개되어 있는지 확인
 필요 (Vercel Labs). 비공개라면 설치 방법 논의 필요
 2. CORS: 클라이언트에서 직접 Claude API 호출 시 CORS 문제 가능. POC에서는
 Vite proxy 또는 서버 미들웨어로 우회
 3. Snippet 간 의존성 체인: ActionButton → LoadingIndicator →
 ProgressCircle. Vite alias가 상대경로를 올바르게 해결하는지 검증 필요
 4. CSS 주입: @seed-design/vite-plugin이 snippet의 CSS recipe를 올바르게
 처리하는지 확인
 5. 토큰 비용: Claude API 시스템 프롬프트에 전체 catalog가 포함되므로 토큰
 사용량 모니터링 필요

● 계획이 승인되었습니다. 구현을 시작하겠습니다. 먼저 @json-render 패키지의 npm
가용성을 확인하고, 패키지 스캐폴딩부터 진행합니다.

malangcat and others added 2 commits April 13, 2026 06:00
…tion

Implement @seed-design/json-render package that bridges json-render framework
with seed-design components for LLM-powered UI generation. Includes catalog
with 30 component schemas, React registry for live preview, code generator
for snippet output, and Claude API client with streaming support.

Add examples/generative-ui Vite+React app as POC with preview/code panels.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 12, 2026

⚠️ No Changeset found

Latest commit: ebe833a

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 12, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3a7a66d5-9f2f-43cd-924f-db0f39bcaf71

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant