๐ธ ๋ก์ปฌ ๋ผ์ด๋ธ ๊ณต์ฐ ํฐ์ผ ํ๋งค ํ์ด์ง
live-show-ticket-sales
๋ฌธ์ ์ค๋ช
ํ๋ก์ ํธ ๊ฐ์
์๊ท๋ชจ ๋ผ์ด๋ธ ๊ณต์ฐ์ฅ, ์ธ๋ ๋ฐด๋, ํด๋ฝ ๊ณต์ฐ์ ์ํ ํฐ์ผ ํ๋งค ๋๋ฉํ์ด์ง๋ฅผ ๋ง๋ญ๋๋ค. Laravel 13.x API ๋ฐฑ์๋์ React 19 ํ๋ก ํธ์๋๋ฅผ ๋ถ๋ฆฌํ์ฌ ๊ตฌ์ฑํ๋ฉฐ, ์ค์ ๊ณต์ฐ ์ ๋ณด๋ฅผ ๋ฑ๋กํ๊ณ ๊ด๊ฐ์ด ํฐ์ผ์ ๊ตฌ๋งค ์ ์ฒญํ ์ ์๋ ํ์คํ ์๋น์ค์ ๋๋ค.
ํ์ ๊ธฐ๋ฅ
- ๊ณต์ฐ ์ ๋ณด ํ์: ๊ณต์ฐ๋ช , ์ํฐ์คํธ, ์ผ์, ์ฅ์, ํฐ์ผ ๊ฐ๊ฒฉ ๋ฑ ์์ธ ์ ๋ณด
- ํฐ์ผ ๊ตฌ๋งค ์ ์ฒญ ํผ: ์ด๋ฆ, ์ด๋ฉ์ผ, ์ฐ๋ฝ์ฒ, ํฐ์ผ ์๋ ์ ๋ ฅ
- ์ค์๊ฐ ์์ฌ์ ํ์ธ: ํ๋งค๋ ํฐ์ผ ์์ ๋จ์ ์ข์ ์ ํ์
- ๋ฐ์ํ ๋์์ธ: ๋ชจ๋ฐ์ผ์์๋ ๊น๋ํ๊ฒ ๋ณด์ด๋ UI
- ์๊ฐ์ ๊ณต์ฐ ํฌ์คํฐ: ์ด๋ฏธ์ง ์ ๋ก๋ ๊ธฐ๋ฅ (์ ํ์ฌํญ)
๋ณด๋์ค ๊ธฐ๋ฅ
- ๊ตฌ๋งค ์๋ฃ ์ ํ์ธ ์ด๋ฉ์ผ ์๋ ๋ฐ์ก
- ๊ณต์ฐ๋ณ ์นดํ ๊ณ ๋ฆฌ ํํฐ๋ง (๋ฝ, ์ฌ์ฆ, ํํฉ ๋ฑ)
- ์ข์์/์ฐํ๊ธฐ ๊ธฐ๋ฅ์ผ๋ก ๊ด์ฌ ๊ณต์ฐ ์ ์ฅ
- ๊ณต์ฐ D-day ์นด์ดํธ๋ค์ด ํ์ด๋จธ
- ํฐ์ผ ๊ตฌ๋งค ํ QR ์ฝ๋ ์์ฑ (์ ์ฅ๊ถ)
๊ธฐ์ ์คํ
- ๋ฐฑ์๋: Laravel 13.x (RESTful API)
- ํ๋ก ํธ์๋: React 19 (Vite)
- ๋ฐ์ดํฐ๋ฒ ์ด์ค: SQLite (๊ฐ๋จํ ๋ก์ปฌ DB)
- ์คํ์ผ๋ง: Tailwind CSS
ํ์ต ๋ชฉํ
- Laravel API ์๋ํฌ์ธํธ ์ค๊ณ ๋ฐ CRUD ๊ตฌํ
- React์์ fetch/axios๋ก API ํธ์ถํ์ฌ ๋ฐ์ดํฐ ์ฐ๋
- useState๋ฅผ ํ์ฉํ ๊ฐ๋จํ ์ํ ๊ด๋ฆฌ
- ํผ ์ ๋ ฅ ๋ฐ ์ ํจ์ฑ ๊ฒ์ฌ ์ฒ๋ฆฌ
- ๋ฐฑ์๋์ ํ๋ก ํธ์๋ ๋ถ๋ฆฌ ๊ฐ๋ฐ ๊ฒฝํ
์ ์ฝ ์กฐ๊ฑด
- โข Laravel 13.x ์ต์ ๋ฒ์ ์ฌ์ฉ (๊ตฌ๋ฒ์ ๊ธ์ง)
- โข React 19 ์ต์ ๋ฒ์ ์ฌ์ฉ
- โข SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฌ์ฉ (์ค์ ๊ฐ์ํ)
- โข ๋ณต์กํ ์ํ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ธ์ง (useState๋ง ์ฌ์ฉ)
- โข WebSocket ์ฌ์ฉ ๊ธ์ง (HTTP ๊ธฐ๋ฐ ํต์ ๋ง)
- โข Tailwind CSS๋ก ์คํ์ผ๋ง
- โข CORS ์ค์ ํ์ (Laravel API โ React ํ๋ก ํธ์๋ ํต์ )
- โข API ์๋ต์ JSON ํ์
- โข ํ๋ก ํธ์๋๋ Vite๋ก ๋ณ๋ ํ๋ก์ ํธ ๊ตฌ์ฑ
ํ๋กฌํํธ ๋ ์ํผ
์๋ ํ๋กฌํํธ๋ฅผ ์์๋๋ก AI์๊ฒ ๋ณด๋ด๋ฉด ๋ฉ๋๋ค. ๋ณต์ฌ ๋ฒํผ์ ๋๋ฌ ๋ฐ๋ก ์ฌ์ฉํ์ธ์.
mkdir live-show-ticket-sales && cd live-show-ticket-sales ์ด ํด๋์์ ํ๋ก์ ํธ๋ฅผ ์์ํฉ๋๋ค. ## Laravel 13.x API ๋ฐฑ์๋ ํ๋ก์ ํธ ์์ฑ 1. `backend` ํด๋์ Laravel 13.x ํ๋ก์ ํธ๋ฅผ ์์ฑํ์ธ์. 2. `.env` ํ์ผ์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ SQLite๋ก ์ค์ ํ์ธ์. 3. `database/database.sqlite` ํ์ผ์ ์์ฑํ์ธ์. 4. CORS ์ค์ ์ ์ถ๊ฐํ์ฌ React ํ๋ก ํธ์๋(http://localhost:5173)์์ API ํธ์ถ์ด ๊ฐ๋ฅํ๋๋ก ํ์ธ์. 5. `php artisan serve --port=8000`๋ก ๋ฐฑ์๋ ์๋ฒ๋ฅผ ์คํํ ์ ์๋๋ก ์ค๋นํ์ธ์. ## ๊ธฐ๋ ๊ฒฐ๊ณผ - `backend` ํด๋์ Laravel 13.x ํ๋ก์ ํธ ์์ฑ ์๋ฃ - SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค์ ์๋ฃ - CORS ๋ฏธ๋ค์จ์ด ์ค์ ์ผ๋ก React ์ฑ๊ณผ ํต์ ๊ฐ๋ฅ - `php artisan serve` ์คํ ์ http://localhost:8000 ์ ์ ๊ฐ๋ฅ
๊ธฐ๋ ๊ฒฐ๊ณผ: Laravel ๋ฐฑ์๋ ํ๋ก์ ํธ๊ฐ ์์ฑ๋๊ณ , SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค์ ๋ฐ CORS ์ค์ ์ด ์๋ฃ๋ฉ๋๋ค. ์๋ฒ๋ฅผ ์คํํ๋ฉด API ์๋ํฌ์ธํธ ์ค๋น ์ํ๊ฐ ๋ฉ๋๋ค.
## Laravel ๋ง์ด๊ทธ๋ ์ด์ ๋ฐ ๋ชจ๋ธ ์์ฑ 1. `shows` ํ ์ด๋ธ์ ์์ฑํ๋ ๋ง์ด๊ทธ๋ ์ด์ ์ ๋ง๋์ธ์. ์ปฌ๋ผ: - id (primary key) - title (๊ณต์ฐ๋ช , string) - artist (์ํฐ์คํธ๋ช , string) - venue (๊ณต์ฐ ์ฅ์, string) - show_date (๊ณต์ฐ ์ผ์, datetime) - ticket_price (ํฐ์ผ ๊ฐ๊ฒฉ, decimal) - total_seats (์ด ์ข์ ์, integer) - sold_seats (ํ๋งค๋ ์ข์ ์, integer, ๊ธฐ๋ณธ๊ฐ 0) - poster_url (ํฌ์คํฐ ์ด๋ฏธ์ง URL, string, nullable) - created_at, updated_at (ํ์์คํฌํ) 2. `ticket_orders` ํ ์ด๋ธ์ ์์ฑํ๋ ๋ง์ด๊ทธ๋ ์ด์ ์ ๋ง๋์ธ์. ์ปฌ๋ผ: - id (primary key) - show_id (์ธ๋ํค, shows ํ ์ด๋ธ ์ฐธ์กฐ) - customer_name (๊ตฌ๋งค์ ์ด๋ฆ, string) - customer_email (๊ตฌ๋งค์ ์ด๋ฉ์ผ, string) - customer_phone (๊ตฌ๋งค์ ์ฐ๋ฝ์ฒ, string) - quantity (ํฐ์ผ ์๋, integer) - created_at, updated_at (ํ์์คํฌํ) 3. `Show` ๋ชจ๋ธ๊ณผ `TicketOrder` ๋ชจ๋ธ์ ์์ฑํ์ธ์. 4. ๋ชจ๋ธ ๊ฐ ๊ด๊ณ ์ค์ : - Show ๋ชจ๋ธ: `hasMany` ๊ด๊ณ๋ก TicketOrder์ ์ฐ๊ฒฐ - TicketOrder ๋ชจ๋ธ: `belongsTo` ๊ด๊ณ๋ก Show์ ์ฐ๊ฒฐ 5. ๋ง์ด๊ทธ๋ ์ด์ ์ ์คํํ์ธ์: `php artisan migrate` ## ๊ธฐ๋ ๊ฒฐ๊ณผ - shows, ticket_orders ํ ์ด๋ธ์ด SQLite DB์ ์์ฑ๋จ - Show, TicketOrder Eloquent ๋ชจ๋ธ ์์ฑ ์๋ฃ - ๋ชจ๋ธ ๊ฐ ๊ด๊ณ ์ค์ ์๋ฃ
๊ธฐ๋ ๊ฒฐ๊ณผ: ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ ์ด๋ธ๊ณผ Eloquent ๋ชจ๋ธ์ด ์์ฑ๋๋ฉฐ, ๊ณต์ฐ ์ ๋ณด์ ํฐ์ผ ์ฃผ๋ฌธ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ์ค๋น๊ฐ ์๋ฃ๋ฉ๋๋ค.
## Laravel API ๋ผ์ฐํธ ๋ฐ ์ปจํธ๋กค๋ฌ ๊ตฌํ
1. `routes/api.php`์ ๋ค์ API ์๋ํฌ์ธํธ๋ฅผ ์ ์ํ์ธ์:
- GET `/api/shows` : ๋ชจ๋ ๊ณต์ฐ ๋ชฉ๋ก ์กฐํ
- GET `/api/shows/{id}` : ํน์ ๊ณต์ฐ ์์ธ ์ ๋ณด ์กฐํ
- POST `/api/shows` : ์ ๊ณต์ฐ ๋ฑ๋ก (๊ด๋ฆฌ์์ฉ, ์ ํ์ฌํญ)
- POST `/api/ticket-orders` : ํฐ์ผ ๊ตฌ๋งค ์ ์ฒญ
2. `ShowController`๋ฅผ ์์ฑํ๊ณ ๋ค์ ๋ฉ์๋๋ฅผ ๊ตฌํํ์ธ์:
- `index()`: ๋ชจ๋ ๊ณต์ฐ ๋ชฉ๋ก์ JSON์ผ๋ก ๋ฐํ (์์ฌ์ ๊ณ์ฐ ํฌํจ)
- `show($id)`: ํน์ ๊ณต์ฐ ์์ธ ์ ๋ณด ๋ฐํ
- `store()`: ์ ๊ณต์ฐ ๋ฑ๋ก (title, artist, venue, show_date, ticket_price, total_seats ์
๋ ฅ)
3. `TicketOrderController`๋ฅผ ์์ฑํ๊ณ `store()` ๋ฉ์๋๋ฅผ ๊ตฌํํ์ธ์:
- ํฐ์ผ ๊ตฌ๋งค ์ ์ฒญ ์ฒ๋ฆฌ
- show_id, customer_name, customer_email, customer_phone, quantity ์
๋ ฅ
- ์์ฌ์ ํ์ธ: `show->sold_seats + quantity <= show->total_seats` ๊ฒ์ฆ
- ๊ตฌ๋งค ๊ฐ๋ฅํ๋ฉด TicketOrder ์์ฑ ๋ฐ Show์ sold_seats ์ฆ๊ฐ
- ์ฑ๊ณต ์ JSON ์๋ต ๋ฐํ
4. Postman ๋๋ curl๋ก API ํ
์คํธ:
- POST `/api/shows`๋ก ์ํ ๊ณต์ฐ ๋ฐ์ดํฐ 1~2๊ฐ ๋ฑ๋ก
- GET `/api/shows`๋ก ๊ณต์ฐ ๋ชฉ๋ก ์กฐํ ํ์ธ
- POST `/api/ticket-orders`๋ก ํฐ์ผ ๊ตฌ๋งค ํ
์คํธ
## ๊ธฐ๋ ๊ฒฐ๊ณผ
- RESTful API ์๋ํฌ์ธํธ ๊ตฌํ ์๋ฃ
- ๊ณต์ฐ ๋ฑ๋ก, ์กฐํ, ํฐ์ผ ๊ตฌ๋งค ๋ก์ง ๋์
- JSON ์๋ต ํ์ ํ์ธ
๊ธฐ๋ ๊ฒฐ๊ณผ: Laravel API๊ฐ ์์ฑ๋์ด ๊ณต์ฐ ์ ๋ณด๋ฅผ ๋ฑ๋กํ๊ณ ์กฐํํ ์ ์์ผ๋ฉฐ, ํฐ์ผ ๊ตฌ๋งค ์ ์ฒญ ์ ์์ฌ์์ด ์๋์ผ๋ก ์ ๋ฐ์ดํธ๋ฉ๋๋ค.
## React 19 ํ๋ก ํธ์๋ ํ๋ก์ ํธ ์์ฑ
1. ํ๋ก์ ํธ ๋ฃจํธ(`live-show-ticket-sales`)์์ `frontend` ํด๋์ React 19 + Vite ํ๋ก์ ํธ๋ฅผ ์์ฑํ์ธ์:
```bash
npm create vite@latest frontend -- --template react
cd frontend
npm install
```
2. Tailwind CSS๋ฅผ ์ค์นํ๊ณ ์ค์ ํ์ธ์:
```bash
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
```
- `tailwind.config.js`์์ content ๊ฒฝ๋ก ์ค์ : `["./index.html", "./src/**/*.{js,jsx}"]`
- `src/index.css`์ Tailwind ์ง์์ด ์ถ๊ฐ:
```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```
3. `npm run dev`๋ก ํ๋ก ํธ์๋ ๊ฐ๋ฐ ์๋ฒ๋ฅผ ์คํํ์ธ์ (http://localhost:5173).
4. `src/App.jsx`๋ฅผ ๊ฐ๋จํ ํค๋์ "๊ณต์ฐ ํฐ์ผ ํ๋งค" ํ์ดํ๋ก ์์ ํ์ฌ Tailwind CSS๊ฐ ์ ์ฉ๋๋์ง ํ์ธํ์ธ์.
## ๊ธฐ๋ ๊ฒฐ๊ณผ
- React 19 + Vite ํ๋ก ํธ์๋ ํ๋ก์ ํธ ์์ฑ ์๋ฃ
- Tailwind CSS ์ค์ ์๋ฃ
- http://localhost:5173 ์ ์ ์ ๊ธฐ๋ณธ ํ๋ฉด ํ์
๊ธฐ๋ ๊ฒฐ๊ณผ: React ํ๋ก ํธ์๋ ํ๋ก์ ํธ๊ฐ ์์ฑ๋๊ณ Tailwind CSS๊ฐ ์ ์ฉ๋์ด ๊ฐ๋ฐ ์๋ฒ๊ฐ ์คํ๋ฉ๋๋ค.
## React ์ปดํฌ๋ํธ ๊ตฌํ - ๊ณต์ฐ ๋ชฉ๋ก ํ์ 1. `src/components/ShowList.jsx` ์ปดํฌ๋ํธ๋ฅผ ์์ฑํ์ธ์. 2. `useState`์ `useEffect`๋ฅผ ์ฌ์ฉํ์ฌ Laravel API(`http://localhost:8000/api/shows`)์์ ๊ณต์ฐ ๋ชฉ๋ก์ fetchํ์ธ์. 3. ๊ณต์ฐ ๋ฐ์ดํฐ๋ฅผ ์นด๋ ํํ๋ก ํ์: - ๊ณต์ฐ๋ช , ์ํฐ์คํธ, ์ฅ์, ์ผ์, ํฐ์ผ ๊ฐ๊ฒฉ - ์์ฌ์ ํ์: `total_seats - sold_seats` ๊ณ์ฐ - Tailwind CSS๋ก ๋ฐ์ํ ๊ทธ๋ฆฌ๋ ๋ ์ด์์ (๋ชจ๋ฐ์ผ: 1์ด, ํ๋ธ๋ฆฟ: 2์ด, ๋ฐ์คํฌํฑ: 3์ด) 4. ๊ฐ ์นด๋์ "ํฐ์ผ ๊ตฌ๋งค" ๋ฒํผ ์ถ๊ฐ (ํด๋ฆญ ์ ํด๋น ๊ณต์ฐ ID๋ฅผ ์ํ๋ก ์ ์ฅํ์ฌ ๊ตฌ๋งค ํผ ํ์ ์ค๋น) 5. `src/App.jsx`์์ `<ShowList />` ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ์ธ์. ## ๊ธฐ๋ ๊ฒฐ๊ณผ - ๊ณต์ฐ ๋ชฉ๋ก์ด ์นด๋ ํํ๋ก ํ์๋จ - ์์ฌ์ ์ ๋ณด๊ฐ ์ค์๊ฐ์ผ๋ก ํ์๋จ - ๋ฐ์ํ ๋์์ธ ์ ์ฉ
๊ธฐ๋ ๊ฒฐ๊ณผ: React ์ฑ์์ Laravel API๋ก๋ถํฐ ๊ณต์ฐ ๋ชฉ๋ก์ ๋ถ๋ฌ์ ํ๋ฉด์ ์นด๋ ํํ๋ก ํ์ํฉ๋๋ค. ๊ฐ ๊ณต์ฐ์ ์์ฌ์ ์ ๋ณด๊ฐ ํจ๊ป ํ์๋ฉ๋๋ค.
## React ์ปดํฌ๋ํธ ๊ตฌํ - ํฐ์ผ ๊ตฌ๋งค ํผ
1. `src/components/TicketOrderForm.jsx` ์ปดํฌ๋ํธ๋ฅผ ์์ฑํ์ธ์.
2. Props๋ก ์ ํ๋ ๊ณต์ฐ ์ ๋ณด(`selectedShow`)๋ฅผ ๋ฐ์์ต๋๋ค.
3. ํผ ํ๋:
- ์ด๋ฆ (customer_name)
- ์ด๋ฉ์ผ (customer_email)
- ์ฐ๋ฝ์ฒ (customer_phone)
- ํฐ์ผ ์๋ (quantity, number input)
4. `useState`๋ก ํผ ์
๋ ฅ๊ฐ์ ๊ด๋ฆฌํ์ธ์.
5. ์ ์ถ ๋ฒํผ ํด๋ฆญ ์:
- Laravel API(`http://localhost:8000/api/ticket-orders`)๋ก POST ์์ฒญ
- ์์ฒญ body: `{ show_id, customer_name, customer_email, customer_phone, quantity }`
- ์ฑ๊ณต ์ ์๋ฆผ ๋ฉ์์ง ํ์ ๋ฐ ํผ ์ด๊ธฐํ
- ์คํจ ์ (์์ฌ์ ๋ถ์กฑ ๋ฑ) ์๋ฌ ๋ฉ์์ง ํ์
6. `ShowList` ์ปดํฌ๋ํธ์์ "ํฐ์ผ ๊ตฌ๋งค" ๋ฒํผ ํด๋ฆญ ์ `TicketOrderForm`์ ๋ชจ๋ฌ ๋๋ ์น์
์ผ๋ก ํ์ํ์ธ์.
7. ๊ตฌ๋งค ์๋ฃ ํ ๊ณต์ฐ ๋ชฉ๋ก์ ๋ค์ fetchํ์ฌ ์์ฌ์ ์
๋ฐ์ดํธ๋ฅผ ํ์ธํ์ธ์.
## ๊ธฐ๋ ๊ฒฐ๊ณผ
- ํฐ์ผ ๊ตฌ๋งค ํผ์ด ๋์ํ์ฌ Laravel API๋ก ์ฃผ๋ฌธ ๋ฐ์ดํฐ ์ ์ก
- ๊ตฌ๋งค ์ฑ๊ณต ์ ์์ฌ์์ด ์ค์๊ฐ์ผ๋ก ๊ฐ์
- ํผ ์ ํจ์ฑ ๊ฒ์ฌ ๋ฐ ์๋ฌ ์ฒ๋ฆฌ
๊ธฐ๋ ๊ฒฐ๊ณผ: ์ฌ์ฉ์๊ฐ ๊ณต์ฐ์ ์ ํํ๊ณ ํฐ์ผ ๊ตฌ๋งค ํผ์ ์์ฑํ์ฌ ์ ์ถํ๋ฉด, Laravel API๋ก ์ฃผ๋ฌธ ๋ฐ์ดํฐ๊ฐ ์ ์ก๋๊ณ ์์ฌ์์ด ์๋์ผ๋ก ์ ๋ฐ์ดํธ๋ฉ๋๋ค. ๊ตฌ๋งค ์๋ฃ ํ ๊ณต์ฐ ๋ชฉ๋ก์ด ์๋ก๊ณ ์นจ๋์ด ๋ณ๊ฒฝ๋ ์์ฌ์์ ํ์ธํ ์ ์์ต๋๋ค.
์ ์ถ๋ ์ํ (0)
๋ก๊ทธ์ธ ํ ์ ์ถ์์ง ์ ์ถ๋ ์ํ์ด ์์ต๋๋ค. ์ฒซ ๋ฒ์งธ ๋์ ์๊ฐ ๋์ด๋ณด์ธ์!