[BE-11] goods 거래 채팅 연동 (FR-18)

작업 내용 (설계 의도)

변경 사항

근거 TDD: 20260704-채팅시스템고도화-tdd.md (FR-18, contextType=GOODS_PRODUCT, GoodsProductGateway). 2단계(Milestone 2).

중고 상품 상세의 “채팅하기”에서 구매자-판매자 1:1 거래 채팅방을 컨텍스트 룸으로 생성/조회한다. 확장 메커니즘의 2번째 연동 사례. 도메인 교차 참조 대신 message 도메인의 Gateway로 판매자 id를 조회.

  • domain/message/gateway/GoodsProductGateway.kt (신규 interface): findOwnerId(productId): Long.
  • infrastructure/message/gateway/GoodsProductGatewayImpl.kt (신규): goods ProductRepository(또는 ProductDomainService)로 Product.ownerId 조회. infrastructure→domain.goods 의존 허용. Client/외부 아님이므로 내부 조회.
  • domain/message/service/RoomContextDomainService.kt(BE-09 파일)에 createOrFindGoodsTradeRoom(productId, buyerId) 추가 — 판매자=ownerId 조회 → findByContext(GOODS_PRODUCT, productId)의 방 중 buyer-seller 조합 확인 또는 생성. (buyer 자신이 owner면 거부.)
  • application/message/usecase/CreateGoodsTradeRoomUseCase.kt (신규).
  • presentation/message/controller/: POST /products/{productId}/chat (신규 컨트롤러 또는 message 하위). /products/**는 SecurityConfig permitAll → 수정 불필요.
  • 롤백: 신규 additive 엔드포인트·Gateway. 제거해도 커뮤니티·기존 채팅 무영향. Success Metric은 1단계 측정 전용.

의존

  • BE-09 (RoomContextDomainService — 같은 파일 확장이므로 BE-09 완료 후)
  • BE-03a (Room.createForContext, findByContext)

다이어그램

처리 흐름

sequenceDiagram
    participant Buyer
    participant Ctl as ProductChatApiController
    participant UC as CreateGoodsTradeRoomUseCase
    participant DS as RoomContextDomainService
    participant G as GoodsProductGateway
    Buyer->>Ctl: POST /products/7/chat
    Ctl->>UC: execute(productId=7, buyerId)
    UC->>DS: createOrFindGoodsTradeRoom(7, buyer)
    DS->>G: findOwnerId(7)
    G-->>DS: sellerId
    DS-->>Buyer: RoomResponse(GOODS_PRODUCT)

테스트 케이스

  • 구매자가 “채팅하기”를 누르면 판매자(Product.ownerId)와의 GOODS_PRODUCT 방이 생성된다.
  • 동일 구매자-상품으로 재요청하면 기존 방으로 이동한다 (중복 생성 없음).
  • 구매자가 상품 소유자 본인이면 거래 채팅 생성이 거부된다.
  • 존재하지 않는 productId 요청 시 예외를 던진다.
  • GoodsProductGatewayImpl이 Product.ownerId를 올바르게 반환한다 (Testcontainers).