๐ŸŽจ ์˜จ๋ผ์ธ ๊ฐค๋Ÿฌ๋ฆฌ ์ „์‹œ & ์ž‘ํ’ˆ ํŒ๋งค ํ”Œ๋žซํผ - ๋ฐ”์ด๋ธŒ์ฝ”๋”ฉ ๋ ˆ์‹œํ”ผ
์ค‘๊ธ‰ PHP + JavaScript Laravel + React + Inertia.js AI: Claude

๐ŸŽจ ์˜จ๋ผ์ธ ๊ฐค๋Ÿฌ๋ฆฌ ์ „์‹œ & ์ž‘ํ’ˆ ํŒ๋งค ํ”Œ๋žซํผ

๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ช… online-art-exhibition-platform
์กฐํšŒ์ˆ˜ 49 0๊ฑด ์ œ์ถœ

๋ฌธ์ œ ์„ค๋ช…

๐ŸŽจ ์˜จ๋ผ์ธ ๊ฐค๋Ÿฌ๋ฆฌ ์ „์‹œ & ์ž‘ํ’ˆ ํŒ๋งค ํ”Œ๋žซํผ

์•„ํ‹ฐ์ŠคํŠธ๊ฐ€ ์ž์‹ ์˜ ์ž‘ํ’ˆ์„ ์ „์‹œํ•˜๊ณ  ํŒ๋งคํ•  ์ˆ˜ ์žˆ๋Š” ์˜จ๋ผ์ธ ๊ฐค๋Ÿฌ๋ฆฌ ํ”Œ๋žซํผ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค. Laravel 13.x + Inertia.js + React 19 ๋ชจ๋…ธ๋ฆฌ์Šค ํ’€์Šคํƒ ๊ตฌ์กฐ๋กœ, ์ž‘ํ’ˆ ๊ฐค๋Ÿฌ๋ฆฌ, ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ํ•„ํ„ฐ๋ง, ์ž‘ํ’ˆ ์ƒ์„ธ ํŽ˜์ด์ง€, ๊ตฌ๋งค ๋ฌธ์˜ ํผ์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

ํ•„์ˆ˜ ๊ธฐ๋Šฅ

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

์„ ํƒ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ (๋ณด๋„ˆ์Šค)

  • ์ด๋ฏธ์ง€ ํ™•๋Œ€ ๋ชจ๋‹ฌ: ์ž‘ํ’ˆ ์ด๋ฏธ์ง€ ํด๋ฆญ ์‹œ ๋ผ์ดํŠธ๋ฐ•์Šค ํšจ๊ณผ
  • ์ž‘ํ’ˆ ์ •๋ ฌ: ์ตœ์‹ ์ˆœ/๊ฐ€๊ฒฉ์ˆœ/์ธ๊ธฐ์ˆœ ์ •๋ ฌ ์˜ต์…˜
  • ์ž‘๊ฐ€ ํ”„๋กœํ•„ ํŽ˜์ด์ง€: ์ž‘๊ฐ€๋ณ„ ์ž‘ํ’ˆ ๋ชจ์Œ & ์†Œ๊ฐœ
  • ํŽ˜์ด์ง€๋„ค์ด์…˜: ์ž‘ํ’ˆ ๋ชฉ๋ก ํŽ˜์ด์ง€๋„ค์ด์…˜ ๋˜๋Š” ๋ฌดํ•œ ์Šคํฌ๋กค
  • ์ด๋ฉ”์ผ ์•Œ๋ฆผ: ๊ตฌ๋งค ๋ฌธ์˜ ์‹œ ์ž‘๊ฐ€์—๊ฒŒ ์ž๋™ ์ด๋ฉ”์ผ ๋ฐœ์†ก
  • ์ž‘ํ’ˆ ๊ณต์œ  ๊ธฐ๋Šฅ: SNS ๊ณต์œ  ๋ฒ„ํŠผ (์นด์นด์˜คํ†ก, ํŽ˜์ด์Šค๋ถ, ํŠธ์œ„ํ„ฐ)

๊ธฐ์ˆ  ์Šคํƒ

  • ๋ฐฑ์—”๋“œ: Laravel 13.x (Eloquent ORM, SQLite)
  • ํ”„๋ก ํŠธ์—”๋“œ: React 19 + Inertia.js
  • ์Šคํƒ€์ผ๋ง: Tailwind CSS
  • ์•„์ด์ฝ˜: Heroicons ๋˜๋Š” React Icons
  • ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ: Laravel Storage (public disk)

์‹ค์ œ ๊ฐค๋Ÿฌ๋ฆฌ ์šด์˜์ž๋‚˜ ์•„ํ‹ฐ์ŠคํŠธ๊ฐ€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ˆ˜์ค€์˜ ํ”Œ๋žซํผ์„ ๋ชฉํ‘œ๋กœ ํ•˜๋ฉฐ, ์ž‘ํ’ˆ ์ด๋ฏธ์ง€๊ฐ€ ๋‹๋ณด์ด๋Š” ์„ธ๋ จ๋œ UI/UX๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

์ œ์•ฝ ์กฐ๊ฑด

  • โ€ข Laravel 13.x + Inertia.js + React 19 ๋ชจ๋…ธ๋ฆฌ์Šค ํ’€์Šคํƒ ๊ตฌ์กฐ
  • โ€ข ๋ณ„๋„ API ๋ผ์šฐํŠธ ์—†์ด Inertia::render()๋กœ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ
  • โ€ข SQLite ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‚ฌ์šฉ (๊ฐ„๋‹จํ•œ ์„ค์ •)
  • โ€ข Tailwind CSS๋กœ ์Šคํƒ€์ผ๋ง
  • โ€ข ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ๋Š” Laravel Storage ํ™œ์šฉ (public disk)
  • โ€ข ์‹ค์‹œ๊ฐ„ ์ฑ„ํŒ… ๊ธˆ์ง€ (๊ตฌ๋งค ๋ฌธ์˜๋Š” ํผ ์ œ์ถœ ๋ฐฉ์‹)
  • โ€ข ๊ด€๋ฆฌ์ž ๋Œ€์‹œ๋ณด๋“œ ์—†์ด ์‚ฌ์šฉ์ž ์ค‘์‹ฌ ๊ฐค๋Ÿฌ๋ฆฌ ๋ทฐ ๊ตฌํ˜„
  • โ€ข ๋ฐ˜์‘ํ˜• ๋””์ž์ธ ํ•„์ˆ˜ (๋ชจ๋ฐ”์ผ ์šฐ์„ )

ํ”„๋กฌํ”„ํŠธ ๋ ˆ์‹œํ”ผ

์•„๋ž˜ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ˆœ์„œ๋Œ€๋กœ AI์—๊ฒŒ ๋ณด๋‚ด๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋ณต์‚ฌ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ๋ฐ”๋กœ ์‚ฌ์šฉํ•˜์„ธ์š”.

1
Step 1
mkdir online-art-exhibition-platform && cd online-art-exhibition-platform

์ด ํด๋”์—์„œ Laravel 13.x + Inertia.js + React 19 ํ”„๋กœ์ ํŠธ๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

`npx create laravel` ๋ช…๋ น์œผ๋กœ Laravel 13.x ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , Laravel Breeze์˜ React + Inertia.js starter kit์„ ์„ค์น˜ํ•ด์ฃผ์„ธ์š”.

์„ค์น˜ ํ›„ ๋‹ค์Œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ด์ฃผ์„ธ์š”:
1. SQLite ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ค์ • (.env ํŒŒ์ผ์—์„œ DB_CONNECTION=sqlite ์„ค์ •, database/database.sqlite ํŒŒ์ผ ์ƒ์„ฑ)
2. Tailwind CSS ์„ค์ • ํ™•์ธ (Breeze๊ฐ€ ์ž๋™์œผ๋กœ ์„ค์ •)
3. `php artisan migrate` ์‹คํ–‰ํ•˜์—ฌ ๊ธฐ๋ณธ ํ…Œ์ด๋ธ” ์ƒ์„ฑ
4. `npm install && npm run dev` ์‹คํ–‰ํ•˜์—ฌ ํ”„๋ก ํŠธ์—”๋“œ ๋นŒ๋“œ ์‹œ์ž‘
5. `php artisan serve` ์‹คํ–‰ํ•˜์—ฌ ๊ฐœ๋ฐœ ์„œ๋ฒ„ ์‹œ์ž‘

ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”.

๊ธฐ๋Œ€ ๊ฒฐ๊ณผ: Laravel 13.x + Inertia.js + React 19 ํ”„๋กœ์ ํŠธ๊ฐ€ ์ƒ์„ฑ๋˜๊ณ , SQLite ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ์„ค์ •๋˜๋ฉฐ, ๊ฐœ๋ฐœ ์„œ๋ฒ„๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. http://localhost:8000์— ์ ‘์†ํ•˜๋ฉด Laravel Breeze ๊ธฐ๋ณธ ํ™”๋ฉด์ด ๋ณด์ž…๋‹ˆ๋‹ค.

2
Step 2
์ž‘ํ’ˆ(Artwork) ๋ชจ๋ธ๊ณผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์„ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”.

`php artisan make:model Artwork -m` ๋ช…๋ น์œผ๋กœ ๋ชจ๋ธ๊ณผ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ , ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํŒŒ์ผ์— ๋‹ค์Œ ์ปฌ๋Ÿผ์„ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”:

- id (์ž๋™ ์ƒ์„ฑ)
- title (string, ์ž‘ํ’ˆ ์ œ๋ชฉ)
- artist_name (string, ์ž‘๊ฐ€๋ช…)
- category (string, ์นดํ…Œ๊ณ ๋ฆฌ: painting/sculpture/photography/digital)
- description (text, ์ž‘ํ’ˆ ์„ค๋ช…)
- size (string, ์ž‘ํ’ˆ ํฌ๊ธฐ, ์˜ˆ: 50x70cm)
- material (string, ์žฌ๋ฃŒ, ์˜ˆ: Oil on canvas)
- price (decimal, ๊ฐ€๊ฒฉ)
- image_path (string, ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ)
- is_sold (boolean, ํŒ๋งค ์—ฌ๋ถ€, ๊ธฐ๋ณธ๊ฐ’ false)
- created_at, updated_at (ํƒ€์ž„์Šคํƒฌํ”„)

๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์‹คํ–‰: `php artisan migrate`

๊ทธ๋ฆฌ๊ณ  Artwork ๋ชจ๋ธ์— $fillable ์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๋Œ€๋Ÿ‰ ํ• ๋‹น ๊ฐ€๋Šฅํ•˜๋„๋ก ์„ค์ •ํ•ด์ฃผ์„ธ์š”.

๊ธฐ๋Œ€ ๊ฒฐ๊ณผ: Artwork ๋ชจ๋ธ๊ณผ artworks ํ…Œ์ด๋ธ”์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ž‘ํ’ˆ ์ •๋ณด๋ฅผ ์ €์žฅํ•  ์ค€๋น„๊ฐ€ ์™„๋ฃŒ๋ฉ๋‹ˆ๋‹ค.

3
Step 3
์‹œ๋”(Seeder)๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ƒ˜ํ”Œ ์ž‘ํ’ˆ ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.

`php artisan make:seeder ArtworkSeeder` ๋ช…๋ น์œผ๋กœ ์‹œ๋”๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์ตœ์†Œ 12๊ฐœ ์ด์ƒ์˜ ์ƒ˜ํ”Œ ์ž‘ํ’ˆ์„ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”. ์นดํ…Œ๊ณ ๋ฆฌ๋Š” painting, sculpture, photography, digital์„ ๊ณจ๊ณ ๋ฃจ ์„ž์–ด์ฃผ์„ธ์š”.

์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ ์˜ˆ์‹œ:
- ์ œ๋ชฉ: "Sunset over the Ocean"
- ์ž‘๊ฐ€๋ช…: "Jane Doe"
- ์นดํ…Œ๊ณ ๋ฆฌ: painting
- ์„ค๋ช…: "A vibrant sunset painting capturing the beauty of nature."
- ํฌ๊ธฐ: "60x80cm"
- ์žฌ๋ฃŒ: "Oil on canvas"
- ๊ฐ€๊ฒฉ: 350000 (์› ๋‹จ์œ„)
- ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ: "artworks/sample1.jpg" (์‹ค์ œ ์ด๋ฏธ์ง€๋Š” ๋‚˜์ค‘์— ์—…๋กœ๋“œ)
- ํŒ๋งค ์—ฌ๋ถ€: false

DatabaseSeeder.php์—์„œ ArtworkSeeder๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก ์„ค์ •ํ•˜๊ณ , `php artisan db:seed` ๋ช…๋ น์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฝ์ž…ํ•ด์ฃผ์„ธ์š”.

์ด๋ฏธ์ง€๋Š” public/storage/artworks ํด๋”์— ์ƒ˜ํ”Œ ์ด๋ฏธ์ง€(placeholder)๋ฅผ ๋„ฃ๊ฑฐ๋‚˜, https://picsum.photos ๊ฐ™์€ ๋ฌด๋ฃŒ ์ด๋ฏธ์ง€ ์„œ๋น„์Šค๋ฅผ ํ™œ์šฉํ•ด์ฃผ์„ธ์š”.

๊ธฐ๋Œ€ ๊ฒฐ๊ณผ: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ƒ˜ํ”Œ ์ž‘ํ’ˆ 12๊ฐœ ์ด์ƒ์ด ์‚ฝ์ž…๋˜๊ณ , ๊ฐค๋Ÿฌ๋ฆฌ์— ํ‘œ์‹œํ•  ๋ฐ์ดํ„ฐ๊ฐ€ ์ค€๋น„๋ฉ๋‹ˆ๋‹ค.

4
Step 4
์ž‘ํ’ˆ ๊ฐค๋Ÿฌ๋ฆฌ ํŽ˜์ด์ง€๋ฅผ ๊ตฌํ˜„ํ•ด์ฃผ์„ธ์š”.

1. **๋ผ์šฐํŠธ ์„ค์ •**: routes/web.php์— ๊ฐค๋Ÿฌ๋ฆฌ ๋ฉ”์ธ ํŽ˜์ด์ง€ ๋ผ์šฐํŠธ ์ถ”๊ฐ€
   - GET '/' โ†’ ArtworkController@index

2. **์ปจํŠธ๋กค๋Ÿฌ ์ƒ์„ฑ**: `php artisan make:controller ArtworkController`
   - index() ๋ฉ”์„œ๋“œ์—์„œ Artwork::all()๋กœ ๋ชจ๋“  ์ž‘ํ’ˆ์„ ๊ฐ€์ ธ์™€ Inertia::render('Gallery/Index', ['artworks' => $artworks])๋กœ ์ „๋‹ฌ

3. **React ์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑ**: resources/js/Pages/Gallery/Index.jsx
   - props๋กœ artworks ๋ฐ›๊ธฐ
   - ๊ทธ๋ฆฌ๋“œ ๋ ˆ์ด์•„์›ƒ(grid-cols-1 md:grid-cols-3 lg:grid-cols-4)์œผ๋กœ ์ž‘ํ’ˆ ์นด๋“œ ํ‘œ์‹œ
   - ๊ฐ ์นด๋“œ์— ์ด๋ฏธ์ง€, ์ œ๋ชฉ, ์ž‘๊ฐ€๋ช…, ๊ฐ€๊ฒฉ ํ‘œ์‹œ
   - Tailwind CSS๋กœ ์„ธ๋ จ๋œ ์นด๋“œ ๋””์ž์ธ (hover ํšจ๊ณผ, ๊ทธ๋ฆผ์ž ๋“ฑ)
   - ์นด๋“œ ํด๋ฆญ ์‹œ ์ž‘ํ’ˆ ์ƒ์„ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ (Inertia Link ์‚ฌ์šฉ)

4. **๋ ˆ์ด์•„์›ƒ**: AuthenticatedLayout ๋Œ€์‹  GuestLayout ๋˜๋Š” ์ปค์Šคํ…€ ๋ ˆ์ด์•„์›ƒ ์‚ฌ์šฉ (๊ฐค๋Ÿฌ๋ฆฌ๋Š” ๋ˆ„๊ตฌ๋‚˜ ๋ณผ ์ˆ˜ ์žˆ๋„๋ก)

์ด๋ฏธ์ง€ ํ‘œ์‹œ๋Š” `/storage/artworks/{image_path}` ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , `php artisan storage:link` ๋ช…๋ น์œผ๋กœ ์‹ฌ๋ณผ๋ฆญ ๋งํฌ๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”.

๊ธฐ๋Œ€ ๊ฒฐ๊ณผ: http://localhost:8000์— ์ ‘์†ํ•˜๋ฉด ์ž‘ํ’ˆ ๊ฐค๋Ÿฌ๋ฆฌ ๊ทธ๋ฆฌ๋“œ๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. 12๊ฐœ ์ด์ƒ์˜ ์ž‘ํ’ˆ ์นด๋“œ๊ฐ€ ๋ณด์ด๋ฉฐ, ๊ฐ ์นด๋“œ๋Š” ์ด๋ฏธ์ง€, ์ œ๋ชฉ, ์ž‘๊ฐ€๋ช…, ๊ฐ€๊ฒฉ์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ์นด๋“œ์— ํ˜ธ๋ฒ„ํ•˜๋ฉด ์‹œ๊ฐ์  ํšจ๊ณผ๊ฐ€ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.

5
Step 5
์นดํ…Œ๊ณ ๋ฆฌ ํ•„ํ„ฐ๋ง ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.

1. **Gallery/Index.jsx ์ˆ˜์ •**:
   - ์ƒ๋‹จ์— ์นดํ…Œ๊ณ ๋ฆฌ ๋ฒ„ํŠผ ์ถ”๊ฐ€ (All, Painting, Sculpture, Photography, Digital)
   - useState๋กœ selectedCategory ์ƒํƒœ ๊ด€๋ฆฌ
   - ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ selectedCategory ์—…๋ฐ์ดํŠธ
   - artworks๋ฅผ ํ•„ํ„ฐ๋งํ•˜์—ฌ ์„ ํƒ๋œ ์นดํ…Œ๊ณ ๋ฆฌ๋งŒ ํ‘œ์‹œ (All์ด๋ฉด ์ „์ฒด ํ‘œ์‹œ)
   - ์„ ํƒ๋œ ๋ฒ„ํŠผ์€ ๋‹ค๋ฅธ ์ƒ‰์ƒ์œผ๋กœ ๊ฐ•์กฐ (Tailwind์˜ bg-blue-500 ๋“ฑ)

2. **๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ ์ถ”๊ฐ€**:
   - ์ž…๋ ฅ ํ•„๋“œ ์ถ”๊ฐ€ (์ž‘ํ’ˆ๋ช… ๋˜๋Š” ์ž‘๊ฐ€๋ช… ๊ฒ€์ƒ‰)
   - useState๋กœ searchQuery ์ƒํƒœ ๊ด€๋ฆฌ
   - artworks๋ฅผ ํ•„ํ„ฐ๋งํ•˜์—ฌ ๊ฒ€์ƒ‰์–ด์™€ ๋งค์นญ๋˜๋Š” ์ž‘ํ’ˆ๋งŒ ํ‘œ์‹œ
   - ์นดํ…Œ๊ณ ๋ฆฌ ํ•„ํ„ฐ์™€ ๊ฒ€์ƒ‰ ํ•„ํ„ฐ๋ฅผ ๋™์‹œ์— ์ ์šฉ

3. **UI ๊ฐœ์„ **:
   - ํ•„ํ„ฐ/๊ฒ€์ƒ‰ ์„น์…˜์„ ์ƒ๋‹จ์— ๊ณ ์ •ํ•˜๊ฑฐ๋‚˜ sticky๋กœ ์„ค์ •
   - ํ•„ํ„ฐ ๊ฒฐ๊ณผ๊ฐ€ ์—†์„ ๋•Œ "No artworks found" ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ
   - ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ ์ถ”๊ฐ€ (์นด๋“œ fade-in ๋“ฑ)

Tailwind CSS์˜ transition๊ณผ transform์„ ํ™œ์šฉํ•˜์—ฌ ๋ถ€๋“œ๋Ÿฌ์šด UX๋ฅผ ๊ตฌํ˜„ํ•ด์ฃผ์„ธ์š”.

๊ธฐ๋Œ€ ๊ฒฐ๊ณผ: ๊ฐค๋Ÿฌ๋ฆฌ ์ƒ๋‹จ์— ์นดํ…Œ๊ณ ๋ฆฌ ๋ฒ„ํŠผ๊ณผ ๊ฒ€์ƒ‰์ฐฝ์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์„ ํƒํ•˜๊ฑฐ๋‚˜ ๊ฒ€์ƒ‰์–ด๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ์ž‘ํ’ˆ ๋ชฉ๋ก์ด ์‹ค์‹œ๊ฐ„์œผ๋กœ ํ•„ํ„ฐ๋ง๋ฉ๋‹ˆ๋‹ค. ์„ ํƒ๋œ ์นดํ…Œ๊ณ ๋ฆฌ ๋ฒ„ํŠผ์€ ํ•˜์ด๋ผ์ดํŠธ ๋˜๊ณ , ํ•„ํ„ฐ ๊ฒฐ๊ณผ๊ฐ€ ์—†์œผ๋ฉด ์•ˆ๋‚ด ๋ฉ”์‹œ์ง€๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

6
Step 6
์ž‘ํ’ˆ ์ƒ์„ธ ํŽ˜์ด์ง€๋ฅผ ๊ตฌํ˜„ํ•ด์ฃผ์„ธ์š”.

1. **๋ผ์šฐํŠธ ์ถ”๊ฐ€**: routes/web.php
   - GET '/artworks/{id}' โ†’ ArtworkController@show

2. **์ปจํŠธ๋กค๋Ÿฌ ๋ฉ”์„œ๋“œ**: ArtworkController@show
   - Artwork::findOrFail($id)๋กœ ์ž‘ํ’ˆ ์กฐํšŒ
   - Inertia::render('Gallery/Show', ['artwork' => $artwork])๋กœ ์ „๋‹ฌ

3. **React ์ปดํฌ๋„ŒํŠธ**: resources/js/Pages/Gallery/Show.jsx
   - ํฐ ์ž‘ํ’ˆ ์ด๋ฏธ์ง€ ํ‘œ์‹œ (์ด๋ฏธ์ง€ ํด๋ฆญ ์‹œ ๋ชจ๋‹ฌ๋กœ ํ™•๋Œ€ - ์„ ํƒ ์‚ฌํ•ญ)
   - ์ž‘ํ’ˆ ์ •๋ณด ํ‘œ์‹œ: ์ œ๋ชฉ, ์ž‘๊ฐ€๋ช…, ์นดํ…Œ๊ณ ๋ฆฌ, ์„ค๋ช…, ํฌ๊ธฐ, ์žฌ๋ฃŒ, ๊ฐ€๊ฒฉ
   - ํŒ๋งค ์—ฌ๋ถ€ ๋ฐฐ์ง€ (Available / Sold Out)
   - "๊ตฌ๋งค ๋ฌธ์˜" ๋ฒ„ํŠผ (ํด๋ฆญ ์‹œ ๋ฌธ์˜ ํผ์œผ๋กœ ์Šคํฌ๋กค)
   - ์ข‹์•„์š” ๋ฒ„ํŠผ (ํ•˜ํŠธ ์•„์ด์ฝ˜, ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅ)
   - ๋’ค๋กœ ๊ฐ€๊ธฐ ๋ฒ„ํŠผ (๊ฐค๋Ÿฌ๋ฆฌ๋กœ ๋Œ์•„๊ฐ€๊ธฐ)

4. **๋ ˆ์ด์•„์›ƒ**: 2์ปฌ๋Ÿผ ๋ ˆ์ด์•„์›ƒ (์™ผ์ชฝ: ์ด๋ฏธ์ง€, ์˜ค๋ฅธ์ชฝ: ์ •๋ณด)
   - ๋ชจ๋ฐ”์ผ์—์„œ๋Š” 1์ปฌ๋Ÿผ์œผ๋กœ ์ „ํ™˜
   - Tailwind CSS๋กœ ๊น”๋”ํ•œ ๋””์ž์ธ

์ข‹์•„์š” ๊ธฐ๋Šฅ์€ ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ๋งŒ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค (๋ฐฑ์—”๋“œ ์ €์žฅ ์„ ํƒ ์‚ฌํ•ญ).

๊ธฐ๋Œ€ ๊ฒฐ๊ณผ: ๊ฐค๋Ÿฌ๋ฆฌ์—์„œ ์ž‘ํ’ˆ ์นด๋“œ๋ฅผ ํด๋ฆญํ•˜๋ฉด ์ƒ์„ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค. ํฐ ์ด๋ฏธ์ง€์™€ ํ•จ๊ป˜ ์ž‘ํ’ˆ์˜ ๋ชจ๋“  ์ •๋ณด๊ฐ€ ํ‘œ์‹œ๋˜๊ณ , ์ข‹์•„์š” ๋ฒ„ํŠผ๊ณผ ๊ตฌ๋งค ๋ฌธ์˜ ๋ฒ„ํŠผ์ด ๋ณด์ž…๋‹ˆ๋‹ค. ๋ฐ˜์‘ํ˜•์œผ๋กœ ๋ชจ๋ฐ”์ผ์—์„œ๋„ ์ž˜ ๋ณด์ž…๋‹ˆ๋‹ค.

7
Step 7
๊ตฌ๋งค ๋ฌธ์˜ ํผ์„ ๊ตฌํ˜„ํ•ด์ฃผ์„ธ์š”.

1. **๋ฌธ์˜ ๋ชจ๋ธ ์ƒ์„ฑ**: `php artisan make:model Inquiry -m`
   - ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ปฌ๋Ÿผ: id, artwork_id, name, email, message, created_at, updated_at
   - Artwork์™€ ๊ด€๊ณ„ ์„ค์ • (belongsTo)
   - ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์‹คํ–‰

2. **Gallery/Show.jsx์— ๋ฌธ์˜ ํผ ์ถ”๊ฐ€**:
   - ์ž‘ํ’ˆ ์ •๋ณด ์•„๋ž˜์— ๋ฌธ์˜ ํผ ์„น์…˜ ์ถ”๊ฐ€
   - ์ž…๋ ฅ ํ•„๋“œ: ์ด๋ฆ„, ์ด๋ฉ”์ผ, ๋ฉ”์‹œ์ง€
   - useForm (Inertia.js์˜ form helper) ์‚ฌ์šฉํ•˜์—ฌ ํผ ์ƒํƒœ ๊ด€๋ฆฌ
   - ์ œ์ถœ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ POST /artworks/{id}/inquiries๋กœ ์ „์†ก
   - ํผ ์ œ์ถœ ํ›„ ์„ฑ๊ณต ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ (Inertia flash message ํ™œ์šฉ)

3. **๋ผ์šฐํŠธ ์ถ”๊ฐ€**: routes/web.php
   - POST '/artworks/{id}/inquiries' โ†’ ArtworkController@storeInquiry

4. **์ปจํŠธ๋กค๋Ÿฌ ๋ฉ”์„œ๋“œ**: ArtworkController@storeInquiry
   - Request validation (name, email, message ํ•„์ˆ˜)
   - Inquiry::create()๋กœ ๋ฐ์ดํ„ฐ ์ €์žฅ
   - redirect()->back()->with('success', '๋ฌธ์˜๊ฐ€ ์ „์†ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค.')

5. **์ด๋ฉ”์ผ ์•Œ๋ฆผ (์„ ํƒ ์‚ฌํ•ญ)**:
   - `php artisan make:mail InquiryReceived --markdown=emails.inquiry`
   - ๋ฌธ์˜ ์ €์žฅ ํ›„ Mail::to('gallery@example.com')->send(new InquiryReceived($inquiry))
   - .env์— ๋ฉ”์ผ ์„ค์ • (๊ฐœ๋ฐœ ์‹œ mailtrap ๋˜๋Š” log ๋“œ๋ผ์ด๋ฒ„ ์‚ฌ์šฉ)

ํผ ๋””์ž์ธ์€ Tailwind CSS๋กœ ๊น”๋”ํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ , ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋„ ํ‘œ์‹œํ•ด์ฃผ์„ธ์š”.

๊ธฐ๋Œ€ ๊ฒฐ๊ณผ: ์ž‘ํ’ˆ ์ƒ์„ธ ํŽ˜์ด์ง€ ํ•˜๋‹จ์— ๊ตฌ๋งค ๋ฌธ์˜ ํผ์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ์ด๋ฆ„, ์ด๋ฉ”์ผ, ๋ฉ”์‹œ์ง€๋ฅผ ์ž…๋ ฅํ•˜๊ณ  ์ œ์ถœํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅ๋˜๊ณ , ์„ฑ๊ณต ๋ฉ”์‹œ์ง€๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์—๋Ÿฌ ์‹œ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๊ฐ€ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.

8
Step 8
๊ฐค๋Ÿฌ๋ฆฌ UI/UX๋ฅผ ๊ฐœ์„ ํ•˜๊ณ  ๋งˆ๋ฌด๋ฆฌ ์ž‘์—…์„ ํ•ด์ฃผ์„ธ์š”.

1. **๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ” ์ถ”๊ฐ€**:
   - ์ƒ๋‹จ์— ๋กœ๊ณ /์‚ฌ์ดํŠธ๋ช…๊ณผ "Gallery", "About" ๋งํฌ ์ถ”๊ฐ€
   - ๋ชจ๋ฐ”์ผ์—์„œ๋Š” ํ–„๋ฒ„๊ฑฐ ๋ฉ”๋‰ด๋กœ ์ „ํ™˜

2. **์ •๋ ฌ ๊ธฐ๋Šฅ ์ถ”๊ฐ€** (Gallery/Index.jsx):
   - ๋“œ๋กญ๋‹ค์šด ๋ฉ”๋‰ด๋กœ ์ •๋ ฌ ์˜ต์…˜ ์ œ๊ณต (์ตœ์‹ ์ˆœ, ๊ฐ€๊ฒฉ ๋‚ฎ์€์ˆœ, ๊ฐ€๊ฒฉ ๋†’์€์ˆœ)
   - useState๋กœ sortBy ์ƒํƒœ ๊ด€๋ฆฌ
   - artworks ๋ฐฐ์—ด์„ ์ •๋ ฌํ•˜์—ฌ ํ‘œ์‹œ

3. **ํŽ˜์ด์ง€๋„ค์ด์…˜ ๋˜๋Š” ๋ฌดํ•œ ์Šคํฌ๋กค**:
   - Laravel์˜ paginate() ์‚ฌ์šฉํ•˜์—ฌ ์ž‘ํ’ˆ ๋ชฉ๋ก ํŽ˜์ด์ง€๋„ค์ด์…˜
   - Inertia.js์˜ Link ์ปดํฌ๋„ŒํŠธ๋กœ ํŽ˜์ด์ง€ ์ด๋™
   - ๋˜๋Š” React Infinite Scroll ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ™œ์šฉ

4. **๋กœ๋”ฉ ์ƒํƒœ ํ‘œ์‹œ**:
   - Inertia.js์˜ progress indicator ํ™œ์šฉ
   - ์ž‘ํ’ˆ ์นด๋“œ ๋กœ๋”ฉ ์‹œ ์Šค์ผˆ๋ ˆํ†ค UI ํ‘œ์‹œ

5. **์ด๋ฏธ์ง€ ์ตœ์ ํ™”**:
   - Lazy loading ์ ์šฉ (loading="lazy" ์†์„ฑ)
   - ์ด๋ฏธ์ง€ ๋น„์œจ ์œ ์ง€ (aspect-ratio ์„ค์ •)

6. **์ ‘๊ทผ์„ฑ ๊ฐœ์„ **:
   - alt ํ…์ŠคํŠธ ์ถ”๊ฐ€
   - ํ‚ค๋ณด๋“œ ๋„ค๋น„๊ฒŒ์ด์…˜ ์ง€์›
   - ARIA ๋ผ๋ฒจ ์ถ”๊ฐ€

7. **๋ฐ˜์‘ํ˜• ํ…Œ์ŠคํŠธ**:
   - ๋ชจ๋ฐ”์ผ, ํƒœ๋ธ”๋ฆฟ, ๋ฐ์Šคํฌํ†ฑ์—์„œ ๋ ˆ์ด์•„์›ƒ ํ™•์ธ
   - Chrome DevTools๋กœ ๋‹ค์–‘ํ•œ ํ™”๋ฉด ํฌ๊ธฐ ํ…Œ์ŠคํŠธ

8. **README ์ž‘์„ฑ**:
   - ํ”„๋กœ์ ํŠธ ์„ค๋ช…, ์„ค์น˜ ๋ฐฉ๋ฒ•, ์‹คํ–‰ ๋ฐฉ๋ฒ• ์ž‘์„ฑ
   - ์Šคํฌ๋ฆฐ์ƒท ์ถ”๊ฐ€

๋ชจ๋“  ๊ธฐ๋Šฅ์ด ์ •์ƒ ์ž‘๋™ํ•˜๋Š”์ง€ ์ตœ์ข… ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•ด์ฃผ์„ธ์š”.

๊ธฐ๋Œ€ ๊ฒฐ๊ณผ: ๊ฐค๋Ÿฌ๋ฆฌ ํ”Œ๋žซํผ์ด ์™„์„ฑ๋ฉ๋‹ˆ๋‹ค. ๋„ค๋น„๊ฒŒ์ด์…˜, ์ •๋ ฌ, ํŽ˜์ด์ง€๋„ค์ด์…˜์ด ์ถ”๊ฐ€๋˜๊ณ , ๋กœ๋”ฉ ์ƒํƒœ์™€ ์Šค์ผˆ๋ ˆํ†ค UI๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ํ™”๋ฉด ํฌ๊ธฐ์—์„œ ๋ฐ˜์‘ํ˜•์œผ๋กœ ์ž˜ ์ž‘๋™ํ•˜๋ฉฐ, ์ ‘๊ทผ์„ฑ์ด ๊ฐœ์„ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. README ํŒŒ์ผ์ด ์ž‘์„ฑ๋˜์–ด ํ”„๋กœ์ ํŠธ๋ฅผ ์‰ฝ๊ฒŒ ์ดํ•ดํ•˜๊ณ  ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ œ์ถœ๋œ ์ž‘ํ’ˆ (0)

๋กœ๊ทธ์ธ ํ›„ ์ œ์ถœ

์•„์ง ์ œ์ถœ๋œ ์ž‘ํ’ˆ์ด ์—†์Šต๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ๋„์ „์ž๊ฐ€ ๋˜์–ด๋ณด์„ธ์š”!

๋Œ“๊ธ€ (0)

๋กœ๊ทธ์ธ ํ›„ ๋Œ“๊ธ€์„ ๋‚จ๊ธธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์•„์ง ๋Œ“๊ธ€์ด ์—†์Šต๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ๋Œ“๊ธ€์„ ๋‚จ๊ฒจ๋ณด์„ธ์š”!