미니 온라인 마켓 - 상품 필터링 & 장바구니
mini-online-market-inertia
문제 설명
프로젝트 개요
Laravel 13.x + Inertia.js + React 19로 구축하는 실용적인 미니 온라인 쇼핑몰입니다. 상품 카탈로그, 카테고리별 필터링, 장바구니 담기, 주문서 작성까지 이커머스의 핵심 플로우를 경험할 수 있습니다.
필수 기능
- 상품 관리: 상품명, 가격, 카테고리, 이미지 URL, 재고 수량 저장
- 카테고리 필터링: 전자제품, 의류, 도서 등 카테고리별 상품 필터링
- 가격 범위 검색: 최소/최대 가격으로 상품 필터링
- 장바구니 시스템: 로그인한 사용자의 장바구니에 상품 추가/삭제/수량 조절
- 총 금액 계산: 장바구니 내 상품들의 합계 금액 실시간 표시
- 주문서 작성: 배송지 정보 입력 및 주문 요약 페이지
- 주문 내역: 사용자별 주문 히스토리 조회
선택 추가 기능 (보너스)
- 상품 재고 부족 시 "품절" 표시 및 장바구니 담기 비활성화
- 상품 정렬 기능 (가격 낮은순/높은순, 최신순)
- 찜하기(위시리스트) 기능
- 주문 상태 관리 (주문 접수 → 배송 중 → 배송 완료)
- 간단한 상품 리뷰 시스템
기술 스택
- 백엔드: Laravel 13.x (Eloquent ORM, 마이그레이션, 시더)
- 프론트엔드: React 19 (함수형 컴포넌트, Hooks)
- 풀스택 연결: Inertia.js (모노리스 아키텍처)
- 스타일링: Tailwind CSS
- 인증: Laravel Breeze (Inertia + React)
- 데이터베이스: SQLite (개발 편의성)
학습 목표
- Laravel 컨트롤러에서 Inertia::render()로 React 컴포넌트에 데이터 전달
- Eloquent 관계 설정 (User - Cart - CartItem - Product)
- React에서 Inertia Link와 Form 활용
- 장바구니 상태 관리 및 실시간 업데이트
- 필터링/검색 쿼리 빌더 활용
제약 조건
- • Laravel 13.x 필수 사용
- • React 19 + Inertia.js 모노리스 구조 (별도 API 라우트 없음)
- • Laravel Breeze (React + Inertia) starter kit으로 프로젝트 초기화
- • SQLite 데이터베이스 사용
- • Tailwind CSS로 스타일링
- • 상품 이미지는 외부 URL 또는 placeholder 이미지 사용
- • 결제 기능은 구현하지 않음 (주문서 작성까지만)
- • 모든 가격은 원화(KRW) 단위로 표시
- • 사용자 인증 필수 (장바구니/주문 기능)
프롬프트 레시피
아래 프롬프트를 순서대로 AI에게 보내면 됩니다. 복사 버튼을 눌러 바로 사용하세요.
mkdir mini-online-market-inertia && cd mini-online-market-inertia 이 폴더에서 Laravel 13.x + Inertia.js + React 19 프로젝트를 시작합니다. 다음 작업을 수행해주세요: 1. Laravel Breeze (React + Inertia) starter kit으로 프로젝트 초기화 - `composer create-project laravel/laravel .` - `composer require laravel/breeze --dev` - `php artisan breeze:install react` - `npm install && npm run dev` 2. .env 파일 설정 - DB_CONNECTION=sqlite - .env.example을 복사하여 .env 생성 - `touch database/database.sqlite` - `php artisan migrate` 3. 기본 인증 테스트 - 회원가입/로그인 페이지가 작동하는지 확인 - Breeze가 제공하는 기본 레이아웃 확인 4. Git 초기화 - `git init` - `git add .` - `git commit -m "Initial Laravel Breeze setup with React and Inertia"`
기대 결과: Laravel 13.x + Breeze + React + Inertia 프로젝트가 생성되고, SQLite 데이터베이스가 설정되며, 기본 인증 시스템이 작동합니다. npm run dev로 Vite 개발 서버가 실행되고, php artisan serve로 Laravel 서버가 실행됩니다.
이커머스 데이터베이스 구조를 설계하고 마이그레이션을 생성해주세요. 필요한 테이블: 1. **categories** 테이블 - id (primary key) - name (string, 카테고리명) - slug (string, URL용) - timestamps 2. **products** 테이블 - id (primary key) - category_id (foreign key to categories) - name (string, 상품명) - description (text, 상품 설명) - price (decimal, 가격) - stock_quantity (integer, 재고 수량) - image_url (string, nullable, 이미지 URL) - timestamps 3. **cart_items** 테이블 - id (primary key) - user_id (foreign key to users) - product_id (foreign key to products) - quantity (integer, 수량) - timestamps - unique index on (user_id, product_id) 4. **orders** 테이블 - id (primary key) - user_id (foreign key to users) - total_amount (decimal, 총 금액) - shipping_name (string, 받는 사람) - shipping_phone (string, 연락처) - shipping_address (text, 배송 주소) - status (enum: 'pending', 'processing', 'shipped', 'delivered') - timestamps 5. **order_items** 테이블 - id (primary key) - order_id (foreign key to orders) - product_id (foreign key to products) - product_name (string, 주문 시점 상품명) - product_price (decimal, 주문 시점 가격) - quantity (integer, 수량) - timestamps 마이그레이션 파일들을 생성하고 `php artisan migrate`를 실행해주세요.
기대 결과: 5개의 마이그레이션 파일이 생성되고 실행되어 SQLite 데이터베이스에 테이블들이 생성됩니다. 외래 키 제약조건과 인덱스가 올바르게 설정됩니다.
Eloquent 모델들을 생성하고 관계를 설정해주세요. 1. **Category 모델** (app/Models/Category.php) - products() hasMany 관계 2. **Product 모델** (app/Models/Product.php) - category() belongsTo 관계 - cartItems() hasMany 관계 - orderItems() hasMany 관계 - $casts에 price를 decimal:2로 설정 - scopeInStock() - 재고가 있는 상품만 필터링 - scopeByCategory($categoryId) - 카테고리별 필터링 - scopePriceRange($min, $max) - 가격 범위 필터링 3. **CartItem 모델** (app/Models/CartItem.php) - user() belongsTo 관계 - product() belongsTo 관계 - getSubtotalAttribute() - 수량 * 상품 가격 계산 4. **Order 모델** (app/Models/Order.php) - user() belongsTo 관계 - orderItems() hasMany 관계 - $casts에 total_amount를 decimal:2로 설정 5. **OrderItem 모델** (app/Models/OrderItem.php) - order() belongsTo 관계 - product() belongsTo 관계 - $casts에 product_price를 decimal:2로 설정 6. **User 모델 확장** - cartItems() hasMany 관계 - orders() hasMany 관계 각 모델에 $fillable 속성도 적절히 설정해주세요.
기대 결과: 5개의 Eloquent 모델이 생성되고 관계가 설정됩니다. User 모델이 확장되어 장바구니 및 주문 관계가 추가됩니다. 각 모델에 유용한 스코프와 접근자가 정의됩니다.
시더(Seeder)를 작성하여 테스트 데이터를 생성해주세요. **DatabaseSeeder.php**에 다음 데이터를 시드: 1. **카테고리** (5개) - 전자제품 - 의류 - 도서 - 식품 - 생활용품 2. **상품** (각 카테고리당 4~5개, 총 20개 이상) - 다양한 가격대 (10,000원 ~ 500,000원) - 재고 수량 (0~100 랜덤, 일부는 0으로 품절 표시) - image_url은 https://via.placeholder.com/300x300?text=[상품명] 형식 사용 - 실제 상품명과 설명 작성 (예: "갤럭시 북 노트북", "나이키 운동화", "클린 코드 도서" 등) 3. **테스트 사용자** (2명) - test@example.com / password - user@example.com / password `php artisan db:seed`를 실행해주세요.
기대 결과: DatabaseSeeder가 실행되어 5개 카테고리, 20개 이상의 상품, 2명의 테스트 사용자가 데이터베이스에 생성됩니다. 상품들은 다양한 가격과 재고를 가지고 있습니다.
상품 목록 페이지를 구현해주세요.
1. **ProductController** (app/Http/Controllers/ProductController.php)
- index() 메서드:
- 카테고리 필터링 (쿼리 파라미터 category_id)
- 가격 범위 필터링 (쿼리 파라미터 min_price, max_price)
- 정렬 (쿼리 파라미터 sort: 'price_asc', 'price_desc', 'latest')
- 페이지네이션 (12개씩)
- Inertia::render('Products/Index', [...]) 반환
- show($id) 메서드:
- 상품 상세 정보
- Inertia::render('Products/Show', [...]) 반환
2. **라우트 설정** (routes/web.php)
- Route::get('/products', [ProductController::class, 'index'])->name('products.index');
- Route::get('/products/{product}', [ProductController::class, 'show'])->name('products.show');
3. **React 컴포넌트** (resources/js/Pages/Products/Index.jsx)
- 상품 그리드 레이아웃 (3열)
- 카테고리 필터 사이드바 (모든 카테고리 목록)
- 가격 범위 입력 필터 (최소/최대 가격)
- 정렬 드롭다운
- 각 상품 카드:
- 이미지
- 상품명
- 가격 (원화 포맷: 1,000원)
- 재고 상태 (품절 시 "품절" 배지)
- "장바구니 담기" 버튼 (품절 시 비활성화)
- "상세보기" 링크
- 페이지네이션 컴포넌트
- Tailwind CSS로 반응형 디자인
4. **React 컴포넌트** (resources/js/Pages/Products/Show.jsx)
- 상품 상세 이미지
- 상품명, 가격, 설명
- 재고 수량 표시
- 수량 선택 input (1~재고 수량)
- "장바구니 담기" 버튼
- "목록으로" 링크
네비게이션 바에 "상품 목록" 링크도 추가해주세요.
기대 결과: 상품 목록 페이지가 작동하며, 카테고리/가격/정렬 필터링이 가능합니다. 상품 카드들이 그리드로 표시되고, 품절 상품은 시각적으로 구분됩니다. 상품 상세 페이지에서 상품 정보를 확인할 수 있습니다.
장바구니 기능을 구현해주세요.
1. **CartController** (app/Http/Controllers/CartController.php)
- index() 메서드:
- 로그인한 사용자의 장바구니 아이템 조회 (with product)
- 총 금액 계산
- Inertia::render('Cart/Index', [...]) 반환
- store(Request $request) 메서드:
- 상품 추가 (product_id, quantity 검증)
- 재고 확인 (재고 부족 시 에러)
- 이미 장바구니에 있으면 수량 증가, 없으면 새로 생성
- 성공 메시지와 함께 redirect()->back()
- update(Request $request, CartItem $cartItem) 메서드:
- 수량 변경 (quantity 검증, 재고 확인)
- redirect()->route('cart.index')
- destroy(CartItem $cartItem) 메서드:
- 장바구니 아이템 삭제
- redirect()->route('cart.index')
2. **라우트 설정** (routes/web.php)
- Route::middleware('auth')->group(function() {
Route::get('/cart', [CartController::class, 'index'])->name('cart.index');
Route::post('/cart', [CartController::class, 'store'])->name('cart.store');
Route::patch('/cart/{cartItem}', [CartController::class, 'update'])->name('cart.update');
Route::delete('/cart/{cartItem}', [CartController::class, 'destroy'])->name('cart.destroy');
});
3. **React 컴포넌트** (resources/js/Pages/Cart/Index.jsx)
- 장바구니 아이템 목록 테이블
- 상품 이미지 (썸네일)
- 상품명
- 단가
- 수량 조절 (-, input, + 버튼)
- 소계 (단가 * 수량)
- 삭제 버튼
- 총 금액 표시 (크고 강조)
- "주문하기" 버튼 (장바구니가 비어있으면 비활성화)
- "쇼핑 계속하기" 링크
- 빈 장바구니 상태 처리 ("장바구니가 비어있습니다" 메시지)
4. **상품 목록/상세 페이지 수정**
- "장바구니 담기" 버튼 클릭 시 CartController@store로 Inertia form 전송
- 성공 시 토스트 메시지 표시
네비게이션 바에 "장바구니" 링크와 장바구니 아이템 개수 배지도 추가해주세요.
기대 결과: 장바구니 기능이 완성됩니다. 상품을 장바구니에 담을 수 있고, 장바구니 페이지에서 수량 조절 및 삭제가 가능합니다. 총 금액이 실시간으로 계산되어 표시됩니다. 재고 부족 시 적절한 에러 메시지가 표시됩니다.
주문 기능을 구현해주세요.
1. **OrderController** (app/Http/Controllers/OrderController.php)
- create() 메서드:
- 장바구니 아이템 확인 (비어있으면 redirect)
- 총 금액 계산
- Inertia::render('Orders/Create', [...]) 반환
- store(Request $request) 메서드:
- 배송 정보 검증 (shipping_name, shipping_phone, shipping_address)
- 장바구니 아이템 재확인 및 재고 확인
- DB 트랜잭션:
- Order 생성
- OrderItem들 생성 (장바구니 각 아이템을 OrderItem으로 변환)
- Product 재고 차감
- 장바구니 비우기
- 성공 시 redirect()->route('orders.show', $order)
- show(Order $order) 메서드:
- 주문 상세 정보 (with orderItems.product)
- 본인 주문만 조회 가능하도록 권한 확인
- Inertia::render('Orders/Show', [...]) 반환
- index() 메서드:
- 로그인한 사용자의 주문 내역 (최신순)
- Inertia::render('Orders/Index', [...]) 반환
2. **라우트 설정** (routes/web.php)
- Route::middleware('auth')->group(function() {
Route::get('/orders', [OrderController::class, 'index'])->name('orders.index');
Route::get('/orders/create', [OrderController::class, 'create'])->name('orders.create');
Route::post('/orders', [OrderController::class, 'store'])->name('orders.store');
Route::get('/orders/{order}', [OrderController::class, 'show'])->name('orders.show');
});
3. **React 컴포넌트** (resources/js/Pages/Orders/Create.jsx)
- 주문 요약 (장바구니 아이템 목록, 총 금액)
- 배송 정보 입력 폼:
- 받는 사람 이름
- 연락처
- 배송 주소 (textarea)
- "주문하기" 버튼
- 유효성 검사 에러 표시
4. **React 컴포넌트** (resources/js/Pages/Orders/Show.jsx)
- 주문 완료 메시지
- 주문 번호, 주문 일시
- 주문 상품 목록 (상품명, 수량, 가격)
- 배송 정보 (받는 사람, 연락처, 주소)
- 총 결제 금액
- "주문 내역으로" 링크
5. **React 컴포넌트** (resources/js/Pages/Orders/Index.jsx)
- 주문 내역 목록 (카드 형식)
- 각 주문:
- 주문 번호, 주문 일시
- 대표 상품명 + "외 N개"
- 총 금액
- 주문 상태 (배지)
- "상세보기" 버튼
장바구니 페이지의 "주문하기" 버튼을 orders.create 라우트로 연결해주세요. 네비게이션 바에 "주문 내역" 링크도 추가해주세요.
기대 결과: 주문 기능이 완성됩니다. 장바구니에서 주문서 작성 페이지로 이동하여 배송 정보를 입력하고 주문할 수 있습니다. 주문 완료 후 주문 상세 페이지에서 주문 정보를 확인할 수 있으며, 주문 내역 페이지에서 과거 주문들을 조회할 수 있습니다. 주문 시 재고가 차감되고 장바구니가 비워집니다.
UI/UX 개선 및 마무리 작업을 해주세요.
1. **공통 레이아웃 개선**
- 로고/사이트명 추가
- 반응형 네비게이션 (모바일 햄버거 메뉴)
- 사용자 메뉴 드롭다운 (프로필, 주문내역, 로그아웃)
- 장바구니 아이콘 + 아이템 개수 배지 (실시간 업데이트)
2. **홈페이지** (resources/js/Pages/Welcome.jsx 또는 Dashboard.jsx)
- 히어로 섹션 ("미니 온라인 마켓에 오신 것을 환영합니다")
- 인기 상품 섹션 (최신 상품 4개)
- "전체 상품 보기" 버튼
- 카테고리 바로가기 버튼들
3. **에러 처리 및 사용자 피드백**
- 성공/에러 토스트 메시지 (Inertia flash 메시지 활용)
- 로딩 상태 표시 (버튼 클릭 시 spinner)
- 빈 상태 처리 (상품 없음, 장바구니 비어있음, 주문 내역 없음)
4. **접근성 및 사용성**
- 모든 이미지에 alt 텍스트
- 포커스 스타일 개선
- 가격 포맷팅 (1000 → 1,000원)
- 날짜 포맷팅 (주문 일시)
5. **테스트 및 디버깅**
- 비로그인 상태에서 장바구니/주문 접근 시 로그인 페이지로 리다이렉트 확인
- 재고 부족 시 에러 메시지 확인
- 다른 사용자의 주문 접근 시 403 에러 확인
- 페이지네이션 작동 확인
- 모든 필터링 조합 테스트
6. **README.md 작성**
- 프로젝트 소개
- 설치 방법
- 시더 실행 방법
- 테스트 계정 정보
- 주요 기능 스크린샷
최종 Git 커밋도 해주세요.
기대 결과: 전체 애플리케이션이 완성되고 UI/UX가 개선됩니다. 에러 처리가 견고해지고, 사용자 피드백이 명확하게 표시됩니다. README.md가 작성되어 다른 개발자가 프로젝트를 이해하고 실행할 수 있습니다. 모든 기능이 정상적으로 작동하며, 실용적인 미니 이커머스 사이트가 완성됩니다.