Projects/[Spring] Coffee Shop Project

API 명세서 만들어보기

montmer27 2026. 4. 1. 16:59

필수 API

분류 API명 캐싱 적용 동시성 제어 인증/인가 여부 외부 api 연동 비동기 처리 가능
Must 커피 메뉴 목록 조회 O        
Must 포인트 충전*   O(낙관적) O O(포트원)  
Must 커피 주문(장바구니 생성)     O    
Must 포인트 결제*(장바구니 결제)   O(분산락) O    
Must 인기 메뉴 목록 조회 O       O
Should 최근 주문 내역 조회(5개) O   O   O
Should 주문 취소(장바구니 삭제)     O    
Should 회원 탈퇴     O    
Could 내 포인트 조회*     O    
Could 커피 메뉴 등록*     O(관리자)    
Could 커피 메뉴 삭제     O(관리자)    
Could 커피 메뉴 수정     O(관리자)    
분류 API명 메서드 Endpoint
Must 커피 메뉴 목록 조회 GET /api/menus
Must 포인트 충전 POST /api/points/charge
Must 커피 주문(장바구니 생성) POST /api/orders
Must 포인트 결제(장바구니 결제) POST /api/orders/{orderId}/payment
Must 인기 메뉴 목록 조회 GET /api/menus/popular
Should 최근 주문 내역 조회 (5개) GET /api/orders/recent
Should 주문 취소(장바구니 삭제) DELETE /api/orders/{orderId}
Should 회원 탈퇴 DELETE /api/users/me
Could 내 포인트 조회 GET /api/points
Could 커피 메뉴 등록 POST /api/admin/menus
Could 커피 메뉴 삭제 DELETE /api/admin/menus/{menuId}
Could 커피 메뉴 수정 PUT /api/admin/menus/{menuId}

*포인트 충전은 같은 유저가 동시에 두 번 충전 요청을 보내는 시나리오가 현실적으로 드물기에, 낙관적 락이 적합하다. 충돌이 드문 상황에서 성능 부담 없이 정합성을 지키는 용도로 사용하기 때문이다. 그러나 포트원 결제 완료 후 서버에 충전을 반영하는 흐름에서, 포트원 웹훅이 중복으로 올 수 있다. 이 경우 charge_id나 포트원 결제 고유번호에 UNIQUE 제약을 걸어 막는 게 적절하다.

*장바구니 결제는 분산락으로 동시성을 제어한다. Redis에서 user_id 기준으로 락을 잡으면 서버가 몇 대든 상관 없이 같은 유저의 동시 결제 요청을 애플리케이션 레벨에서 차단한다. 

*포인트 잔액은 충전/결제가 일어날 때마다 바뀌는데, 바뀔 때마다 캐시를 무효화해야 하니까 캐시 히트율이 생각보다 낮을 수 있다. 게다가 user_points.point_balance를 캐시 컬럼으로 설계했기 때문에, db에서 sum 집계 없이 컬럼 하나만 읽으면 되는 구조라 조회 자체가 이미 가볍다. 추가로 Redis 캐싱까지 올리면 캐시 동기화 복잡도만 올라가고 실익이 크지 않다. 따라서 db 직접 조회가 더 적절하다.

*커피 메뉴 CRUD는 여러 명의 관리자가 같은 메뉴에 대해 동시에 접근할 상황을 필요로 하지만, 현실적으로 그 가능성은 높지 않다. 하지만 그 가능성이 아예 없지는 않기 때문에 낙관적 락을 걸어 성능 부담 없이 충돌만 방지하도록 할 예정이다. 

*회원 탈퇴

  • users.deleted = 1 soft delete
  • 탈퇴 토큰 Redis 블랙리스트 등록 (TTL = 토큰 잔여 만료 시간)
  • DB 커밋 후 Redis 등록 (@TransactionalEventListener)
  • Redis 장애 시 503 반환 (fail-closed)

아키텍처 설계

 

도전 요구사항

- 동시성 이슈 고려

- 다수 서버에 다수의 인스턴스로 동작하더라도 기능에 문제가 없어야 함

- 데이터 일관성이 보장돼야 함