๐จ ์ผ๋ฌ์คํธ ์ํ ํ๋งค์ต - ๋์งํธ ์ํธ ๋ง์ผํ๋ ์ด์ค
illustration-art-shop-platform
๋ฌธ์ ์ค๋ช
๐จ ์ผ๋ฌ์คํธ ์ํ ํ๋งค์ต
์ผ๋ฌ์คํธ๋ ์ดํฐ๊ฐ ์์ ์ ์ํ์ ํ๋งคํ ์ ์๋ ๊ฐ๋จํ ์จ๋ผ์ธ ์ต์ ๋ง๋ญ๋๋ค. ์ํ ๊ฐค๋ฌ๋ฆฌ, ์์ธ ํ์ด์ง, ์ฅ๋ฐ๊ตฌ๋ ๊ธฐ๋ฅ์ ํฌํจํ๋ฉฐ, Laravel API์ React ํ๋ก ํธ์๋๋ฅผ ์ฐ๋ํ๋ ํ์คํ ํ๋ก์ ํธ์ ๋๋ค.
๐ฏ ํ์ ๊ธฐ๋ฅ
- ์ํ ๊ฐค๋ฌ๋ฆฌ: ๊ทธ๋ฆฌ๋ ๋ ์ด์์์ผ๋ก ์ํ ๋ชฉ๋ก ํ์ (์ธ๋ค์ผ, ์ ๋ชฉ, ๊ฐ๊ฒฉ)
- ์ํ ์์ธ ํ์ด์ง: ํฐ ์ด๋ฏธ์ง, ์ํ ์ค๋ช , ์ฌ์ด์ฆ/ํด์๋ ์ ๋ณด, ๊ตฌ๋งค ๋ฒํผ
- ์ฅ๋ฐ๊ตฌ๋: ์ํ ์ถ๊ฐ/์ญ์ , ์ด ๊ธ์ก ๊ณ์ฐ
- ๋ฐ์ํ ๋์์ธ: ๋ชจ๋ฐ์ผ/ํ๋ธ๋ฆฟ/๋ฐ์คํฌํฑ ๋์
- SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค: ์ํ ์ ๋ณด ์ ์ฅ (์ ๋ชฉ, ์ค๋ช , ๊ฐ๊ฒฉ, ์ด๋ฏธ์ง URL)
๐ ์ ํ ์ถ๊ฐ ๊ธฐ๋ฅ (๋ณด๋์ค)
- ์ํ ํํฐ๋ง (๊ฐ๊ฒฉ๋๋ณ, ์นดํ ๊ณ ๋ฆฌ๋ณ)
- ์ํ ์ข์์/์ฐํ๊ธฐ ๊ธฐ๋ฅ
- ์๊ฐ ํ๋กํ ํ์ด์ง
- ์ด๋ฏธ์ง ํ๋/์ถ์ ๋ชจ๋ฌ
- ๋คํฌ๋ชจ๋ ์ง์
๐ก ํ์ต ํฌ์ธํธ
- Laravel 13.x RESTful API ์ค๊ณ (CRUD)
- React 19 ์ปดํฌ๋ํธ ๊ตฌ์กฐ ์ค๊ณ
- fetch/axios๋ฅผ ์ฌ์ฉํ API ํธ์ถ
- useState๋ฅผ ํ์ฉํ ์ํ ๊ด๋ฆฌ
- Tailwind CSS ๊ทธ๋ฆฌ๋ ๋ ์ด์์
- ์ฅ๋ฐ๊ตฌ๋ ๋ก์ง ๊ตฌํ (localStorage ํ์ฉ)
์ ์ฝ ์กฐ๊ฑด
- โข Laravel 13.x + React 19 (Vite) ํ์คํ ๊ตฌ์ฑ
- โข SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฌ์ฉ
- โข Tailwind CSS ์คํ์ผ๋ง
- โข fetch ๋๋ axios๋ก API ํธ์ถ
- โข ๋ณต์กํ ์ํ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ธ์ง (useState๋ง ์ฌ์ฉ)
- โข ์ค์ ๊ฒฐ์ ์ฐ๋ ๋ถํ์ (UI๋ง ๊ตฌํ)
- โข ์ด๋ฏธ์ง๋ ์ธ๋ถ URL ๋๋ public ํด๋์ ์ ์ฅ
ํ๋กฌํํธ ๋ ์ํผ
์๋ ํ๋กฌํํธ๋ฅผ ์์๋๋ก AI์๊ฒ ๋ณด๋ด๋ฉด ๋ฉ๋๋ค. ๋ณต์ฌ ๋ฒํผ์ ๋๋ฌ ๋ฐ๋ก ์ฌ์ฉํ์ธ์.
mkdir illustration-art-shop-platform && cd illustration-art-shop-platform
์ด ํด๋์์ ํ๋ก์ ํธ๋ฅผ ์์ํฉ๋๋ค.
Laravel 13.x ๋ฐฑ์๋ API ํ๋ก์ ํธ๋ฅผ ์์ฑํด์ฃผ์ธ์.
์๊ตฌ์ฌํญ:
- Laravel 13.x ์ต์ ๋ฒ์ ์ค์น
- SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค์ (.env ํ์ผ์์ DB_CONNECTION=sqlite ์ค์ )
- CORS ๋ฏธ๋ค์จ์ด ์ค์ (React ํ๋ก ํธ์๋์ ํต์ ๊ฐ๋ฅํ๋๋ก)
- artworks ํ
์ด๋ธ ๋ง์ด๊ทธ๋ ์ด์
์์ฑ:
- id (primary key)
- title (string, ์ํ ์ ๋ชฉ)
- description (text, ์ํ ์ค๋ช
)
- price (decimal, ๊ฐ๊ฒฉ)
- image_url (string, ์ด๋ฏธ์ง URL)
- category (string, ์นดํ
๊ณ ๋ฆฌ - ์: ์ผ๋ฌ์คํธ, ๋์งํธํ์ธํ
, ์บ๋ฆญํฐ๋์์ธ)
- size (string, ์ฌ์ด์ฆ ์ ๋ณด - ์: 3000x4000px)
- created_at, updated_at
- Artwork ๋ชจ๋ธ ์์ฑ (fillable ์์ฑ ์ค์ )
- ์๋ ํ์ผ ์์ฑํ์ฌ ์ํ ์ํ 5๊ฐ ์ถ๊ฐ (์ด๋ฏธ์ง๋ Lorem Picsum ๋๋ Unsplash API ์ฌ์ฉ)
- API ๋ผ์ฐํธ ์ค์ (routes/api.php):
- GET /api/artworks - ์ ์ฒด ์ํ ๋ชฉ๋ก
- GET /api/artworks/{id} - ์ํ ์์ธ ์ ๋ณด
- ArtworkController ์์ฑํ์ฌ index(), show() ๋ฉ์๋ ๊ตฌํ
- JSON ์๋ต ํ์์ผ๋ก ๋ฐ์ดํฐ ๋ฐํ
์คํ ๋ช
๋ น:
- php artisan migrate
- php artisan db:seed
- php artisan serve (ํฌํธ 8000์์ ์คํ)
๊ธฐ๋ ๊ฒฐ๊ณผ: Laravel ๋ฐฑ์๋ API๊ฐ ์ค๋น๋๊ณ , http://localhost:8000/api/artworks ์๋ํฌ์ธํธ์์ ์ํ ๋ชฉ๋ก JSON์ ํ์ธํ ์ ์์ต๋๋ค. SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ํ ์ํ 5๊ฐ๊ฐ ์ ์ฅ๋์ด ์์ต๋๋ค.
๊ฐ์ ํด๋(illustration-art-shop-platform) ๋ด์ React 19 ํ๋ก ํธ์๋ ํ๋ก์ ํธ๋ฅผ ์์ฑํด์ฃผ์ธ์. ์๊ตฌ์ฌํญ: - Vite๋ฅผ ์ฌ์ฉํ React 19 ํ๋ก์ ํธ ์์ฑ (frontend ํด๋์) - Tailwind CSS ์ค์น ๋ฐ ์ค์ - React Router ์ค์น (react-router-dom) - ๊ธฐ๋ณธ ํด๋ ๊ตฌ์กฐ: - src/components/ (์ปดํฌ๋ํธ ํด๋) - src/pages/ (ํ์ด์ง ์ปดํฌ๋ํธ) - src/services/ (API ํธ์ถ ํจ์) - API ์๋น์ค ํ์ผ ์์ฑ (src/services/api.js): - fetchArtworks() - ์ ์ฒด ์ํ ๋ชฉ๋ก ๊ฐ์ ธ์ค๊ธฐ - fetchArtworkById(id) - ์ํ ์์ธ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ - fetch API ์ฌ์ฉ, Laravel ๋ฐฑ์๋(http://localhost:8000/api) ์ฐ๊ฒฐ - ๊ธฐ๋ณธ ๋ผ์ฐํ ์ค์ : - / - ์ํ ๊ฐค๋ฌ๋ฆฌ ํ์ด์ง - /artwork/:id - ์ํ ์์ธ ํ์ด์ง - /cart - ์ฅ๋ฐ๊ตฌ๋ ํ์ด์ง - App.jsx์ ๊ธฐ๋ณธ ๋ ์ด์์ ๋ฐ ๋ค๋น๊ฒ์ด์ ๋ฐ ๊ตฌํ: - ๋ก๊ณ , ๊ฐค๋ฌ๋ฆฌ ๋งํฌ, ์ฅ๋ฐ๊ตฌ๋ ์์ด์ฝ (์ฅ๋ฐ๊ตฌ๋ ์์ดํ ๊ฐ์ ํ์) - Tailwind CSS๋ก ์คํ์ผ๋ง (๋ฐ์ํ ๋์์ธ) ์คํ ๋ช ๋ น: - npm run dev (ํฌํธ 5173์์ ์คํ)
๊ธฐ๋ ๊ฒฐ๊ณผ: React ํ๋ก ํธ์๋๊ฐ http://localhost:5173์์ ์คํ๋๋ฉฐ, ๋ค๋น๊ฒ์ด์ ๋ฐ๊ฐ ํ์๋ฉ๋๋ค. API ์๋น์ค ํ์ผ์ด ์ค๋น๋์ด ์๊ณ , ๋ผ์ฐํ ๊ตฌ์กฐ๊ฐ ์ค์ ๋์ด ์์ต๋๋ค.
์ํ ๊ฐค๋ฌ๋ฆฌ ํ์ด์ง(src/pages/Gallery.jsx)๋ฅผ ๊ตฌํํด์ฃผ์ธ์.
์๊ตฌ์ฌํญ:
- useEffect์ useState๋ฅผ ์ฌ์ฉํ์ฌ ์ปดํฌ๋ํธ ๋ง์ดํธ ์ API์์ ์ํ ๋ชฉ๋ก ๊ฐ์ ธ์ค๊ธฐ
- ๋ก๋ฉ ์ํ ํ์ (์คํผ๋ ๋๋ "Loading..." ํ
์คํธ)
- ์ํ ๋ชฉ๋ก์ ๊ทธ๋ฆฌ๋ ๋ ์ด์์์ผ๋ก ํ์:
- ๋ฐ์ํ ๊ทธ๋ฆฌ๋ (๋ชจ๋ฐ์ผ 1์ด, ํ๋ธ๋ฆฟ 2์ด, ๋ฐ์คํฌํฑ 3์ด)
- ๊ฐ ์ํ ์นด๋:
- ์ธ๋ค์ผ ์ด๋ฏธ์ง (object-cover๋ก ๋น์จ ์ ์ง)
- ์ํ ์ ๋ชฉ
- ๊ฐ๊ฒฉ (์ํ ํ์, ์ฒ ๋จ์ ์ฝค๋ง)
- ์นดํ
๊ณ ๋ฆฌ ๋ฐฐ์ง
- ํธ๋ฒ ์ ํ๋ ํจ๊ณผ (transform scale)
- ์นด๋ ํด๋ฆญ ์ ์์ธ ํ์ด์ง๋ก ์ด๋ (React Router Link ์ฌ์ฉ)
- ์๋ฌ ์ฒ๋ฆฌ (API ํธ์ถ ์คํจ ์ ์๋ฌ ๋ฉ์์ง ํ์)
- Tailwind CSS๋ก ์ธ๋ จ๋ ๋์์ธ:
- ์นด๋ ๊ทธ๋ฆผ์ ํจ๊ณผ
- ๋ถ๋๋ฌ์ด ์ ๋๋ฉ์ด์
(transition)
- ์นดํ
๊ณ ๋ฆฌ ๋ฐฐ์ง ์์ ๊ตฌ๋ถ
์คํ์ผ ๊ฐ์ด๋:
- ๋ฉ์ธ ์ปฌ๋ฌ: ํ์คํ
ํค (์: ์ฐ๋ณด๋ผ, ์ฐํํฌ)
- ํฐํธ: ๊น๋ํ sans-serif
- ์ฌ๋ฐฑ: ๋๋ํ padding/margin
๊ธฐ๋ ๊ฒฐ๊ณผ: ๊ฐค๋ฌ๋ฆฌ ํ์ด์ง์์ ์ํ ๋ชฉ๋ก์ด ๊ทธ๋ฆฌ๋ ํํ๋ก ํ์๋ฉ๋๋ค. ๊ฐ ์ํ ์นด๋๋ ์ด๋ฏธ์ง, ์ ๋ชฉ, ๊ฐ๊ฒฉ, ์นดํ ๊ณ ๋ฆฌ๋ฅผ ๋ณด์ฌ์ฃผ๋ฉฐ, ํด๋ฆญ ์ ์์ธ ํ์ด์ง๋ก ์ด๋ํฉ๋๋ค. ๋ฐ์ํ ๋์์ธ์ด ์ ์ฉ๋์ด ๋ชจ๋ฐ์ผ์์๋ ์ ๋ณด์ ๋๋ค.
์ํ ์์ธ ํ์ด์ง(src/pages/ArtworkDetail.jsx)์ ์ฅ๋ฐ๊ตฌ๋ ๊ธฐ๋ฅ์ ๊ตฌํํด์ฃผ์ธ์.
์๊ตฌ์ฌํญ:
### ์ํ ์์ธ ํ์ด์ง
- useParams๋ก URL์์ ์ํ ID ๊ฐ์ ธ์ค๊ธฐ
- useEffect๋ก ํด๋น ์ํ ์ ๋ณด API ํธ์ถ
- ๋ ์ด์์:
- ์ผ์ชฝ: ํฐ ์ํ ์ด๋ฏธ์ง (ํด๋ฆญ ์ ๋ชจ๋ฌ๋ก ํ๋ - ์ ํ์ฌํญ)
- ์ค๋ฅธ์ชฝ: ์ํ ์ ๋ณด
- ์ ๋ชฉ (ํฐ ํฐํธ)
- ์นดํ
๊ณ ๋ฆฌ ๋ฐฐ์ง
- ๊ฐ๊ฒฉ (๊ฐ์กฐ ์คํ์ผ)
- ์ฌ์ด์ฆ ์ ๋ณด
- ์ํ ์ค๋ช
(์ฌ๋ฌ ์ค)
- "์ฅ๋ฐ๊ตฌ๋์ ์ถ๊ฐ" ๋ฒํผ (๋์ ๋๋ ์์)
- "๊ฐค๋ฌ๋ฆฌ๋ก ๋์๊ฐ๊ธฐ" ๋งํฌ
- ์ฅ๋ฐ๊ตฌ๋ ์ถ๊ฐ ๋ฒํผ ํด๋ฆญ ์:
- localStorage์ ์ฅ๋ฐ๊ตฌ๋ ์์ดํ
์ ์ฅ (๋ฐฐ์ด ํํ)
- ์๋ฆผ ๋ฉ์์ง ํ์ ("์ฅ๋ฐ๊ตฌ๋์ ์ถ๊ฐ๋์์ต๋๋ค!")
- ๋ค๋น๊ฒ์ด์
๋ฐ์ ์ฅ๋ฐ๊ตฌ๋ ์์ด์ฝ ๊ฐ์ ์
๋ฐ์ดํธ
### ์ฅ๋ฐ๊ตฌ๋ Context ๋๋ ์ํ ๊ด๋ฆฌ
- App.jsx ๋๋ ๋ณ๋ Context ํ์ผ์ ์ฅ๋ฐ๊ตฌ๋ ์ํ ๊ด๋ฆฌ:
- cartItems (๋ฐฐ์ด)
- addToCart(item) ํจ์
- removeFromCart(id) ํจ์
- getCartCount() ํจ์
- getTotalPrice() ํจ์
- localStorage์ ๋๊ธฐํ (์๋ก๊ณ ์นจ ์์๋ ์ฅ๋ฐ๊ตฌ๋ ์ ์ง)
์คํ์ผ:
- ํฐ ์ด๋ฏธ์ง๋ ์ต๋ ๋๋น ์ ํ
- ๋ฒํผ์ ํธ๋ฒ ์ ์์ ๋ณ๊ฒฝ
- ๋ฐ์ํ: ๋ชจ๋ฐ์ผ์์๋ ์ธ๋ก ๋ ์ด์์
๊ธฐ๋ ๊ฒฐ๊ณผ: ์ํ ์์ธ ํ์ด์ง์์ ํฐ ์ด๋ฏธ์ง์ ์์ธ ์ ๋ณด๋ฅผ ๋ณผ ์ ์์ต๋๋ค. "์ฅ๋ฐ๊ตฌ๋์ ์ถ๊ฐ" ๋ฒํผ ํด๋ฆญ ์ localStorage์ ์ ์ฅ๋๊ณ , ๋ค๋น๊ฒ์ด์ ๋ฐ์ ์ฅ๋ฐ๊ตฌ๋ ์์ด์ฝ ๊ฐ์๊ฐ ์ ๋ฐ์ดํธ๋ฉ๋๋ค. ํ์ด์ง๋ฅผ ์๋ก๊ณ ์นจํด๋ ์ฅ๋ฐ๊ตฌ๋ ๋ด์ฉ์ด ์ ์ง๋ฉ๋๋ค.
์ฅ๋ฐ๊ตฌ๋ ํ์ด์ง(src/pages/Cart.jsx)๋ฅผ ๊ตฌํํ๊ณ ์ต์ข
๋ง๋ฌด๋ฆฌ๋ฅผ ํด์ฃผ์ธ์.
์๊ตฌ์ฌํญ:
### ์ฅ๋ฐ๊ตฌ๋ ํ์ด์ง
- localStorage์์ ์ฅ๋ฐ๊ตฌ๋ ์์ดํ
๋ถ๋ฌ์ค๊ธฐ
- ์ฅ๋ฐ๊ตฌ๋๊ฐ ๋น์ด์์ ๋:
- "์ฅ๋ฐ๊ตฌ๋๊ฐ ๋น์ด์์ต๋๋ค" ๋ฉ์์ง
- "๊ฐค๋ฌ๋ฆฌ ๋๋ฌ๋ณด๊ธฐ" ๋งํฌ
- ์ฅ๋ฐ๊ตฌ๋ ์์ดํ
๋ชฉ๋ก:
- ๊ฐ ์์ดํ
:
- ์ธ๋ค์ผ ์ด๋ฏธ์ง (์์ ํฌ๊ธฐ)
- ์ํ ์ ๋ชฉ
- ๊ฐ๊ฒฉ
- ์ญ์ ๋ฒํผ (X ์์ด์ฝ)
- ํ
์ด๋ธ ๋๋ ์นด๋ ํํ๋ก ํ์
- ํ๋จ์ ์ด ๊ธ์ก ํ์:
- ์๊ณ (์ํ ๊ฐ๊ฒฉ ํฉ๊ณ)
- ๋ฐฐ์ก๋น (์: ๋ฌด๋ฃ ๋๋ 3,000์)
- ์ด ๊ฒฐ์ ๊ธ์ก (๊ฐ์กฐ ์คํ์ผ)
- "์ฃผ๋ฌธํ๊ธฐ" ๋ฒํผ (ํด๋ฆญ ์ alert๋ก "์ฃผ๋ฌธ์ด ์๋ฃ๋์์ต๋๋ค!" ๋ฉ์์ง - ์ค์ ๊ฒฐ์ ์ฐ๋์ ํ์ง ์์)
- ์ฃผ๋ฌธ ์๋ฃ ํ ์ฅ๋ฐ๊ตฌ๋ ๋น์ฐ๊ธฐ
### ์ต์ข
๋ง๋ฌด๋ฆฌ
- ๋ชจ๋ ํ์ด์ง์์ ๋ฐ์ํ ๋์์ธ ํ์ธ
- ๋ก๋ฉ ์ํ์ ์๋ฌ ์ฒ๋ฆฌ ๊ฐ์
- ์ฝ๋ ์ ๋ฆฌ ๋ฐ ์ฃผ์ ์ถ๊ฐ
- README.md ์์ฑ:
- ํ๋ก์ ํธ ์๊ฐ
- ์คํ ๋ฐฉ๋ฒ (Laravel ๋ฐฑ์๋, React ํ๋ก ํธ์๋ ๊ฐ๊ฐ)
- ๊ธฐ๋ฅ ๋ชฉ๋ก
- ์คํฌ๋ฆฐ์ท (์ ํ์ฌํญ)
์คํ์ผ:
- ์ฅ๋ฐ๊ตฌ๋ ์์ดํ
์ฌ์ด ๊ตฌ๋ถ์
- ์ญ์ ๋ฒํผ ํธ๋ฒ ์ ๋นจ๊ฐ์
- ์ด ๊ธ์ก์ ํฐ ํฐํธ๋ก ๊ฐ์กฐ
- "์ฃผ๋ฌธํ๊ธฐ" ๋ฒํผ์ ๋์ ๋๋ ์์ (์: ์ด๋ก์)
๊ธฐ๋ ๊ฒฐ๊ณผ: ์ฅ๋ฐ๊ตฌ๋ ํ์ด์ง์์ ์ถ๊ฐํ ์ํ ๋ชฉ๋ก์ ํ์ธํ ์ ์์ต๋๋ค. ๊ฐ ์์ดํ ์ ์ญ์ ํ ์ ์๊ณ , ์ด ๊ธ์ก์ด ์๋์ผ๋ก ๊ณ์ฐ๋ฉ๋๋ค. "์ฃผ๋ฌธํ๊ธฐ" ๋ฒํผ ํด๋ฆญ ์ ์ฃผ๋ฌธ ์๋ฃ ๋ฉ์์ง๊ฐ ํ์๋๊ณ ์ฅ๋ฐ๊ตฌ๋๊ฐ ๋น์์ง๋๋ค. ์ ์ฒด ํ๋ก์ ํธ๊ฐ ๊น๋ํ๊ฒ ์๋ํ๋ฉฐ, README ํ์ผ์ด ์์ฑ๋์ด ์์ต๋๋ค.
์ ์ถ๋ ์ํ (0)
๋ก๊ทธ์ธ ํ ์ ์ถ์์ง ์ ์ถ๋ ์ํ์ด ์์ต๋๋ค. ์ฒซ ๋ฒ์งธ ๋์ ์๊ฐ ๋์ด๋ณด์ธ์!