๐ŸŽจ ํ”„๋ก ํŠธ์—”๋“œ ๊ธฐ์ˆ  ์Šคํƒ ์„ค๊ณ„ - 100-hours-a-week/9-team-Devths-WIKI GitHub Wiki

๐Ÿ“ ์ตœ์ข… ๊ธฐ์ˆ  ์Šคํƒ ์š”์•ฝํ‘œ

์˜์—ญ ๊ธฐ์ˆ  ์„ ์ • ์ด์œ  ์š”์•ฝ
์–ธ์–ด TypeScript v5.9.3 ํ™”๋ฉด/๊ธฐ๋Šฅ์ด ๋งŽ์•„ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๊ฐ€ ๋ณต์žกํ•ด์ง€๋Š” Devths์—์„œ ํƒ€์ž…์„ ํ†ตํ•ด ํ•„๋“œ ๋ˆ„๋ฝยทํƒ€์ž… ์ฐฉ๊ฐ์„ ๊ฐœ๋ฐœ ๋‹จ๊ณ„์—์„œ ์ฐจ๋‹จํ•˜๊ณ , ๋ฆฌํŒฉํ† ๋ง๊ณผ ํ˜‘์—… ์•ˆ์ •์„ฑ์„ ๋†’์ด๊ธฐ ์œ„ํ•ด ์ฑ„ํƒ
๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ React v19.2 ์บ˜๋ฆฐ๋”/๊ฒŒ์‹œํŒ/์ฑ„ํŒ…์ฒ˜๋Ÿผ ์ƒํƒœ ๋ณ€ํ™”์™€ ์ธํ„ฐ๋ž™์…˜์ด ๋งŽ์€ UI๋ฅผ ์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„๋กœ ๋ถ„๋ฆฌํ•ด ๊ด€๋ฆฌํ•˜๊ณ , ์ƒํƒœ ๊ธฐ๋ฐ˜ UI ์—…๋ฐ์ดํŠธ๋กœ ๋ณต์žก๋„๋ฅผ ๋‚ฎ์ถ”๊ธฐ ์œ„ํ•ด ์ฑ„ํƒ
ํ”„๋ ˆ์ž„์›Œํฌ Next.js 16 ํŽ˜์ด์ง€ ์ˆ˜๊ฐ€ ๋งŽ๊ณ (๊ณตํ†ต ๋ ˆ์ด์•„์›ƒ ๋ฐ˜๋ณต), ๋กœ๊ทธ์ธ ์ „/ํ›„ ๋ถ„๊ธฐ์™€ ์—๋Ÿฌ ํŽ˜์ด์ง€๊ฐ€ ์ค‘์š”ํ•œ ๊ตฌ์กฐ์—์„œ ๋ผ์šฐํŒ…ยท๋ ˆ์ด์•„์›ƒยท์—๋Ÿฌ ์ฒ˜๋ฆฌยทSSR/SSG๋ฅผ ํ”„๋ ˆ์ž„์›Œํฌ ์ˆ˜์ค€์—์„œ ํ‘œ์ค€ํ™”ํ•˜๊ธฐ ์œ„ํ•ด ์ฑ„ํƒ
์ „์—ญ ์ƒํƒœ Zustand v5.0.9 ํ† ์ŠคํŠธ/์ „์—ญ ๋ชจ๋‹ฌ/ํƒญยทํ•„ํ„ฐ ๊ฐ™์€ UI ์ „์—ญ ์ƒํƒœ๊ฐ€ ๋งŽ์•„ prop drilling์„ ์ค„์ด๊ณ , ํ•„์š”ํ•œ ์ƒํƒœ๋งŒ ์„ ํƒ ๊ตฌ๋…ํ•ด ๋ฆฌ๋ Œ๋”๋ง ๋ฒ”์œ„๋ฅผ ํ†ต์ œํ•˜๊ธฐ ์œ„ํ•ด ์ฑ„ํƒ
์„œ๋ฒ„ ์ƒํƒœ TanStack Query v5.90.16 ๋ชฉ๋ก/๊ฒ€์ƒ‰/ํ•„ํ„ฐ/๋ฌดํ•œ ์Šคํฌ๋กค์ด ๋งŽ๊ณ , ๋ณ€๊ฒฝ ํ›„ ๊ฐฑ์‹ (invalidate) ํ๋ฆ„์ด ๋ณต์žกํ•ด์ง€๋Š” Devths์—์„œ ์บ์‹ฑยท๋™๊ธฐํ™”ยทํŽ˜์ด์ง€๋„ค์ด์…˜ ํŒจํ„ด์„ ํ‘œ์ค€ํ™”ํ•˜๊ธฐ ์œ„ํ•ด ์ฑ„ํƒ
์Šคํƒ€์ผ๋ง Tailwind CSS v4.1 ๋ฐ˜๋ณต UI์™€ ์ƒํƒœ๋ณ„ ์Šคํƒ€์ผ(์„ ํƒ/์—๋Ÿฌ/๋น„ํ™œ์„ฑ ๋“ฑ)์ด ๋งŽ์€ ๊ตฌ์กฐ์—์„œ JSX์—์„œ ๋น ๋ฅด๊ฒŒ ์ˆ˜์ •ํ•˜๊ณ , config๋กœ ๋””์ž์ธ ๊ธฐ์ค€์„ ๊ณ ์ •ํ•ด ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์ฑ„ํƒ
UI ์ปดํฌ๋„ŒํŠธ shadcn/ui ๋ชจ๋‹ฌ/๋“œ๋กญ๋‹ค์šด/ํƒญ ๋“ฑ ์ƒํ˜ธ์ž‘์šฉ UI๋ฅผ ํ”„๋กœ์ ํŠธ๊ฐ€ ์ฝ”๋“œ๋กœ ์†Œ์œ ํ•ด ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž๊ฒŒ ์ˆ˜์ •ํ•˜๊ณ , ์ ‘๊ทผ์„ฑ ํŒจํ„ด์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ณตํ†ต UI๋ฅผ ํ‘œ์ค€ํ™”ํ•˜๊ธฐ ์œ„ํ•ด ์ฑ„ํƒ
์บ˜๋ฆฐ๋” UI FullCalendar v6.1.20 ๋‹ฌ๋ ฅ ํŠน์œ ์˜ ๋ทฐ ์ „ํ™˜ยท์ด๋ฒคํŠธ ๋ฐฐ์น˜ยท์˜ˆ์™ธ ์ผ€์ด์Šค๋ฅผ ๊ฒ€์ฆ๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์ปค๋ฒ„ํ•˜๊ณ , Devths ์š”๊ตฌ์— ๋งž์ถ˜ ์ปค์Šคํ…€ ๋ Œ๋”๋ง/์ƒํ˜ธ์ž‘์šฉ ๊ตฌํ˜„์— ์ง‘์ค‘ํ•˜๊ธฐ ์œ„ํ•ด ์ฑ„ํƒ
ํŒจํ‚ค์ง€ ๊ด€๋ฆฌ pnpm v10.27.0 ์˜์กด์„ฑ์ด ์ปค์งˆ์ˆ˜๋ก ์„ค์น˜ ์†๋„/๋””์Šคํฌ/CI ์•ˆ์ •์„ฑ์ด ์ค‘์š”ํ•ด์ง€๋Š” ํŒ€ ํ”„๋กœ์ ํŠธ์—์„œ ๊ณต์šฉ ์ €์žฅ์†Œ ๊ธฐ๋ฐ˜ ์„ค์น˜ ํšจ์œจ๊ณผ lockfile ์žฌํ˜„์„ฑ์„ ํ™•๋ณดํ•˜๊ธฐ ์œ„ํ•ด ์ฑ„ํƒ
๋ฒˆ๋“ค๋Ÿฌ/๋นŒ๋“œ Turbopack Next.js ๊ธฐ๋ณธ ํ†ตํ•ฉ ํ๋ฆ„์„ ์œ ์ง€ํ•˜๋ฉด์„œ ์„ค์ • ๋ถ€๋‹ด์„ ์ค„์ด๊ณ , ๊ทœ๋ชจ ํ™•์žฅ ์‹œ ๊ฐœ๋ฐœ ์„œ๋ฒ„ ์ฒด๊ฐ ์†๋„๋ฅผ ํ™•๋ณดํ•˜๋Š” ์„ ํƒ์ง€๋กœ ์ฑ„ํƒ
์œ ํšจ์„ฑ ๊ฒ€์‚ฌ Zod v4.3.4 ์ž…๋ ฅ ํ™”๋ฉด๊ณผ ๊ทœ์น™์ด ๋งŽ์€ ๊ตฌ์กฐ์—์„œ ๊ฒ€์ฆ ์ •์ฑ…์„ ์Šคํ‚ค๋งˆ๋กœ ๊ณ ์ •ยท์žฌ์‚ฌ์šฉํ•˜๊ณ , TypeScript ํƒ€์ž… ์ถ”๋ก ์œผ๋กœ ๊ฒ€์ฆ ๊ทœ์น™๊ณผ ํƒ€์ž… ๋ถˆ์ผ์น˜ ๋ฆฌ์Šคํฌ๋ฅผ ์ค„์ด๊ธฐ ์œ„ํ•ด ์ฑ„ํƒ
ํผ ์ฒ˜๋ฆฌ React Hook Form v7.70.0 ํšŒ์›๊ฐ€์ž…/์ž‘์„ฑ/์ˆ˜์ • ๋“ฑ ํผ์ด ๋งŽ์€ ํ”„๋กœ์ ํŠธ์—์„œ ํผ ์ƒํƒœยท์ œ์ถœยท์—๋Ÿฌ ์ฒ˜๋ฆฌ๋ฅผ ํ‘œ์ค€ํ™”ํ•˜๊ณ , Zod ๊ฒ€์ฆ ๊ฒฐ๊ณผ๋ฅผ UI์— ์ผ๊ด€๋˜๊ฒŒ ์—ฐ๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์ฑ„ํƒ
API ํ†ต์‹  Axios v1.13.2 OAuth ์ดํ›„ ๊ณตํ†ต ํ—ค๋”/ํ† ํฐ ์ฃผ์ž…, ๊ณตํ†ต ์—๋Ÿฌ ์ฒ˜๋ฆฌ, ์—…๋กœ๋“œ ํŒจํ„ด ๋“ฑ์„ ์ธํ„ฐ์…‰ํ„ฐ์™€ ์ธ์Šคํ„ด์Šค๋กœ ์ค‘์•™ํ™”ํ•ด ๋„คํŠธ์›Œํฌ ์ •์ฑ…์„ ์ผ๊ด€๋˜๊ฒŒ ์šด์˜ํ•˜๊ธฐ ์œ„ํ•ด ์ฑ„ํƒ
๋‹จ์œ„/์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ Vitest v4.0.16 UI ๋กœ์ง/๊ฒ€์ฆ/์ƒํƒœ ์ „ํ™˜ ํ…Œ์ŠคํŠธ๋ฅผ ๋น ๋ฅด๊ฒŒ ๋ฐ˜๋ณต ์‹คํ–‰ํ•˜๊ณ , TS/React ํ…Œ์ŠคํŠธ ์ƒํƒœ๊ณ„์™€ ๊ฒฐํ•ฉํ•ด ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ ์šด์˜ ๋ถ€๋‹ด์„ ์ค„์ด๊ธฐ ์œ„ํ•ด ์ฑ„ํƒ
์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ React Testing Library v16.3.1 ๊ตฌํ˜„์ด ์•„๋‹ˆ๋ผ ์‚ฌ์šฉ์ž ๊ด€์ (DOM ์ƒํ˜ธ์ž‘์šฉ)์œผ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•ด ๋ฆฌํŒฉํ† ๋ง ๋‚ด๊ตฌ์„ฑ์„ ๋†’์ด๊ณ , ์ ‘๊ทผ์„ฑ ๊ธฐ๋ฐ˜ ์กฐํšŒ๋กœ ํ…Œ์ŠคํŠธ ํ‘œ์ค€์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์ฑ„ํƒ
E2E ํ…Œ์ŠคํŠธ Playwright v1.57.0 ๋žœ๋”ฉโ†’๋กœ๊ทธ์ธโ†’๋ฉ”์ธ ์ง„์ž… ๊ฐ™์€ ํ•ต์‹ฌ ์‚ฌ์šฉ์ž ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์‹ค์ œ ๋ธŒ๋ผ์šฐ์ €์—์„œ ๊ฒ€์ฆํ•˜๊ณ , ์ž๋™ ๋Œ€๊ธฐ/ํŠธ๋ ˆ์ด์Šค ๋“ฑ์œผ๋กœ E2E ์šด์˜ ์•ˆ์ •์„ฑ์„ ํ™•๋ณดํ•˜๊ธฐ ์œ„ํ•ด ์ฑ„ํƒ
์‹ค์‹œ๊ฐ„ STOMP + WebSocket ์ฑ„ํŒ…/์•Œ๋ฆผ์—์„œ ํ•„์š”ํ•œ ์žฌ์—ฐ๊ฒฐยทํด๋ฐฑยท๋ฃธ ๋‹จ์œ„ ๋ฉ”์‹œ์ง•ยทACK ํŒจํ„ด์„ ๊ธฐ๋ณธ ์ œ๊ณตํ•ด, ์‹คํ™˜๊ฒฝ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๋ถ€๋‹ด์„ ์ค„์ด๊ณ  ์•ˆ์ •์ ์ธ ์‹ค์‹œ๊ฐ„ UX๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์ฑ„ํƒ

๐Ÿค– Devths

1๏ธโƒฃ ์„œ๋น„์Šค ๋ชฉ์ 

Devths๋Š” ์ทจ์—… ์ค€๋น„ ์‚ฌ์šฉ์ž๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์ผ์ •(์บ˜๋ฆฐ๋”/To-Do) ๊ด€๋ฆฌ, ๊ฒŒ์‹œํŒ ๊ธฐ๋ฐ˜ ์ •๋ณด ํƒ์ƒ‰ยท์ž‘์„ฑยท๊ณต์œ , ๊ฐœ์ธ/๊ทธ๋ฃน ์ฑ„ํŒ…, AI ์ปค๋ฆฌ์–ด ์ฑ—๋ด‡์„ ํ†ตํ•œ ์ž๋ฃŒ ๋ถ„์„ยท์ƒ๋‹ด, ์•Œ๋ฆผ, ํ”„๋กœํ•„/ํŒ”๋กœ์šฐ ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ์ทจ์—… ์ค€๋น„ ๊ณผ์ •์„ ํ•œ ๊ณณ์—์„œ ๊ด€๋ฆฌํ•˜๊ณ  ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ์„œ๋น„์Šค์ด๋‹ค.

2๏ธโƒฃ ์„œ๋น„์Šค ํ•ต์‹ฌ ๊ธฐ๋Šฅ

(1) ์บ˜๋ฆฐ๋”

  • ์ผ์ • ์กฐํšŒ/๋“ฑ๋ก/์ˆ˜์ •/์‚ญ์ œ (์›”, ์ฃผ ๋ทฐ)
  • AI ์ž๋™ ์ผ์ • ์‚ฝ์ž…: ์ฑ„์šฉ ๊ณต๊ณ  ์—…๋กœ๋“œ โ†’ AI๋กœ ์ถ”์ถœ โ†’ ์ผ์ • ์ดˆ์•ˆ ์ƒ์„ฑ โ†’ ์‚ฌ์šฉ์ž ํ™•์ธ ํ›„ ์บ˜๋ฆฐ๋”์— ์ €์žฅ

(2) ๊ฒŒ์‹œํŒ

  • ๊ธ€ ๋ชฉ๋ก/์ƒ์„ธ/์ž‘์„ฑ/์ˆ˜์ •/์‚ญ์ œ
  • ๋Œ“๊ธ€/์ข‹์•„์š”/๊ฒ€์ƒ‰(ํ•„ํ„ฐ)

(3) ์ฑ—๋ด‡/AI

  • ์ด๋ ฅ์„œ/ํฌํŠธํด๋ฆฌ์˜ค/์ฑ„์šฉ๊ณต๊ณ  ๋“ฑ ์ž…๋ ฅ ๊ธฐ๋ฐ˜ ๋‹ต๋ณ€ ์ƒ์„ฑ
  • ๋ฉด์ ‘ ๋ชจ๋“œ (์งˆ๋ฌธ ์ƒ์„ฑ/ํ”ผ๋“œ๋ฐฑ)
  • ๋Œ€ํ™” ์ด๋ ฅ ๊ด€๋ฆฌ ๋ฐ ์ปจํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ ์‘๋‹ต ์ œ๊ณต

(4) ์ฑ„ํŒ…

  • ์ฑ„ํŒ…๋ฐฉ ๋ชฉ๋ก/์ƒ์„ฑ/์ฐธ์—ฌ/๋‚˜๊ฐ€๊ธฐ
  • ์‹ค์‹œ๊ฐ„ ๋ฉ”์‹œ์ง€ ์ „์†ก/์ˆ˜์‹ , ์ฝ์Œ ์ฒ˜๋ฆฌ
  • ๋ฉ”์‹œ์ง€ ํžˆ์Šคํ† ๋ฆฌ ๋กœ๋”ฉ(๋ฌดํ•œ์Šคํฌ๋กค) ๋ฐ ํŒŒ์ผ/์ด๋ฏธ์ง€ ์ฒจ๋ถ€

3๏ธโƒฃ ์„ ์ • ๊ธฐ์ค€

๐Ÿ’ก

Devths๋Š” ํŽ˜์ด์ง€๊ฐ€ ๋งŽ๊ณ (์บ˜๋ฆฐ๋”/๊ฒŒ์‹œํŒ/์ฑ„ํŒ…/์ฑ—๋ด‡/ํ”„๋กœํ•„/์„ค์ • ๋“ฑ), ๋ฐ์ดํ„ฐ ํ˜•ํƒœ๊ฐ€ ๋‹ค์–‘ํ•˜๋ฉฐ, ์‹ค์‹œ๊ฐ„ ๊ธฐ๋Šฅ(์ฑ„ํŒ…)๊ณผ AI ๊ธฐ๋ฐ˜ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ(๊ณต๊ณ  ์—…๋กœ๋“œ โ†’ ์ถ”์ถœ โ†’ ์ดˆ์•ˆ ์ƒ์„ฑ)๊ฐ€ ์„ž์—ฌ ์žˆ๋Š” ์„œ๋น„์Šค์ž„

  • ๊ทธ๋ž˜์„œ ํ”„๋ก ํŠธ์—”๋“œ ๊ธฐ์ˆ  ์Šคํƒ์€ ์„œ๋น„์Šค ์š”๊ตฌ์‚ฌํ•ญ์„ ์•ˆ์ •์ ์œผ๋กœ ๊ตฌํ˜„ํ•˜๊ณ , ์œ ์ง€๋ณด์ˆ˜์™€ ํ™•์žฅ์— ๊ฐ•ํ•œ ์กฐํ•ฉ์ธ์ง€ ๋” ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•จ

(1) ๊ธฐ๋Šฅ ์ ํ•ฉ์„ฑ

  • Devths๋Š” ๋‹จ์ˆœ CRUD๋งŒ ์žˆ๋Š” ์„œ๋น„์Šค๊ฐ€ ์•„๋‹ˆ๋ผ, ์บ˜๋ฆฐ๋”/๋ฌดํ•œ์Šคํฌ๋กค/์‹ค์‹œ๊ฐ„/ํŒŒ์ผ์—…๋กœ๋“œ/AI ์ฒ˜๋ฆฌ ํ๋ฆ„์ฒ˜๋Ÿผ UI ์š”๊ตฌ๊ฐ€ ๋ณต์žกํ•จ
  • ํŒ๋‹จ ๊ธฐ์ค€
    • ์‹ค์‹œ๊ฐ„ ์ด๋ฒคํŠธ(์ฝ์Œ/์ „์†ก/์ž…์žฅ ๋“ฑ) ์ฒ˜๋ฆฌ๋ฅผ ์•ˆ์ •์ ์œผ๋กœ ๋ถ™์ผ ์ˆ˜ ์žˆ๋Š”๊ฐ€?
    • ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ(์กฐํšŒ/์ €์žฅ/์žฌ์‹œ๋„/์บ์‹ฑ) ์ฒ˜๋ฆฌ๊ฐ€ ํ‘œ์ค€ํ™” ๊ฐ€๋Šฅํ•œ๊ฐ€?
    • ๋ผ์šฐํŒ…/๋ ˆ์ด์•„์›ƒ ๊ตฌํ˜„์ด ์‰ฌ์šด๊ฐ€?

(2) ์œ ์ง€๋ณด์ˆ˜์„ฑ

  • ํ™”๋ฉด๊ณผ API๊ฐ€ ๋Š˜์ˆ˜๋ก ์–ด๋””์„œ ๋ญ๊ฐ€ ๋ฐ”๋€Œ๋Š”์ง€ ์ถ”์  ๋น„์šฉ์ด ๋ฐœ์ƒํ•จ
  • ํŒ๋‹จ ๊ธฐ์ค€
    • ํƒ€์ž…/์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๊ฐ€ ๊ณ ์ •๋˜๋Š”๊ฐ€? (ํ•„๋“œ ๋ˆ„๋ฝ/ํƒ€์ž… ์ฐฉ๊ฐ ๋ฐฉ์ง€)
    • ์ปดํฌ๋„ŒํŠธ/์ƒํƒœ/๋ฐ์ดํ„ฐ ๊ณ„์ธต์ด ์—ญํ• ๋ณ„๋กœ ๋ถ„๋ฆฌ๋˜๋Š”๊ฐ€?
    • ํด๋” ๊ตฌ์กฐ/์ฝ”๋”ฉ ๊ทœ์น™์„ ์ผ๊ด€๋˜๊ฒŒ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋Š”๊ฐ€?

(3) ์„ฑ๋Šฅ

  • ์ฑ„ํŒ…(๋ฉ”์‹œ์ง€ ๋ฆฌ์ŠคํŠธ), ๊ฒŒ์‹œํŒ(๋ชฉ๋ก), ์บ˜๋ฆฐ๋”(์›”/์ฃผ ๋ Œ๋”๋ง)๋Š” ๋ Œ๋”๋ง ๋น„์šฉ์ด ์ปค์„œ ์„ฑ๋Šฅ ์ตœ์ ํ™”๊ฐ€ ์ฒด๊ฐ๋จ
  • ํŒ๋‹จ ๊ธฐ์ค€
    • ๋ฌดํ•œ์Šคํฌ๋กค/๊ฐ€์ƒํ™”๋กœ ๊ธด ๋ฆฌ์ŠคํŠธ ๋ Œ๋”๋ง์„ ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ๋Š”๊ฐ€?
    • ๋ฐ์ดํ„ฐ ์บ์‹ฑ/ํ”„๋ฆฌํŒจ์น˜๋กœ ํ™”๋ฉด ์ „ํ™˜ ์ฒด๊ฐ ์†๋„๋ฅผ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋Š”๊ฐ€?
    • ๋ฒˆ๋“ค ๋ถ„๋ฆฌ, ์ด๋ฏธ์ง€ ์ตœ์ ํ™”, SSR/SSG ๋“ฑ ๋ Œ๋”๋ง ์ „๋žต์„ ์ ์šฉํ•˜๊ธฐ ์‰ฌ์šด๊ฐ€?

(4) ์•ˆ์ •์„ฑ/์˜ˆ์ธก ๊ฐ€๋Šฅ์„ฑ

  • ์ฑ„ํŒ…, ์•Œ๋ฆผ, AI ๊ฒฐ๊ณผ ๋ฐ˜์˜์ฒ˜๋Ÿผ ์ƒํƒœ ๋ณ€ํ™”๊ฐ€ ๋งŽ์œผ๋ฉด ๋ฒ„๊ทธ๊ฐ€ ๋Š˜์–ด๋‚จ
  • ํŒ๋‹จ ๊ธฐ์ค€
    • ์ „์—ญ ์ƒํƒœ๊ฐ€ ์–ด๋–ค ๊ธฐ์ค€์œผ๋กœ ์ €์žฅ/๋ณ€๊ฒฝ๋˜๋Š”์ง€ ๋ช…ํ™•ํ•œ๊ฐ€?
    • ์„œ๋ฒ„ ์ƒํƒœ(๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ)์™€ ํด๋ผ์ด์–ธํŠธ ์ƒํƒœ(UI ์ƒํƒœ)๊ฐ€ ์„ž์ด์ง€ ์•Š๊ฒŒ ๋ถ„๋ฆฌ ๊ฐ€๋Šฅํ•œ๊ฐ€?
    • ์—๋Ÿฌ ์ฒ˜๋ฆฌ/๋กœ๋”ฉ ์ฒ˜๋ฆฌ/์žฌ์‹œ๋„ ์ •์ฑ…์„ ์ผ๊ด€๋˜๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๊ฐ€?

๐Ÿ—ฃ๏ธ ์–ธ์–ด

โœ… TypeScript v5.9.3

1. ํŠน์ง• ์š”์•ฝ

  • ์ •์  ํƒ€์ž…
    • ๋ณ€์ˆ˜/ํ•จ์ˆ˜/๊ฐ์ฒด์˜ ํƒ€์ž…์„ ๋ฏธ๋ฆฌ ์ •ํ•ด๋‘๊ณ , ์ฝ”๋“œ ์‹คํ–‰ ์ „ ์ปดํŒŒ์ผ ๋‹จ๊ณ„์—์„œ ํƒ€์ž… ์˜ค๋ฅ˜๋ฅผ ์žก์•„์ค˜์„œ ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ๋ฅผ ์ค„์—ฌ์คŒ
  • ๊ฐ•๋ ฅํ•œ IDE ์ง€์›
    • ํƒ€์ž… ์ •๋ณด ๋•๋ถ„์— ์ž๋™์™„์„ฑ, ์˜คํƒ€ ๊ฐ์ง€, ํ•จ์ˆ˜ ํŒŒ๋ผ๋ฏธํ„ฐ ์•ˆ๋‚ด, ์•ˆ์ „ํ•œ ๋ฆฌํŒฉํ† ๋ง(๋ณ€์ˆ˜๋ช… ๋ณ€๊ฒฝ ๋“ฑ)์ด ํ›จ์”ฌ ์ •ํ™•ํ•ด์ง
  • ์ฝ”๋“œ ๊ฐ€๋…์„ฑ๊ณผ ํ˜‘์—…์— ์œ ๋ฆฌ
  • ๋Œ€๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ์— ๊ฐ•ํ•จ

2. devths์— ์ด ๊ธฐ์ˆ ์ด ํ•„์š”ํ•œ ์ด์œ 

๐Ÿ’ก

Devths๋Š” ํŽ˜์ด์ง€/๊ธฐ๋Šฅ์ด ๋งŽ๊ณ , ๊ธฐ๋Šฅ ๊ฐ„์— ์ฃผ๊ณ ๋ฐ›๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณต์žกํ•ด์ง€๋Š” ์„œ๋น„์Šค๋ผ์„œ TypeScript๊ฐ€ ํŠนํžˆ ํšจ๊ณผ์ ์ด๋ผ๊ณ  ํŒ๋‹จํ•จ

(1) API ์‘๋‹ต/์š”์ฒญ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๊ฐ€ ๋งŽ๊ณ  ๋ณต์žกํ•จ

  • ์œ ์ €(User), ๊ฒŒ์‹œ๊ธ€(Post), ๋Œ“๊ธ€(Comment), ์ฑ„ํŒ… ๋ฉ”์‹œ์ง€(Message), ์•Œ๋ฆผ(Notification), ์บ˜๋ฆฐ๋” ์ด๋ฒคํŠธ(CalendarEvent) ๋“ฑ
  • ๊ฐ ๋ฐ์ดํ„ฐ๋Š” ํ•„๋“œ๊ฐ€ ๋งŽ๊ณ , ํ™”๋ฉด๋งˆ๋‹ค ํ•„์š”ํ•œ ํ•„๋“œ๋„ ๋‹ค๋ฆ„
    • TypeScript๋กœ ํƒ€์ž…์„ ์ •์˜ํ•ด๋‘๋ฉด ํ•„๋“œ ๋ˆ„๋ฝ/์˜คํƒ€/ํƒ€์ž… ์ฐฉ๊ฐ์„ ์ปดํŒŒ์ผ ๋‹จ๊ณ„์—์„œ ์ฐจ๋‹จ ๊ฐ€๋Šฅ

(2) ํผ ์ž…๋ ฅ/๊ฒ€์ฆ๊ณผ์˜ ๊ถํ•ฉ์ด ์ข‹์Œ

  • ๋กœ๊ทธ์ธ/ํšŒ์›๊ฐ€์ž…, ํ”„๋กœํ•„ ์ˆ˜์ •, ๊ฒŒ์‹œ๊ธ€ ์ž‘์„ฑ, ํŒŒ์ผ ์—…๋กœ๋“œ ๋“ฑ ํผ์ด ๋งŽ์Œ
    • ํผ ๋ฐ์ดํ„ฐ ํƒ€์ž…์„ ๋ช…ํ™•ํžˆ ํ•ด๋‘๋ฉด, ์œ ํšจ์„ฑ ๊ฒ€์ฆ๊ณผ ๊ฒฐํ•ฉํ•  ๋•Œ ํด๋ผ์ด์–ธํŠธ์—์„œ ์•ˆ์ •์ ์œผ๋กœ ๋ฐ์ดํ„ฐ ์ •๋ฆฌ ๊ฐ€๋Šฅ

(3) ์‹ค์‹œ๊ฐ„ ๊ธฐ๋Šฅ(์ฑ„ํŒ…)์—์„œ ์ด๋ฒคํŠธ/ํŽ˜์ด๋กœ๋“œ ์•ˆ์ •์„ฑ์ด ์ค‘์š”ํ•จ

  • ์ฑ„ํŒ…์€ ์ด๋ฒคํŠธ๊ฐ€ ๋‹ค์–‘ํ•˜๊ณ (์ „์†ก/์ฝ์Œ/์ž…์žฅ/๋‚˜๊ฐ ๋“ฑ) ํŽ˜์ด๋กœ๋“œ ๊ตฌ์กฐ๊ฐ€ ์กฐ๊ธˆ๋งŒ ๋‹ฌ๋ผ๋„ ๋ฒ„๊ทธ๊ฐ€ ๋‚˜๊ธฐ ์‰ฌ์›€

(4) ํ™”๋ฉด ์ˆ˜๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ๋ณ€๊ฒฝ ์˜ํ–ฅ์ด ์ปค์ง

  • TypeScript๋Š” ์–ด๋””๊ฐ€ ๊นจ์กŒ๋Š”์ง€ ๋ฐ”๋กœ ํ‘œ์‹œํ•ด์ค˜์„œ ์ˆ˜์ • ๋ฒ”์œ„๋ฅผ ๋น ๋ฅด๊ฒŒ ์ฐพ์„ ์ˆ˜ ์žˆ์Œ

(5) ํ˜‘์—…๊ด€์ ์—์„œ ์œ ์šฉ

  • ํƒ€์ž…์ด ๊ณง ๋ฌธ์„œ๊ฐ€ ๋˜๊ธฐ ๋•Œ๋ฌธ์—, ํŒ€์›๋“ค์ด ์ฝ”๋“œ๋ฅผ ๋ณผ๋•Œ ์ด ํ•จ์ˆ˜๋Š” ์–ด๋–ค ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์„œ ์–ด๋–ค ํ˜•ํƒœ๋กœ ๋Œ๋ ค์ฃผ๋Š”์ง€๋ฅผ ๋น ๋ฅด๊ฒŒ ์ดํ•ด ๊ฐ€๋Šฅ
    • ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜ ๋น„์šฉ์ด ์ค„๊ณ  ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์‰ฌ์›Œ์ง

2-1. ์บ˜๋ฆฐ๋”

  • ํ๋ฆ„
    1. ์„œ๋ฒ„(API)์—์„œ ์ผ์ • ๋ชฉ๋ก์„ ๋ฐ›์Œ
    2. ํ”„๋ก ํŠธ์—์„œ ๊ทธ ๋ฐ์ดํ„ฐ๋ฅผ ํ™”๋ฉด(UI) ์ปดํฌ๋„ŒํŠธ์— ๋„ฃ์–ด ๋ Œ๋”๋งํ•จ (FullCalendar)
    3. ํด๋ฆญ/์ˆ˜์ •/์‚ญ์ œ ๊ฐ™์€ ์ด๋ฒคํŠธ๊ฐ€ ๊ณ„์† ๋ฐœ์ƒํ•จ
  • ๋ฌธ์ œ
    • ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๊ฐ€ ํ‹€๋ฆฌ๋ฉด ํ™”๋ฉด์ด ์กฐ์šฉํžˆ ๊นจ์ง
      • ์˜ˆ๋ฅผ ๋“ค๋ฉด startAt์„ start๋กœ ์ž˜๋ชป ์“ฐ๋ฉด:
      • ํ™”๋ฉด์— ์ผ์ •์ด ์•ˆ ๋œจ๊ฑฐ๋‚˜
      • ์ผ์ • ์‹œ๊ฐ„๋Œ€๊ฐ€ ์ด์ƒํ•ด์ง€๊ฑฐ๋‚˜
      • ๋Ÿฐํƒ€์ž„์—์„œ undefined ์—๋Ÿฌ๊ฐ€ ๋‚˜๊ฑฐ๋‚˜

โ‡’ TypeScript ํƒ€์ž…์„ ์žก์•„๋‘ฌ์„œ ์ฝ”๋“œ ์‹คํ–‰ ์ „์— ์‹ค์ˆ˜๋ฅผ ๋ง‰์Œ

2-2. ์ฑ„ํŒ…

  • ํ๋ฆ„
    1. ์‚ฌ์šฉ์ž๊ฐ€ ์ฑ„ํŒ…๋ฐฉ์— ์ž…์žฅ โ†’ ์„œ๋ฒ„์™€ ์‹ค์‹œ๊ฐ„ ์—ฐ๊ฒฐ(Socket.IO)
    2. ๋ฉ”์„ธ์ง€ ์ „์†ก ์‹œ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„๋กœ ์ด๋ฒคํŠธ emit
    3. ์„œ๋ฒ„๊ฐ€ ์ €์žฅ ํ›„, ๊ฐ™์€ ๋ฐฉ ์‚ฌ์šฉ์ž๋“ค์—๊ฒŒ ์ƒˆ ๋ฉ”์‹œ์ง€ ์ด๋ฒคํŠธ broadcast
    4. ํด๋ผ์ด์–ธํŠธ๋Š” ์ˆ˜์‹ ํ•œ ๋ฉ”์‹œ์ง€๋ฅผ ์ƒํƒœ์— ์ถ”๊ฐ€ํ•˜๊ณ  ํ™”๋ฉด์— ๋ Œ๋”๋ง
    5. ์ฝ์Œ ์ฒ˜๋ฆฌ/์ž…์žฅ,ํ‡ด์žฅ/ํŒŒ์ผ ์ฒจ๋ถ€ ๊ฐ™์€ ์ด๋ฒคํŠธ๊ฐ€ ์ถ”๊ฐ€๋กœ ๊ณ„์† ๋ฐœ์ƒ
  • ๋ฌธ์ œ
    • ์‹ค์‹œ๊ฐ„ ๊ธฐ๋Šฅ์€ โ€˜์ด๋ฒคํŠธ ์ด๋ฆ„ + ํŽ˜์ด๋กœ๋“œ ๊ตฌ์กฐโ€™๊ฐ€ ๋งŽ์•„์„œ, ์กฐ๊ธˆ๋งŒ ํ‹€๋ ค๋„ ๋ฒ„๊ทธ ๋ฐœ์ƒ ์‰ฌ์›€

โ‡’ TypeScript๋กœ ๋ฉ”์‹œ์ง€ ํƒ€์ž…/๋ฃธ ํƒ€์ž…/์†Œ์ผ“ ์ด๋ฒคํŠธ ํƒ€์ž…์„ ๊ณ ์ •ํ•ด์„œ ๋ณด๋‚ด๋Š” ๋ฐ์ดํ„ฐ/๋ฐ›๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ”๋“œ ์‹คํ–‰ ์ „์— ๊ฒ€์ฆํ•˜๊ณ  ์‹ค์‹œ๊ฐ„ ๋ฒ„๊ทธ๋ฅผ ์ค„์ž„

3. ๋‹ค๋ฅธ ์Šคํƒ๊ณผ ๋น„๊ต

ํ•ญ๋ชฉ JavaScript TypeScript
ํƒ€์ž… ๊ฒ€์‚ฌ ์‹œ์  ์‹คํ–‰ ์ค‘ (๋Ÿฐํƒ€์ž„) ์ปดํŒŒ์ผ ๋‹จ๊ณ„
ํƒ€์ž… ์•ˆ์ „์„ฑ ๋‚ฎ์Œ ๋†’์Œ
๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ ๋ฐœ์ƒ ๊ฐ€๋Šฅ์„ฑ ๋†’์Œ ์‚ฌ์ „ ๋ฐฉ์ง€ ๊ฐ€๋Šฅ
์ž๋™์™„์„ฑ / IDE ์ง€์› ์ œํ•œ์  ๋งค์šฐ ๊ฐ•๋ ฅ
๋ฆฌํŒฉํ† ๋ง ์•ˆ์ •์„ฑ ๊ทœ๋ชจ ์ปค์งˆ์ˆ˜๋ก ์œ„ํ—˜ ๋ณ€๊ฒฝ ์˜ํ–ฅ ์ฆ‰์‹œ ํ™•์ธ ๊ฐ€๋Šฅ
ํ˜‘์—… ํšจ์œจ ์ฃผ์„, ๋ฌธ์„œ ์˜์กด ํƒ€์ž… ์ž์ฒด๊ฐ€ ๋ฌธ์„œ ์—ญํ• 
๋Œ€๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ ์ ํ•ฉ์„ฑ ๋‚ฎ์Œ ๋†’์Œ
  • ํƒ€์ž… ๊ฒ€์‚ฌ ์‹œ์ ๊ณผ ์•ˆ์ •์„ฑ

    • JS๋Š” ํƒ€์ž… ๊ฒ€์‚ฌ๊ฐ€ ์ฝ”๋“œ ์‹คํ–‰ ์ค‘(๋Ÿฐํƒ€์ž„)์—๋งŒ ์ด๋ฃจ์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์—, ์ž˜๋ชป๋œ ๊ฐ’์ด๋‚˜ ๊ตฌ์กฐ๊ฐ€ ์žˆ์–ด๋„ ์‹ค์ œ๋กœ ์‹คํ–‰ํ•ด ๋ณด๊ธฐ ์ „๊นŒ์ง€๋Š” ์˜ค๋ฅ˜๋ฅผ ์•Œ๊ธฐ ์–ด๋ ค์›€. ๊ทธ ๊ฒฐ๊ณผ ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์ƒ๋Œ€์ ์œผ๋กœ ๋†’์Œ

      โ†”๏ธ TS๋Š” ์ปดํŒŒ์ผ ๋‹จ๊ณ„์—์„œ ํƒ€์ž…์„ ๊ฒ€์‚ฌํ•ด ์ž˜๋ชป๋œ ์‚ฌ์šฉ์„ ๋ฏธ๋ฆฌ ์ฐจ๋‹จํ•˜๋ฏ€๋กœ, ์‹คํ–‰ ์ค‘์— ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฅ˜๋ฅผ ์‚ฌ์ „์— ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Œ

  • IDE ์ง€์› ๋ฐ ๊ฐœ๋ฐœ ํšจ์œจ

    • JS๋Š” ๊ฐ์ฒด ๊ตฌ์กฐ๋‚˜ ํ•จ์ˆ˜์˜ ์ž…์ถœ๋ ฅ์„ IDE๊ฐ€ ์ •ํ™•ํžˆ ์•Œ๊ธฐ ์–ด๋ ค์›Œ ์ž๋™์™„์„ฑ์ด ์ œํ•œ์ ์ธ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Œ

      โ†”๏ธ TS๋Š” ํƒ€์ž… ์ •๋ณด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ IDE๊ฐ€ ์ •ํ™•ํ•œ ์ž๋™์™„์„ฑ๊ณผ ์˜ค๋ฅ˜ ์•ˆ๋‚ด๋ฅผ ์ œ๊ณตํ•ด ๊ฐœ๋ฐœ ํšจ์œจ์„ ํฌ๊ฒŒ ๋†’์—ฌ์คŒ.

  • ๋ฆฌํŒฉํ† ๋ง ์•ˆ์ •์„ฑ

    • JS๋Š” ๋ฆฌํŒฉํ† ๋ง ๊ณผ์ •์—์„œ ํ”„๋กœ์ ํŠธ ๊ทœ๋ชจ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก ๋ณ€๊ฒฝ ์˜ํ–ฅ ๋ฒ”์œ„๋ฅผ ํŒŒ์•…ํ•˜๊ธฐ ์–ด๋ ค์›Œ ์œ„ํ—˜์ด ์ปค์ง

      โ†”๏ธ TS๋Š” ํƒ€์ž… ์˜ค๋ฅ˜๋ฅผ ํ†ตํ•ด ์ˆ˜์ •์ด ํ•„์š”ํ•œ ์ง€์ ์„ ์ฆ‰์‹œ ์•Œ๋ ค์ค˜ ๋น„๊ต์  ์•ˆ์ „ํ•˜๊ฒŒ ๊ตฌ์กฐ ๋ณ€๊ฒฝ์„ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ์Œ

  • ํ˜‘์—… ๋ฐ ์ฝ”๋“œ ๊ฐ€๋…์„ฑ

    • JS๋Š” ํ˜‘์—…ํ•  ๋•Œ ์ฃผ์„์ด๋‚˜ ๋ณ„๋„์˜ ๋ฌธ์„œ์— ์˜์กดํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Œ

      โ†”๏ธ TS๋Š” ํƒ€์ž… ์ •์˜ ์ž์ฒด๊ฐ€ ์ฝ”๋“œ์˜ ์„ค๋ช…์„œ ์—ญํ• ์„ ํ•˜์—ฌ ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ํ›จ์”ฌ ์ˆ˜์›”ํ•จ

4. ๋ฒ„์ „ ์„ ํƒ ์ด์œ 

  • TypeScript v5.9.3
    • 2025๋…„ 10์›” 1์ผ์— GitHub๋ฅผ ํ†ตํ•ด ๋ฆด๋ฆฌ์ฆˆ๋จ
  • ํŠน๋ณ„ํ•˜๊ฒŒ 5.9.3 ๋ฒ„์ „์„ ์„ ํƒํ•œ ์ด์œ 
    • Next.js, React ๋“ฑ ์ฃผ์š” ํ”„๋ก ํŠธ์—”๋“œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ƒํƒœ๊ณ„์—์„œ TypeScript 5.x ๋ผ์ธ์ด ์•ˆ์ •์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์–ด, ํ”„๋ ˆ์ž„์›Œํฌ ๋ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ฐ„ ์ถฉ๋Œ ์œ„ํ—˜์ด ๋‚ฎ๋‹ค๊ณ  ํŒ๋‹จํ•จ
    • TypeScript๋Š” ๋™์ผ ๋ฉ”์ด์ € ๋ฒ„์ „(5.x)์„ ์œ ์ง€ํ•˜๋Š” ๋ฒ”์œ„ ๋‚ด์—์„œ, ๋ฒ„๊ทธ ์ˆ˜์ •๊ณผ ์•ˆ์ •์„ฑ ๊ฐœ์„ ์ด ๋ฐ˜์˜๋œ ํŒจ์น˜ ๋ฒ„์ „(v5.9.3)์„ ์„ ํƒํ•จ
    • v5.9.3์€ ๊ธฐ์กด ๋ฌธ๋ฒ•๊ณผ ํƒ€์ž… ์‹œ์Šคํ…œ์˜ ๋™์ž‘์„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์œผ๋ฉด์„œ, ์ปดํŒŒ์ผ ์•ˆ์ •์„ฑ๊ณผ IDE ์—ฐ๋™ ํ’ˆ์งˆ ๊ฐœ์„ ์ด ๋ฐ˜์˜๋œ ๋ฒ„์ „์œผ๋กœ ํ‰๊ฐ€๋จ

5. ๊ฒฐ๋ก 

  • Devths๋Š” ์บ˜๋ฆฐ๋”, ๊ฒŒ์‹œํŒ, ์ฑ„ํŒ…, AI์ฑ—๋ด‡์ฒ˜๋Ÿผ ํ™”๋ฉด๊ณผ ๊ธฐ๋Šฅ์ด ๋งŽ๊ณ , ๊ธฐ๋Šฅ ๊ฐ„์— ์ฃผ๊ณ ๋ฐ›๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณต์žกํ•œ ์„œ๋น„์Šค์ž„
  • ๋”ฐ๋ผ์„œ TypeScript๋ฅผ ์ ์šฉํ•ด
    • API ๊ณ„์•ฝ(์š”์ฒญ/์‘๋‹ต)๊ณผ ๋„๋ฉ”์ธ ๋ชจ๋ธ(User/Post/Message/Event ๋“ฑ)์„ ํƒ€์ž…์œผ๋กœ ๊ณ ์ •ํ•˜๊ณ ,
    • ํผ ์ž…๋ ฅ/๊ฒ€์ฆ ๋กœ์ง์„ ํƒ€์ž… ๊ธฐ๋ฐ˜์œผ๋กœ ์•ˆ์ •ํ™”ํ•˜๋ฉฐ,
    • ์‹ค์‹œ๊ฐ„ ์ฑ„ํŒ…์˜ ์ด๋ฒคํŠธ/ํŽ˜์ด๋กœ๋“œ๋ฅผ ํƒ€์ž…์œผ๋กœ ๊ฐ•์ œํ•ด ์˜คํƒ€, ๋ˆ„๋ฝ, ํ˜•์‹ ๋ถˆ์ผ์น˜๋กœ ์ธํ•œ ๋ฒ„๊ทธ๋ฅผ ์ปดํŒŒ์ผ ๋‹จ๊ณ„์—์„œ ์ฐจ๋‹จํ•จ
  • ๊ฒฐ๊ณผ์ ์œผ๋กœ TypeScript๋Š” Devths์—์„œ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๋ฅผ ์ค„์ด๊ณ , ๋ณ€๊ฒฝ์— ๊ฐ•ํ•œ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค๋ฉฐ, ํ˜‘์—… ์†๋„์™€ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ๋†’์ด๋Š” ๊ธฐ์ˆ ๋กœ์„œ ์ฑ„ํƒ ๊ฐ€์น˜๊ฐ€ ํผ

๐Ÿ“š ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

โœ… React v19.2

1. ํŠน์ง• ์š”์•ฝ

  • ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜ UI ๊ฐœ๋ฐœ
    • ํ™”๋ฉด์„ Header/๋ฒ„ํŠผ/์นด๋“œ/๋ฆฌ์ŠคํŠธ ๊ฐ™์€ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ปดํฌ๋„ŒํŠธ๋กœ ๋‚˜๋ˆ  ์กฐ๋ฆฝํ•˜๋“ฏ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์–ด, ๊ธฐ๋Šฅ์ด ๋งŽ๊ณ  ํ™”๋ฉด์ด ๋งŽ์€ ์„œ๋น„์Šค์—์„œ ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์‰ฌ์›€
  • ์ปดํฌ๋„ŒํŠธ ์žฌ์‚ฌ์šฉ์„ ํ†ตํ•œ ์ƒ์‚ฐ์„ฑ
    • ๋ฒ„ํŠผ/๋ชจ๋‹ฌ/์ž…๋ ฅํผ ๊ฐ™์€ ๊ณตํ†ต UI๋ฅผ ํ•œ ๋ฒˆ ๋งŒ๋“ค์–ด๋‘๋ฉด ์—ฌ๋Ÿฌ ํŽ˜์ด์ง€์—์„œ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ด์„œ ๊ฐœ๋ฐœ ์†๋„์™€ ์ผ๊ด€์„ฑ์ด ๋†’์•„์ง
  • ์ƒํƒœ ๊ธฐ๋ฐ˜ ๋ Œ๋”๋ง
    • ์‚ฌ์šฉ์ž ์ž…๋ ฅ, API ์‘๋‹ต, ์‹ค์‹œ๊ฐ„ ๋ฉ”์‹œ์ง€์ฒ˜๋Ÿผ ๊ณ„์† ๋ณ€ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ state๋กœ ๊ด€๋ฆฌํ•˜๊ณ , ๊ทธ ๋ณ€ํ™”๊ฐ€ ๊ณง ํ™”๋ฉด ์—…๋ฐ์ดํŠธ๋กœ ์—ฐ๊ฒฐ๋จ
  • ํ’๋ถ€ํ•œ ์ƒํƒœ๊ณ„
    • ๋ผ์šฐํŒ…(React Router), ๋ฐ์ดํ„ฐ ํŒจ์นญ(React Query), ํผ(React Hook Form), ์ƒํƒœ๊ด€๋ฆฌ(Zustand) ๋“ฑ๊ณผ ์กฐํ•ฉ์ด ์‰ฌ์›Œ ๊ธฐ๋Šฅ ํ™•์žฅ ๋น ๋ฆ„

2. Devths์— ์ด ๊ธฐ์ˆ ์ด ํ•„์š”ํ•œ ์ด์œ 

๐Ÿ’ก

Devths๋Š” ํŽ˜์ด์ง€/์ธํ„ฐ๋ž™์…˜์ด ๋งŽ๊ณ  ๋ฐ์ดํ„ฐ๊ฐ€ ๊ณ„์† ๋ฐ”๋€Œ๋Š” ์„œ๋น„์Šค๋ผ์„œ, React ์ปดํฌ๋„ŒํŠธ/์ƒํƒœ ๊ธฐ๋ฐ˜ UI ๋ฐฉ์‹์ด ๋งž์Œ

(1) ๊ธฐ๋Šฅ๋ณ„ ํ™”๋ฉด์ด ๋งŽ์•„๋„ ์ปดํฌ๋„ŒํŠธ๋กœ ์ชผ๊ฐœ์„œ ๊ด€๋ฆฌ ๊ฐ€๋Šฅ

  • Devths๋Š” ์บ˜๋ฆฐ๋”, ๊ฒŒ์‹œํŒ, ์ฑ—๋ด‡, ์ฑ„ํŒ…์ฒ˜๋Ÿผ ๋„๋ฉ”์ธ์ด ๋‹ค๋ฅธ ํ™”๋ฉด์ด ์—ฌ๋Ÿฌ ๊ฐœ ์žˆ์Œ
  • React๋Š” ํ™”๋ฉด์„ ์ž‘์€ ๋ถ€ํ’ˆ์œผ๋กœ ์ชผ๊ฐœ์„œ ์žฌ์‚ฌ์šฉ/์กฐ๋ฆฝํ•˜๋Š” ๊ตฌ์กฐ๋ผ์„œ ์œ ์ง€๋ณด์ˆ˜์— ๊ฐ•ํ•จ
  • ์ปดํฌ๋„ŒํŠธ๋Š” 2-2์— ์ž‘์„ฑ

โ‡’ ์ด๋ ‡๊ฒŒ ๋‚˜๋ˆ„๋ฉด ๊ธฐ๋Šฅ์ด ๋Š˜์–ด๋‚˜๋„ ์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„๋กœ ์ˆ˜์ •ํ•˜๋ฉด ๋ผ์„œ ์ฝ”๋“œ ๋œ ๋ง๊ฐ€์ง

(2) ์ƒํƒœ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ํ™”๋ฉด์ด ์ž๋™์œผ๋กœ ๋”ฐ๋ผ์˜ค๋Š” ๊ตฌ์กฐ๊ฐ€ ํ•„์š”ํ•จ

  • Devths๋Š” ์ƒํƒœ ๋ณ€ํ™”๊ฐ€ ๋งŽ์€ ์„œ๋น„์Šค
    • ์บ˜๋ฆฐ๋”: ์ผ์ • ์ถ”๊ฐ€/์ˆ˜์ •/์‚ญ์ œ โ†’ ์ฆ‰์‹œ ํ™”๋ฉด ๋ฐ˜์˜
    • ๊ฒŒ์‹œํŒ: ๋ฌดํ•œ์Šคํฌ๋กค๋กœ ๊ธ€ ๊ณ„์† ์ถ”๊ฐ€ โ†’ ๋ฆฌ์ŠคํŠธ UI ๊ฐฑ์‹ 
    • ์ฑ—๋ด‡: ๋‹ต๋ณ€ ์ŠคํŠธ๋ฆฌ๋ฐ/๋Œ€ํ™” ๋ˆ„์  โ†’ ๋ฉ”์‹œ์ง€ UI๊ฐ€ ๊ณ„์† ๋Š˜์–ด๋‚จ
    • ์ฑ„ํŒ…: ์‹ค์‹œ๊ฐ„ ์ˆ˜์‹  ๋ฉ”์‹œ์ง€ โ†’ ํ™”๋ฉด์— ๋ฐ”๋กœ ์ถ”๊ฐ€ + ์Šคํฌ๋กค ์ฒ˜๋ฆฌ

โ‡’ Zustand๋งŒ ์ž˜ํ•˜๋ฉด DOM์„ ์ง์ ‘ ๋งŒ์ง€์ง€ ์•Š์•„๋„ UI๊ฐ€ ์ž๋™ ๊ฐฑ์‹ ๋จ

(3) ์„ฑ๋Šฅ ์ตœ์ ํ™” ํฌ์ธํŠธ๊ฐ€ ๋งŽ์€ ํ™”๋ฉด์— ์œ ๋ฆฌํ•จ

  • Devths๋Š” ๋ฆฌ์ŠคํŠธ๊ฐ€ ๊ธด UI๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ์ž„
    • ๊ฒŒ์‹œํŒ ๊ธ€ ๋ชฉ๋ก (๋ฌดํ•œ ์Šคํฌ๋กค)
    • ์ฑ„ํŒ… ๋ฉ”์‹œ์ง€
    • ์บ˜๋ฆฐ๋” ์ด๋ฒคํŠธ
  • React๋Š” ๋ฆฌ์ŠคํŠธ๋ฅผ ์ปดํฌ๋„ŒํŠธ๋กœ ๊ด€๋ฆฌํ•˜๋ฉด์„œ
    • ๊ฐ€์ƒ ์Šคํฌ๋กค(react-window)
    • ๋ฉ”๋ชจ์ด์ œ์ด์…˜(useMemo, memo)
    • ํ‚ค ๊ธฐ๋ฐ˜ ๋ Œ๋”๋ง ์ตœ์ ํ™”

โ‡’ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ํ”„๋ก ํŠธ ์„ฑ๋Šฅ์„ ๋‹จ๊ณ„์ ์œผ๋กœ ๊ฐœ์„ ํ•˜๊ธฐ ์ข‹์Œ

2-1. ์ธํ„ฐ๋ž™์…˜

  • ์บ˜๋ฆฐ๋”
    • ์›”/์ฃผ ๋ทฐ ์ „ํ™˜
    • ์ผ์ • (๋‚ ์งœ ํด๋ฆญ์‹œ ์ „์ฒด โ†’ ์ผ) ๋ทฐ ์ „ํ™˜
    • ์ฑ„์šฉ๊ณต๊ณ  OCR
      • ํ…์ŠคํŠธ/์ด๋ฏธ์ง€ ์—…๋กœ๋“œ
      • ๊ฒฐ๊ณผ ์ดˆ์•ˆ ํ™•์ธ/์ˆ˜์ • ํ›„ ์ €์žฅ
      • ์‹คํŒจ ์‹œ ์žฌ์‹œ๋„/์ˆ˜๋™ ์ž…๋ ฅ ์ „ํ™˜
  • ๊ฒŒ์‹œํŒ
    • ๋ฌดํ•œ ์Šคํฌ๋กค
    • ๊ฒ€์ƒ‰/ํ•„ํ„ฐ/์ •๋ ฌ ๋ณ€๊ฒฝ
    • ๊ฒŒ์‹œ๊ธ€ ์นด๋“œ ํด๋ฆญ โ†’ ์ƒ์„ธ ์ง„์ž…
    • ์ข‹์•„์š” ํ† ๊ธ€ (์ฆ‰์‹œ UI ๋ฐ˜์˜)
    • ๋Œ“๊ธ€ ์ž‘์„ฑ/์ˆ˜์ • ์‚ญ์ œ
    • ์ข‹์•„์š”/๊ณต์œ 
    • ๊ฒŒ์‹œ๊ธ€ ์ž‘์„ฑ(ํผ ์ž…๋ ฅ โ†’ ์ œ๋ชฉ/๋ณธ๋ฌธ/ํƒœ๊ทธ)
    • ์ด๋ฏธ์ง€/ํŒŒ์ผ ์ฒจ๋ถ€
  • ์ฑ—๋ด‡/AI
    • ์ฑ„ํŒ… ๋ชฉ๋ก/๋Œ€ํ™” ์‹œ์ž‘ ํŽ˜์ด์ง€
    • AI๊ฐ€ ์ƒ์„ฑํ•œ ๋‹ต๋ณ€ ๋ณด๊ธฐ
    • ๋ฉด์ ‘๋ชจ๋“œ ํ† ๊ธ€
    • ๋ฉ”์‹œ์ง€ ์ž…๋ ฅ/์ „์†ก
    • ๋‹ต๋ณ€ ์ŠคํŠธ๋ฆฌ๋ฐ
    • ๋Œ€ํ™” ์ด๋ ฅ ์Šคํฌ๋กค/๋กœ๋“œ
  • ์ฑ„ํŒ…
    • ๋ฐฉ ์„ ํƒ โ†’ ๋ฐฉ ์ง„์ž…
    • ์ƒˆ ๋ฐฉ ๋งŒ๋“ค๊ธฐ
    • ๊ฒ€์ƒ‰
    • ๋ฉ”์‹œ์ง€ ์ „์†ก/์ˆ˜์‹ 
    • ๊ณผ๊ฑฐ ๋ฉ”์‹œ์ง€ ๋กœ๋”ฉ
    • ์ฝ์Œ ์ฒ˜๋ฆฌ. ์ž…/ํ‡ด์žฅ ํ‘œ์‹œ
    • ํŒŒ์ผ/์ด๋ฏธ์ง€ ์ฒจ๋ถ€

2-2. ์ปดํฌ๋„ŒํŠธ

  • ์บ˜๋ฆฐ๋”
    • CalendarToolbar
      • ์บ˜๋ฆฐ๋” ์ƒ๋‹จ ์ปจํŠธ๋กค ์˜์—ญ(์›”/์ฃผ ๋ทฐ ์ „ํ™˜, ์ด์ „/๋‹ค์Œ, ์˜ค๋Š˜ ๋ฒ„ํŠผ, ์ฑ„์šฉ ๊ณต๊ณ ๋กœ ์ผ์ • ๋งŒ๋“ค๊ธฐ ๋ฒ„ํŠผ)
    • EventModal
      • ์ผ์ • ์ƒ์„ฑ/์ˆ˜์ •/์‚ญ์ œ๋ฅผ ์œ„ํ•œ ํผ ๋ชจ๋‹ฌ
      • ์ œ๋ชฉ/์‹œ๊ฐ„/์ข…์ผ/์žฅ์†Œ/๋ฉ”๋ชจ ์ž…๋ ฅ + ์œ ํšจ์„ฑ ๊ฒ€์ฆ + ์ €์žฅ/์‚ญ์ œ API ํ˜ธ์ถœ ์—ฐ๊ฒฐ
    • EventCard
      • ์ผ์ • ๋ฆฌ์ŠคํŠธ/์ƒ์„ธ์—์„œ ์ผ์ • ํ•œ ๊ฐœ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ์นด๋“œ(UI)
      • ์ œ๋ชฉ/์‹œ๊ฐ„/์žฅ์†Œ/ํƒœ๊ทธ/์ƒ‰์ƒ ํ‘œ์‹œ, ํด๋ฆญ ์‹œ ์ƒ์„ธ/์ˆ˜์ • ๋ชจ๋‹ฌ ์˜คํ”ˆ ํŠธ๋ฆฌ๊ฑฐ
    • OcrUploadModal
      • ์ฑ„์šฉ๊ณต๊ณ (PDF/์ด๋ฏธ์ง€) ์—…๋กœ๋“œ ๋ชจ๋‹ฌ
      • ํŒŒ์ผ ์„ ํƒ โ†’ ์—…๋กœ๋“œ ์š”์ฒญ โ†’ โ€œ์ฒ˜๋ฆฌ ์ค‘(๋Œ€๊ธฐ)โ€ ์ƒํƒœ ํ‘œ์‹œ โ†’ ๊ฒฐ๊ณผ(draft) ๋„์ฐฉ ์‹œ ๊ฒ€ํ†  ํ™”๋ฉด์œผ๋กœ ์—ฐ๊ฒฐ
  • ๊ฒŒ์‹œํŒ
    • PostList
      • ๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก์„ ๋ Œ๋”๋งํ•˜๋Š” ๋ฆฌ์ŠคํŠธ ์ปดํฌ๋„ŒํŠธ
      • ๋ฌดํ•œ์Šคํฌ๋กค ํŠธ๋ฆฌ๊ฑฐ, ๋กœ๋”ฉ/์—๋Ÿฌ/๋นˆ ์ƒํƒœ ์ฒ˜๋ฆฌ
    • PostCard
      • ๋ชฉ๋ก์—์„œ ๊ฒŒ์‹œ๊ธ€ 1๊ฐœ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ์นด๋“œ(UI)
      • ์ œ๋ชฉ/์š”์•ฝ/์ž‘์„ฑ์ž/์ž‘์„ฑ์ผ/์ข‹์•„์š”/๋Œ“๊ธ€ ์ˆ˜/๊ณต์œ  ์ˆ˜, ํด๋ฆญ ์‹œ ์ƒ์„ธ ์ด๋™
    • CommentList
      • ๋Œ“๊ธ€ ๋ชฉ๋ก + ๋Œ“๊ธ€ ์ž‘์„ฑ ์ž…๋ ฅ์„ ํฌํ•จํ•œ ์˜์—ญ
      • ๋Œ“๊ธ€ ์ถ”๊ฐ€/์ˆ˜์ •/์‚ญ์ œ ํ›„ ๋ฆฌ์ŠคํŠธ ์ฆ‰์‹œ ๊ฐฑ์‹ , ๋‚™๊ด€์  ์—…๋ฐ์ดํŠธ
    • LikeButton
      • ์ข‹์•„์š” ํ† ๊ธ€ ๋ฒ„ํŠผ(ํ™œ์„ฑ/๋น„ํ™œ์„ฑ UI)
      • ํด๋ฆญ ์‹œ ์ข‹์•„์š” API ํ˜ธ์ถœ + ์ฆ‰์‹œ UI ๋ฐ˜์˜(๋‚™๊ด€์  ์—…๋ฐ์ดํŠธ) + ์‹คํŒจ ์‹œ ๋กค๋ฐฑ ์ฒ˜๋ฆฌ
    • SearchFilter
      • ๊ฒ€์ƒ‰์–ด ์ž…๋ ฅ + ์ •๋ ฌ(์ตœ์‹ ์ˆœ) ์ปจํŠธ๋กค
      • ๋ณ€๊ฒฝ ์‹œ ๋ชฉ๋ก ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐฑ์‹  โ†’ PostList ์žฌ์กฐํšŒ ํŠธ๋ฆฌ๊ฑฐ
  • ์ฑ„ํŒ…
    • RoomList
      • ์‚ฌ์šฉ์ž๊ฐ€ ์ฐธ์—ฌํ•œ ์ฑ„ํŒ…๋ฐฉ ๋ชฉ๋ก(์ตœ๊ทผ ๋ฉ”์‹œ์ง€, ์•ˆ์ฝ์Œ ๋ฑƒ์ง€ ํฌํ•จ)
      • ๋ฐฉ ์„ ํƒ/๊ฒ€์ƒ‰/์ •๋ ฌ, ์„ ํƒ ์‹œ ํ•ด๋‹น ๋ฐฉ์œผ๋กœ ๋ผ์šฐํŒ… ๋˜๋Š” ์ƒํƒœ ๋ณ€๊ฒฝ
    • MessageList
      • ํŠน์ • ๋ฐฉ์˜ ๋ฉ”์‹œ์ง€ ๋ชฉ๋ก์„ ๋ Œ๋”๋ง(์Šคํฌ๋กค ์˜์—ญ)
      • ์ƒˆ ๋ฉ”์‹œ์ง€ ์ˆ˜์‹  ์‹œ ์ƒ๋‹จ ์ถ”๊ฐ€ + ์ž๋™ ์Šคํฌ๋กค, ํ•˜๋‹จ ์Šคํฌ๋กค ์‹œ ๊ณผ๊ฑฐ ๋ฉ”์‹œ์ง€ ๋กœ๋”ฉ(๋ฌดํ•œ์Šคํฌ๋กค)
    • MessageBubble
      • ๋ฉ”์‹œ์ง€ 1๊ฐœ์˜ ๋งํ’์„  UI(๋‚ด ๋ฉ”์‹œ์ง€/์ƒ๋Œ€ ๋ฉ”์‹œ์ง€ ๊ตฌ๋ถ„)
      • ์‹œ๊ฐ„/ํ”„๋กœํ•„/์ฝ์Œ ์ƒํƒœ ํ‘œ์‹œ
    • ChatInput
      • ๋ฉ”์‹œ์ง€ ์ž…๋ ฅ์ฐฝ + ์ „์†ก ๋ฒ„ํŠผ + ์ฒจ๋ถ€ ๋ฒ„ํŠผ
      • ์—”ํ„ฐ ์ „์†ก, ์ „์†ก ์ค‘ ๋น„ํ™œ์„ฑํ™”
  • ๊ณตํ†ต
    • Header
      • ์ƒ๋‹จ ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ”(๋กœ๊ณ /ํŽ˜์ด์ง€ ํƒ€์ดํ‹€/์•Œ๋ฆผ/ํ”„๋กœํ•„ ๋ฉ”๋‰ด)
    • Modal
      • ๊ณตํ†ต ๋ชจ๋‹ฌ UI(์˜ค๋ฒ„๋ ˆ์ด, ESC/๋ฐ”๊นฅ ํด๋ฆญ ๋‹ซ๊ธฐ, ํฌ์ปค์Šค ํŠธ๋žฉ ๋“ฑ)
    • Toast
      • ์„ฑ๊ณต/์‹คํŒจ/๊ฒฝ๊ณ  ์•Œ๋ฆผ์„ ์งง๊ฒŒ ๋ณด์—ฌ์ฃผ๋Š” ์ปดํฌ๋„ŒํŠธ
      • โ€œ์ผ์ •์ด ์ €์žฅ๋์–ด์š”โ€, โ€œ์—…๋กœ๋“œ ์‹คํŒจ, ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”โ€
    • Avatar
      • ์‚ฌ์šฉ์ž ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ํ‘œ์‹œ(์—†์œผ๋ฉด ์ด๋‹ˆ์…œ/๊ธฐ๋ณธ ์•„์ด์ฝ˜)
      • ํฌ๊ธฐ/๋ชจ์–‘ ์˜ต์…˜ ์ œ๊ณต, ํด๋ฆญ ์‹œ ํ”„๋กœํ•„ ๋ฉ”๋‰ด ํŠธ๋ฆฌ๊ฑฐ

3. ๋‹ค๋ฅธ ์Šคํƒ๊ณผ์˜ ๋น„๊ต ํ‘œ

ํ•ญ๋ชฉ React Vanilla JS Vue
UI ๊ตฌ์„ฑ ๋ฐฉ์‹ ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜ DOM ์ง์ ‘ ์กฐ์ž‘ ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜
์ƒํƒœ ๊ด€๋ฆฌ ์ƒํƒœ(State) ์ค‘์‹ฌ ์ง์ ‘ ์ƒํƒœ ๊ด€๋ฆฌ ํ•„์š” ์ƒํƒœ ์ค‘์‹ฌ
UI ๋ณต์žก๋„ ๋Œ€์‘ ๋†’์Œ ๋ณต์žกํ•ด์งˆ์ˆ˜๋ก ์–ด๋ ค์›€ ๋†’์Œ
์ƒํƒœ๊ณ„/ํ™•์žฅ์„ฑ ๋งค์šฐ ํ’๋ถ€ ์ œํ•œ์  ํ’๋ถ€
๋Œ€๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ ์ ํ•ฉ์„ฑ ๋†’์Œ ๋‚ฎ์Œ ๋†’์Œ
  • UI ๊ตฌ์กฐ ๋ฐ ๋ณต์žก๋„ ๊ด€๋ฆฌ

    • Vanilla JS๋Š” DOM์„ ์ง์ ‘ ์กฐ์ž‘ํ•˜๋Š” ๋ฐฉ์‹์ด๊ธฐ ๋•Œ๋ฌธ์—, ํ™”๋ฉด ์ƒํƒœ๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก DOM ์กฐ์ž‘ ์ฝ”๋“œ์™€ ์ƒํƒœ ๊ด€๋ฆฌ ๋กœ์ง์ด ์„œ๋กœ ์–ฝํ˜€ ๊ตฌ์กฐ๊ฐ€ ๋น ๋ฅด๊ฒŒ ๋ณต์žกํ•ด์ง. โ†’ ํ™”๋ฉด ์ˆ˜์™€ ๊ธฐ๋Šฅ์ด ์ฆ๊ฐ€ํ• ์ˆ˜๋ก ์œ ์ง€๋ณด์ˆ˜ ๋น„์šฉ์ด ์ปค์งˆ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Œ

      โ†”๏ธ React๋Š” ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜ ๊ตฌ์กฐ์™€ ์ƒํƒœ ์ค‘์‹ฌ(State) UI ๋ชจ๋ธ์„ ์ œ๊ณตํ•˜์—ฌ, ํ™”๋ฉด๊ณผ ๋กœ์ง์„ ๊ธฐ๋Šฅ ๋‹จ์œ„๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด UI ๋ณต์žก๋„๊ฐ€ ๋†’์€ ์„œ๋น„์Šค์— ๋” ์ ํ•ฉํ•จ

  • ์ƒํƒœ ๊ด€๋ฆฌ ๋ฐฉ์‹๊ณผ UI ์—…๋ฐ์ดํŠธ ํ๋ฆ„

    • Vanilla JS๋Š” ์ƒํƒœ ๊ด€๋ฆฌ์™€ UI ์—…๋ฐ์ดํŠธ ํ๋ฆ„์„ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์„ค๊ณ„ํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ๋ฌดํ•œ ์Šคํฌ๋กค, ๋ชจ๋‹ฌ ์—ด๋ฆผ/๋‹ซํž˜, ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ๋ฐ˜์˜๊ณผ ๊ฐ™์€ ์š”๊ตฌ์‚ฌํ•ญ์ด ๋งŽ์•„์งˆ์ˆ˜๋ก ๊ตฌํ˜„ ๋ฐฉ์‹์ด ํ™”๋ฉด๋งˆ๋‹ค ๋‹ฌ๋ผ์งˆ ์œ„ํ—˜์ด ์žˆ์Œ

      โ†”๏ธ React๋Š” ์ƒํƒœ ๋ณ€ํ™”์— ๋”ฐ๋ผ UI๊ฐ€ ์ž๋™์œผ๋กœ ๊ฐฑ์‹ ๋˜๋Š” ์„ ์–ธํ˜• ๋ฐฉ์‹์œผ๋กœ, ์ƒํƒœ์™€ UI ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Œ

  • ํ”„๋ ˆ์ž„์›Œํฌ, ์ƒํƒœ๊ณ„ ์—ฐ๊ณ„์„ฑ

    • Vue ์—ญ์‹œ ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜ ๊ตฌ์กฐ์™€ ์ƒํƒœ ์ค‘์‹ฌ UI๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฐ•๋ ฅํ•œ ํ”„๋ ˆ์ž„์›Œํฌ์ด์ง€๋งŒ, devths๋Š” Next.js ๊ธฐ๋ฐ˜ ๊ตฌ์กฐ์™€์˜ ๊ถํ•ฉ, React ์ƒํƒœ๊ณ„(์ƒํƒœ ๊ด€๋ฆฌ, ์„œ๋ฒ„ ์ƒํƒœ ๊ด€๋ฆฌ, UI ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋“ฑ)๋ฅผ ํญ๋„“๊ฒŒ ํ™œ์šฉํ•  ํ•„์š”๊ฐ€ ์žˆ๋Š” ํ”„๋กœ์ ํŠธ์ž„

      โ†”๏ธ React๋Š” Next.js๋ฅผ ๋น„๋กฏํ•œ ํ”„๋ ˆ์ž„์›Œํฌ ๋ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ƒํƒœ๊ณ„์™€์˜ ์—ฐ๊ณ„์„ฑ์ด ๋†’์•„,์žฅ๊ธฐ์ ์ธ ํ™•์žฅ์„ฑ๊ณผ ๊ธฐ์ˆ  ์Šคํƒ ์ผ๊ด€์„ฑ ์ธก๋ฉด์—์„œ ์œ ๋ฆฌํ•˜๋‹ค๊ณ  ํŒ๋‹จํ•จ

  • ๋Œ€๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ ๋ฐ ํŒ€ ํ˜‘์—… ์ ํ•ฉ์„ฑ

    • ๋Œ€๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ ๊ด€์ ์—์„œ, Vanilla JS๋Š” ํ”„๋กœ์ ํŠธ ๊ทœ๋ชจ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก ๊ตฌ์กฐ ๊ด€๋ฆฌ๊ฐ€ ์–ด๋ ค์›Œ์ง€๋Š” ๋ฐ˜๋ฉด, React์™€ Vue๋Š” ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜ ์„ค๊ณ„๋ฅผ ํ†ตํ•ด ๋Œ€๊ทœ๋ชจ UI๋ฅผ ์ฒด๊ณ„์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Œ

      โ†”๏ธ ์ด ์ค‘ React๋Š” ์ปค๋ฎค๋‹ˆํ‹ฐ์™€ ๋ ˆํผ๋Ÿฐ์Šค, ํ™•์žฅ ์ƒํƒœ๊ณ„๊ฐ€ ๋งค์šฐ ํ’๋ถ€ํ•˜์—ฌ ํŒ€ ํ”„๋กœ์ ํŠธ ํ™˜๊ฒฝ์—์„œ ๋ฌธ์ œ ํ•ด๊ฒฐ๊ณผ ๊ธฐ์ˆ  ํ™•์žฅ์ด ์ƒ๋Œ€์ ์œผ๋กœ ์ˆ˜์›”ํ•จ

4. ๋ฒ„์ „ ์„ ํƒ ์ด์œ 

  • React 19.2
    • 2025๋…„ 10์›” 1์ผ์— ๋ฆด๋ฆฌ์ฆˆ๋œ ์•ˆ์ •(stable) ๋ฒ„์ „
  • 18 ๋ฒ„์ „์ด๋ž‘ ๋‹ฌ๋ผ์ง„ ์ 
    • ๋น„๋™๊ธฐ ์ž‘์—… ์ฒ˜๋ฆฌ ๋ฐฉ์‹์ด ํ›จ์”ฌ ๋‹จ์ˆœํ•ด์ง: Action ์ค‘์‹ฌ
      • 18: ๋ฒ„ํŠผ๋งˆ๋‹ค ๋กœ๋”ฉ/์‹คํŒจ/์™„๋ฃŒ ๊ด€๋ฆฌ๋ฅผ ์ง์ ‘ ์ฑ™๊ฒจ์•ผ ํ–ˆ์Œ
      • 19: ํผ/๋ฒ„ํŠผ์—์„œ) Action ํ•จ์ˆ˜๋ฅผ ์ค‘์‹ฌ์œผ๋กœ React๊ฐ€ pending(์ง„ํ–‰ ์ค‘) ์ƒํƒœ์™€ Action ๊ฒฐ๊ณผ(state)๋ฅผ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋Š” ํ‘œ์ค€ ํ›…/ํ๋ฆ„์„ ์ œ๊ณตํ•ด์„œ, ๋กœ๋”ฉ ํ‘œ์‹œยท๋ฒ„ํŠผ ๋น„ํ™œ์„ฑํ™”ยท๊ฒฐ๊ณผ ๋ฉ”์‹œ์ง€ ์—ฐ๊ฒฐ์ด ํ›จ์”ฌ ๋‹จ์ˆœํ•ด์ง (<form action>, useActionState, useFormStatus)
  • Devths์—์„œ Action์ด ํŠนํžˆ ๋„์›€๋˜๋Š” ๊ณณ
    • OCR ์—…๋กœ๋“œ: ์—…๋กœ๋“œ โ†’ ๋ถ„์„ ์ค‘ โ†’ ๊ฒฐ๊ณผ ๋ฐ›๊ธฐ/์‹คํŒจ
    • ์ผ์ • ์ €์žฅ: ์ €์žฅ ์ค‘ โ†’ ์™„๋ฃŒ/์‹คํŒจ
    • ๊ฒŒ์‹œ๊ธ€ ์ž‘์„ฑ: ๋“ฑ๋ก ์ค‘ โ†’ ์™„๋ฃŒ/์‹คํŒจ
    • ์ฑ„ํŒ… ์ „์†ก: ์ „์†ก ์ค‘ โ†’ ์™„๋ฃŒ/์‹คํŒจ
    • ์ฑ—๋ด‡ ์งˆ๋ฌธ: ๋‹ต๋ณ€ ์ƒ์„ฑ ์ค‘ โ†’ ์™„๋ฃŒ/์‹คํŒจ

โ‡’ ๋กœ๋”ฉ ํ‘œ์‹œ, ๋ฒ„ํŠผ ๋น„ํ™œ์„ฑํ™”, ์—๋Ÿฌ/์„ฑ๊ณต ๋ฉ”์‹œ์ง€ ๊ฐ™์€ ๊ฒƒ์„ ์ผ๊ด€๋˜๊ฒŒ ๋งŒ๋“ค๊ธฐ ์‰ฌ์›Œ์ง

5. ๊ฒฐ๋ก 

  • Devths๋Š” ์บ˜๋ฆฐ๋”(OCR ๊ธฐ๋ฐ˜ ์ผ์ • ์ž๋™ ์ƒ์„ฑ), ๊ฒŒ์‹œํŒ(๋ฌดํ•œ ์Šคํฌ๋กค/์ข‹์•„์š”/๋Œ“๊ธ€), ์ฑ—๋ด‡(AI ์‘๋‹ต ์ŠคํŠธ๋ฆฌ๋ฐ), ์ฑ„ํŒ…(์‹ค์‹œ๊ฐ„ ์†ก์ˆ˜์‹ /์ฝ์Œ/์ฒจ๋ถ€)์ฒ˜๋Ÿผ ์ƒํƒœ ๋ณ€ํ™”์™€ ์ธํ„ฐ๋ž™์…˜์ด ๋งŽ์€ ๊ธฐ๋Šฅ์ด ํ•ต์‹ฌ์ธ ์„œ๋น„์Šค์ž„
  • ๋”ฐ๋ผ์„œ ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜์œผ๋กœ UI๋ฅผ ๋ถ„๋ฆฌํ•˜๊ณ , ์ƒํƒœ ๋ณ€ํ™”์— ๋”ฐ๋ผ ํ™”๋ฉด์ด ์ž๋™์œผ๋กœ ๊ฐฑ์‹ ๋˜๋Š” React์˜ ๋ฐฉ์‹์ด ์„œ๋น„์Šค ๊ตฌ์กฐ์— ๊ฐ€์žฅ ์ ํ•ฉํ•˜๋‹ค๊ณ  ํŒ๋‹จํ•จ
  • ๋˜ํ•œ Devths์—์„œ ํ•„์š”ํ•œ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ(๋ผ์šฐํŒ…, ์„œ๋ฒ„ ์ƒํƒœ ๊ด€๋ฆฌ, ํผ ์ฒ˜๋ฆฌ, ์ƒํƒœ๊ด€๋ฆฌ, UI ์ปดํฌ๋„ŒํŠธ)์„ ์ƒํƒœ๊ณ„ ๋„๊ตฌ๋“ค๊ณผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๊ฒฐํ•ฉํ•  ์ˆ˜ ์žˆ์–ด ํ™•์žฅ์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์ด ๋†’์Œ
  • ํŠนํžˆ React 19.2๋Š” Action ์ค‘์‹ฌ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ํŒจํ„ด์„ ํ†ตํ•ด ์—…๋กœ๋“œ/์ €์žฅ/์ „์†ก์ฒ˜๋Ÿผ ๋ฐ˜๋ณต๋˜๋Š” ์š”์ฒญ UI๋ฅผ ์ผ๊ด€๋œ ํ˜•ํƒœ๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ ์‰ฌ์›Œ, ํ”„๋กœ์ ํŠธ ์ „๋ฐ˜์˜ ์ฝ”๋“œ ์ค‘๋ณต๊ณผ ๋ฒ„๊ทธ ๊ฐ€๋Šฅ์„ฑ์„ ์ค„์ผ ์ˆ˜ ์žˆ์Œ

๐Ÿ–ผ๏ธ ํ”„๋ ˆ์ž„์›Œํฌ

โœ… Next.js 16

1. ํŠน์ง• ์š”์•ฝ

  • React ๊ธฐ๋ฐ˜ ํ’€์Šคํƒ ํ”„๋ ˆ์ž„์›Œํฌ
    • React UI ๊ฐœ๋ฐœ์— ๋”ํ•ด, ๋ผ์šฐํŒ…/๋นŒ๋“œ/๋ฐฐํฌ/์ตœ์ ํ™” ๊ฐ™์€ ์•ฑ ์šด์˜์— ํ•„์š”ํ•œ ๊ฒƒ๋“ค์„ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ํ‘œ์ค€์œผ๋กœ ์ œ๊ณตํ•จ
  • ํŒŒ์ผ ๊ธฐ๋ฐ˜ ๋ผ์šฐํŒ… + ๋ ˆ์ด์•„์›ƒ ์‹œ์Šคํ…œ (App Router)
    • ํด๋” ๊ตฌ์กฐ๊ฐ€ URL ๊ตฌ์กฐ๊ฐ€ ๋˜๊ณ , layout.tsx๋กœ ๊ณตํ†ต ๋ ˆ์ด์•„์›ƒ์„ ๋ถ„๋ฆฌ ๊ฐ€๋Šฅ
    • ํŽ˜์ด์ง€ ์ˆ˜๊ฐ€ ๋งŽ๊ณ  ๊ณตํ†ต ๋ ˆ์ด์•„์›ƒ์ด ๋ฐ˜๋ณต๋˜๋Š” ์„œ๋น„์Šค์—์„œ ๊ตฌ์กฐ๊ฐ€ ๊ฐˆ๋”ํ•˜๊ฒŒ ์œ ์ง€๋จ
  • ๋ Œ๋”๋ง ์ „๋žต ์„ ํƒ ๊ฐ€๋Šฅ (CSR/SSG/SSR)
    • ํŽ˜์ด์ง€ ์„ฑ๊ฒฉ์— ๋”ฐ๋ผ ์„ž์–ด์„œ ๊ตฌ์„ฑ ๊ฐ€๋Šฅ
  • ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ธฐ๋ณธ ์ œ๊ณต
    • ์ฝ”๋“œ ์Šคํ”Œ๋ฆฌํŒ…, ํ”„๋ฆฌํŒจ์นญ, ์ด๋ฏธ์ง€ ์ตœ์ ํ™” ๋“ฑ ๊ธฐ๋ณธ ์ตœ์ ํ™” ๊ธฐ๋Šฅ์ด ๋‚ด์žฅ๋˜์–ด ์ดˆ๊ธฐ ์„ฑ๋Šฅ์„ ๋Œ์–ด์˜ฌ๋ฆฌ๊ธฐ ์‰ฌ์›€
  • ์—๋Ÿฌ/๋กœ๋”ฉ/Not Found ์ฒ˜๋ฆฌ ํŒจํ„ด ์ œ๊ณต
    • loading.tsx, error.tsx, not-found.tsx ๊ฐ™์€ ํŒŒ์ผ๋กœ ์ƒํƒœ UI๋ฅผ ํ‘œ์ค€ ๋ฐฉ์‹์œผ๋กœ ๊ด€๋ฆฌ ๊ฐ€๋Šฅ
    • ํ™”๋ฉด์ด ๋งŽ์•„์ ธ๋„ UX๋ฅผ ์ผ๊ด€๋˜๊ฒŒ ์œ ์ง€ํ•˜๊ธฐ ์ข‹์Œ

2. devths์— ์ด ๊ธฐ์ˆ ์ด ํ•„์š”ํ•œ ์ด์œ 

๐Ÿ’ก

Devths๋Š” ๋žœ๋”ฉ ํŽ˜์ด์ง€๋Š” SSG, ๋กœ๊ทธ์ธ ์ดํ›„ ์•ฑ ์˜์—ญ(์บ˜๋ฆฐ๋”/๊ฒŒ์‹œํŒ/์ฑ—๋ด‡/์ฑ„ํŒ…)์€ CSR๋กœ ์šด์˜ํ•˜๋Š” ๊ตฌ์กฐ์ด๊ธฐ ๋•Œ๋ฌธ์—, Next.js๊ฐ€ ์ œ๊ณตํ•˜๋Š” ํŽ˜์ด์ง€ ์„ฑ๊ฒฉ๋ณ„ ๋ Œ๋”๋ง ์ „๋žต + ์•ฑ ๊ตฌ์กฐ ํ‘œ์ค€ํ™”๊ฐ€ ํŠนํžˆ ์œ ๋ฆฌํ•จ

(1) ๋žœ๋”ฉ์€ SSG๋กœ ๋น ๋ฅด๊ฒŒ ์ œ๊ณตํ•ด์•ผ ํ•จ

  • ๋žœ๋”ฉ์€ ์„œ๋น„์Šค ์†Œ๊ฐœ/์‹œ์ž‘ํ•˜๊ธฐ ๋ชฉ์ ์ด๋ผ ์ฝ˜ํ…์ธ ๊ฐ€ ๋น„๊ต์  ๊ณ ์ •์ ์ด๋ฉฐ, ์ฒซ ์ง„์ž… ์†๋„๊ฐ€ ์ค‘์š”ํ•จ
    • Next.js๋Š” ํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ SSG๋ฅผ ์ ์šฉํ•ด ์ •์  HTML์„ ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์–ด ์ดˆ๊ธฐ ๋กœ๋”ฉ์„ ๋น ๋ฅด๊ฒŒ ๋งŒ๋“ค๊ธฐ ์ข‹์Œ

(2) ๋กœ๊ทธ์ธ ์ดํ›„ ํŽ˜์ด์ง€๋Š” CSR

  • ์บ˜๋ฆฐ๋”/๊ฒŒ์‹œํŒ/์ฑ„ํŒ…/์ฑ—๋ด‡์€ ์‚ฌ์šฉ์ž๋ณ„ ๋ฐ์ดํ„ฐ์™€ ์‹ค์‹œ๊ฐ„ ์ธํ„ฐ๋ž™์…˜์ด ํ•ต์‹ฌ์ด๋ผ, ํ™”๋ฉด์ด ๊ณ„์† ๋ณ€ํ•˜๊ณ  ์ƒํƒœ ๊ด€๋ฆฌ๊ฐ€ ์ค‘์š”ํ•จ
    • Next.js๋Š” CSR ๊ธฐ๋ฐ˜์˜ React ์•ฑ์„ ๊ทธ๋Œ€๋กœ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๊ณ , ๋ผ์šฐํŒ…/๋ ˆ์ด์•„์›ƒ/์ฝ”๋“œ ์Šคํ”Œ๋ฆฌํŒ… ๊ฐ™์€ ์•ฑ ๊ตฌ์กฐ๋ฅผ ํ”„๋ ˆ์ž„์›Œํฌ ๊ทœ์น™์œผ๋กœ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Œ

(3) ํ™”๋ฉด์ด ๋งŽ์„์ˆ˜๋ก โ€˜๋ผ์šฐํŒ…/๋ ˆ์ด์•„์›ƒ ํ‘œ์ค€โ€™์ด ์ค‘์š”ํ•ด์ง

  • Devths๋Š” ๋„๋ฉ”์ธ์ด ์—ฌ๋Ÿฌ ๊ฐœ(์บ˜๋ฆฐ๋”/๊ฒŒ์‹œํŒ/์ฑ—๋ด‡/์ฑ„ํŒ…)๋ผ ๊ณตํ†ต ๋ ˆ์ด์•„์›ƒ๊ณผ ์ ‘๊ทผ ์ œ์–ด(๋กœ๊ทธ์ธ ์ „/ํ›„)๊ฐ€ ๋ฐ˜๋ณต๋จ
    • Next.js(App Router)๋Š” layout, loading, error ๊ฐ™์€ ํ‘œ์ค€ ํŒŒ์ผ๋กœ ๊ณตํ†ต UI์™€ ์ƒํƒœ UI๋ฅผ ๊ตฌ์กฐ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด ํ™•์žฅ ์‹œ ๊ทœ์น™์ด ํ”๋“ค๋ฆฌ์ง€ ์•Š์Œ

2-1. SSG vs CSR vs SSR vs ISR

(1) SSG (Static Site Generation)

๐Ÿ’ก

๋นŒ๋“œ ์‹œ์ ์— ํŽ˜์ด์ง€ HTML์„ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด๋‘๊ณ , ์‚ฌ์šฉ์ž๊ฐ€ ์š”์ฒญํ•˜๋ฉด ๊ทธ ์ •์  HTML์„ ๊ทธ๋Œ€๋กœ ๋น ๋ฅด๊ฒŒ ์ œ๊ณตํ•˜๋Š” ๋ฐฉ์‹

  • ๋นŒ๋“œ/๋ฐฐํฌ ์‹œ์ ์— ์„œ๋ฒ„๊ฐ€ HTML์„ ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•ด๋‘๊ณ , ์‚ฌ์šฉ์ž๋Š” ๋งŒ๋“ค์–ด์ง„ ์ •์  HTML์„ ๊ทธ๋Œ€๋กœ ๋ฐ›๋Š” ๋ฐฉ์‹
  • ์‚ฌ์šฉ์ž๋Š” ์š”์ฒญํ•˜์ž๋งˆ์ž ์™„์„ฑ๋œ ํ™”๋ฉด์„ ๋น ๋ฅด๊ฒŒ ๋ณด๊ฒŒ ๋จ
  • ์žฅ์ 
    • ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด๋‘” HTML์„ ๋ฐ”๋กœ ์ œ๊ณตํ•˜๋ฏ€๋กœ ์ฒซ ๋กœ๋”ฉ์ด ๋งค์šฐ ๋น ๋ฅด๊ณ , ์„œ๋ฒ„ ๋ถ€๋‹ด/๋น„์šฉ์ด ๋‚ฎ์Œ
      • HTML์ด ์™„์„ฑ๋œ ์ƒํƒœ๋ผ SEO/๊ณต์œ  ๋ฏธ๋ฆฌ๋ณด๊ธฐ(OF)์—๋„ ์œ ๋ฆฌํ•ด ๋žœ๋”ฉ/์†Œ๊ฐœ ํŽ˜์ด์ง€์— ์ ํ•ฉํ•จ
  • ๋‹จ์ 
    • ๋นŒ๋“œ ์ดํ›„ ๋‚ด์šฉ์ด ๋ฐ”๋€Œ๋ฉด ์ฆ‰์‹œ ๋ฐ˜์˜๋˜์ง€ ์•Š์•„์„œ, ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋ฐ˜์˜ํ•˜๋ ค๋ฉด ์žฌ๋นŒ๋“œ/์žฌ๋ฐฐํฌ(๋˜๋Š” ISR ๊ฐ™์€ ๋ณด์™„ ์ „๋žต)๊ฐ€ ํ•„์š”ํ•จ

Devths

  • SSG๊ฐ€ ํ•„์š”ํ•œ ํŽ˜์ด์ง€/์ปดํฌ๋„ŒํŠธ
  • ํŽ˜์ด์ง€: ๋žœ๋”ฉ ํŽ˜์ด์ง€

(2) CSR (Client-Side Rendering)

๐Ÿ’ก

์„œ๋ฒ„๋Š” ๋ณดํ†ต

๋นˆ HTML(๊ป๋ฐ๊ธฐ) + JS ํŒŒ์ผ

์„ ์ฃผ๊ณ ,

๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๊ทธ

JS๋ฅผ ๋‹ค์šด๋กœ๋“œ/์‹คํ–‰ํ•ด์„œ ํ™”๋ฉด์„ ๋ Œ๋”๋ง

ํ•˜๋Š” ๋ฐฉ์‹

  • ์„œ๋ฒ„๋Š” ๋นˆ HTML + JS๋ฅผ ๋‚ด๋ ค์ฃผ๊ณ , ๋ธŒ๋ผ์šฐ์ €๊ฐ€ JS๋ฅผ ์‹คํ–‰ํ•ด ํ™”๋ฉด์„ ๋ Œ๋”๋งํ•˜๋Š” ๋ฐฉ์‹
  • ์‚ฌ์šฉ์ž๋Š” JS ๋กœ๋”ฉ ํ›„ ๋ฐ์ดํ„ฐ(API)๋ฅผ ๋ฐ›์•„ ํ™”๋ฉด์ด ์™„์„ฑ๋จ
  • ์žฅ์ 
    • ์‚ฌ์šฉ์ž๋ณ„ ๋ฐ์ดํ„ฐ/์‹ค์‹œ๊ฐ„ ์ธํ„ฐ๋ž™์…˜์ด ๋งŽ์€ ํŽ˜์ด์ง€์— ์œ ๋ฆฌํ•จ
    • ์ƒํƒœ ๋ณ€ํ™”์— ๋”ฐ๋ผ UI๋ฅผ ์ž์ฃผ ๊ฐฑ์‹ ํ•ด์•ผํ•˜๋Š” ์•ฑ์—์„œ ๊ตฌ์กฐ๊ฐ€ ๋‹จ์ˆœํ•˜๊ณ  ์œ ์—ฐํ•˜๊ฒŒ ๊ตฌํ˜„ ๊ฐ€๋Šฅํ•จ
  • ๋‹จ์ 
    • ์ดˆ๊ธฐ ๋กœ๋”ฉ ์‹œ JS ๋‹ค์šด๋กœ๋“œ, ์‹คํ–‰์ด ํ•„์š”ํ•ด์„œ ์ฒซ ํ™”๋ฉด์ด ๋Šฆ๊ฒŒ ๋œฐ ์ˆ˜ ์žˆ๊ณ , SEO(๊ฒ€์ƒ‰ ๋…ธ์ถœ) ์ธก๋ฉด์—์„œ ๋ถˆ๋ฆฌํ•  ์ˆ˜ ์žˆ์Œ

CSR์ด ํ•„์š”ํ•œ ํŽ˜์ด์ง€/์ปดํฌ๋„ŒํŠธ

  • ํŽ˜์ด์ง€: ์บ˜๋ฆฐ๋”, ๊ฒŒ์‹œํŒ, ์ฑ—๋ด‡, ์ฑ„ํŒ…, ํ”„๋กœํ•„
  • ์ปดํฌ๋„ŒํŠธ
    • ์บ˜๋ฆฐ๋”
      • FullCalendar(์›”/์ฃผ/์ผ ์ „ํ™˜, ํด๋ฆญ, ๋“œ๋ž˜๊ทธ)
      • EventModal(ํผ ์ž…๋ ฅ/์ €์žฅ)
      • OcrUploadModal(์—…๋กœ๋“œโ†’์ฒ˜๋ฆฌ์ค‘โ†’๊ฒฐ๊ณผ ๋ฐ˜์˜)
    • ๊ฒŒ์‹œํŒ
      • PostList(๋ฌดํ•œ์Šคํฌ๋กค)
      • LikeButton(์ฆ‰์‹œ ํ† ๊ธ€/๋‚™๊ด€์  ์—…๋ฐ์ดํŠธ)
      • CommentList(์ถ”๊ฐ€/์ˆ˜์ •/์‚ญ์ œ)
      • WriteForm(์ž…๋ ฅ/์ฒจ๋ถ€)
    • ์ฑ—๋ด‡/AI
      • ChatThread(๋Œ€ํ™” ๋ˆ„์ )
      • StreamingAnswer(์ŠคํŠธ๋ฆฌ๋ฐ ์ถœ๋ ฅ)
    • ์ฑ„ํŒ…
      • RoomList(์•ˆ์ฝ์Œ ๋ฑƒ์ง€ ๊ฐฑ์‹ )

      • MessageList(์‹ค์‹œ๊ฐ„ ์ˆ˜์‹  + ๊ณผ๊ฑฐ ๋กœ๋”ฉ)

      • ChatInput(์ „์†ก/์ฒจ๋ถ€)

        โžก๏ธ ๊ณตํ†ต ํŠน์ง•: ์‚ฌ์šฉ์ž ์ž…๋ ฅ/์„œ๋ฒ„ ์š”์ฒญ/์‹ค์‹œ๊ฐ„ ์ด๋ฒคํŠธ๋กœ ์ƒํƒœ๊ฐ€ ๊ณ„์† ๋ฐ”๋€œ

(3) SSR (Server-Side Rendering)

๐Ÿ’ก

์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ๋งˆ๋‹ค ์„œ๋ฒ„๊ฐ€ HTML์„ ๋จผ์ € ๋ Œ๋”๋งํ•ด์„œ ๋‚ด๋ ค์ฃผ๋Š” ๋ฐฉ์‹

  • ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ๋งˆ๋‹ค ์„œ๋ฒ„๊ฐ€ HTML์„ ๋จผ์ € ๋ Œ๋”๋งํ•ด์„œ ๋‚ด๋ ค์ฃผ๋Š” ๋ฐฉ์‹
  • ์‚ฌ์šฉ์ž๋Š” ์™„์„ฑ๋œ ํ™”๋ฉด์„ ๋” ๋นจ๋ฆฌ ๋ณด๊ฒŒ ๋จ
  • ์žฅ์ 
    • ์ฒซ ํ™”๋ฉด์ด ๋น ๋ฅด๊ฒŒ ๋ณด์ผ ์ˆ˜ ์žˆ๊ณ , ์„œ๋ฒ„๊ฐ€ ์š”์ฒญ ์‹œ์ ์˜ ์ตœ์‹  ๋ฐ์ดํ„ฐ๋กœ HTML์„ ๋งŒ๋“ค์–ด์„œ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์–ด์„œ ์ดˆ๊ธฐ UX์™€ ์ตœ์‹ ์„ฑ์ด ์ค‘์š”ํ•œ ํŽ˜์ด์ง€์— ์œ ๋ฆฌํ•จ
  • ๋‹จ์ 
    • ์š”์ฒญ๋งˆ๋‹ค ์„œ๋ฒ„๊ฐ€ ๋ Œ๋”๋ง/๋ฐ์ดํ„ฐ ํŒจ์นญ์„ ํ•ด์•ผํ•ด์„œ ์„œ๋ฒ„ ๋ถ€ํ•˜์™€ ๋น„์šฉ์ด ์ฆ๊ฐ€ํ•  ์ˆ˜ ์žˆ๊ณ , ์บ์‹ฑ/์ธ์ฆ/์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋“ฑ ๊ตฌํ˜„ ๋ณต์žก๋„๊ฐ€ ์˜ฌ๋ผ๊ฐˆ ์ˆ˜ ์žˆ์Œ

Devths๋Š” ๋žœ๋”ฉ์„ ์ œ์™ธํ•˜๋ฉด ๋กœ๊ทธ์ธ ํ›„ ์‚ฌ์šฉ์ž๋ณ„ ๋ฐ์ดํ„ฐ + ์‹ค์‹œ๊ฐ„ ์ธํ„ฐ๋ž™์…˜์ด ํ•ต์‹ฌ์ด๋ผ, SSR์˜ ์žฅ์ (๊ณต๊ฐœ ํŽ˜์ด์ง€ SEO, ์ฒซ ํ™”๋ฉด ์™„์„ฑ)์ด ํฌ๊ฒŒ ํ•„์š”ํ•˜์ง€ ์•Š์Œ โ†’ ๋Œ€์‹  ์„œ๋ฒ„ ๋ถ€ํ•˜, ์ธ์ฆ/์บ์‹œ/์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋ณต์žก๋„๋งŒ ๋Š˜ ์ˆ˜ ์žˆ์–ด์„œ ๋งž์ง€ ์•Š์Œ

(4) ISR (Incremental Static Regeneration)

๐Ÿ’ก

์ฒ˜์Œ์—” SSG์ฒ˜๋Ÿผ ์ •์  HTML๋กœ ๋น ๋ฅด๊ฒŒ ์ œ๊ณตํ•˜๋˜, ์„ค์ •ํ•œ ์‹œ๊ฐ„(๋˜๋Š” ์กฐ๊ฑด)๋งˆ๋‹ค ์„œ๋ฒ„๊ฐ€ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ํŽ˜์ด์ง€๋ฅผ ๋‹ค์‹œ ์ƒ์„ฑํ•ด ์ตœ์‹  ๋‚ด์šฉ์œผ๋กœ ๊ฐฑ์‹ ํ•˜๋Š” ๋ฐฉ์‹

  • SSG์ฒ˜๋Ÿผ HTML์„ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด๋‘๋˜, ์„ค์ •ํ•œ ์ฃผ๊ธฐ๋งˆ๋‹ค ์„œ๋ฒ„๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ๋‹ค์‹œ ์ƒ์„ฑํ•ด์„œ ์ •์  ํŽ˜์ด์ง€๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๋ฐฉ์‹
  • ์‚ฌ์šฉ์ž๋Š” ๋Œ€๋ถ€๋ถ„ ์ •์  HTML์„ ๋น ๋ฅด๊ฒŒ ๋ฐ›๊ณ , ์ผ์ • ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด ๋‚ด์šฉ์ด ์ž๋™์œผ๋กœ ์ตœ์‹ ์œผ๋กœ ๊ฐฑ์‹ ๋จ
  • ์žฅ์ 
    • SSG์˜ ๋น ๋ฅธ ๋กœ๋”ฉ/๋‚ฎ์€ ์„œ๋ฒ„ ๋ถ€๋‹ด์„ ์œ ์ง€ํ•˜๋ฉด์„œ๋„, ๊ณต์ง€/๋ฐฐ๋„ˆ/๋žญํ‚น์ฒ˜๋Ÿผ ๊ฐ€๋” ๋ฐ”๋€Œ๋Š” ์ฝ˜ํ…์ธ ๋ฅผ ์ž๋™์œผ๋กœ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ์–ด ์„ฑ๋Šฅ๊ณผ ์ตœ์‹ ์„ฑ์„ ๊ท ํ˜•์žˆ๊ฒŒ ๊ฐ€์ ธ๊ฐˆ ์ˆ˜ ์žˆ์Œ
  • ๋‹จ์ 
    • ์ฆ‰์‹œ ์ตœ์‹ ์€ ์•„๋‹ˆ๊ณ , ์ฃผ๊ธฐ ์ „๊นŒ์ง€๋Š” ์ด์ „ ๋‚ด์šฉ์ด ๋ณด์ผ ์ˆ˜ ์žˆ์Œ.
    • ๋˜ํ•œ ์žฌ์ƒ์„ฑ ํƒ€์ด๋ฐ/์บ์‹œ ์ •์ฑ…์„ ์ž˜๋ชป ์žก์œผ๋ฉด ๋ฐ์ดํ„ฐ ๊ฐฑ์‹ ์ด ์˜ˆ์ƒ๊ณผ ๋‹ค๋ฅด๊ฒŒ ๋А๊ปด์งˆ ์ˆ˜ ์žˆ์Œ

Devths์˜ ํ•ต์‹ฌ ํŽ˜์ด์ง€๋“ค์€ ๋กœ๊ทธ์ธ ๊ธฐ๋ฐ˜ ๊ฐœ์ธํ™” + ์‹ค์‹œ๊ฐ„/์ฆ‰์‹œ ๋ฐ˜์˜ ๋ฐ์ดํ„ฐ๋ผ์„œ, ๊ณต๊ฐœ ์ •์  ํŽ˜์ด์ง€๋ฅผ ์ฃผ๊ธฐ์ ์œผ๋กœ ๊ฐฑ์‹ ํ•˜๋Š” ISR์˜ ๊ฐ•์ ์„ ๊ฑฐ์˜ ๋ชป ์”€ โ†’ ๋Œ€์‹  ๊ฐฑ์‹  ์ง€์—ฐ/์ค‘๋ณต ๊ตฌํ˜„์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ์Œ

2-2. App Router vs Page Router

(1) App Router

  • /app ํด๋” ๊ธฐ๋ฐ˜์œผ๋กœ ๋ผ์šฐํŒ…๋˜๋Š” Next.js์˜ ์ตœ์‹  ๋ผ์šฐํ„ฐ
  • layout.tsx๋กœ ๊ณตํ†ต ๋ ˆ์ด์•„์›ƒ์„ ํด๋” ๋‹จ์œ„๋กœ ๊ธฐ๋ณธ ์ œ๊ณตํ•˜๊ณ , loading.tsx / error.tsx / not-found.tsx๋กœ ์ƒํƒœ UI๋ฅผ ํ‘œ์ค€ ํŒŒ์ผ๋กœ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ์Œ
  • Route Group์œผ๋กœ URL์€ ์œ ์ง€ํ•˜๋ฉด์„œ ํด๋” ๊ตฌ์กฐ๋งŒ ๋ชฉ์ ๋ณ„๋กœ ๋ถ„๋ฆฌ ๊ฐ€๋Šฅ
    • (marketing) : ๋žœ๋”ฉ(SSG)
    • (app) : ๋กœ๊ทธ์ธ ์ดํ›„ ๋ชจ๋“  ํŽ˜์ด์ง€(CSR)
  • ์žฅ์ 
    • Devths์ฒ˜๋Ÿผ ๊ณตํ†ต ๋ ˆ์ด์•„์›ƒ(ํ—ค๋”/์‚ฌ์ด๋“œ๋ฐ”)์ด ๋งŽ์€ ์„œ๋น„์Šค์—์„œ ๊ตฌ์กฐ๊ฐ€ ๊น”๋”ํ•ด์ง
    • ๋žœ๋”ฉ(SSG)๊ณผ ๋กœ๊ทธ์ธ ํ›„ ์•ฑ(CSR) ์˜์—ญ์„ ํด๋” ๊ตฌ์กฐ๋กœ ๋ช…ํ™•ํžˆ ๋‚˜๋ˆ  ํŒ€ ๊ทœ์น™์„ ์œ ์ง€ํ•˜๊ธฐ ์‰ฌ์›€
    • ๋กœ๋”ฉ/์—๋Ÿฌ UI๋ฅผ ํ‘œ์ค€ ๋ฐฉ์‹์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด ํŽ˜์ด์ง€๊ฐ€ ๋Š˜์–ด๋‚˜๋„ UX๊ฐ€ ์ผ๊ด€๋จ
  • ๋‹จ์ 
    • ๊ธฐ๋ณธ ๊ฐœ๋…(์„œ๋ฒ„/ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ ๋ถ„๋ฆฌ, use client, ํด๋” ๊ทœ์น™ ๋“ฑ)์ด Pages Router๋ณด๋‹ค ๋‚ฏ์„ค์–ด์„œ ์ดˆ๊ธฐ ํ•™์Šต ๋น„์šฉ์ด ๋” ํผ
    • ์ž˜๋ชป ์„ค๊ณ„ํ•˜๋ฉด ํด๋ผ์ด์–ธํŠธ๋กœ๋งŒ ์“ธ ๊ฑด๋ฐ๋„ use client ๋ฒ”์œ„๊ฐ€ ์ปค์ ธ ์žฅ์ ์ด ์•ฝํ•ด์งˆ ์ˆ˜ ์žˆ์Œ

Devths๋Š” ๋žœ๋”ฉ SSG + ๋กœ๊ทธ์ธ ํ›„ CSR ์•ฑ ๊ตฌ์กฐ๋ผ์„œ, App Router์˜ ๋ ˆ์ด์•„์›ƒ/๋ผ์šฐํŒ… ํ‘œ์ค€ํ™” + ๋งˆ์ผ€ํŒ…/์•ฑ ์˜์—ญ ๋ถ„๋ฆฌ(Route Group) ์žฅ์ ์„ ๊ทธ๋Œ€๋กœ ํ™œ์šฉํ•˜๊ธฐ ์ข‹์Œ โ†’ ํ™”๋ฉด ์ˆ˜๊ฐ€ ๋Š˜์–ด๋„ ๊ตฌ์กฐ ๊ทœ์น™์ด ํ”๋“ค๋ฆฌ์ง€ ์•Š์Œ

(2) Page Router

  • /pages ํด๋” ๊ธฐ๋ฐ˜์˜ ์ „ํ†ต์ ์ธ Next.js ๋ผ์šฐํ„ฐ
  • ํŒŒ์ผ์ด ๊ณง URL์ด๋ฉฐ, ๋ฐ์ดํ„ฐ ํŒจ์นญ์€ getStaticProps/getServerSideProps ๊ฐ™์€ ํŽ˜์ด์ง€ ํ•จ์ˆ˜ ์ค‘์‹ฌ์œผ๋กœ ๊ตฌ์„ฑ๋จ
  • ์žฅ์ 
    • ๊ฐœ๋…์ด ๋‹จ์ˆœํ•ด์„œ Next.js๋ฅผ ์ฒ˜์Œ ์“ฐ๋Š” ํŒ€์—๊ฒŒ ์ง„์ž…์žฅ๋ฒฝ์ด ๋‚ฎ์Œ
    • โ€œํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ SSR/SSGโ€๊ฐ€ ์ง๊ด€์ ์ด๋ผ ๋น ๋ฅด๊ฒŒ ๊ตฌํ˜„ํ•˜๊ธฐ ์‰ฌ์›€
  • ๋‹จ์ 
    • Devths์ฒ˜๋Ÿผ ๊ณตํ†ต ๋ ˆ์ด์•„์›ƒ์ด ๋งŽ๊ณ  ํŽ˜์ด์ง€๊ฐ€ ๋งŽ์€ ์„œ๋น„์Šค์—์„œ ๋ ˆ์ด์•„์›ƒ/์ƒํƒœ UI(๋กœ๋”ฉ/์—๋Ÿฌ) ํŒจํ„ด์„ ์ผ๊ด€๋˜๊ฒŒ ์œ ์ง€ํ•˜๋ ค๋ฉด ํŒ€์ด ๊ทœ์น™์„ ๋” ๋งŽ์ด ์ง์ ‘ ์ •ํ•ด์•ผ ํ•จ
    • ๋žœ๋”ฉ(SSG)๊ณผ ์•ฑ(CSR)์„ ๊ตฌ์กฐ์ ์œผ๋กœ ๋ถ„๋ฆฌํ•˜๋”๋ผ๋„, App Router๋งŒํผ โ€œํด๋” ๋‹จ์œ„ ๋ ˆ์ด์•„์›ƒ/์ƒํƒœ UI ํ‘œ์ค€โ€์ด ๊ฐ•ํ•˜์ง€ ์•Š์•„ ๊ทœ๋ชจ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก ๊ด€๋ฆฌ ๋‚œ์ด๋„๊ฐ€ ์˜ฌ๋ผ๊ฐˆ ์ˆ˜ ์žˆ์Œ

Devths์—์„œ๋„ Pages Router๋กœ ๊ตฌํ˜„์€ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ํ™”๋ฉด์ด ๋Š˜์–ด๋‚ ์ˆ˜๋ก ๋ ˆ์ด์•„์›ƒ/์—๋Ÿฌ/๋กœ๋”ฉ ๊ทœ์น™์„ ํŒ€์ด ์ง์ ‘ ๊ด€๋ฆฌํ•ด์•ผ ํ•˜๋Š” ๋น„์ค‘์ด ์ปค์ง

โ†’ ์žฅ๊ธฐ์ ์œผ๋กœ๋Š” ๊ตฌ์กฐ ์ผ๊ด€์„ฑ ์œ ์ง€ ๋น„์šฉ์ด ๋” ๋“ค ์ˆ˜ ์žˆ์Œ

3. ๋‹ค๋ฅธ ์Šคํƒ๊ณผ์˜ ๋น„๊ต ํ‘œ

ํ•ญ๋ชฉ Next.js Vite + React
๋ผ์šฐํŒ… ํŒŒ์ผ ๊ธฐ๋ฐ˜ ๋ผ์šฐํŒ… ๋‚ด์žฅ ์ง์ ‘ ๊ตฌ์„ฑ ํ•„์š”
SSR/SSG ๊ธฐ๋ณธ ์ง€์› ์ง์ ‘ ๊ตฌ์„ฑ
๋ ˆ์ด์•„์›ƒ ๊ด€๋ฆฌ layout ๊ตฌ์กฐ ์ œ๊ณต ์ง์ ‘ ์„ค๊ณ„
์—๋Ÿฌ ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌ ๋‚ด์žฅ(error/not-found) ์ง์ ‘ ๊ตฌํ˜„
ํ”„๋กœ์ ํŠธ ํ™•์žฅ์„ฑ ๋†’์Œ ์„ค๊ณ„์— ๋”ฐ๋ผ ํŽธ์ฐจ
  • ๋ผ์šฐํŒ…/ํŽ˜์ด์ง€ ๊ตฌ์กฐ ๊ด€๋ฆฌ

    • Vite + React๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ผ์šฐํŒ…์ด ๋‚ด์žฅ๋˜์–ด ์žˆ์ง€ ์•Š์•„, React Router ๋“ฑ ์™ธ๋ถ€ ๋ผ์šฐํ„ฐ๋ฅผ ๋ถ™์ด๊ณ (์ค‘์ฒฉ ๋ผ์šฐํŒ…, ์ธ์ฆ ๊ฐ€๋“œ, ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๊ทœ์น™ ํฌํ•จ) ํ”„๋กœ์ ํŠธ์—์„œ ์ง์ ‘ ์„ค๊ณ„ํ•ด์•ผ ํ•จ.

    • ํŽ˜์ด์ง€ ์ˆ˜๊ฐ€ ๋Š˜์–ด๋‚ ์ˆ˜๋ก ๋ผ์šฐํŒ… ๊ทœ์น™ + ํด๋” ๊ตฌ์กฐ + ๋ ˆ์ด์•„์›ƒ ์ ์šฉ ๋ฐฉ์‹์ด ํŒ€ ์ปจ๋ฒค์…˜์— ์˜์กดํ•˜๊ฒŒ ๋˜์–ด ๊ตฌ์กฐ๊ฐ€ ํ”๋“ค๋ฆด ๊ฐ€๋Šฅ์„ฑ์ด ์ปค์ง

      โ†”๏ธ ๋ฐ˜๋ฉด Next.js๋Š” ํŒŒ์ผ ๊ธฐ๋ฐ˜ ๋ผ์šฐํŒ…์ด ๋‚ด์žฅ๋˜์–ด ์žˆ์–ด, ํด๋” ๊ตฌ์กฐ๊ฐ€ ๊ณง URL ๊ตฌ์กฐ๋กœ ์—ฐ๊ฒฐ๋˜๊ณ  ๋ผ์šฐํŒ… ๊ทœ์น™์ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํ‘œ์ค€ํ™”๋จ. ๋”ฐ๋ผ์„œ ํŽ˜์ด์ง€๊ฐ€ ๋งŽ์•„์ ธ๋„ ๊ตฌ์กฐ๋ฅผ ์ผ๊ด€๋˜๊ฒŒ ์œ ์ง€ํ•˜๊ธฐ์— ์œ ๋ฆฌํ•จ

  • SSR/SSG ๋„์ž… ๋น„์šฉ๊ณผ ์šด์˜ ํ™•์žฅ์„ฑ

    • Vite + React๋Š” ๊ธฐ๋ณธ์ด SPA ์ค‘์‹ฌ์ด๋ฏ€๋กœ SSR/SSG๊ฐ€ ํ•„์š”ํ•ด์งˆ ๊ฒฝ์šฐ(๋žœ๋”ฉ ํŽ˜์ด์ง€์˜ ์ดˆ๊ธฐ ๋กœ๋”ฉ, ๊ณต์œ /๊ฒ€์ƒ‰ ๋…ธ์ถœ ๋“ฑ) ๋ณ„๋„ ํ”„๋ ˆ์ž„์›Œํฌ/๊ตฌ์„ฑ(์˜ˆ: SSR ์„œ๋ฒ„ ๊ตฌ์„ฑ, ๋ผ์šฐํŒ…/๋นŒ๋“œ ํŒŒ์ดํ”„๋ผ์ธ ์žฌ์„ค๊ณ„)์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•  ์ˆ˜ ์žˆ์Œ

    • โ†’ ๋ณ€๊ฒฝ ๋น„์šฉ ๋ฐœ์ƒ

      โ†”๏ธ ๋ฐ˜๋ฉด Next.js๋Š” SSR/SSG๋ฅผ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ๊ธฐ๋ณธ ์ œ๊ณตํ•˜๋ฏ€๋กœ, ํ™”๋ฉด ํŠน์„ฑ์— ๋”ฐ๋ผ ๋ Œ๋”๋ง ๋ฐฉ์‹์„ ์„ ํƒํ•˜๊ธฐ ์‰ฝ๊ณ , ํ–ฅํ›„ ์š”๊ตฌ์‚ฌํ•ญ ๋ณ€ํ™”(๋žœ๋”ฉ ์ตœ์ ํ™” ๋“ฑ)์— ๋Œ€์‘ํ•˜๋Š” ๋น„์šฉ์ด ์ƒ๋Œ€์ ์œผ๋กœ ๋‚ฎ์Œ

  • ๊ณตํ†ต ๋ ˆ์ด์•„์›ƒ ๊ด€๋ฆฌ ๋ฐฉ์‹

    • Vite + React์—์„œ๋Š” Header/Footer ๊ฐ™์€ ๊ณตํ†ต ๋ ˆ์ด์•„์›ƒ์„ ์ ์šฉํ•˜๋ ค๋ฉด ๋ผ์šฐํ„ฐ ์ค‘์ฒฉ ๊ตฌ์กฐ๋‚˜ ๋ ˆ์ด์•„์›ƒ ์ปดํฌ๋„ŒํŠธ ์ ์šฉ ๊ทœ์น™์„ ํ”„๋กœ์ ํŠธ์—์„œ ์ง์ ‘ ์„ค๊ณ„ํ•ด์•ผ ํ•จ.

    • ํ™”๋ฉด์ด ๋งŽ์•„์งˆ์ˆ˜๋ก ์–ด๋–ค ํŽ˜์ด์ง€์— ์–ด๋–ค ๋ ˆ์ด์•„์›ƒ์ด ์ ์šฉ๋˜๋Š”์ง€๊ฐ€ ๋ณต์žกํ•ด์ง

      โ†”๏ธ ๋ฐ˜๋ฉด Next.js(App Router)๋Š” layout ๊ตฌ์กฐ๊ฐ€ ํ”„๋ ˆ์ž„์›Œํฌ ๋ ˆ๋ฒจ์—์„œ ์ œ๊ณต๋˜๊ธฐ ๋•Œ๋ฌธ์— ๊ณตํ†ต ๋ ˆ์ด์•„์›ƒ์„ ํ‘œ์ค€ ๋ฐฉ์‹์œผ๋กœ ์ ์šฉํ•  ์ˆ˜ ์žˆ๊ณ , ํŽ˜์ด์ง€ ์ฆ๊ฐ€ ์‹œ์—๋„ ๋ ˆ์ด์•„์›ƒ ๊ด€๋ฆฌ๊ฐ€ ์•ˆ์ •์ ์œผ๋กœ ์œ ์ง€๋จ

  • ์—๋Ÿฌ ํŽ˜์ด์ง€ ๋ฐ ๋ผ์šฐํŒ… ์ •์ฑ…์˜ ํ‘œ์ค€ํ™”

    • Vite + React๋Š” 404/500 ์ฒ˜๋ฆฌ, ์—๋Ÿฌ ๋ฐ”์šด๋”๋ฆฌ ๊ตฌ์„ฑ, ๋ผ์šฐํŒ… ์‹คํŒจ ์ฒ˜๋ฆฌ ๋“ฑ์„ ํ”„๋กœ์ ํŠธ์—์„œ ์ง์ ‘ ์„ค๊ณ„ํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ํ™”๋ฉด๋ณ„ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์ด ๋‹ฌ๋ผ์ง€๊ฑฐ๋‚˜ ๋ˆ„๋ฝ๋  ์œ„ํ—˜์ด ์žˆ์Œ.

    • ํŠนํžˆ ์ธ์ฆ ํ๋ฆ„(๋กœ๊ทธ์ธ ์ „/ํ›„ ๋ถ„๊ธฐ), ์ž˜๋ชป๋œ ๊ฒฝ๋กœ ์ ‘๊ทผ, ์„œ๋ฒ„ ์˜ค๋ฅ˜ ๋Œ€์‘ ๊ฐ™์€ ์ •์ฑ…์„ฑ ๋ผ์šฐํŒ…์ด ๋งŽ์•„์งˆ์ˆ˜๋ก ๊ด€๋ฆฌ ๋น„์šฉ์ด ์ฆ๊ฐ€ํ•จ

      โ†”๏ธ ๋ฐ˜๋ฉด Next.js๋Š” not-found.tsx, error.tsx ๋“ฑ ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๊ตฌ์กฐ๊ฐ€ ๋‚ด์žฅ๋˜์–ด ์žˆ์–ด, ์—๋Ÿฌ ๋Œ€์‘์„ ๋ผ์šฐํŒ… ์ •์ฑ…์˜ ์ผ๋ถ€๋กœ ํ‘œ์ค€ํ™”ํ•˜๊ธฐ ์‰ฝ๊ณ  ์šด์˜ ํ’ˆ์งˆ์„ ์ผ์ •ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๊ธฐ ์œ ๋ฆฌํ•จ

  • ํ”„๋กœ์ ํŠธ ํ™•์žฅ ์‹œ ๋ˆ„์  ๋น„์šฉ(์„ค๊ณ„ ๋ถ€๋‹ด)

    • Vite + React๋Š” ์‹œ์ž‘์ด ๊ฐ€๋ณ์ง€๋งŒ, ์„œ๋น„์Šค๊ฐ€ ์ปค์งˆ์ˆ˜๋ก ๋ผ์šฐํŒ…/SSR/๋ ˆ์ด์•„์›ƒ/์—๋Ÿฌ ์ฒ˜๋ฆฌ ๊ฐ™์€ ์•ฑ์˜ ๊ณจ๊ฒฉ์„ ํŒ€์ด ๊ณ„์† ์ฑ…์ž„์ ธ์•ผ ํ•จ.

    • ์ด ๋ˆ„์  ๋น„์šฉ์ด ์ปค์ง€๋ฉด ๊ฐœ๋ฐœ ์†๋„๊ฐ€ ๋–จ์–ด์ง€๊ณ , ๊ตฌ์กฐ๊ฐ€ ๋ณต์žกํ•ด์ง€๋ฉฐ, ์œ ์ง€๋ณด์ˆ˜ ๋ฆฌ์Šคํฌ๊ฐ€ ์ฆ๊ฐ€ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Œ.

      โ†”๏ธ ๋ฐ˜๋ฉด Next.js๋Š” ์ด๋Ÿฌํ•œ ๊ณจ๊ฒฉ์„ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ํ‘œ์ค€ํ™”ํ•ด ์ œ๊ณตํ•˜๋ฏ€๋กœ, ํŒ€์€ Devths์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ(์บ˜๋ฆฐ๋”/๊ฒŒ์‹œํŒ/์ฑ„ํŒ…/์•Œ๋ฆผ ๋“ฑ) ๊ตฌํ˜„์— ๋” ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๊ณ , ๊ฒฐ๊ณผ์ ์œผ๋กœ ํ™•์žฅ์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜ ์ธก๋ฉด์—์„œ ์œ ๋ฆฌํ•œ ์„ ํƒ์ด ๋จ

4. ๋ฒ„์ „ ์„ ํƒ ์ด์œ 

  • Next.js 16
    • 2025๋…„ 10์›” 21์ผ ๋ฆด๋ฆฌ์ฆˆ
  • ํŠน๋ณ„ํ•˜๊ฒŒ 16 ๋ฒ„์ „์„ ์„ ํƒํ•œ ์ด์œ 
    • 15๋ฒ„์ „๊ณผ ๋‹ค๋ฅธ ์ 
      • Turbopack ๊ฐœ๋ฐœ๋ฟ ์•„๋‹ˆ๋ผ ํ”„๋กœ๋•์…˜ ๋นŒ๋“œ๊นŒ์ง€ ์•ˆ์ • + ๊ธฐ๋ณธ ๋ฒˆ๋“ค๋Ÿฌ๊ฐ€ ๋จ
        • 15: Turbopack์€ dev ์•ˆ์ •ํ™” ์ค‘์‹ฌ
        • 16: dev + build๊นŒ์ง€ ์•ˆ์ •ํ™”๋˜์–ด ๋นŒ๋“œ/๋ฆฌํ”„๋ ˆ์‹œ ์„ฑ๋Šฅ ๊ฐœ์„  ๊ธฐ๋Œ€
      • ๋ผ์šฐํŒ…/ํ”„๋ฆฌํŒจ์น˜(ํŽ˜์ด์ง€ ์ „ํ™˜) ์ตœ์ ํ™” ๊ฐ•ํ™”
        • Next(App Router)๋Š” ํŽ˜์ด์ง€ ์ด๋™ํ•  ๋•Œ ๊ณตํ†ต ๋ ˆ์ด์•„์›ƒ(ํ—ค๋”/์‚ฌ์ด๋“œ๋ฐ” ๋“ฑ)์€ ์žฌ์‚ฌ์šฉํ•˜๊ณ , ๋ณ€๊ฒฝ๋˜๋Š” ํŽ˜์ด์ง€ ์˜์—ญ๋งŒ ์ƒˆ๋กœ ๋กœ๋“œํ•ด ์ „ํ™˜์„ ๋” ๋น ๋ฅด๊ฒŒ ๋А๋ผ๊ฒŒ ํ•จ
        • ๊ทธ๋ฆฌ๊ณ  ๋ฏธ๋ฆฌ ๊ฐ€์ ธ์˜ค๊ธฐ(ํ”„๋ฆฌํŒจ์น˜)๋„ ํ•„์š”ํ•œ ๋ฒ”์œ„๋งŒ ์ ์ง„์ ์œผ๋กœ ๊ฐ€์ ธ์™€์„œ ๋ถˆํ•„์š”ํ•œ ๋‹ค์šด๋กœ๋“œ๋ฅผ ์ค„์ด๊ณ  ๋„คํŠธ์›Œํฌ ๋‚ญ๋น„๋ฅผ ๊ฐ์†Œ์‹œํ‚ด
          • 15๋ฒ„์ „์—์„œ๋Š” ๊ณตํ†ต ๋ ˆ์ด์•„์›ƒ์ด ์ค‘๋ณต ๋‹ค์šด๋กœ๋“œ๋  ์ˆ˜ ์žˆ์—ˆ์Œ
  • Devths์—์„œ 16๋ฒ„์ „์ด ๋” ๋‚˜์€ ์ด์œ 
    • ๋žœ๋”ฉ(SSG) + ๋กœ๊ทธ์ธ ํ›„ (CSR) ๊ตฌ์กฐ์—์„œ, ํŽ˜์ด์ง€ ์ „ํ™˜์ด ์žฆ์€ ์•ฑ ์˜์—ญ์—์„œ ๊ณตํ†ต ๋ ˆ์ด์•„์›ƒ ์žฌ์‚ฌ์šฉ + ํ”„๋ฆฌํŒจ์น˜ ์ตœ์ ํ™”๊ฐ€ ์ฒด๊ฐ ์„ฑ๋Šฅ์„ ์˜ฌ๋ ค์คŒ
      • ํ—ค๋”/ํ‘ธํ„ฐ๊ฐ€ ๊ณ ์ •๋œ ํ™”๋ฉด์„ ์—ฌ๋Ÿฌ ํŽ˜์ด์ง€๊ฐ€ ๊ณต์œ ํ•˜๋Š” ์„œ๋น„์Šค์ผ์ˆ˜๋ก ์ค‘๋ณต ๋‹ค์šด๋กœ๋“œ๋ฅผ ์ค„์ด๋Š” ๊ฐœ์„  ํšจ๊ณผ๊ฐ€ ํผ
    • ํ™”๋ฉด/์ปดํฌ๋„ŒํŠธ ์ˆ˜๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ๊ฐœ๋ฐœ ์ค‘ ์ˆ˜์ •์ด ์žฆ์€๋ฐ, Turbopack์ด dev๋ฟ ์•„๋‹ˆ๋ผ build๊นŒ์ง€ ์•ˆ์ •ํ™”๋˜๋ฉด์„œ ๋กœ์ปฌ ๊ฐœ๋ฐœ ๋ฐ˜์˜ ์†๋„์™€ ๋ฐฐํฌ ๋นŒ๋“œ ์†๋„ ์ธก๋ฉด์—์„œ ๊ฐœ๋ฐœ ํšจ์œจ์ด ์ข‹์•„์ง

5. ๊ฒฐ๋ก 

  • Devths๋Š” ๋žœ๋”ฉ์€ SSG, ๋กœ๊ทธ์ธ ์ดํ›„ ์˜์—ญ์€ CSR๋กœ ์šด์˜๋˜๋Š” ๊ตฌ์กฐ์ด๋ฉฐ, ์บ˜๋ฆฐ๋”/๊ฒŒ์‹œํŒ/์ฑ—๋ด‡/์ฑ„ํŒ…์ฒ˜๋Ÿผ ํŽ˜์ด์ง€ ์ˆ˜์™€ ๊ณตํ†ต ๋ ˆ์ด์•„์›ƒ(ํ—ค๋”/ํ‘ธํ„ฐ)์ด ๋งŽ์€ ์„œ๋น„์Šค์ž„
  • ๋ผ์šฐํŒ…, ๋ ˆ์ด์•„์›ƒ, ๋กœ๋”ฉ/์—๋Ÿฌ UI ๊ฐ™์€ ์•ฑ์˜ ๊ณจ๊ฒฉ์„ ํ”„๋ ˆ์ž„์›Œํฌ ์ฐจ์›์—์„œ ํ‘œ์ค€ํ™”ํ•ด์ฃผ๋Š” Next.js(App Router)๊ฐ€ ๊ตฌ์กฐ๋ฅผ ์•ˆ์ •์ ์œผ๋กœ ์œ ์ง€ํ•˜๋Š” ๋ฐ ์ ํ•ฉํ•จ
  • ๋˜ํ•œ Next.js 16์€ Turbopack์˜ ๋นŒ๋“œ ์•ˆ์ •ํ™”์™€ ๋ผ์šฐํŒ…/ํ”„๋ฆฌํŒจ์น˜ ์ตœ์ ํ™” ๊ฐ•ํ™”๋กœ, ๊ฐœ๋ฐœ, ๋ฐฐํฌ ๊ณผ์ •์˜ ํšจ์œจ๊ณผ ํŽ˜์ด์ง€ ์ „ํ™˜ ์ฒด๊ฐ์„ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ์–ด Devths์˜ SSG + CSR ์ „๋žต๊ณผ ์ž˜ ๋งž์Œ

๐Ÿ”ง ์ƒํƒœ ๊ด€๋ฆฌ ์ „๋žต

โœ… ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - Zustand v5.0.9

1. ํŠน์ง• ์š”์•ฝ

  • ๊ฐ€๋ณ๊ณ  ๋‹จ์ˆœํ•œ ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ
    • Redux์ฒ˜๋Ÿผ ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ๊ฐ€ ๋งŽ์ง€ ์•Š๊ณ , ํ•„์š”ํ•œ ์ƒํƒœ๋งŒ ๋น ๋ฅด๊ฒŒ ์ „์—ญ์œผ๋กœ ์˜ฌ๋ ค ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Œ
  • Hooks ๊ธฐ๋ฐ˜ API๋กœ ์‚ฌ์šฉ์ด ์ง๊ด€์ 
    • useStore() ํ˜•ํƒœ๋กœ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ฐ”๋กœ ์ƒํƒœ๋ฅผ ์ฝ๊ณ /๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์–ด React ๊ฐœ๋ฐœ ํ๋ฆ„๊ณผ ์ž˜๋งž์Œ
  • ์„ ํƒ ๊ตฌ๋…(Selector)๋กœ ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง ๊ฐ์†Œ
    • ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ•„์š”ํ•œ ์ƒํƒœ๋งŒ ์„ ํƒ์• ์„œ ๊ตฌ๋…ํ•  ์ˆ˜ ์žˆ์–ด, ์ƒํƒœ๊ฐ€ ์ž์ฃผ ๋ฐ”๋€Œ๋Š” ํ™”๋ฉด(์ฑ„ํŒ…/์•Œ๋ฆผ ๋“ฑ)์—์„œ๋„ ์„ฑ๋Šฅ ๊ด€๋ฆฌ๊ฐ€ ์‰ฌ์›€
  • ์ƒํƒœ์™€ ์•ก์…˜์„ ํ•œ ํŒŒ์ผ์— ์‘์ง‘
    • ์ƒํƒœ(state)์™€ ์ƒํƒœ ๋ณ€๊ฒฝ ํ•จ์ˆ˜(action)๋ฅผ ๊ฐ€๊นŒ์ด ๋‘๊ณ  ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด ์–ด๋””์„œ ์ƒํƒœ๊ฐ€ ๋ฐ”๋€Œ๋Š”์ง€ ์ถ”์ ์ด ์‰ฌ์›€
  • ๋ฏธ๋“ค์›จ์–ด ์ง€์›
    • persist(๋กœ์ปฌ ์ €์žฅ), devtools(๋””๋ฒ„๊น…), subscribeWithSelector ๋“ฑ ํ™•์žฅ ๊ธฐ๋Šฅ์„ ๋ถ™์—ฌ ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž๊ฒŒ ๊ตฌ์„ฑ ๊ฐ€๋Šฅ

2. devths์— ์ด ๊ธฐ์ˆ ์ด ํ•„์š”ํ•œ ์ด์œ 

๐Ÿ’ก
  • Devths๋Š” ์บ˜๋ฆฐ๋”ยท๊ฒŒ์‹œํŒยท์ฑ„ํŒ…ยท์ฑ—๋ด‡์ฒ˜๋Ÿผ ๊ธฐ๋Šฅ์ด ๋งŽ๊ณ , ํŽ˜์ด์ง€๋ฅผ ๋„˜๋‚˜๋“ค๋ฉฐ ๊ณต์œ ํ•ด์•ผ ํ•˜๋Š” ์ƒํƒœ๊ฐ€ ๋งŽ์Œ.
    • React์˜ useState๋งŒ์œผ๋กœ๋„ ์ƒํƒœ ๊ด€๋ฆฌ๋Š” ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ์ „์—ญ์œผ๋กœ ๊ณต์œ ๋˜๋Š” ์ƒํƒœ๋ฅผ ํŽ˜์ด์ง€/์ปดํฌ๋„ŒํŠธ๋งˆ๋‹ค props๋กœ ์ „๋‹ฌํ•˜๋ฉด ๊ตฌ์กฐ๊ฐ€ ๋ณต์žกํ•ด์ง€๊ณ  ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์–ด๋ ค์›Œ์ง.
    • ๋”ฐ๋ผ์„œ Devths์—์„œ๋Š” Zustand๋กœ ์•ฑ ์ „์ฒด์—์„œ ๊ณต์œ ๋˜๋Š” ์ƒํƒœ๋ฅผ ํ•œ ๊ณณ์—์„œ ์ผ๊ด€๋˜๊ฒŒ ๊ด€๋ฆฌํ•  ํ•„์š”๊ฐ€ ์žˆ์Œ.

(1) ๋กœ๊ทธ์ธ/์œ ์ € ์ •๋ณด์ฒ˜๋Ÿผ ์•ฑ ์ „์—ญ์—์„œ ์ฐธ์กฐ๋˜๋Š” ์ƒํƒœ๊ฐ€ ์กด์žฌํ•จ

  • ํ—ค๋”(ํ”„๋กœํ•„ ํ‘œ์‹œ), ๊ฒŒ์‹œํŒ(์ž‘์„ฑ์ž ์ •๋ณด), ์ฑ„ํŒ…(๋ฐœ์‹ ์ž/๊ถŒํ•œ), ์ฑ—๋ด‡(๊ฐœ์ธํ™”) ๋“ฑ ์—ฌ๋Ÿฌ ํ™”๋ฉด์—์„œ ๋™์ผํ•œ ์œ ์ € ์ •๋ณด๊ฐ€ ํ•„์š”ํ•จ

    โ†’ me, isLoggedIn ๊ฐ™์€ ๊ฐ’์„ ์ „์—ญ์œผ๋กœ ๋‘๋ฉด ์ค‘๋ณต ์กฐํšŒ/props ์ „๋‹ฌ์„ ์ค„์ด๊ณ  UI ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Œ

(2) ์ „์—ญ UI ์ƒํƒœ(๋ชจ๋‹ฌ/ํ† ์ŠคํŠธ/๋กœ๋”ฉ)๋ฅผ ์ผ๊ด€๋˜๊ฒŒ ์ œ์–ดํ•ด์•ผ ํ•จ

  • ์˜ˆ: ์ฑ„์šฉ๊ณต๊ณ  ์—…๋กœ๋“œ ํ›„ OCR ์ฒ˜๋ฆฌ ์‹œ โ€œ๋Œ€๊ธฐ ๋ชจ๋‹ฌโ€, ์ฒ˜๋ฆฌ ์‹คํŒจ ์‹œ โ€œ์—๋Ÿฌ ํ† ์ŠคํŠธโ€, ์™„๋ฃŒ ์‹œ โ€œ๊ฒฐ๊ณผ ๊ฒ€ํ†  ๋ชจ๋‹ฌโ€ ๋“ฑ

    โ†’ ์ „์—ญ UI ์ƒํƒœ๋ฅผ Zustand๋กœ ๊ด€๋ฆฌํ•˜๋ฉด ์–ด๋А ํŽ˜์ด์ง€์—์„œ๋“  ๋™์ผํ•œ UX ํŒจํ„ด์œผ๋กœ ์—ด๊ณ  ๋‹ซ์„ ์ˆ˜ ์žˆ์Œ

(3) ์ฑ„ํŒ…์ฒ˜๋Ÿผ ์ƒํƒœ ๋ณ€ํ™”๊ฐ€ ์žฆ์€ ๊ธฐ๋Šฅ์—์„œ ์„ฑ๋Šฅ/๊ตฌ์กฐ ๊ด€๋ฆฌ๊ฐ€ ์ค‘์š”ํ•จ

  • ์ฑ„ํŒ… ๋ฉ”์‹œ์ง€/์ฝ์ง€ ์•Š์€ ์ˆ˜/์—ฐ๊ฒฐ ์ƒํƒœ๋Š” ๋งค์šฐ ์ž์ฃผ ๋ฐ”๋€Œ๋ฉฐ, ์ž˜๋ชป ๊ด€๋ฆฌํ•˜๋ฉด ํ™”๋ฉด ์ „์ฒด๊ฐ€ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋ฆฌ๋ Œ๋”๋ง๋  ์ˆ˜ ์žˆ์Œ

    โ†’ Zustand์˜ Selector(์„ ํƒ ๊ตฌ๋…) ๋ฅผ ํ™œ์šฉํ•˜๋ฉด ํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ๋งŒ ์ƒํƒœ๋ฅผ ๊ตฌ๋…ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ์„ฑ๋Šฅ์„ ์•ˆ์ •์ ์œผ๋กœ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Œ

(4) ๊ธฐ๋Šฅ์ด ํ™•์žฅ๋ ์ˆ˜๋ก โ€œ์ƒํƒœ ๋ณ€๊ฒฝ ์œ„์น˜โ€๋ฅผ ์ถ”์ ํ•˜๊ธฐ ์–ด๋ ค์›Œ์ง

  • ์ผ์ • ์ถ”๊ฐ€, ์ข‹์•„์š” ํ† ๊ธ€, ์ฑ„ํŒ… ์ˆ˜์‹  ๋“ฑ ์ƒํƒœ ๋ณ€๊ฒฝ์ด ์—ฌ๊ธฐ์ €๊ธฐ์„œ ๋ฐœ์ƒํ•˜๋ฉด ์›์ธ ์ถ”์ ์ด ์–ด๋ ค์›€

    โ†’ Zustand๋Š” ์ƒํƒœ์™€ ์•ก์…˜์„ ํ•œ ์Šคํ† ์–ด์— ์‘์ง‘์‹œ์ผœ ๋ณ€๊ฒฝ ๊ฒฝ๋กœ๋ฅผ ๋‹จ์ˆœํ™”ํ•˜๊ณ  ๋””๋ฒ„๊น…์„ ์‰ฝ๊ฒŒ ํ•จ

(5) ๋ฏธ๋“ค์›จ์–ด๋กœ Devths ์š”๊ตฌ์‚ฌํ•ญ์„ ๋น ๋ฅด๊ฒŒ ์ถฉ์กฑ ๊ฐ€๋Šฅํ•จ

  • persist: ๋กœ๊ทธ์ธ ์ƒํƒœ/์‚ฌ์šฉ์ž ์„ค์ •์„ ๋กœ์ปฌ์— ์ €์žฅํ•ด ์ƒˆ๋กœ๊ณ ์นจ์—๋„ ์œ ์ง€

  • devtools: ์ƒํƒœ ๋ณ€ํ™” ์ถ”์ (๋ฒ„๊ทธ ์žฌํ˜„/์›์ธ ํŒŒ์•…)

  • subscribeWithSelector: ํŠน์ • ์ƒํƒœ ๋ณ€ํ™”์—๋งŒ ๋ฐ˜์‘(์˜ˆ: unreadCount ๋ณ€ํ•  ๋•Œ๋งŒ ๋ฑƒ์ง€ ์—…๋ฐ์ดํŠธ)

    โ†’ โ€œ์ถ”๊ฐ€ ๊ตฌํ˜„โ€ ์—†์ด๋„ ํ•ต์‹ฌ UX๋ฅผ ๋น ๋ฅด๊ฒŒ ์•ˆ์ •ํ™”ํ•  ์ˆ˜ ์žˆ์Œ

3. Zustand์— ์˜ฌ๋ฆด ์ƒํƒœ

(1) Zustand์— ์˜ฌ๋ฆด ์ƒํƒœ

  • ์ธ์ฆ/์œ ์ €

    • isLoggedIn (๋กœ๊ทธ์ธ ์—ฌ๋ถ€)
    • me (๋‚ด ์œ ์ € ์ •๋ณด: id, name, avatarUrl ๋“ฑ)
  • ์ „์—ญ UI ์ƒํƒœ (ํŽ˜์ด์ง€๊ฐ€ ๋‹ฌ๋ผ๋„ ๋™์ผ UX)

    • ์ „์—ญ ๋ชจ๋‹ฌ ์ƒํƒœ
    • ํ† ์ŠคํŠธ
    • ๊ณตํ†ต ๋‹ค์ด์–ผ๋กœ๊ทธ: ํ™•์ธ/์ทจ์†Œ ๋ชจ๋‹ฌ ์ƒํƒœ
    • ๋ ˆ์ด์•„์›ƒ ์ƒํƒœ

    โ‡’ ํŽ˜์ด์ง€ ์ƒ๊ด€์—†์ด ๋œจ๋Š” UI๋Š” ํ•œ ๊ณณ์—์„œ ์ œ์–ดํ•˜๋Š” ๊ฒŒ ๊น”๋”ํ•จ

  • ์ฑ„ํŒ… (์‹ค์‹œ๊ฐ„ UI ์ค‘์‹ฌ)

    • activeRoomId (ํ˜„์žฌ ๋ณด๊ณ  ์žˆ๋Š” ๋ฐฉ)
    • socketStatus (connected / reconnecting / disconnected)

    โ‡’ ์‹ค์‹œ๊ฐ„ UI๋Š” ๋น ๋ฅด๊ฒŒ ์ƒํƒœ ๋ฐ˜์˜์ด ์ค‘์š”ํ•˜๊ณ , ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ(๋ฐฉ ๋ชฉ๋ก/์ฑ„ํŒ…์ฐฝ)์—์„œ ๋™์‹œ์— ์”€

  • ์‚ฌ์šฉ์ž ์„ค์ •

    • ์บ˜๋ฆฐ๋” ๋ทฐ ์„ค์ •(์›”/์ฃผ ๊ธฐ๋ณธ๊ฐ’), ํ•„ํ„ฐ(ํƒœ๊ทธ/์นดํ…Œ๊ณ ๋ฆฌ) ๊ธฐ๋ณธ๊ฐ’

    โ‡’ ์ƒˆ๋กœ๊ณ ์นจ/์žฌ์ ‘์†์—๋„ ์œ ์ง€๋˜๋ฉด UX๊ฐ€ ์ข‹์•„์„œ persist๋ž‘ ๊ถํ•ฉ ์ข‹์Œ

(2) ๋กœ์ปฌ(useState)๋กœ ๋‘๋Š” ๊ฒŒ ์ข‹์€ ์ƒํƒœ (ํ•œ ํ™”๋ฉด/ํ•œ ์ปดํฌ๋„ŒํŠธ ์ „์šฉ)

  • ํผ ์ž…๋ ฅ๊ฐ’
    • ๋กœ๊ทธ์ธ/ํšŒ์›๊ฐ€์ž… ํผ ๊ฐ’
    • ๊ธ€ ์ž‘์„ฑ ํผ ๊ฐ’(์ œ๋ชฉ/๋ณธ๋ฌธ/ํƒœ๊ทธ ์ž…๋ ฅ ์ค‘)
    • ํ”„๋กœํ•„ ์ˆ˜์ • ํผ ๊ฐ’

4. ๋‹ค๋ฅธ ์Šคํƒ๊ณผ ๋น„๊ต

ํ•ญ๋ชฉ Zustand Jotai Recoil Redux Toolkit React Context
์„ค์ • ๋ณต์žก๋„ ๋งค์šฐ ๋‚ฎ์Œ ๋‚ฎ์Œ ๋ณดํ†ต ๋น„๊ต์  ๋†’์Œ ๋‚ฎ์Œ(๋‹จ, ๊ตฌ์กฐ ์„ค๊ณ„๋Š” ํ•„์š”)
๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ ์ ์Œ ์ ์Œ ๋ณดํ†ต ๋งŽ์Œ ์—†์Œ
์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ ์ ํ•ฉ์„ฑ ๋†’์Œ(UI ์ƒํƒœ์— ํŠนํžˆ ๊ฐ•ํ•จ) ๋†’์Œ(์ƒํƒœ๋ฅผ ์ž˜๊ฒŒ ์ชผ๊ฐœ๊ธฐ ์ข‹์Œ) ๋†’์Œ(ํŒŒ์ƒ/์˜์กด ์ƒํƒœ์— ๊ฐ•์ ) ๋งค์šฐ ๋†’์Œ(ํ‘œ์ค€ํ™”ยท๊ทœ๋ชจ์— ๊ฐ•ํ•จ) ์ค‘๊ฐ„(๊ฐ„๋‹จํ•œ ์ „์—ญ ๊ณต์œ ์— ์ ํ•ฉ)
๋ฆฌ๋ Œ๋”๋ง ์ œ์–ด ์šฐ์ˆ˜(์„ ํƒ ๊ตฌ๋…) ์šฐ์ˆ˜(atom ๋‹จ์œ„) ์šฐ์ˆ˜(์˜์กด์„ฑ ๊ธฐ๋ฐ˜) ์šฐ์ˆ˜(์…€๋ ‰ํ„ฐ/๋ฉ”๋ชจํ™” ๋“ฑ ์กฐํ•ฉ) ๊นŒ๋‹ค๋กœ์›€(Provider ๊ฐ’ ๋ณ€๊ฒฝ ์‹œ ์˜ํ–ฅ ํผ)
Devths ์ ํ•ฉ๋„ UI ์ „์—ญ ์ƒํƒœ์— ์ตœ์  UI ์ƒํƒœ/๊ฐ„๋‹จ ์ „์—ญ๋„ ๊ฐ€๋Šฅ, atom ๊ด€๋ฆฌ ๊ทœ์น™ ํ•„์š” ์ƒํƒœ ๊ด€๊ณ„๊ฐ€ ๋ณต์žกํ•  ๋•Œ ์œ ๋ฆฌ, ๊ตฌ์กฐ๊ฐ€ ์ปค์ง€๋ฉด ์„ค๊ณ„ ๋ถ€๋‹ด ๊ทœ๋ชจ ๋Œ€๋น„ ๋‹ค์†Œ ๋ฌด๊ฑฐ์šธ ์ˆ˜ ์žˆ์Œ(๊ทœ์น™ยท์ฝ”๋“œ๋Ÿ‰ ์ฆ๊ฐ€) ์ƒํƒœ ๋งŽ์•„์ง€๋ฉด ๋ฆฌ๋ Œ๋”๋ง/๊ตฌ์กฐ ๊ด€๋ฆฌ๊ฐ€ ์–ด๋ ค์›€
  • UI ์ „์—ญ ์ƒํƒœ์˜ ํ‘œ์ค€ํ™”(Prop Drilling ๋ฐฉ์ง€)

    • Redux Toolkit์€ ์ „์—ญ ์ƒํƒœ๋ฅผ ์ฒด๊ณ„์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์•ก์…˜/์Šฌ๋ผ์ด์Šค/๋””์ŠคํŒจ์น˜ ๋“ฑ ์ „์—ญ ์ƒํƒœ ์šด์˜์„ ์œ„ํ•œ ๊ตฌ์กฐ๋ฅผ ๋จผ์ € ์žก์•„์•ผ ํ•ด์„œ UI ์ƒํƒœ(ํ† ์ŠคํŠธ, ๋ชจ๋‹ฌ, ํƒญ) ์ค‘์‹ฌ์˜ ์š”๊ตฌ์—์„œ๋Š” ์ดˆ๊ธฐ ์ฝ”๋“œ๋Ÿ‰๊ณผ ์šด์˜ ๊ทœ์น™์ด ๋น ๋ฅด๊ฒŒ ๋Š˜์–ด๋‚  ์ˆ˜ ์žˆ์Œ.

    • ํ™”๋ฉด์ด ๋งŽ์•„์งˆ์ˆ˜๋ก ์ƒํƒœ ์ถ”๊ฐ€ ์ž์ฒด์˜ ๋ถ€๋‹ด์ด ์ปค์ง€๊ณ , ๋‹จ์ˆœ UI ์ƒํƒœ์—๋„ ํŒจํ„ด์„ ๊ณผํ•˜๊ฒŒ ์ ์šฉํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Œ

      โ†”๏ธ ๋ฐ˜๋ฉด Zustand๋Š” ์Šคํ† ์–ด ํ•˜๋‚˜์— ์ƒํƒœ์™€ ์—…๋ฐ์ดํŠธ ํ•จ์ˆ˜๋ฅผ ํ•จ๊ป˜ ๋‘๋Š” ๋ฐฉ์‹์œผ๋กœ UI ์ „์—ญ ์ƒํƒœ๋ฅผ ๋น ๋ฅด๊ฒŒ ํ‘œ์ค€ํ™”ํ•  ์ˆ˜ ์žˆ์–ด, Devths์ฒ˜๋Ÿผ ํ† ์ŠคํŠธ/์ „์—ญ ๋ชจ๋‹ฌ/ํƒญ ํ™œ์„ฑ/ํ•„ํ„ฐ ์—ด๋ฆผ ๋“ฑ โ€œ๊ณต์œ  UI ์ƒํƒœโ€๊ฐ€ ๋งŽ์€ ์„œ๋น„์Šค์—์„œ ๊ตฌํ˜„ ๋ฐฉ์‹์ด ํ”๋“ค๋ฆฌ์ง€ ์•Š๋„๋ก ๋งŒ๋“ค๊ธฐ ์œ ๋ฆฌํ•จ.

  • ๋ฆฌ๋ Œ๋”๋ง/์„ฑ๋Šฅ ๊ด€๋ฆฌ์˜ ์‹ค์šฉ์„ฑ

    • React Context๋Š” ๋„์ž…์ด ๊ฐ„๋‹จํ•˜์ง€๋งŒ, Provider์˜ value๊ฐ€ ๋ฐ”๋€Œ๋ฉด ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋„“๊ฒŒ ์˜ํ–ฅ์„ ๋ฐ›๊ธฐ ์‰ฌ์›Œ(๊ตฌ์กฐ์— ๋”ฐ๋ผ) ์ƒํƒœ๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ๋ฆฌ๋ Œ๋”๋ง ๋ฒ”์œ„๋ฅผ ์˜ˆ์ธกยทํ†ต์ œํ•˜๊ธฐ๊ฐ€ ์–ด๋ ค์›Œ์งˆ ์ˆ˜ ์žˆ์Œ.

    • ํŠนํžˆ ์ „์—ญ UI ์ƒํƒœ๊ฐ€ ์ž์ฃผ ๋ฐ”๋€Œ๋Š” ๊ฒฝ์šฐ(ํ† ์ŠคํŠธ ํ, ๋ชจ๋‹ฌ ์—ด๋ฆผ/๋‹ซํž˜, ํƒญ ์ „ํ™˜) ์„ฑ๋Šฅ ์ด์Šˆ๋กœ ์ด์–ด์งˆ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Œ

      โ†”๏ธ ๋ฐ˜๋ฉด Zustand๋Š” โ€œํ•„์š”ํ•œ ์ƒํƒœ๋งŒ ์„ ํƒํ•ด์„œ ๊ตฌ๋…โ€ํ•˜๋Š” ๋ฐฉ์‹์ด ๊ธฐ๋ณธ์ด๋ผ, ์‹ค์ œ๋กœ ์‚ฌ์šฉ ์ค‘์ธ ๊ฐ’์ด ๋ฐ”๋€” ๋•Œ๋งŒ ๋ฆฌ๋ Œ๋”๋ง๋˜๋„๋ก ๊ตฌ์„ฑํ•˜๊ธฐ ์‰ฝ๊ณ , UI ์ƒํ˜ธ์ž‘์šฉ์ด ๋งŽ์€ Devths์—์„œ ์ฒด๊ฐ ์„ฑ๋Šฅ๊ณผ ๊ตฌํ˜„ ๋‚œ์ด๋„ ์‚ฌ์ด์˜ ๊ท ํ˜•์ด ์ข‹์Œ

  • ํŒ€ ๊ฐœ๋ฐœ/์œ ์ง€๋ณด์ˆ˜ ๊ด€์ ์˜ ๋ˆ„์  ๋น„์šฉ

    • Recoil/Jotai๋Š” atom ๋‹จ์œ„๋กœ ์ƒํƒœ๋ฅผ ์ชผ๊ฐœ๊ธฐ ์‰ฌ์›Œ ์œ ์—ฐํ•˜์ง€๋งŒ, ํ”„๋กœ์ ํŠธ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก atom ์„ค๊ณ„/๋ช…๋ช…/์˜์กด ๊ด€๊ณ„(ํŒŒ์ƒ ์ƒํƒœ ํฌํ•จ)์— ๋Œ€ํ•œ ํŒ€ ๊ทœ์น™์ด ํ•„์š”ํ•ด์ง€๊ณ , ๊ด€๋ฆฌ ๊ธฐ์ค€์ด ์•ฝํ•˜๋ฉด ์ƒํƒœ๊ฐ€ ๋ถ„์‚ฐ๋˜์–ด ์–ด๋””์— ๋ญ๊ฐ€ ์žˆ๋Š”์ง€ ์ถ”์  ๋น„์šฉ์ด ์ปค์งˆ ์ˆ˜ ์žˆ์Œ

      โ†”๏ธ ๋ฐ˜๋ฉด Zustand๋Š” โ€˜UI ์ „์—ญ ์ƒํƒœ๋Š” ์ด ์Šคํ† ์–ด(๋˜๋Š” ๋ช‡ ๊ฐœ ์Šคํ† ์–ด)์—์„œ ๊ด€๋ฆฌํ•œ๋‹คโ€™์ฒ˜๋Ÿผ ์ฑ…์ž„ ๋ฒ”์œ„๋ฅผ ๋ช…ํ™•ํžˆ ์žก๊ธฐ ์‰ฌ์›Œ, ํ™”๋ฉด ์ˆ˜๊ฐ€ ๋Š˜์–ด๋„ ์ƒํƒœ ์œ„์น˜์™€ ๋ณ€๊ฒฝ ์ง€์ ์„ ์ฐพ๋Š” ๋น„์šฉ์ด ์ƒ๋Œ€์ ์œผ๋กœ ๋‚ฎ๊ณ , Devths์˜ UI ์ „์—ญ ์ƒํƒœ ์šด์˜์— ๋” ์ ํ•ฉํ•˜๋‹ค๊ณ  ํŒ๋‹จํ•จ

5. ๋ฒ„์ „ ์„ ํƒ ์ด์œ 

  • v5.0.9
    • 2025๋…„ 11์›” 30์ผ์— ๋ฆด๋ฆฌ์ฆˆ
  • ์ด์œ 
    • React 18+๋ฅผ ์ตœ์†Œ๋กœ ๋งž์ถฐ ํ˜„๋Œ€ React/Next ํ™˜๊ฒฝ์— ๋งž๋Š” ์šด์˜์„ ์ „์ œ๋กœ ํ•จ
    • ๊ฐ€์žฅ ์ตœ์‹  ํŒจ์น˜(5.0.9) ๋ฅผ ๊ณ ์ •ํ•ด์„œ, ๋™์ผ ๋ฉ”์ด์ € ๋‚ด ๋ฒ„๊ทธ ์ˆ˜์ •/๊ฐœ์„ ๋ถ„์„ ์ตœ๋Œ€ํ•œ ๋ฐ˜์˜
    • ๋งค์šฐ ์ž‘์€ ๋ฒˆ๋“ค ํฌ๊ธฐ(๊ฒฝ๋Ÿ‰)๋กœ ์ „์—ญ ์ƒํƒœ๋ฅผ ๋ถ™์ผ ์ˆ˜ ์žˆ์Œ
    • persist/shallow ๋“ฑ ์ž์ฃผ ์“ฐ๋Š” ์œ ํ‹ธ/๋ฏธ๋“ค์›จ์–ด ์ชฝ ๋ฒ„๊ทธ/๊ฐœ์„ ์ด ํŒจ์น˜๋กœ ๋ˆ„์ ๋จ

6. ๊ฒฐ๋ก 

๐Ÿ’ก

Devths๋Š” ์บ˜๋ฆฐ๋”ยท๊ฒŒ์‹œํŒยท์ฑ„ํŒ…ยท์ฑ—๋ด‡์ฒ˜๋Ÿผ ๊ธฐ๋Šฅ์ด ๋งŽ๊ณ , ํ™”๋ฉด์„ ๋„˜๋‚˜๋“ค๋ฉฐ ๊ณต์œ ํ•ด์•ผ ํ•˜๋Š” ์ƒํƒœ(์ธ์ฆ/์œ ์ €, ์ „์—ญ UI, ์ฑ„ํŒ… ์—ฐ๊ฒฐ ์ƒํƒœ ๋“ฑ)๊ฐ€ ๋ฐ˜๋ณต์ ์œผ๋กœ ๋ฐœ์ƒํ•œ๋‹ค. ์ด ์ƒํƒœ๋“ค์„ useState + props ์ „๋‹ฌ๋กœ๋งŒ ๊ด€๋ฆฌํ•˜๋ฉด prop drilling์ด ๋Š˜๊ณ , ์ƒํƒœ ๋ณ€๊ฒฝ ์ง€์ ์„ ์ถ”์ ํ•˜๊ธฐ ์–ด๋ ค์›Œ์ง€๋ฉฐ, ํ™”๋ฉด์ด ๋งŽ์•„์งˆ์ˆ˜๋ก ์œ ์ง€๋ณด์ˆ˜ ๋น„์šฉ์ด ๊ธ‰๊ฒฉํžˆ ์ฆ๊ฐ€ํ•œ๋‹ค.

๋”ฐ๋ผ์„œ Devths์—์„œ๋Š” Zustand๋ฅผ ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ ๋„๊ตฌ๋กœ ์ฑ„ํƒํ•˜์—ฌ

  • ์ธ์ฆ/์œ ์ € ์ •๋ณด๋ฅผ ์•ฑ ์ „๋ฐ˜์—์„œ ์ผ๊ด€๋˜๊ฒŒ ์ฐธ์กฐํ•˜๊ณ ,
  • ๋ชจ๋‹ฌ/ํ† ์ŠคํŠธ/๋กœ๋”ฉ ๊ฐ™์€ ์ „์—ญ UI ์ƒํƒœ๋ฅผ ํ‘œ์ค€ํ™”ํ•˜๋ฉฐ,
  • ์ฑ„ํŒ…์ฒ˜๋Ÿผ ์ƒํƒœ ๋ณ€ํ™”๊ฐ€ ์žฆ์€ ๊ธฐ๋Šฅ์—์„œ Selector ๊ธฐ๋ฐ˜ ๊ตฌ๋…์œผ๋กœ ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง์„ ์ค„์—ฌ ์„ฑ๋Šฅ์„ ์•ˆ์ •ํ™”ํ•จ

๋˜ํ•œ persist, devtools, subscribeWithSelector ๊ฐ™์€ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ํ™œ์šฉํ•ด ์ƒˆ๋กœ๊ณ ์นจ ์ƒํƒœ ์œ ์ง€, ๋””๋ฒ„๊น…, ํŠน์ • ์ƒํƒœ ๋ณ€ํ™” ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ๋น ๋ฅด๊ฒŒ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์–ด, Devths์˜ ์š”๊ตฌ์‚ฌํ•ญ์„ ํšจ์œจ์ ์œผ๋กœ ์ถฉ์กฑํ•  ์ˆ˜ ์žˆ์Œ

โ‡’ ๊ฒฐ๋ก ์ ์œผ๋กœ Zustand๋Š” Devths์—์„œ ๊ณต์œ  ์ƒํƒœ๋ฅผ ๋‹จ์ˆœํ•˜๊ณ  ์ผ๊ด€๋˜๊ฒŒ ๊ด€๋ฆฌํ•˜๋ฉด์„œ๋„, ์„ฑ๋Šฅ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ํ•จ๊ป˜ ํ™•๋ณดํ•  ์ˆ˜ ์žˆ๋Š” ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์ ํ•ฉํ•จ

โœ… ์„œ๋ฒ„ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - TanStack Query(React Query) v5.90.12

1. ํŠน์ง• ์š”์•ฝ

  • ์„œ๋ฒ„ ์ƒํƒœ(Server State) ์ „์šฉ ๊ด€๋ฆฌ
    • ์„œ๋ฒ„์—์„œ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐ์ดํ„ฐ(๋ชฉ๋ก/์ƒ์„ธ/๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ)๋ฅผ ์ „์—ญ ์ƒํƒœ๋กœ ์ง์ ‘ ๋“ค๊ณ  ์žˆ์ง€ ์•Š์•„๋„, Query๊ฐ€ ์บ์‹œ + ๋™๊ธฐํ™”๋ฅผ ๋‹ด๋‹นํ•ด์คŒ
  • ์บ์‹ฑ(Caching) + ์ž๋™ ์žฌ์กฐํšŒ(Refetch)
    • ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ์จ๋„ ์ค‘๋ณต ํ˜ธ์ถœ์„ ์ค„์ด๊ณ , ์–ธ์ œ ๋‹ค์‹œ ๊ฐ€์ ธ์˜ฌ์ง€ ์ „๋žต์„ ์„ธ์šธ ์ˆ˜ ์žˆ์Œ(์˜ˆ: staleTime)
  • Mutation(๋ณ€๊ฒฝ) ์ดํ›„ ์บ์‹œ ๋ฌดํšจํ™”(invalidate) ํŒจํ„ด ์ œ๊ณต
    • ๊ธ€ ์ž‘์„ฑ/์ˆ˜์ •/์‚ญ์ œ, ์ผ์ • ์ถ”๊ฐ€/์ˆ˜์ • ๊ฐ™์€ ๋ณ€๊ฒฝ ์ดํ›„์— ๊ด€๋ จ ๋ชฉ๋ก์„ ๋˜‘๋˜‘ํ•˜๊ฒŒ stale ์ฒ˜๋ฆฌํ•˜๊ณ  ์žฌ์กฐํšŒ ๊ฐ€๋Šฅ
  • ๋ฌดํ•œ ์Šคํฌ๋กค(useInfiniteQuery) ์ง€์›
    • ๊ฒŒ์‹œํŒ/๋Œ“๊ธ€/์ฑ„ํŒ… ํžˆ์Šคํ† ๋ฆฌ์ฒ˜๋Ÿผ ํŽ˜์ด์ง€๊ฐ€ ๊ธธ์–ด์ง€๋Š” UI์— ํ‘œ์ค€ ํŒจํ„ด ์ œ๊ณต (v5์—์„œ๋Š” maxPages๋กœ ์ €์žฅ ํŽ˜์ด์ง€ ์ˆ˜ ์ œํ•œ ๊ฐ€๋Šฅ)
  • ๋กœ๋”ฉ/์—๋Ÿฌ/์žฌ์‹œ๋„ ๋“ฑ ๋น„๋™๊ธฐ ์ƒํƒœ ์ฒ˜๋ฆฌ ํ‘œ์ค€ํ™”
    • isPending, isError ๊ฐ™์€ ์ƒํƒœ๋กœ UI๋ฅผ ์ผ๊ด€๋˜๊ฒŒ ๊ตฌ์„ฑ ๊ฐ€๋Šฅ
  • v5์˜ API ๋‹จ์ˆœํ™”(๊ฐ์ฒด ์‹œ๊ทธ๋‹ˆ์ฒ˜ ์ค‘์‹ฌ)
    • v5๋Š” API๋ฅผ ๋” ๋‹จ์ˆœ/์ง๊ด€์ ์œผ๋กœ ์ •๋ฆฌํ•˜๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ๊ฐœ์„ ๋จ

3. devths์— ์ด ๊ธฐ์ˆ ์ด ํ•„์š”ํ•œ ์ด์œ 

๐Ÿ’ก
  • Devths๋Š” ์„œ๋ฒ„์—์„œ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ๊ณ , ๋ชฉ๋ก/์ƒ์„ธ/๋ฌดํ•œ์Šคํฌ๋กค/๊ฒ€์ƒ‰/์ˆ˜์ • ํ›„ ๊ฐฑ์‹  ๊ฐ™์€ ํŒจํ„ด์ด ๋ฐ˜๋ณต๋จ.
    • ์ด๋ฅผ useEffect + fetch๋กœ ํ™”๋ฉด๋งˆ๋‹ค ์ง์ ‘ ๊ตฌํ˜„ํ•˜๋ฉด ์บ์‹ฑ/๋™๊ธฐํ™”/๋กœ๋”ฉยท์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋กœ์ง์ด ๋ถ„์‚ฐ๋˜์–ด ์œ ์ง€๋ณด์ˆ˜ ๋น„์šฉ์ด ๋น ๋ฅด๊ฒŒ ์ฆ๊ฐ€ํ•จ
    • TanStack Query๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์„œ๋ฒ„ ์ƒํƒœ๋ฅผ ํ‘œ์ค€ ๋ฐฉ์‹์œผ๋กœ ๊ด€๋ฆฌํ•ด ์ฝ”๋“œ ์ค‘๋ณต๊ณผ ๋ฒ„๊ทธ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์Œ

(1) ๊ฒŒ์‹œํŒ: ๊ธ€ ๋ชฉ๋ก(๋ฌดํ•œ์Šคํฌ๋กค), ์ƒ์„ธ, ๋Œ“๊ธ€, ์ข‹์•„์š” ํ† ๊ธ€ ํ›„ ๋ชฉ๋ก/์ƒ์„ธ ๋™๊ธฐํ™”

(2) ์บ˜๋ฆฐ๋”: ์›”/์ฃผ ๋‹จ์œ„ ์ผ์ • ์กฐํšŒ + CRUD ์ดํ›„ ์ฆ‰์‹œ ๊ฐฑ์‹ 

(3) ์บ˜๋ฆฐ๋” AI(OCR): ์—…๋กœ๋“œ โ†’ ์ฒ˜๋ฆฌ ์ƒํƒœ(job) ํ™•์ธ โ†’ ๊ฒฐ๊ณผ ์ดˆ์•ˆ(draft) ์กฐํšŒ/ํ™•์ •(๋น„๋™๊ธฐ ํ๋ฆ„)

(4) ์ฑ„ํŒ…: ์‹ค์‹œ๊ฐ„ ์ˆ˜์‹ ์€ Socket.IO๋กœ ์ฒ˜๋ฆฌํ•˜๋˜, ๊ณผ๊ฑฐ ๋ฉ”์‹œ์ง€ ํžˆ์Šคํ† ๋ฆฌ ๋กœ๋”ฉ์€ ์„œ๋ฒ„ ์ƒํƒœ๋กœ ๊ด€๋ฆฌ๊ฐ€ ํŽธํ•จ

4. ์‚ฌ์šฉ ๋ฐฉ๋ฒ•

(1) ์บ˜๋ฆฐ๋” (์ผ์ • ๋ชฉ๋ก/CRUD)

  • useQuery: โ€œํ˜„์žฌ ์›”/์ฃผโ€ ๊ธฐ์ค€ ์ผ์ • ์กฐํšŒ (queryKey์— year-month ๋˜๋Š” range ํฌํ•จ)
  • useMutation: ์ผ์ • ์ถ”๊ฐ€/์ˆ˜์ •/์‚ญ์ œ
  • ์„ฑ๊ณต ์‹œ queryClient.invalidateQueries({ queryKey: ['calendarEvents', range] })๋กœ ๋ชฉ๋ก ๊ฐฑ์‹ 

(2) ๊ฒŒ์‹œํŒ (๋ชฉ๋ก/๋ฌดํ•œ์Šคํฌ๋กค)

  • useInfiniteQuery: ๊ธ€ ๋ชฉ๋ก ๋ฌดํ•œ์Šคํฌ๋กค
  • v5์˜ maxPages๋กœ โ€œ์บ์‹œ์— ์ €์žฅํ•  ํŽ˜์ด์ง€ ์ˆ˜โ€๋ฅผ ์ œํ•œํ•ด ์„ฑ๋Šฅ์„ ์•ˆ์ •ํ™”
  • ๊ธ€ ์ž‘์„ฑ/์‚ญ์ œ ํ›„ ๋ชฉ๋ก invalidate๋กœ ์ตœ์‹ ํ™”

(3) OCR ๊ธฐ๋ฐ˜ ์ž๋™ ์ผ์ • ์‚ฝ์ž…

  • useMutation: ํŒŒ์ผ ์—…๋กœ๋“œ ์š”์ฒญ
  • useQuery: job ์ƒํƒœ ์กฐํšŒ(ํ•„์š” ์‹œ polling) โ†’ ์™„๋ฃŒ๋˜๋ฉด draft ์กฐํšŒ
  • ํ™•์ • ์ €์žฅ ์„ฑ๊ณต ์‹œ ์บ˜๋ฆฐ๋” ๋ชฉ๋ก invalidate

(4) ์ฑ„ํŒ… (ํžˆ์Šคํ† ๋ฆฌ ๋กœ๋”ฉ + ์‹ค์‹œ๊ฐ„ ๊ฒฐํ•ฉ)

  • ํžˆ์Šคํ† ๋ฆฌ(๊ณผ๊ฑฐ ๋ฉ”์‹œ์ง€)๋Š” useInfiniteQuery๋กœ ํŽ˜์ด์ง€ ๋‹จ์œ„ ๋กœ๋”ฉ
  • ์‹ค์‹œ๊ฐ„ ์ƒˆ ๋ฉ”์‹œ์ง€๋Š” Socket.IO๋กœ ๋ฐ›๊ณ , ํ•„์š”ํ•˜๋ฉด Query ์บ์‹œ์— ํ•ฉ์ณ์„œ(append) ํ™”๋ฉด์— ๋ฐ˜์˜
    • โ€œ์‹ค์‹œ๊ฐ„ ์ˆ˜์‹ โ€๊ณผ โ€œ์„œ๋ฒ„ ํžˆ์Šคํ† ๋ฆฌโ€ ์—ญํ•  ๋ถ„๋ฆฌ๊ฐ€ ๋ช…ํ™•ํ•ด์ง

5. ๋‹ค๋ฅธ ์Šคํƒ๊ณผ์˜ ๋น„๊ต ํ‘œ

ํ•ญ๋ชฉ TanStack Query SWR RTK Query
ํ•ต์‹ฌ ๊ฐœ๋… ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ ์บ์‹ฑ/๋™๊ธฐํ™”์— ํŠนํ™”๋œ ํ‘œ์ค€ ๋„๊ตฌ ๊ฐ„๋‹จํ•œ fetch + ์บ์‹œ(๊ฒฝ๋Ÿ‰) Redux ๊ธฐ๋ฐ˜์œผ๋กœ API๋ฅผ ์Šคํ† ์–ด ์ค‘์‹ฌ์œผ๋กœ ํ†ตํ•ฉ
๋ฌดํ•œ ์Šคํฌ๋กค/ํŽ˜์ด์ง€๋„ค์ด์…˜ ๊ธฐ๋ณธ ํŒจํ„ด์ด ํƒ„ํƒ„ํ•˜์—ฌ ๊ตฌํ˜„ ๋ถ€๋‹ด์ด ๋‚ฎ์Œ ๊ตฌํ˜„ ๊ฐ€๋Šฅํ•˜๋‚˜ ํ”„๋กœ์ ํŠธ ์„ค๊ณ„ ์˜์กด๋„๊ฐ€ ๋†’์•„์งˆ ์ˆ˜ ์žˆ์Œ ๊ฐ€๋Šฅํ•˜๋‚˜ Redux ๊ตฌ์กฐ๋ฅผ ํ•จ๊ป˜ ๊ณ ๋ คํ•ด์•ผ ํ•จ
๋ณ€๊ฒฝ ํ›„ ๊ฐฑ์‹  invalidate ์ค‘์‹ฌ์œผ๋กœ ๊ฐฑ์‹  ํ๋ฆ„์„ ์ •์„๋Œ€๋กœ ๊ด€๋ฆฌ ๊ฐ€๋Šฅ ๊ฐฑ์‹  ๊ฐ€๋Šฅํ•˜๋‚˜ ์ปจ๋ฒค์…˜ ์˜์กด์ด ์ปค์งˆ ์ˆ˜ ์žˆ์Œ ํ†ตํ•ฉ ๊ด€๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‚˜ ์„ค์ •/๊ตฌ์„ฑ์ด ์ƒ๋Œ€์ ์œผ๋กœ ํผ
๋„์ž… ๋ฌด๊ฒŒ ์„œ๋ฒ„ ์ƒํƒœ์— ์ง‘์ค‘ํ•˜์—ฌ React ํ”„๋กœ์ ํŠธ์— ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋„์ž… ๊ฐ€๋Šฅ ๊ฐ€์žฅ ๊ฐ€๋ณ๊ณ  ๋‹จ์ˆœ Redux ํฌํ•จ ์ „์ œ๋กœ ๊ทœ๋ชจ๊ฐ€ ์ปค์งˆ ์ˆ˜ ์žˆ์Œ
Devths ์ ํ•ฉ๋„ ๋ชฉ๋ก/ํ•„ํ„ฐ/๋ฌดํ•œ ์Šคํฌ๋กค/๋‚™๊ด€์  UI๊ฐ€ ๋งŽ์€ ๊ตฌ์กฐ์— ํŠนํžˆ ์ ํ•ฉ ๋‹จ์ˆœ ์กฐํšŒ ์œ„์ฃผ์˜ ์ž‘์€ ๊ทœ๋ชจ์— ์ ํ•ฉ ํŒ€์ด Redux ํ‘œ์ค€์„ ์ด๋ฏธ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ํ›„๋ณด
  • ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ์˜ ํ‘œ์ค€ํ™”(์บ์‹ฑ/๋™๊ธฐํ™” ์ค‘์‹ฌ)

    • SWR์€ โ€œ๊ฐ„๋‹จํ•œ fetch + ์บ์‹œโ€์— ๊ฐ•์ ์ด ์žˆ์ง€๋งŒ, ํ”„๋กœ์ ํŠธ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก(์ฟผ๋ฆฌ ํ‚ค ์„ค๊ณ„, refetch ์กฐ๊ฑด, ๊ฐฑ์‹  ๊ทœ์น™ ๋“ฑ) ํŒ€ ์ปจ๋ฒค์…˜์— ์˜์กดํ•˜๋Š” ๋ถ€๋ถ„์ด ๋Š˜์–ด๋‚  ์ˆ˜ ์žˆ์Œ.

    • ์ด ๊ฒฝ์šฐ ํ™”๋ฉด๋ณ„๋กœ ๋ฐ์ดํ„ฐ ๊ฐฑ์‹  ๋ฐฉ์‹์ด ๋‹ฌ๋ผ์ง€๊ฑฐ๋‚˜ ๋ˆ„๋ฝ๋  ์œ„ํ—˜์ด ์ปค์ง

      โ†”๏ธ ๋ฐ˜๋ฉด TanStack Query๋Š” ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ ์บ์‹ฑ/๋™๊ธฐํ™”๋ฅผ ๋ชฉ์ ์œผ๋กœ ์„ค๊ณ„๋œ ๋„๊ตฌ๋ผ queryKey ๊ธฐ๋ฐ˜ ์บ์‹œ, ์ž๋™ refetch ์˜ต์…˜, staleTime/cacheTime ๊ฐ™์€ ์ •์ฑ…์„ ์ผ๊ด€๋œ ๋ฐฉ์‹์œผ๋กœ ์ ์šฉํ•˜๊ธฐ ์‰ฌ์›Œ โ€œ์„œ๋ฒ„ ์ƒํƒœ ๊ด€๋ฆฌ ๋ฐฉ์‹โ€์„ ํ”„๋กœ์ ํŠธ ํ‘œ์ค€์œผ๋กœ ๊ณ ์ •ํ•˜๊ธฐ ์œ ๋ฆฌํ•จ

  • ๋ฌดํ•œ ์Šคํฌ๋กค/ํŽ˜์ด์ง€๋„ค์ด์…˜ ๊ตฌํ˜„ ๋ถ€๋‹ด ๊ฐ์†Œ

    • SWR๋„ ๋ฌดํ•œ ์Šคํฌ๋กค์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ํŽ˜์ด์ง€ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ด€๋ฆฌยท์ค‘๋ณต ์š”์ฒญ ๋ฐฉ์ง€ยท๋‹ค์Œ ํŽ˜์ด์ง€ ๋ณ‘ํ•ฉ ๋“ฑ ์„ค๊ณ„๋ฅผ ํ”„๋กœ์ ํŠธ์—์„œ ๋” ์ง์ ‘ ์ฑ…์ž„์ ธ์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Œ

    • ๋ฐ์ดํ„ฐ ํŒจํ„ด์ด ๋‹ค์–‘ํ•ด์งˆ์ˆ˜๋ก(๊ฒŒ์‹œ๊ธ€/์•Œ๋ฆผ/์ฑ„ํŒ…๋ฐฉ/๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ) ๊ตฌํ˜„ ๋ฐฉ์‹์ด ํ™”๋ฉด๋งˆ๋‹ค ๋‹ฌ๋ผ์งˆ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Œ

      โ†”๏ธ ๋ฐ˜๋ฉด TanStack Query๋Š” useInfiniteQuery ๊ฐ™์€ ํŒจํ„ด์ด ์ •๊ตํ•˜๊ฒŒ ์ œ๊ณต๋˜์–ด, ๋ชฉ๋ก๊ณผ ๋‹ค์Œ ํŽ˜์ด์ง€ ๋กœ๋”ฉ ์š”๊ตฌ๊ฐ€ ๋งŽ์€ ์„œ๋น„์Šค์—์„œ ๊ตฌํ˜„์„ ํ‘œ์ค€ํ™”ํ•˜๊ธฐ ์‰ฝ๊ณ  ๊ฐœ๋ฐœ ๋น„์šฉ์„ ๋‚ฎ์ถœ ์ˆ˜ ์žˆ์Œ

  • ๋ณ€๊ฒฝ ์ž‘์—… ์ดํ›„ ๊ฐฑ์‹  ํ๋ฆ„์„ ์ •์„๋Œ€๋กœ ๊ด€๋ฆฌ

    • SWR์€ ๊ฐฑ์‹ ์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ์–ด๋–ค ๋ณ€๊ฒฝ ํ›„ ์–ด๋–ค ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์‹œ ์ตœ์‹ ํ™”ํ• ์ง€๋ฅผ ํ™”๋ฉด/ํŒ€ ๊ทœ์น™์œผ๋กœ ๋งž์ถฐ์•ผ ํ•˜๋Š” ๋น„์ค‘์ด ์ปค์งˆ ์ˆ˜ ์žˆ์Œ

    • ์ข‹์•„์š”/๋Œ“๊ธ€/์ผ์ • CRUD์ฒ˜๋Ÿผ ๋ณ€๊ฒฝ ์ง€์ ์ด ๋งŽ์•„์ง€๋ฉด ๋ˆ„๋ฝ์ด ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฌ์›€

      โ†”๏ธ ๋ฐ˜๋ฉด TanStack Query๋Š” useMutation + invalidateQueries(๋˜๋Š” cache update) ํ๋ฆ„์ด ํ‘œ์ค€์ด๋ผ, ๋ณ€๊ฒฝ ์ดํ›„ ๊ด€๋ จ ๋ชฉ๋ก/์ƒ์„ธ๋ฅผ ์ผ๊ด€๋œ ๋ฐฉ์‹์œผ๋กœ ๊ฐฑ์‹ ํ•ด ๋ฐ์ดํ„ฐ ์ •ํ•ฉ์„ฑ์„ ์œ ์ง€ํ•˜๊ธฐ ์œ ๋ฆฌํ•จ

  • ๋„์ž… ๋ฌด๊ฒŒ์™€ ์—ญํ•  ๋ถ„๋ฆฌ(์„œ๋ฒ„ ์ƒํƒœ์—๋งŒ ์ง‘์ค‘)

    • RTK Query๋Š” Redux ๊ธฐ๋ฐ˜์œผ๋กœ ์Šคํ† ์–ด ์ค‘์‹ฌ์˜ ํ†ตํ•ฉ ๊ด€๋ฆฌ๊ฐ€ ์žฅ์ ์ด์ง€๋งŒ, ๊ทธ ์ „์ œ๋กœ Redux ๊ตฌ์กฐ(์Šฌ๋ผ์ด์Šค/์Šคํ† ์–ด ๊ตฌ์„ฑ)๋ฅผ ํ•จ๊ป˜ ๊ฐ€์ ธ๊ฐ€์•ผ ํ•˜๋ฏ€๋กœ ํ”„๋กœ์ ํŠธ ๊ทœ๋ชจ ๋Œ€๋น„ ๋„์ž… ๋ฌด๊ฒŒ๊ฐ€ ์ปค์งˆ ์ˆ˜ ์žˆ์Œ

    • ํŠนํžˆ ์„œ๋ฒ„ ์ƒํƒœ์™€ UI ์ „์—ญ ์ƒํƒœ๋ฅผ ๋ถ„๋ฆฌํ•ด์„œ ๊ฐ€์ ธ๊ฐ€๋ ค๋Š” ๊ตฌ์กฐ์—์„œ๋Š” ๋ถˆํ•„์š”ํ•˜๊ฒŒ ์ปค์งˆ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Œ

      โ†”๏ธ ๋ฐ˜๋ฉด TanStack Query๋Š” ์„œ๋ฒ„ ์ƒํƒœ์—๋งŒ ์ง‘์ค‘ํ•ด์„œ React์— ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ถ™์ผ ์ˆ˜ ์žˆ์–ด, UI ์ „์—ญ ์ƒํƒœ(Zustand)์™€ ์—ญํ• ์„ ๋ถ„๋ฆฌํ•˜๊ธฐ ์‰ฝ๊ณ  ์ „์ฒด ์•„ํ‚คํ…์ฒ˜๋ฅผ ๋‹จ์ˆœํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๋ฐ ์œ ๋ฆฌํ•จ

5. ๋ฒ„์ „ ์„ ํƒ ์ด์œ 

  • v 5.90.16
    • 2025๋…„ 12 30์ผ ๋ฆด๋ฆฌ์ฆˆ
  • ์ด์œ 
    • v5๋Š” API๋ฅผ ๋‹จ์ˆœํ™”/์ •๋ฆฌํ•˜๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ๊ฐœ์„ ๋˜์–ด, ์‹ ๊ทœ ํ”„๋กœ์ ํŠธ์—์„œ ํ‘œ์ค€ ํŒจํ„ด์„ ์žก๊ธฐ ์ข‹์Œ
    • invalidate / infinite query ๋“ฑ Devths์— ํ•„์š”ํ•œ ํ•ต์‹ฌ ๊ธฐ๋Šฅ์„ ๊ณต์‹ ํŒจํ„ด์œผ๋กœ ์ œ๊ณต
      • invalidate
        • ๊ฒŒ์‹œํŒ
          • ๊ธ€ ์ž‘์„ฑ/์‚ญ์ œ/์ˆ˜์ • ์„ฑ๊ณต โ†’ posts ๋ชฉ๋ก invalidate
          • ๋Œ“๊ธ€ ์ž‘์„ฑ/์‚ญ์ œ ์„ฑ๊ณต โ†’ comments invalidate
        • ์บ˜๋ฆฐ๋”
          • ์ผ์ • CRUD ์„ฑ๊ณต โ†’ calendarEvents(ํ•ด๋‹น ์›”/์ฃผ) invalidate
        • OCR ์ผ์ • ์ƒ์„ฑ
          • โ€œํ™•์ • ์ €์žฅโ€ ์„ฑ๊ณต โ†’ calendarEvents invalidate
    • ****๋™์ผ ๋ฉ”์ด์ € ๋ผ์ธ์—์„œ ์•ˆ์ •์ ์œผ๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

6. ๊ฒฐ๋ก 

  • devths๋Š” ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ(๋ชฉ๋ก/๊ฒ€์ƒ‰/ํ•„ํ„ฐ/๋ฌดํ•œ ์Šคํฌ๋กค)์˜ ๋น„์ค‘์ด ํฌ๊ณ , ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ์ดํ›„ ๊ด€๋ จ ํ™”๋ฉด์„ ์ตœ์‹  ์ƒํƒœ๋กœ ๋™๊ธฐํ™”ํ•ด์•ผ ํ•˜๋Š” ์š”๊ตฌ๊ฐ€ ๋งŽ์Œ
  • ์ด์— ๋”ฐ๋ผ ์„œ๋ฒ„ ์ƒํƒœ๋ฅผ ํ‘œ์ค€ํ™”ํ•˜์—ฌ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” TanStack Query๋ฅผ ๋„์ž…ํ•˜๋Š” ๊ฒƒ์ด ์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ ์„ฑ๋Šฅ ์ธก๋ฉด์—์„œ ๊ฐ€์žฅ ์ ํ•ฉํ•˜๋‹ค๊ณ  ํŒ๋‹จํ•จ

๐ŸŽจ UI ๊ตฌ์„ฑ ์ „๋žต

โœ… ์Šคํƒ€์ผ๋ง - Tailwind CSS v4.1

0. Build-time ์Šคํƒ€์ผ๋ง vs Runtime ์Šคํƒ€์ผ๋ง

๊ตฌ๋ถ„ Build-time ์Šคํƒ€์ผ๋ง Runtime ์Šคํƒ€์ผ๋ง
CSS ์ƒ์„ฑ ์‹œ์  ๋นŒ๋“œ ์‹œ์ ์— CSS๋ฅผ ๋ฏธ๋ฆฌ ์ƒ์„ฑ ์‹คํ–‰(๋ธŒ๋ผ์šฐ์ € ๋Ÿฐํƒ€์ž„) ์ค‘์— JS๋กœ ์Šคํƒ€์ผ ์ƒ์„ฑ/์ฃผ์ž…
๋Œ€ํ‘œ ์˜ˆ์‹œ Tailwind CSS, CSS Modules, SCSS styled-components, emotion(๊ธฐ๋ณธ), ๊ธฐํƒ€ CSS-in-JS
๋™์ž‘ ๋ฐฉ์‹ ์‚ฌ์šฉํ•œ ํด๋ž˜์Šค/์Šคํƒ€์ผ์„ ๋ถ„์„ํ•ด ํ•„์š”ํ•œ CSS๋งŒ ๋ฒˆ๋“ค์— ํฌํ•จ ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง ์‹œ ์Šคํƒ€์ผ ๋ฌธ์ž์—ด์„ ๋งŒ๋“ค๊ณ  <style>์— inject
์„ฑ๋Šฅ ํŠน์„ฑ ๋Ÿฐํƒ€์ž„ ์ž‘์—…์ด ์ ์–ด ์˜ˆ์ธก ๊ฐ€๋Šฅํ•˜๊ณ  ๋น ๋ฅธ ํŽธ ๋Ÿฐํƒ€์ž„์— ์Šคํƒ€์ผ ๊ณ„์‚ฐ/์ฃผ์ž… ๋น„์šฉ์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ์Œ
๋ฒˆ๋“ค/CSS ํฌ๊ธฐ โ€œ์“ด ๊ฒƒ๋งŒ ๋‚จ๊ธฐ๊ธฐโ€ ์ตœ์ ํ™”๊ฐ€ ์‰ฌ์›Œ CSS๊ฐ€ ์ž‘์•„์ง€๊ธฐ ์‰ฌ์›€ JS ๋ฒˆ๋“ค์— ์Šคํƒ€์ผ ๋กœ์ง์ด ํฌํ•จ๋  ์ˆ˜ ์žˆ์–ด ๋ฒˆ๋“ค ๋ณต์žก๋„ ์ฆ๊ฐ€ ๊ฐ€๋Šฅ
๋™์  ์Šคํƒ€์ผ ํ‘œํ˜„ ์กฐ๊ฑด๋ถ€ ํด๋ž˜์Šค ์กฐํ•ฉ์œผ๋กœ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, โ€œ์™„์ „ ๋™์ โ€์€ ์ƒ๋Œ€์ ์œผ๋กœ ๋ถˆํŽธํ•  ์ˆ˜ ์žˆ์Œ props/์ƒํƒœ ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์  ์Šคํƒ€์ผ ํ‘œํ˜„์ด ๋งค์šฐ ์‰ฌ์›€
์œ ์ง€๋ณด์ˆ˜/์ผ๊ด€์„ฑ ๊ทœ์น™(ํ† ํฐ/์œ ํ‹ธ) ๊ธฐ๋ฐ˜์ด๋ผ UI ์ผ๊ด€์„ฑ ์œ ์ง€์— ์œ ๋ฆฌ ํŒ€ ๊ทœ์น™์ด ์—†์œผ๋ฉด ์Šคํƒ€์ผ์ด ํผ์งˆ ์ˆ˜ ์žˆ์–ด ์ปจ๋ฒค์…˜ ๊ด€๋ฆฌ๊ฐ€ ์ค‘์š”
Devths ์ ํ•ฉ๋„ ํ™”๋ฉด/์ปดํฌ๋„ŒํŠธ ๋งŽ๊ณ  ๋ฐ˜๋ณต UI๊ฐ€ ๋งŽ์„ ๋•Œ ์œ ๋ฆฌ(๋ฆฌ์ŠคํŠธ/์ฑ„ํŒ…/๋ชจ๋‹ฌ ๋“ฑ) ๊ฐ•ํ•œ ํ…Œ๋งˆ/๋™์  ์Šคํƒ€์ผ์ด ํ•ต์‹ฌ์ผ ๋•Œ ์œ ๋ฆฌ(๊ทœ์น™ ์—†์œผ๋ฉด ๋ณต์žก๋„โ†‘)

1. ํŠน์ง• ์š”์•ฝ

  • ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค(Utility-first) ๊ธฐ๋ฐ˜
    • p-4, text-sm, flex, gap-2 ๊ฐ™์€ ํด๋ž˜์Šค๋ฅผ ์กฐํ•ฉํ•ด UI๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐฉ์‹์ด๋ผ, CSS ํŒŒ์ผ์„ ๋”ฐ๋กœ ํฌ๊ฒŒ ๋งŒ๋“ค์ง€ ์•Š๊ณ ๋„ ๋น ๋ฅด๊ฒŒ ํ™”๋ฉด์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Œ
  • ์ผ๊ด€๋œ ๋””์ž์ธ ์‹œ์Šคํ…œ ์œ ์ง€
    • spacing/์ƒ‰์ƒ/ํฐํŠธ ํฌ๊ธฐ ๋“ฑ์ด ๊ทœ์น™ํ™”๋œ ํ† ํฐ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ด€๋ฆฌ๋˜์–ด, ํŽ˜์ด์ง€๊ฐ€ ๋งŽ์•„์ ธ๋„ UI ์Šคํƒ€์ผ์ด ๋“ค์ญ‰๋‚ ์ญ‰ํ•ด์ง€์ง€ ์•Š์Œ
  • ๋ฐ˜์‘ํ˜•/์ƒํƒœ ์Šคํƒ€์ผ๋ง์ด ์ง๊ด€์ 
    • sm:, md: ๊ฐ™์€ ๋ฐ˜์‘ํ˜• ํ”„๋ฆฌํ”ฝ์Šค์™€ hover:, focus: ๊ฐ™์€ ์ƒํƒœ ํด๋ž˜์Šค ์กฐํ•ฉ์œผ๋กœ ๋‹ค์–‘ํ•œ UI ์ƒํƒœ๋ฅผ ํ•œ ์ค„์—์„œ ๊ด€๋ฆฌ ๊ฐ€๋Šฅ
  • ์ƒ์‚ฐ์„ฑ ํ–ฅ์ƒ
    • ์ปดํฌ๋„ŒํŠธ ๊ฐœ๋ฐœ ์‹œ โ€œCSS ์ž‘์„ฑ โ†” ํด๋ž˜์Šค ์ ์šฉโ€ ์™•๋ณต์ด ์ค„์–ด๋“ค์–ด ๊ฐœ๋ฐœ ์†๋„๊ฐ€ ๋น ๋ฅด๊ณ , ๋””์ž์ธ ๋ณ€๊ฒฝ๋„ ํด๋ž˜์Šค ์ˆ˜์ •๋งŒ์œผ๋กœ ๋Œ€์‘ ๊ฐ€๋Šฅ
  • ๋ฒˆ๋“ค ์ตœ์ ํ™”(์‚ฌ์šฉํ•œ ํด๋ž˜์Šค๋งŒ ๋นŒ๋“œ)
    • ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” CSS๋Š” ๋นŒ๋“œ ๋‹จ๊ณ„์—์„œ ์ œ๊ฑฐ๋˜์–ด(์ตœ์ ํ™”) ์Šคํƒ€์ผ ์‹œํŠธ ์šฉ๋Ÿ‰์„ ์ค„์ผ ์ˆ˜ ์žˆ์Œ

2. devths์— ์ด ๊ธฐ์ˆ ์ด ํ•„์š”ํ•œ ์ด์œ 

๐Ÿ’ก
  • Devths๋Š” ์บ˜๋ฆฐ๋”/๊ฒŒ์‹œํŒ/์ฑ„ํŒ…/AI ๋“ฑ ํ™”๋ฉด ์ˆ˜๊ฐ€ ๋งŽ๊ณ  ๊ณตํ†ต UI(๋ฒ„ํŠผ, ๋ชจ๋‹ฌ, ์ž…๋ ฅํผ, ์นด๋“œ, ๋ฆฌ์ŠคํŠธ)๊ฐ€ ๋ฐ˜๋ณต๋˜๋Š” ์„œ๋น„์Šค์ž„
    • Tailwind CSS๋ฅผ ์ ์šฉํ•˜๋ฉด ๋ฐ˜๋ณต UI๋ฅผ ๋น ๋ฅด๊ฒŒ ๊ตฌํ˜„ํ•˜๋ฉด์„œ๋„ ๋””์ž์ธ ๊ทœ์น™์„ ์ผ๊ด€๋˜๊ฒŒ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Œ

(1) ํŽ˜์ด์ง€ ์ˆ˜๊ฐ€ ๋งŽ์•„ โ€œ์Šคํƒ€์ผ ์ผ๊ด€์„ฑโ€์ด ์ค‘์š”ํ•จ

  • ํ™”๋ฉด๋งˆ๋‹ค ๋‹ค๋ฅธ CSS ๋ฐฉ์‹์œผ๋กœ ์ž‘์„ฑํ•˜๋ฉด ํฐํŠธ/๊ฐ„๊ฒฉ/์ƒ‰์ƒ์ด ์กฐ๊ธˆ์”ฉ ๋‹ฌ๋ผ์ง€๊ธฐ ์‰ฌ์›€

    โ†’ Tailwind์˜ ๊ทœ์น™ํ™”๋œ ์œ ํ‹ธ๋ฆฌํ‹ฐ๋กœ ๊ธฐ๋ณธ ํ†ค์„ ํ†ต์ผ ๊ฐ€๋Šฅ

(2) ๊ณตํ†ต ์ปดํฌ๋„ŒํŠธ(๋ชจ๋‹ฌ/๋ฒ„ํŠผ/์ž…๋ ฅํผ) ๊ฐœ๋ฐœ ์†๋„๊ฐ€ ๋นจ๋ผ์ง

  • Devths๋Š” OCR ์ฒ˜๋ฆฌ ๋ชจ๋‹ฌ, ๊ธ€ ์ž‘์„ฑ ํผ, ์ฑ„ํŒ… ์ž…๋ ฅ์ฐฝ ๋“ฑ ๊ณตํ†ต UI๊ฐ€ ๋งŽ์Œ

    โ†’ Tailwind๋กœ ๋น ๋ฅด๊ฒŒ ํ”„๋กœํ† ํƒ€์ดํ•‘ํ•˜๊ณ , ์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„๋กœ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์ข‹์Œ

(3) ๋ฐ˜์‘ํ˜• UI ๊ตฌํ˜„์ด ๊ฐ„๋‹จํ•จ

  • ์บ˜๋ฆฐ๋”/์ฑ„ํŒ…์€ ๋ฐ์Šคํฌํƒ‘๊ณผ ๋ชจ๋ฐ”์ผ ๋ ˆ์ด์•„์›ƒ์ด ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Œ

    โ†’ md:flex, sm:hidden ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ํŽ˜์ด์ง€๋งˆ๋‹ค ๋ฐ˜์‘ํ˜• ์ฒ˜๋ฆฌ๊ฐ€ ์‰ฌ์›€

3. ๋‹ค๋ฅธ ์Šคํƒ๊ณผ์˜ ๋น„๊ต ํ‘œ

ํ•ญ๋ชฉ Tailwind CSS styled-components CSS Modules(Sass ํฌํ•จ)
๊ฐœ๋ฐœ ๋ฐฉ์‹ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค ์กฐํ•ฉ ์ปดํฌ๋„ŒํŠธ์— CSS-in-JS ์ž‘์„ฑ ํŒŒ์ผ ๋‹จ์œ„๋กœ ํด๋ž˜์Šค ์ž‘์„ฑ
UI ๋ณ€๊ฒฝ ์†๋„ JSX์—์„œ ์ฆ‰์‹œ ์ˆ˜์ • ๊ฐ€๋Šฅ ์Šคํƒ€์ผ ์ •์˜ ํŒŒ์ผ๋กœ ์ด๋™ ํ•„์š” ์Šคํƒ€์ผ ํŒŒ์ผ ์ˆ˜์ • ํ•„์š”
์ƒํƒœ๋ณ„ ์Šคํƒ€์ผ๋ง hover:, focus:, data-* ๋“ฑ ํŒจํ„ดํ™” ์‰ฌ์›€ ์กฐ๊ฑด๋ถ€ ์Šคํƒ€์ผ ๋ถ„๊ธฐ ๊ตฌํ˜„ ํด๋ž˜์Šค ์กฐํ•ฉ/๋ถ„๊ธฐ ํ•„์š”
๋””์ž์ธ ์ผ๊ด€์„ฑ config ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฐ•์ œ ์‰ฌ์›€ ํ…Œ๋งˆ๋กœ ๊ฐ€๋Šฅ(์„ค๊ณ„ ํ•„์š”) ์ปจ๋ฒค์…˜ ์˜์กด๋„๊ฐ€ ํผ
์œ ์ง€๋ณด์ˆ˜ ํฌ์ธํŠธ ํด๋ž˜์Šค๊ฐ€ ๊ธธ์–ด์งˆ ์ˆ˜ ์žˆ์–ด ๊ด€๋ฆฌ ๊ทœ์น™ ํ•„์š” ํŒŒ์ผ/์Šคํƒ€์ผ ๋ถ„๋ฆฌ๋กœ ๊ทœ๋ชจ ์ปค์งˆ์ˆ˜๋ก ๊ด€๋ฆฌ ๋ณต์žก ํŒŒ์ผ ์ฆ๊ฐ€/๋„ค์ด๋ฐ ๊ด€๋ฆฌ ๋ถ€๋‹ด
  • UI ๋ณ€๊ฒฝ ์†๋„ ๋ฐ ๋ฐ˜๋ณต UI ์ƒ์‚ฐ์„ฑ

    • styled-components / CSS Modules๋Š” ์Šคํƒ€์ผ์„ ๋ณ„๋„ ํŒŒ์ผ(๋˜๋Š” CSS-in-JS ์˜์—ญ)์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ๋น„์ค‘์ด ์ปค์„œ, ๋ฒ„ํŠผ/ํƒญ/๋ฐฐ์ง€/์นด๋“œ/๋ชจ๋‹ฌ์ฒ˜๋Ÿผ UI๊ฐ€ ๋งŽ์ด ๋ฐ˜๋ณต๋˜๋Š” ์„œ๋น„์Šค์—์„œ๋Š” โ€œ๋งˆํฌ์—… ์ˆ˜์ • โ†” ์Šคํƒ€์ผ ํŒŒ์ผ ์ด๋™โ€ ํ๋ฆ„์ด ์ž์ฃผ ๋ฐœ์ƒํ•จ. ์ด ๊ฒฝ์šฐ ํ™”๋ฉด ๋‹จ์œ„ ์ž‘์—…๋Ÿ‰์ด ๋ˆ„์ ๋ ์ˆ˜๋ก ์ˆ˜์ • ๋น„์šฉ์ด ์ปค์งˆ ์ˆ˜ ์žˆ์Œ

      โ†”๏ธ ๋ฐ˜๋ฉด Tailwind CSS๋Š” JSX ์•ˆ์—์„œ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค๋ฅผ ์กฐํ•ฉํ•ด ์ฆ‰์‹œ ์Šคํƒ€์ผ์„ ์ ์šฉยท์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์–ด, ํ™”๋ฉด ์ˆ˜๊ฐ€ ๋งŽ๊ณ  UI ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฐ˜๋ณต๋˜๋Š” Devths์—์„œ ๊ฐœ๋ฐœ ์†๋„์™€ ๋ฐ˜๋ณต ์ž‘์—… ํšจ์œจ์„ ํ™•๋ณดํ•˜๊ธฐ ์œ ๋ฆฌํ•จ

  • ์ƒํƒœ๋ณ„ ์Šคํƒ€์ผ๋ง์˜ ํ‘œ์ค€ํ™”

    • CSS Modules / styled-components๋„ ์ƒํƒœ๋ณ„ ์Šคํƒ€์ผ๋ง์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ์กฐ๊ฑด ๋ถ„๊ธฐ(ํด๋ž˜์Šค ์กฐํ•ฉ, props ๊ธฐ๋ฐ˜ ๋ถ„๊ธฐ)๊ฐ€ ํ™”๋ฉด๋งˆ๋‹ค ๋‹ค๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜๋ฉด ์Šคํƒ€์ผ ๊ทœ์น™์ด ๋ถ„์‚ฐ๋˜๊ณ  ๋ˆ„๋ฝ๋  ์œ„ํ—˜์ด ์žˆ์Œ

    • ํŠนํžˆ ํ™œ์„ฑ/๋น„ํ™œ์„ฑ/์—๋Ÿฌ/์„ ํƒ/hover/focus ๊ฐ™์€ ์ƒํƒœ๊ฐ€ ๋งŽ์€ UI์—์„œ๋Š” ๋ถ„๊ธฐ ๋กœ์ง์ด ๋Š˜์–ด๋‚˜ ๊ด€๋ฆฌ ํฌ์ธํŠธ๊ฐ€ ์ฆ๊ฐ€ํ•  ์ˆ˜ ์žˆ์Œ

      โ†”๏ธ ๋ฐ˜๋ฉด Tailwind CSS๋Š” hover:, focus:, disabled:, data-* ๋“ฑ ์ƒํƒœ ํ‘œํ˜„์„ ํด๋ž˜์Šค ๋ ˆ๋ฒจ์—์„œ ํŒจํ„ดํ™”ํ•˜๊ธฐ ์‰ฌ์›Œ, ์ƒํƒœ๋ณ„ UI ๊ทœ์น™์„ ์ผ๊ด€๋œ ๋ฐฉ์‹์œผ๋กœ ์ ์šฉยทํ™•์žฅํ•˜๋Š” ๋ฐ ์œ ๋ฆฌํ•จ

  • ๋””์ž์ธ ์ผ๊ด€์„ฑ ์œ ์ง€ ๋ฐฉ์‹

    • CSS Modules๋Š” ๋„ค์ด๋ฐ/๊ตฌ์กฐ๊ฐ€ ํŒ€ ์ปจ๋ฒค์…˜์— ํฌ๊ฒŒ ์˜์กดํ•˜๊ณ , styled-components๋Š” ํ…Œ๋งˆ ์„ค๊ณ„๋ฅผ ํ†ตํ•ด ํ†ต์ผํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ดˆ๊ธฐ ์„ค๊ณ„์™€ ํŒ€ ํ•ฉ์˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ํ”„๋กœ์ ํŠธ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก ์–ด๋–ค ๊ฐ’์ด ํ‘œ์ค€์ธ์ง€๊ฐ€ ํ๋ ค์งˆ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Œ

      โ†”๏ธ ๋ฐ˜๋ฉด Tailwind CSS๋Š” config(์ƒ‰์ƒ, ๊ฐ„๊ฒฉ, ํฐํŠธ, ๋ธŒ๋ ˆ์ดํฌํฌ์ธํŠธ ๋“ฑ)๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์Šคํƒ€์ผ์„ ๊ฐ•์ œํ•˜๊ธฐ ์‰ฌ์›Œ, ์—ฌ๋Ÿฌ ํ™”๋ฉด์„ ๋ณ‘๋ ฌ๋กœ ๊ฐœ๋ฐœํ•˜๋”๋ผ๋„ ํ†ค์•ค๋งค๋„ˆ๋ฅผ ์œ ์ง€ํ•˜๋Š” ๋ฐ ์ ํ•ฉํ•จ

  • ์œ ์ง€๋ณด์ˆ˜ ๋ฆฌ์Šคํฌ์˜ ํ˜•ํƒœ

    • Tailwind CSS๋Š” ํด๋ž˜์Šค๊ฐ€ ๊ธธ์–ด์งˆ ์ˆ˜ ์žˆ์–ด ๊ทœ์น™(์˜ˆ: ๊ณตํ†ต ์ปดํฌ๋„ŒํŠธํ™”, ํด๋ž˜์Šค ์ •๋ฆฌ ๊ธฐ์ค€)์ด ํ•„์š”ํ•˜๋‹ค๋Š” ๊ด€๋ฆฌ ํฌ์ธํŠธ๊ฐ€ ์กด์žฌํ•จ

      โ†”๏ธ ๋‹ค๋งŒ Devths์ฒ˜๋Ÿผ UI๊ฐ€ ๋งŽ๊ณ  ์š”๊ตฌ์‚ฌํ•ญ ๋ณ€๊ฒฝ์ด ์žฆ์€ ํ™˜๊ฒฝ์—์„œ๋Š” ํŒŒ์ผ ์ฆ๊ฐ€/๋„ค์ด๋ฐ ๊ด€๋ฆฌ/CSS ๋ถ„๊ธฐ ๋กœ์ง ์ฆ๊ฐ€๊ฐ€ ๋ˆ„์ ๋˜๋Š” ๋ฐฉ์‹๋ณด๋‹ค, ํด๋ž˜์Šค ์กฐํ•ฉ ์ค‘์‹ฌ์œผ๋กœ ๋น ๋ฅด๊ฒŒ ์ˆ˜์ • ๊ฐ€๋Šฅํ•œ Tailwind์˜ ์œ ์ง€๋ณด์ˆ˜ ํ˜•ํƒœ๊ฐ€ ๋” ์ ํ•ฉํ•˜๋‹ค๊ณ  ํŒ๋‹จ๋จ

4. ์‚ฌ์šฉ ๋ฐฉ๋ฒ•

  • ๊ณตํ†ต ๋ฒ„ํŠผ
    • primary/secondary/disabled๋ฅผ ํด๋ž˜์Šค ์กฐํ•ฉ์œผ๋กœ ํ†ต์ผ
  • ์ „์—ญ ๋ชจ๋‹ฌ
    • OCR ์ฒ˜๋ฆฌ ๋Œ€๊ธฐ ๋ชจ๋‹ฌ, ๊ฒฐ๊ณผ ๊ฒ€ํ†  ๋ชจ๋‹ฌ ๋“ฑ ๋ ˆ์ด์–ด UI๋ฅผ ๊ฐ™์€ ์Šคํƒ€์ผ ๊ทœ์น™์œผ๋กœ ๊ตฌ์„ฑ
  • ๋ฆฌ์ŠคํŠธ UI
    • ๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก, ์ฑ„ํŒ… ๋ฉ”์‹œ์ง€ ๋ชฉ๋ก์ฒ˜๋Ÿผ ๋ฐ˜๋ณต๋˜๋Š” UI๋ฅผ spacing ๊ทœ์น™(gap, py, border)์œผ๋กœ ๊น”๋”ํ•˜๊ฒŒ ์œ ์ง€

5. ๋ฒ„์ „ ์„ ํƒ ์ด์œ 

  • v4.1
    • 2025๋…„ 4์›” 1์ผ์— ๋ฆด๋ฆฌ์ฆˆ
  • Tailwind CSS๋Š” ๋ฉ”์ด์ € ๋ฒ„์ „์ด ๋ฐ”๋€” ๋•Œ ์„ค์ •/๋นŒ๋“œ ๋ฐฉ์‹์ด ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ์ตœ์‹  ์•ˆ์ • ๋ฒ„์ „์ธ 4.1์„ ๊ธฐ์ค€์œผ๋กœ ์žก์œผ๋ฉด ๋ฌธ์„œ์™€ ๋™์ผํ•œ ํ๋ฆ„์œผ๋กœ ์ ์šฉํ•˜๊ธฐ ์‰ฌ์›€
  • ๋™์ผ ๋ฉ”์ด์ €(4.x) ์•ˆ์—์„œ ํŒจ์น˜ ์—…๋ฐ์ดํŠธ๋กœ ๋ฒ„๊ทธ ์ˆ˜์ •๊ณผ ์•ˆ์ •์„ฑ ๊ฐœ์„ ์„ ๋ฐ›๋Š” ๋ฐฉ์‹์ด ์œ ์ง€๋ณด์ˆ˜์— ์œ ๋ฆฌํ•˜๋ฏ€๋กœ, ํ”„๋กœ์ ํŠธ ๊ธฐ๋ณธ ๋ฒ„์ „์€ 4.1๋กœ ๊ณ ์ •ํ•˜๋Š” ๊ฒƒ์ด ํ•ฉ๋ฆฌ์ ์ด๋ผ๊ณ  ํŒ๋‹จ

6. ๊ฒฐ๋ก 

  • devths๋Š” ๋ฐ˜๋ณต UI์™€ ์ƒํƒœ ๋ณ€ํ™”๊ฐ€ ๋งŽ์€ ํ™”๋ฉด์ด ๋งŽ๊ธฐ ๋•Œ๋ฌธ์—, ์Šคํƒ€์ผ์„ ๋น ๋ฅด๊ฒŒ ์กฐํ•ฉํ•˜๊ณ  ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ํ‘œํ˜„ ๋ฐฉ์‹์ด ํ†ต์ผ๋˜๊ธฐ ์‰ฌ์šด Tailwind CSS๊ฐ€ ์ ํ•ฉํ•˜๋‹ค๊ณ  ํŒ๋‹จํ•จ.

โœ… UI ์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - shadcn/ui

1. ํŠน์ง• ์š”์•ฝ

  • ํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ๋งŒ ์„ค์น˜ํ•ด์„œ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ์‹

    • ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ†ต์งธ๋กœ ์˜์กดํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ, ํ•„์š”ํ•œ UI๋งŒ ํ”„๋กœ์ ํŠธ์— ์ถ”๊ฐ€ํ•ด์„œ ์‚ฌ์šฉํ•จ

      โ†’ ๋ถˆํ•„์š”ํ•œ ๋ฒˆ๋“ค ์ฆ๊ฐ€๋ฅผ ์ค„์ด๊ณ  ํ”„๋กœ์ ํŠธ ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž๊ฒŒ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•˜๊ธฐ ์‰ฌ์›€

  • ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ๊ฐ€ ํ”„๋กœ์ ํŠธ ๋‚ด๋ถ€์— ์กด์žฌ

    • ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ทธ๋Œ€๋กœ ์“ฐ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ์ƒ์„ฑ๋œ ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ๊ฐ€ ์šฐ๋ฆฌ ๋ ˆํฌ ์•ˆ์— ๋“ค์–ด์˜ด

      โ†’ ๋””์ž์ธ/๋™์ž‘์„ ์šฐ๋ฆฌ ์„œ๋น„์Šค์— ๋งž๊ฒŒ ์ˆ˜์ •ํ•˜๊ธฐ ์‰ฝ๊ณ , ์œ ์ง€๋ณด์ˆ˜๋„ ํˆฌ๋ช…ํ•จ

  • Radix UI ๊ธฐ๋ฐ˜์˜ ์ ‘๊ทผ์„ฑ(A11y)

    • Dialog, Dropdown, Tabs ๊ฐ™์€ ๋ณต์žกํ•œ UI๋ฅผ ์ ‘๊ทผ์„ฑ ๊ณ ๋ ค๋œ ํŒจํ„ด์œผ๋กœ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Œ

      โ†’ ๋ชจ๋‹ฌ/๋“œ๋กญ๋‹ค์šด/ํƒญ ๋“ฑ ์ธํ„ฐ๋ž™์…˜์ด ๋งŽ์€ ์„œ๋น„์Šค์—์„œ ์•ˆ์ •์ 

  • Tailwind CSS์™€ ๊ถํ•ฉ์ด ์ข‹์Œ

    • ๊ธฐ๋ณธ ์Šคํƒ€์ผ๋ง์ด Tailwind ๊ธฐ๋ฐ˜์ด๋ผ, Devths์˜ ์Šคํƒ€์ผ๋ง ์ „๋žต(Tailwind)๊ณผ ์ผ๊ด€๋˜๊ฒŒ ํ†ตํ•ฉ ๊ฐ€๋Šฅ
  • ์ผ๊ด€๋œ UI ํ’ˆ์งˆ

    • ๋ฒ„ํŠผ/์ž…๋ ฅ/๋ชจ๋‹ฌ/ํ† ์ŠคํŠธ ๋“ฑ ๊ณตํ†ต UI๋ฅผ ํ‘œ์ค€ ์ปดํฌ๋„ŒํŠธ๋กœ ์žฌ์‚ฌ์šฉํ•ด์„œ ํ™”๋ฉด์ด ๋งŽ์•„์ ธ๋„ ๋””์ž์ธ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๊ธฐ ์‰ฌ์›€

2. devths์— ์ด ๊ธฐ์ˆ ์ด ํ•„์š”ํ•œ ์ด์œ 

๐Ÿ’ก

Devths๋Š” ์บ˜๋ฆฐ๋”/๊ฒŒ์‹œํŒ/์ฑ„ํŒ…/AI ๊ธฐ๋Šฅ ์ „๋ฐ˜์—์„œ ๊ณตํ†ต UI ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฐ˜๋ณต์ ์œผ๋กœ ๋“ฑ์žฅํ•จ

โ‡’ shadcn/ui๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ณตํ†ต UI๋ฅผ ๋น ๋ฅด๊ฒŒ ๊ตฌ์„ฑํ•˜๋ฉด์„œ๋„, ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ๊ฐ€ ํ”„๋กœ์ ํŠธ ๋‚ด๋ถ€์— ์žˆ์–ด Devths ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž๊ฒŒ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•์ด ๊ฐ€๋Šฅ

(1) ๊ณตํ†ต UI๊ฐ€ ๋งค์šฐ ๋งŽ์Œ

  • ์˜ˆ: ๋ฒ„ํŠผ, ์ž…๋ ฅํผ, ๋“œ๋กญ๋‹ค์šด, ํƒญ, ๋ชจ๋‹ฌ(Dialog), ํ† ์ŠคํŠธ, ์นด๋“œ, ๋ฐฐ์ง€

  • OCR ์ฒ˜๋ฆฌ ๋Œ€๊ธฐ ๋ชจ๋‹ฌ / ๊ฒฐ๊ณผ ๊ฒ€ํ†  ๋ชจ๋‹ฌ ๊ฐ™์€ ๋ ˆ์ด์–ด UI๊ฐ€ ์ž์ฃผ ๋“ฑ์žฅ

    โ†’ shadcn/ui๋กœ ๊ธฐ๋ณธ ํ€„๋ฆฌํ‹ฐ๋ฅผ ๋น ๋ฅด๊ฒŒ ํ™•๋ณด

(2) ๋””์ž์ธ ์ผ๊ด€์„ฑ๊ณผ ๊ฐœ๋ฐœ ์†๋„๋ฅผ ๋™์‹œ์— ์žก์„ ์ˆ˜ ์žˆ์Œ

  • ํŽ˜์ด์ง€๊ฐ€ ๋Š˜์ˆ˜๋ก ๊ฐ์ž ๋งŒ๋“  ๋ฒ„ํŠผ/๋ชจ๋‹ฌ์ด ์ƒ๊ธฐ๋ฉด UI๊ฐ€ ํ”๋“ค๋ฆผ

    โ†’ ํ‘œ์ค€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํ†ต์ผํ•˜๋ฉด ํ’ˆ์งˆ์ด ์•ˆ์ •์ 

(3) ์ปค์Šคํ„ฐ๋งˆ์ด์ง•์ด ์‰ฌ์›€

  • Devths๋Š” ์„œ๋น„์Šค ํ†ค(์ƒ‰/์—ฌ๋ฐฑ/ํƒ€์ดํฌ)๊ณผ UX(๋ชจ๋‹ฌ ๋‹จ๊ณ„, ํผ ๊ฒ€์ฆ ๋ฉ”์‹œ์ง€ ๋“ฑ)๊ฐ€ ์ค‘์š”

    โ†’ ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ๊ฐ€ ๋‚ด๋ถ€์— ์žˆ์œผ๋‹ˆ ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž๊ฒŒ ์ˆ˜์ • ๊ฐ€๋Šฅ

3. ์‚ฌ์šฉ ๋ฐฉ๋ฒ•

  • ์บ˜๋ฆฐ๋”
    • ์ผ์ • ์ถ”๊ฐ€/์ˆ˜์ •: Dialog + Input + Select + Button
    • OCR ์—…๋กœ๋“œ/์ฒ˜๋ฆฌ ๋Œ€๊ธฐ/๊ฒฐ๊ณผ ๊ฒ€ํ† : Dialog/Sheet + Progress(๋กœ๋”ฉ UI) + Toast
  • ๊ฒŒ์‹œํŒ
    • ๊ธ€ ๋ชฉ๋ก ์นด๋“œ: Card
    • ๊ฒ€์ƒ‰/ํ•„ํ„ฐ: Input, DropdownMenu, Tabs
    • ๋Œ“๊ธ€ ์˜์—ญ: Textarea, Button, Separator
  • ์ฑ„ํŒ…
    • ๋ฐฉ ๋ชฉ๋ก/๋ฉ”์‹œ์ง€ ํŒจ๋„ ๋ ˆ์ด์•„์›ƒ: Sheet(๋ชจ๋ฐ”์ผ), ScrollArea
    • ๋ฉ”์‹œ์ง€ ์ž…๋ ฅ: Textarea/Input + Button
    • ์‹œ์Šคํ…œ ์•Œ๋ฆผ/์—๋Ÿฌ ์•ˆ๋‚ด: Toast

4. ๋‹ค๋ฅธ ์Šคํƒ๊ณผ์˜ ๋น„๊ต ํ‘œ

ํ•ญ๋ชฉ shadcn/ui MUI (Material UI) Ant Design
์‚ฌ์šฉ ๋ฐฉ์‹ ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ๋ฅผ ํ”„๋กœ์ ํŠธ์— ์ถ”๊ฐ€ํ•˜์—ฌ ์†Œ์œ  ํŒจํ‚ค์ง€ ์„ค์น˜ ํ›„ ์ปดํฌ๋„ŒํŠธ ์‚ฌ์šฉ ํŒจํ‚ค์ง€ ์„ค์น˜ ํ›„ ์ปดํฌ๋„ŒํŠธ ์‚ฌ์šฉ
์ปค์Šคํ„ฐ๋งˆ์ด์ง• ์ฝ”๋“œ ์ˆ˜์ •์œผ๋กœ ์ง์ ‘ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ๊ฐ€๋Šฅ ํ…Œ๋งˆ/์˜ค๋ฒ„๋ผ์ด๋“œ ์ค‘์‹ฌ(๊ทœ์น™ ํ•™์Šต ํ•„์š”) ํ…Œ๋งˆ ์ค‘์‹ฌ(๋””์ž์ธ ์‹œ์Šคํ…œ ์„ฑ๊ฒฉ ๊ฐ•ํ•จ)
๋””์ž์ธ ์ผ๊ด€์„ฑ ํ”„๋กœ์ ํŠธ ๊ทœ์น™ ์ค‘์‹ฌ์œผ๋กœ ์„ค๊ณ„ ๊ฐ€๋Šฅ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ธฐ๋ณธ ๋””์ž์ธ ์ฒด๊ณ„๊ฐ€ ์กด์žฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ธฐ๋ณธ ๋””์ž์ธ ์ฒด๊ณ„๊ฐ€ ๊ฐ•ํ•จ
์—…๋ฐ์ดํŠธ ์˜ํ–ฅ ํ•„์š” ์‹œ์—๋งŒ ๋ฐ˜์˜(์„ ํƒ์ ) ์—…๋ฐ์ดํŠธ์— ๋”ฐ๋ฅธ ์˜ํ–ฅ ๊ฐ€๋Šฅ ์—…๋ฐ์ดํŠธ์— ๋”ฐ๋ฅธ ์˜ํ–ฅ ๊ฐ€๋Šฅ
์ ํ•ฉํ•œ ์ƒํ™ฉ ์„œ๋น„์Šค ๊ณ ์œ  UI๊ฐ€ ๋งŽ๊ณ  ์ฝ”๋“œ ์†Œ์œ ๋ฅผ ์„ ํ˜ธํ•  ๋•Œ ํ‘œ์ค€ UI๋กœ ๋น ๋ฅด๊ฒŒ ๊ตฌ์ถ•ํ•  ๋•Œ ๋Œ€์‹œ๋ณด๋“œ/๊ด€๋ฆฌ์ž ์„ฑ๊ฒฉ UI์— ์œ ๋ฆฌ
  • ์„œ๋น„์Šค ๊ณ ์œ  UI ๋ฐ˜์˜(์ปค์Šคํ„ฐ๋งˆ์ด์ง• ๋น„์šฉ)

    • MUI / Ant Design์€ ๊ธฐ๋ณธ ๋””์ž์ธ ์‹œ์Šคํ…œ์ด ๊ฐ•ํ•ด์„œ, ์„œ๋น„์Šค๋งŒ์˜ ํ†ค์•ค๋งค๋„ˆ(๊ฐ„๊ฒฉ/ํฐํŠธ/๋ฒ„ํŠผ ํ˜•ํƒœ/๋ชจ๋‹ฌ ๋™์ž‘)๋ฅผ ๋งž์ถ”๋ ค๋ฉด ํ…Œ๋งˆ ์„ค์ •ยท์˜ค๋ฒ„๋ผ์ด๋“œ ๊ทœ์น™์„ ๊นŠ๊ฒŒ ์ดํ•ดํ•ด์•ผ ํ•˜๊ณ , ์ปค์Šคํ…€ ๋ฒ”์œ„๊ฐ€ ์ปค์งˆ์ˆ˜๋ก ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฐฉ์‹์— ๋งž์ถฐ ์ˆ˜์ •ํ•˜๋Š” ๋น„์šฉ์ด ๋ˆ„์ ๋  ์ˆ˜ ์žˆ์Œ

      โ†”๏ธ ๋ฐ˜๋ฉด shadcn/ui๋Š” ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ๋ฅผ ํ”„๋กœ์ ํŠธ์— ์ง์ ‘ ๊ฐ€์ ธ์™€ ์ฝ”๋“œ ์ž์ฒด๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๊ตฌ์กฐ๋ผ, Devths์ฒ˜๋Ÿผ ํ™”๋ฉด์ด ๋งŽ๊ณ  UI ๋””ํ…Œ์ผ์ด ์ž์ฃผ ๋ฐ”๋€Œ๋Š” ํ”„๋กœ์ ํŠธ์—์„œ ์š”๊ตฌ์‚ฌํ•ญ์„ ๋น ๋ฅด๊ฒŒ ๋ฐ˜์˜ํ•˜๊ณ  ์ผ๊ด€๋œ ์Šคํƒ€์ผ ๊ทœ์น™์„ ์œ ์ง€ํ•˜๊ธฐ ์œ ๋ฆฌํ•จ

  • ์ฝ”๋“œ ์†Œ์œ ๊ถŒ๊ณผ ์—…๋ฐ์ดํŠธ ๋ฆฌ์Šคํฌ ํ†ต์ œ

    • MUI / Ant Design์€ ํŒจํ‚ค์ง€์— ์˜์กดํ•˜๋Š” ๋ฐฉ์‹์ด๋ผ, ๋ฒ„์ „ ์—…๋ฐ์ดํŠธ ์‹œ ๋‚ด๋ถ€ ๋ณ€๊ฒฝ์— ๋”ฐ๋ผ ์Šคํƒ€์ผ/๋™์ž‘์ด ์˜ํ–ฅ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๊ณ (ํŠนํžˆ ์ปค์Šคํ…€ ์˜ค๋ฒ„๋ผ์ด๋“œ๊ฐ€ ๋งŽ์„์ˆ˜๋ก) ํšŒ๊ท€ ์ด์Šˆ ๋Œ€์‘ ๋น„์šฉ์ด ์ปค์งˆ ์ˆ˜ ์žˆ์Œ

      โ†”๏ธ ๋ฐ˜๋ฉด shadcn/ui๋Š” ํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ๋งŒ ํ”„๋กœ์ ํŠธ์— ์ถ”๊ฐ€ํ•˜๊ณ , ์—…๋ฐ์ดํŠธ๋„ ํ•„์š”ํ•  ๋•Œ๋งŒ ์„ ํƒ์ ์œผ๋กœ ๋ฐ˜์˜ํ•  ์ˆ˜ ์žˆ์–ด, ์—…๋ฐ์ดํŠธ ์˜ํ–ฅ ๋ฒ”์œ„๋ฅผ ํŒ€์ด ํ†ต์ œํ•˜๊ธฐ ์‰ฌ์›€

  • ์ ‘๊ทผ์„ฑ(ARIA/ํ‚ค๋ณด๋“œ ํฌ์ปค์Šค) ํ’ˆ์งˆ ํ™•๋ณด

    • ๋ชจ๋‹ฌ/๋“œ๋กญ๋‹ค์šด/ํƒญ/ํˆดํŒ ๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ๋Š” ํ‚ค๋ณด๋“œ ํฌ์ปค์Šค ์ด๋™, aria ์†์„ฑ, ์Šคํฌ๋ฆฐ๋ฆฌ๋” ๋Œ€์‘ ๋“ฑ ์ ‘๊ทผ์„ฑ ์š”๊ตฌ๋ฅผ ์ œ๋Œ€๋กœ ๋งž์ถ”์ง€ ์•Š์œผ๋ฉด ํ’ˆ์งˆ ํŽธ์ฐจ๊ฐ€ ์ƒ๊ธฐ๊ธฐ ์‰ฌ์›€

      โ†”๏ธ shadcn/ui๋Š” Radix UI ๊ธฐ๋ฐ˜ ํŒจํ„ด์„ ํ™œ์šฉํ•˜๋ฏ€๋กœ, Devths์—์„œ ๋ฐ˜๋ณต์ ์œผ๋กœ ํ•„์š”ํ•œ ์ƒํ˜ธ์ž‘์šฉ UI๋ฅผ ์ ‘๊ทผ์„ฑ ๊ธฐ์ค€์— ๋งž์ถฐ ํ‘œ์ค€ํ™”๋œ ํ’ˆ์งˆ๋กœ ๊ฐ€์ ธ๊ฐ€๊ธฐ ์œ ๋ฆฌํ•จ

  • Tailwind ๊ธฐ๋ฐ˜ ์Šคํƒ€์ผ๋ง๊ณผ์˜ ์ •ํ•ฉ์„ฑ

    • Devths๋Š” Tailwind๋ฅผ ์Šคํƒ€์ผ๋ง ์ „๋žต์œผ๋กœ ์ฑ„ํƒํ–ˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ปดํฌ๋„ŒํŠธ ๋ ˆ๋ฒจ์—์„œ๋„ Tailwind ์œ ํ‹ธ๋ฆฌํ‹ฐ๋กœ ์Šคํƒ€์ผ์„ ํ†ต์ผํ•˜๋Š” ๊ฒƒ์ด ์œ ์ง€๋ณด์ˆ˜์— ์œ ๋ฆฌํ•จ

      โ†”๏ธ shadcn/ui๋Š” Tailwind ์ค‘์‹ฌ์œผ๋กœ ๊ตฌ์„ฑ/ํ™•์žฅํ•˜๋Š” ํ๋ฆ„๊ณผ ์ž˜ ๋งž์•„, ์ „์—ญ ๋””์ž์ธ ๊ทœ์น™(config) + ์ปดํฌ๋„ŒํŠธ ๊ตฌํ˜„์„ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์šด์˜ํ•˜๊ธฐ ์‰ฌ์›€

5. ๊ฒฐ๋ก 

  • devths๋Š” ๋‹ค์ˆ˜์˜ ํ™”๋ฉด๊ณผ ๋ฐ˜๋ณต๋˜๋Š” ์ƒํ˜ธ์ž‘์šฉ UI๊ฐ€ ์กด์žฌํ•˜๋ฉฐ, ์ „์—ญ ๋ชจ๋‹ฌ/ํƒญ/๋“œ๋กญ๋‹ค์šด ๋“ฑ ์ ‘๊ทผ์„ฑ๊นŒ์ง€ ๊ณ ๋ คํ•ด์•ผ ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์˜ ๋น„์ค‘์ด ๋†’์Œ
  • shadcn/ui๋Š” ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ๋ฅผ ํ”„๋กœ์ ํŠธ๊ฐ€ ์ง์ ‘ ์†Œ์œ ํ•˜์—ฌ ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž๊ฒŒ ์ˆ˜์ •, ํ™•์žฅํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, devths์˜ UI ํ‘œ์ค€ํ™”์™€ ์œ ์ง€๋ณด์ˆ˜์„ฑ ํ™•๋ณด๋ฅผ ์œ„ํ•ด ์ ํ•ฉํ•œ ์„ ํƒ์œผ๋กœ ํŒ๋‹จํ•จ

โœ… ๋‹ฌ๋ ฅ UI ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - FullCalendar v6.1.20

1. ํŠน์ง• ์š”์•ฝ

  • ์›”/์ฃผ/์ผ ๋ทฐ ๋“ฑ ์บ˜๋ฆฐ๋” UI๋ฅผ ์™„์„ฑ๋„ ๋†’๊ฒŒ ์ œ๊ณต
    • ๊ธฐ๋ณธ์œผ๋กœ Month/Week/Day ๋ทฐ๋ฅผ ์ง€์›ํ•˜๊ณ , ์ผ์ •(์ด๋ฒคํŠธ)์„ ์บ˜๋ฆฐ๋” ํ˜•ํƒœ๋กœ ์‹œ๊ฐํ™”ํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์ž˜ ๊ฐ–์ถฐ์ ธ ์žˆ์Œ
  • ๊ฐ•๋ ฅํ•œ ์ธํ„ฐ๋ž™์…˜ ์ง€์›
    • ๋‚ ์งœ ํด๋ฆญ, ์ผ์ • ํด๋ฆญ, ๋“œ๋ž˜๊ทธ&๋“œ๋กญ ์ด๋™, ๋ฆฌ์‚ฌ์ด์ฆˆ(์‹œ๊ฐ„ ๋Š˜๋ฆฌ๊ธฐ) ๋“ฑ ์บ˜๋ฆฐ๋”์—์„œ ๊ธฐ๋Œ€ํ•˜๋Š” UX๋ฅผ ํ‘œ์ค€ ๊ธฐ๋Šฅ์œผ๋กœ ์ œ๊ณต
  • ์ด๋ฒคํŠธ ๋ฐ์ดํ„ฐ ๋ Œ๋”๋ง/์ปค์Šคํ„ฐ๋งˆ์ด์ง•์ด ์œ ์—ฐํ•จ
    • ์ด๋ฒคํŠธ ์ƒ‰์ƒ, ํ‘œ์‹œ ํ˜•ํƒœ, ํˆดํŒ/ํŒ์˜ค๋ฒ„, ์ปค์Šคํ…€ ๋ Œ๋”๋ง ๋“ฑ UI ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž๊ฒŒ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ๊ฐ€๋Šฅ
  • ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ตฌ์กฐ
    • ํ•„์š”ํ•œ ๋ทฐ/๊ธฐ๋Šฅ๋งŒ ์ถ”๊ฐ€ํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด, ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž๊ฒŒ ๊ตฌ์„ฑํ•˜๊ธฐ ์ข‹์Œ
    • ์˜ˆ: dayGrid, timeGrid, interaction ๋“ฑ
  • React ์—ฐ๋™ ์ง€์›
    • React์šฉ ํŒจํ‚ค์ง€๋ฅผ ์ œ๊ณตํ•ด ์ปดํฌ๋„ŒํŠธ ํ˜•ํƒœ๋กœ ์บ˜๋ฆฐ๋”๋ฅผ ๋ถ™์ผ ์ˆ˜ ์žˆ๊ณ , ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ React ์ƒํƒœ/๋กœ์ง๊ณผ ์—ฐ๊ฒฐํ•˜๊ธฐ ์‰ฌ์›€

2. devths์— ์ด ๊ธฐ์ˆ ์ด ํ•„์š”ํ•œ ์ด์œ 

๐Ÿ’ก

Devths์˜ ์บ˜๋ฆฐ๋”๋Š” ๋‹จ์ˆœ ์ผ์ • ํ‘œ์‹œ๊ฐ€ ์•„๋‹ˆ๋ผ ์ผ์ • CRUD + ์‚ฌ์šฉ์ž ์ธํ„ฐ๋ž™์…˜ + AI(OCR) ๊ธฐ๋ฐ˜ ์ผ์ • ์ž๋™ ์‚ฝ์ž…๊นŒ์ง€ ํฌํ•จํ•˜๋Š” ํ•ต์‹ฌ ๊ธฐ๋Šฅ์ž„

  • FullCalendar๋Š” ์™„์„ฑ๋œ ์บ˜๋ฆฐ๋” UI + ๊ฐ•๋ ฅํ•œ ์ธํ„ฐ๋ž™์…˜์„ ๊ธฐ๋ณธ ์ œ๊ณตํ•˜๋ฏ€๋กœ, ์ง์ ‘ ์บ˜๋ฆฐ๋”๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋น„์šฉ์„ ์ค„์ด๊ณ  ํ•ต์‹ฌ ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ(OCR/AI, ์ผ์ • ๊ด€๋ฆฌ ๋กœ์ง)์— ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ์Œ

(1) ์›”/์ฃผ ๋ทฐ๊ฐ€ ํ•„์ˆ˜์ธ ์„œ๋น„์Šค ์š”๊ตฌ์‚ฌํ•ญ์— ์ ํ•ฉ

  • ์ฑ„์šฉ ์ผ์ •/๋งˆ๊ฐ/๋ฉด์ ‘ ์ผ์ •์€ ์›”/์ฃผ ๋‹จ์œ„๋กœ ๋ณด๋Š” ๋‹ˆ์ฆˆ๊ฐ€ ํผ

    โ†’ FullCalendar๋Š” ์ด ๋ทฐ๋ฅผ ๊ธฐ๋ณธ ์ง€์›

(2) ์ผ์ • ํŽธ์ง‘ UX(ํด๋ฆญ/๋“œ๋ž˜๊ทธ/๋ฆฌ์‚ฌ์ด์ฆˆ)๊ฐ€ ์ค‘์š”

  • ์ผ์ • ํด๋ฆญ โ†’ ์ƒ์„ธ/์ˆ˜์ • ๋ชจ๋‹ฌ
  • ๋“œ๋ž˜๊ทธ๋กœ ๋‚ ์งœ ์ด๋™, ๋ฆฌ์‚ฌ์ด์ฆˆ๋กœ ์‹œ๊ฐ„ ์กฐ์ • ๊ฐ™์€ UX๋ฅผ ์ œ๊ณตํ•˜๋ฉด ์บ˜๋ฆฐ๋” ์‚ฌ์šฉ์„ฑ์ด ํฌ๊ฒŒ ์˜ฌ๋ผ๊ฐ

(3) OCR๋กœ ์ƒ์„ฑ๋œ โ€œ์ดˆ์•ˆ ์ผ์ •โ€์„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ฐ˜์˜ ๊ฐ€๋Šฅ

  • OCR ๊ฒฐ๊ณผ๋กœ ์ƒ์„ฑ๋œ ์ด๋ฒคํŠธ๋ฅผ ์บ˜๋ฆฐ๋”์— ์ฆ‰์‹œ ๋ฏธ๋ฆฌ ๋ณด์—ฌ์ฃผ๊ณ (์ดˆ์•ˆ ํ‘œ์‹œ),
  • ์‚ฌ์šฉ์ž ํ™•์ธ ํ›„ ์ €์žฅํ•˜๋Š” ํ๋ฆ„์— ๋งž์ถฐ ์ด๋ฒคํŠธ ๋ Œ๋”๋ง/์—…๋ฐ์ดํŠธ๋ฅผ ์œ ์—ฐํ•˜๊ฒŒ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ

3. ์‚ฌ์šฉ ๋ฐฉ๋ฒ•

  • ์ด๋ฒคํŠธ ํƒ€์ž… ๊ณ ์ •(TypeScript)
    • ์„œ๋ฒ„์—์„œ ๋ฐ›์€ ์ด๋ฒคํŠธ๋ฅผ CalendarEvent ํƒ€์ž…์œผ๋กœ ๊ณ ์ •ํ•˜๊ณ , FullCalendar๊ฐ€ ์š”๊ตฌํ•˜๋Š” ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜ ํ•จ์ˆ˜๋กœ ๋งคํ•‘
  • ํ•ต์‹ฌ ์ธํ„ฐ๋ž™์…˜ ์—ฐ๊ฒฐ
    • ๋‚ ์งœ ํด๋ฆญ: ์ผ์ • ์ถ”๊ฐ€ ๋ชจ๋‹ฌ ์˜คํ”ˆ
    • ์ด๋ฒคํŠธ ํด๋ฆญ: ์ผ์ • ์ƒ์„ธ/์ˆ˜์ • ๋ชจ๋‹ฌ ์˜คํ”ˆ
    • ๋“œ๋ž˜๊ทธ/๋ฆฌ์‚ฌ์ด์ฆˆ: ์ผ์ • ์ˆ˜์ • API ํ˜ธ์ถœ โ†’ ์„ฑ๊ณต ์‹œ ์ผ์ • ๋ชฉ๋ก ๊ฐฑ์‹ 
  • OCR ์ž๋™ ์‚ฝ์ž…
    • ์—…๋กœ๋“œ โ†’ ์ฒ˜๋ฆฌ์ค‘ ๋ชจ๋‹ฌ โ†’ ๊ฒฐ๊ณผ ์ดˆ์•ˆ ์ƒ์„ฑ โ†’ ์บ˜๋ฆฐ๋”์— ์ž„์‹œ ํ‘œ์‹œ โ†’ ์‚ฌ์šฉ์ž ํ™•์ • ์‹œ ์ €์žฅ

4. ๋‹ค๋ฅธ ์Šคํƒ๊ณผ์˜ ๋น„๊ต ํ‘œ

ํ•ญ๋ชฉ FullCalendar react-big-calendar ์ง์ ‘ ๊ตฌํ˜„
๊ตฌํ˜„ ๋ฒ”์œ„ ๋‹ฌ๋ ฅ UI ๊ธฐ๋Šฅ ํญ์ด ๋„“๊ณ , ๋ทฐ/์ด๋ฒคํŠธ ๋ฐฐ์น˜/์ƒํ˜ธ์ž‘์šฉ ์ง€์›์ด ์ฒด๊ณ„์  ๊ธฐ๋ณธ ๋‹ฌ๋ ฅ ๊ตฌํ˜„์€ ๊ฐ€๋Šฅํ•˜๋‚˜, ๋ณต์žกํ•œ ํ‘œํ˜„ ๊ทœ์น™์ด ๋งŽ์„์ˆ˜๋ก ์ปค์Šคํ…€ ๋ถ€๋‹ด ์ฆ๊ฐ€ ์™„์ „ ์ž์œ ์ด๋‚˜ ๋‚ ์งœ ๊ณ„์‚ฐ/๋ฐฐ์น˜/๊ฒน์นจ/์ ‘๊ทผ์„ฑ/์„ฑ๋Šฅ์„ ๋ชจ๋‘ ์ง์ ‘ ๊ตฌํ˜„ํ•ด์•ผ ํ•จ
์ปค์Šคํ„ฐ๋งˆ์ด์ง• ์ด๋ฒคํŠธ ํ‘œ์‹œ ๋ฐฉ์‹ ์ปค์Šคํ…€์— ๊ฐ•ํ•จ ์ปค์Šคํ…€ ๊ฐ€๋Šฅํ•˜๋‚˜ ์š”๊ตฌ์‚ฌํ•ญ์ด ๋งŽ์œผ๋ฉด ์„ค๊ณ„ ๋‚œ์ด๋„ ์ฆ๊ฐ€ ์ž์œ ๋„ ์ตœ๊ณ (๋Œ€์‹  ์œ ์ง€๋ณด์ˆ˜ ๋น„์šฉ ์ตœ๊ณ )
๋ฆฌ์Šคํฌ/์ผ์ • ๊ฒ€์ฆ๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ธฐ๋ฐ˜์œผ๋กœ ๋‹ฌ๋ ฅ ํŠน์œ  ์˜ˆ์™ธ ์ผ€์ด์Šค ๋ฆฌ์Šคํฌ ๊ฐ์†Œ ๋‹จ์ˆœ ์š”๊ตฌ์—๋Š” ์ ํ•ฉ, ๋ณต์žก ์š”๊ตฌ์—๋Š” ์ถ”๊ฐ€ ๋น„์šฉ ๋ฐœ์ƒ ๊ฐ€๋Šฅ ๊ฐœ๋ฐœ ๊ธฐ๊ฐ„/๋ฒ„๊ทธ/์„ฑ๋Šฅ ๋ฆฌ์Šคํฌ๊ฐ€ ํผ
Devths ์ ํ•ฉ๋„ ๊ทœ์น™์ด ๋งŽ์€ ์บ˜๋ฆฐ๋” UIโ€์— ์ ํ•ฉ ๋‹จ์ˆœ ๋‹ฌ๋ ฅ ์ˆ˜์ค€์ด๋ฉด ํ›„๋ณด ๊ณผ์ œ/๊ธฐ๊ฐ„ ์ œํ•œ ์ƒํ™ฉ์—์„œ๋Š” ๋น„์ถ”์ฒœ
  • ๊ตฌํ˜„ ๋ฒ”์œ„์™€ ๊ธฐ๋ณธ ๊ธฐ๋Šฅ ์ปค๋ฒ„๋ฆฌ์ง€

    • react-big-calendar๋Š” ๊ธฐ๋ณธ์ ์ธ ๋‹ฌ๋ ฅ ํ™”๋ฉด ๊ตฌ์„ฑ์€ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ์›”/์ฃผ ์ „ํ™˜ + ์ผ์ • ๋ฐฐ์น˜ + ํด๋ฆญ ์ƒํ˜ธ์ž‘์šฉ + ๋‹ค์–‘ํ•œ ํ‘œํ˜„ ๊ทœ์น™์ฒ˜๋Ÿผ ์š”๊ตฌ์‚ฌํ•ญ์ด ๋Š˜์–ด๋‚ ์ˆ˜๋ก ์ถ”๊ฐ€ ๊ตฌํ˜„ ๋ฒ”์œ„๊ฐ€ ๋น ๋ฅด๊ฒŒ ์ปค์งˆ ์ˆ˜ ์žˆ์Œ

    • ์ง์ ‘ ๊ตฌํ˜„์€ ์ž์œ ๋„๋Š” ๋†’์ง€๋งŒ, ๋‚ ์งœ ๊ทธ๋ฆฌ๋“œ ๊ตฌ์„ฑ/์›”ยท์ฃผ ๊ณ„์‚ฐ/์ด๋ฒคํŠธ ๋ฐฐ์น˜/๊ฒน์นจ ์ฒ˜๋ฆฌ ๊ฐ™์€ ๋‹ฌ๋ ฅ ํ•ต์‹ฌ ๋กœ์ง๊นŒ์ง€ ์ „๋ถ€ ์ง์ ‘ ์ฑ…์ž„์ ธ์•ผ ํ•ด์„œ ๊ฐœ๋ฐœ ๋‚œ์ด๋„์™€ ์ผ์ • ๋ถ€๋‹ด์ด ๋งค์šฐ ํผ

      โ†”๏ธ ๋ฐ˜๋ฉด FullCalendar๋Š” ๋‹ฌ๋ ฅ UI์—์„œ ๋ฐ˜๋ณต์ ์œผ๋กœ ํ•„์š”ํ•œ ๋ทฐ ์ „ํ™˜, ์ด๋ฒคํŠธ ๋ฐฐ์น˜, ์ƒํ˜ธ์ž‘์šฉ ์ฒ˜๋ฆฌ๊ฐ€ ์ฒด๊ณ„์ ์œผ๋กœ ์ œ๊ณต๋˜์–ด, Devths๋Š” ๋‹ฌ๋ ฅ ์—”์ง„์„ ์ƒˆ๋กœ ๋งŒ๋“ค๊ธฐ๋ณด๋‹ค ์„œ๋น„์Šค ์š”๊ตฌ์‚ฌํ•ญ์— ์ง‘์ค‘ํ•˜๊ธฐ ์œ ๋ฆฌํ•จ

  • ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ๋น„์šฉ๊ณผ ํ™•์žฅ์„ฑ

    • Devths ์บ˜๋ฆฐ๋”๋Š” ๋‹จ์ˆœํžˆ ์ผ์ • ๋ชฉ๋ก ํ‘œ์‹œ๊ฐ€ ์•„๋‹ˆ๋ผ, ์ /์„  ํ‘œํ˜„, ํƒœ๊ทธยท๋‹จ๊ณ„ยทํšŒ์‚ฌ ๊ฐ™์€ ๋ถ€๊ฐ€ ์ •๋ณด ํ‘œ์‹œ, ํ•„ํ„ฐ UX ๋“ฑ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ์š”์†Œ๊ฐ€ ๋Š˜์–ด๋‚  ๊ฐ€๋Šฅ์„ฑ์ด ํผ

    • react-big-calendar์—์„œ๋„ ์ปค์Šคํ…€์€ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ์š”๊ตฌ์‚ฌํ•ญ์ด ๋ณต์žกํ•ด์งˆ์ˆ˜๋ก ์„ค๊ณ„ ๋‚œ์ด๋„์™€ ์œ ์ง€๋ณด์ˆ˜ ๋น„์šฉ์ด ์ฆ๊ฐ€ํ•  ์ˆ˜ ์žˆ์Œ

    • ์ง์ ‘ ๊ตฌํ˜„์€ ์›ํ•˜๋Š” ๊ฑด ๋‹ค ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๊ทธ๋งŒํผ ๊ตฌํ˜„ยทํ…Œ์ŠคํŠธยท์œ ์ง€๋ณด์ˆ˜ ์ฑ…์ž„์ด ์ „๋ถ€ ํ”„๋กœ์ ํŠธ์— ๋‚จ์Œ

      โ†”๏ธ FullCalendar๋Š” ์ด๋ฒคํŠธ ๋ Œ๋”๋ง ์ปค์Šคํ„ฐ๋งˆ์ด์ง•์„ ์ „์ œ๋กœ ํ•œ ๊ตฌ์กฐ๊ฐ€ ํƒ„ํƒ„ํ•ด, ํ‘œํ˜„ ๊ทœ์น™์ด ๋งŽ์€ ์บ˜๋ฆฐ๋”์—์„œ ๋ณ€๊ฒฝ ๋Œ€์‘ ๋น„์šฉ์„ ๋‚ฎ์ถ”๋Š” ๋ฐ ์œ ๋ฆฌํ•จ.

  • ๋ฆฌ์Šคํฌ์™€ ์ผ์ •(๋‹ฌ๋ ฅ ํŠน์œ  ์˜ˆ์™ธ ์ผ€์ด์Šค)

    • ๋‹ฌ๋ ฅ์€ ์ƒ๊ฐ๋ณด๋‹ค ์˜ˆ์™ธ ์ผ€์ด์Šค๊ฐ€ ๋งŽ์Œ(์›” ๊ฒฝ๊ณ„, ์ฃผ์ฐจ ๊ณ„์‚ฐ, ํƒ€์ž„์กด/์ข…์ผ ์ผ์ •, ๊ธฐ๊ฐ„ ์ผ์ •์˜ ์‹œ์ž‘ยท๋ ์ฒ˜๋ฆฌ, ์ด๋ฒคํŠธ ๊ฒน์นจ ๋“ฑ).

    • ์ง์ ‘ ๊ตฌํ˜„์€ ์ด๋Ÿฐ ์˜ˆ์™ธ ์ผ€์ด์Šค๋ฅผ ๋ชจ๋‘ ์ง์ ‘ ํ•ด๊ฒฐํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋ฒ„๊ทธ/์„ฑ๋Šฅ/์ผ์ • ๋ฆฌ์Šคํฌ๊ฐ€ ๊ฐ€์žฅ ํผ.

    • react-big-calendar๋Š” ๋‹จ์ˆœ ์š”๊ตฌ์—” ์ ํ•ฉํ•˜์ง€๋งŒ, ๋ณต์žกํ•œ ๊ทœ์น™์ด ์ถ”๊ฐ€๋ ์ˆ˜๋ก ์ถ”๊ฐ€ ๊ตฌํ˜„ + ์˜ˆ์™ธ ์ผ€์ด์Šค ์ฒ˜๋ฆฌ๊ฐ€ ๋ˆ„์ ๋  ์ˆ˜ ์žˆ์Œ.

      โ†”๏ธ FullCalendar๋Š” ๊ฒ€์ฆ๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ธฐ๋ฐ˜์œผ๋กœ ๋‹ฌ๋ ฅ ํ•ต์‹ฌ ์˜ˆ์™ธ ์ผ€์ด์Šค๋ฅผ ๊ธฐ๋ณธ์ ์œผ๋กœ ํก์ˆ˜ํ•ด, ๊ธฐ๊ฐ„ ์ œํ•œ ํ™˜๊ฒฝ์—์„œ ์•ˆ์ •์ ์ธ ์„ ํƒ์ด ๋จ

  • Devths ์š”๊ตฌ์‚ฌํ•ญ ์ ํ•ฉ์„ฑ

    • Devths๋Š” ๊ทœ์น™์ด ๋งŽ์€ ์บ˜๋ฆฐ๋” UI๊ฐ€ ์ค‘์‹ฌ ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜์ด๋ฏ€๋กœ, ๋‹จ์ˆœ ๋‹ฌ๋ ฅ ์ˆ˜์ค€์— ์ตœ์ ํ™”๋œ ์„ ํƒ๋ณด๋‹ค ํ‘œํ˜„๋ ฅ/ํ™•์žฅ์„ฑ/์•ˆ์ •์„ฑ์ด ์ค‘์š”ํ•จ.

      โ†”๏ธ ๋”ฐ๋ผ์„œ Devths์—์„œ๋Š” FullCalendar๋ฅผ ์ฑ„ํƒํ•˜์—ฌ ๋‹ฌ๋ ฅ์˜ ํ•ต์‹ฌ ์—”์ง„์€ ๊ฒ€์ฆ๋œ ๋„๊ตฌ์— ๋งก๊ธฐ๊ณ , ์„œ๋น„์Šค ๊ณ ์œ  ์š”๊ตฌ์‚ฌํ•ญ(ํ•„ํ„ฐ๋ง, ์ปค์Šคํ…€ ๋ Œ๋”๋ง, ์ƒ์„ธ ์นด๋“œ/๋ชจ๋‹ฌ ํ”Œ๋กœ์šฐ)์— ๊ฐœ๋ฐœ ์—ญ๋Ÿ‰์„ ์ง‘์ค‘ํ•˜๋Š” ๊ตฌ์„ฑ์ด ํ•ฉ๋ฆฌ์ ์ž„.

5. ๋ฒ„์ „ ์„ ํƒ ์ด์œ 

  • v6.1.20
    • 2025๋…„ 12์›” 23์ผ์— ๋ฆด๋ฆฌ์ฆˆ๋จ
  • ์ด์œ 
    • ์•ˆ์ •์ ์ธ(Stable) ๋ฒ„์ „ ๋ผ์ธ์„ ๊ธฐ์ค€์œผ๋กœ ์„ ์ •ํ•˜์—ฌ, ๊ณผ์ œ/์„œ๋น„์Šค ๊ฐœ๋ฐœ์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์˜ˆ๊ธฐ์น˜ ๋ชปํ•œ ๋ณ€๊ฒฝ(๋ฒ ํƒ€ ๊ธฐ๋Šฅ/๋ถˆ์•ˆ์ •์„ฑ) ๋ฆฌ์Šคํฌ๋ฅผ ์ค„์ž„
    • React ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๊ตฌ์„ฑ(React ์ปดํฌ๋„ŒํŠธ ์ œ๊ณต)์„ ๊ธฐ๋ฐ˜์œผ๋กœ Next.js ํ”„๋กœ์ ํŠธ์— ์ ์šฉ์ด ์šฉ์ดํ•จ

6. ๊ฒฐ๋ก 

  • Devths ์บ˜๋ฆฐ๋”๋Š” Google Calendar API๋ฅผ ํ†ตํ•ด ์ผ์ • ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋˜, ํ™”๋ฉด ์š”๊ตฌ์‚ฌํ•ญ(์›”/์ฃผ ์ „ํ™˜, ์ผ์ • ์ /์„  ํ‘œํ˜„, ์ƒ์„ธ ์นด๋“œ/๋ชจ๋‹ฌ ์—ฐ๋™, ํ•„ํ„ฐ UX ๋“ฑ)์€ ํ”„๋ก ํŠธ์—์„œ ๊ตฌํ˜„ํ•ด์•ผ ํ•จ
  • FullCalendar๋Š” ๋‹ฌ๋ ฅ UI์˜ ๊ธฐ๋ณธ ๊ตฌ์กฐ์™€ ์ด๋ฒคํŠธ ๋ฐฐ์น˜/์ƒํ˜ธ์ž‘์šฉ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜์—ฌ ์š”๊ตฌ์‚ฌํ•ญ ์ถฉ์กฑ์— ์ ํ•ฉํ•˜๋ฉฐ, ๊ฐœ๋ฐœ ํšจ์œจ ๋ฐ ์œ ์ง€๋ณด์ˆ˜ ์ธก๋ฉด์—์„œ๋„ ์œ ๋ฆฌํ•จ

๐Ÿ’ป ๋นŒ๋“œ & ๊ฐœ๋ฐœ ํ™˜๊ฒฝ

โœ… ํŒจํ‚ค์ง€ ๊ด€๋ฆฌ ๋„๊ตฌ - pnpm v10.27.0

1. ํŠน์ง• ์š”์•ฝ

  • ๋น ๋ฅด๊ณ  ๋””์Šคํฌ ํšจ์œจ์ ์ธ ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ €
    • npm/yarn์ฒ˜๋Ÿผ node_modules๋ฅผ ์„ค์น˜ํ•˜์ง€๋งŒ, ์„ค์น˜ ์†๋„์™€ ๋””์Šคํฌ ์‚ฌ์šฉ๋Ÿ‰ ์ตœ์ ํ™”์— ๊ฐ•์ ์ด ์žˆ์Œ.
  • ๋ฒ„์ „ ๊ณ ์ •(์žฌํ˜„ ๊ฐ€๋Šฅํ•œ ์„ค์น˜) ์ง€์›
    • Corepack์„ ์“ฐ๋ฉด ํ”„๋กœ์ ํŠธ package.json์˜ packageManager ํ•„๋“œ๋กœ pnpm ๋ฒ„์ „์„ ๊ณ ์ •ํ•ด์„œ, ํŒ€์›/CI ํ™˜๊ฒฝ์ด ๋‹ฌ๋ผ๋„ ๊ฐ™์€ ๋ฒ„์ „์œผ๋กœ ์„ค์น˜๋˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Œ.
  • ์›Œํฌ์ŠคํŽ˜์ด์Šค(๋ชจ๋…ธ๋ ˆํฌ) ๊ตฌ์„ฑ์— ์ ํ•ฉ
    • pnpm-workspace.yaml ๊ธฐ๋ฐ˜์œผ๋กœ ์—ฌ๋Ÿฌ ํŒจํ‚ค์ง€๋ฅผ ํ•œ ๋ ˆํฌ์—์„œ ๊ด€๋ฆฌํ•˜๊ธฐ ์‰ฌ์›€.
  • ์„ค์ •/๊ทœ์น™์„ ํ•œ ๊ณณ์—์„œ ๊ด€๋ฆฌ ๊ฐ€๋Šฅ
    • ์„ค์ •์€ CLI / ํ™˜๊ฒฝ๋ณ€์ˆ˜ / pnpm-workspace.yaml / .npmrc์—์„œ ๊ฐ€์ ธ์˜ค๋ฉฐ, ํŒ€ ๊ณตํ†ต ๊ทœ์น™์„ ์ •ํ•˜๊ธฐ ์ข‹์Œ.

2. devths์— ์ด ๊ธฐ์ˆ ์ด ํ•„์š”ํ•œ ์ด์œ 

๐Ÿ’ก

Devths๋Š” ํ”„๋ก ํŠธ(Next/React/TS) + ํ…Œ์ŠคํŠธ/๋ฆฐํŠธ/๋นŒ๋“œ ๋„๊ตฌ + ๋‹ค์–‘ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์˜์กด์„ฑ์ด ๋งŽ์•„์งˆ ๊ฐ€๋Šฅ์„ฑ์ด ํฌ๊ณ , ํŒ€ ํ˜‘์—… ํ™˜๊ฒฝ์—์„œ๋Š” ์„ค์น˜ ๊ฒฐ๊ณผ๊ฐ€ ๋งค๋ฒˆ ๊ฐ™์•„์•ผ ์•ˆ์ •์ ์ž„.

(1) ํŒ€ ํ˜‘์—…์—์„œ ์„ค์น˜ ํ™˜๊ฒฝ์„ ํ†ต์ผํ•ด์•ผ ํ•จ

  • ํŒ€์›๋งˆ๋‹ค pnpm ๋ฒ„์ „์ด ๋‹ค๋ฅด๋ฉด ์„ค์น˜ ๊ฒฐ๊ณผ/๋ฝํŒŒ์ผ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์ด ๋‹ฌ๋ผ์ ธ ์ถฉ๋Œ์ด ๋‚  ์ˆ˜ ์žˆ์Œ

    โ†’ Corepack์œผ๋กœ pnpm ๋ฒ„์ „์„ ํ”„๋กœ์ ํŠธ์— ๊ณ ์ •ํ•˜๋ฉด ํ™˜๊ฒฝ ์ฐจ์ด๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์Œ.

(2) ์›Œํฌ์ŠคํŽ˜์ด์Šค๋กœ ํ™•์žฅ ๊ฐ€๋Šฅ

  • ์ดํ›„ apps/web, packages/ui, packages/shared ๊ฐ™์€ ๊ตฌ์กฐ๋กœ ์ปค์งˆ ๋•Œ pnpm-workspace.yaml ๊ธฐ๋ฐ˜ ๊ด€๋ฆฌ๊ฐ€ ํŽธํ•จ.

(3) CI(๋นŒ๋“œ/ํ…Œ์ŠคํŠธ)์—์„œ ์„ค์น˜ ์‹œ๊ฐ„์„ ์ค„์ด๊ธฐ ์œ ๋ฆฌ

  • pnpm์€ ์บ์‹œ/์Šคํ† ์–ด ๊ธฐ๋ฐ˜ ์„ค์น˜ ์ „๋žต์„ ์ œ๊ณตํ•ด์„œ ๋ฐ˜๋ณต ์„ค์น˜ ์ƒํ™ฉ(๋กœ์ปฌ/CI)์—์„œ ํšจ์œจ์„ ๊ธฐ๋Œ€ํ•  ์ˆ˜ ์žˆ์Œ.

3.์‚ฌ์šฉ ๋ฐฉ๋ฒ•

  • Corepack์œผ๋กœ pnpm ํ™œ์„ฑํ™” & ๋ฒ„์ „ ๊ณ ์ •

    • Corepack ํ™œ์„ฑํ™”: corepack enable pnpm

    • ํ”„๋กœ์ ํŠธ์—์„œ pnpm ๋ฒ„์ „ ๊ณ ์ •: corepack use [email protected]

      โ†’ package.json์— packageManager๊ฐ€ ๊ธฐ๋ก๋˜์–ด ํŒ€ ์ „์ฒด๊ฐ€ ๊ฐ™์€ ๋ฒ„์ „์„ ์“ฐ๊ธฐ ์‰ฌ์›€.

  • ๊ธฐ๋ณธ ๋ช…๋ น์–ด

    • ์˜์กด์„ฑ ์„ค์น˜: pnpm install
    • ํŒจํ‚ค์ง€ ์ถ”๊ฐ€: pnpm add <pkg> (๊ฐœ๋ฐœ ์˜์กด์„ฑ์€ D)
    • ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰: pnpm dev, pnpm build, pnpm lint (package.json scripts ๊ธฐ์ค€)

4. ๋‹ค๋ฅธ ์Šคํƒ๊ณผ์˜ ๋น„๊ต ํ‘œ

ํ•ญ๋ชฉ pnpm npm Yarn
์„ค์น˜/์šฉ๋Ÿ‰ ํšจ์œจ ์ „์—ญ ์ €์žฅ์†Œ(๊ณต์šฉ) ํ™œ์šฉ์œผ๋กœ ์ค‘๋ณต ์„ค์น˜ ๋‚ญ๋น„๋ฅผ ์ค„์ด๋Š” ๋ฐฉํ–ฅ ํ”„๋กœ์ ํŠธ๋ณ„ ์„ค์น˜ ์ค‘์‹ฌ(์ค‘๋ณต์ด ์ƒ๊ธฐ๊ธฐ ์‰ฌ์›€) ์„ค์ •/๋ฒ„์ „์— ๋”ฐ๋ผ ์ „๋žต์ด ๋‹ค๋ฆ„(ํ”„๋กœ์ ํŠธ ํ‘œ์ค€์— ์˜์กด)
์˜์กด์„ฑ โ€œ์—„๊ฒฉํ•จโ€ ์„ ์–ธํ•œ ์˜์กด์„ฑ ์ค‘์‹ฌ์œผ๋กœ ๋” ์—„๊ฒฉํ•œ ๊ตฌ์กฐ ์ง€ํ–ฅ โ†’ ์ˆจ์€ ์˜์กด์„ฑ ์‹ค์ˆ˜ ๋ฐฉ์ง€์— ์œ ๋ฆฌ ๋น„๊ต์  ๊ด€๋Œ€ํ•œ ํŽธ์ด๋ผ ์‹ค์ˆ˜๊ฐ€ ๋Šฆ๊ฒŒ ๋“œ๋Ÿฌ๋‚  ์ˆ˜ ์žˆ์Œ PnP ๋“ฑ ์„ ํƒ์ง€๋กœ ์—„๊ฒฉํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์œผ๋‚˜ ํŒ€ ํ•ฉ์˜/ํ•™์Šต์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Œ
ํŒ€/CI ์žฌํ˜„์„ฑ lockfile ๊ธฐ๋ฐ˜ ์žฌํ˜„์— ์ดˆ์  lockfile ๊ธฐ๋ฐ˜์ด์ง€๋งŒ ํ™˜๊ฒฝ ์ฐจ์ด ๊ด€๋ฆฌ๊ฐ€ ๊ณผ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ์Œ lockfile ๊ธฐ๋ฐ˜, ๋‹ค๋งŒ ์กฐ์ง/๋ ˆํฌ ํ‘œ์ค€์— ๋”ฐ๋ผ ํŽธ์ฐจ
  • ์„ค์น˜/์šฉ๋Ÿ‰ ํšจ์œจ

    • npm/Yarn์€ ํ”„๋กœ์ ํŠธ๋ณ„ node_modules ๊ตฌ์กฐ ํŠน์„ฑ์ƒ ๊ฐ™์€ ํŒจํ‚ค์ง€๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ๋‚ด๋ ค๋ฐ›์•„ ์ €์žฅํ•˜๋Š” ์ƒํ™ฉ์ด ๋ฐ˜๋ณต๋˜๊ธฐ ์‰ฌ์›Œ, ์˜์กด์„ฑ์ด ๋Š˜์–ด๋‚ ์ˆ˜๋ก ์„ค์น˜ ์‹œ๊ฐ„๊ณผ ๋””์Šคํฌ ์‚ฌ์šฉ๋Ÿ‰์ด ๋ˆ„์ ๋  ๊ฐ€๋Šฅ์„ฑ์ด ํผ

      โ†”๏ธ ๋ฐ˜๋ฉด pnpm์€ ๊ณต์šฉ ์ €์žฅ์†Œ(content-addressable store)์— ํŒจํ‚ค์ง€๋ฅผ ํ•œ ๋ฒˆ ์ €์žฅํ•˜๊ณ  ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ๋งํฌ๋กœ ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐฉ์‹์ด๋ผ, ํŒ€ ํ”„๋กœ์ ํŠธ์—์„œ ๋ฐ˜๋ณต ์„ค์น˜ ๋น„์šฉ์ด ์ค„์–ด๋“ค๊ณ  ๋กœ์ปฌยทCI ํ™˜๊ฒฝ ๋ชจ๋‘์—์„œ ํšจ์œจ์ด ์ข‹์•„์งˆ ์ˆ˜ ์žˆ์Œ

  • ์˜์กด์„ฑ ์˜ค๋ฅ˜๋ฅผ ๋นจ๋ฆฌ ๋“œ๋Ÿฌ๋‚ด๋Š” ๊ตฌ์กฐ

    • npm/Yarn(์ผ๋ฐ˜์ ์ธ node_modules ๊ตฌ์„ฑ)์—์„œ๋Š” ๊ฐ„์ ‘์ ์œผ๋กœ ์„ค์น˜๋œ ํŒจํ‚ค์ง€๊ฐ€ ์šฐ์—ฐํžˆ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ๊ฐ€ ์žˆ์–ด, ์‹ค์ œ๋กœ๋Š” ์„ ์–ธ๋˜์ง€ ์•Š์€ ์˜์กด์„ฑ์— ๊ธฐ๋Œ€๋Š” ์ฝ”๋“œ๊ฐ€ ๋Šฆ๊ฒŒ ๋ฐœ๊ฒฌ๋  ์ˆ˜ ์žˆ์Œ

      โ†”๏ธ ๋ฐ˜๋ฉด pnpm์€ ์„ ์–ธํ•œ ์˜์กด์„ฑ ์ค‘์‹ฌ์œผ๋กœ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•œ ๋” ์—„๊ฒฉํ•œ ์„ค์น˜ ๊ตฌ์กฐ๋ฅผ ์ง€ํ–ฅํ•˜๋ฏ€๋กœ, ์ˆจ์€ ์˜์กด์„ฑ/๋ชจ๋“ˆ ํ•ด์„ ๋ฌธ์ œ๋ฅผ ๊ฐœ๋ฐœ ์ดˆ๊ธฐ์— ๋“œ๋Ÿฌ๋‚ด๋Š” ๋ฐ ์œ ๋ฆฌํ•จ

  • CI/๋ฐฐํฌ ์žฌํ˜„์„ฑ

    • npm/Yarn๋„ lockfile์„ ์ œ๊ณตํ•˜์ง€๋งŒ, ํŒ€์ด ์‚ฌ์šฉํ•˜๋Š” ๋ฒ„์ „/ํ™˜๊ฒฝ ์ฐจ์ด์— ๋”ฐ๋ผ ์„ค์น˜ ๊ฒฐ๊ณผ๋ฅผ ๋™์ผํ•˜๊ฒŒ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์ถ”๊ฐ€ ๊ด€๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Œ

      โ†”๏ธ ๋ฐ˜๋ฉด pnpm์€ lockfile ๊ธฐ๋ฐ˜ ์žฌํ˜„์„ฑ์— ์ดˆ์ ์„ ๋‘๊ณ , ์„ค์น˜ ๊ตฌ์กฐ๊ฐ€ ๋น„๊ต์  ์ผ๊ด€๋˜๊ฒŒ ์œ ์ง€๋˜๋Š” ํŽธ์ด๋ผ CI์—์„œ ๊ฒฐ๊ณผ๋ฅผ ๊ณ ์ •ํ•˜๊ธฐ์— ์œ ๋ฆฌํ•˜๋ฉฐ, ๋ฐฐํฌ/๊ณผ์ œ ํ™˜๊ฒฝ์—์„œ ์˜ˆ์ธก ๋ถˆ๊ฐ€๋Šฅํ•œ ์˜์กด์„ฑ ์ด์Šˆ๋ฅผ ์ค„์ด๋Š” ๋ฐ ๋„์›€์ด ๋จ

5. ๋ฒ„์ „ ์„ ํƒ ์ด์œ 

  • v10.27.0
    • 2025๋…„ 12์›” 30์ผ์— ๋ฆด๋ฆฌ์ฆˆ
  • ์ด์œ 
    • pnpm์€ ๋ฉ”์ด์ € ๋ฒ„์ „ ๋‚ด์—์„œ ํŒจ์น˜ ๋ฒ„์ „์„ ์ตœ์‹ ์œผ๋กœ ์œ ์ง€ํ•˜๋Š” ๋ฐฉ์‹์ด ์ผ๋ฐ˜์ ์œผ๋กœ ์•ˆ์ •์ ์ด๋ฉฐ(๋ฒ„๊ทธ ์ˆ˜์ •/๊ฐœ์„  ๋ฐ˜์˜), v10.27.0์€ pnpm ๊ณต์‹ ๋ฆด๋ฆฌ์ฆˆ๋กœ ์ œ๊ณต๋˜๋Š” ๋ฒ„์ „์ž„
    • ๋”ฐ๋ผ์„œ Devths์—์„œ๋Š” ๋ฉ”์ด์ € ๋ฒ„์ „(10.x)์€ ์œ ์ง€ํ•˜๋˜, ์ตœ์‹  ์•ˆ์ • ํŒจ์น˜(v10.27.0) ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์‚ฌ์šฉํ•˜์—ฌ ์„ค์น˜/CI/์šด์˜ ๊ณผ์ •์—์„œ์˜ ์•ˆ์ •์„ฑ์„ ํ™•๋ณดํ•˜๋Š” ์ „๋žต์„ ์ฑ„ํƒํ•จ

6. ๊ฒฐ๋ก 

  • Devths๋Š” ํ”„๋ก ํŠธ์—”๋“œ ์˜์กด์„ฑ์ด ์ปค์งˆ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์€ ํ”„๋กœ์ ํŠธ์ด๋ฏ€๋กœ, ์„ค์น˜ ํšจ์œจ(์†๋„/์šฉ๋Ÿ‰)๊ณผ ํŒ€ ๋‹จ์œ„ ์žฌํ˜„์„ฑ(๋ฒ„์ „ ๊ณ ์ •/CI ์•ˆ์ •์„ฑ)์„ ๋™์‹œ์— ํ™•๋ณดํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•จ
  • ์ด์— ๋”ฐ๋ผ ํŒจํ‚ค์ง€ ๊ด€๋ฆฌ ๋„๊ตฌ๋กœ pnpm(ํ”„๋กœ์ ํŠธ ๋ฒ„์ „ ๊ณ ์ • ํฌํ•จ)์„ ์ฑ„ํƒํ•˜๋Š” ๊ฒƒ์ด ์ ์ ˆํ•˜๋‹ค๊ณ  ํŒ๋‹จํ•จ

โœ… ๋ชจ๋“ˆ ๋ฒˆ๋“ค๋Ÿฌ / ๋นŒ๋“œ ๋„๊ตฌ - Turbopack

1. ํŠน์ง• ์š”์•ฝ

๐Ÿ’ก

Devths๋Š” Next.js 16์„ ์“ฐ๋Š” ์ „์ œ๋กœ, ๋ฒˆ๋“ค๋Ÿฌ๋Š” ๋ณ„๋„ ์„ค์น˜๊ฐ€ ์•„๋‹ˆ๋ผ Next.js์— ๋‚ด์žฅ๋œ Turbopack์„ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ์“ฐ๋ฉด ์ž์—ฐ์Šค๋Ÿฌ์›€

  • Next.js ๋‚ด์žฅ ๋ฒˆ๋“ค๋Ÿฌ(๊ธฐ๋ณธ๊ฐ’)
    • Next.js 16์—์„œ Turbopack์ด ๊ธฐ๋ณธ ๋ฒˆ๋“ค๋Ÿฌ๊ฐ€ ๋˜์–ด, ๋ณ„๋„ ํ”Œ๋ž˜๊ทธ ์—†์ด๋„ ๊ฐœ๋ฐœ/๋นŒ๋“œ์—์„œ ์‚ฌ์šฉ๋จ
  • ๊ฐœ๋ฐœ ๊ฒฝํ—˜(DX) ์ตœ์ ํ™”: ๋น ๋ฅธ dev ์„œ๋ฒ„/๊ฐฑ์‹ 
    • ๋น ๋ฅธ ๊ฐœ๋ฐœ ์„œ๋ฒ„ ์‹œ์ž‘, ์ฝ”๋“œ ๋ณ€๊ฒฝ ์‹œ ๋น ๋ฅธ ๋ฆฌํ”„๋ ˆ์‹œ(๊ฐœ๋ฐœ ์›Œํฌํ”Œ๋กœ์šฐ ๊ฐœ์„ )๋ฅผ ๋ชฉํ‘œ๋กœ ์„ค๊ณ„๋จ
  • ํ”„๋กœ๋•์…˜ ๋นŒ๋“œ๊นŒ์ง€ ์ง€์› ๋ฒ”์œ„ ํ™•๋Œ€
    • Next.js 15.5๋ถ€ํ„ฐ next build ์ง€์›์ด ๋ฒ ํƒ€๋กœ ๋“ค์–ด๊ฐ€๊ณ , Next.js 16์—์„œ๋Š” dev/build ๋ชจ๋‘ โ€œ๊ธฐ๋ณธโ€ ํ๋ฆ„์œผ๋กœ ์ •๋ฆฌ๋จ
  • Webpack loader ์„ค์ •์— ๋œ ์˜์กด
    • Next.js์˜ ๊ธฐ๋ณธ ๊ธฐ๋Šฅ ๋ฒ”์œ„(CSS/JS ์ปดํŒŒ์ผ ๋“ฑ)๋Š” Turbopack์—์„œ ๋กœ๋” ์„ค์ • ์—†์ด๋„ ๋™์ž‘ํ•˜๋„๋ก ์•ˆ๋‚ด๋จ

2. devths์— ์ด ๊ธฐ์ˆ ์ด ํ•„์š”ํ•œ ์ด์œ 

  • (1) ํ™”๋ฉด/๊ธฐ๋Šฅ์ด ๋งŽ์•„ ๊ฐœ๋ฐœ ์ค‘ ์ˆ˜์ •ยท๊ฒ€์ฆ ์‚ฌ์ดํด์ด ๋งค์šฐ ์ž์ฃผ ๋ฐœ์ƒ

    • ์บ˜๋ฆฐ๋”(์›”/์ฃผ ๋ทฐ ์ „ํ™˜), ๊ฒŒ์‹œํŒ(๋ฌดํ•œ์Šคํฌ๋กค), ์ฑ„ํŒ…(์‹ค์‹œ๊ฐ„ UI), OCR ์—…๋กœ๋“œ/๋ชจ๋‹ฌ ๋“ฑ์€ ๊ฐœ๋ฐœ ์ค‘ ๋ณ€๊ฒฝ์ด ์žฆ์Œ

      โ†’ Turbopack์€ ๊ฐœ๋ฐœ ์›Œํฌํ”Œ๋กœ์šฐ ์†๋„ ๊ฐœ์„ ์„ ํ•ต์‹ฌ ๋ชฉํ‘œ๋กœ ํ•˜๊ณ , Next 16.1์—์„œ๋„ Turbopack/ํˆด๋ง ๊ฐœ์„ ์„ ๊ฐ•์กฐํ•จ

  • (2) Next.js 16์˜ ํ‘œ์ค€(๊ธฐ๋ณธ) ๋ฒˆ๋“ค๋Ÿฌ๋ฅผ ๋”ฐ๋ผ๊ฐ€๋ฉด ํŒ€ ๊ทœ์น™์ด ๋‹จ์ˆœํ•ด์ง

    • ๋”ฐ๋กœ -turbopack ํ”Œ๋ž˜๊ทธ๋ฅผ ๊ด€๋ฆฌํ•˜์ง€ ์•Š์•„๋„ ๋˜๊ณ , Next.js ์—…๊ทธ๋ ˆ์ด๋“œ ๊ฐ€์ด๋“œ์—์„œ๋„ โ€œ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉโ€์„ ์ „์ œ๋กœ ์„ค๋ช…๋จ

3. ์‚ฌ์šฉ ๋ฐฉ๋ฒ•

๊ธฐ๋ณธ ์‚ฌ์šฉ(Next.js 16)

  • pnpm dev โ†’ ๋‚ด๋ถ€์ ์œผ๋กœ next dev ์‹คํ–‰ ์‹œ Turbopack์ด ๊ธฐ๋ณธ ์ ์šฉ
  • pnpm build โ†’ next build๋„ ๊ธฐ๋ณธ์œผ๋กœ Turbopack ์‚ฌ์šฉ

4. ๋‹ค๋ฅธ ์Šคํƒ๊ณผ์˜ ๋น„๊ต ํ‘œ

ํ•ญ๋ชฉ Turbopack (Next.js ๊ธฐ๋ณธ) Webpack (Next.js์—์„œ --webpack) Vite (์ผ๋ฐ˜์ ์œผ๋กœ Vite + React)
Next.js ํ†ตํ•ฉ Next์— ๋‚ด์žฅ, ๊ธฐ๋ณธ ๋ฒˆ๋“ค๋Ÿฌ Next์—์„œ ์„ ํƒ์ ์œผ๋กœ ์‚ฌ์šฉ Next ํ”„๋ ˆ์ž„์›Œํฌ ๋Œ€์ฒด(๋ณ„๋„ ๋ผ์šฐํŒ…/SSR ๊ตฌ์„ฑ ํ•„์š”)
์„ค์ • ๋‚œ์ด๋„ ๊ณตํ†ต ์ผ€์ด์Šค โ€œ๋ฌด์„ค์ •โ€์— ๊ฐ€๊นŒ์›€ ํ•„์š”ํ•œ ์„ค์ •/ํ”Œ๋Ÿฌ๊ทธ์ธ ์กฐํ•ฉ์ด ๋Š˜ ์ˆ˜ ์žˆ์Œ ๋น ๋ฅด๊ฒŒ ์‹œ์ž‘ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์•ฑ ๊ตฌ์กฐ ์ปค์ง€๋ฉด ์กฐํ•ฉ ์„ค๊ณ„ ๋ถ€๋‹ด
๊ฐœ๋ฐœ ์ฒด๊ฐ ์†๋„ ๋ชฉํ‘œ ๋Œ€๊ทœ๋ชจ ์•ฑ์—์„œ ๋น ๋ฅธ dev ๊ฒฝํ—˜์„ ๋ชฉํ‘œ๋กœ ์„ค๊ณ„ ํ‘œ์ค€/์„ฑ์ˆ™, ๋‹ค๋งŒ dev ์†๋„๋Š” ํ”„๋กœ์ ํŠธ์— ๋”ฐ๋ผ ๋ถ€๋‹ด dev ์„œ๋ฒ„ ๋น ๋ฅธ ํŽธ(๋‹จ, Next ๊ธฐ๋Šฅ์€ ์ง์ ‘ ๋ถ™์—ฌ์•ผ ํ•จ)
ํ˜ธํ™˜์„ฑ/ํ™•์žฅ Next ๊ณตํ†ต ์‚ฌ์šฉ์€ ์ž˜ ์ง€์›, ๋‹ค๋งŒ ์ผ๋ถ€๋Š” โ€œwebpack ๋Œ€๋น„ ๊ฐญโ€ ์กด์žฌ(์˜ˆ: webpack ํ”Œ๋Ÿฌ๊ทธ์ธ) webpack ์ƒํƒœ๊ณ„(๋กœ๋”/ํ”Œ๋Ÿฌ๊ทธ์ธ) ํ™œ์šฉ ํญ์ด ํผ ๋ฒˆ๋“ค๋Ÿฌ ์ž์ฒด ์ƒํƒœ๊ณ„๋Š” ํ’๋ถ€ํ•˜์ง€๋งŒ Next์˜ SSR/๋ผ์šฐํŒ…์€ ๋ณ„๋„ ์„ค๊ณ„
์ถ”์ฒœ ์ƒํ™ฉ Next.js ํ‘œ์ค€ ํ๋ฆ„(์„ค์ • ์ ๊ฒŒ, ๋น ๋ฅธ dev) webpack ํ”Œ๋Ÿฌ๊ทธ์ธ/ํŠน์ˆ˜ ๋กœ๋”๊ฐ€ ๊ผญ ํ•„์š”ํ•  ๋•Œ Next๊ฐ€ ์•„๋‹ˆ๋ผ SPA ์ค‘์‹ฌ์œผ๋กœ ๊ฐ€๋ณ๊ฒŒ ๊ตฌ์„ฑํ•  ๋•Œ
  • Next.js ํ‘œ์ค€ ํ๋ฆ„ ์œ ์ง€(ํ†ตํ•ฉ์„ฑ)

    • Webpack(Next์—์„œ --webpack)์€ ํŠน์ • ๋กœ๋”/ํ”Œ๋Ÿฌ๊ทธ์ธ ์š”๊ตฌ๊ฐ€ ์ƒ๊ธฐ๋ฉด ์ปค์Šคํ…€ ์„ค์ •์ด ๋Š˜์–ด๋‚  ์ˆ˜ ์žˆ๊ณ , ์„ค์ •์ด ๋Š˜์–ด๋‚ ์ˆ˜๋ก Next ๊ธฐ๋ณธ ์ตœ์ ํ™”/์—…๋ฐ์ดํŠธ ํ๋ฆ„๊ณผ ์ถฉ๋Œํ•˜๊ฑฐ๋‚˜ ์œ ์ง€๋ณด์ˆ˜ ํฌ์ธํŠธ๊ฐ€ ์ฆ๊ฐ€ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Œ

      โ†”๏ธ ๋ฐ˜๋ฉด Turbopack(Next.js ๊ธฐ๋ณธ)์€ Next์— ๋‚ด์žฅ๋œ ๊ธฐ๋ณธ ๋ฒˆ๋“ค๋Ÿฌ๋กœ ๋™์ž‘ํ•˜๋ฏ€๋กœ, ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์˜๋„ํ•œ ๊ฐœ๋ฐœยท๋นŒ๋“œ ํŒŒ์ดํ”„๋ผ์ธ์„ ๊ทธ๋Œ€๋กœ ๋”ฐ๋ฅด๊ธฐ ์‰ฌ์›Œ ํ†ตํ•ฉ ๊ด€์ ์˜ ๋ฆฌ์Šคํฌ(์„ค์ • ์ถฉ๋Œ/์ถ”๊ฐ€ ๊ด€๋ฆฌ)๋ฅผ ์ค„์ด๋Š” ๋ฐ ์œ ๋ฆฌํ•จ

  • ๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ(๊ฐœ๋ฐœ ์ฒด๊ฐ ์†๋„) ์ค‘์‹ฌ์˜ ์„ ํƒ

    • Webpack์€ ํ‘œ์ค€์ ์ด์ง€๋งŒ, ํ”„๋กœ์ ํŠธ ๊ทœ๋ชจ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก ๊ฐœ๋ฐœ ์„œ๋ฒ„ ์ฒด๊ฐ ์†๋„(์žฌ๋นŒ๋“œ/ํ•ซ๋ฆฌ๋กœ๋“œ)๊ฐ€ ๋ถ€๋‹ด์ด ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์†๋„ ์ด์Šˆ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ตœ์ ํ™” ์ž‘์—…์ด ๋ณ„๋„ ๊ณผ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ์Œ

      โ†”๏ธ Turbopack์€ ๋Œ€๊ทœ๋ชจ ์•ฑ์—์„œ ๋น ๋ฅธ ๊ฐœ๋ฐœ ๊ฒฝํ—˜์„ ๋ชฉํ‘œ๋กœ ์„ค๊ณ„๋œ Next ๊ธฐ๋ณธ ์„ ํƒ์ง€์ด๋ฏ€๋กœ, ์ดˆ๊ธฐ๋ถ€ํ„ฐ ์„ค์ • ๋น„์šฉ ์—†์ด ๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ์„ ํ™•๋ณดํ•˜๋Š” ๋ฐฉํ–ฅ์— ๋” ์ ํ•ฉํ•จ

  • ํ”„๋กœ์ ํŠธ ํ™•์žฅ ์‹œ ๋ˆ„์  ๋น„์šฉ(์„ค๊ณ„ยท์šด์˜ ๋ถ€๋‹ด) ์ตœ์†Œํ™”

    • Vite(์ผ๋ฐ˜์ ์œผ๋กœ Vite + React)๋Š” dev ์„œ๋ฒ„๊ฐ€ ๋น ๋ฅด๊ณ  ์‹œ์ž‘์ด ๊ฐ€๋ณ์ง€๋งŒ, Next์˜ ๋ผ์šฐํŒ…/SSR/SSG/์„œ๋ฒ„ ๊ธฐ๋Šฅ์„ ํ”„๋ ˆ์ž„์›Œํฌ ์ฐจ์›์—์„œ ์ œ๊ณตํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ๊ฐ™์€ ๋ชฉ์ ์„ ๋‹ฌ์„ฑํ•˜๋ ค๋ฉด ๋ณ„๋„ ์กฐํ•ฉ ์„ค๊ณ„(๋ผ์šฐํŒ…, SSR ์ „๋žต, ์—๋Ÿฌ ์ฒ˜๋ฆฌ, ๋ฐฐํฌ ๊ตฌ์กฐ ๋“ฑ)๊ฐ€ ํ•„์š”ํ•ด์งˆ ์ˆ˜ ์žˆ์Œ

      โ†”๏ธ Devths๋Š” Next.js ๊ธฐ๋ฐ˜์œผ๋กœ ๊ธฐ๋Šฅ ํ™•์žฅ์ด ์˜ˆ์ƒ๋˜๋Š” ๊ตฌ์กฐ์ด๋ฏ€๋กœ, ๋ฒˆ๋“ค๋Ÿฌ๋„ Next ๋‚ด์žฅ ๊ธฐ๋ณธ๊ฐ’(Turbopack)์„ ์ฑ„ํƒํ•ด ํ”„๋ ˆ์ž„์›Œํฌ ์ œ๊ณต ๊ธฐ๋Šฅ + ๋ฒˆ๋“ค๋Ÿฌ๋ฅผ ํ•œ ํ๋ฆ„์œผ๋กœ ๋ฌถ๋Š” ๊ฒƒ์ด ํ™•์žฅ/์œ ์ง€๋ณด์ˆ˜ ๊ด€์ ์—์„œ ํ•ฉ๋ฆฌ์ ์ž„

5. ๊ฒฐ๋ก 

  • devths๋Š” Next.js ๊ธฐ๋ฐ˜์œผ๋กœ ํ™”๋ฉด๊ณผ ๊ธฐ๋Šฅ์ด ํ™•์žฅ๋˜๋Š” ๊ตฌ์กฐ์ด๋ฏ€๋กœ, Next.js์— ๊ธฐ๋ณธ์œผ๋กœ ํ†ตํ•ฉ๋œ Turbopack์„ ์‚ฌ์šฉํ•ด ๊ฐœ๋ฐœ ๊ฒฝํ—˜์„ ํ‘œ์ค€ํ™”ํ•˜๋Š” ๊ฒƒ์ด ์ ์ ˆํ•จ

๐Ÿ”Ž ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์ „๋žต

โœ… Zod v4.3.4

1. ํŠน์ง• ์š”์•ฝ

  • ์Šคํ‚ค๋งˆ ๊ธฐ๋ฐ˜ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ

    • ์ด ๋ฐ์ดํ„ฐ๋Š” ์ด๋Ÿฐ ํ˜•ํƒœ์—ฌ์•ผ ํ•œ๋‹ค๋ฅผ ์Šคํ‚ค๋งˆ(schema) ๋กœ ์ •์˜ํ•˜๊ณ , ์ž…๋ ฅ๊ฐ’/์‘๋‹ต๊ฐ’์ด ๊ทธ ๊ทœ์น™์„ ๋งŒ์กฑํ•˜๋Š”์ง€ ๊ฒ€์‚ฌํ•จ
  • TypeScript์™€ ๊ฐ•ํ•˜๊ฒŒ ์—ฐ๊ฒฐ๋จ (ํƒ€์ž… ์ถ”๋ก )

    • z.object({...})๋กœ ์Šคํ‚ค๋งˆ๋ฅผ ๋งŒ๋“ค๋ฉด, ๊ทธ ์Šคํ‚ค๋งˆ์—์„œ ํƒ€์ž…์„ ์ž๋™์œผ๋กœ ๋ฝ‘์•„(z.infer) ํ”„๋ก ํŠธ ์ „๋ฐ˜์—์„œ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ

      โ†’ โ€œ๊ฒ€์ฆ ๊ทœ์น™โ€๊ณผ โ€œํƒ€์ž…โ€์ด ๋”ฐ๋กœ ๋†€์ง€ ์•Š์Œ(๋™๊ธฐํ™”๋จ)

  • ๋Ÿฐํƒ€์ž„ ๊ฒ€์ฆ ๊ฐ€๋Šฅ

    • TypeScript๋Š” ์ปดํŒŒ์ผ ๋‹จ๊ณ„์—์„œ๋งŒ ์ฒดํฌํ•˜์ง€๋งŒ, Zod๋Š” ์‹ค์ œ ์‹คํ–‰ ์ค‘(๋Ÿฐํƒ€์ž„)์— ๋“ค์–ด์˜จ ๊ฐ’์„ ๊ฒ€์‚ฌํ•ด์„œ ์„œ๋ฒ„ ์‘๋‹ต/์™ธ๋ถ€ ์ž…๋ ฅ์˜ ์ด์ƒ๊ฐ’์„ ๋ง‰์„ ์ˆ˜ ์žˆ์Œ
  • ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ๊ตฌ์กฐํ™”

    • ์–ด๋–ค ํ•„๋“œ๊ฐ€ ์™œ ์‹คํŒจํ–ˆ๋Š”์ง€ ์—๋Ÿฌ ์ •๋ณด๋ฅผ ๊ตฌ์กฐ์ ์œผ๋กœ ์–ป์„ ์ˆ˜ ์žˆ์–ด, ํผ ์—๋Ÿฌ UI์— ์—ฐ๊ฒฐํ•˜๊ธฐ ์ข‹์Œ
  • safeParse๋กœ ์•ˆ์ „ํ•˜๊ฒŒ ์ฒ˜๋ฆฌ

    • ์˜ˆ์™ธ๋ฅผ ๋˜์ง€๋Š” ๋Œ€์‹  ์„ฑ๊ณต/์‹คํŒจ๋ฅผ ๊ฐ์ฒด๋กœ ๋ฐ˜ํ™˜ํ•ด, ์‹คํŒจ ์ผ€์ด์Šค๋ฅผ ์•ˆ์ •์ ์œผ๋กœ ๋ถ„๊ธฐ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์‰ฌ์›€

2. devths์— ์ด ๊ธฐ์ˆ ์ด ํ•„์š”ํ•œ ์ด์œ 

๐Ÿ’ก

Devths๋Š” ํผ ์ž…๋ ฅ + ํŒŒ์ผ ์—…๋กœ๋“œ + AI/OCR ๊ฒฐ๊ณผ + ์‹ค์‹œ๊ฐ„/๋ชฉ๋ก ๋ฐ์ดํ„ฐ์ฒ˜๋Ÿผ ์™ธ๋ถ€์—์„œ ๋“ค์–ด์˜ค๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ์•„์„œ, ํด๋ผ์ด์–ธํŠธ์—์„œ ๋ฐ์ดํ„ฐ ํ˜•ํƒœ๋ฅผ ํ™•์‹คํžˆ ๊ณ ์ •ํ•ด๋‘๋Š” ๊ฒŒ ์ค‘์š”ํ•จ.

(1) ํผ์ด ๋งŽ์•„ ์ž…๋ ฅ๊ฐ’ ๊ฒ€์ฆ์ด ๋ฐ˜๋ณต๋จ

  • ๋กœ๊ทธ์ธ/ํšŒ์›๊ฐ€์ž…, ํ”„๋กœํ•„ ์ˆ˜์ •, ๊ฒŒ์‹œ๊ธ€ ์ž‘์„ฑ, ํŒŒ์ผ ์—…๋กœ๋“œ ๋“ฑ

    โ†’ Zod๋กœ ์Šคํ‚ค๋งˆ๋ฅผ ๊ณตํ†ตํ™”ํ•˜๋ฉด ํผ๋งˆ๋‹ค ๊ฒ€์ฆ ๊ทœ์น™์„ ์ค‘๋ณต์œผ๋กœ ๊ตฌํ˜„ํ•˜์ง€ ์•Š๊ณ  ์ผ๊ด€๋œ ๊ธฐ์ค€์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Œ

(2) ์„œ๋ฒ„ ์‘๋‹ต์ด ํ•ญ์ƒ โ€˜์ •์ƒโ€™์ด๋ผ๊ณ  ๊ฐ€์ •ํ•˜๋ฉด ์œ„ํ—˜ํ•จ

  • ๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก, ๋Œ“๊ธ€, ์บ˜๋ฆฐ๋” ์ด๋ฒคํŠธ, ์ฑ„ํŒ…๋ฐฉ ๋ชฉ๋ก ๋“ฑ์€ API ์‘๋‹ต ๊ตฌ์กฐ๊ฐ€ ์กฐ๊ธˆ๋งŒ ๋ฐ”๋€Œ์–ด๋„ ํ™”๋ฉด์ด ๊นจ์งˆ ์ˆ˜ ์žˆ์Œ

    โ†’ Zod๋กœ ์‘๋‹ต์„ ๋Ÿฐํƒ€์ž„์—์„œ ๊ฒ€์ฆํ•˜๋ฉด ์กฐ์šฉํžˆ ๊นจ์ง€๋Š” ๋ฒ„๊ทธ๋ฅผ ์ค„์ด๊ณ , ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋ฉด ๋น ๋ฅด๊ฒŒ ๊ฐ์ง€ ๊ฐ€๋Šฅ

(3) OCR/AI ๊ฒฐ๊ณผ๋Š” ํŠนํžˆ ๋ถˆํ™•์‹คํ•œ ์ž…๋ ฅ

  • ๋‚ ์งœ/์‹œ๊ฐ„/์žฅ์†Œ๊ฐ€ ๋ˆ„๋ฝ๋˜๊ฑฐ๋‚˜ ํ˜•์‹์ด ์• ๋งคํ•œ ๊ฐ’์ด ๋“ค์–ด์˜ฌ ์ˆ˜ ์žˆ์Œ

    โ†’ Zod๋กœ โ€˜์ตœ์†Œํ•œ ์ด ํ•„๋“œ๋Š” ์žˆ์–ด์•ผ ํ•œ๋‹ค/์—†์œผ๋ฉด ๋ณด์ • UI๋กœ ์œ ๋„โ€™ ๊ฐ™์€ ๊ทœ์น™์„ ๋งŒ๋“ค๊ธฐ ์ข‹์Œ

3. ๋‹ค๋ฅธ ์Šคํƒ๊ณผ์˜ ๋น„๊ต ํ‘œ

ํ•ญ๋ชฉ Zod Yup Joi
TypeScript ๊ถํ•ฉ ์Šคํ‚ค๋งˆ์—์„œ ํƒ€์ž… ์ถ”๋ก  ์ค‘์‹ฌ์ด๋ผ TS์™€ ๊ฒฐํ•ฉ์ด ์ž์—ฐ์Šค๋Ÿฌ์›€ TS ์‚ฌ์šฉ์€ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ํƒ€์ž… ์ถ”๋ก ์ด Zod๋งŒํผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์Šคํ‚ค๋งˆ=ํƒ€์ž…์œผ๋กœ ์ด์–ด์ง€์ง„ ์•Š๋Š” ํŽธ ์ฃผ๋กœ ๋Ÿฐํƒ€์ž„ ๊ฒ€์ฆ ์ค‘์‹ฌ์ด๋ฉฐ ํ”„๋ก ํŠธ TS ํƒ€์ž… ํ๋ฆ„๊ณผ ์ผ์ฒดํ™”๋Š” ์ถ”๊ฐ€ ์ž‘์—…์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Œ
๊ทœ์น™ ๊ด€๋ฆฌ ๋ฐฉ์‹ ๊ฒ€์ฆ ๊ทœ์น™์„ ์Šคํ‚ค๋งˆ๋กœ ๊ณ ์ •ํ•˜๊ณ  ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์ข‹์Œ ์Šคํ‚ค๋งˆ ๊ธฐ๋ฐ˜์ด์ง€๋งŒ ํ”„๋กœ์ ํŠธ๋งˆ๋‹ค ํƒ€์ž…ยท๊ฒ€์ฆ ๋™๊ธฐํ™” ์ „๋žต์„ ๋”ฐ๋กœ ์žก๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Œ ๊ฐ•๋ ฅํ•œ ๊ฒ€์ฆ ๊ธฐ๋Šฅ์ด ์žˆ์ง€๋งŒ ํ”„๋ก ํŠธ ํผ ์ค‘์‹ฌ ์šด์˜์—์„œ๋Š” ๋‹ค์†Œ ๋ฌด๊ฒ๊ฒŒ ๋А๊ปด์งˆ ์ˆ˜ ์žˆ์Œ
Devths ์ ํ•ฉ ํฌ์ธํŠธ ํผ/์ž…๋ ฅ ๊ทœ์น™์ด ๋งŽ๊ณ , TS ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌ์กฐ๋ฅผ ํ‘œ์ค€ํ™”ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์œ ๋ฆฌ ๊ธฐ์กด Yup ๊ธฐ๋ฐ˜ ๋ ˆ๊ฑฐ์‹œ/ํŒ€ ๊ฒฝํ—˜์ด ๋งŽ๋‹ค๋ฉด ํ›„๋ณด ๊ฒ€์ฆ ์ŠคํŽ™์ด ๋งค์šฐ ๋ณต์žกํ•˜๊ณ  ๋Ÿฐํƒ€์ž„ ๊ฒ€์ฆ์„ ๊ฐ•ํ•˜๊ฒŒ ๊ฐ€์ ธ๊ฐ€์•ผ ํ•  ๋•Œ ํ›„๋ณด
  • TypeScript์™€์˜ ๊ฒฐํ•ฉ(์Šคํ‚ค๋งˆ=ํƒ€์ž… ํ๋ฆ„)

    • Yup์€ TypeScript ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ์Šคํ‚ค๋งˆ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค๊ณ  ํ•ด์„œ ๊ทธ๊ฒŒ ๊ณง๋ฐ”๋กœ ํ”„๋ก ํŠธ ํƒ€์ž…์˜ ๊ทผ๊ฑฐ๋กœ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ด์–ด์ง€์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์–ด, ํƒ€์ž…๊ณผ ๊ฒ€์ฆ ๊ทœ์น™์ด ๋”ฐ๋กœ ๋†€ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Œ

      โ†”๏ธ ๋ฐ˜๋ฉด Zod๋Š” ์Šคํ‚ค๋งˆ์—์„œ ํƒ€์ž…์„ ์ถ”๋ก ํ•˜๋Š” ํ๋ฆ„์ด ์ค‘์‹ฌ์ด๋ผ, ๊ฒ€์ฆ ๊ทœ์น™(์Šคํ‚ค๋งˆ)๊ณผ TypeScript ํƒ€์ž…์„ ํ•œ ๋ฉ์–ด๋ฆฌ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ์‰ฝ๊ณ , ํ•„๋“œ ๋ˆ„๋ฝ/nullable ์ฐฉ๊ฐ/ํƒ€์ž… ๋ถˆ์ผ์น˜ ๊ฐ™์€ ์‹ค์ˆ˜ ๋น„์šฉ์„ ์ค„์ด๋Š” ๋ฐ ์œ ๋ฆฌํ•จ

  • ๊ทœ์น™์˜ ํ‘œ์ค€ํ™” ๋ฐ ์žฌ์‚ฌ์šฉ(์ •์ฑ…์„ ์ฝ”๋“œ๋กœ ๊ณ ์ •)

    • Yup๋„ ์Šคํ‚ค๋งˆ ๊ธฐ๋ฐ˜์ด์ง€๋งŒ, ํ”„๋กœ์ ํŠธ์—์„œ ํƒ€์ž…ยท๊ฒ€์ฆ์„ ์–ด๋–ป๊ฒŒ ๋™๊ธฐํ™”ํ• ์ง€๋ฅผ ๋ณ„๋„ ์ „๋žต์œผ๋กœ ์žก์•„์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์–ด, ํ™”๋ฉด์ด ๋Š˜์–ด๋‚˜๋ฉด ๊ทœ์น™ ๊ด€๋ฆฌ๊ฐ€ ํŒ€ ์ปจ๋ฒค์…˜์— ๋” ์˜์กดํ•  ์ˆ˜ ์žˆ์Œ

      โ†”๏ธ Zod๋Š” ์Šคํ‚ค๋งˆ๋ฅผ ๋งŒ๋“ค๋ฉด ๊ทธ ์ž์ฒด๊ฐ€ ํƒ€์ž…๊ณผ ๊ฒ€์ฆ์˜ ๊ธฐ์ค€์ด ๋˜๊ธฐ ์‰ฌ์›Œ, ํšŒ์›๊ฐ€์ž…/๊ฒŒ์‹œ๊ธ€/๋Œ“๊ธ€/์ผ์ •/๊ฒ€์ƒ‰/ํŒŒ์ผ ์—…๋กœ๋“œ์ฒ˜๋Ÿผ ์ž…๋ ฅ ๊ทœ์น™์ด ๋ฐ˜๋ณต๋˜๋Š” Devths์—์„œ ๊ทœ์น™์„ ์ผ๊ด€๋œ ๋ฐฉ์‹์œผ๋กœ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์ข‹์Œ

  • ํ”„๋ก ํŠธ ํผ ์šด์˜ ์ ํ•ฉ์„ฑ

    • Joi๋Š” ๋Ÿฐํƒ€์ž„ ๊ฒ€์ฆ ๊ธฐ๋Šฅ์ด ๊ฐ•๋ ฅํ•˜์ง€๋งŒ, ํ”„๋ก ํŠธ ํผ ์ค‘์‹ฌ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ธฐ์—” ์ƒ๋Œ€์ ์œผ๋กœ ๋ฌด๊ฒ๊ฒŒ ๋А๊ปด์งˆ ์ˆ˜ ์žˆ๊ณ , TypeScript ํƒ€์ž… ํ๋ฆ„๊ณผ ์™„์ „ํžˆ ์ผ์ฒดํ™”ํ•˜๋ ค๋ฉด ์ถ”๊ฐ€ ์ž‘์—…์ด ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ์Œ

      โ†”๏ธ Zod๋Š” ํ”„๋ก ํŠธ์—์„œ ์ž…๋ ฅ๊ฐ’ ๊ฒ€์ฆ + ํƒ€์ž… ์ •ํ•ฉ์„ฑ ์œ ์ง€ ๋ชฉ์ ์— ๋งž๊ฒŒ ๊ฐ€๋ณ๊ณ  ์ง๊ด€์ ์œผ๋กœ ์ ์šฉ ๊ฐ€๋Šฅํ•ด, Devths์ฒ˜๋Ÿผ ํผ์ด ๋งŽ์€ ์„œ๋น„์Šค์—์„œ ์šด์˜ ๋ถ€๋‹ด์ด ๋‚ฎ์Œ

4. ๋ฒ„์ „ ์„ ํƒ ์ด์œ 

  • Zod v4.3.4
    • 2026๋…„ 1์›” 2์ผ ๋ฆด๋ฆฌ์ฆˆ
  • ์ด์œ 
    • v4 ๋ผ์ธ์€ ํ˜„์žฌ ๋ฌธ์„œ/์ƒํƒœ๊ณ„ ํ๋ฆ„์„ ๊ธฐ์ค€์œผ๋กœ ์žก๊ธฐ ์ข‹๊ณ , ์ตœ์‹  ํŒจ์น˜ ๋ฒ„์ „์„ ์ฑ„ํƒํ•˜๋ฉด ๋ฒ„๊ทธ ์ˆ˜์ • ๋ฐ ์•ˆ์ •์„ฑ ๊ฐœ์„ ์„ ํฌํ•จํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์•„ ์œ ์ง€๋ณด์ˆ˜์— ์œ ๋ฆฌํ•จ
    • ์šด์˜ ์ „๋žต์€ ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ๋™์ผํ•˜๊ฒŒ ๋ฉ”์ด์ €(v4)๋Š” ์œ ์ง€, ํŒจ์น˜/๋งˆ์ด๋„ˆ๋Š” ์ •๊ธฐ ๋ฐ˜์˜ํ•จ

5. ๊ฒฐ๋ก 

  • Devths๋Š” ์ž…๋ ฅ/ํผ์ด ๋งŽ๊ณ  ๊ฒ€์ฆ ๊ทœ์น™์ด ์„ธ๋ฐ€ํ•ด์งˆ ๊ฐ€๋Šฅ์„ฑ์ด ํฐ ์„œ๋น„์Šค์ด๋ฏ€๋กœ, ๊ฒ€์ฆ ๊ทœ์น™์„ ์Šคํ‚ค๋งˆ๋กœ ํ‘œ์ค€ํ™”ํ•˜๊ณ  TypeScript ํƒ€์ž…๊นŒ์ง€ ํ•จ๊ป˜ ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” Zod๋ฅผ ์ฑ„ํƒํ•˜๋Š” ๊ฒƒ์ด ์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ ์•ˆ์ •์„ฑ ์ธก๋ฉด์—์„œ ํ•ฉ๋ฆฌ์ ์ด๋ผ๊ณ  ํŒ๋‹จํ•จ

โœ… React Hook Form v7.70.0

1. ํŠน์ง• ์š”์•ฝ

  • ํผ(Form) ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ
    • ์ž…๋ ฅ๊ฐ’(value), ์—๋Ÿฌ(errors), ์ œ์ถœ(submit), ๋กœ๋”ฉ ์ƒํƒœ ๋“ฑ์„ ํผ ๋‹จ์œ„๋กœ ํ•œ ๋ฒˆ์— ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Œ
    • register, handleSubmit, formState ๊ฐ™์€ ๊ธฐ๋ณธ API๋กœ ํ๋ฆ„์ด ๋‹จ์ˆœํ•จ
  • ๋ฆฌ๋ Œ๋”๋ง์ด ์ ์–ด์„œ ์„ฑ๋Šฅ์— ์œ ๋ฆฌ
    • ์ž…๋ ฅํ•  ๋•Œ๋งˆ๋‹ค ์ „์ฒด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ณ„์† ๋ฆฌ๋ Œ๋”๋˜๋Š” ๋ฐฉ์‹์ด ์•„๋‹ˆ๋ผ, ํผ ์ƒํƒœ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ๋‹ค๋ค„์„œ ์ž…๋ ฅ ํ•„๋“œ๊ฐ€ ๋งŽ์•„๋„ ์„ฑ๋Šฅ์ด ๋น„๊ต์  ์•ˆ์ •์ ์ž„
  • ๊ฒ€์ฆ(Validation) ์—ฐ๊ฒฐ์ด ์‰ฌ์›€
    • ๊ธฐ๋ณธ ๊ฒ€์ฆ(required/minLength ๋“ฑ)๋„ ๊ฐ€๋Šฅํ•˜๊ณ ,
    • Zod ๊ฐ™์€ ์Šคํ‚ค๋งˆ ๊ฒ€์ฆ๋„ resolver๋กœ ์‰ฝ๊ฒŒ ์—ฐ๊ฒฐ ๊ฐ€๋Šฅ โ†’ ํ•œ ๊ณณ์—์„œ ๊ทœ์น™ ๊ด€๋ฆฌ ๊ฐ€๋Šฅ
  • ์—๋Ÿฌ ๋ฉ”์‹œ์ง€/UI ์—ฐ๊ฒฐ์ด ๊น”๋”ํ•จ
    • errors.email?.message์ฒ˜๋Ÿผ ํ•„๋“œ๋ณ„ ์—๋Ÿฌ๋ฅผ ๊ตฌ์กฐ์ ์œผ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์–ด, ์ž…๋ ฅํผ UI(์—๋Ÿฌ ํ…์ŠคํŠธ/๋นจ๊ฐ„ ํ…Œ๋‘๋ฆฌ) ๋ถ™์ด๊ธฐ ์‰ฌ์›€
  • ๋ณต์žกํ•œ ํผ ๊ธฐ๋Šฅ ์ง€์›
    • ๋™์  ํ•„๋“œ(์ถ”๊ฐ€/์‚ญ์ œ) useFieldArray
    • ํŠน์ • ๊ฐ’ ๊ฐ์‹œ watch
    • ์ปค์Šคํ…€

2. devths์— ์ด ๊ธฐ์ˆ ์ด ํ•„์š”ํ•œ ์ด์œ 

๐Ÿ’ก

Devths๋Š” ์ž…๋ ฅ ํผ์ด ๋งŽ์€ ์„œ๋น„์Šค๋ผ์„œ, ํผ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์ด ํ‘œ์ค€ํ™”๋˜์ง€ ์•Š์œผ๋ฉด ํŽ˜์ด์ง€๋งˆ๋‹ค ๊ตฌํ˜„ ๋ฐฉ์‹์ด ๋‹ฌ๋ผ์ง€๊ณ  ๋ฒ„๊ทธ๊ฐ€ ๋Š˜์–ด๋‚˜๊ธฐ ์‰ฌ์›€.

  • React Hook Form์„ ๋„์ž…ํ•˜๋ฉด ํผ ์ž…๋ ฅ โ†’ ๊ฒ€์ฆ โ†’ ์—๋Ÿฌ ํ‘œ์‹œ โ†’ ์ œ์ถœ ํ๋ฆ„์„ ๊ณตํ†ต ํŒจํ„ด์œผ๋กœ ํ†ต์ผํ•  ์ˆ˜ ์žˆ์Œ

(1) ํผ์ด ๋งŽ์€ ์„œ๋น„์Šค ๊ตฌ์กฐ

  • ๋กœ๊ทธ์ธ/ํšŒ์›๊ฐ€์ž…
  • ํ”„๋กœํ•„ ์ˆ˜์ •(๋‹‰๋„ค์ž„/๋น„๋ฐ€๋ฒˆํ˜ธ/์ด๋ฏธ์ง€)
  • ๊ฒŒ์‹œ๊ธ€ ์ž‘์„ฑ/์ˆ˜์ •(์ œ๋ชฉ/๋ณธ๋ฌธ/ํƒœ๊ทธ/์ฒจ๋ถ€)
  • ์บ˜๋ฆฐ๋” ์ผ์ • ์ถ”๊ฐ€/์ˆ˜์ •(์‹œ๊ฐ„/์žฅ์†Œ/๋ฉ”๋ชจ)
  • OCR ๊ฒฐ๊ณผ ์ผ์ • ์ดˆ์•ˆ(draft) ๊ฒ€ํ† /๋ณด์ • ์ž…๋ ฅ

โ†’ ํผ์ด ๋งŽ์„์ˆ˜๋ก โ€œ๊ฒ€์ฆ/์—๋Ÿฌ UI/์ œ์ถœ ๋กœ์งโ€์„ ๋งค๋ฒˆ ์ง์ ‘ ์งœ๋ฉด ์ค‘๋ณต์ด ์ปค์ง

โ†’ RHF๋กœ ๊ณตํ†ต ํ๋ฆ„์„ ์žก์œผ๋ฉด ์œ ์ง€๋ณด์ˆ˜ ๋น„์šฉ์ด ์ค„์–ด๋“ฆ

(2) Zod์™€ ์กฐํ•ฉํ•ด์„œ โ€˜๊ฒ€์ฆ ๊ทœ์น™โ€™์„ ํ•œ ๊ณณ์— ๋ชจ์„ ์ˆ˜ ์žˆ์Œ

  • Devths๋Š” ์ด๋ฏธ Zod๋ฅผ ์“ฐ๋Š” ๋ฐฉํ–ฅ์ด๋ฏ€๋กœ,

  • RHF + Zod resolver ์กฐํ•ฉ์ด๋ฉด ํƒ€์ž…/๊ฒ€์ฆ/์—๋Ÿฌ๋ฉ”์‹œ์ง€๊ฐ€ ํ•œ ๋ฉ์–ด๋ฆฌ๋กœ ๊ด€๋ฆฌ๋จ

    โ†’ ํผ๋งˆ๋‹ค ๊ฒ€์ฆ ๊ทœ์น™์ด ๋“ค์ญ‰๋‚ ์ญ‰ํ•ด์ง€๋Š” ๋ฌธ์ œ๋ฅผ ์ค„์ž„

(3) OCR/AI ๊ฒฐ๊ณผ์ฒ˜๋Ÿผ ๋ถˆ์™„์ „ํ•œ ์ž…๋ ฅ์„ ๋ณด์ •ํ•˜๋Š” UX์— ์ ํ•ฉ

  • OCR์ด ๋‚ ์งœ/์‹œ๊ฐ„์„ ๋ชป ๋ฝ‘๋Š” ๊ฒฝ์šฐ, ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ์ฑ„์›Œ ๋„ฃ๋Š” ํผ์ด ํ•„์š”ํ•จ

    โ†’ RHF๋กœ ๋ถ€๋ถ„ ์ž…๋ ฅ + ์ฆ‰์‹œ ๊ฒ€์ฆ + ์ €์žฅ ํ”Œ๋กœ์šฐ๋ฅผ ์•ˆ์ •์ ์œผ๋กœ ๋งŒ๋“ค๊ธฐ ์ข‹์Œ

3. ๋‹ค๋ฅธ ์Šคํƒ๊ณผ์˜ ๋น„๊ต ํ‘œ

ํ•ญ๋ชฉ React Hook Form Formik React ๋‹จ๋…(useState๋กœ ์ง์ ‘ ๊ตฌํ˜„)
ํผ ์ƒํƒœ ๊ด€๋ฆฌ ๋ฐฉ์‹ ํ•„์š”ํ•œ ์ƒํƒœ๋ฅผ ์„ ํƒ์ ์œผ๋กœ ๊ตฌ๋…ํ•˜๋Š” ํŒจํ„ด์— ๊ฐ•์  ํผ ์ƒํƒœ๋ฅผ ํ•œ ๋ฉ์–ด๋ฆฌ๋กœ ๋‹ค๋ฃจ๋Š” ๋ฐฉ์‹์ด ํ”ํ•จ ํ™”๋ฉด๋งˆ๋‹ค ์ œ๊ฐ๊ฐ ๊ตฌํ˜„๋  ๊ฐ€๋Šฅ์„ฑ์ด ํผ
๋ Œ๋”๋ง/์„ฑ๋Šฅ ๊ด€์  ํฐ ํผ/์ž…๋ ฅ ๋งŽ์„ ๋•Œ ๋ฆฌ๋ Œ๋”๋ง ์ œ์–ด์— ์œ ๋ฆฌ ๊ทœ๋ชจ ์ปค์ง€๋ฉด ์ตœ์ ํ™”๊ฐ€ ์ถ”๊ฐ€๋กœ ํ•„์š”ํ•ด์งˆ ์ˆ˜ ์žˆ์Œ ์ตœ์ ํ™”/ํŒจํ„ดํ™” ๋ชจ๋‘ ์ง์ ‘ ์ฑ…์ž„
๊ฒ€์ฆ ๋„๊ตฌ ๊ฒฐํ•ฉ Zod ๋“ฑ ์Šคํ‚ค๋งˆ ๊ฒ€์ฆ๊ณผ ๊ฒฐํ•ฉ ํŒจํ„ด์ด ๋„๋ฆฌ ์“ฐ์ž„ Yup ์กฐํ•ฉ์ด ํ”ํ•˜์ง€๋งŒ ๊ตฌ์„ฑ์— ๋”ฐ๋ผ ๋‹ค๋ฆ„ ๊ฒ€์ฆ/์—๋Ÿฌ ๋งคํ•‘ ๋กœ์ง์„ ์ง์ ‘ ๋‹ค ๋งŒ๋“ค์–ด์•ผ ํ•จ
Devths ์ ํ•ฉ๋„ ์ž…๋ ฅ ํ™”๋ฉด/๊ทœ์น™์ด ๋งŽ์€ ์„œ๋น„์Šค์— ์ ํ•ฉ ํŒ€์ด Formik ํ‘œ์ค€์„ ์ด๋ฏธ ์“ฐ๋ฉด ํ›„๋ณด ์žฅ๊ธฐ์ ์œผ๋กœ ์œ ์ง€๋ณด์ˆ˜ ๋น„์šฉ์ด ์ปค์ง€๊ธฐ ์‰ฌ์›€
  • ํผ ์ƒํƒœ ๊ด€๋ฆฌ์˜ ํ‘œ์ค€ํ™”(๊ตฌํ˜„ ๋ฐฉ์‹ ํ”๋“ค๋ฆผ ๋ฐฉ์ง€)

    • **React ๋‹จ๋…(useState)**์€ ํ™”๋ฉด๋งˆ๋‹ค ์ž…๋ ฅ๊ฐ’/์—๋Ÿฌ/ํ„ฐ์น˜ ์—ฌ๋ถ€/์ œ์ถœ ์ƒํƒœ๋ฅผ ๊ฐ๊ฐ ์ง์ ‘ ๊ตฌํ˜„ํ•ด์•ผ ํ•ด์„œ, ํŽ˜์ด์ง€๊ฐ€ ๋Š˜์–ด๋‚ ์ˆ˜๋ก ๊ตฌํ˜„ ๋ฐฉ์‹์ด ์ œ๊ฐ๊ฐ์ด ๋˜๊ณ  ๋ˆ„๋ฝ(์˜ˆ: ์—๋Ÿฌ ํ‘œ์‹œ, ์ œ์ถœ ์ค‘ ๋น„ํ™œ์„ฑ, ์ดˆ๊ธฐํ™”)์ด ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฌ์›€

      โ†”๏ธ ๋ฐ˜๋ฉด React Hook Form์€ ํผ ์ƒํƒœ ๊ด€๋ฆฌ ํ๋ฆ„(๋“ฑ๋ก, ์ œ์ถœ, ์—๋Ÿฌ ๊ด€๋ฆฌ)์„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ ˆ๋ฒจ์—์„œ ํ‘œ์ค€ํ™”ํ•˜๋ฏ€๋กœ, Devths์ฒ˜๋Ÿผ ์ž…๋ ฅ ํ™”๋ฉด์ด ๋งŽ์€ ๊ตฌ์กฐ์—์„œ ์ผ๊ด€๋œ ๊ตฌํ˜„ ํŒจํ„ด์„ ์œ ์ง€ํ•˜๊ธฐ ์œ ๋ฆฌํ•จ

  • ๋ Œ๋”๋ง/์„ฑ๋Šฅ ๊ด€์ 

    • Formik์€ ํผ ์ƒํƒœ๋ฅผ ํ•œ ๋ฉ์–ด๋ฆฌ๋กœ ๋‹ค๋ฃจ๋Š” ๋ฐฉ์‹์ด ํ”ํ•ด, ํผ์ด ์ปค์ง€๊ฑฐ๋‚˜ ์ž…๋ ฅ์ด ๋งŽ์•„์งˆ์ˆ˜๋ก ๋ฆฌ๋ Œ๋”๋ง ์ตœ์ ํ™”๊ฐ€ ์ถ”๊ฐ€๋กœ ํ•„์š”ํ•ด์งˆ ์ˆ˜ ์žˆ์Œ

      โ†”๏ธ React Hook Form์€ ํ•„์š”ํ•œ ์ƒํƒœ๋งŒ ์„ ํƒ์ ์œผ๋กœ ๊ตฌ๋…ํ•˜๋Š” ํŒจํ„ด์— ๊ฐ•์ ์ด ์žˆ์–ด, ํฐ ํผ/์ž…๋ ฅ ์ˆ˜๊ฐ€ ๋งŽ์€ ํ™”๋ฉด์—์„œ ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง์„ ์ค„์ด๋Š” ์„ค๊ณ„์— ์œ ๋ฆฌํ•จ

  • ๊ฒ€์ฆ ๋„๊ตฌ ๊ฒฐํ•ฉ์˜ ๋ช…ํ™•์„ฑ

    • **React ๋‹จ๋…(useState)**์€ ๊ฒ€์ฆ ๋กœ์ง๊ณผ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ๋งคํ•‘์„ ํ™”๋ฉด๋งˆ๋‹ค ์ง์ ‘ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋ฏ€๋กœ, ๊ทœ์น™์ด ๋งŽ์•„์งˆ์ˆ˜๋ก ์ค‘๋ณต๊ณผ ๋ถˆ์ผ์น˜๊ฐ€ ๋Š˜์–ด๋‚  ๊ฐ€๋Šฅ์„ฑ์ด ํผ

    • Formik์€ Yup ์กฐํ•ฉ์ด ํ”ํ•˜์ง€๋งŒ, ํ”„๋กœ์ ํŠธ ๊ตฌ์„ฑ์— ๋”ฐ๋ผ ๊ฒ€์ฆ ํ๋ฆ„์ด ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์–ด ํŒ€ ์ปจ๋ฒค์…˜ ์˜์กด์ด ์ปค์งˆ ์ˆ˜ ์žˆ์Œ

      โ†”๏ธ React Hook Form์€ Zod ๊ฐ™์€ ์Šคํ‚ค๋งˆ ๊ฒ€์ฆ๊ณผ ๊ฒฐํ•ฉํ•˜๋Š” ์‹ค๋ฌด ํŒจํ„ด์ด ๋„๋ฆฌ ์ •์ฐฉ๋˜์–ด ์žˆ์–ด, โ€˜ํผ ์ž…๋ ฅ โ†’ ์Šคํ‚ค๋งˆ ๊ฒ€์ฆ โ†’ ์—๋Ÿฌ ๋งคํ•‘โ€™ ํ๋ฆ„์„ ์•ˆ์ •์ ์œผ๋กœ ๊ณ ์ •ํ•˜๊ธฐ ์ข‹์Œ

4. ๋ฒ„์ „ ์„ ํƒ ์ด์œ 

  • v7.70.0
    • 2026๋…„ 1์›” 4์ผ์— ๋ฆด๋ฆฌ์ฆˆ๋จ
  • ์ด์œ 
    • GitHub ๋ฆด๋ฆฌ์ฆˆ ๊ธฐ์ค€์œผ๋กœ v7.70.0์ด ์•ˆ์ • ๋ฆด๋ฆฌ์ฆˆ๋กœ ๋ฐฐํฌ๋˜์–ด ์žˆ์Œ
    • ํผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์•ฑ ์ „์—ญ์— ์˜ํ–ฅ์ด ํฌ๋ฏ€๋กœ(๋ชจ๋“  ์ž…๋ ฅ ํ™”๋ฉด์— ๊ฑธ๋ฆผ), ๋ฉ”์ด์ €๋ฅผ ์ž์ฃผ ํ”๋“ค๊ธฐ๋ณด๋‹ค ๋ฉ”์ด์ € ๋ผ์ธ์€ ๊ณ ์ •ํ•˜๊ณ  ํŒจ์น˜ ์—…๋ฐ์ดํŠธ๋กœ ์•ˆ์ •์„ฑ(๋ฒ„๊ทธ ์ˆ˜์ •)์„ ๋ฐ›๋Š” ์ „๋žต์ด ์šด์˜ ๊ด€์ ์—์„œ ๋ณด์ˆ˜์ ์œผ๋กœ ์•ˆ์ „ํ•˜๋‹ค๊ณ  ํŒ๋‹จํ–ˆ์Œ

5. ๊ฒฐ๋ก 

  • Devths๋Š” ์ž…๋ ฅ ํ™”๋ฉด์ด ๋งŽ๊ณ  ์ž…๋ ฅ ๊ทœ์น™์ด ๋ณต์žกํ•ด์งˆ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค. ๋”ฐ๋ผ์„œ ํผ ๊ตฌํ˜„์„ ํ™”๋ฉด๋งˆ๋‹ค ๋ถ„์‚ฐ์‹œํ‚ค๊ธฐ๋ณด๋‹ค, React Hook Form์„ ๋„์ž…ํ•ด ํผ ์ƒํƒœ/์ œ์ถœ/์—๋Ÿฌ ์ฒ˜๋ฆฌ๋ฅผ ํ‘œ์ค€ํ™”ํ•˜๊ณ , Zod์™€ ๊ฒฐํ•ฉํ•˜์—ฌ ๊ฒ€์ฆ ๊ทœ์น™์„ ์ผ๊ด€๋˜๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๊ตฌ์„ฑ์ด ์ ํ•ฉํ•˜๋‹ค๊ณ  ํŒ๋‹จํ–ˆ์Œ

๐Ÿ“ก API ํ†ต์‹ 

โœ… Axios v1.13.2

1. ์ •์˜

  • ๋ธŒ๋ผ์šฐ์ €์™€ Node.js ํ™˜๊ฒฝ์—์„œ HTTP ์š”์ฒญ์„ ์‰ฝ๊ฒŒ ๋ณด๋‚ด๊ธฐ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ, ์š”์ฒญ/์‘๋‹ต ์„ค์ •์„ ๊ฐ์ฒด(config)๋กœ ๊ด€๋ฆฌํ•˜๊ณ  ๊ณตํ†ต ๋กœ์ง์„ ์ธํ„ฐ์…‰ํ„ฐ๋กœ ํ‘œ์ค€ํ™”ํ•  ์ˆ˜ ์žˆ์Œ

2. ํŠน์ง•

  • baseURL, headers, params, timeout, withCredentials ๋“ฑ ๋„คํŠธ์›Œํฌ ์˜ต์…˜์„ ํ•œ ๊ณณ์—์„œ ์„ ์–ธ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Œ
  • ๋ชจ๋“  ์š”์ฒญ ์ „์— ํ† ํฐ/์„ธ์…˜์„ ์ž๋™ ์ฒจ๋ถ€ํ•˜๊ฑฐ๋‚˜, ๋ชจ๋“  ์‘๋‹ต์—์„œ 401/500 ๊ฐ™์€ ๊ณตํ†ต ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋ฅผ ํ•œ ๋ฒˆ์— ์ ์šฉํ•  ์ˆ˜ ์žˆ์Œ
  • ํ™”๋ฉด ์ด๋™/ํƒญ ์ „ํ™˜/๊ฒ€์ƒ‰์–ด ๋ณ€๊ฒฝ์ฒ˜๋Ÿผ ์ด์ „ ์š”์ฒญ์€ ๋ฒ„๋ ค์•ผ ํ•˜๋Š” ์ƒํ™ฉ์—์„œ ์š”์ฒญ ์ทจ์†Œ ํ๋ฆ„์„ ์„ค๊ณ„ํ•  ์ˆ˜ ์žˆ์Œ
  • ์ด๋ฏธ์ง€/ํŒŒ์ผ ์ฒจ๋ถ€ ๊ธฐ๋Šฅ์—์„œ multipart ์—…๋กœ๋“œ๋ฅผ ๊ตฌ์„ฑํ•˜๊ธฐ ์‰ฌ์›€

3. devths์— ์ด ๊ธฐ์ˆ ์ด ํ•„์š”ํ•œ ์ด์œ 

  • Google OAuth ์ดํ›„ API ํ˜ธ์ถœ๋งˆ๋‹ค ํ† ํฐ/์„ธ์…˜ ์ •๋ณด๋ฅผ ๊ณตํ†ต์œผ๋กœ ๋ถ™์—ฌ์•ผ ํ•˜๋ฏ€๋กœ, ์ธํ„ฐ์…‰ํ„ฐ ๊ธฐ๋ฐ˜์œผ๋กœ ์ž๋™ ์ฃผ์ž… + ๊ณตํ†ต ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋ฅผ ํ‘œ์ค€ํ™”ํ•˜๋Š” ๊ฒƒ์ด ์œ ์ง€๋ณด์ˆ˜์— ์œ ๋ฆฌํ•˜๋‹ค๊ณ  ํŒ๋‹จํ•จ
  • ๊ฒŒ์‹œ๊ธ€/์ฑ„ํŒ…/ํ”„๋กœํ•„ ๋“ฑ์—์„œ ์ฒจ๋ถ€๋ฅผ ๋‹ค๋ฃจ๊ฒŒ ๋˜๋ฉด multipart ์—…๋กœ๋“œ๊ฐ€ ํ•ต์‹ฌ์ด ๋˜๋ฏ€๋กœ Axios์˜ ์—…๋กœ๋“œ ๊ตฌ์„ฑ ๋ฐฉ์‹์ด ์ ํ•ฉํ•˜๋‹ค๊ณ  ํŒ๋‹จํ•จ
  • ํŽ˜์ด์ง€๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ๋กœ๋”ฉ/์—๋Ÿฌ/์žฌ์‹œ๋„/์ทจ์†Œ ๊ฐ™์€ ๋„คํŠธ์›Œํฌ UX๊ฐ€ ํ”๋“ค๋ฆฌ๊ธฐ ์‰ฌ์šด๋ฐ, Axios๋Š” ์„ค์ •(config)๊ณผ ์ธํ„ฐ์…‰ํ„ฐ๋กœ ์ •์ฑ…์„ ํ•œ ๊ณณ์— ๋ชจ์œผ๊ธฐ ์ข‹์Œ

4. ๋‹ค๋ฅธ ์Šคํƒ๊ณผ์˜ ๋น„๊ต ํ‘œ

ํ•ญ๋ชฉ Axios fetch(๋‚ด์žฅ)
๊ณตํ†ต ํ—ค๋”/ํ† ํฐ ์ฃผ์ž… ์ธํ„ฐ์…‰ํ„ฐ๋กœ ํ‘œ์ค€ํ™” ๊ฐ€๋Šฅ ์ง์ ‘ ๋ž˜ํผ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•จ
์š”์ฒญ ์˜ต์…˜ ๊ด€๋ฆฌ config ๊ฐ์ฒด๋กœ ์ผ๊ด€๋˜๊ฒŒ ๊ด€๋ฆฌ ์˜ต์…˜์„ ํ˜ธ์ถœ๋งˆ๋‹ค ๊ตฌ์„ฑ(์ปจ๋ฒค์…˜ ํ•„์š”)
์š”์ฒญ ์ทจ์†Œ ์ทจ์†Œ ํ๋ฆ„ ์ง€์› AbortController๋ฅผ ์ง์ ‘ ์„ค๊ณ„ํ•ด์•ผ ํ•จ
ํŒŒ์ผ ์—…๋กœ๋“œ multipart ์˜ˆ์‹œ/ํŒจํ„ด์ด ๋ช…ํ™• FormData ๊ตฌ์„ฑ์€ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ํŒจํ„ด ํ‘œ์ค€ํ™”๋Š” ์ง์ ‘ ํ•„์š”
ํŒ€ ์ผ๊ด€์„ฑ ์ธ์Šคํ„ด์Šค 1๊ฐœ๋กœ ์ •์ฑ… ๊ณ ์ •์ด ์‰ฌ์›€ ํŒ€ ์ปจ๋ฒค์…˜์— ๋”ฐ๋ผ ํŽธ์ฐจ ๋ฐœ์ƒ ๊ฐ€๋Šฅ
  • ๊ณตํ†ต ํ—ค๋”/ํ† ํฐ ์ฃผ์ž…์˜ ํ‘œ์ค€ํ™”

    • **fetch(๋‚ด์žฅ)**์€ ์š”์ฒญ๋งˆ๋‹ค ํ—ค๋”๋ฅผ ๋ถ™์ด๊ฑฐ๋‚˜, ๋ณ„๋„์˜ ๋ž˜ํผ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด โ€œํ† ํฐ ์ฃผ์ž… ๊ทœ์น™โ€์„ ํŒ€์ด ์ง์ ‘ ๊ฐ•์ œํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ํ™”๋ฉด/๊ธฐ๋Šฅ์ด ๋Š˜์–ด๋‚ ์ˆ˜๋ก ๋ˆ„๋ฝ(์˜ˆ: ํŠน์ • API๋งŒ ํ† ํฐ ๋น ์ง) ๊ฐ€๋Šฅ์„ฑ์ด ์ฆ๊ฐ€ํ•จ

      โ†”๏ธ ๋ฐ˜๋ฉด Axios๋Š” ์ธํ„ฐ์…‰ํ„ฐ ๊ธฐ๋ฐ˜์œผ๋กœ ์ธ์ฆ ํ† ํฐ, ์„ธ์…˜ ํ—ค๋”, ๊ณตํ†ต ํ—ค๋” ์ •์ฑ…์„ ํ•œ ๊ณณ์—์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด, Devths์ฒ˜๋Ÿผ ์ธ์ฆ/๊ถŒํ•œ์ด ์—ฌ๋Ÿฌ API์— ๊ฑธ์นœ ๊ตฌ์กฐ์—์„œ ์ •์ฑ…์„ ํ‘œ์ค€ํ™”ํ•˜๊ธฐ ์œ ๋ฆฌํ•จ

  • ์š”์ฒญ ์˜ต์…˜ ๊ด€๋ฆฌ์˜ ์ผ๊ด€์„ฑ

    • **fetch(๋‚ด์žฅ)**์€ ๊ฐ ํ˜ธ์ถœ๋งˆ๋‹ค ์˜ต์…˜์„ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐฉ์‹์ด์–ด์„œ, timeout/credentials/baseURL/์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋“ฑ ๊ณตํ†ต ๊ทœ์น™์„ ํŒ€ ์ปจ๋ฒค์…˜์œผ๋กœ ์œ ์ง€ํ•ด์•ผ ํ•˜๊ณ  ๊ตฌํ˜„ ํŽธ์ฐจ๊ฐ€ ์ƒ๊ธฐ๊ธฐ ์‰ฌ์›€

      โ†”๏ธ Axios๋Š” ์ธ์Šคํ„ด์Šค์˜ config๋กœ baseURL, timeout, ๊ณตํ†ต ํ—ค๋”, withCredentials ๊ฐ™์€ ์ •์ฑ…์„ ๊ณ ์ •ํ•  ์ˆ˜ ์žˆ์–ด, ํ”„๋กœ์ ํŠธ ์ „๋ฐ˜์—์„œ ๋™์ผํ•œ ์š”์ฒญ ๊ทœ์น™์„ ์œ ์ง€ํ•˜๊ธฐ ์‰ฌ์›€

  • ์š”์ฒญ ์ทจ์†Œ(Abort) ํ๋ฆ„์˜ ์šด์˜ ๋‚œ์ด๋„

    • **fetch(๋‚ด์žฅ)**์€ AbortController๋ฅผ ํ™”๋ฉด๋งˆ๋‹ค ์„ค๊ณ„ํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ๊ฒ€์ƒ‰/์ž๋™์™„์„ฑ/๋ฌดํ•œ์Šคํฌ๋กค์ฒ˜๋Ÿผ ์ด์ „ ์š”์ฒญ ์ทจ์†Œ๊ฐ€ ํ•„์š”ํ•œ ํ™”๋ฉด์ด ๋Š˜์–ด๋‚˜๋ฉด ์ฝ”๋“œ ์ค‘๋ณต๊ณผ ๋ˆ„๋ฝ ์œ„ํ—˜์ด ์ปค์งˆ ์ˆ˜ ์žˆ์Œ

      โ†”๏ธ Axios๋Š” ์ทจ์†Œ ํ๋ฆ„์„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ˆ˜์ค€์—์„œ ์ง€์›ํ•˜๋ฉฐ, ๊ณตํ†ต ์š”์ฒญ ์œ ํ‹ธ๊ณผ ๊ฒฐํ•ฉํ•ด ์ทจ์†Œ ์ •์ฑ…์„ ํŒจํ„ดํ™”ํ•˜๊ธฐ ์œ ๋ฆฌํ•จ

  • ํŒŒ์ผ ์—…๋กœ๋“œ ํŒจํ„ด์˜ ํ‘œ์ค€ํ™”

    • **fetch(๋‚ด์žฅ)**๋„ FormData๋กœ ์—…๋กœ๋“œ๋Š” ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ๋ฉ€ํ‹ฐํŒŒํŠธ ์š”์ฒญ ๊ตฌ์„ฑ/์—๋Ÿฌ ์ฒ˜๋ฆฌ/์ง„ํ–‰ ์ƒํƒœ/๊ณตํ†ต ํ—ค๋” ์ •์ฑ…์„ ํŒ€์ด ์ง์ ‘ ํ‘œ์ค€ํ™”ํ•ด์•ผ ํ•จ

      โ†”๏ธ Axios๋Š” multipart ์—…๋กœ๋“œ์— ๋Œ€ํ•œ ์‹ค๋ฌด ํŒจํ„ด๊ณผ ๋ ˆํผ๋Ÿฐ์Šค๊ฐ€ ๋งŽ๊ณ , ์ธ์Šคํ„ด์Šค/์ธํ„ฐ์…‰ํ„ฐ์™€ ๊ฒฐํ•ฉํ•ด ์—…๋กœ๋“œ ์ •์ฑ…(์˜ˆ: ๊ณตํ†ต ์—๋Ÿฌ ์ฒ˜๋ฆฌ, ์ธ์ฆ ํ—ค๋”)์„ ์ผ๊ด€๋˜๊ฒŒ ์ ์šฉํ•˜๊ธฐ ์šฉ์ดํ•จ

  • ํŒ€ ์ผ๊ด€์„ฑ(์šด์˜ ์ •์ฑ… ๊ณ ์ •)

    • **fetch(๋‚ด์žฅ)**์€ ๊ฐ์ž fetch๋ฅผ ์–ด๋–ป๊ฒŒ ๊ฐ์Œ€์ง€์— ๋”ฐ๋ผ ์ฝ”๋“œ ์Šคํƒ€์ผ๊ณผ ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์ด ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์–ด, ๊ทœ๋ชจ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก ํŽธ์ฐจ๊ฐ€ ๋ˆ„์ ๋  ์ˆ˜ ์žˆ์Œ

      โ†”๏ธ Axios๋Š” ์ธ์Šคํ„ด์Šค 1๊ฐœ๋กœ ์š”์ฒญ/์‘๋‹ต ์ •์ฑ…์„ ์ค‘์•™ํ™”ํ•  ์ˆ˜ ์žˆ์–ด, Devths์ฒ˜๋Ÿผ ํ™”๋ฉด/๊ธฐ๋Šฅ์ด ๋งŽ์€ ํ”„๋กœ์ ํŠธ์—์„œ ํŒ€ ๋‹จ์œ„ ์ผ๊ด€์„ฑ ํ™•๋ณด์— ์œ ๋ฆฌํ•จ

5. ๋ฒ„์ „ ์„ ํƒ ์ด์œ 

  • v1.13.2
    • 2025๋…„ 11์›” 4์ผ์— ๋ฆด๋ฆฌ์ฆˆ๋จ
  • ์ด์œ 
    • ์ตœ์‹  ์•ˆ์ •(stable) ๋ฐฐํฌ ๋ฒ„์ „์„ ๊ธฐ์ค€์œผ๋กœ ์„ ํƒํ•˜์—ฌ, ๋ฒ„๊ทธ ์ˆ˜์ • ๋ฐ ์•ˆ์ •์„ฑ ๊ฐœ์„ ์„ ๋ฐ˜์˜ํ•  ์ˆ˜ ์žˆ์Œ
    • ์šด์˜ ์ „๋žต์€ ๋ฉ”์ด์ €๋Š” ์œ ์ง€ํ•˜๊ณ , ํŒจ์น˜/๋งˆ์ด๋„ˆ ์—…๋ฐ์ดํŠธ๋Š” ์ •๊ธฐ ๋ฐ˜์˜ํ•˜๋Š” ๋ฐฉ์‹์ด ํ•ฉ๋ฆฌ์ ์ด๋ผ๊ณ  ์ƒ๊ฐํ•จ
      • ์˜์กด์„ฑ ์ถฉ๋Œ ๋ฆฌ์Šคํฌ๋Š” ๋‚ฎ์ถ”๊ณ , ์•ˆ์ •์„ฑ ํŒจ์น˜๋Š” ๋”ฐ๋ผ๊ฐ€๊ธฐ ์œ„ํ•จ

6. ๊ฒฐ๋ก 

  • devths๋Š” ์ธ์ฆ ๊ธฐ๋ฐ˜ API ํ˜ธ์ถœ์ด ๋งŽ๊ณ  ํŒŒ์ผ ์—…๋กœ๋“œ ๋ฐ ๊ณตํ†ต ์—๋Ÿฌ ์ฒ˜๋ฆฌ ์š”๊ตฌ๊ฐ€ ์ปค์งˆ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์œผ๋ฏ€๋กœ, ์ธํ„ฐ์…‰ํ„ฐ์™€ config ์ค‘์‹ฌ์œผ๋กœ ๋„คํŠธ์›Œํฌ ์ •์ฑ…์„ ํ‘œ์ค€ํ™”ํ•  ์ˆ˜ ์žˆ๋Š” Axios๋ฅผ API ํ†ต์‹  ์Šคํƒ์œผ๋กœ ์„ ํƒํ•จ

๐Ÿ’ฏ ์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ

โœ… vitest v4.0.16

1. ์ •์˜

  • Vitest๋Š” JavaScript/TypeScript ํ™˜๊ฒฝ์—์„œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ๋ฐ ์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•œ ํ…Œ์ŠคํŠธ๋Ÿฌ๋„ˆ์ž„
  • Node.js์—์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉฐ, DOM์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ jsdom๊ณผ ๊ฐ™์€ ๊ฐ€์ƒ ๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝ์„ ํ†ตํ•ด UI ํ…Œ์ŠคํŠธ๋ฅผ ์ง€์›ํ•จ

2. ํŠน์ง•

  • ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์†๋„๊ฐ€ ๋น ๋ฅธ ํŽธ์œผ๋กœ, ๊ฐœ๋ฐœ ๊ณผ์ •์—์„œ ๋ฐ˜๋ณต ์‹คํ–‰(์ˆ˜์ •-๊ฒ€์ฆ)์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ์— ์ ํ•ฉํ•จ
  • TypeScript ํ”„๋กœ์ ํŠธ์— ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ ์šฉ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ํƒ€์ž… ๊ธฐ๋ฐ˜ ์ฝ”๋“œ ๊ตฌ์กฐ์™€์˜ ๊ฒฐํ•ฉ์ด ์šฉ์ดํ•จ
  • describe, it, expect ๋“ฑ ์ผ๋ฐ˜์ ์ธ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ ๋ฐฉ์‹๊ณผ ์œ ์‚ฌํ•œ API๋ฅผ ์ œ๊ณตํ•˜์—ฌ ๋„์ž… ๋‚œ์ด๋„๊ฐ€ ๋‚ฎ์Œ
  • mock, spy ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ์™ธ๋ถ€ ์˜์กด์„ฑ(API ํ•จ์ˆ˜, ์œ ํ‹ธ ํ•จ์ˆ˜ ๋“ฑ)์„ ๋ถ„๋ฆฌํ•œ ์ƒํƒœ์—์„œ ๋กœ์ง ๊ฒ€์ฆ์ด ๊ฐ€๋Šฅํ•จ
  • React Testing Library์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง ๋ฐ ์‚ฌ์šฉ์ž ์ƒํ˜ธ์ž‘์šฉ ์ˆ˜์ค€์˜ ํ…Œ์ŠคํŠธ๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Œ

3. devths์— ์ด ๊ธฐ์ˆ ์ด ํ•„์š”ํ•œ ์ด์œ 

  • devths๋Š” ํ™”๋ฉด ์ˆ˜๊ฐ€ ๋งŽ๊ณ  ์ž…๋ ฅ ๊ทœ์น™, ์ƒํƒœ ๋ณ€ํ™”, ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์ด ๋ฐ˜๋ณต์ ์œผ๋กœ ๋“ฑ์žฅํ•˜๋Š” ๊ตฌ์กฐ์ด๋ฏ€๋กœ, ๋‹จ์œ„/์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ์˜ ์ ์šฉ ๊ฐ€์น˜๊ฐ€ ๋†’๋‹ค๊ณ  ํŒ๋‹จํ•จ.
  • ํ’ˆ์งˆ ํŽธ์ฐจ์™€ ํšŒ๊ท€ ์œ„ํ—˜์„ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค๊ณ  ํŒ๋‹จํ•จ
    • ์ž…๋ ฅ ๊ฒ€์ฆ ๋กœ์ง(๋‹‰๋„ค์ž„ ๊ทœ์น™, ๊ธธ์ด ์ œํ•œ, ๋‚ ์งœ ๋ฒ”์œ„, ํŒŒ์ผ ์ œํ•œ ๋“ฑ)์€ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๊ณ  ๋ˆ„๋ฝ ์‹œ ์˜ค๋ฅ˜๋กœ ์—ฐ๊ฒฐ๋˜๊ธฐ ์‰ฌ์›Œ ์ž๋™ํ™” ๊ฒ€์ฆ์ด ํ•„์š”ํ•จ
    • ๋กœ๋”ฉ/์—๋Ÿฌ/์„ฑ๊ณต ์ƒํƒœ์— ๋”ฐ๋ฅธ UI ๋ถ„๊ธฐ, ์ธ์ฆ ์ƒํƒœ์— ๋”ฐ๋ฅธ ํ™”๋ฉด ๋ถ„๊ธฐ ๋“ฑ์€ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ ๊ณผ์ •์—์„œ ์‰ฝ๊ฒŒ ๊นจ์งˆ ์ˆ˜ ์žˆ์–ด ํ…Œ์ŠคํŠธ๋กœ ๊ณ ์ •ํ•˜๋Š” ํŽธ์ด ์•ˆ์ •์ ์ž„
    • ๋ชจ๋‹ฌ/ํƒญ/ํ•„ํ„ฐ ๋“ฑ UI ์ƒํƒœ ์ „ํ™˜ ๋กœ์ง์ด ๋งŽ์•„, ์‚ฌ์šฉ์ž ์ธํ„ฐ๋ž™์…˜์— ๋”ฐ๋ฅธ ๊ธฐ๋Œ€ ๋™์ž‘์„ ํ…Œ์ŠคํŠธ๋กœ ๋ช…ํ™•ํžˆ ์ •์˜ํ•  ํ•„์š”๊ฐ€ ์žˆ์Œ

4. ๋‹ค๋ฅธ ์Šคํƒ๊ณผ์˜ ๋น„๊ต ํ‘œ

ํ•ญ๋ชฉ Vitest Jest Node ๋‚ด์žฅ test ๋Ÿฌ๋„ˆ
ํ”„๋ก ํŠธ ๋‹จ์œ„/์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ ์ ํ•ฉ์„ฑ ํ”„๋ก ํŠธ ์ƒํƒœ๊ณ„ ์นœํ™”์  ๊ตฌ์„ฑ์— ์œ ๋ฆฌ ๋„๋ฆฌ ์‚ฌ์šฉ๋˜๋‚˜ ์„ค์ •์ด ๋Š˜์–ด๋‚  ์ˆ˜ ์žˆ์Œ ๊ธฐ๋ณธ ๊ธฐ๋Šฅ ์œ„์ฃผ๋กœ UI ํ…Œ์ŠคํŠธ ๊ตฌ์„ฑ์€ ์ถ”๊ฐ€ ์„ค๊ณ„ ํ•„์š”
TypeScript ์ ์šฉ ์ƒ๋Œ€์ ์œผ๋กœ ์ ์šฉ ๋ถ€๋‹ด์ด ๋‚ฎ์€ ํŽธ ๊ฐ€๋Šฅํ•˜๋‚˜ ํ”„๋กœ์ ํŠธ ๊ตฌ์„ฑ์— ๋”ฐ๋ผ ์„ค์ • ์ฆ๊ฐ€ ๊ฐ€๋Šฅ ๊ฐ€๋Šฅํ•˜๋‚˜ ๊ด€๋ จ ์ƒํƒœ๊ณ„ ์กฐํ•ฉ์ด ์ œํ•œ์ 
๊ฐœ๋ฐœ ์ค‘ ๋ฐ˜๋ณต ์‹คํ–‰(์†๋„/๊ฒฝํ—˜) ๋น ๋ฅธ ์‹คํ–‰์„ ๋ชฉํ‘œ๋กœ ์„ค๊ณ„ ์ผ€์ด์Šค์— ๋”ฐ๋ผ ์‹คํ–‰ ๋น„์šฉ ์ฆ๊ฐ€ ๊ฐ€๋Šฅ ๋‹จ์ˆœํ•˜๋‚˜ ํŽธ์˜ ๊ธฐ๋Šฅ์€ ์ œํ•œ์ 
mocking/spy ๊ธฐ๋ณธ ์ œ๊ณต(vi ๊ธฐ๋ฐ˜) ๊ธฐ๋ณธ ์ œ๊ณต(jest ๊ธฐ๋ฐ˜) ์™ธ๋ถ€ ๋„๊ตฌ ๋˜๋Š” ์ง์ ‘ ๊ตฌ์„ฑ ํ•„์š”
Devths ์ ํ•ฉ๋„ UI ๋กœ์ง/๊ฒ€์ฆ/์ƒํƒœ ํ…Œ์ŠคํŠธ์— ์ ํ•ฉ ํ›„๋ณด ๊ฐ€๋Šฅ(ํŒ€ ๊ฒฝํ—˜์— ๋”ฐ๋ผ) ๋‹จ์ˆœ ๋กœ์ง์—” ๊ฐ€๋Šฅํ•˜๋‚˜ UI ์ค‘์‹ฌ์—๋Š” ๋น„ํšจ์œจ์ 
  • ํ”„๋ก ํŠธ ๋‹จ์œ„/์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ ๊ตฌ์„ฑ์˜ ํ‘œ์ค€ํ™”

    • Jest๋Š” ๋„๋ฆฌ ์‚ฌ์šฉ๋˜์ง€๋งŒ, ํ”„๋กœ์ ํŠธ ๊ตฌ์„ฑ(ESM, Next.js, TS, JSX)๊ณผ ๋งž์ถ”๋Š” ๊ณผ์ •์—์„œ ์„ค์ •์ด ๋Š˜์–ด๋‚˜๊ณ  ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ(ํŠธ๋žœ์ŠคํŒŒ์ผ/๋Ÿฐํƒ€์ž„) ์ด์Šˆ๋ฅผ ํŒ€์ด ๊ณ„์† ๊ด€๋ฆฌํ•ด์•ผ ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Œ

      โ†”๏ธ Vitest๋Š” ํ”„๋ก ํŠธ ์ƒํƒœ๊ณ„ ์นœํ™”์ ์ธ ๊ตฌ์„ฑ์ด ๊ฐ•์ ์ด๋ผ, Devths์ฒ˜๋Ÿผ ์ปดํฌ๋„ŒํŠธ/ํ›…/์œ ํ‹ธ ํ…Œ์ŠคํŠธ ๋น„์ค‘์ด ํฐ ํ”„๋กœ์ ํŠธ์—์„œ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์„ ๋น„๊ต์  ๋‹จ์ˆœํ•˜๊ฒŒ ์œ ์ง€ํ•˜๊ธฐ ์œ ๋ฆฌํ•จ

  • TypeScript ์ ์šฉ ๋ถ€๋‹ด๊ณผ ์œ ์ง€๋ณด์ˆ˜ ๋น„์šฉ

    • Jest๋Š” TypeScript ์ ์šฉ์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ๋ณ€ํ™˜ ํŒŒ์ดํ”„๋ผ์ธ(ts-jest, babel-jest ๋“ฑ)๊ณผ ์„ค์ •์ด ํ”„๋กœ์ ํŠธ ์ƒํ™ฉ์— ๋”ฐ๋ผ ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ์–ด ์œ ์ง€๋ณด์ˆ˜ ๋น„์šฉ์ด ์ปค์งˆ ์ˆ˜ ์žˆ์Œ

      โ†”๏ธ Vitest๋Š” TypeScript/ESM ๊ธฐ๋ฐ˜ ๊ฐœ๋ฐœ ํ๋ฆ„๊ณผ์˜ ๊ฒฐํ•ฉ์ด ๋น„๊ต์  ์ž์—ฐ์Šค๋Ÿฌ์›Œ, ํ…Œ์ŠคํŠธ ์ธํ”„๋ผ๋ฅผ โ€œ์„ค์ • ์ค‘์‹ฌโ€์ด ์•„๋‹ˆ๋ผ โ€œ์ฝ”๋“œ ์ค‘์‹ฌโ€์œผ๋กœ ์šด์˜ํ•˜๊ธฐ ์œ ๋ฆฌํ•จ

  • ๊ฐœ๋ฐœ ์ค‘ ๋ฐ˜๋ณต ์‹คํ–‰ ๊ฒฝํ—˜(์†๋„/ํ”ผ๋“œ๋ฐฑ ๋ฃจํ”„)

    • Jest๋Š” ์ผ€์ด์Šค์— ๋”ฐ๋ผ ์‹คํ–‰ ๋น„์šฉ์ด ์ฆ๊ฐ€ํ•  ์ˆ˜ ์žˆ์–ด, ๊ฐœ๋ฐœ ์ค‘ ํ…Œ์ŠคํŠธ๋ฅผ ์ž์ฃผ ๋Œ๋ฆฌ๋Š” ํ๋ฆ„์—์„œ ์ฒด๊ฐ ์†๋„๊ฐ€ ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ์Œ

      โ†”๏ธ Vitest๋Š” ๋น ๋ฅธ ๋ฐ˜๋ณต ์‹คํ–‰ ๊ฒฝํ—˜์„ ๋ชฉํ‘œ๋กœ ์„ค๊ณ„๋˜์–ด, ๊ธฐ๋Šฅ ์ถ”๊ฐ€/๋ฆฌํŒฉํ† ๋ง ๊ณผ์ •์—์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์ž์ฃผ ์‹คํ–‰ํ•˜๋Š” Devths ๊ฐœ๋ฐœ ๋ฐฉ์‹๊ณผ ์ž˜ ๋งž์Œ

  • mocking/spy ๋„๊ตฌ์˜ ์ผ๊ด€์„ฑ

    • Node ๋‚ด์žฅ test ๋Ÿฌ๋„ˆ๋Š” ๊ธฐ๋ณธ ๊ธฐ๋Šฅ ์œ„์ฃผ๋ผ mocking/spy, UI ํ…Œ์ŠคํŠธ๋ฅผ ์•ˆ์ •์ ์œผ๋กœ ์šด์˜ํ•˜๋ ค๋ฉด ์™ธ๋ถ€ ๋„๊ตฌ ์กฐํ•ฉ๊ณผ ํŒ€ ๋‚ด ๊ทœ์น™ ์„ค๊ณ„๊ฐ€ ์ถ”๊ฐ€๋กœ ํ•„์š”ํ•จ

      โ†”๏ธ Vitest๋Š” vi ๊ธฐ๋ฐ˜ mocking/spy๋ฅผ ๊ธฐ๋ณธ ์ œ๊ณตํ•˜๋ฏ€๋กœ, ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ ๋ฐฉ์‹๊ณผ ๋„๊ตฌ ์‚ฌ์šฉ๋ฒ•์„ ํŒ€ ๋‹จ์œ„๋กœ ํ‘œ์ค€ํ™”ํ•˜๊ธฐ ์‰ฌ์›€

  • Devths ์„ฑ๊ฒฉ(UI ๋กœ์ง/๊ฒ€์ฆ/์ƒํƒœ ํ…Œ์ŠคํŠธ)๊ณผ์˜ ์ ํ•ฉ์„ฑ

    • Node ๋‚ด์žฅ test ๋Ÿฌ๋„ˆ๋Š” ๋‹จ์ˆœ ๋กœ์ง ํ…Œ์ŠคํŠธ์—๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋‚˜, UI ์ค‘์‹ฌ ํ…Œ์ŠคํŠธ๋ฅผ ์šด์˜ํ•˜๋ ค๋ฉด ์ถ”๊ฐ€ ์„ค๊ณ„๊ฐ€ ํ•„์š”ํ•ด ๋น„ํšจ์œจ์ด ์ปค์งˆ ์ˆ˜ ์žˆ์Œ

      โ†”๏ธ Vitest๋Š” UI ๋กœ์ง/๊ฒ€์ฆ/์ƒํƒœ ํ…Œ์ŠคํŠธ์— ์ ํ•ฉํ•œ ์ƒํƒœ๊ณ„ ์กฐํ•ฉ(React Testing Library ๋“ฑ)๊ณผ ํ•จ๊ป˜ ์“ฐ๊ธฐ ์ข‹์•„, Devths์˜ ๋‹จ์œ„/์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ ๋„๊ตฌ๋กœ ์„ ํƒํ•˜๋Š” ๊ทผ๊ฑฐ๊ฐ€ ๋จ

5. ๋ฒ„์ „ ์„ ํƒ ์ด์œ 

  • v4.0.16
    • 2025๋…„ 12์›” 16์ผ์— ๋ฆด๋ฆฌ์ฆˆ๋จ
  • ์ด์œ 
    • Vitest์˜ 4.x ๋ฉ”์ด์ € ๋ผ์ธ์—์„œ ์ตœ์‹  ์•ˆ์ •(Stable) ํŒจ์น˜ ๋ฒ„์ „์„ ์‚ฌ์šฉํ•˜๋ฉด, ๋™์ผํ•œ ๋ฉ”์ด์ € ๋ฒ„์ „ ๋‚ด์—์„œ ๋ฒ„๊ทธ ์ˆ˜์ •/์•ˆ์ •์„ฑ ๊ฐœ์„ ์„ ๋ฐ˜์˜ํ•˜๋ฉด์„œ๋„ ํฐ ๊ตฌ์กฐ ๋ณ€๊ฒฝ(๋ธŒ๋ ˆ์ดํ‚น ์ฒด์ธ์ง€) ์œ„ํ—˜์„ ์ƒ๋Œ€์ ์œผ๋กœ ๋‚ฎ์ถœ ์ˆ˜ ์žˆ์Œ

6. ๊ฒฐ๋ก 

  • Devths๋Š” ์ž…๋ ฅ ๊ฒ€์ฆ, ์กฐ๊ฑด๋ถ€ UI, ์ƒํƒœ ์ „ํ™˜๊ณผ ๊ฐ™์€ ํ”„๋ก ํŠธ์—”๋“œ ๋กœ์ง์ด ๋ฐ˜๋ณต์ ์œผ๋กœ ๋ฐœ์ƒํ•˜๋Š” ๊ตฌ์กฐ์ด๋ฉฐ, ์ด ์˜์—ญ์€ ํšŒ๊ท€ ์œ„ํ—˜์ด ๋†’์Œ
  • Vitest๋Š” ๋‹จ์œ„/์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ๋ฅผ ๋น ๋ฅด๊ฒŒ ๋ฐ˜๋ณต ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ณ  TypeScript ๋ฐ React ํ…Œ์ŠคํŠธ ๊ตฌ์„ฑ๊ณผ์˜ ๊ฒฐํ•ฉ์ด ์šฉ์ดํ•˜๋ฏ€๋กœ, ์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ๋„๊ตฌ๋กœ ์ฑ„ํƒํ•˜์˜€์Œ

โœ… React Testing Library v16.3.1

1. ํŠน์ง• ์š”์•ฝ

  • Promise ๊ธฐ๋ฐ˜ HTTP ํด๋ผ์ด์–ธํŠธ
    • ๋ธŒ๋ผ์šฐ์ €/Node ํ™˜๊ฒฝ์—์„œ API ์š”์ฒญ์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๊ณ , async/await๋กœ ํ๋ฆ„์„ ๊น”๋”ํ•˜๊ฒŒ ์ž‘์„ฑ ๊ฐ€๋Šฅ
  • ์ธ์Šคํ„ด์Šค(instance) ๊ธฐ๋ฐ˜ ๊ณตํ†ต ์„ค์ •
    • baseURL, timeout, ๊ณตํ†ต ํ—ค๋” ๋“ฑ ํ”„๋กœ์ ํŠธ ํ‘œ์ค€ ์„ค์ •์„ ํ•œ ๋ฒˆ์— ๋ฌถ์–ด ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด API ์ฝ”๋“œ๊ฐ€ ์ •๋ˆ๋จ
  • Interceptor(์š”์ฒญ/์‘๋‹ต ๊ฐ€๋กœ์ฑ„๊ธฐ) ์ง€์›
    • ์š”์ฒญ ์ „์— ํ† ํฐ ๋ถ™์ด๊ธฐ, ์‘๋‹ต ์—๋Ÿฌ๋ฅผ ๊ณตํ†ต ์ฒ˜๋ฆฌ(๋กœ๊ทธ์ธ ๋งŒ๋ฃŒ, ํ† ์ŠคํŠธ) ๊ฐ™์€ โ€œ๊ณตํ†ต ๋กœ์งโ€์„ ์ค‘์•™์—์„œ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ
  • ์š”์ฒญ ์˜ต์…˜์ด ํ’๋ถ€ํ•จ
    • params(์ฟผ๋ฆฌ), headers, timeout, responseType, ์—…๋กœ๋“œ(FormData) ๋“ฑ ์‹ค๋ฌด์—์„œ ์ž์ฃผ ํ•„์š”ํ•œ ์˜ต์…˜์ด ์ •๋ฆฌ๋ผ ์žˆ์Œ

2. devths์— ์ด ๊ธฐ์ˆ ์ด ํ•„์š”ํ•œ ์ด์œ 

๐Ÿ’ก

Devths๋Š” ์บ˜๋ฆฐ๋” / ๊ฒŒ์‹œํŒ / ์ฑ„ํŒ… / ์ฑ—๋ด‡ / OCR ์—…๋กœ๋“œ์ฒ˜๋Ÿผ API ํ˜ธ์ถœ์ด ๋‹ค์–‘ํ•œ ์„œ๋น„์Šค๋ผ์„œ, ํ™”๋ฉด๋งˆ๋‹ค fetch๋ฅผ ์ œ๊ฐ๊ฐ ์“ฐ๋ฉด ์š”์ฒญ ๋ฐฉ์‹๊ณผ ์—๋Ÿฌ ์ฒ˜๋ฆฌ๊ฐ€ ๋ถ„์‚ฐ๋ผ ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์–ด๋ ค์›Œ์ง.

  • Axios๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด API ํ˜ธ์ถœ ํŒจํ„ด์„ ํ‘œ์ค€ํ™”ํ•˜๊ณ , ๊ณตํ†ต ์ฒ˜๋ฆฌ๋ฅผ(ํ† ํฐ/์—๋Ÿฌ/ํƒ€์ž„์•„์›ƒ) ํ•œ ๊ณณ์—์„œ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Œ.
  • (1) ๊ณตํ†ต ํ—ค๋”/์ธ์ฆ ์ฒ˜๋ฆฌ ํ‘œ์ค€ํ™”

    • ๋กœ๊ทธ์ธ ์ดํ›„ ์š”์ฒญ์— ์ธ์ฆ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•˜๋ฉด, ์ธํ„ฐ์…‰ํ„ฐ๋กœ โ€œ์ž๋™ ์ฒจ๋ถ€โ€ ํŒจํ„ด์„ ๋งŒ๋“ค๊ธฐ ์‰ฌ์›€
  • (2) ์—๋Ÿฌ ์ฒ˜๋ฆฌ ์ผ๊ด€์„ฑ

    • 401(์ธ์ฆ ๋งŒ๋ฃŒ), 403(๊ถŒํ•œ), 500(์„œ๋ฒ„ ์˜ค๋ฅ˜) ๋“ฑ์„ ํ™”๋ฉด๋งˆ๋‹ค ๋”ฐ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉด UX๊ฐ€ ๋“ค์ญ‰๋‚ ์ญ‰ํ•ด์ง

      โ†’ Axios ์ธํ„ฐ์…‰ํ„ฐ๋กœ ๊ณตํ†ต ์—๋Ÿฌ UX(ํ† ์ŠคํŠธ/๋ฆฌ๋‹ค์ด๋ ‰ํŠธ)๋ฅผ ํ•œ ๋ฒˆ์— ๋ฌถ๊ธฐ ์ข‹์Œ

  • (3) ํŒŒ์ผ ์—…๋กœ๋“œ(OCR) ๊ฐ™์€ ์š”์ฒญ์ด ์กด์žฌ

    • ์ฑ„์šฉ๊ณต๊ณ  ์ด๋ฏธ์ง€/PDF ์—…๋กœ๋“œ๋Š” multipart/form-data ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜๊ณ , Axios๊ฐ€ ์ด ํ๋ฆ„๊ณผ ์ž˜ ๋งž์Œ

3. ์‚ฌ์šฉ ๋ฐฉ๋ฒ•

(1) Axios ์ธ์Šคํ„ด์Šค ๋งŒ๋“ค๊ธฐ (๊ณตํ†ต ์„ค์ •)

  • baseURL: ๋ฐฑ์—”๋“œ API ์ฃผ์†Œ
  • timeout: ๋„ˆ๋ฌด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋ฉด ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์ด ๋‚˜๋น ์ง€๋‹ˆ ์ œํ•œ
  • ๊ณตํ†ต ํ—ค๋” ๋“ฑ

(2) Interceptor๋กœ ์ธ์ฆ/์—๋Ÿฌ ๊ณตํ†ต ์ฒ˜๋ฆฌ

  • ์š”์ฒญ ์ธํ„ฐ์…‰ํ„ฐ: ํ† ํฐ(๋˜๋Š” ์„ธ์…˜ ํ—ค๋”) ์ž๋™ ์ฒจ๋ถ€
  • ์‘๋‹ต ์ธํ„ฐ์…‰ํ„ฐ: 401์ด๋ฉด ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์œ ๋„, ํ† ์ŠคํŠธ ๋“ฑ ๊ณตํ†ต ์ฒ˜๋ฆฌ

4. ๋‹ค๋ฅธ ์Šคํƒ๊ณผ์˜ ๋น„๊ต ํ‘œ

ํ•ญ๋ชฉ React Testing Library React Test Renderer Cypress/Playwright ์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ
ํ…Œ์ŠคํŠธ ๊ด€์  ์‚ฌ์šฉ์ž ๊ด€์ (DOM ์ƒํ˜ธ์ž‘์šฉ ์ค‘์‹ฌ) ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ/์Šค๋ƒ…์ƒท ์ค‘์‹ฌ์œผ๋กœ ํ๋ฅด๊ธฐ ์‰ฌ์›€ ์‹ค์ œ ๋ธŒ๋ผ์šฐ์ €์— ๊ฐ€๊นŒ์šด ํ™˜๊ฒฝ์—์„œ ๊ฒ€์ฆ ๊ฐ€๋Šฅ
๊ฐ•์  ์ ‘๊ทผ์„ฑ ๊ธฐ๋ฐ˜ ์กฐํšŒ, ๋ฆฌํŒฉํ† ๋ง ๋‚ด๊ตฌ์„ฑ, ํŒ€ ํ‘œ์ค€ํ™” ์šฉ์ด ๋‹จ์ˆœ ๊ตฌ์กฐ ๊ฒ€์ฆ/์Šค๋ƒ…์ƒท์— ๋น ๋ฅด๊ฒŒ ์ ์šฉ ๊ฐ€๋Šฅ ๋ Œ๋”๋ง/์Šคํƒ€์ผ/๋ธŒ๋ผ์šฐ์ € ๋™์ž‘๊นŒ์ง€ ๋” ํ˜„์‹ค์ ์œผ๋กœ ํ™•์ธ
์ฃผ์˜์  ์—ญํ• /๋ผ๋ฒจ ์„ค๊ณ„(์ ‘๊ทผ์„ฑ)๊ฐ€ ์•ˆ ๋˜์–ด ์žˆ์œผ๋ฉด ํ…Œ์ŠคํŠธ๊ฐ€ ์–ด๋ ต๊ฒŒ ๋А๊ปด์งˆ ์ˆ˜ ์žˆ์Œ ์Šค๋ƒ…์ƒท ๋‚จ๋ฐœ ์‹œ ์˜๋ฏธ ์—†๋Š” ๋ณ€๊ฒฝ์—๋„ ํ…Œ์ŠคํŠธ๊ฐ€ ์ž์ฃผ ๊นจ์งˆ ์ˆ˜ ์žˆ์Œ ์„ค์ •/์‹คํ–‰ ๋น„์šฉ์ด ์ƒ๋Œ€์ ์œผ๋กœ ํฌ๊ณ , ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋กœ๋Š” ๊ณผํ•  ์ˆ˜ ์žˆ์Œ
์ถ”์ฒœ ์ƒํ™ฉ ๋Œ€๋ถ€๋ถ„์˜ ์ปดํฌ๋„ŒํŠธ/๋‹จ์œ„ ํ…Œ์ŠคํŠธ ๊ธฐ๋ณธ๊ฐ’ ์•„์ฃผ ๋‹จ์ˆœํ•œ ๋ Œ๋” ๊ตฌ์กฐ ํ™•์ธ, ์ œํ•œ์  ์‚ฌ์šฉ UI ๋ธŒ๋ผ์šฐ์ € ํŠน์„ฑ/๋ ˆ์ด์•„์›ƒ/ํ†ตํ•ฉ์— ๊ฐ€๊นŒ์šด ๊ฒ€์ฆ์ด ํ•„์š”ํ•  ๋•Œ
  • ์‚ฌ์šฉ์ž ๊ด€์  ํ…Œ์ŠคํŠธ ์ ํ•ฉ์„ฑ

    • React Test Renderer๋Š” ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ/์Šค๋ƒ…์ƒท ์ค‘์‹ฌ์œผ๋กœ ํ…Œ์ŠคํŠธ๊ฐ€ ํ๋ฅด๊ธฐ ์‰ฌ์›Œ, โ€˜์‚ฌ์šฉ์ž๊ฐ€ ์‹ค์ œ๋กœ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๊ณ  ํ™”๋ฉด์ด ๋ฐ”๋€Œ๋Š”์ง€โ€™ ๊ฐ™์€ ํ•ต์‹ฌ ์‹œ๋‚˜๋ฆฌ์˜ค ๊ฒ€์ฆ์ด ์•ฝํ•ด์งˆ ์ˆ˜ ์žˆ์Œ

      โ†”๏ธ ๋ฐ˜๋ฉด React Testing Library๋Š” DOM ์ƒํ˜ธ์ž‘์šฉ(ํด๋ฆญ/์ž…๋ ฅ/ํ™”๋ฉด์— ๋ณด์ด๋Š” ํ…์ŠคํŠธ)์„ ๊ธฐ์ค€์œผ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ฒŒ ์œ ๋„ํ•˜๋ฏ€๋กœ, Devths์ฒ˜๋Ÿผ ์ธํ„ฐ๋ž™์…˜์ด ๋งŽ์€ UI์—์„œ ํ…Œ์ŠคํŠธ ๋ชฉ์ ์ด ๋ช…ํ™•ํ•ด์ง€๊ณ  ์œ ์ง€๋ณด์ˆ˜์„ฑ์ด ๋†’์•„์ง

  • ๋ฆฌํŒฉํ† ๋ง ๋‚ด๊ตฌ์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜ ๋น„์šฉ

    • React Test Renderer์˜ ์Šค๋ƒ…์ƒท์€ ๋งˆํฌ์—… ๊ตฌ์กฐ ๋ณ€ํ™”์— ๋ฏผ๊ฐํ•ด, ๊ธฐ๋Šฅ์€ ๋™์ผํ•œ๋ฐ๋„ ๊ตฌ์กฐ๊ฐ€ ์กฐ๊ธˆ๋งŒ ๋ฐ”๋€Œ๋ฉด ํ…Œ์ŠคํŠธ๊ฐ€ ์ž์ฃผ ๊นจ์ง€๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ

      โ†”๏ธ ๋ฐ˜๋ฉด React Testing Library๋Š” ์—ญํ• (role), ๋ผ๋ฒจ(label), ํ…์ŠคํŠธ ๋“ฑ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์ด๋Š” ๊ธฐ์ค€์œผ๋กœ ์กฐํšŒํ•˜๋Š” ํŒจํ„ด์ด ๊ฐ•ํ•ด, ๋‚ด๋ถ€ ๊ตฌํ˜„์„ ๋ฆฌํŒฉํ† ๋งํ•ด๋„ ํ…Œ์ŠคํŠธ๊ฐ€ ์ƒ๋Œ€์ ์œผ๋กœ ๋œ ๊นจ์ ธ ์žฅ๊ธฐ ์œ ์ง€๋ณด์ˆ˜ ๋น„์šฉ์„ ๋‚ฎ์ถ”๋Š” ๋ฐ ์œ ๋ฆฌํ•จ

  • ํ…Œ์ŠคํŠธ ๋ฒ”์œ„ ๋Œ€๋น„ ์‹คํ–‰/์šด์˜ ํšจ์œจ

    • Cypress/Playwright์˜ ์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ๋Š” ์‹ค์ œ ๋ธŒ๋ผ์šฐ์ €์— ๊ฐ€๊นŒ์šด ํ™˜๊ฒฝ์—์„œ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์„ค์ •ยท์‹คํ–‰ ๋น„์šฉ์ด ์ƒ๋Œ€์ ์œผ๋กœ ํฌ๊ณ  ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋กœ๋Š” ๊ณผํ•œ ์ˆ˜์ค€์ด ๋  ์ˆ˜ ์žˆ์Œ(ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก ๋ถ€๋‹ด ๋ˆ„์ )

      โ†”๏ธ ๋ฐ˜๋ฉด React Testing Library๋Š” ๋Œ€๋ถ€๋ถ„์˜ ์ปดํฌ๋„ŒํŠธ/๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์ปค๋ฒ„ํ•˜๋Š” ํ‘œ์ค€ ์กฐํ•ฉ์œผ๋กœ ์“ฐ๊ธฐ ์ข‹์•„, Devths์˜ ์ปดํฌ๋„ŒํŠธ/๋กœ์ง ํ…Œ์ŠคํŠธ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ๋‘๊ธฐ ์ ํ•ฉํ•จ

  • ํŒ€ ํ‘œ์ค€ํ™” ๋ฐ ์ ‘๊ทผ์„ฑ(UX) ํ’ˆ์งˆ ๊ด€์ 

    • ๋‹จ์ˆœ ๋ Œ๋” ๊ตฌ์กฐ ๊ฒ€์ฆ์— ์น˜์šฐ์น˜๋ฉด, ์ ‘๊ทผ์„ฑ ์†์„ฑ(๋ผ๋ฒจ/role)์ด๋‚˜ ์‚ฌ์šฉ์ž ํ๋ฆ„ ์ค‘์‹ฌ์˜ ํ’ˆ์งˆ ๊ธฐ์ค€์ด ํ…Œ์ŠคํŠธ์— ๋ฐ˜์˜๋˜๊ธฐ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์Œ

      โ†”๏ธ ๋ฐ˜๋ฉด React Testing Library๋Š” ์ ‘๊ทผ์„ฑ ๊ธฐ๋ฐ˜ ์กฐํšŒ(getByRole ๋“ฑ) ์‚ฌ์šฉ์ด ์ž์—ฐ์Šค๋Ÿฌ์›Œ, ์ปดํฌ๋„ŒํŠธ ๊ฐœ๋ฐœ ์‹œ ์ ‘๊ทผ์„ฑยท์‚ฌ์šฉ์„ฑ ๊ธฐ์ค€์„ ํ•จ๊ป˜ ๋งž์ถ”๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ํŒ€ ํ‘œ์ค€ํ™”๋ฅผ ๋งŒ๋“ค๊ธฐ ์šฉ์ดํ•จ

5. ๋ฒ„์ „ ์„ ํƒ ์ด์œ 

  • v16.3.1
    • 2025๋…„ 12์›” 15์ผ์— ๋ฆด๋ฆฌ์ฆˆ ๋จ
  • ์ด์œ 
    • ํ…Œ์ŠคํŠธ ์ธํ”„๋ผ์˜ ํ•ต์‹ฌ ์˜์กด์„ฑ์ด๋ฏ€๋กœ, ๋™์ผ ๋ฉ”์ด์ € ๋ผ์ธ(16.x)์—์„œ ํŒจ์น˜ ๋ฒ„์ „๊นŒ์ง€ ํฌํ•จํ•œ ์•ˆ์ • ๋ฒ„์ „์„ ์‚ฌ์šฉํ•ด ๋ฒ„๊ทธ ์ˆ˜์ •/์•ˆ์ •์„ฑ ๊ฐœ์„  ์‚ฌํ•ญ์„ ๋ฐ˜์˜ํ•จ
    • Devths๋Š” React 19.x ๋ฐ Next.js ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฐœ๋ฐœ๋˜๋ฏ€๋กœ, ์ตœ์‹  React ํ™˜๊ฒฝ์—์„œ์˜ ๋™์ž‘ ํ˜ธํ™˜์„ฑ๊ณผ ํƒ€์ž… ์ •์˜ ์ผ๊ด€์„ฑ์„ ์šฐ์„  ๊ณ ๋ คํ•จ
    • ๋˜ํ•œ Vitest/Jest ๋“ฑ ์ฃผ์š” ํ…Œ์ŠคํŠธ ๋Ÿฌ๋„ˆ ์กฐํ•ฉ์—์„œ ๋„๋ฆฌ ์‚ฌ์šฉ๋˜๋Š” ๋ฒ„์ „ ๋ผ์ธ์„ ์„ ํƒํ•จ์œผ๋กœ์จ, ๋„์ž… ๋ฐ ์šด์˜ ๊ณผ์ •์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ํ˜ธํ™˜์„ฑ ์ด์Šˆ์™€ ์˜ˆ๊ธฐ์น˜ ์•Š์€ ๋ณ€๊ฒฝ ๋ฆฌ์Šคํฌ๋ฅผ ์ตœ์†Œํ™”ํ•จ

6. ๊ฒฐ๋ก 

  • Devths๋Š” ์ƒํ˜ธ์ž‘์šฉ๊ณผ ์ƒํƒœ ๋ณ€ํ™”๊ฐ€ ๋งŽ์€ ํ™”๋ฉด์ด ์ค‘์‹ฌ์ด๋ฏ€๋กœ, ๊ตฌํ˜„ ๋ฐฉ์‹์ด ์•„๋‹ˆ๋ผ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜(๋™์ž‘/ํ‘œ์‹œ/๊ฒ€์ฆ ๊ทœ์น™)์„ ๊ธฐ์ค€์œผ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ์ด ์œ ์ง€๋ณด์ˆ˜์— ์œ ๋ฆฌํ•จ
  • ๋”ฐ๋ผ์„œ ์ปดํฌ๋„ŒํŠธ/๋‹จ์œ„ ํ…Œ์ŠคํŠธ์˜ ๊ธฐ๋ณธ ๋„๊ตฌ๋กœ React Testing Library๋ฅผ ์ฑ„ํƒํ•˜๋Š” ๊ตฌ์„ฑ์ด ์ ํ•ฉํ•˜๋‹ค๊ณ  ํŒ๋‹จํ•จ

๐Ÿ’ฏ E2E ํ…Œ์ŠคํŠธ

โœ… Playwright

1. ํŠน์ง• ์š”์•ฝ

  • ์ง„์งœ ๋ธŒ๋ผ์šฐ์ €๋กœ ์‚ฌ์šฉ์ž ํ–‰๋™์„ ๊ทธ๋Œ€๋กœ ํ…Œ์ŠคํŠธ
    • ํด๋ฆญ/์ž…๋ ฅ/์Šคํฌ๋กค/ํŽ˜์ด์ง€ ์ด๋™์ฒ˜๋Ÿผ ์‚ฌ์šฉ์ž๊ฐ€ ํ•˜๋Š” ํ–‰๋™์„ ์ž๋™์œผ๋กœ ์‹คํ–‰ํ•ด์„œ, โ€œ๋กœ๊ทธ์ธ๋ถ€ํ„ฐ ๊ธ€ ์ž‘์„ฑ๊นŒ์ง€โ€ ๊ฐ™์€ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ํ†ต์œผ๋กœ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ์Œ
  • ํฌ๋กœ์Šค ๋ธŒ๋ผ์šฐ์ € ์ง€์›
    • Chromium / Firefox / WebKit(์‚ฌํŒŒ๋ฆฌ ๊ณ„์—ด) ํ™˜๊ฒฝ์„ ํ•œ ๋ฒˆ์— ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์–ด, ํŠน์ • ๋ธŒ๋ผ์šฐ์ €์—์„œ๋งŒ ๊นจ์ง€๋Š” ๋ฌธ์ œ๋ฅผ ์žก๊ธฐ ์ข‹์Œ
  • ์ž๋™ ๋Œ€๊ธฐ(auto-wait)๋กœ ํ”Œ๋ž˜ํ‚ค ํ…Œ์ŠคํŠธ ๊ฐ์†Œ
    • ์š”์†Œ๊ฐ€ ์ค€๋น„๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ธ๋‹ค๊ฐ€ ๋™์ž‘ํ•˜๋Š” ๋ฐฉ์‹์ด๋ผ(๋ฒ„ํŠผ์ด ๋œจ๊ธฐ ์ „์— ํด๋ฆญํ•ด์„œ ์‹คํŒจํ•˜๋Š” ๋ฌธ์ œ ๋“ฑ) E2E ์•ˆ์ •์„ฑ์ด ์ข‹์•„์ง
  • ๋””๋ฒ„๊น… ๋„๊ตฌ๊ฐ€ ๊ฐ•ํ•จ(Trace/๋ฆฌํฌํŠธ/์Šคํฌ๋ฆฐ์ƒท/๋น„๋””์˜ค)
    • ์‹คํŒจํ–ˆ์„ ๋•Œ ์™œ ์‹คํŒจํ–ˆ๋Š”์ง€๋ฅผ ์ถ”์ ํ•˜๊ธฐ ์œ„ํ•ด Trace Viewer, HTML ๋ฆฌํฌํŠธ, ์Šคํฌ๋ฆฐ์ƒท/๋น„๋””์˜ค ๋“ฑ์„ ๋‚จ๊ธธ ์ˆ˜ ์žˆ์Œ

2. devths์— ์ด ๊ธฐ์ˆ ์ด ํ•„์š”ํ•œ ์ด์œ 

๐Ÿ’ก

Devths๋Š” ๊ธฐ๋Šฅ์ด ๋งŽ๊ณ  ํ๋ฆ„์ด ๊ธธ์–ด์„œ(์บ˜๋ฆฐ๋”/๊ฒŒ์‹œํŒ/์ฑ„ํŒ…/AI), ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋งŒ์œผ๋กœ๋Š” โ€œ์ „์ฒด ๋™์ž‘โ€์ด ๊นจ์กŒ๋Š”์ง€ ๋†“์น˜๊ธฐ ์‰ฌ์›€.

  • Playwright E2E๋กœ ํ•ต์‹ฌ ์œ ์ € ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ํ†ต์งธ๋กœ ์ž๋™ ๊ฒ€์ฆํ•˜๋ฉด ๋ฐฐํฌ ์ „ ํšŒ๊ท€(Regression) ๋ฒ„๊ทธ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์Œ.

(1) ๋กœ๊ทธ์ธ/์ธ์ฆ ํ๋ฆ„ ๊ฒ€์ฆ

  • ๋กœ๊ทธ์ธ ์„ฑ๊ณต/์‹คํŒจ, ๋กœ๊ทธ์ธ ํ›„ ๋ณดํ˜ธ ํŽ˜์ด์ง€ ์ ‘๊ทผ ๊ฐ€๋Šฅ ์—ฌ๋ถ€(๊ฐ€๋“œ) ๊ฐ™์€ ํ๋ฆ„์€ E2E์—์„œ ์žก๋Š” ๊ฒŒ ๊ฐ€์žฅ ํ™•์‹คํ•จ

(2) ๊ฒŒ์‹œํŒ ํ•ต์‹ฌ ์‹œ๋‚˜๋ฆฌ์˜ค

  • ๊ธ€ ๋ชฉ๋ก ์ง„์ž… โ†’ ๊ฒ€์ƒ‰/ํ•„ํ„ฐ โ†’ ์ƒ์„ธ ์ง„์ž… โ†’ ๋Œ“๊ธ€ ์ž‘์„ฑ/์‚ญ์ œ โ†’ ์ข‹์•„์š” ํ† ๊ธ€ ๊ฐ™์€ ์—ฐ์† ํ๋ฆ„โ€๊ฒ€์ฆ

(3) ์บ˜๋ฆฐ๋” + OCR ์ผ์ • ์ž๋™ ์‚ฝ์ž…

  • ํŒŒ์ผ ์—…๋กœ๋“œ โ†’ ์ฒ˜๋ฆฌ ๋Œ€๊ธฐ ๋ชจ๋‹ฌ โ†’ ๊ฒฐ๊ณผ ์ดˆ์•ˆ ํ™•์ธ โ†’ ์ €์žฅ ํ›„ ์บ˜๋ฆฐ๋”์— ๋ฐ˜์˜

    ์ด๋Ÿฐ ๋น„๋™๊ธฐ + ๋ชจ๋‹ฌ ํ๋ฆ„์€ E2E๋กœ ์‹ค์ œ ์‚ฌ์šฉ์ž ๊ด€์ ์—์„œ ํ™•์ธํ•˜๋Š” ๊ฒŒ ํšจ๊ณผ์ ์ž„

(4) ์ฑ„ํŒ…(์‹ค์‹œ๊ฐ„)

  • ์ตœ์†Œํ•œ โ€œ๋ฉ”์‹œ์ง€ ์ „์†ก UI๊ฐ€ ๊นจ์ง€์ง€ ์•Š๋Š”๋‹คโ€, โ€œ์—ฐ๊ฒฐ ๋Š๊น€ ์‹œ ์•ˆ๋‚ด๊ฐ€ ๋œฌ๋‹คโ€ ๊ฐ™์€ ํ•ต์‹ฌ UX๋ฅผ ์‹œ๋‚˜๋ฆฌ์˜ค๋กœ ๊ณ ์ • ๊ฐ€๋Šฅ

3. ์‚ฌ์šฉ ๋ฐฉ๋ฒ•

  • ํ…Œ์ŠคํŠธ ๋‹จ์œ„
    • auth.spec.ts: ๋กœ๊ทธ์ธ/๋กœ๊ทธ์•„์›ƒ/๋ณดํ˜ธ ๋ผ์šฐํŠธ
    • board.spec.ts: ๊ธ€ ๋ชฉ๋ก/์ƒ์„ธ/๋Œ“๊ธ€/์ข‹์•„์š”
    • calendar.spec.ts: ์ผ์ • CRUD + ์›”/์ฃผ ๋ทฐ ์ „ํ™˜
    • ocr.spec.ts: ๊ณต๊ณ  ์—…๋กœ๋“œ โ†’ ์ฒ˜๋ฆฌ โ†’ ์ดˆ์•ˆ โ†’ ์ €์žฅ
    • chat.spec.ts: ๋ฉ”์‹œ์ง€ ์ž…๋ ฅ/์ „์†ก(๊ฐ€๋Šฅํ•˜๋ฉด ํ…Œ์ŠคํŠธ์šฉ ์„œ๋ฒ„/๋ชฉ์—… ํ™˜๊ฒฝ์—์„œ)
  • ์‹คํŒจ ๋””๋ฒ„๊น…
    • CI์—์„œ ์‹คํŒจํ•˜๋ฉด Trace Viewer๋กœ ํด๋ฆญ/๋„คํŠธ์›Œํฌ/DOM ์Šค๋ƒ…์ƒท์„ ํƒ€์ž„๋ผ์ธ์œผ๋กœ ๋ณด๋Š” ๋ฐฉ์‹์ด ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•จ

4. ๋‹ค๋ฅธ ์Šคํƒ๊ณผ์˜ ๋น„๊ต ํ‘œ

ํ•ญ๋ชฉ Playwright Cypress Selenium(WebDriver) Puppeteer
๋ธŒ๋ผ์šฐ์ € ์—”์ง„ ๋ฒ”์œ„ Chromium/Firefox/WebKit ์ง€์› (Playwright) ์ฃผ๋กœ Chromium ๊ณ„์—ด ์ค‘์‹ฌ, WebKit์€ ๋ณ„๋„/์ œํ•œ์ (์‹คํ—˜์  ์ง€์› ๋งฅ๋ฝ) (pptr.dev) ๋‹ค์–‘ํ•œ ๋ธŒ๋ผ์šฐ์ € ์ง€์›(ํ‘œ์ค€ ๊ธฐ๋ฐ˜) (Selenium) Chrome/Firefox ์ž๋™ํ™” ์ค‘์‹ฌ
ํ…Œ์ŠคํŠธ ๋Ÿฌ๋„ˆ/๋ณ‘๋ ฌ/๋ฆฌํฌํŠธ ๊ณต์‹ Test ๋Ÿฌ๋„ˆ ๋‚ด์žฅ, ์šด์˜ ๊ธฐ๋Šฅ ํฌํ•จ (Playwright) ๋Ÿฌ๋„ˆ ์ œ๊ณต(์ƒํƒœ๊ณ„ ๊ฐ•ํ•จ) ๋Ÿฌ๋„ˆ๋Š” ๋ณ„๋„ ์กฐํ•ฉ ํ•„์š”(ํ”„๋ ˆ์ž„์›Œํฌ ์„ ํƒ) ๋Ÿฌ๋„ˆ๋ผ๊ธฐ๋ณด๋‹ค โ€œ๋ธŒ๋ผ์šฐ์ € ์ž๋™ํ™” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌโ€ ์„ฑ๊ฒฉ
์•ˆ์ •์„ฑ(ํƒ€์ด๋ฐ ์ด์Šˆ ๋Œ€์‘) locator/auto-wait ํ๋ฆ„ ์ œ๊ณต (Playwright) ์ž์ฒด ๋Œ€๊ธฐ/์žฌ์‹œ๋„ ํŒจํ„ด ์ œ๊ณต ๋Œ€๊ธฐ/๋™๊ธฐํ™” ์„ค๊ณ„๋ฅผ ์ง์ ‘ ์ž˜ ํ•ด์•ผ ํ•จ (Selenium) ๋Œ€๊ธฐ/๋™๊ธฐํ™”๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ์„ค๊ณ„ํ•˜๋Š” ๋น„์ค‘ ํผ
Next.js์™€์˜ ๊ถํ•ฉ ๋ธŒ๋ผ์šฐ์ € ๊ธฐ๋ฐ˜ E2E์— ์ ํ•ฉ(๋ผ์šฐํŒ…/SSR/์ฟ ํ‚ค ํ๋ฆ„ ๊ฒ€์ฆ) ๊ฐ€๋Šฅ ๊ฐ€๋Šฅ(๊ตฌ์„ฑ ๋ถ€๋‹ด ์ƒ๋Œ€์ ์œผ๋กœ ํผ) ๊ฐ€๋Šฅ(ํ•˜์ง€๋งŒ E2E ์šด์˜ ๊ธฐ๋Šฅ์€ ์ง์ ‘ ๊ตฌ์„ฑ ํ•„์š”)
  • ๋ธŒ๋ผ์šฐ์ € ์ปค๋ฒ„๋ฆฌ์ง€์™€ ํฌ๋กœ์Šค ๋ธŒ๋ผ์šฐ์ € ๊ฒ€์ฆ

    • Cypress๋Š” ์ฃผ๋กœ Chromium ๊ณ„์—ด ์ค‘์‹ฌ์œผ๋กœ ์šด์˜๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์•„, Firefox/WebKit๊นŒ์ง€ ๊ฐ™์€ ์ˆ˜์ค€์œผ๋กœ ํญ๋„“๊ฒŒ ๊ฒ€์ฆํ•˜๋ ค๋ฉด ์ œ์•ฝ์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ์Œ

      โ†”๏ธ ๋ฐ˜๋ฉด Playwright๋Š” Chromium/Firefox/WebKit์„ ๊ณต์‹์ ์œผ๋กœ ์ง€์›ํ•˜๋ฏ€๋กœ, Devths์ฒ˜๋Ÿผ ๋กœ๊ทธ์ธ(OAuth), ์ฟ ํ‚ค/์„ธ์…˜, ๋ผ์šฐํŒ… ๋“ฑ ๋ธŒ๋ผ์šฐ์ €๋ณ„ ์ฐจ์ด๊ฐ€ ์ด์Šˆ๊ฐ€ ๋  ์ˆ˜ ์žˆ๋Š” ํ๋ฆ„์„ ํ•œ ๋„๊ตฌ์—์„œ ์ผ๊ด€๋˜๊ฒŒ ํ™•์ธํ•˜๊ธฐ ์œ ๋ฆฌํ•จ

  • E2E ์šด์˜ ๊ธฐ๋Šฅ์˜ ๋‚ด์žฅ ์—ฌ๋ถ€(ํ…Œ์ŠคํŠธ ๋Ÿฌ๋„ˆ/๋ฆฌํฌํŠธ/๋ณ‘๋ ฌ)

    • **Selenium(WebDriver)**์€ ๋‹ค์–‘ํ•œ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ํ‘œ์ค€ ๊ธฐ๋ฐ˜์œผ๋กœ ์ง€์›ํ•˜์ง€๋งŒ, ํ…Œ์ŠคํŠธ ๋Ÿฌ๋„ˆยท๋ณ‘๋ ฌ ์‹คํ–‰ยท๋ฆฌํฌํŠธ ๊ฐ™์€ ์šด์˜ ๊ธฐ๋Šฅ์€ ๋ณ„๋„๋กœ ์กฐํ•ฉํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์•„ ์ดˆ๊ธฐ ๊ตฌ์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜ ๋ถ€๋‹ด์ด ์ปค์งˆ ์ˆ˜ ์žˆ์Œ

      โ†”๏ธ ๋ฐ˜๋ฉด Playwright๋Š” ๊ณต์‹ ํ…Œ์ŠคํŠธ ๋Ÿฌ๋„ˆ๋ฅผ ํฌํ•จํ•˜๊ณ  ๋ณ‘๋ ฌ ์‹คํ–‰/๋ฆฌํฌํŠธ ๋“ฑ ์šด์˜ ๊ธฐ๋Šฅ์„ ๊ธฐ๋ณธ ์ œ๊ณตํ•˜๋ฏ€๋กœ, ํŒ€ ๊ณผ์ œ/ํ”„๋กœ์ ํŠธ ํ™˜๊ฒฝ์—์„œ ๋„์ž… ํ›„ ๋ฐ”๋กœ ๋Œ๋ฆด ์ˆ˜ ์žˆ๋Š” ํ˜•ํƒœ๋กœ ํ‘œ์ค€ํ™”ํ•˜๊ธฐ ์šฉ์ดํ•จ

  • ์•ˆ์ •์„ฑ(ํƒ€์ด๋ฐ ์ด์Šˆ)๊ณผ ์œ ์ง€๋ณด์ˆ˜ ๋น„์šฉ

    • Selenium์ด๋‚˜ Puppeteer๋Š” ๋Œ€๊ธฐ/๋™๊ธฐํ™”(์š”์†Œ๊ฐ€ ๋œจ๋Š” ์‹œ์ , ๋„คํŠธ์›Œํฌ ์™„๋ฃŒ ์‹œ์ )๋ฅผ ์‚ฌ์šฉ์ž๊ฐ€ ๋” ์ง์ ‘ ์„ค๊ณ„ํ•ด์•ผ ํ•ด์„œ, ํ™”๋ฉด์ด ๋ณต์žกํ•ด์งˆ์ˆ˜๋ก ํƒ€์ด๋ฐ ์ด์Šˆ๋กœ ํ…Œ์ŠคํŠธ๊ฐ€ ๋ถˆ์•ˆ์ •ํ•ด์งˆ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Œ

      โ†”๏ธ ๋ฐ˜๋ฉด Playwright๋Š” locator ๊ธฐ๋ฐ˜ auto-wait ํ๋ฆ„์„ ์ œ๊ณตํ•˜์—ฌ, DOM ๋ Œ๋”๋ง/๋„ค๋น„๊ฒŒ์ด์…˜/๋น„๋™๊ธฐ ์š”์ฒญ์ด ์„ž์ธ ํ™˜๊ฒฝ์—์„œ๋„ ํ…Œ์ŠคํŠธ ํ”Œ๋ž˜ํ‚ค(๊ฐ€๋” ์‹คํŒจ) ๋ฆฌ์Šคํฌ๋ฅผ ์ค„์ด๋Š” ๋ฐ ์œ ๋ฆฌํ•จ

  • Next.js ๊ธฐ๋ฐ˜ ์„œ๋น„์Šค ํ๋ฆ„๊ณผ์˜ ์ ํ•ฉ์„ฑ

    • Puppeteer๋Š” ๋ธŒ๋ผ์šฐ์ € ์ž๋™ํ™” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ฑ๊ฒฉ์ด ๊ฐ•ํ•ด E2E ์šด์˜(๋Ÿฌ๋„ˆ, ๋ฆฌํฌํŠธ, ๋ณ‘๋ ฌ, ์žฌ์‹œ๋„ ์ •์ฑ… ๋“ฑ)์€ ์ง์ ‘ ๊ตฌ์„ฑํ•ด์•ผ ํ•˜๋Š” ๋น„์ค‘์ด ํผ

      โ†”๏ธ ๋ฐ˜๋ฉด Playwright๋Š” ๋ธŒ๋ผ์šฐ์ € ๊ธฐ๋ฐ˜ E2E์— ํ•„์š”ํ•œ ์šด์˜ ๊ธฐ๋Šฅ์„ ๊ฐ–์ถ˜ ์ƒํƒœ์—์„œ Next.js์˜ ๋ผ์šฐํŒ…/SSR/์ฟ ํ‚คยท์„ธ์…˜/OAuth ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๊ฐ™์€ ํ๋ฆ„์„ ๊ฒ€์ฆํ•˜๊ธฐ ์ ํ•ฉํ•˜๋ฏ€๋กœ, Devths์˜ ํ•ต์‹ฌ ์‚ฌ์šฉ์ž ์‹œ๋‚˜๋ฆฌ์˜ค(๋žœ๋”ฉโ†’๋กœ๊ทธ์ธโ†’๋ฉ”์ธ ์ง„์ž… ๋“ฑ)๋ฅผ ์•ˆ์ •์ ์œผ๋กœ ์ž๋™ํ™”ํ•˜๊ธฐ์— ์ ์ ˆํ•จ

5. ๋ฒ„์ „ ์„ ํƒ ์ด์œ 

  • v1.57.0
    • 2025๋…„ 11์›” 25์ผ์— ๋ฆด๋ฆฌ์ฆˆ๋จ
  • ์ด์œ 
    • ๊ณต์‹ ๋ฆด๋ฆฌ์ฆˆ ๋…ธํŠธ ๊ธฐ์ค€์œผ๋กœ v1.57 ๋ผ์ธ์ด ์ œ๊ณต๋˜๋ฉฐ(๋ฒ„๊ทธ ์ˆ˜์ •/๊ธฐ๋Šฅ ๊ฐœ์„  ํฌํ•จ), ๋ฉ”์ด์ € ๋ผ์ธ์—์„œ ์ตœ์‹  ๋ฒ„์ „์„ ๊ธฐ์ค€์œผ๋กœ ๋ฌธ์„œ/๊ฐ€์ด๋“œ์™€ ๋™์ผํ•œ ํ๋ฆ„์œผ๋กœ ์šด์˜ํ•˜๊ธฐ ์‰ฌ์›€
    • E2E๋Š” ๋ธŒ๋ผ์šฐ์ € ์‹คํ–‰ ํ™˜๊ฒฝ์— ์˜ํ–ฅ์„ ํฌ๊ฒŒ ๋ฐ›๊ธฐ ๋•Œ๋ฌธ์—, ๋™์ผ ๋ฉ”์ด์ € ๋ผ์ธ์—์„œ ์ตœ์‹  ์•ˆ์ • ๋ฒ„์ „์„ ๊ธฐ์ค€์œผ๋กœ ๋‘๊ณ  ํŒจ์น˜ ์—…๋ฐ์ดํŠธ๋ฅผ ๋”ฐ๋ผ๊ฐ€๋Š” ์ „๋žต์ด ์ผ๋ฐ˜์ ์œผ๋กœ ์šด์˜ ๋ฆฌ์Šคํฌ๋ฅผ ๋‚ฎ์ถค

6. ๊ฒฐ๋ก 

  • devths์˜ ํ•ต์‹ฌ ํ”Œ๋กœ์šฐ๋ฅผ ์‹ค์ œ ๋ธŒ๋ผ์šฐ์ €์—์„œ ๊ฒ€์ฆํ•˜๊ธฐ ์œ„ํ•ด playwright๋ฅผ E2E ํ…Œ์ŠคํŠธ ๋„๊ตฌ๋กœ ์„ ํƒํ•จ

โฐ ์‹ค์‹œ๊ฐ„

โœ… STOMP/WebSocket

1. ํŠน์ง•

  • WebSocket = ์—ฐ๊ฒฐ
    • HTTP์ฒ˜๋Ÿผ ์š”์ฒญํ•  ๋•Œ๋งˆ๋‹ค ๋Š๊ธฐ๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ, ํ•œ ๋ฒˆ ์—ฐ๊ฒฐํ•˜๋ฉด ๊ณ„์† ์œ ์ง€ํ•ด์„œ ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์–‘๋ฐฉํ–ฅ์œผ๋กœ ๋ฐ”๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ์ฃผ๊ณ ๋ฐ›์„ ์ˆ˜ ์žˆ์Œ
  • STOMP = ๋ฉ”์‹œ์ง€ ์ฃผ๊ณ  ๋ฐ›๋Š” ๊ทœ์น™(ํ”„๋กœํ† ์ฝœ)
    • WebSocket ์œ„์—์„œ SEND(์ „์†ก) / SUBSCRIBE (๊ตฌ๋…) ๊ฐ™์€ ํ‘œ์ค€ ๊ทœ์น™์œผ๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ๋‹ค๋ฃธ
    • Spring์€ STOMP๊ธฐ๋ฐ˜์œผ๋กœ destination(์ฃผ์†Œ) ๋ผ์šฐํŒ…์„ ์ง€์›ํ•ด์„œ ์ฑ„ํŒ…๋ฐฉ/์•Œ๋žŒ ๊ฐ™์€ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค๊ธฐ ์‰ฌ์›€
  • Pub/Sub ๋ชจ๋ธ์ด๋ผ ์ฑ„ํŒ…๋ฐฉ์— ๋”ฑ ๋งž์Œ

2. devths์— ์ด ๊ธฐ์ˆ ์ด ํ•„์š”ํ•œ ์ด์œ 

  • 1:1 + ๊ทธ๋ฃน์ฑ„ํŒ…์„ room(๋ฐฉ) ํ•˜๋‚˜๋กœ ํ†ต์ผ ๊ฐ€๋Šฅ
    • 1:1๋„ ์ฐธ์—ฌ์ž 2๋ช…์ธ ๋ฐฉ์œผ๋กœ ๋ณด๋ฉด ๋กœ์ง์ด ํ†ต์ผ๋ผ์„œ ๊ตฌํ˜„/์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์‰ฌ์›€
  • ์ฝ์Œ ์ฒ˜๋ฆฌ๋ฅผ ์‹ค์‹œ๊ฐ„ ์ด๋ฒคํŠธ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์ข‹์Œ
    • ์ฝ์Œ์€ ์ƒํƒœ ๋ณ€ํ™”๋ผ์„œ, STOMP ๋ฉ”์‹œ์ง€๋กœ READ ์ด๋ฒคํŠธ๋ฅผ ๋ณด๋‚ด๊ณ  ๊ฐ™์€ ๋ฐฉ ํ† ํ”ฝ์œผ๋กœ ๋ฟŒ๋ฆฌ๋ฉด UI ๋ฐ˜์˜์ด ๊น”๋”ํ•จ
  • ๊ณผ๊ฑฐ ๋Œ€ํ™”๋Š” REST๋กœ ๊ฐ€์ ธ์˜ค๊ณ , ์‹ค์‹œ๊ฐ„ ์ˆ˜์‹ /์ฝ์Œ๋งŒ WebSocket(STOMP)๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉด ์•ˆ์ •์ ์ž„

3. ์™œ Socket.IO๊ฐ€ ์•„๋‹ˆ๋ผ STOMP?

  • Spring์—์„œ STOMP/WebSocket์ด ํ‘œ์ค€ ๊ฒฝ๋กœ
    • Spring ๊ณต์‹ ์ƒํƒœ๊ณ„๊ฐ€ STOMP ๊ธฐ๋ฐ˜ ๋ฉ”์‹œ์ง•์„ ๊ธฐ๋ณธ ํ๋ฆ„์œผ๋กœ ์ง€์›ํ•จ
    • ๊ด€๋ จ ๋ ˆํผ๋Ÿฐ์Šค/์šด์˜ ํŒจํ„ด์ด ๋งŽ์•„์„œ ํŒ€ ๊ธฐ์ค€์œผ๋กœ ์„ค๋ช…/์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์‰ฌ์›€
  • STOMP๋Š” ํ‘œ์ค€ ํ”„๋กœํ† ์ฝœ โ†’ ๊ตฌ์กฐ๊ฐ€ ๋” ๊ทœ์น™์ 
    • ์ฃผ์†Œ ๊ธฐ๋ฐ˜์ด๋ผ ๋ฐฉ/์œ ์ €/์•Œ๋ฆผ ๋ผ์šฐํŒ… ๊ทœ์น™์„ ๋ฌธ์„œ๋กœ ์ •๋ฆฌํ•˜๊ธฐ ์‰ฌ์›€
    • ๋‚˜์ค‘์— ๋ฉ”์‹œ์ง€ ๋ธŒ๋กœ์ปค ์—ฐ๋™ ํ™•์žฅ๋„ ์ž์—ฐ์Šค๋Ÿฌ์›€
  • Socket.io๋Š” ์ฃผ๋ ฅ ์ƒํƒœ๊ณ„๊ฐ€ ๋‹ค๋ฆ„
    • Socket.io๋Š” Node์—์„œ ๊ฐ•๋ ฅํ•œ ํŽธ์˜ ๊ธฐ๋Šฅ(๋ฃธ/ACK/์žฌ์—ฐ๊ฒฐ ๋“ฑ)์„ ์ œ๊ณตํ•˜์ง€๋งŒ, Spring ๋‹จ๋… ์„œ๋ฒ„์—์„œ ์“ฐ๋ฉด ์ฃผ๋ฅ˜ ํŒจํ„ด์ด ์•„๋‹ˆ๊ธฐ์— ์„ค๋ช…/์œ ์ง€๋ณด์ˆ˜ ๊ด€์ ์—์„œ ์ด์ ์ด ์ค„์–ด๋“ฆ

4. ์™œ Socket.IO์™€์˜ ์ฐจ์ด์ 

  • ์ •์ฒด
    • Socket.IO: ์‹ค์‹œ๊ฐ„ ํ†ต์‹ ์„ ์‰ฝ๊ฒŒ ํ•ด์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ/ํ”„๋ ˆ์ž„์›Œํฌ
    • STOMP: WebSocket ์œ„์—์„œ ๋ฉ”์‹œ์ง€๋ฅผ ์ฃผ๊ณ ๋ฐ›๋Š” ํ‘œ์ค€ ํ”„๋กœํ† ์ฝœ
  • ํ†ต์‹  ๋ฐฉ์‹
    • Socket.IO: emit/on ์ด๋ฒคํŠธ ์ด๋ฆ„ ๊ธฐ๋ฐ˜
    • STOMP: SEND / SUBSCRIBE destiantion(์ฃผ์†Œ) ๊ธฐ๋ฐ˜ (Pub/Sub)
  • ์ฑ„ํŒ…๋ฐฉ ์ฒ˜๋ฆฌ
    • Socket.IO: room ๊ธฐ๋Šฅ ๋‚ด์žฅ
    • STOMP: topic ๊ตฌ๋…์œผ๋กœ ๋ฐฉ์„ ํ‘œํ˜„(์ฃผ์†Œ ์„ค๊ณ„๋กœ ๊ตฌํ˜„)
  • Socket.IO: Node ์ƒํƒœ๊ณ„์—์„œ ๊ฐ•ํ•จ
  • STOMP: Spring์—์„œ ํ‘œ์ค€ ๊ฒฝ๋กœ๋กœ ๋งŽ์ด ์”€

4. ์‚ฌ์šฉ ๋ฐฉ๋ฒ•

(1) destination ๊ทœ์น™

  • ๋ฉ”์‹œ์ง€ ์ˆ˜์‹ (๊ตฌ๋…): /topic/rooms/{roomId}/messages
  • ์ฝ์Œ ์ˆ˜์‹ (๊ตฌ๋…): /topic/rooms/{roomId}/reads
  • ๋ฉ”์‹œ์ง€ ์ „์†ก: /app/rooms/{roomId}/messages
  • ์ฝ์Œ ์ „์†ก: /app/rooms/{roomId}/reads

(2) ์„œ๋ฒ„(Spring) ํ๋ฆ„(๊ฐœ๋…)

  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ /topic/... ๋ฅผ subscribe
  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ /app/... ๋กœ send
  • ์„œ๋ฒ„๋Š” ๋ฐ›์€ ๋ฉ”์‹œ์ง€๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  /topic/... ์œผ๋กœ publish

(3) ํด๋ผ์ด์–ธํŠธ(ํ”„๋ก ํŠธ) ํ๋ฆ„(๊ฐœ๋…)

  • STOMP client๋กœ WebSocket ์—ฐ๊ฒฐ
  • ๋ฐฉ ์ง„์ž… ์‹œ subscribe("/topic/rooms/{roomId}/messages")
  • ๋ฉ”์‹œ์ง€ ๋ณด๋‚ผ ๋•Œ send("/app/rooms/{roomId}/messages", payload)
  • ์ฝ์Œ ์ฒ˜๋ฆฌ ์‹œ send("/app/rooms/{roomId}/reads", payload)
    • ์ƒ๋Œ€๋Š” /topic/rooms/{roomId}/reads ๊ตฌ๋…์œผ๋กœ ์ฆ‰์‹œ ๋ฐ˜์˜

5. ๋‹ค๋ฅธ ์Šคํƒ๊ณผ์˜ ๋น„๊ต ํ‘œ

๋ฐฉ์‹ ์žฅ์  ๋‹จ์  Devths ์ ํ•ฉ๋„
STOMP + WebSocket Spring ํ‘œ์ค€ ํŒจํ„ด, pub/sub๋กœ ๋ฐฉ/์ฝ์Œ ๋ชจ๋ธ๋ง ์‰ฌ์›€, ๋ผ์šฐํŒ… ๊ทœ์น™์ด ๋ช…ํ™• ๊ตฌ๋…/๋ฐœํ–‰ ๊ฐœ๋…์— ์ต์ˆ™ํ•ด์ ธ์•ผ ํ•จ ์ตœ์ 
Socket.IO ์ด๋ฒคํŠธ/๋ฃธ/ACK/์žฌ์—ฐ๊ฒฐ ๋“ฑ ๊ตฌํ˜„์ด ํŽธํ•จ(ํŠนํžˆ Node์—์„œ) Spring ๋‹จ๋… ์„œ๋ฒ„์—์„  ์ฃผ๋ฅ˜ ๊ฒฝ๋กœ๊ฐ€ ์•„๋‹˜(๋ ˆํผ๋Ÿฐ์Šค/์šด์˜ ํŒจํ„ด ์•ฝํ•ด์งˆ ์ˆ˜ ์žˆ์Œ) ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์šฐ์„ ์ˆœ์œ„โ†“
์ˆœ์ˆ˜ WebSocket ๊ฐ€๋ณ๊ณ  ์ž์œ ๋„ ๋†’์Œ destination/๊ตฌ๋…/๊ถŒํ•œ/๋ผ์šฐํŒ…์„ ์ง์ ‘ ์„ค๊ณ„ํ•ด์•ผ ํ•ด์„œ ๊ธˆ๋ฐฉ ๋ณต์žกํ•ด์ง ๊ทœ๋ชจ ์ปค์ง€๋ฉด ๋ถ€๋‹ด
SSE ์„œ๋ฒ„โ†’ํด๋ผ ๋‹จ๋ฐฉํ–ฅ ํ‘ธ์‹œ๊ฐ€ ๊ฐ„๋‹จ ํด๋ผโ†’์„œ๋ฒ„ ์‹ค์‹œ๊ฐ„ ์ „์†ก์— ๋ถ€์ ํ•ฉ(์ฑ„ํŒ…์—” ๋ถˆ๋ฆฌ) โŒ

7. ๊ฒฐ๋ก 

  • Devths๋Š” Spring ๊ธฐ๋ฐ˜์ด๊ณ  1:1/๊ทธ๋ฃน ์ฑ„ํŒ… + ์ฝ์Œ ์ฒ˜๋ฆฌ๊ฐ€ ํ•ต์‹ฌ์ด๋ผ, WebSocket(์—ฐ๊ฒฐ)+ STOMP(๋ฉ”์‹œ์ง• ๊ทœ์น™) ์กฐํ•ฉ์ด ๊ฐ€์žฅ ํ‘œ์ค€์ ์ด๊ณ  ์„ค๊ณ„๊ฐ€ ๊น”๋”ํ•จ
  • ํŠนํžˆ ์ฑ„ํŒ…์„ room ๋‹จ์œ„๋กœ ํ†ต์ผํ•˜๊ณ , ์ฝ์Œ์„ lastRead(๋งˆ์ง€๋ง‰์œผ๋กœ ์ฝ์€ ์œ„์น˜)๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉด ๋ณต์žก๋„๋ฅผ ํฌ๊ฒŒ ์ค„์ด๋ฉด์„œ UX๋ฅผ ๋งŒ์กฑ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Œ
โš ๏ธ **GitHub.com Fallback** โš ๏ธ