Skip to content

Fix/404 채팅방생성수정 - #408

Merged
Chungs0604 merged 3 commits into
developfrom
fix/404-채팅방생성수정
Aug 13, 2026

Hidden character warning

The head ref may contain hidden characters: "fix/404-\ucc44\ud305\ubc29\uc0dd\uc131\uc218\uc815"
Merged

Fix/404 채팅방생성수정#408
Chungs0604 merged 3 commits into
developfrom
fix/404-채팅방생성수정

Conversation

@Chungs0604

Copy link
Copy Markdown
Collaborator

🔗 관련 이슈

📌 작업 내용

  • 판매 등록 없는 아이템에 구매 제안 후 채팅 생성 시 404 PRODUCT_NOT_FOUND 오류 수정
  • 구매 제안 수락(ACCEPTED) 후 채팅 생성 시 409 오류 수정 (SENT만 체크하던 로직을
    SENT+ACCEPTED로 확장)
  • 판매자(제안 받은 쪽)가 구매 제안 상세에서 채팅을 먼저 시작할 수 있도록 지원
  • 채팅방 price 응답 로직 개선 (판매중→판매가격 / 미판매+제안→제안금액 / 그 외→null)

변경 파일

  • ChatRoomRequestpurchaseOfferId 필드 추가 (nullable)
  • ChatRoomServicefindOrCreateChatRoom 판매자 분기 추가, product null-safe 처리,
    offerPrice 조회
  • ChatRoomServiceenterChatroom product null-safe 처리, offerPrice 조회
  • ChatRoomResponse — product null-safe 처리, price 로직 변경
  • PurchaseOfferRepositoryexistsByProposerIdAndOwnerIdAndItemIdAndStatusIn,
    findOfferPriceByProposerIdAndOwnerIdAndItemIdAndStatusIn, findByIdWithUsers 추가

📌 변경된 API

  • POST /chats request body에 purchaseOfferId 추가 (nullable)
    • 구매자: 기존과 동일, { "itemId": 1 }
    • 판매자: 구매 제안 상세에서 채팅 시작 시, { "itemId": 1, "purchaseOfferId": 5 }
  • POST /chats, GET /chats/{chatRoomId} 응답 price 값 변화
    • 판매중(ON_SALE/TRADING): 판매 가격
    • 미판매/HIDDEN + 구매 제안 있음: 제안 금액
    • 미판매/HIDDEN + 구매 제안 없음: null

📌 테스트 결과

케이스 결과
ON_SALE 상품 — 구매자 채팅 시작 ✅ 200, price=판매가격
ON_SALE 상품 — 판매자 채팅 시작 (purchaseOfferId 없음) ✅ 403
HIDDEN + offer SENT — 구매자/판매자 채팅 시작 ✅ 200, price=제안금액
미판매(no product) + offer SENT — 구매자/판매자 채팅 시작 ✅ 200, price=제안금액
미판매(no product) + offer ACCEPTED — 구매자/판매자 채팅 시작 ✅ 200, price=제안금액

|
| 미판매(no product) + offer 없음 | ✅ 403 |
| ON_SALE → HIDDEN 전환 후 기존 채팅방 조회 (offer없음) | ✅ 200, price=null |
| 기존 채팅방 있는 경우 재진입 | ✅ 기존 방 반환 |

📌 확인 필요 사항

  • 프론트: price = null인 경우 "미판매 아이템" 표시 처리 필요
  • 프론트: 판매자가 구매 제안 상세에서 "채팅하기" 클릭 시 purchaseOfferId 함께 전송 필요

✅ 체크리스트

  • 기능 요구사항을 충족했는가?
  • API 응답 형식이 통일되어 있는가?
  • 예외 상황이 적절히 처리되었는가?
  • 인증/인가 검증이 누락되지 않았는가?
  • Entity를 직접 응답하지 않았는가?
  • 중복 코드가 과도하지 않은가?
  • 메서드와 클래스의 역할이 명확한가?
  • 테스트가 필요한 핵심 로직에 테스트가 작성되었는가?

@github-actions

Copy link
Copy Markdown

Gemini 파일 단위 요약 리뷰

src/main/java/com/tenure/domain/purchase/repository/PurchaseOfferRepository.java

변경 요약

  • PurchaseOffer 조회 시 연관 엔티티(item, owner, proposer)를 한 번에 조회하는 Fetch Join 쿼리 메서드(findByIdWithUsers) 추가
  • 특정 제안자, 소유자, 상품, 상태 목록 조건에 매칭되는 제안 가격(offerPrice)을 조회하는 쿼리 메서드(findOfferPriceByProposerIdAndOwnerIdAndItemIdAndStatusIn) 추가

영향 범위

  • PurchaseOffer 엔티티 조회 및 검증이 필요한 서비스 레이어 로직
  • 구매 제안 상세 조회, 제안 금액 검증 흐름에서 발생하는 N+1 쿼리 방지 및 DB 조회 성능 개선

확인 필요

  • findOfferPriceByProposerIdAndOwnerIdAndItemIdAndStatusIn 메서드는 단일 Optional<Integer>를 반환합니다. 만약 DB에 동일한 제안자(proposerId), 소유자(ownerId), 상품(itemId)에 대해 전달된 상태 목록(statuses)에 부합하는 데이터가 2건 이상 존재할 경우 NonUniqueResultException이 발생합니다.
  • 프로젝트 컨텍스트 상 "구매 제안은 사용자당 아이템별 1회 제한"이므로 정상적인 흐름에서는 1건만 존재해야 하지만, DB 수준에서 proposer_iditem_id에 대한 Unique 제약 조건이 설정되어 있는지 확인이 필요합니다.

제안

  • findByIdWithUsers에서 Fetch Join 대상인 item, owner, proposer 엔티티들이 실제로 FetchType.LAZY로 매핑되어 있는지 확인하십시오. 만약 즉시 로딩(FetchType.EAGER) 설정이 남아있다면 fetch join의 효과가 반감되거나 예상치 못한 쿼리가 발생할 수 있으므로, 엔티티 매핑 설정을 LAZY로 유지하는 것을 권장합니다.

src/main/java/com/tenure/domain/chat/service/ChatRoomService.java

변경 요약

  • 판매자 채팅방 생성 지원: 채팅방 생성/조회(findOrCreateChatRoom) 메서드에 purchaseOfferId 파라미터를 추가하여, 판매자(currentUserId == ownerId)도 구매 제안을 기반으로 채팅방을 생성하거나 조회할 수 있도록 로직을 확장했습니다.
  • 구매 제안 검증 로직 추가: 판매자가 채팅방을 생성할 때 전달한 구매 제안(PurchaseOffer)이 해당 아이템의 제안인지, 소유자가 일치하는지, 상태가 유효(SENT 또는 ACCEPTED)한지 검증하는 흐름을 추가했습니다.
  • 제안 가격 반환: 채팅방 조회 및 입장 시, 제안 상태가 SENT 또는 ACCEPTED인 제안 가격(offerPrice)을 조회하여 응답 DTO(ChatRoomResponse)에 포함하도록 변경했습니다.

영향 범위

  • 기능: 채팅방 생성 및 입장 flow (구매자뿐만 아니라 판매자도 채팅방을 최초로 개설할 수 있게 됨)
  • 계층 및 흐름: ChatRoomService -> PurchaseOfferRepository (제안 단건 조회 및 상태별 가격 조회 흐름 추가) -> ChatRoomResponse (반환 타입 변경)

확인 필요

  • 차단 관계 검증 흐름 확인: 판매자가 채팅을 시작하는 경우에도 하단의 양방향 차단 조회(userBlockRepository.findBlockRelation) 및 차단 여부에 따른 예외 처리(또는 차단 플래그 설정)가 정상적으로 적용되는지 전체 흐름 검증이 필요합니다. (diff 상에는 차단 조회 후 예외를 던지는지 여부가 나타나지 않음)
  • 제안 가격 조회 시 다건 발생 가능성: findOfferPriceByProposerIdAndOwnerIdAndItemIdAndStatusIn 호출 시, 한 사용자당 아이템별 구매 제안은 1회로 제한된다고 하지만 만약 데이터 정합성 이슈나 테스트 데이터 유실로 인해 SENT 또는 ACCEPTED 상태의 제안이 복수 개 존재할 경우, Repository에서 NonUniqueResultException이 발생할 위험이 없는지 쿼리 구조 확인이 필요합니다.

제안

  • 도메인 엔티티 내 검증 캡슐화: findOrCreateChatRoom 내부의 구매 제안 유효성 검증 로직(offer.getItem().getId().equals(itemId) ...)은 PurchaseOffer 엔티티 내부의 비즈니스 메서드(예: offer.isValidForChat(itemId, currentUserId))로 캡슐화하여 서비스 레이어의 피로도를 낮추는 것을 제안합니다.
  • Enum 값 가독성: SENT, ACCEPTED 상태 비교 시 정적 임포트(Static Import)를 사용하고 있으나, 코드 가독성과 유지보수를 위해 PurchaseOfferStatus.SENT와 같이 명확한 타입을 드러내거나 엔티티 메서드로 위임하는 것이 좋습니다.

src/main/java/com/tenure/domain/chat/controller/ChatController.java

변경 요약

  • findOrCreateChatRoom API에서 ChatRoomRequest로부터 purchaseOfferId(구매 제안 ID)를 추가로 전달받도록 수정되었습니다.
  • chatRoomService.findOrCreateChatRoom 메서드 호출 시, 기존 userIditemId 외에 purchaseOfferId를 세 번째 인자로 함께 전달하도록 변경되었습니다.

영향 범위

  • 기능: 채팅방 생성 및 조회 기능 흐름에 특정 구매 제안(Purchase Offer) 정보가 연동됩니다.
  • 계층 및 흐름: Presentation(Controller) 계층에서 Application Service 계층으로의 데이터 전달 시그니처가 변경되었습니다.

확인 필요

  • DTO 필드 및 유효성 검증: ChatRoomRequest DTO에 purchaseOfferId 필드가 추가되었는지, 그리고 이 필드가 필수값(@NotNull)인지 혹은 선택값(Nullable)인지에 대한 설계가 의도대로 반영되었는지 확인이 필요합니다. (구매 제안 없이 일반 문의로 채팅방을 개설하는 시나리오가 존재한다면 Nullable이어야 합니다.)
  • 권한 검증 누락 여부: 전달된 purchaseOfferId가 실제 존재하는 제안인지, 그리고 현재 로그인한 사용자(userId)가 해당 제안의 송신자(구매 제안자)이거나 수신자(아이템 판매자)가 맞는지에 대한 권한 검증 로직이 ChatRoomService 내부에 구현되어 있는지 확인해야 합니다.

제안

  • purchaseOfferId가 Nullable한 선택적 필드라면, 서비스 레이어(ChatRoomService) 내부에서 purchaseOfferIdnull로 넘어올 때의 방어 코드와 이에 대한 단위 테스트가 작성되었는지 점검할 것을 권장합니다.

src/main/java/com/tenure/domain/chat/dto/request/ChatRoomRequest.java

변경 요약

  • 채팅방 생성 요청 DTO(ChatRoomRequest)에 구매 제안 ID(purchaseOfferId) 필드가 추가되었습니다.

영향 범위

  • 채팅방 생성 API(POST /chat-rooms 등)의 Request Body 스키마가 변경됩니다.
  • 판매자가 특정 구매 제안을 수락하거나 이에 기반하여 채팅방을 생성하는 비즈니스 흐름(Controller 및 Service 레이어)에 영향을 줍니다.

확인 필요

  • 권한 및 소유권 검증 누락 리스크: 주석에 언급된 것처럼 판매자가 채팅방을 생성할 때 purchaseOfferId가 입력됩니다. 이때, CurrentUserProvider.getCurrentUserId()로 획득한 현재 사용자 ID가 해당 purchaseOfferId의 대상 상품(Item)의 실제 소유자(판매자)가 맞는지 검증하는 로직이 서비스 레이어에 누락 없이 구현되어 있는지 확인이 필요합니다.
  • 클라이언트 입력 신뢰성: 구매자가 채팅방을 생성할 때 악의적으로 타인의 purchaseOfferId를 바인딩하여 요청을 보낼 경우를 대비한 방어 로직(구매자 요청 시에는 purchaseOfferId가 비어있어야 하거나 무시되어야 함)이 검증 단계에 존재하는지 확인해야 합니다.

제안

  • purchaseOfferId는 비즈니스 상황에 따라 Null이 허용되므로 별도의 Bean Validation 어노테이션은 불필요하지만, 서비스 레이어에서 이 값이 넘어왔을 때의 유효성 검증(실제 존재하는 제안인지, 만료/취소되지 않은 제안인지 등)을 수행하는 비즈니스 검증 메서드를 명확히 분리하여 구현할 것을 권장합니다.

src/main/java/com/tenure/domain/chat/dto/response/ChatRoomResponse.java

변경 요약

  • ChatRoomResponse.from 정적 팩토리 메서드에 구매 제안 가격(Integer offerPrice) 매개변수가 추가되었습니다.
  • 채팅방에 표시할 가격(price) 결정 로직이 변경되었습니다. 상품이 존재하고 상태가 ON_SALE(판매중) 또는 TRADING(거래중)일 때는 상품 등록 가격을 사용하고, 그 외의 경우(상품이 없거나 다른 상태)에는 제안 가격(offerPrice)을 사용하도록 수정되었습니다.

영향 범위

  • 계층 및 흐름: 채팅방 상세 정보 또는 목록을 조회하여 DTO로 변환하는 Service 계층과 이를 호출하는 Controller 계층에 영향을 줍니다.
  • 기능: 채팅방 내에서 사용자에게 노출되는 대표 가격 정보의 표시 기준이 상품 상태에 따라 동적으로 변경됩니다.

확인 필요

  • 호출부 수정 및 컴파일 에러 여부: ChatRoomResponse.from 메서드의 시그니처가 변경되었습니다(파라미터 추가). 이 메서드를 호출하는 서비스 클래스(예: ChatService 등)와 관련 테스트 코드에서 누락 없이 offerPrice 인자를 넘겨주도록 수정되었는지 확인이 필요합니다.
  • NullPointerException 방지: productnull이 아니면서 상태가 ON_SALE 또는 TRADING인 경우 product.getPrice()를 호출하는데, Product 엔티티의 price 필드가 Nullable인 경우 price에 null이 할당될 수 있으며 클라이언트가 이를 정상적으로 처리하는지 확인이 필요합니다.

제안

  • 코드 가독성 개선을 위해 이미 위에서 선언된 productStatus 변수를 활용할 것을 제안합니다.
    // AS-IS
    Integer price = (product != null && (product.getProductStatus() == ON_SALE || product.getProductStatus() == TRADING))
            ? product.getPrice()
            : offerPrice;
    
    // TO-BE
    Integer price = (productStatus == ON_SALE || productStatus == TRADING)
            ? product.getPrice()
            : offerPrice;
    productStatusON_SALE이거나 TRADING이라는 것은 이미 productnull이 아님을 내포하므로, 중복된 product != null 체크와 product.getProductStatus() 호출을 줄여 코드가 한결 깔끔해집니다.

@Chungs0604
Chungs0604 merged commit e20710b into develop Aug 13, 2026
2 checks passed
@Chungs0604
Chungs0604 deleted the fix/404-채팅방생성수정 branch August 13, 2026 13:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants