Search

Storybook SoT ์ „๋žต

05. Storybook ์ค‘์‹ฌ Single Source of Truth ์ „๋žต

์ „๋žต ๊ฐœ์š”

Storybook(์ฝ”๋“œ ์ปดํฌ๋„ŒํŠธ ์นดํƒˆ๋กœ๊ทธ) ์„ ๋””์ž์ธ ์‹œ์Šคํ…œ์˜ SoT๋กœ ๋‘๊ณ , Figma๋Š” ๊ทธ ์ฝ”๋“œ ์ปดํฌ๋„ŒํŠธ์˜ ์‹œ๊ฐ ๋ช…์„ธ/์ŠคํŽ™ ๋ฏธ๋Ÿฌ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์ „๋žต์ž…๋‹ˆ๋‹ค. "์ฝ”๋“œ๊ฐ€ ์ง„์‹ค์ด๋‹ค"๋ผ๋Š” ์›์น™์„ ๊ฐ€์žฅ ๊ฐ•ํ•˜๊ฒŒ ์ ์šฉํ•œ ์ „๋žต.
[React Components Repo] โ”‚ โ–ผ [Storybook (๋ฐฐํฌ๋œ ์นดํƒˆ๋กœ๊ทธ)] โ”‚ โ”œโ”€โ†’ Chromatic (์‹œ๊ฐ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ) โ”œโ”€โ†’ Figma "Story" ํ”Œ๋Ÿฌ๊ทธ์ธ์œผ๋กœ ์ž„๋ฒ ๋“œ โ””โ”€โ†’ Code Connect ๋งคํ•‘ โ”‚ โ–ผ [Figma Library Components] (์ฝ”๋“œ ์ปดํฌ๋„ŒํŠธ์™€ 1:1 ๋งคํ•‘๋œ ์ŠคํŽ™)
Plain Text
๋ณต์‚ฌ

ํ•ต์‹ฌ ๋„๊ตฌ

โ€ข
Storybook 7+
โ€ข
Chromatic: Storybook ํ˜ธ์ŠคํŒ… + ์‹œ๊ฐ ํšŒ๊ท€
โ€ข
Figma Code Connect: Figma ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ ์ปดํฌ๋„ŒํŠธ ๋งคํ•‘
โ€ข
story.to.design ๋˜๋Š” html.to.design: Storybook โ†’ Figma ์ž๋™ ๋ณ€ํ™˜
โ€ข
Figma Storybook Connect ํ”Œ๋Ÿฌ๊ทธ์ธ

์ ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค

โ€ข
๊ฐœ๋ฐœ์ž ์ฃผ๋„ ์กฐ์ง, ์ฝ”๋“œ ์šฐ์„  ๋ฌธํ™”
โ€ข
์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„ ์žฌ์‚ฌ์šฉ์„ฑ์ด ๋งค์šฐ ์ค‘์š”ํ•œ ์ œํ’ˆ (B2B SaaS, ๋Œ€์‹œ๋ณด๋“œ)
โ€ข
์‹œ๊ฐ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ๊ฐ€ ์ค‘์š”ํ•œ ํ™˜๊ฒฝ
โ€ข
๋””์ž์ด๋„ˆ๊ฐ€ ์ฝ”๋“œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‹ ๋ขฐํ•˜๊ณ  ์‚ฌ์šฉํ•  ์˜์ง€๊ฐ€ ์žˆ์Œ

๋‹จ๊ณ„๋ณ„ ์›Œํฌํ”Œ๋กœ

1) Storybook ์…‹์—…

npx storybook@latest init
Bash
๋ณต์‚ฌ
๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋งˆ๋‹ค *.stories.tsx ์ž‘์„ฑ:
export default { component: Button } satisfies Meta<typeof Button> export const Primary: Story = { args: { variant: 'primary', children: 'Click' } } export const Secondary: Story = { args: { variant: 'secondary', children: 'Click' } }
TypeScript
๋ณต์‚ฌ

2) Chromatic ๋ฐฐํฌ

โ€ข
Chromatic ๊ฐ€์ž… โ†’ ํ† ํฐ ๋ฐœ๊ธ‰
โ€ข
GitHub Actions๋กœ PR๋งˆ๋‹ค ์ž๋™ ๋ฐฐํฌ + ์‹œ๊ฐ ํšŒ๊ท€ ๊ฒ€์ฆ

3) Figma Code Connect ๋งคํ•‘

button.figma.tsx:
import { Button } from './Button' import figma from '@figma/code-connect' figma.connect(Button, '<https://figma.com/>...?node-id=1-2', { props: { variant: figma.enum('Variant', { Primary: 'primary', Secondary: 'secondary' }), label: figma.string('Label'), }, example: ({ variant, label }) => <Button variant={variant}>{label}</Button>, })
TypeScript
๋ณต์‚ฌ
npx figma connect publish
Bash
๋ณต์‚ฌ

4) Figma์— Storybook ์ž„๋ฒ ๋“œ

โ€ข
๋””์ž์ด๋„ˆ๊ฐ€ Figma์—์„œ Story URL์„ ์ž„๋ฒ ๋“œ ๋…ธ๋“œ๋กœ ์ถ”๊ฐ€
โ€ข
ํ•ญ์ƒ ์ตœ์‹  ์ฝ”๋“œ ์ปดํฌ๋„ŒํŠธ ์‹œ๊ฐ ํ™•์ธ ๊ฐ€๋Šฅ

5) story.to.design์œผ๋กœ Figma ์ปดํฌ๋„ŒํŠธ ์ž๋™ ์ƒ์„ฑ (์„ ํƒ)

โ€ข
Storybook ์Šคํ† ๋ฆฌ โ†’ Figma ์ปดํฌ๋„ŒํŠธ ์ž๋™ ๋ณ€ํ™˜
โ€ข
๋””์ž์ด๋„ˆ๊ฐ€ ๊ทธ๋ฆด ํ•„์š” ์—†์ด Figma Library๊ฐ€ ํ•ญ์ƒ ์ตœ์‹ 

์šด์˜ ๊ทœ์น™

โ€ข
์ปดํฌ๋„ŒํŠธ ์ถ”๊ฐ€/๋ณ€๊ฒฝ์€ ์ฝ”๋“œ์—์„œ๋งŒ โ†’ Storybook PR
โ€ข
๋””์ž์ด๋„ˆ๋Š” Figma์—์„œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ธ์Šคํ„ด์Šค๋กœ๋งŒ ์‚ฌ์šฉ (์ง์ ‘ ๊ทธ๋ฆฌ๊ธฐ ๊ธˆ์ง€)
โ€ข
Code Connect ๋งคํ•‘์ด ์—†๋Š” ์ปดํฌ๋„ŒํŠธ๋Š” ์‚ฌ์šฉ ๊ธˆ์ง€
โ€ข
Storybook์ด ๋นจ๊ฐ„์ƒ‰์ด๋ฉด Figma๋„ ์ž ๊ธˆ (๋ฐฐํฌ ๊ฒŒ์ดํŠธ)

์žฅ์ 

โ€ข
๋””์ž์ธ-์ฝ”๋“œ 1:1 ๋งคํ•‘ ๋ณด์žฅ (Code Connect)
โ€ข
์‹œ๊ฐ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ๋กœ ํšŒ๊ท€ ์‚ฌ๊ณ  ๋ฐฉ์ง€
โ€ข
๋””์ž์ด๋„ˆ๊ฐ€ ํ•ญ์ƒ "๋™์ž‘ ๊ฐ€๋Šฅํ•œ ์ปดํฌ๋„ŒํŠธ" ์‚ฌ์šฉ
โ€ข
์‹ ๊ทœ ์ž…์‚ฌ์ž ์˜จ๋ณด๋”ฉ ์ž๋ฃŒ๋กœ ์ตœ๊ฐ• (Storybook ํ•œ ๊ณณ์— ๋‹ค ์žˆ์Œ)

ํ•œ๊ณ„

โ€ข
์ดˆ๊ธฐ ๊ตฌ์ถ• ๋น„์šฉ ๋งค์šฐ ํผ
โ€ข
๋””์ž์ด๋„ˆ ์ž์œ ๋„ โ†“ (์ •ํ•ด์ง„ ์ปดํฌ๋„ŒํŠธ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ)
โ€ข
๋””์ž์ธ ํƒ์ƒ‰ ๋‹จ๊ณ„(์Šค์ผ€์น˜, ์™€์ด์–ดํ”„๋ ˆ์ž„)์™€ ์•ˆ ๋งž์Œ
โ€ข
Code Connect ๋งคํ•‘ ์œ ์ง€๋ณด์ˆ˜ ๋ถ€๋‹ด

Figma Make / MCP์™€์˜ ๊ฒฐํ•ฉ

โ€ข
Make๋Š” PoC/ํƒ์ƒ‰ ๋‹จ๊ณ„์—์„œ๋งŒ ์‚ฌ์šฉ โ†’ Storybook ์ปดํฌ๋„ŒํŠธ๋กœ ์ด๊ด€ ํ›„ ๋ณธ๊ฒฉ ์‚ฌ์šฉ
โ€ข
MCP๊ฐ€ ์ฝ”๋“œ ์ƒ์„ฑ ์‹œ Storybook ์ปดํฌ๋„ŒํŠธ๋งŒ importํ•˜๋„๋ก ํ”„๋กฌํ”„ํŠธ ๊ฐ•์ œ
โ€ข
AI๊ฐ€ ์ƒˆ ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ ์ „์— Storybook์— ์œ ์‚ฌ ์ปดํฌ๋„ŒํŠธ ๊ฒ€์ƒ‰ํ•˜๋„๋ก ์ง€์‹œ