๐ต ์ธ๋ ์๋ฐ ํ๋ฆฌ์ค๋ ํ๋ซํผ - ํ์ ํ ๋ฐ์ด๋ ์์ฝ ํ๋งค
indie-vinyl-preorder-platform
๋ฌธ์ ์ค๋ช
ํ๋ก์ ํธ ๊ฐ์
์ธ๋ ๋ ์ด๋ธ๊ณผ ๋ฎค์ง์ ์ ์ํ ์๋ฐ ํ๋ฆฌ์ค๋ ํ๋ซํผ์ ๋ง๋ญ๋๋ค. ์ค์ ์ธ๋ ์์ ์ฌ์์ ๋ฐ์ด๋/CD ํ์ ํ์ ์์ฝ ํ๋งคํ ๋ ์ฌ์ฉํ ์ ์๋ ์ค์ฉ์ ์ธ ํ์คํ ์๋น์ค์ ๋๋ค.
Laravel 13.x + Inertia.js + React 19 ๋ชจ๋
ธ๋ฆฌ์ค ์ํคํ
์ฒ๋ก ๊ตฌํํ๋ฉฐ, Inertia๊ฐ Laravel ๋ผ์ฐํธ์ React ์ปดํฌ๋ํธ๋ฅผ ๋งค๋๋ฝ๊ฒ ์ฐ๊ฒฐํฉ๋๋ค. ๋ณ๋ API ์ค๊ณ ์์ด Laravel ์ปจํธ๋กค๋ฌ์์ Inertia::render()๋ก ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๋ ๋ฐฉ์์
๋๋ค.
ํ์ ๊ธฐ๋ฅ
- ์๋ฐ ๋ชฉ๋ก ํ์ด์ง: ํ๋ฆฌ์ค๋ ์งํ ์ค์ธ ์จ๋ฒ ์นด๋ ๊ทธ๋ฆฌ๋ (์จ๋ฒ ์ปค๋ฒ, ์ํฐ์คํธ๋ช , ๊ฐ๊ฒฉ, ๋จ์ ์๋)
- ์๋ฐ ์์ธ ํ์ด์ง: ํธ๋๋ฆฌ์คํธ, ์จ๋ฒ ์๊ฐ, ์คํธ๋ฆฌ๋ฐ ๋งํฌ, ํ๋ฆฌ์ค๋ ๋ง๊ฐ์ผ ์นด์ดํธ๋ค์ด
- ํ๋ฆฌ์ค๋ ์ ์ฒญ ํผ: ๊ตฌ๋งค์ ์ ๋ณด(์ด๋ฆ, ์ด๋ฉ์ผ, ๋ฐฐ์ก์ง), ์๋ ์ ํ, ์ต์ ์ ํ(๋ฐ์ด๋ ์ปฌ๋ฌ ๋ฑ)
- ์ค์๊ฐ ์ฌ๊ณ ๊ด๋ฆฌ: ์ฃผ๋ฌธ ์ ์๋์ผ๋ก ๋จ์ ์๋ ๊ฐ์, ํ์ ์ '๋งค์ง' ๋ฐฐ์ง ํ์
- ์ฃผ๋ฌธ ๋ด์ญ ํ์ธ: ์ฃผ๋ฌธ ๋ฒํธ๋ก ์์ฝ ์ํ ์กฐํ ํ์ด์ง
- ๊ด๋ฆฌ์ ๋์๋ณด๋: ์จ๋ฒ ๋ฑ๋ก/์์ , ์ฃผ๋ฌธ ๋ชฉ๋ก ํ์ธ, ๋ฐฐ์ก ์ํ ์ ๋ฐ์ดํธ
๋ณด๋์ค ๊ธฐ๋ฅ
- ์๋ฐ ์์๋ฆฌ์คํธ (๋ก๊ทธ์ธ ์์ด ๋ธ๋ผ์ฐ์ localStorage ํ์ฉ)
- ํ๋ฆฌ์ค๋ ์ฑ๊ณต ์ ์ด๋ฉ์ผ ์๋ ๋ฐ์ก (Laravel Mail)
- ์์ ๊ณต์ ๋ฒํผ (ํธ์ํฐ/์ธ์คํ๊ทธ๋จ ๊ณต์ ๋งํฌ ์์ฑ)
- ์จ๋ฒ ์ถ์ D-Day ์นด์ดํธ๋ค์ด ์ ๋๋ฉ์ด์
- ๋คํฌ๋ชจ๋ ํ ๊ธ
๊ธฐ์ ์คํ
- ๋ฐฑ์๋: Laravel 13.x (Eloquent ORM, SQLite DB, Validation, Mail)
- ํ๋ก ํธ์๋: React 19 (Hooks, Context API)
- ํ์คํ ์ฐ๊ฒฐ: Inertia.js (SPA-like UX without API)
- ์คํ์ผ๋ง: Tailwind CSS 4.x
- ๋น๋ ๋๊ตฌ: Vite 6.x
ํ์ต ๋ชฉํ
- Laravel + Inertia + React ๋ชจ๋ ธ๋ฆฌ์ค ํ์คํ ํจํด ์ดํด
- Eloquent ๊ด๊ณ ์ค์ (Album, Order, OrderItem)
- React ์ปดํฌ๋ํธ ๋ถ๋ฆฌ ๋ฐ ์ํ ๊ด๋ฆฌ (useState, useContext)
- ํผ ์ ํจ์ฑ ๊ฒ์ฌ (Laravel Validation + React ์๋ฌ ํ์)
- ์ค์๊ฐ UI ์ ๋ฐ์ดํธ (์ฃผ๋ฌธ ์ ์ฌ๊ณ ๊ฐ์ ๋ฐ์)
์ ์ฝ ์กฐ๊ฑด
- โข Laravel 13.x + Inertia.js + React 19 ๋ชจ๋ ธ๋ฆฌ์ค ํ๋ก์ ํธ (๋ณ๋ API ๋ผ์ฐํธ ์์)
- โข Laravel Breeze (React + Inertia) starter kit ์ฌ์ฉ
- โข SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค (๊ฐ๋ฐ ํธ์์ฑ)
- โข Tailwind CSS 4.x๋ก ๋ฐ์ํ ๋์์ธ
- โข ์ค์๊ฐ ์ฌ๊ณ ๊ฐ์ ๋ก์ง (๋์ ์ฃผ๋ฌธ ๊ณ ๋ คํ ํธ๋์ญ์ ์ฒ๋ฆฌ)
- โข ์ด๋ฏธ์ง ์ ๋ก๋๋ public/storage ์ฌ๋ณผ๋ฆญ ๋งํฌ ํ์ฉ
- โข ์ฃผ๋ฌธ ๋ฒํธ ์๋ ์์ฑ (์: ORD-20250101-0001)
- โข ํ๋ฆฌ์ค๋ ๋ง๊ฐ์ผ ์ง๋ ์จ๋ฒ์ ์๋์ผ๋ก ์ฃผ๋ฌธ ๋ถ๊ฐ ์ฒ๋ฆฌ
ํ๋กฌํํธ ๋ ์ํผ
์๋ ํ๋กฌํํธ๋ฅผ ์์๋๋ก AI์๊ฒ ๋ณด๋ด๋ฉด ๋ฉ๋๋ค. ๋ณต์ฌ ๋ฒํผ์ ๋๋ฌ ๋ฐ๋ก ์ฌ์ฉํ์ธ์.
mkdir indie-vinyl-preorder-platform && cd indie-vinyl-preorder-platform ์ด ํด๋์์ Laravel 13.x + Inertia.js + React 19 ํ๋ก์ ํธ๋ฅผ ์์ํฉ๋๋ค. ๋ค์ ๋ช ๋ น์ด๋ก Laravel Breeze (React + Inertia) starter kit๋ฅผ ์ค์นํ์ธ์: ```bash composer create-project laravel/laravel . composer require laravel/breeze --dev php artisan breeze:install react npm install npm run dev ``` ์ดํ `.env` ํ์ผ์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ SQLite๋ก ์ค์ : ``` DB_CONNECTION=sqlite # DB_HOST, DB_PORT, DB_DATABASE ๋ฑ ์ฃผ์ ์ฒ๋ฆฌ ``` `database/database.sqlite` ํ์ผ์ ์์ฑํ๊ณ ๋ง์ด๊ทธ๋ ์ด์ ์คํ: ```bash touch database/database.sqlite php artisan migrate ``` ์ด์ `php artisan serve`๋ก ์๋ฒ๋ฅผ ์คํํ๊ณ `http://localhost:8000`์์ Laravel Breeze ๊ธฐ๋ณธ ํ๋ฉด์ด ๋์ค๋์ง ํ์ธํ์ธ์. ์๋ฃ๋๋ฉด ๋ค์ ๋จ๊ณ๋ก ์งํํฉ๋๋ค.
๊ธฐ๋ ๊ฒฐ๊ณผ: Laravel 13.x + Breeze (React + Inertia) ํ๋ก์ ํธ๊ฐ ์์ฑ๋๊ณ , SQLite DB ๋ง์ด๊ทธ๋ ์ด์ ์ด ์๋ฃ๋์ด ๊ธฐ๋ณธ ์ธ์ฆ ํ๋ฉด์ด ํ์๋ฉ๋๋ค. `npm run dev`๋ก Vite ๊ฐ๋ฐ ์๋ฒ๊ฐ ์คํ ์ค์ด์ด์ผ ํฉ๋๋ค.
์ด์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์คํค๋ง๋ฅผ ์ค๊ณํฉ๋๋ค. ๋ค์ 3๊ฐ ํ ์ด๋ธ์ ์์ฑํ์ธ์: 1. **albums** ํ ์ด๋ธ: ์๋ฐ ์ ๋ณด - id (primary key) - title (์จ๋ฒ๋ช ) - artist (์ํฐ์คํธ๋ช ) - description (์จ๋ฒ ์๊ฐ, text) - cover_image (์ปค๋ฒ ์ด๋ฏธ์ง ๊ฒฝ๋ก) - price (๊ฐ๊ฒฉ, decimal 10,2) - stock (์ฌ๊ณ ์๋, integer) - preorder_deadline (ํ๋ฆฌ์ค๋ ๋ง๊ฐ์ผ, date) - release_date (์ ์ ๋ฐ๋งค์ผ, date) - tracklist (ํธ๋๋ฆฌ์คํธ JSON, text) - streaming_links (์คํธ๋ฆฌ๋ฐ ๋งํฌ JSON, text) - timestamps 2. **orders** ํ ์ด๋ธ: ์ฃผ๋ฌธ ์ ๋ณด - id (primary key) - order_number (์ฃผ๋ฌธ ๋ฒํธ, unique) - customer_name (๊ตฌ๋งค์๋ช ) - customer_email (์ด๋ฉ์ผ) - shipping_address (๋ฐฐ์ก์ง, text) - total_amount (์ด ๊ธ์ก, decimal 10,2) - status (์ฃผ๋ฌธ ์ํ: pending, confirmed, shipped, delivered) - timestamps 3. **order_items** ํ ์ด๋ธ: ์ฃผ๋ฌธ ์์ธ (๋ค๋๋ค ๊ด๊ณ) - id (primary key) - order_id (foreign key -> orders.id) - album_id (foreign key -> albums.id) - quantity (์๋, integer) - unit_price (๋จ๊ฐ, decimal 10,2) - options (์ต์ JSON, text - ์: ๋ฐ์ด๋ ์ปฌ๋ฌ) - timestamps ๋ค์ ๋ช ๋ น์ด๋ก ๋ง์ด๊ทธ๋ ์ด์ ํ์ผ์ ์์ฑํ๊ณ ์์ฑํ์ธ์: ```bash php artisan make:migration create_albums_table php artisan make:migration create_orders_table php artisan make:migration create_order_items_table ``` ๊ฐ ๋ง์ด๊ทธ๋ ์ด์ ํ์ผ์ ์ ์คํค๋ง๋ฅผ ๊ตฌํํ๊ณ `php artisan migrate`๋ก ์คํํ์ธ์. ๋ํ Album, Order, OrderItem ๋ชจ๋ธ์ ์์ฑํ๊ณ ๊ด๊ณ๋ฅผ ์ค์ ํ์ธ์: ```bash php artisan make:model Album php artisan make:model Order php artisan make:model OrderItem ``` - Album ๋ชจ๋ธ: `hasMany(OrderItem::class)` - Order ๋ชจ๋ธ: `hasMany(OrderItem::class)` - OrderItem ๋ชจ๋ธ: `belongsTo(Album::class)`, `belongsTo(Order::class)` Seeder๋ก ์ํ ์จ๋ฒ ๋ฐ์ดํฐ 3~5๊ฐ๋ฅผ ์์ฑํ์ธ์ (AlbumSeeder ์์ฑ ํ `php artisan db:seed`).
๊ธฐ๋ ๊ฒฐ๊ณผ: albums, orders, order_items ํ ์ด๋ธ์ด ์์ฑ๋๊ณ , Eloquent ๋ชจ๋ธ ๊ด๊ณ๊ฐ ์ค์ ๋ฉ๋๋ค. Seeder๋ก ์ํ ์จ๋ฒ ๋ฐ์ดํฐ๊ฐ DB์ ์ฝ์ ๋์ด ํ ์คํธ ์ค๋น๊ฐ ์๋ฃ๋ฉ๋๋ค.
์๋ฐ ๋ชฉ๋ก ํ์ด์ง๋ฅผ ๊ตฌํํฉ๋๋ค. ๋ค์ ์์
์ ์ํํ์ธ์:
1. **๋ผ์ฐํธ ์ค์ ** (`routes/web.php`):
- `GET /albums` -> `AlbumController@index` (์๋ฐ ๋ชฉ๋ก)
- `GET /albums/{id}` -> `AlbumController@show` (์๋ฐ ์์ธ)
2. **์ปจํธ๋กค๋ฌ ์์ฑ** (`php artisan make:controller AlbumController`):
- `index()`: ํ๋ฆฌ์ค๋ ๋ง๊ฐ์ผ์ด ์ง๋์ง ์์ ์จ๋ฒ๋ง ํํฐ๋งํ์ฌ `Inertia::render('Albums/Index', ['albums' => $albums])`๋ก ์ ๋ฌ
- `show($id)`: ํน์ ์จ๋ฒ ์์ธ ์ ๋ณด๋ฅผ `Inertia::render('Albums/Show', ['album' => $album])`๋ก ์ ๋ฌ
3. **React ์ปดํฌ๋ํธ ์์ฑ**:
- `resources/js/Pages/Albums/Index.jsx`: ์จ๋ฒ ์นด๋ ๊ทธ๋ฆฌ๋ ๋ ์ด์์
- ๊ฐ ์นด๋: ์จ๋ฒ ์ปค๋ฒ ์ด๋ฏธ์ง, ์ํฐ์คํธ๋ช
, ์จ๋ฒ๋ช
, ๊ฐ๊ฒฉ, ๋จ์ ์๋, "์์ธ ๋ณด๊ธฐ" ๋ฒํผ
- ์ฌ๊ณ ๊ฐ 0์ด๋ฉด "๋งค์ง" ๋ฐฐ์ง ํ์ (๋นจ๊ฐ์ ๋ฐฐ๊ฒฝ)
- Tailwind CSS๋ก ๋ฐ์ํ ๊ทธ๋ฆฌ๋ (๋ชจ๋ฐ์ผ 1์ด, ํ๋ธ๋ฆฟ 2์ด, ๋ฐ์คํฌํ 3์ด)
- `resources/js/Pages/Albums/Show.jsx`: ์จ๋ฒ ์์ธ ํ์ด์ง (๋ค์ ๋จ๊ณ์์ ๊ตฌํ)
4. **๋ค๋น๊ฒ์ด์
์ถ๊ฐ**: `resources/js/Layouts/AuthenticatedLayout.jsx` (๋๋ GuestLayout)์ "์๋ฐ ๋ชฉ๋ก" ๋งํฌ ์ถ๊ฐ
5. **์ด๋ฏธ์ง ์
๋ก๋ ์ค๋น**:
- `php artisan storage:link`๋ก ์ฌ๋ณผ๋ฆญ ๋งํฌ ์์ฑ
- Seeder์์ ์ํ ์ด๋ฏธ์ง ๊ฒฝ๋ก๋ฅผ `storage/app/public/covers/sample.jpg` ํํ๋ก ์ค์
์๋ฃ ํ `http://localhost:8000/albums`์์ ์จ๋ฒ ๋ชฉ๋ก์ด ํ์๋๋์ง ํ์ธํ์ธ์.
๊ธฐ๋ ๊ฒฐ๊ณผ: ์๋ฐ ๋ชฉ๋ก ํ์ด์ง๊ฐ ์๋ํ๋ฉฐ, Seeder๋ก ์์ฑํ ์ํ ์จ๋ฒ๋ค์ด ์นด๋ ๊ทธ๋ฆฌ๋๋ก ํ์๋ฉ๋๋ค. ์ฌ๊ณ ๊ฐ 0์ธ ์จ๋ฒ์ '๋งค์ง' ๋ฐฐ์ง๊ฐ ๋ณด์ ๋๋ค. Inertia.js๊ฐ Laravel ๋ผ์ฐํธ์ React ์ปดํฌ๋ํธ๋ฅผ ์ฐ๊ฒฐํฉ๋๋ค.
์๋ฐ ์์ธ ํ์ด์ง์ ํ๋ฆฌ์ค๋ ์ ์ฒญ ํผ์ ๊ตฌํํฉ๋๋ค:
1. **React ์ปดํฌ๋ํธ ์์ฑ** (`resources/js/Pages/Albums/Show.jsx`):
- ๋ ์ด์์: ์ผ์ชฝ์ ํฐ ์จ๋ฒ ์ปค๋ฒ ์ด๋ฏธ์ง, ์ค๋ฅธ์ชฝ์ ์ ๋ณด ๋ฐ ์ฃผ๋ฌธ ํผ
- ํ์ ์ ๋ณด:
- ์จ๋ฒ๋ช
, ์ํฐ์คํธ๋ช
, ๊ฐ๊ฒฉ, ํ๋ฆฌ์ค๋ ๋ง๊ฐ์ผ ์นด์ดํธ๋ค์ด (react-countdown ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ฉ)
- ์จ๋ฒ ์๊ฐ (description)
- ํธ๋๋ฆฌ์คํธ (tracklist JSON ํ์ฑํ์ฌ ๋ฆฌ์คํธ ํ์)
- ์คํธ๋ฆฌ๋ฐ ๋งํฌ ๋ฒํผ (Spotify, Apple Music ๋ฑ)
- **์ฃผ๋ฌธ ํผ**:
- ๊ตฌ๋งค์๋ช
(input)
- ์ด๋ฉ์ผ (input)
- ๋ฐฐ์ก์ง (textarea)
- ์๋ ์ ํ (number input, ์ต์ 1, ์ต๋ ์ฌ๊ณ ์๋)
- ์ต์
์ ํ (select - ์: "๋ธ๋ ๋ฐ์ด๋", "ํฌ๋ช
๋ฐ์ด๋", "CD")
- "ํ๋ฆฌ์ค๋ ์ ์ฒญ" ๋ฒํผ (์ฌ๊ณ 0์ด๋ฉด ๋นํ์ฑํ)
- ํผ ์ ์ถ ์ `Inertia.post('/orders', formData)`๋ก ์ฃผ๋ฌธ ์์ฑ
2. **๋ผ์ฐํธ ์ถ๊ฐ** (`routes/web.php`):
- `POST /orders` -> `OrderController@store`
3. **์ปจํธ๋กค๋ฌ ์์ฑ** (`php artisan make:controller OrderController`):
- `store(Request $request)`:
- ์ ํจ์ฑ ๊ฒ์ฌ (customer_name, customer_email, shipping_address, album_id, quantity ํ์)
- ์ฌ๊ณ ํ์ธ (์์ฒญ ์๋์ด ์ฌ๊ณ ๋ณด๋ค ๋ง์ผ๋ฉด ์๋ฌ)
- DB ํธ๋์ญ์
์ผ๋ก ์ฃผ๋ฌธ ์์ฑ:
- Order ๋ ์ฝ๋ ์์ฑ (order_number๋ "ORD-" + ๋ ์ง + ์ผ๋ จ๋ฒํธ ํ์)
- OrderItem ๋ ์ฝ๋ ์์ฑ
- Album ์ฌ๊ณ ๊ฐ์ (`stock -= quantity`)
- ์ฑ๊ณต ์ ์ฃผ๋ฌธ ๋ฒํธ์ ํจ๊ป `/orders/{order_number}` ํ์ด์ง๋ก ๋ฆฌ๋ค์ด๋ ํธ
4. **์๋ฌ ์ฒ๋ฆฌ**: React ์ปดํฌ๋ํธ์์ Inertia ์๋ฌ๋ฅผ ํ์ (`usePage().props.errors` ํ์ฉ)
์๋ฃ ํ ์๋ฐ ์์ธ ํ์ด์ง์์ ์ฃผ๋ฌธ ํผ์ด ์๋ํ๋์ง ํ
์คํธํ์ธ์.
๊ธฐ๋ ๊ฒฐ๊ณผ: ์๋ฐ ์์ธ ํ์ด์ง์ ํธ๋๋ฆฌ์คํธ, ์คํธ๋ฆฌ๋ฐ ๋งํฌ, ํ๋ฆฌ์ค๋ ๋ง๊ฐ์ผ ์นด์ดํธ๋ค์ด์ด ํ์๋ฉ๋๋ค. ์ฃผ๋ฌธ ํผ ์ ์ถ ์ DB์ ์ฃผ๋ฌธ์ด ์ ์ฅ๋๊ณ ์ฌ๊ณ ๊ฐ ๊ฐ์ํ๋ฉฐ, ์ฃผ๋ฌธ ํ์ธ ํ์ด์ง๋ก ๋ฆฌ๋ค์ด๋ ํธ๋ฉ๋๋ค.
์ฃผ๋ฌธ ํ์ธ ํ์ด์ง์ ์ฃผ๋ฌธ ์กฐํ ๊ธฐ๋ฅ์ ๊ตฌํํฉ๋๋ค:
1. **๋ผ์ฐํธ ์ถ๊ฐ** (`routes/web.php`):
- `GET /orders/{order_number}` -> `OrderController@show`
2. **์ปจํธ๋กค๋ฌ ๋ฉ์๋ ์ถ๊ฐ** (`OrderController`):
- `show($orderNumber)`:
- Order ๋ชจ๋ธ์์ `where('order_number', $orderNumber)->with('orderItems.album')->firstOrFail()`๋ก ์ฃผ๋ฌธ ์ ๋ณด ์กฐํ
- `Inertia::render('Orders/Show', ['order' => $order])`๋ก ์ ๋ฌ
3. **React ์ปดํฌ๋ํธ ์์ฑ** (`resources/js/Pages/Orders/Show.jsx`):
- ์ฃผ๋ฌธ ์๋ฃ ๋ฉ์์ง ("ํ๋ฆฌ์ค๋ ์ ์ฒญ์ด ์๋ฃ๋์์ต๋๋ค!" + ์ถํ ์์ด์ฝ)
- ์ฃผ๋ฌธ ์ ๋ณด ์นด๋:
- ์ฃผ๋ฌธ ๋ฒํธ (๊ตต์ ๊ธ์จ)
- ๊ตฌ๋งค์๋ช
, ์ด๋ฉ์ผ, ๋ฐฐ์ก์ง
- ์ฃผ๋ฌธํ ์จ๋ฒ ๋ชฉ๋ก (์จ๋ฒ๋ช
, ์๋, ๋จ๊ฐ, ์ต์
)
- ์ด ๊ธ์ก
- ์ฃผ๋ฌธ ์ํ (pending, confirmed, shipped, delivered - ๋ฐฐ์ง๋ก ํ์)
- "์ฃผ๋ฌธ ๋ด์ญ ์ ์ฅ" ๋ฒํผ (ํ์ด์ง๋ฅผ PDF๋ก ์ ์ฅํ๊ฑฐ๋ ์คํฌ๋ฆฐ์ท ์ดฌ์ ์๋ด)
- "์๋ฐ ๋ชฉ๋ก์ผ๋ก ๋์๊ฐ๊ธฐ" ๋ฒํผ
4. **์ฃผ๋ฌธ ์กฐํ ํ์ด์ง ์ถ๊ฐ** (์ ํ):
- `GET /orders` -> ์ฃผ๋ฌธ ๋ฒํธ ์
๋ ฅ ํผ
- ์
๋ ฅ ํ `/orders/{order_number}`๋ก ๋ฆฌ๋ค์ด๋ ํธ
์๋ฃ ํ ์ฃผ๋ฌธ ์๋ฃ ํ ํ์ธ ํ์ด์ง๊ฐ ์ ์ ํ์๋๋์ง ํ
์คํธํ์ธ์.
๊ธฐ๋ ๊ฒฐ๊ณผ: ์ฃผ๋ฌธ ํ์ธ ํ์ด์ง๊ฐ ์๋ํ๋ฉฐ, ์ฃผ๋ฌธ ๋ฒํธ๋ก ์ฃผ๋ฌธ ์ ๋ณด๋ฅผ ์กฐํํ ์ ์์ต๋๋ค. ์ฃผ๋ฌธํ ์จ๋ฒ ๋ชฉ๋ก๊ณผ ๋ฐฐ์ก์ง ์ ๋ณด๊ฐ ๋ช ํํ ํ์๋ฉ๋๋ค.
๊ด๋ฆฌ์ ๋์๋ณด๋๋ฅผ ๊ตฌํํฉ๋๋ค (๊ฐ๋จํ CRUD):
1. **๋ผ์ฐํธ ์ถ๊ฐ** (`routes/web.php`):
- `GET /admin/albums` -> `AdminAlbumController@index` (์จ๋ฒ ๋ชฉ๋ก ๊ด๋ฆฌ)
- `GET /admin/albums/create` -> `AdminAlbumController@create` (์จ๋ฒ ๋ฑ๋ก ํผ)
- `POST /admin/albums` -> `AdminAlbumController@store` (์จ๋ฒ ์ ์ฅ)
- `GET /admin/albums/{id}/edit` -> `AdminAlbumController@edit` (์จ๋ฒ ์์ ํผ)
- `PUT /admin/albums/{id}` -> `AdminAlbumController@update` (์จ๋ฒ ์
๋ฐ์ดํธ)
- `DELETE /admin/albums/{id}` -> `AdminAlbumController@destroy` (์จ๋ฒ ์ญ์ )
- `GET /admin/orders` -> `AdminOrderController@index` (์ฃผ๋ฌธ ๋ชฉ๋ก ๊ด๋ฆฌ)
- `PATCH /admin/orders/{id}` -> `AdminOrderController@updateStatus` (๋ฐฐ์ก ์ํ ๋ณ๊ฒฝ)
2. **์ปจํธ๋กค๋ฌ ์์ฑ**:
- `php artisan make:controller Admin/AdminAlbumController --resource`
- `php artisan make:controller Admin/AdminOrderController`
3. **React ์ปดํฌ๋ํธ ์์ฑ**:
- `resources/js/Pages/Admin/Albums/Index.jsx`: ์จ๋ฒ ๋ชฉ๋ก ํ
์ด๋ธ (์ ๋ชฉ, ์ํฐ์คํธ, ์ฌ๊ณ , ์์ /์ญ์ ๋ฒํผ)
- `resources/js/Pages/Admin/Albums/Create.jsx`: ์จ๋ฒ ๋ฑ๋ก ํผ (๋ชจ๋ ํ๋ ์
๋ ฅ, ์ด๋ฏธ์ง ์
๋ก๋)
- `resources/js/Pages/Admin/Albums/Edit.jsx`: ์จ๋ฒ ์์ ํผ
- `resources/js/Pages/Admin/Orders/Index.jsx`: ์ฃผ๋ฌธ ๋ชฉ๋ก ํ
์ด๋ธ (์ฃผ๋ฌธ ๋ฒํธ, ๊ตฌ๋งค์๋ช
, ์ํ, ์ํ ๋ณ๊ฒฝ ๋๋กญ๋ค์ด)
4. **์ด๋ฏธ์ง ์
๋ก๋ ์ฒ๋ฆฌ** (`AdminAlbumController@store`):
- `$request->file('cover_image')->store('covers', 'public')`๋ก ์ ์ฅ
- ์ ์ฅ๋ ๊ฒฝ๋ก๋ฅผ DB์ ๊ธฐ๋ก
5. **์ธ์ฆ ๋ฏธ๋ค์จ์ด ์ ์ฉ** (์ ํ):
- ๊ด๋ฆฌ์ ๋ผ์ฐํธ์ `auth` ๋ฏธ๋ค์จ์ด ์ถ๊ฐ
- ๋๋ ๊ฐ๋จํ `/admin` ๊ฒฝ๋ก ์์ฒด๋ฅผ ๋น๋ฐ๋ฒํธ๋ก ๋ณดํธ
์๋ฃ ํ `/admin/albums`์์ ์จ๋ฒ์ ์ถ๊ฐ/์์ ํ๊ณ , `/admin/orders`์์ ์ฃผ๋ฌธ ์ํ๋ฅผ ๋ณ๊ฒฝํ ์ ์๋์ง ํ
์คํธํ์ธ์.
๊ธฐ๋ ๊ฒฐ๊ณผ: ๊ด๋ฆฌ์ ๋์๋ณด๋๊ฐ ์๋ํ๋ฉฐ, ์จ๋ฒ์ ๋ฑ๋ก/์์ /์ญ์ ํ๊ณ ์ฃผ๋ฌธ ์ํ๋ฅผ ์ ๋ฐ์ดํธํ ์ ์์ต๋๋ค. ์ด๋ฏธ์ง ์ ๋ก๋๊ฐ ์ ์ ์๋ํ๊ณ , ์ฃผ๋ฌธ ๋ชฉ๋ก์์ ๋ฐฐ์ก ์ํ๋ฅผ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
์ ์ถ๋ ์ํ (0)
๋ก๊ทธ์ธ ํ ์ ์ถ์์ง ์ ์ถ๋ ์ํ์ด ์์ต๋๋ค. ์ฒซ ๋ฒ์งธ ๋์ ์๊ฐ ๋์ด๋ณด์ธ์!