1. 프로젝트 개요
https://github.com/JHParrrk/book_market
GitHub - JHParrrk/book_market
Contribute to JHParrrk/book_market development by creating an account on GitHub.
github.com
Book Market은 사용자가 도서를 검색하고, 장바구니에 담아 주문하며, 리뷰를 작성하고 다른 사용자와 소통할 수 있는 기능을 갖춘 온라인 서점 플랫폼입니다. 이 프로젝트는 백엔드 시스템을 중심으로 견고한 데이터베이스 구조와 확장성을 고려한 아키텍처 설계를 목표로 진행되었습니다.
주요 기능으로는 사용자 인증 및 권한 관리, 계층형 카테고리, 도서 관리, 장바구니, 주문 처리, 리뷰 및 좋아요 기능 등이 포함됩니다.
2. 결과물 소개
2.1. 주요 기능
- 사용자 관리: 회원가입, 로그인, 정보 수정 및 역할(일반 사용자/관리자)에 따른 접근 제어 기능을 제공합니다.
- 도서 및 카테고리: 계층 구조를 가진 카테고리별로 도서를 분류하고, 도서 상세 정보 및 검색 기능을 구현했습니다.
- 주문 시스템: 장바구니에 담긴 도서를 기반으로 주문을 생성하고, 배송 정보와 총 결제 금액을 관리합니다.
- 리뷰 및 상호작용: 사용자는 구매한 도서에 대해 별점과 리뷰를 남길 수 있으며, 다른 사용자의 리뷰나 도서에 '좋아요'를 표시할 수 있습니다.
2.2. 데이터베이스 설계 (ERD)
프로젝트의 모든 데이터는 MySQL(MariaDB) 기반의 관계형 데이터베이스에 저장됩니다. 전체 스키마는 사용자와 도서, 주문, 리뷰 등 각 도메인 간의 관계를 명확하게 정의하고 데이터 무결성을 보장하도록 설계되었습니다.

2.3. API 명세 (Endpoints)
** 인증 (Authentication)**
- 회원가입
PUBLICPOST /users/register- 설명: 새로운 사용자를 시스템에 등록합니다.
- 요청 본문 (Body):
{ "email": "user@example.com", "password": "password123", "name": "John Doe", "address": "(선택) 서울시 강남구", "phone_number": "(선택) 010-1234-5678" }
- 로그인
PUBLICPOST /users/login- 설명: 사용자 인증 후
accessToken과refreshToken을 발급합니다. - 요청 본문 (Body):
{ "email": "user@example.com", "password": "password123" }- 응답:
accessToken은 JSON으로,refreshToken은HttpOnly쿠키로 전송됩니다.
- 설명: 사용자 인증 후
- Access Token 갱신
PUBLIC (Requires Refresh Token)POST /users/refresh-token- 설명: 만료된
accessToken을refreshToken을 이용해 재발급합니다. - 요청: 본문 없이, 브라우저의
HttpOnly쿠키에 담긴refreshToken을 통해 자동으로 요청됩니다.
- 설명: 만료된
- 로그아웃
AUTHPOST /users/logout- 설명: 현재 세션을 종료하고, 서버와 클라이언트의
refreshToken을 모두 삭제합니다.
- 설명: 현재 세션을 종료하고, 서버와 클라이언트의
** 사용자 정보 (User Profile)**
- 내 정보 조회
AUTHGET /users/me- 설명: 현재 로그인된 사용자 본인의 상세 정보를 조회합니다.
- 특정 사용자 정보 조회
AUTH / ADMINGET /users/:id- 설명: 특정 ID를 가진 사용자의 정보를 조회합니다.
- 인가 규칙:
- 일반 사용자 (member): 자기 자신의 정보(
id가 본인 ID와 일치)만 조회 가능합니다. - 관리자 (admin): 모든 사용자의 정보를 조회할 수 있습니다.
- 일반 사용자 (member): 자기 자신의 정보(
- 사용자 정보 수정
AUTH / ADMINPUT /users/:id- 설명: 특정 사용자의 정보를 수정합니다. (비밀번호 변경 포함)
- 인가 규칙:
- 일반 사용자 (member): 자기 자신의 정보만 수정 가능합니다.
- 관리자 (admin): 모든 사용자의 정보를 수정할 수 있습니다.
- 회원 탈퇴 (계정 비활성화)
AUTHDELETE /users/:id- 설명: 사용자 계정을 비활성화(Soft-delete)합니다.
- 인가 규칙:
- 오직 사용자 본인만 자신의 계정을 삭제할 수 있습니다. (관리자도 타인 계정 삭제 불가)
** 관리자 전용 (Admin-Only)**
- 모든 사용자 목록 조회
ADMINGET /users- 설명: 시스템에 등록된 모든 사용자 목록을 조회합니다. (관리자 전용)
- 사용자 역할 변경
ADMINPUT /users/:userId/role- 설명: 특정 사용자의 역할을
member또는admin으로 변경합니다. (관리자 전용) - 요청 본문 (Body):
{ "role": "admin" }- 제약: 관리자는 자기 자신의 역할은 변경할 수 없습니다.
- 설명: 특정 사용자의 역할을
** 도서 (Books)**
- 도서 목록 조회 및 검색
PUBLICGET /books- 설명: 전체 도서 목록을 조회하거나, 쿼리 파라미터를 통해 검색, 필터링, 페이지네이션을 수행합니다.
- 쿼리 파라미터:
keyword(선택): 도서 제목, 저자, 요약 내용에서 검색할 키워드category_id(선택): 특정 카테고리 및 모든 하위 카테고리 내의 도서 필터링page(선택): 조회할 페이지 번호 (기본값: 1)limit(선택): 페이지 당 도서 수 (기본값: 8)
- 신간 도서 조회
PUBLICGET /books/new- 설명: 최근 1개월 내에 출간된 신간 도서 목록을 조회합니다.
- 쿼리 파라미터:
category_id(선택): 특정 카테고리 및 하위 카테고리 내 신간 필터링page(선택): 조회할 페이지 번호 (기본값: 1)limit(선택): 페이지 당 도서 수 (기본값: 4)
- 도서 상세 정보 조회
PUBLIC / AUTH (Optional)GET /books/:bookId- 설명: 특정 도서의 상세 정보를 조회합니다.
- 인증/인가:
- 비로그인 사용자 (PUBLIC): 도서의 기본 정보만 조회합니다.
- 로그인 사용자 (AUTH): 도서 정보에 더해, 현재 사용자의 해당 도서 '좋아요' 여부(
isLiked)를 함께 반환합니다.
- 도서 '좋아요' 토글
AUTHPOST /books/:bookId/like- 설명: 특정 도서에 대한 '좋아요' 상태를 추가하거나 취소합니다. 로그인한 사용자만 가능합니다.
** 특정 도서의 리뷰 (Reviews)**
- 리뷰 목록 조회
PUBLIC / AUTH (Optional)GET /books/:bookId/reviews- 설명: 특정 도서에 달린 모든 리뷰 목록을 조회합니다.
- 인증/인가:
- 로그인 사용자 (AUTH)의 경우, 각 리뷰에 대한 '좋아요' 여부(
isLiked)를 함께 반환합니다.
- 로그인 사용자 (AUTH)의 경우, 각 리뷰에 대한 '좋아요' 여부(
- 리뷰 작성
AUTHPOST /books/:bookId/reviews- 설명: 특정 도서에 새로운 리뷰를 작성합니다. 로그인한 사용자만 가능합니다.
- 리뷰 수정
AUTHPUT /books/:bookId/reviews/:reviewId- 설명: 자신이 작성한 리뷰를 수정합니다. 해당 리뷰를 작성한 사용자만 수정할 수 있습니다.
- 리뷰 삭제
AUTHDELETE /books/:bookId/reviews/:reviewId- 설명: 자신이 작성한 리뷰를 삭제합니다. 해당 리뷰를 작성한 사용자만 삭제할 수 있습니다.
- 리뷰 '좋아요' 토글
AUTHPOST /books/:bookId/reviews/:reviewId/like- 설명: 특정 리뷰에 대한 '좋아요' 상태를 추가하거나 취소합니다. 로그인한 사용자만 가능합니다.
카테고리 (Categories)
모든 카테고리 조회
GET /categories
장바구니 (Shopping Cart)
장바구니에 상품 추가
POST /carts
Authorization: Bearer <access_token>
Content-Type: application/json
- **장바구니에 상품 추가 (Bulk)** `AUTH`
`POST /carts`
- **설명**: 하나 또는 여러 개의 상품을 장바구니에 추가하거나, 이미 있는 상품의 수량을 더합니다(UPSERT).
- **요청 본문 (Body)**:
```json
[
{ "book_id": 1, "quantity": 2 },
{ "book_id": 3, "quantity": 1 }
]
```
- **장바구니 목록 조회** `AUTH`
`GET /carts`
- **설명**: 현재 사용자의 장바구니에 담긴 모든 상품 목록을 조회합니다.
- **장바구니 상품 수량 변경** `AUTH`
`PUT /carts/:cartItemId`
- **설명**: 장바구니에 담긴 특정 상품의 수량을 변경합니다.
- **요청 본문 (Body)**:
```json
{
"quantity": 3
}
```
- **장바구니 상품 삭제** `AUTH`
`DELETE /carts/:cartItemId`
- **설명**: 장바구니에서 특정 상품을 제거합니다.
{
"bookId": 1,
"quantity": 2
}
장바구니 상품 조회
GET /carts
Authorization: Bearer <access_token>
장바구니 상품 수량 수정
PUT /carts/:cartItemId
Authorization: Bearer <access_token>
Content-Type: application/json
{
"quantity": 3
}
장바구니 상품 삭제
DELETE /carts/:cartItemId
Authorization: Bearer <access_token>
주문 (Orders)
- 주문 생성
AUTHPOST /orders- 설명: 장바구니에 담긴 상품들을 기반으로 새로운 주문을 생성합니다.
- 요청 본문 (Body):
{ "delivery_info": { "recipient": "...", "address": "...", "phone": "..." }, "cart_item_ids": [1, 2, 3], "use_default_address": false }
- 내 주문 목록 조회
AUTHGET /orders- 설명: 현재 사용자의 모든 주문 내역을 조회합니다.
- 주문 상세 정보 조회
AUTHGET /orders/:orderId- 설명: 특정 주문의 상세 정보를 조회합니다.
- 인가 규칙: 본인의 주문만 조회 가능합니다.
관리자 라우트 (Admin Routes)
모든 사용자 조회 (관리자 전용)
GET /users
Authorization: Bearer <admin_access_token>
사용자 역할 수정 (관리자 전용)
PUT /users/:userId/role
Authorization: Bearer <admin_access_token>
Content-Type: application/json
{
"role": "admin"
}
주문 상태 수정 (관리자 전용)
PUT /orders/:orderId/status
Authorization: Bearer <admin_access_token>
Content-Type: application/json
{
"status": "배송완료"
}
범례:
PUBLIC: 인증 없이 누구나 접근 가능AUTH: 로그인을 통한 인증(Access Token)이 반드시 필요한 기능ADMIN: 관리자(Admin) 권한이 있어야만 접근 가능한 기능
3. 개발 후기 및 특징적인 부분
이번 프로젝트를 진행하며 몇 가지 핵심적인 설계 포인트를 적용했습니다. 이는 시스템의 확장성과 유지보수성을 높이는 데 기여했습니다.
3.1. 인가 구조: 인증을 넘어 관리자 계정 구현
단순한 로그인(Authentication)을 넘어, 역할 기반 접근 제어(RBAC)를 구현하여 인가(Authorization) 구조를 설계했습니다.
- 구현:
users테이블에role컬럼 ('member','admin')을 추가했습니다. - 기대 효과: 이를 통해 특정 API나 기능(예: 도서 정보 등록, 사용자 관리)은
admin역할을 가진 사용자만 접근할 수 있도록 제한할 수 있습니다. 이는 향후 관리자 페이지와 같은 고급 기능을 안정적으로 추가할 수 있는 기반이 됩니다.
3.2. 폴더 구조: Nest.js 대비를 위한 선행적 적용
Node.js 백엔드 개발 시 유지보수성을 높이기 위해, 향후 Nest.js 프레임워크로의 마이그레이션 또는 아키텍처 전환을 염두에 둔 폴더 구조를 선행적으로 도입했습니다.
- 구현: 도메인(기능)을 기준으로 폴더를 분리하는 모듈형 구조를 적용했습니다. (예:
/users,/books,/orders등) - 기대 효과: 각 폴더는 자체적인 Controller, Service, Repository(DAO) 패턴을 따르도록 구성하여 기능 간의 결합도를 낮추고 코드의 응집도를 높였습니다. 이는 Nest.js의 모듈 시스템과 유사하여, 기술 스택 변경 시 발생하는 비용과 시간을 최소화할 수 있습니다.
3.3. 카테고리 DB 설계 및 재귀 함수
도서 카테고리를 효율적으로 관리하기 위해 자기 참조(Self-referencing) 관계를 이용한 계층형 데이터 구조를 설계했습니다.
- 구현:
categories테이블 내에parent_id컬럼을 두어, 특정 카테고리가 다른 카테고리의 하위 항목이 될 수 있도록 설계했습니다. - 활용: 프론트엔드에 전체 카테고리 목록(예: 내비게이션 메뉴)을 트리 형태로 제공하기 위해, 백엔드에서 재귀 함수 또는 CTE(Common Table Expressions)를 사용해 데이터를 조회하고 가공하는 로직을 구현했습니다. 이 방식은 카테고리 깊이에 제한 없이 유연하게 구조를 확장할 수 있는 큰 장점을 가집니다.
4. 결론
Book Market 프로젝트는 단순한 CRUD를 넘어 확장성 있는 아키텍처와 견고한 데이터베이스 설계를 고민하고 적용해볼 수 있었던 의미 있는 경험이었습니다. 특히, 역할 기반 인가 구조, 모듈형 폴더 설계, 재귀적인 데이터 처리 방식은 앞으로의 백엔드 개발에 훌륭한 자산이 될 것이라 확신합니다.
'Programmers' 카테고리의 다른 글
| [43일차]타입스크립트 2일차: 타입과 객체 지향 프로그래밍의 통합. (0) | 2025.11.11 |
|---|---|
| [42일차]타입스크립트: 언어 개념과 기본 설정. (0) | 2025.11.10 |
| [41일차]프로그래밍 패러다임과 객체 지향 개념의 TS에서의 활용 (0) | 2025.11.06 |
| [40일차] C언어와 JavaScript의 메모리 관리 및 포인터 (0) | 2025.11.05 |
| [39일차]프로그래밍 기초 개념, 컴파일 언어, 메모리 구조, 변수와 상수 (0) | 2025.11.04 |