pgms

[6주차] - [9기] 타입스크립트로 함께하는 웹 풀 사이클 개발(React, Node.js) 10회차 - 25

Ejah 2026. 2. 10. 17:28

dbdiagram.io 를 사용한 ERD 그려보기

 

ERD → 기능 → API

이번 회차에서는 “서점(Book Store)” 도메인을 기준으로 ERD를 먼저 잡고, 화면에서 필요한 기능을 정의한 뒤, 그 기능을 만족시키는 API 스펙을 구체화하는 흐름으로 설계를 진행했다. 핵심은 “화면에서 필요한 데이터”를 기준으로 API를 만들되, 데이터 모델(ERD)행위(좋아요/장바구니/주문) 가 자연스럽게 맞물리도록 연결하는 것이다.

 

1) dbdiagram.io로 ERD 먼저 고정하기

먼저 dbdiagram.io로 테이블을 텍스트 기반으로 정의하고, 시각화된 다이어그램으로 관계를 확인했다. 이 단계에서 확정한 테이블은 크게 다음 흐름을 가진다.

  • users: 로그인/사용자 식별
  • books: 도서 상세/목록의 핵심 엔티티
  • likes: 사용자-도서 좋아요 관계(교차 테이블)
  • posts: (리뷰/게시글 성격의 확장 가능성)

ERD를 먼저 잡아두니 이후 API 설계에서 “어떤 데이터가 어디에 저장되는지”가 명확해져서, 요청/응답 JSON을 설계할 때도 근거가 생겼다.

 

2) 화면(요구사항)에서 API 요구를 뽑아내기

상세 화면 요구사항을 보면 “도서 기본 정보 + 좋아요 + 장바구니 담기”가 핵심이다.
특히 좋아요는 “총 좋아요 수”와 “내가 눌렀는지 여부”가 같이 필요하고, 장바구니는 비로그인 시 로그인 유도까지 포함된다.

즉 화면 요구사항을 API 관점으로 번역하면:

  • 도서 상세 조회: 책 정보 + (좋아요 수, 내 좋아요 여부) + (장바구니 담기 가능)
  • 좋아요 토글: 추가/취소
  • 장바구니 CRUD: 담기/조회/삭제
  • 주문 생성: 장바구니에서 선택한 항목으로 주문 생성 + 배송/결제 입력
  • 주문 조회: 목록/상세

이 “화면이 원하는 것”이 API의 스펙을 결정한다.

 

3) 좋아요 API 설계 포인트

좋아요는 “유저가 특정 도서에 대해 좋아요 관계를 만든다/지운다”로 단순하다. 그래서 엔드포인트도 도서 ID를 기준으로 직관적으로 잡았다.

  • 좋아요 추가: POST /likes/{bookId} (성공 200)
  • 좋아요 취소: DELETE /likes/{bookId} (성공 200)

여기서 중요한 건 Request Body가 비어도 된다는 점. “행위” 자체가 리소스 생성/삭제이기 때문에, 로그인 유저 정보는 보통 토큰에서 꺼내면 된다.

 

4) 장바구니 API 설계 포인트

장바구니는 “담기(수량 포함) / 조회 / 삭제”가 기본이다.

(1) 담기

  • POST /cart (성공 201)
  • Body: { bookId, count }

여기서 201을 준 건 “장바구니 항목이 생성됨”을 명확히 표현해서 좋다.

(2) 조회

  • GET /cart (성공 200)
  • Response: 장바구니 아이템 배열(예: cartItemId, bookId, title, summary, count, price)

조회 응답이 “책 테이블을 조인해서 화면에 필요한 최소 정보(title/summary/price)를 같이 내려준다”는 점이 설계적으로 매우 실용적이다. 프론트가 화면을 그리기 위해 다시 /books/{id}를 여러 번 호출하지 않아도 된다.

(3) 삭제

  • DELETE /cart/{bookId} (성공 200)

삭제 기준을 bookId로 잡으면 간단하지만, 실제로는 동일 도서가 1개만 존재한다는 전제가 들어간다. 만약 “같은 도서를 여러 옵션으로 담는 구조”가 된다면 cartItemId가 더 안전해질 수 있다(확장 포인트).

 

5) 주문(결제) API 설계 포인트

주문 화면 요구사항은 “장바구니에서 선택한 상품 목록 노출 + 배송정보 입력 + 결제 수단 선택 + 총 금액 확인”이다.
따라서 주문 생성 API는 장바구니 선택 항목 + 배송 정보 + 총액을 한 번에 받는 형태로 설계했다.

(1) 주문 생성

  • POST /orders (성공 200)
  • Body 구조
    • items: [{ cartItemId, bookId, count }, ...]
    • delivery: { address, receiver, contact }
    • totalPrice

여기서 “주문 성공 시 장바구니에서 주문된 상품은 delete”라는 처리 흐름도 같이 명시되어 있어서, 트랜잭션 관점에서 백엔드 구현 순서(주문 생성 → 주문아이템 insert → 장바구니 delete)가 자연스럽게 도출된다.

(2) 주문 목록(내역) 조회

  • GET /orders (성공 200)
  • Response: order_id, created_at, delivery(주소/수령인/연락처), bookTitle(대표), totalPrice, totalCount

목록에서 “대표 책 제목 + 총 수량/금액”만 내려주는 건 화면/성능 관점에서 적절한 요약이다.

(3) 주문 상세 상품 조회

  • GET /orders/{orderId} (성공 200)
  • Response: 주문에 포함된 도서들의 배열( bookId, bookTitle, author, price, count …)

목록은 요약, 상세는 펼침. UI 요구사항(오른쪽 토글로 상세 노출)과 API가 잘 맞는다.

 

6) 구현 순서(추천)와 체크리스트

설계를 끝냈다면 구현은 다음 순서가 안전하다.

  1. ERD 기반 테이블 생성 + 더미 데이터
  2. GET /cart, POST /cart 먼저 구현
    • 화면에 바로 연결해서 성공 경험 만들기
  3. POST/DELETE /likes/{bookId} 구현
    • “내 좋아요 여부”는 상세 조회에 붙일지, 별도 API로 할지 결정
  4. POST /orders 구현
    • 트랜잭션(주문/주문아이템/장바구니 삭제) 안정화
  5. GET /orders, GET /orders/{orderId} 구현
    • 목록/상세 UI 토글과 함께 검증

체크리스트:

  • 상태코드 일관성(장바구니 생성 201처럼 의도가 드러나는지)
  • Response는 “화면이 바로 그릴 수 있는 데이터”인지(조인 결과 포함 여부)
  • 삭제 기준(bookId vs cartItemId) 같은 설계 전제가 문서에 남아있는지

 

마무리

이번 설계의 가장 좋은 점은, “API를 먼저 만들기”가 아니라 ERD → 화면 요구사항 → API 스펙 순서로 내려오면서 근거 있는 설계를 했다는 것이다.
이 흐름을 한 번 제대로 잡아두면, 이후 기능이 늘어나도(리뷰 작성/배송 추적/베스트 목록 등) “어디에 데이터를 두고, 어떤 응답이 필요한지”를 흔들리지 않고 확장할 수 있다.