Programmers

[과제] Book Market 프로젝트 결과 보고서

PARKpatchnotes 2025. 11. 6. 16:28

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)**

  • 회원가입 PUBLIC
    POST /users/register
    • 설명: 새로운 사용자를 시스템에 등록합니다.
    • 요청 본문 (Body):
    • { "email": "user@example.com", "password": "password123", "name": "John Doe", "address": "(선택) 서울시 강남구", "phone_number": "(선택) 010-1234-5678" }
  • 로그인 PUBLIC
    POST /users/login
    • 설명: 사용자 인증 후 accessTokenrefreshToken을 발급합니다.
    • 요청 본문 (Body):
    • { "email": "user@example.com", "password": "password123" }
    • 응답: accessToken은 JSON으로, refreshTokenHttpOnly 쿠키로 전송됩니다.
  • Access Token 갱신 PUBLIC (Requires Refresh Token)
    POST /users/refresh-token
    • 설명: 만료된 accessTokenrefreshToken을 이용해 재발급합니다.
    • 요청: 본문 없이, 브라우저의 HttpOnly 쿠키에 담긴 refreshToken을 통해 자동으로 요청됩니다.
  • 로그아웃 AUTH
    POST /users/logout
    • 설명: 현재 세션을 종료하고, 서버와 클라이언트의 refreshToken을 모두 삭제합니다.

** 사용자 정보 (User Profile)**

  • 내 정보 조회 AUTH
    GET /users/me
    • 설명: 현재 로그인된 사용자 본인의 상세 정보를 조회합니다.
  • 특정 사용자 정보 조회 AUTH / ADMIN
    GET /users/:id
    • 설명: 특정 ID를 가진 사용자의 정보를 조회합니다.
    • 인가 규칙:
      • 일반 사용자 (member): 자기 자신의 정보(id가 본인 ID와 일치)만 조회 가능합니다.
      • 관리자 (admin): 모든 사용자의 정보를 조회할 수 있습니다.
  • 사용자 정보 수정 AUTH / ADMIN
    PUT /users/:id
    • 설명: 특정 사용자의 정보를 수정합니다. (비밀번호 변경 포함)
    • 인가 규칙:
      • 일반 사용자 (member): 자기 자신의 정보만 수정 가능합니다.
      • 관리자 (admin): 모든 사용자의 정보를 수정할 수 있습니다.
  • 회원 탈퇴 (계정 비활성화) AUTH
    DELETE /users/:id
    • 설명: 사용자 계정을 비활성화(Soft-delete)합니다.
    • 인가 규칙:
      • 오직 사용자 본인만 자신의 계정을 삭제할 수 있습니다. (관리자도 타인 계정 삭제 불가)

** 관리자 전용 (Admin-Only)**

  • 모든 사용자 목록 조회 ADMIN
    GET /users
    • 설명: 시스템에 등록된 모든 사용자 목록을 조회합니다. (관리자 전용)
  • 사용자 역할 변경 ADMIN
    PUT /users/:userId/role
    • 설명: 특정 사용자의 역할을 member 또는 admin으로 변경합니다. (관리자 전용)
    • 요청 본문 (Body):
    • { "role": "admin" }
    • 제약: 관리자는 자기 자신의 역할은 변경할 수 없습니다.

** 도서 (Books)**

  • 도서 목록 조회 및 검색 PUBLIC
    GET /books
    • 설명: 전체 도서 목록을 조회하거나, 쿼리 파라미터를 통해 검색, 필터링, 페이지네이션을 수행합니다.
    • 쿼리 파라미터:
      • keyword (선택): 도서 제목, 저자, 요약 내용에서 검색할 키워드
      • category_id (선택): 특정 카테고리 및 모든 하위 카테고리 내의 도서 필터링
      • page (선택): 조회할 페이지 번호 (기본값: 1)
      • limit (선택): 페이지 당 도서 수 (기본값: 8)
  • 신간 도서 조회 PUBLIC
    GET /books/new
    • 설명: 최근 1개월 내에 출간된 신간 도서 목록을 조회합니다.
    • 쿼리 파라미터:
      • category_id (선택): 특정 카테고리 및 하위 카테고리 내 신간 필터링
      • page (선택): 조회할 페이지 번호 (기본값: 1)
      • limit (선택): 페이지 당 도서 수 (기본값: 4)
  • 도서 상세 정보 조회 PUBLIC / AUTH (Optional)
    GET /books/:bookId
    • 설명: 특정 도서의 상세 정보를 조회합니다.
    • 인증/인가:
      • 비로그인 사용자 (PUBLIC): 도서의 기본 정보만 조회합니다.
      • 로그인 사용자 (AUTH): 도서 정보에 더해, 현재 사용자의 해당 도서 '좋아요' 여부(isLiked)를 함께 반환합니다.
  • 도서 '좋아요' 토글 AUTH
    POST /books/:bookId/like
    • 설명: 특정 도서에 대한 '좋아요' 상태를 추가하거나 취소합니다. 로그인한 사용자만 가능합니다.

** 특정 도서의 리뷰 (Reviews)**

  • 리뷰 목록 조회 PUBLIC / AUTH (Optional)
    GET /books/:bookId/reviews
    • 설명: 특정 도서에 달린 모든 리뷰 목록을 조회합니다.
    • 인증/인가:
      • 로그인 사용자 (AUTH)의 경우, 각 리뷰에 대한 '좋아요' 여부(isLiked)를 함께 반환합니다.
  • 리뷰 작성 AUTH
    POST /books/:bookId/reviews
    • 설명: 특정 도서에 새로운 리뷰를 작성합니다. 로그인한 사용자만 가능합니다.
  • 리뷰 수정 AUTH
    PUT /books/:bookId/reviews/:reviewId
    • 설명: 자신이 작성한 리뷰를 수정합니다. 해당 리뷰를 작성한 사용자만 수정할 수 있습니다.
  • 리뷰 삭제 AUTH
    DELETE /books/:bookId/reviews/:reviewId
    • 설명: 자신이 작성한 리뷰를 삭제합니다. 해당 리뷰를 작성한 사용자만 삭제할 수 있습니다.
  • 리뷰 '좋아요' 토글 AUTH
    POST /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)

  • 주문 생성 AUTH
    POST /orders
    • 설명: 장바구니에 담긴 상품들을 기반으로 새로운 주문을 생성합니다.
    • 요청 본문 (Body):
    • { "delivery_info": { "recipient": "...", "address": "...", "phone": "..." }, "cart_item_ids": [1, 2, 3], "use_default_address": false }
  • 내 주문 목록 조회 AUTH
    GET /orders
    • 설명: 현재 사용자의 모든 주문 내역을 조회합니다.
  • 주문 상세 정보 조회 AUTH
    GET /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를 넘어 확장성 있는 아키텍처와 견고한 데이터베이스 설계를 고민하고 적용해볼 수 있었던 의미 있는 경험이었습니다. 특히, 역할 기반 인가 구조, 모듈형 폴더 설계, 재귀적인 데이터 처리 방식은 앞으로의 백엔드 개발에 훌륭한 자산이 될 것이라 확신합니다.