์ด๋ ฅ์„œ
home
Product
home

CHINGOO.BE

์œ ํ˜•
Side Project (Essential)
ํ•œ ์ค„ ์†Œ๊ฐœ
ํ† ์Šค ์ต๋ช…์†ก๊ธˆ๊ณผ ์—ฐ๋™๋˜๋Š” ์นœ๊ตฌ๋น„ ์˜์ˆ˜์ฆ ์„œ๋น„์Šค
ํ”„๋กœ์ ํŠธ ๊ธฐ๊ฐ„
2024/02/15 โ†’ 2024/02/22
ํ”„๋กœ์ ํŠธ ๊ธฐ์ˆ  ์Šคํƒ
Next.js
PlanetScale
Prisma ORM
Tailwind CSS
React-Hook-Form
Superstruct
Vercel
ํŒ€ ๊ตฌ์„ฑ
1์ธ ๊ฐœ๋ฐœ
๋‹ด๋‹น ํฌ์ง€์…˜
Front-End
Back-End
1 more property

๋งํฌ

GitHub Repository

DEMO

Blog Posting

[Typescript] Next.js์™€ Storybook์—์„œ SVGํŒŒ์ผ์„ ์ปดํฌ๋„ŒํŠธ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜๊ธฐ (with @svgr/webpack)
์„œ๋ก  ํ•„์ž๊ฐ€ ์ตœ๊ทผ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ, SVG ์ด๋ฏธ์ง€ ํŒŒ์ผ๋“ค์„ ์ปดํฌ๋„ŒํŠธ์ฒ˜๋Ÿผ importํ•˜์—ฌ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋Š” ๋‹ˆ์ฆˆ๊ฐ€ ์ƒ๊ฒผ๋‹ค. ๊ทธ๋ž˜์„œ Next.js์™€ Storybook ๋“ฑ, Webpack ํ™˜๊ฒฝ์—์„œ SVG ์ด๋ฏธ์ง€ ํŒŒ์ผ์„ ์ปดํฌ๋„ŒํŠธ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ์•„๋ณด์•˜๊ณ , ์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„  ์ด๋ฅผ ๊ณต์œ ํ•ด๋ณด๋ ค ํ•œ๋‹ค. SVGR๊ณผ @svgr/webpack SVGR์€ SVG ์ด๋ฏธ์ง€ ํŒŒ์ผ์„ React ์ปดํฌ๋„ŒํŠธ๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ๋Š” ํ”„๋กœ์ ํŠธ์ด๋‹ค. ๊ทธ์ค‘์—์„œ @svgr/webpack ํŒจํ‚ค์ง€๋ฅผ ์ด์šฉํ•˜๋ฉด, Webpack ๋ฒˆ๋“ค๋Ÿฌ๋ฅผ ์ด์šฉํ•˜๋Š” ํ”„๋กœ์ ํŠธ์—์„œ SVG ์ด๋ฏธ์ง€ ํŒŒ์ผ์„ ์ปดํฌ๋„ŒํŠธ์ฒ˜๋Ÿผ importํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค. SVGR - Transforms SVG into React Components. - SVGR Transforms SVG into ..
[Typescript] Superstruct ์˜ค๋ฅ˜๋ฉ”์‹œ์ง€ ์ปค์Šคํ…€ํ•˜๊ธฐ
์„œ๋ก  ์ตœ๊ทผ ํ•„์ž๋Š” Supersturct๋ฅผ ์‚ฌ์šฉํ•ด๋ณด๋‹ค๊ฐ€ Superstruct๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์˜ค๋ฅ˜๋ฉ”์‹œ์ง€๋ฅผ ์ปค์Šคํ…€ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ์ ์„ ์•Œ๊ฒŒ๋๋‹ค. ์ด๋Š”, ๊ฐœ๋ฐœ์ž๊ฐ€ ์ž„์˜๋กœ ์˜ค๋ฅ˜๋ฉ”์‹œ์ง€๋ฅผ ์ˆ˜์ •ํ•˜์—ฌ ๋ถ€์ •ํ™•ํ•œ validation ๊ฒฐ๊ณผ๋ฅผ ๋‚ด๋ณด๋‚ด์ง€ ๋ชปํ•˜๋„๋ก ํ•˜๋Š” Supersturct์˜ ์ฒ ํ•™์ด๋ผ๊ณ  ํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์ผ์ƒ์ ์ธ ์ƒํ™ฉ์—์„  ์‚ฌ์šฉ์ž์—๊ฒŒ ํ˜„์žฌ ๋ฐœ์ƒํ•œ ์˜ค๋ฅ˜์— ๋”ฐ๋ฅธ ๋ฌธ๊ตฌ๋ฅผ ๋ณด์—ฌ์ฃผ์–ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ด ๋” ๋งŽ์„ ๊ฒƒ์ด๊ณ , Supersturct๋Š” ์ด๋ฅผ ์œ„ํ•œ ๋Œ€์‘์„ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ด๋ฅผ ์œ„ํ•œ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์„ ์ฐพ๋‹ค๊ฐ€ Superstruct GitHub issue์— ๊ดœ์ฐฎ์€ ์•„์ด๋””์–ด๋ฅผ ๋ฐœ๊ฒฌํ•˜๊ฒŒ ๋˜์–ด ์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ ์†Œ๊ฐœํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ค. ํ•ด๊ฒฐ์ฑ…: ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ํ•จ์ˆ˜๋ฅผ ์ง์ ‘ ๋งŒ๋“ค์–ด๋ฒ„๋ฆฌ์ž custom error messages ยท Issue #568 ยท ians..
[Typescript] Zod์—์„œ Superstruct๋กœ์˜ ์ „ํ™˜๊ธฐ
์„œ๋ก  ์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„ , ํ•„์ž๊ฐ€ CHINGOO.BE ํ”„๋กœ์ ํŠธ(GitHub repo.)๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ตœ์ ํ™”๋“ค์„ ์‹œ๋„ํ•˜๋‹ค๊ฐ€ ๋ฒˆ๋“ค ์‚ฌ์ด์ฆˆ ๊ด€๋ จ ์ตœ์ ํ™”์˜ ์ผํ™˜์œผ๋กœ ๊ธฐ์กด ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉ์ค‘์ด๋˜ zod ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ superstruct๋กœ ์ „ํ™˜ํ•˜๊ฒŒ ๋œ ๊ณผ์ •์„ ์†Œ๊ฐœํ•œ๋‹ค. Zod๋ฅผ ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์ „ํ™˜ํ•˜๋ ค๋Š” ์ด์œ  Zod์—์„œ ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ์˜ ์ „ํ™˜์„ ํ†ตํ•ด ๋‹ฌ์„ฑํ•˜๋ ค๋˜ ๋ชฉํ‘œ๋Š” "๋ฒˆ๋“ค ์‚ฌ์ด์ฆˆ" ์ ˆ๊ฐ์ด์–ด์žˆ๋‹ค. CHINGOO.BE๋Š” Next.js ๊ธฐ๋ฐ˜์˜ ํ”„๋กœ์ ํŠธ๋ผ์„œ next-bundle-analyzer๋ฅผ ๋Œ๋ ค๋ณด์•˜์—ˆ๋‹ค. ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋ˆˆ์— ๋„๋Š” ํผ์งํผ์งํ•œ ํŒจํ‚ค์ง€๋“ค์ด ๋ณด์ธ๋‹ค. react-dom์—๋‚˜ next๊ด€๋ จ ํŒจํ‚ค์ง€๋Š” ๋Œ€์ฒด ๊ฐ€๋Šฅํ•œ ํŒจํ‚ค์ง€๊ฐ€ ์—†์œผ๋‹ˆ ๊ฑด๋„ˆ๋›ฐ๊ณ , ๊ทธ ๋‹ค์Œ์œผ๋กœ ๊ฐ€์žฅ ๋ˆˆ์— ๋„๋Š” ํŒจํ‚ค์ง€๋Š” ์œ„ ์ด๋ฏธ์ง€์—์„œ ๋นจ๊ฐ„ ๋ฐ•์Šค๊ฐ€ ์ณ์ง„ Z..

๋‹ด๋‹น ์—ญํ•  ๋ฐ ๊ธฐ์ˆ  ์Šคํƒ

๋ณ„๋„์˜ Backend ์„œ๋น„์Šค ์—†์ด, Next.js๋ฅผ ํ†ตํ•ด Frontend์™€ Backend๋ฅผ ํ•จ๊ป˜ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
์œ ํ˜•
์ ์šฉ ๊ธฐ์ˆ 
Node
v20.9.0
Package Manager
PNPM 8.14.0
Framework
Next.js 14.1.0 (App router)
Styling
Tailwind CSS
DB
MySQL(PlanetScale)
ORM
Prisma
Infra
Vercel SaaS
Validation
Superstruct
Form
react-hook-form
Monitoring & Analyzer
Google Analytics, Sentry, next-bundle-analyzer
Etc
Storybook, SVGR, Prettier, ESLint

ย ์ฃผ์š” ๊ฐœ๋ฐœ์‚ฌํ•ญ

โ€ข
๋ฉ”์ธํŽ˜์ด์ง€
โ—ฆ
์นœ๊ตฌ๋น„ ์˜์ˆ˜์ฆ ์ƒ์„ฑํŽ˜์ด์ง€๋กœ ์—ฐ๊ฒฐ๋˜๋Š” CTA ๋ฒ„ํŠผ๊ณผ ํ† ์Šค ์•„์ด๋””๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•œ ๋ฒ„ํŠผ์„ ์ œ๊ณตํ•จ
โ—ฆ
ํ‘ธํ„ฐ์—” CHINGOO.BE๋ฅผ ํ†ตํ•œ ํ”„๋กœ์ ํŠธ ํ›„์› ๋งํฌ ๋ฒ„ํŠผ, ๋ฒ„๊ทธ/๋ถˆํŽธ์‚ฌํ•ญ ์ œ๋ณด ๋ฒ„ํŠผ, GitHub ๋ ˆํฌ์ง€ํ† ๋ฆฌ ๋ฒ„ํŠผ์„ ์ œ๊ณตํ•จ.
โ€ข
์นœ๊ตฌ๋น„ ์˜์ˆ˜์ฆ ์ƒ์„ฑ ํŽ˜์ด์ง€
โ—ฆ
React-Hook-Form๊ณผ Superstruct๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์นœ๊ตฌ๋น„ ์˜์ˆ˜์ฆ์— ํ•„์š”ํ•œ Form data๋ฅผ ๊ด€๋ฆฌํ•จ.
โ–ช
Input ํ•„๋“œ ์ž…๋ ฅ์— ๋”ฐ๋ฅธ ๋ฆฌ๋ Œ๋”๋ง์„ ์ตœ์†Œ ์˜์—ญ์œผ๋กœ ์ค„์ด๊ธฐ ์œ„ํ•ด ๋„๋ฉ”์ธ์— ๋”ฐ๋ผ Component๋ฅผ ์ž˜๊ฒŒ ์ชผ๊ฒŒ ๊ด€๋ฆฌํ•จ.
โ—ฆ
โ€œ๋งํฌ ๋ณต์‚ฌโ€ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๊ฐ’์œผ๋กœ Next.js App router route handler์— POST ์š”์ฒญ์„ ๋ณด๋‚ด๊ฒŒ ๋จ.
โ–ช
route handler์—์„  Prisma๋ฅผ ํ†ตํ•ด PlanetScale MySQL์„ ์ง์ ‘ ์ ‘๊ทผํ•ด, ์˜์ˆ˜์ฆ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๊ณ  client์— UUID๋ฅผ ๋‚ด๋ ค์คŒ.
โ–ช
client๋Š” ์‘๋‹ต์„ ํ†ตํ•ด ๋‹ต์€ UUID๋ฅผ ๊ฐ€์ง€๊ณ  ์นœ๊ตฌ๋น„ ์˜์ˆ˜์ฆ ๋งํฌ๋ฅผ ํด๋ฆฝ๋ณด๋“œ์— ๋ณต์‚ฌํ•จ.
โ€ข
์นœ๊ตฌ๋น„ ์˜์ˆ˜์ฆ ์—ด๋žŒ ํŽ˜์ด์ง€
โ—ฆ
https://chingoo.be/receipt/{UUID} ํ˜•์‹์˜ URL๋กœ ์ ‘๊ทผํ•  ๊ฒฝ์šฐ, Prisma๋ฅผ ํ†ตํ•ด PlanetScale MySQL์— UUID๋กœ select ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•จ.
โ–ช
row๊ฐ€ ์กด์žฌํ•  ๊ฒฝ์šฐ, ํ•ด๋‹น row์˜ ๊ฐ’์„ ์ด์šฉํ•˜์—ฌ ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•˜๊ณ  ์ด๋ฅผ client์— ์ „๋‹ฌํ•จ.
โ—ฆ
์นœ๊ตฌ๋น„ ๋ณด๋‚ด๊ธฐ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด, ์˜์ˆ˜์ฆ ๋‚ด ํ•ฉ๊ณ„ ๊ธˆ์•ก์— ๋งž์ถฐ ์˜์ˆ˜์ฆ ์ฃผ์ธ์˜ ํ† ์Šค ์ต๋ช…์†ก๊ธˆ ๋งํฌ๋กœ ์—ฐ๊ฒฐํ•จ.