Skip to content

Conversation

@unifolio0
Copy link
Contributor

@unifolio0 unifolio0 commented Nov 4, 2025

🚩 Issue

closed #71

🗣️ 리뷰 요구사항 (선택)

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 서비스 간 통신(Feign/Eureka) 통합으로 즐겨찾기, 예약, 레스토랑 조회, 가용일·메뉴·리뷰·평점 연동 지원 강화
  • 버그 수정 / 개선

    • 예약·즐겨찾기 흐름이 외부 서비스 연동(BFF 스타일)으로 전환되어 실시간 데이터 반영 개선
  • 테스트

    • 통합/단위 테스트를 MockMvc/Mockito 중심으로 재구성해 테스트 안정성 향상
  • 기타

    • 환경별 설정(로컬/개발/테스트) 정비 및 CI/CD 워크플로우 확장

@unifolio0 unifolio0 self-assigned this Nov 4, 2025
@coderabbitai
Copy link

coderabbitai bot commented Nov 4, 2025

Caution

Review failed

The pull request is closed.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

api-user 모듈을 BFF로 전환하여 도메인 직접 호출을 제거하고 Spring Cloud OpenFeign 기반의 클라이언트/DTO 호출로 교체했습니다. Feign 설정(타임아웃·리트라이·에러디코더)과 Redis 잠금 기반 예약 흐름, 다수의 DTO/요청 타입, 테스트를 MockMvc/Mockito 기반으로 전환했고 여러 도메인 애플리케이션과 환경 설정을 활성화/추가했습니다.

Changes

Cohort / File(s) 변경 요약
빌드/설정 변경
api-user/build.gradle, api-user/src/main/resources/..., api-user/src/main/java/com/wellmeet/ApiUserApplication.java
Spring Cloud OpenFeign 및 Eureka 의존성 추가, 애플리케이션 이름·포트·Feign 기본 설정(feign timeouts/logger) 및 Eureka URL 추가, @EnableFeignClients 활성화.
Feign 클라이언트
api-user/src/main/java/com/wellmeet/client/*
.../AvailableDateClient.java, .../FavoriteRestaurantClient.java, .../MemberClient.java, .../OwnerClient.java, .../ReservationClient.java, .../RestaurantClient.java
도메인 서비스 호출용 Feign 인터페이스 추가(여러 엔드포인트 매핑 포함).
Feign 구성/에러처리
api-user/src/main/java/com/wellmeet/config/FeignConfig.java, .../FeignErrorDecoder.java
Feign 로그 레벨, 타임아웃, Retryer, ErrorDecoder 빈 추가 및 커스텀 에러 디코더 구현.
클라이언트 DTO 및 요청/응답 DTO
api-user/src/main/java/com/wellmeet/client/dto/**, .../request/***
다수의 DTO/record/요청 타입 추가(AvailableDateDTO, RestaurantDTO, ReservationDTO, MemberDTO, OwnerDTO, MenuDTO, ReviewDTO, FavoriteRestaurantDTO, Create/Update/Increase/Decrease 요청 등).
서비스 리팩토링 (BFF 로직)
api-user/src/main/java/com/wellmeet/favorite/FavoriteService.java, .../reservation/ReservationService.java, .../restaurant/RestaurantService.java
도메인 서비스 호출을 Feign 클라이언트로 전환. ReservationService에 Redis 분산 잠금·capacity 조정 호출 및 이벤트 발행 흐름 추가. @Transactional 제거.
응답/이벤트 DTO 변경
api-user/src/main/java/com/wellmeet/reservation/dto/*, .../restaurant/dto/*, .../global/event/event/*, .../favorite/dto/*
여러 Response/Event 클래스의 생성자/필드 타입을 도메인 엔티티에서 클라이언트 DTO로 변경(ReservationDTO 기반 이벤트 등). Lombok 빌더/생성자 추가.
테스트 마이그레이션
api-user/src/test/java/com/wellmeet/**
통합형 DB 의존 테스트(데이터 생성기, DataBaseCleaner 등) 제거 및 MockMvc/@WebMvcTest·@MockitoBean 기반 단위/컨트롤러 테스트로 전환. 여러 테스트 클래스 재작성 및 DataBaseCleaner 제거.
도메인 애플리케이션 활성화 및 환경파일 추가/수정
domain-*/src/main/java/*ServiceApplication.java, domain-*/src/main/resources/application-*.yml, domain-*/src/main/resources/dev-secret.yml
여러 도메인 모듈의 SpringBoot 진입점 활성화 및 dev/local/test 환경 설정 추가·수정(데이터소스, Eureka, 포트 등).
CI/CD 및 인프라 변경
.github/workflows/*, Dockerfile 변경점
다수의 Dev_* CD 워크플로우 추가/수정, Dev_CI에 MySQL 다중 서비스 추가, 여러 Dockerfile 베이스 이미지 변경(Temurin jre), 배포/아티팩트 처리 추가.

Sequence Diagram(s)

sequenceDiagram
    participant Client as 클라이언트
    participant ApiUser as api-user (BFF)
    participant Redis as Redis (분산 잠금)
    participant Feign as Feign Client
    participant Services as 도메인 서비스들

    rect rgba(200,220,255,0.6)
    Note over ApiUser,Services: 예약 생성(간략)
    end

    Client->>ApiUser: POST /user/reservation (CreateReservationRequest)
    activate ApiUser

    ApiUser->>Redis: acquire lock (reservationLock)
    activate Redis
    Redis-->>ApiUser: lock acquired
    deactivate Redis

    ApiUser->>Feign: MemberClient.getMember(memberId)
    Feign->>Services: member-service call
    Services-->>Feign: MemberDTO
    Feign-->>ApiUser: MemberDTO

    ApiUser->>Feign: AvailableDateClient.decreaseCapacity(request)
    Feign->>Services: restaurant-service call
    Services-->>Feign: 200 OK
    Feign-->>ApiUser: void

    ApiUser->>Feign: ReservationClient.createReservation(CreateReservationDTO)
    Feign->>Services: reservation-service call
    Services-->>Feign: ReservationDTO
    Feign-->>ApiUser: ReservationDTO

    ApiUser->>ApiUser: eventPublishService.publish(ReservationCreatedEvent)
    ApiUser->>Redis: release lock
    Redis-->>ApiUser: lock released

    ApiUser-->>Client: 201 Created (ReservationResponse)
    deactivate ApiUser
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • 이유: 광범위한 모듈 변경(Feign 도입, 다수 DTO 추가, 서비스 로직 재작성, 분산 잠금 흐름, 테스트 스타일 대대적 전환, 여러 프로파일/YAML·CI/CD 변경)이 혼재되어 있어 각 영역별로 별도 검토가 필요함.
  • 추가로 주의할 파일/영역:
    • ReservationService (분산 잠금·capacity 조정·보상 로직)
    • FeignConfig / FeignErrorDecoder (타임아웃·재시도·예외 매핑)
    • 테스트 전환으로 인한 커버리지 손실 여부 (통합→모킹)
    • 이벤트 클래스 변경(ReservationDTO 사용)에 따른 소비자 호환성
    • application-*.yml 및 dev-secret 변경으로 인한 환경 간 불일치

Possibly related PRs

Suggested labels

feat

Suggested reviewers

  • ezcolin2

Poem

🐰 작은 토끼의 축하 노래
Feign 발자국 따라 서비스가 춤추고,
DTO 한 손에, 이벤트는 다른 손에 들고,
Redis 잠금으로 예약을 안전히 지키며,
BFF가 모두를 이어주는 다리가 되었네. 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning PR 설명이 매우 불완전합니다. 필수 섹션인 이슈 번호는 포함되어 있으나, 리뷰 요구사항 섹션은 비어 있고, 변경 사항에 대한 구체적인 설명, 영향 범위, 테스트 방법 등의 상세 정보가 부족합니다. PR 설명에 변경 사항의 세부 내용, 마이크로서비스 통합 방식, 영향을 받는 모듈, 테스트 방법 등을 추가하여 작성하십시오.
Out of Scope Changes check ⚠️ Warning 변경 사항이 BFF 아키텍처 전환과 관련이 없는 항목들을 포함합니다. GitHub Actions 워크플로우, 테스트 기반 클래스 프로필 변경, 배포 설정 등은 핵심 기능 변경과 독립적입니다. GitHub Actions 워크플로우(.github/workflows/*), 배포 설정, 테스트 프로필 변경 등의 변경사항을 별도 PR로 분리하거나, PR 설명에 이들 변경이 필요한 이유를 명시하십시오.
Linked Issues check ❓ Inconclusive 링크된 이슈 #71이 제목만 제공되고 구체적인 요구사항이 명시되지 않아 완전한 검증이 불가능합니다. 하지만 코드 변경 내용(Feign 클라이언트, 마이크로서비스 통합)이 BFF 전환이라는 제목과 부합합니다. 이슈 #71의 설명에 구체적인 기술 요구사항(Feign 클라이언트 구현, 마이크로서비스 엔드포인트 등)을 명시하여 검증 가능하도록 작성하십시오.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 변경 사항의 핵심을 명확하게 나타냅니다. 'api-user BFF 전환'은 마이크로서비스 기반의 BFF(Backend For Frontend) 아키텍처로의 전환을 의미하며, 코드 변경 내용과 일치합니다.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 051e6ad and 84bd7b4.

📒 Files selected for processing (9)
  • discovery-server/Dockerfile (1 hunks)
  • domain-member/Dockerfile (1 hunks)
  • domain-member/build.gradle (1 hunks)
  • domain-owner/Dockerfile (1 hunks)
  • domain-owner/build.gradle (1 hunks)
  • domain-reservation/Dockerfile (1 hunks)
  • domain-reservation/build.gradle (1 hunks)
  • domain-restaurant/Dockerfile (1 hunks)
  • domain-restaurant/build.gradle (1 hunks)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link

Summary of Changes

Hello @unifolio0, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 Pull Request는 api-user 서비스를 BFF(Backend For Frontend) 아키텍처로 전환하는 것을 목표로 합니다. 기존에는 api-user가 여러 도메인 서비스에 직접 의존했지만, 이제는 Feign 클라이언트를 사용하여 각 마이크로서비스와 통신하는 게이트웨이 역할을 수행합니다. 이를 통해 서비스 간의 결합도를 낮추고, 각 서비스의 독립성을 강화하여 전체 시스템의 유연성과 확장성을 향상시킵니다.

Highlights

  • BFF 아키텍처 전환: api-user 서비스가 백엔드 포 프론트엔드(BFF) 아키텍처로 전환되었습니다. 이제 api-user는 다른 도메인 서비스에 직접 의존하는 대신, Feign 클라이언트를 통해 마이크로서비스와 통신합니다.
  • Feign 클라이언트 도입: AvailableDate, FavoriteRestaurant, Member, Owner, Reservation, Restaurant 등 각 도메인 서비스와의 통신을 위한 전용 Feign 클라이언트 인터페이스와 관련 DTO들이 추가되었습니다.
  • 의존성 및 설정 변경: build.gradle에서 기존 도메인 프로젝트에 대한 직접적인 의존성이 제거되고, Spring Cloud OpenFeign 및 Eureka Client 의존성이 추가되었습니다. Feign 클라이언트의 로깅, 요청 옵션, 재시도 정책, 에러 디코딩을 위한 설정 클래스도 도입되었습니다.
  • 서비스 로직 및 테스트 리팩토링: 기존 서비스 로직에서 직접 도메인 서비스를 호출하던 부분이 Feign 클라이언트를 통한 호출로 변경되었으며, 이에 따라 @transactional 어노테이션이 제거되었습니다. 테스트 코드 또한 Mockito를 활용하여 Feign 클라이언트를 모킹하는 방식으로 전면 수정되었습니다.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

이번 PR은 api-user 모듈을 다른 마이크로서비스와 Feign 클라이언트를 통해 통신하는 BFF(Backend-For-Frontend)로 전환하는 중요한 아키텍처 리팩토링을 다루고 있습니다. Feign 클라이언트, DTO, 설정을 포함한 새로운 아키텍처로의 전환이 광범위하게 이루어졌습니다. 리뷰 결과, 분산 트랜잭션의 정확성, 성능, 비즈니스 로직의 위치와 관련된 몇 가지 중요하고 심각도가 높은 이슈들을 발견했습니다. 특히 비효율적인 데이터 조회(N+1 문제, 인메모리 필터링), 여러 서비스 호출에 걸친 작업의 원자성 부족, BFF가 아닌 도메인 서비스에 위치해야 할 비즈니스 로직 등의 문제가 있습니다.

Comment on lines 142 to 203
public CreateReservationResponse updateReservation(
Long reservationId,
String memberId,
CreateReservationRequest request
) {
AvailableDate availableDate = restaurantDomainService.getAvailableDate(request.getAvailableDateId(),
request.getRestaurantId());
Reservation reservation = reservationDomainService.getByIdAndMemberId(reservationId, memberId);
// 1. Redis 분산 락 획득
reservationRedisService.isUpdating(memberId, reservationId);
if (reservationDomainService.alreadyUpdated(memberId, request.getRestaurantId(), request.getAvailableDateId(),
request.getPartySize())) {
var restaurant = restaurantDomainService.getById(reservation.getRestaurantId());
var currentAvailableDate = restaurantDomainService.getAvailableDate(
reservation.getAvailableDateId(), reservation.getRestaurantId());

// 2. 현재 예약 정보 조회
ReservationDTO reservation = reservationClient.getReservation(reservationId);
if (!reservation.getMemberId().equals(memberId)) {
throw new IllegalArgumentException("권한이 없습니다.");
}

// 3. 중복 수정 체크 (BFF에서 직접 처리)
boolean alreadyUpdated = reservation.getRestaurantId().equals(request.getRestaurantId())
&& reservation.getAvailableDateId().equals(request.getAvailableDateId())
&& reservation.getPartySize() == request.getPartySize();
if (alreadyUpdated) {
RestaurantDTO restaurant = restaurantClient.getRestaurant(reservation.getRestaurantId());
AvailableDateDTO currentAvailableDate = restaurantClient.getAvailableDate(
reservation.getRestaurantId(),
reservation.getAvailableDateId()
);
return new CreateReservationResponse(reservation, restaurant.getName(), currentAvailableDate);
}
AvailableDate oldAvailableDate = restaurantDomainService.getAvailableDate(
reservation.getAvailableDateId(), reservation.getRestaurantId());
restaurantDomainService.increaseAvailableDateCapacity(oldAvailableDate,
reservation.getPartySize());
restaurantDomainService.decreaseAvailableDateCapacity(availableDate, request.getPartySize());
reservation.update(

// 4. 새로운 AvailableDate 조회
AvailableDateDTO newAvailableDate = restaurantClient.getAvailableDate(
request.getRestaurantId(),
request.getAvailableDateId()
);

// 5. 보상 트랜잭션: 기존 Capacity 복구 + 새로운 Capacity 감소
AvailableDateDTO oldAvailableDate = restaurantClient.getAvailableDate(
reservation.getRestaurantId(),
reservation.getAvailableDateId()
);
availableDateClient.increaseCapacity(new IncreaseCapacityRequest(
reservation.getAvailableDateId(), reservation.getPartySize()));
availableDateClient.decreaseCapacity(new DecreaseCapacityRequest(
request.getAvailableDateId(), request.getPartySize()));

// 6. Reservation 업데이트
UpdateReservationDTO updateRequest = new UpdateReservationDTO(
request.getRestaurantId(),
request.getAvailableDateId(),
request.getPartySize(),
request.getSpecialRequest()
);
ReservationDTO updatedReservation = reservationClient.updateReservation(reservationId, updateRequest);

Member member = memberDomainService.getById(memberId);
var restaurant = restaurantDomainService.getById(reservation.getRestaurantId());
LocalDateTime dateTime = LocalDateTime.of(availableDate.getDate(), availableDate.getTime());
// 7. 이벤트 발행
MemberDTO member = memberClient.getMember(memberId);
RestaurantDTO restaurant = restaurantClient.getRestaurant(reservation.getRestaurantId());
LocalDateTime dateTime = LocalDateTime.of(newAvailableDate.getDate(), newAvailableDate.getTime());
ReservationUpdatedEvent event = new ReservationUpdatedEvent(
reservation, member.getName(), restaurant.getName(), dateTime);
updatedReservation, member.getName(), restaurant.getName(), dateTime);
eventPublishService.publishReservationUpdatedEvent(event);
return new CreateReservationResponse(reservation, restaurant.getName(), availableDate);

return new CreateReservationResponse(updatedReservation, restaurant.getName(), newAvailableDate);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

updateReservation 메소드는 increaseCapacity, decreaseCapacity, updateReservation 등 여러 원격 호출을 조합하는데, 이 작업들은 원자적으로 실행되지 않습니다. 만약 첫 번째 호출 이후에 다른 호출이 실패하면 시스템은 데이터가 일관되지 않은 상태로 남게 됩니다. 예를 들어, updateReservation 호출이 실패해도 이미 변경된 예약 가능 인원수는 롤백되지 않습니다. 이는 분산 트랜잭션 문제입니다. Saga 패턴을 적용하거나, 가급적 reservation-service에서 전체 업데이트 로직을 원자적으로 처리하는 단일 트랜잭션 API를 제공하는 것이 더 안정적인 해결책입니다. cancel 메소드(205-232행)에서도 동일한 원자성 문제가 존재합니다.

Comment on lines +48 to +55
List<ReservationDTO> memberReservations = reservationClient.getReservationsByMember(memberId);
boolean alreadyReserved = memberReservations.stream()
.anyMatch(r -> r.getRestaurantId().equals(request.getRestaurantId())
&& r.getAvailableDateId().equals(request.getAvailableDateId())
&& r.getStatus().equals("CONFIRMED"));
if (alreadyReserved) {
throw new IllegalStateException("이미 예약된 날짜입니다.");
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

중복 예약 확인 로직이 BFF에 구현되어 있습니다. Redis 분산 락이 일부 동시성 문제를 완화해주지만, 데이터 무결성과 관련된 이런 비즈니스 로직은 데이터의 소유자인 reservation-service에서 책임지고 강제해야 합니다. reservation-service가 중복 확인을 포함하여 예약 생성을 원자적으로 처리하는 API를 제공하는 것이 이상적입니다. 이 로직이 BFF에 있으면 락 만료나 BFF를 우회하는 다른 클라이언트 호출 등으로 인해 데이터 불일치가 발생할 수 있습니다.

Comment on lines 105 to 119
return reservations.stream()
.map(reservation -> {
var restaurant = restaurantsById.get(reservation.getRestaurantId());
var availableDate = availableDatesById.get(reservation.getAvailableDateId());
return new SummaryReservationResponse(reservation, restaurant.getName(), availableDate);
RestaurantDTO restaurant = restaurantsById.get(reservation.getRestaurantId());
// AvailableDate는 각 Restaurant에서 개별 조회
AvailableDateDTO availableDate = restaurantClient.getAvailableDate(
reservation.getRestaurantId(),
reservation.getAvailableDateId()
);
return new SummaryReservationResponse(
reservation,
restaurant.getName(),
availableDate
);
})
.toList();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

getReservations 메소드에 N+1 문제가 있습니다. 예약 목록을 가져온 후, 스트림의 map 내부에서 각 예약에 대해 restaurantClient.getAvailableDate(...)를 개별적으로 호출하고 있습니다. 사용자가 예약 건수가 많을 경우, 수많은 API 호출로 인해 성능이 저하될 수 있습니다. 모든 availableDateId를 수집한 후, 레스토랑 정보를 가져오는 것처럼 단일 배치(batch) 요청으로 조회하도록 수정해야 합니다. 이를 위해 restaurant-serviceavailableDate를 배치로 조회하는 API가 필요합니다.

Comment on lines 31 to 41
return restaurantClient.getAllRestaurants()
.stream()
.filter(restaurant -> {
double distance = DistanceCalculator.calculateDistance(
latitude, longitude,
restaurant.getLatitude(), restaurant.getLongitude()
);
return distance <= SEARCH_RADIUS_KM;
})
.map(restaurant -> getNearbyRestaurantResponse(restaurant, latitude, longitude))
.toList();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

findWithNearbyRestaurant 메소드는 restaurantClient로부터 모든 레스토랑 목록을 가져온 후 인메모리에서 거리를 기준으로 필터링하고 있습니다. 레스토랑 수가 많아지면 api-user 서비스의 메모리 사용량과 CPU 부하가 커지고, 불필요한 네트워크 트래픽이 발생하는 등 확장성에 문제가 생길 수 있습니다. 레스토랑 서비스에서 좌표와 검색 반경을 파라미터로 받아 데이터소스 레벨에서 효율적으로 필터링(예: 공간 인덱스 사용)하는 API를 제공하는 것이 바람직합니다.

Comment on lines +17 to +23
return switch (response.status()) {
case 400 -> new IllegalArgumentException("잘못된 요청입니다: " + response.reason());
case 404 -> new IllegalArgumentException("요청한 리소스를 찾을 수 없습니다: " + response.reason());
case 500 -> new RuntimeException("서버 내부 오류가 발생했습니다: " + response.reason());
case 503 -> new RuntimeException("서비스를 사용할 수 없습니다: " + response.reason());
default -> defaultDecoder.decode(methodKey, response);
};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

decode 메소드에서 IllegalArgumentException, RuntimeException과 같은 일반적인 예외를 던지고 있습니다. 이렇게 하면 호출하는 쪽에서 오류 유형에 따라 섬세하게 예외를 처리하기 어렵습니다. HTTP 상태 코드에 따라 ResourceNotFoundException, DownstreamServiceException 등과 같은 커스텀 예외를 정의하여 사용하면 오류에 대한 컨텍스트를 더 명확하게 전달하고, 더 세분화된 예외 처리가 가능해져 시스템의 안정성이 향상됩니다.

        return switch (response.status()) {
            case 400 -> new IllegalArgumentException("잘못된 요청입니다: " + response.reason()); // TODO: 커스텀 예외(e.g. BadRequestException)로 변경
            case 404 -> new IllegalArgumentException("요청한 리소스를 찾을 수 없습니다: " + response.reason()); // TODO: 커스텀 예외(e.g. ResourceNotFoundException)로 변경
            case 500 -> new RuntimeException("서버 내부 오류가 발생했습니다: " + response.reason()); // TODO: 커스텀 예외(e.g. DownstreamServiceException)로 변경
            case 503 -> new RuntimeException("서비스를 사용할 수 없습니다: " + response.reason()); // TODO: 커스텀 예외(e.g. ServiceUnavailableException)로 변경
            default -> defaultDecoder.decode(methodKey, response);
        };

this.id = reservation.getId();
this.restaurantName = restaurantName;
this.status = reservation.getStatus();
this.status = ReservationStatus.valueOf(reservation.getStatus());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

ReservationStatus.valueOf(reservation.getStatus())를 사용하는 것은 API 응답이 변경될 경우 취약할 수 있습니다. 만약 reservation-service에서 반환하는 상태 문자열이 ReservationStatus 열거형 상수의 이름과 정확히 일치하지 않으면 IllegalArgumentException이 발생하여 요청 전체가 실패하게 됩니다. ReservationStatus 열거형에 알 수 없는 값을 더 안전하게 처리하는 정적 팩토리 메소드(예: fromString(String text))를 만들어, 알 수 없는 값이 오면 경고를 로깅하고 기본값이나 null을 반환하도록 하는 것이 더 안정적입니다. 이 문제는 ReservationResponse.java:39SummaryReservationResponse.java:26에도 동일하게 적용됩니다.

Comment on lines 55 to 75
public RestaurantResponse getRestaurant(String restaurantId, String memberId) {
boolean isFavorite = favoriteRestaurantDomainService.isFavorite(memberId, restaurantId);
Restaurant restaurant = restaurantDomainService.getById(restaurantId);
List<RepresentativeReviewResponse> reviews = restaurantDomainService.getReviewByRestaurantId(restaurant.getId())
.stream()
Boolean isFavorite = favoriteRestaurantClient.isFavorite(memberId, restaurantId);
boolean isFavoriteValue = Boolean.TRUE.equals(isFavorite);

RestaurantDTO restaurant = restaurantClient.getRestaurant(restaurantId);

List<ReviewDTO> reviewDTOs = restaurantClient.getReviewsByRestaurant(restaurant.getId());
List<RepresentativeReviewResponse> reviews = reviewDTOs.stream()
.map(RepresentativeReviewResponse::new)
.toList();
List<RepresentativeMenuResponse> menus = restaurantDomainService.getMenuByRestaurantId(restaurant.getId())
.stream()

List<MenuDTO> menuDTOs = restaurantClient.getMenusByRestaurant(restaurant.getId());
List<RepresentativeMenuResponse> menus = menuDTOs.stream()
.map(RepresentativeMenuResponse::new)
.toList();
double rating = restaurantDomainService.getAverageRating(restaurant.getId());
return new RestaurantResponse(restaurant, reviews, menus, isFavorite, rating);

Double rating = restaurantClient.getAverageRating(restaurant.getId());
double ratingValue = (rating != null) ? rating : 0.0;

return new RestaurantResponse(restaurant, reviews, menus, isFavoriteValue, ratingValue);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

getRestaurant 메소드는 단일 응답을 만들기 위해 isFavorite, getRestaurant, getReviewsByRestaurant, getMenusByRestaurant, getAverageRating 등 여러 API를 개별적으로 호출하고 있습니다. 이러한 "Chatty"한 통신 패턴은 높은 지연 시간(latency)을 유발할 수 있습니다. BFF 패턴의 일반적인 최적화 방식처럼, 하위 서비스에서 레스토랑 상세보기에 필요한 모든 정보를 집계하여 단일 응답으로 제공하는 API를 만드는 것을 고려해 보세요.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
api-user/src/main/java/com/wellmeet/reservation/ReservationService.java (1)

65-84: 예약 생성 실패 시 수용 인원 롤백 누락

Line [65]에서 수용 인원을 감소시킨 직후 Line [76]에서 외부 예약 생성 호출을 수행하는데, 이 호출이 실패하면 감소된 수용 인원을 되돌릴 방법이 없어 좌석이 영구히 차감됩니다. 이는 예약 실패만으로도 다른 사용자가 좌석을 잃는 심각한 일관성 문제입니다. 예약 생성 실패 시 IncreaseCapacityRequest로 즉시 복구하도록 예외 처리 블록을 추가해 주세요.

         availableDateClient.decreaseCapacity(new DecreaseCapacityRequest(
                 request.getAvailableDateId(), request.getPartySize()));
 
         // 5. Reservation 생성
         CreateReservationDTO createRequest = new CreateReservationDTO(
                 request.getRestaurantId(),
                 request.getAvailableDateId(),
                 memberId,
                 request.getPartySize(),
                 request.getSpecialRequest()
         );
-        ReservationDTO savedReservation = reservationClient.createReservation(createRequest);
+        ReservationDTO savedReservation;
+        try {
+            savedReservation = reservationClient.createReservation(createRequest);
+        } catch (RuntimeException ex) {
+            availableDateClient.increaseCapacity(new IncreaseCapacityRequest(
+                    request.getAvailableDateId(), request.getPartySize()));
+            throw ex;
+        }
🧹 Nitpick comments (14)
api-user/src/main/java/com/wellmeet/config/FeignErrorDecoder.java (1)

17-23: 예외 타입을 더 구체적으로 지정하는 것을 권장합니다.

현재 IllegalArgumentExceptionRuntimeException을 사용하고 있는데, 다음과 같은 개선을 고려하세요:

  • 커스텀 예외 클래스 생성 (예: FeignClientException, ExternalServiceException)
  • 4xx 오류에 대해서는 IllegalArgumentException 대신 커스텀 클라이언트 예외 사용
  • 5xx 오류에 대해서는 더 구체적인 서버 예외 사용

이렇게 하면 호출하는 쪽에서 예외를 더 명확하게 처리할 수 있습니다.

api-user/src/main/java/com/wellmeet/client/dto/request/RestaurantIdsRequest.java (1)

5-6: 유효성 검증 추가를 고려해보세요.

배치 요청에서 빈 리스트나 null 값을 방지하기 위해 @NotNull, @NotEmpty 같은 validation 어노테이션 추가를 고려해볼 수 있습니다.

적용 가능한 개선안:

 package com.wellmeet.client.dto.request;
 
+import jakarta.validation.constraints.NotEmpty;
 import java.util.List;
 
-public record RestaurantIdsRequest(List<String> restaurantIds) {
+public record RestaurantIdsRequest(@NotEmpty List<String> restaurantIds) {
 }
api-user/src/main/java/com/wellmeet/client/dto/request/IncreaseCapacityRequest.java (1)

3-4: 입력값 유효성 검증 추가를 권장합니다.

partySize는 음수나 0이 될 수 없고, availableDateId는 null이 될 수 없으므로 유효성 검증을 추가하는 것이 좋습니다.

 package com.wellmeet.client.dto.request;
 
-public record IncreaseCapacityRequest(Long availableDateId, int partySize) {
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Positive;
+
+public record IncreaseCapacityRequest(
+    @NotNull Long availableDateId,
+    @Positive int partySize
+) {
 }
api-user/src/main/java/com/wellmeet/client/dto/ReviewDTO.java (1)

3-11: 평점 범위 검증 추가를 고려해보세요.

rating 필드에 대한 범위 제약(예: 0.0~5.0)을 추가하면 데이터 무결성을 향상시킬 수 있습니다.

 package com.wellmeet.client.dto;
 
+import jakarta.validation.constraints.DecimalMax;
+import jakarta.validation.constraints.DecimalMin;
+
 public record ReviewDTO(
         Long id,
         String content,
-        double rating,
+        @DecimalMin("0.0") @DecimalMax("5.0") double rating,
         String situation,
         String restaurantId,
         String memberId
 ) {
 }
api-user/src/main/java/com/wellmeet/client/dto/request/UpdateRestaurantDTO.java (1)

14-18: 위도/경도 범위 검증 추가를 권장합니다.

latitudelongitude 필드에 유효한 좌표 범위 제약을 추가하여 잘못된 데이터가 저장되는 것을 방지하는 것이 좋습니다.

 package com.wellmeet.client.dto.request;
 
+import jakarta.validation.constraints.DecimalMax;
+import jakarta.validation.constraints.DecimalMin;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Getter;
 import lombok.NoArgsConstructor;
 
 @Getter
 @Builder
 @NoArgsConstructor
 @AllArgsConstructor
 public class UpdateRestaurantDTO {
 
     private String name;
     private String address;
-    private double latitude;
-    private double longitude;
+    @DecimalMin("-90.0") @DecimalMax("90.0")
+    private double latitude;
+    @DecimalMin("-180.0") @DecimalMax("180.0")
+    private double longitude;
     private String thumbnail;
 }
api-user/src/main/java/com/wellmeet/reservation/dto/SummaryReservationResponse.java (1)

21-27: 생성자 파라미터에 null 안전성 검증을 추가하는 것을 권장합니다.

생성자에서 DTO 파라미터들(reservation, restaurantName, availableDate)에 대한 null 체크를 추가하면 NPE를 방지할 수 있습니다.

     public SummaryReservationResponse(ReservationDTO reservation, String restaurantName, AvailableDateDTO availableDate) {
+        if (reservation == null || availableDate == null) {
+            throw new IllegalArgumentException("Reservation and availableDate must not be null");
+        }
         this.id = reservation.getId();
         this.restaurantName = restaurantName;
         this.dateTime = LocalDateTime.of(availableDate.getDate(), availableDate.getTime());
         this.partySize = reservation.getPartySize();
         this.status = ReservationStatus.valueOf(reservation.getStatus());
     }
api-user/src/main/java/com/wellmeet/client/dto/request/UpdateOperatingHoursDTO.java (1)

22-29: BusinessHourDTO와 구조적 유사성이 있습니다.

DayHoursDTO는 BusinessHourDTO와 거의 동일한 필드를 가지고 있으며, id 필드만 제외되어 있습니다. 요청용과 응답용 DTO를 분리하는 것은 타당하지만, 향후 공통 인터페이스나 상속 구조를 고려하여 중복을 줄일 수 있습니다.

api-user/src/main/java/com/wellmeet/client/dto/request/CreateReservationDTO.java (1)

12-19: 요청 DTO에 검증 어노테이션 추가를 권장합니다.

CreateReservationDTO에 @NotNull, @NotBlank, @Min 등의 검증 어노테이션을 추가하면 BFF 레이어에서 조기 검증을 수행하여 더 나은 에러 핸들링과 사용자 피드백을 제공할 수 있습니다.

예시:

 public class CreateReservationDTO {
 
+    @NotBlank
     private String restaurantId;
+    @NotNull
     private Long availableDateId;
+    @NotBlank
     private String memberId;
+    @Min(1)
     private int partySize;
     private String specialRequest;
 }
api-user/src/main/java/com/wellmeet/client/dto/ReservationDTO.java (1)

1-24: api-owner 모듈과 DTO 구조가 중복됩니다.

api-owner/src/main/java/com/wellmeet/client/dto/ReservationDTO.java와 동일한 구조를 가지고 있습니다. BFF 아키텍처에서 서비스 경계별로 DTO를 분리하는 것이 일반적이지만, 두 DTO가 항상 동일하게 유지되어야 한다면 공통 모듈로 추출하여 유지보수 부담을 줄일 수 있습니다.

api-user/src/main/java/com/wellmeet/config/FeignConfig.java (1)

14-40: 설정 값을 외부화하는 것을 권장합니다.

현재 타임아웃(5000ms) 및 재시도 파라미터(100ms, 1000ms, 3회)가 하드코딩되어 있습니다. 환경별로 다른 설정이 필요할 수 있으므로 application.yml로 외부화하는 것이 좋습니다.

예시:

+@Value("${feign.client.config.default.connect-timeout:5000}")
+private int connectTimeout;
+
+@Value("${feign.client.config.default.read-timeout:5000}")
+private int readTimeout;
+
 @Bean
 public Request.Options requestOptions() {
     return new Request.Options(
-            5000, TimeUnit.MILLISECONDS,
-            5000, TimeUnit.MILLISECONDS,
+            connectTimeout, TimeUnit.MILLISECONDS,
+            readTimeout, TimeUnit.MILLISECONDS,
             true
     );
 }
api-user/src/main/java/com/wellmeet/restaurant/RestaurantService.java (1)

30-42: 성능 최적화를 권장합니다.

모든 레스토랑을 가져온 후 애플리케이션 메모리에서 필터링하고 있습니다. 레스토랑 수가 많아질 경우 성능 문제가 발생할 수 있습니다. 가능하다면 domain-restaurant-service에서 위치 기반 필터링을 제공하여 네트워크 트래픽과 메모리 사용량을 줄이는 것을 고려하세요.

api-user/src/test/java/com/wellmeet/restaurant/RestaurantControllerTest.java (2)

36-70: 테스트가 기본 동작을 검증하지만 더 강화할 수 있습니다.

응답 배열 크기만 확인하고 있습니다. 거리(distance), 평점(rating), 레스토랑 세부 정보 등 응답 내용에 대한 추가 검증을 고려해보세요.

다음과 같이 개선할 수 있습니다:

 assertThat(responses).hasSize(2);
+assertThat(responses[0].getId()).isEqualTo("restaurant-1");
+assertThat(responses[0].getName()).isEqualTo("식당1");
+assertThat(responses[0].getRating()).isEqualTo(4.5);

132-168: 예약 가능 시간 조회 테스트가 동작하지만 개선 가능합니다.

응답 배열 크기만 확인하고 있습니다. 날짜, 시간, 최대 수용 인원 등 응답 내용에 대한 추가 검증을 고려해보세요.

api-user/src/main/java/com/wellmeet/client/FavoriteRestaurantClient.java (1)

12-26: Feign 클라이언트 인터페이스가 올바르게 정의되었습니다.

모든 엔드포인트 매핑과 파라미터 바인딩이 정확합니다.

일관성 개선을 위해 addFavoriteremoveFavorite 메서드에서 restaurantId@PathVariable로 변경하는 것을 고려해보세요. 현재 @RequestParam을 사용하고 있지만, RESTful 설계 관점에서 경로 변수로 사용하는 것이 더 명확할 수 있습니다.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a84551e and 62493a8.

📒 Files selected for processing (61)
  • api-user/build.gradle (1 hunks)
  • api-user/src/main/java/com/wellmeet/ApiUserApplication.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/AvailableDateClient.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/FavoriteRestaurantClient.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/MemberClient.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/OwnerClient.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/ReservationClient.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/RestaurantClient.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/dto/AvailableDateDTO.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/dto/BusinessHourDTO.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/dto/FavoriteRestaurantDTO.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/dto/MemberDTO.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/dto/MenuDTO.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/dto/OwnerDTO.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/dto/ReservationDTO.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/dto/RestaurantDTO.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/dto/ReviewDTO.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/dto/request/CreateReservationDTO.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/dto/request/DecreaseCapacityRequest.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/dto/request/IncreaseCapacityRequest.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/dto/request/MemberIdsRequest.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/dto/request/RestaurantIdsRequest.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/dto/request/UpdateOperatingHoursDTO.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/dto/request/UpdateReservationDTO.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/dto/request/UpdateRestaurantDTO.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/config/FeignConfig.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/config/FeignErrorDecoder.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/favorite/FavoriteService.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/favorite/dto/FavoriteRestaurantResponse.java (2 hunks)
  • api-user/src/main/java/com/wellmeet/global/event/event/ReservationCanceledEvent.java (2 hunks)
  • api-user/src/main/java/com/wellmeet/global/event/event/ReservationCreatedEvent.java (2 hunks)
  • api-user/src/main/java/com/wellmeet/global/event/event/ReservationUpdatedEvent.java (2 hunks)
  • api-user/src/main/java/com/wellmeet/reservation/ReservationService.java (3 hunks)
  • api-user/src/main/java/com/wellmeet/reservation/dto/CreateReservationRequest.java (0 hunks)
  • api-user/src/main/java/com/wellmeet/reservation/dto/CreateReservationResponse.java (2 hunks)
  • api-user/src/main/java/com/wellmeet/reservation/dto/ReservationResponse.java (3 hunks)
  • api-user/src/main/java/com/wellmeet/reservation/dto/ReservationStatus.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/reservation/dto/SummaryReservationResponse.java (2 hunks)
  • api-user/src/main/java/com/wellmeet/restaurant/RestaurantService.java (2 hunks)
  • api-user/src/main/java/com/wellmeet/restaurant/dto/AvailableDateResponse.java (2 hunks)
  • api-user/src/main/java/com/wellmeet/restaurant/dto/NearbyRestaurantResponse.java (2 hunks)
  • api-user/src/main/java/com/wellmeet/restaurant/dto/RepresentativeMenuResponse.java (2 hunks)
  • api-user/src/main/java/com/wellmeet/restaurant/dto/RepresentativeReviewResponse.java (2 hunks)
  • api-user/src/main/java/com/wellmeet/restaurant/dto/RestaurantResponse.java (2 hunks)
  • api-user/src/main/resources/application.yml (1 hunks)
  • api-user/src/test/java/com/wellmeet/BaseControllerTest.java (0 hunks)
  • api-user/src/test/java/com/wellmeet/BaseServiceTest.java (0 hunks)
  • api-user/src/test/java/com/wellmeet/favorite/FavoriteControllerTest.java (1 hunks)
  • api-user/src/test/java/com/wellmeet/favorite/FavoriteServiceTest.java (6 hunks)
  • api-user/src/test/java/com/wellmeet/global/controller/HealthCheckControllerTest.java (1 hunks)
  • api-user/src/test/java/com/wellmeet/global/event/EventPublishServiceTest.java (4 hunks)
  • api-user/src/test/java/com/wellmeet/global/event/listener/ReservationEventListenerTest.java (4 hunks)
  • api-user/src/test/java/com/wellmeet/reservation/ReservationControllerTest.java (1 hunks)
  • api-user/src/test/java/com/wellmeet/reservation/ReservationServiceTest.java (1 hunks)
  • api-user/src/test/java/com/wellmeet/restaurant/DomainRestaurantControllerTest.java (0 hunks)
  • api-user/src/test/java/com/wellmeet/restaurant/RestaurantControllerTest.java (1 hunks)
  • api-user/src/test/java/com/wellmeet/restaurant/RestaurantServiceTest.java (8 hunks)
  • domain-member/src/main/java/com/wellmeet/domain/MemberServiceApplication.java (1 hunks)
  • domain-owner/src/main/java/com/wellmeet/domain/OwnerServiceApplication.java (1 hunks)
  • domain-reservation/src/main/java/com/wellmeet/domain/ReservationServiceApplication.java (1 hunks)
  • domain-restaurant/src/main/java/com/wellmeet/domain/RestaurantServiceApplication.java (1 hunks)
💤 Files with no reviewable changes (4)
  • api-user/src/test/java/com/wellmeet/BaseControllerTest.java
  • api-user/src/test/java/com/wellmeet/restaurant/DomainRestaurantControllerTest.java
  • api-user/src/main/java/com/wellmeet/reservation/dto/CreateReservationRequest.java
  • api-user/src/test/java/com/wellmeet/BaseServiceTest.java
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-10T02:52:48.337Z
Learnt from: unifolio0
Repo: Team-soft-macaron/WellMeet-Backend PR: 14
File: src/main/java/com/wellmeet/recommend/dto/RecommendRestaurantResponse.java:3-3
Timestamp: 2025-07-10T02:52:48.337Z
Learning: The Restaurant class is located at `com.wellmeet.restaurant.domain.Restaurant` after the package refactoring in the WellMeet-Backend project, not in a nested model package structure.

Applied to files:

  • api-user/src/main/java/com/wellmeet/client/dto/MenuDTO.java
  • api-user/src/main/java/com/wellmeet/restaurant/dto/NearbyRestaurantResponse.java
  • api-user/src/main/java/com/wellmeet/client/dto/request/RestaurantIdsRequest.java
  • api-user/src/main/java/com/wellmeet/restaurant/dto/RepresentativeMenuResponse.java
  • api-user/src/main/java/com/wellmeet/restaurant/dto/RestaurantResponse.java
  • api-user/src/test/java/com/wellmeet/favorite/FavoriteServiceTest.java
  • api-user/src/main/java/com/wellmeet/client/dto/RestaurantDTO.java
  • api-user/src/main/java/com/wellmeet/client/RestaurantClient.java
  • api-user/src/test/java/com/wellmeet/restaurant/RestaurantControllerTest.java
  • api-user/src/main/java/com/wellmeet/restaurant/dto/RepresentativeReviewResponse.java
  • api-user/src/main/java/com/wellmeet/favorite/FavoriteService.java
  • api-user/src/test/java/com/wellmeet/restaurant/RestaurantServiceTest.java
  • api-user/src/main/java/com/wellmeet/reservation/ReservationService.java
  • api-user/src/main/java/com/wellmeet/client/ReservationClient.java
  • api-user/src/main/java/com/wellmeet/restaurant/RestaurantService.java
  • api-user/src/main/java/com/wellmeet/favorite/dto/FavoriteRestaurantResponse.java
  • api-user/src/main/java/com/wellmeet/client/FavoriteRestaurantClient.java
  • api-user/src/main/java/com/wellmeet/client/dto/request/UpdateRestaurantDTO.java
  • domain-restaurant/src/main/java/com/wellmeet/domain/RestaurantServiceApplication.java
  • api-user/src/main/java/com/wellmeet/client/dto/FavoriteRestaurantDTO.java
🧬 Code graph analysis (27)
api-user/src/main/java/com/wellmeet/client/MemberClient.java (1)
api-owner/src/main/java/com/wellmeet/client/MemberClient.java (1)
  • FeignClient (12-20)
api-user/src/main/java/com/wellmeet/client/dto/MemberDTO.java (1)
api-user/src/main/java/com/wellmeet/client/dto/OwnerDTO.java (1)
  • Getter (8-19)
api-user/src/main/java/com/wellmeet/client/dto/ReservationDTO.java (3)
api-user/src/main/java/com/wellmeet/client/dto/AvailableDateDTO.java (1)
  • Getter (10-22)
api-user/src/main/java/com/wellmeet/client/dto/request/CreateReservationDTO.java (1)
  • Getter (8-19)
api-owner/src/main/java/com/wellmeet/client/dto/ReservationDTO.java (1)
  • Getter (9-24)
api-user/src/test/java/com/wellmeet/global/controller/HealthCheckControllerTest.java (3)
api-user/src/test/java/com/wellmeet/favorite/FavoriteControllerTest.java (4)
  • Nested (30-55)
  • Nested (57-79)
  • Nested (81-96)
  • WebMvcTest (21-107)
api-user/src/test/java/com/wellmeet/reservation/ReservationControllerTest.java (5)
  • Nested (42-103)
  • Nested (105-140)
  • Nested (142-172)
  • Nested (174-209)
  • WebMvcTest (30-227)
api-owner/src/test/java/com/wellmeet/global/controller/HealthCheckControllerTest.java (1)
  • HealthCheckControllerTest (8-20)
api-user/src/test/java/com/wellmeet/reservation/ReservationControllerTest.java (3)
api-user/src/test/java/com/wellmeet/favorite/FavoriteControllerTest.java (4)
  • Nested (30-55)
  • Nested (57-79)
  • Nested (81-96)
  • WebMvcTest (21-107)
api-user/src/test/java/com/wellmeet/reservation/ReservationServiceTest.java (4)
  • Nested (61-117)
  • Nested (119-165)
  • Nested (167-209)
  • Nested (211-255)
api-user/src/test/java/com/wellmeet/global/controller/HealthCheckControllerTest.java (1)
  • WebMvcTest (12-27)
api-user/src/test/java/com/wellmeet/reservation/ReservationServiceTest.java (2)
api-user/src/test/java/com/wellmeet/reservation/ReservationControllerTest.java (4)
  • Nested (42-103)
  • Nested (105-140)
  • Nested (142-172)
  • Nested (174-209)
api-user/src/test/java/com/wellmeet/BaseServiceTest.java (1)
  • ExtendWith (11-54)
api-user/src/main/java/com/wellmeet/reservation/dto/SummaryReservationResponse.java (3)
api-user/src/main/java/com/wellmeet/reservation/dto/CreateReservationResponse.java (1)
  • Getter (9-30)
api-user/src/main/java/com/wellmeet/reservation/dto/ReservationResponse.java (1)
  • Getter (10-41)
api-user/src/main/java/com/wellmeet/restaurant/dto/AvailableDateResponse.java (1)
  • Getter (9-26)
api-user/src/main/java/com/wellmeet/client/dto/OwnerDTO.java (2)
api-user/src/main/java/com/wellmeet/client/dto/MemberDTO.java (1)
  • Getter (8-23)
api-user/src/main/java/com/wellmeet/client/dto/RestaurantDTO.java (1)
  • Getter (8-21)
api-user/src/main/java/com/wellmeet/client/dto/RestaurantDTO.java (3)
api-user/src/main/java/com/wellmeet/favorite/dto/FavoriteRestaurantResponse.java (1)
  • Getter (7-26)
api-user/src/main/java/com/wellmeet/restaurant/dto/RestaurantResponse.java (1)
  • Getter (8-43)
api-user/src/main/java/com/wellmeet/restaurant/dto/NearbyRestaurantResponse.java (1)
  • Getter (7-26)
domain-member/src/main/java/com/wellmeet/domain/MemberServiceApplication.java (3)
domain-owner/src/main/java/com/wellmeet/domain/OwnerServiceApplication.java (1)
  • SpringBootApplication (6-12)
domain-reservation/src/main/java/com/wellmeet/domain/ReservationServiceApplication.java (1)
  • SpringBootApplication (7-14)
domain-restaurant/src/main/java/com/wellmeet/domain/RestaurantServiceApplication.java (1)
  • SpringBootApplication (6-12)
api-user/src/main/java/com/wellmeet/client/dto/request/MemberIdsRequest.java (3)
api-user/src/main/java/com/wellmeet/client/dto/request/CreateReservationDTO.java (1)
  • Getter (8-19)
api-user/src/main/java/com/wellmeet/client/dto/request/UpdateOperatingHoursDTO.java (2)
  • Getter (10-30)
  • Getter (18-29)
api-user/src/main/java/com/wellmeet/client/dto/request/UpdateRestaurantDTO.java (1)
  • Getter (8-19)
api-user/src/main/java/com/wellmeet/client/dto/request/UpdateReservationDTO.java (6)
api-user/src/main/java/com/wellmeet/reservation/dto/CreateReservationResponse.java (1)
  • Getter (9-30)
api-user/src/main/java/com/wellmeet/reservation/dto/ReservationResponse.java (1)
  • Getter (10-41)
api-user/src/main/java/com/wellmeet/reservation/dto/SummaryReservationResponse.java (1)
  • Getter (9-28)
api-user/src/main/java/com/wellmeet/global/event/event/ReservationCanceledEvent.java (1)
  • Getter (7-33)
api-user/src/main/java/com/wellmeet/global/event/event/ReservationCreatedEvent.java (1)
  • Getter (7-33)
api-user/src/main/java/com/wellmeet/global/event/event/ReservationUpdatedEvent.java (1)
  • Getter (7-33)
api-user/src/main/java/com/wellmeet/client/dto/request/CreateReservationDTO.java (1)
api-user/src/main/java/com/wellmeet/client/dto/ReservationDTO.java (1)
  • Getter (9-24)
api-user/src/test/java/com/wellmeet/restaurant/RestaurantControllerTest.java (1)
api-user/src/test/java/com/wellmeet/restaurant/RestaurantServiceTest.java (3)
  • Nested (42-99)
  • Nested (101-169)
  • Nested (171-213)
api-user/src/main/java/com/wellmeet/client/dto/AvailableDateDTO.java (1)
api-user/src/main/java/com/wellmeet/restaurant/dto/AvailableDateResponse.java (1)
  • Getter (9-26)
api-user/src/main/java/com/wellmeet/favorite/FavoriteService.java (3)
api-user/src/main/java/com/wellmeet/reservation/ReservationService.java (1)
  • Service (32-233)
api-user/src/main/java/com/wellmeet/restaurant/RestaurantService.java (1)
  • Service (20-83)
domain-member/src/main/java/com/wellmeet/domain/member/FavoriteRestaurantDomainService.java (1)
  • Service (11-37)
api-user/src/main/java/com/wellmeet/client/dto/request/UpdateOperatingHoursDTO.java (1)
api-user/src/main/java/com/wellmeet/client/dto/BusinessHourDTO.java (1)
  • Getter (9-22)
api-user/src/main/java/com/wellmeet/restaurant/RestaurantService.java (1)
api-user/src/main/java/com/wellmeet/common/util/DistanceCalculator.java (1)
  • DistanceCalculator (3-18)
api-user/src/test/java/com/wellmeet/favorite/FavoriteControllerTest.java (2)
api-user/src/test/java/com/wellmeet/favorite/FavoriteServiceTest.java (3)
  • Nested (34-76)
  • Nested (78-100)
  • Nested (102-114)
api-user/src/test/java/com/wellmeet/reservation/ReservationControllerTest.java (6)
  • Nested (42-103)
  • Nested (105-140)
  • Nested (142-172)
  • Nested (174-209)
  • Nested (211-226)
  • WebMvcTest (30-227)
api-user/src/main/java/com/wellmeet/favorite/dto/FavoriteRestaurantResponse.java (1)
api-user/src/main/java/com/wellmeet/client/dto/RestaurantDTO.java (1)
  • Getter (8-21)
api-user/src/main/java/com/wellmeet/client/dto/request/UpdateRestaurantDTO.java (1)
api-user/src/main/java/com/wellmeet/client/dto/RestaurantDTO.java (1)
  • Getter (8-21)
domain-restaurant/src/main/java/com/wellmeet/domain/RestaurantServiceApplication.java (3)
domain-member/src/main/java/com/wellmeet/domain/MemberServiceApplication.java (1)
  • SpringBootApplication (6-12)
domain-owner/src/main/java/com/wellmeet/domain/OwnerServiceApplication.java (1)
  • SpringBootApplication (6-12)
domain-reservation/src/main/java/com/wellmeet/domain/ReservationServiceApplication.java (1)
  • SpringBootApplication (7-14)
api-user/src/main/java/com/wellmeet/reservation/dto/CreateReservationResponse.java (4)
api-user/src/main/java/com/wellmeet/favorite/dto/FavoriteRestaurantResponse.java (1)
  • Getter (7-26)
api-user/src/main/java/com/wellmeet/reservation/dto/ReservationResponse.java (1)
  • Getter (10-41)
api-user/src/main/java/com/wellmeet/reservation/dto/SummaryReservationResponse.java (1)
  • Getter (9-28)
api-user/src/main/java/com/wellmeet/restaurant/dto/AvailableDateResponse.java (1)
  • Getter (9-26)
domain-owner/src/main/java/com/wellmeet/domain/OwnerServiceApplication.java (3)
domain-member/src/main/java/com/wellmeet/domain/MemberServiceApplication.java (1)
  • SpringBootApplication (6-12)
domain-reservation/src/main/java/com/wellmeet/domain/ReservationServiceApplication.java (1)
  • SpringBootApplication (7-14)
domain-restaurant/src/main/java/com/wellmeet/domain/RestaurantServiceApplication.java (1)
  • SpringBootApplication (6-12)
api-user/src/main/java/com/wellmeet/client/dto/BusinessHourDTO.java (1)
api-user/src/main/java/com/wellmeet/client/dto/request/UpdateOperatingHoursDTO.java (2)
  • Getter (10-30)
  • Getter (18-29)
domain-reservation/src/main/java/com/wellmeet/domain/ReservationServiceApplication.java (3)
domain-member/src/main/java/com/wellmeet/domain/MemberServiceApplication.java (1)
  • SpringBootApplication (6-12)
domain-owner/src/main/java/com/wellmeet/domain/OwnerServiceApplication.java (1)
  • SpringBootApplication (6-12)
domain-restaurant/src/main/java/com/wellmeet/domain/RestaurantServiceApplication.java (1)
  • SpringBootApplication (6-12)
api-user/src/main/java/com/wellmeet/reservation/dto/ReservationResponse.java (5)
api-user/src/main/java/com/wellmeet/favorite/dto/FavoriteRestaurantResponse.java (1)
  • Getter (7-26)
api-user/src/main/java/com/wellmeet/reservation/dto/CreateReservationResponse.java (1)
  • Getter (9-30)
api-user/src/main/java/com/wellmeet/reservation/dto/SummaryReservationResponse.java (1)
  • Getter (9-28)
api-user/src/main/java/com/wellmeet/restaurant/dto/AvailableDateResponse.java (1)
  • Getter (9-26)
api-owner/src/main/java/com/wellmeet/reservation/dto/ReservationResponse.java (2)
  • Getter (13-67)
  • Getter (49-66)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-and-push
🔇 Additional comments (46)
api-user/src/main/java/com/wellmeet/client/dto/MenuDTO.java (2)

3-9: LGTM! DTO 설계가 적절합니다.

불변 데이터 전송을 위해 record를 사용한 것은 BFF 패턴에 적합합니다.


7-7: 가격 필드에 유효성 검증 고려가 필요합니다.

price 필드가 음수가 될 수 있는지 확인하세요. 필요하다면 서비스 레이어 또는 Feign 클라이언트에서 유효성 검증을 수행하는 것이 좋습니다.

domain-member/src/main/java/com/wellmeet/domain/MemberServiceApplication.java (1)

6-7: 서비스 디스커버리 등록 확인이 필요합니다.

ReservationServiceApplication에는 @EnableDiscoveryClient 어노테이션이 있지만 이 서비스에는 없습니다. Eureka 서버에 등록되어야 하는 서비스인지 확인하고, 필요하다면 어노테이션을 추가하세요.

다음과 같이 수정할 수 있습니다:

+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+
 @SpringBootApplication
+@EnableDiscoveryClient
 public class MemberServiceApplication {
api-user/src/main/java/com/wellmeet/restaurant/dto/RepresentativeMenuResponse.java (1)

14-17: LGTM! BFF 패턴에 맞는 변경입니다.

도메인 엔티티 대신 DTO를 사용하도록 변경한 것은 BFF 패턴의 올바른 적용입니다. API 레이어와 도메인 레이어의 분리가 잘 이루어졌습니다.

domain-restaurant/src/main/java/com/wellmeet/domain/RestaurantServiceApplication.java (1)

6-7: 서비스 디스커버리 등록 확인이 필요합니다.

다른 도메인 서비스들과 일관성을 위해 @EnableDiscoveryClient 어노테이션이 필요한지 확인하세요. BFF 패턴에서 api-user가 이 서비스를 Feign 클라이언트로 호출할 경우 Eureka 등록이 필수입니다.

필요시 다음과 같이 수정하세요:

+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+
 @SpringBootApplication
+@EnableDiscoveryClient
 public class RestaurantServiceApplication {
api-user/src/main/java/com/wellmeet/config/FeignErrorDecoder.java (1)

18-21: response.reason()의 null 안정성을 확인하세요.

response.reason()이 null일 수 있습니다. null 체크를 추가하거나 Optional을 사용하는 것이 안전합니다.

예시:

-case 400 -> new IllegalArgumentException("잘못된 요청입니다: " + response.reason());
+case 400 -> new IllegalArgumentException("잘못된 요청입니다: " + 
+    (response.reason() != null ? response.reason() : "Unknown"));
domain-owner/src/main/java/com/wellmeet/domain/OwnerServiceApplication.java (1)

6-7: 서비스 디스커버리 등록 확인이 필요합니다.

일관성을 위해 다른 도메인 서비스들과 동일하게 @EnableDiscoveryClient 어노테이션 추가 여부를 검토하세요. Feign 클라이언트를 통한 서비스 간 통신이 필요한 경우 필수입니다.

api-user/src/main/java/com/wellmeet/client/dto/AvailableDateDTO.java (1)

10-22: LGTM! DTO 구조가 잘 설계되었습니다.

Lombok 어노테이션을 적절히 사용했고, @builder 패턴을 통해 가독성 높은 객체 생성이 가능합니다. AvailableDateResponse와의 매핑도 잘 이루어질 것으로 보입니다.

api-user/build.gradle (1)

6-8: Spring Cloud BOM이 올바르게 설정되어 있습니다.

확인 결과, 루트 build.gradle의 41-44줄에서 spring-cloud-dependencies BOM이 dependencyManagement를 통해 적절히 관리되고 있습니다. api-user/build.gradle의 6-8줄에 추가된 OpenFeign과 Eureka 클라이언트 의존성은 이미 구성된 BOM을 통해 버전이 관리되므로, 추가 조치가 필요하지 않습니다.

api-user/src/main/java/com/wellmeet/client/dto/RestaurantDTO.java (1)

8-21: LGTM! DTO 구조가 적절합니다.

Lombok 애노테이션과 필드 구조가 올바르게 정의되어 있으며, 다른 Response DTO들에서의 사용 패턴과 일관성을 유지하고 있습니다.

api-user/src/main/java/com/wellmeet/favorite/dto/FavoriteRestaurantResponse.java (1)

3-25: LGTM! BFF 패턴으로의 전환이 적절합니다.

도메인 엔티티에서 DTO로의 전환이 올바르게 수행되었으며, Lombok 애노테이션을 통한 빌더 패턴 지원도 적절히 추가되었습니다.

api-user/src/main/java/com/wellmeet/client/dto/FavoriteRestaurantDTO.java (1)

3-8: 구조가 명확하고 간결합니다.

DTO 구조가 적절하며, 클라이언트 레이어에서 사용하기에 적합합니다.

api-user/src/main/java/com/wellmeet/ApiUserApplication.java (1)

5-10: Feign 클라이언트 활성화가 올바르게 적용되었습니다.

BFF 패턴 전환을 위한 @EnableFeignClients 어노테이션 추가가 적절합니다.

api-user/src/main/java/com/wellmeet/client/MemberClient.java (1)

12-20: Feign 클라이언트 구현이 올바릅니다.

인터페이스 정의가 명확하고, api-owner 모듈의 MemberClient와 일관성 있게 구현되었습니다. 엔드포인트 매핑과 파라미터 바인딩이 적절합니다.

api-user/src/test/java/com/wellmeet/global/event/listener/ReservationEventListenerTest.java (1)

1-105: 도메인 엔티티에서 DTO로의 테스트 마이그레이션이 올바르게 수행되었습니다.

테스트 로직이 정확하며, ReservationDTO를 사용한 이벤트 생성 및 검증이 일관되게 구현되어 있습니다.

api-user/src/main/java/com/wellmeet/restaurant/dto/NearbyRestaurantResponse.java (1)

18-25: RestaurantDTO로의 마이그레이션이 올바르게 수행되었습니다.

생성자 시그니처가 적절히 업데이트되었고 모든 필드 매핑이 정확합니다.

api-user/src/main/java/com/wellmeet/client/dto/MemberDTO.java (1)

1-23: MemberDTO 구조가 깔끔하게 정의되었습니다.

필드 구성이 적절하고 기능 플래그들이 올바르게 포함되어 있습니다.

api-user/src/main/java/com/wellmeet/global/event/event/ReservationUpdatedEvent.java (1)

21-32: ReservationDTO 기반으로 올바르게 마이그레이션되었습니다.

상태 값이 enum에서 String으로 변경되어 DTO 기반 아키텍처와 일관성을 유지합니다.

api-user/src/main/java/com/wellmeet/restaurant/dto/AvailableDateResponse.java (1)

19-26: AvailableDateDTO로의 전환이 정확하게 구현되었습니다.

생성자와 필드 매핑이 올바르게 업데이트되었습니다.

api-user/src/main/java/com/wellmeet/client/dto/ReservationDTO.java (1)

9-24: ReservationDTO 구조가 잘 정의되어 있습니다.

예약 데이터를 표현하기에 적절한 필드 구성입니다.

api-user/src/main/java/com/wellmeet/global/event/event/ReservationCanceledEvent.java (1)

21-32: 변경 사항이 올바릅니다.

Reservation 엔티티에서 ReservationDTO로 변경한 것이 BFF 패턴 전환과 일치하며, status 필드를 String으로 직접 가져오는 것도 적절합니다.

api-user/src/test/java/com/wellmeet/global/controller/HealthCheckControllerTest.java (1)

12-25: MockMvc 마이그레이션이 올바르게 구현되었습니다.

RestAssured에서 MockMvc로의 전환이 깔끔하게 이루어졌으며, Spring의 표준 테스트 방식을 따르고 있습니다.

api-user/src/main/java/com/wellmeet/client/dto/OwnerDTO.java (1)

8-19: DTO 구현이 적절합니다.

다른 DTO 클래스들(MemberDTO, RestaurantDTO)과 일관된 패턴을 따르고 있으며, Lombok 사용도 적절합니다.

api-user/src/main/java/com/wellmeet/client/dto/request/UpdateReservationDTO.java (1)

7-16: Request DTO 구현이 적절합니다.

표준적인 요청 DTO 패턴을 따르고 있으며, 필드 구성이 적절합니다.

api-user/src/main/java/com/wellmeet/restaurant/RestaurantService.java (1)

44-82: Null 처리가 적절하게 구현되었습니다.

평점(rating)과 즐겨찾기(isFavorite) 값에 대한 null 처리가 안전하게 구현되어 있으며, Feign 클라이언트를 통한 데이터 조회 로직도 올바릅니다.

api-user/src/main/java/com/wellmeet/client/AvailableDateClient.java (1)

13-24: Feign 클라이언트가 올바르게 구현되었습니다.

Spring Cloud OpenFeign의 표준을 따르고 있으며, 엔드포인트 매핑과 애노테이션 사용이 적절합니다.

api-user/src/main/java/com/wellmeet/global/event/event/ReservationCreatedEvent.java (1)

21-32: 변경 사항이 올바릅니다.

ReservationDTO로의 마이그레이션이 다른 이벤트 클래스들과 일관되게 적용되었으며, BFF 패턴 전환에 적합합니다.

api-user/src/main/java/com/wellmeet/restaurant/dto/RepresentativeReviewResponse.java (1)

14-17: DTO 매핑이 올바르게 구현되었습니다.

ReviewDTO의 레코드 접근자(accessor)를 사용한 매핑이 정확합니다.

api-user/src/main/java/com/wellmeet/client/OwnerClient.java (1)

8-13: Feign 클라이언트 구현이 올바릅니다.

서비스 디스커버리와 경로 매핑이 정확하게 설정되었습니다.

다음을 확인하세요:

  • FeignConfig에서 전역 에러 핸들링과 타임아웃 설정이 적절히 구성되어 있는지 검증이 필요합니다.
  • Owner 서비스의 장애 시 폴백 전략이 필요한지 고려해보세요.
api-user/src/test/java/com/wellmeet/restaurant/RestaurantControllerTest.java (1)

76-126: 레스토랑 상세 조회 테스트가 잘 작성되었습니다.

응답의 핵심 필드(id, menus, reviews)를 적절히 검증하고 있습니다.

api-user/src/main/java/com/wellmeet/restaurant/dto/RestaurantResponse.java (1)

24-42: DTO 기반 응답 생성이 올바르게 구현되었습니다.

RestaurantDTO에서 모든 필드가 정확하게 매핑되었으며, reviewCount도 적절히 계산되고 있습니다.

api-user/src/test/java/com/wellmeet/favorite/FavoriteControllerTest.java (5)

21-28: @WebMvcTest를 사용한 컨트롤러 테스트 구조가 우수합니다.

Spring MVC 테스트 모범 사례를 따르고 있으며, MockMvc와 서비스 모킹이 적절히 설정되었습니다.


33-54: 즐겨찾기 조회 테스트가 잘 작성되었습니다.

MockMvc와 jsonPath를 활용한 JSON 응답 검증이 명확하고 포괄적입니다.


60-78: 즐겨찾기 추가 테스트가 정확합니다.

POST 요청과 201 Created 상태 코드, 그리고 응답 필드를 적절히 검증하고 있습니다.


84-95: 즐겨찾기 삭제 테스트가 적절합니다.

DELETE 요청과 204 No Content 상태 코드를 올바르게 검증하고 있습니다.


98-106: 테스트 데이터 생성 헬퍼 메서드가 잘 작성되었습니다.

빌더 패턴을 사용하여 테스트 데이터 생성을 간결하게 처리하고 있습니다.

api-user/src/main/java/com/wellmeet/favorite/FavoriteService.java (3)

23-44: 즐겨찾기 조회 로직이 효율적으로 구현되었습니다.

배치 조회 패턴을 사용하여 N+1 쿼리 문제를 방지하고 있으며, Map을 활용한 O(1) 조회가 성능에 유리합니다.


46-50: 평점 처리 로직이 안전하게 구현되었습니다.

null 평점을 0.0으로 기본 처리하는 방어적 프로그래밍이 좋습니다.


52-60: 즐겨찾기 추가/삭제 메서드가 간결하게 구현되었습니다.

BFF 패턴에 맞게 Feign 클라이언트로 적절히 위임하고 있습니다.

api-user/src/test/java/com/wellmeet/global/event/EventPublishServiceTest.java (2)

27-76: 이벤트 발행 테스트가 명확하게 작성되었습니다.

세 가지 이벤트 타입 모두 일관된 패턴으로 검증되고 있으며, Mockito 검증이 적절합니다.


78-90: ReservationDTO 생성 헬퍼 메서드가 잘 작성되었습니다.

빌더 패턴으로 모든 필수 필드를 설정하여 일관된 테스트 데이터를 제공하고 있습니다.

api-user/src/main/java/com/wellmeet/reservation/dto/ReservationResponse.java (1)

28-40: DTO 매핑 전환이 일관적입니다.
ReservationDTO·RestaurantDTO·AvailableDateDTO를 통한 필드 매핑이 명확하고, 상태 변환도 기존 Enum 체계를 유지하고 있어 BFF 전환 흐름이 잘 정리되었습니다.

api-user/src/main/java/com/wellmeet/client/dto/BusinessHourDTO.java (1)

9-21: 운영 시간 DTO 구조가 명확합니다.
필수 필드와 Lombok 조합이 깔끔하게 정리되어 있어 추후 직렬화/역직렬화에 활용하기 좋습니다.

api-user/src/main/java/com/wellmeet/client/RestaurantClient.java (1)

19-59: Feign 클라이언트 계약이 잘 정리되었습니다.
식당·예약·리뷰 관련 경로와 DTO 매핑이 명확해 서비스 간 연동이 수월해 보입니다.

api-user/src/test/java/com/wellmeet/favorite/FavoriteServiceTest.java (1)

37-130: 테스트가 BFF 흐름을 정확히 검증합니다.
Mock 클라이언트로 즐겨찾기 조회·추가·삭제 시나리오를 명확히 검증하고 있어 리팩터에 안심할 수 있습니다.

api-user/src/test/java/com/wellmeet/reservation/ReservationServiceTest.java (1)

64-352: Mockito 리팩터가 핵심 시나리오를 두루 커버합니다.
예약 생성·조회·수정·취소와 예외 케이스를 DTO 및 클라이언트 기반으로 촘촘히 검증해 서비스 전환 안정성을 확보했습니다.

this.id = reservation.getId();
this.restaurantName = restaurantName;
this.status = reservation.getStatus();
this.status = ReservationStatus.valueOf(reservation.getStatus());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

ReservationStatus.valueOf()의 예외 처리를 확인하세요.

ReservationStatus.valueOf(reservation.getStatus())reservation.getStatus()가 반환하는 문자열이 enum 상수와 정확히 일치하지 않으면 IllegalArgumentException을 던집니다. ReservationDTO의 status 값이 항상 유효한 enum 값임을 보장하거나, 적절한 예외 처리를 추가해야 합니다.

다음 스크립트로 ReservationDTO의 status 필드 타입과 설정 방식을 확인해주세요:


🏁 Script executed:

#!/bin/bash
# ReservationDTO에서 status 필드의 타입과 사용 패턴 확인
ast-grep --pattern $'class ReservationDTO {
  $$$
  String status;
  $$$
}'

# ReservationDTO를 생성하는 코드 패턴 검색
rg -nP -A5 -B5 'new ReservationDTO|ReservationDTO\.builder' --type=java

Length of output: 5204


🏁 Script executed:

#!/bin/bash
# Find ReservationStatus enum definition
fd -t f 'ReservationStatus.java' --type f

# Search for Reservation entity definition
fd -t f 'Reservation.java' -E '*Test*' --type f

# Search for how status is used in Reservation entity
rg -n 'class Reservation' --type=java -A 10 -g '!*Test*'

Length of output: 41135


🏁 Script executed:

#!/bin/bash
# Check CreateReservationResponse imports and usage
cat api-user/src/main/java/com/wellmeet/reservation/dto/CreateReservationResponse.java | head -50

# Check ReservationStatus enum in domain-reservation
cat domain-reservation/src/main/java/com/wellmeet/domain/reservation/entity/ReservationStatus.java

# Check how ReservationDTO status is populated from Reservation entity
rg -n 'Reservation\.getStatus|status\.name|status\.toString' --type=java -A2 -B2 | head -80

Length of output: 1149


🏁 Script executed:

#!/bin/bash
# Check which ReservationStatus is imported in CreateReservationResponse
rg -n 'import.*ReservationStatus' api-user/src/main/java/com/wellmeet/reservation/dto/CreateReservationResponse.java

# Check api-user ReservationStatus definition
cat api-user/src/main/java/com/wellmeet/reservation/dto/ReservationStatus.java

# Check api-owner ReservationStatus definition
cat api-owner/src/main/java/com/wellmeet/restaurant/dto/ReservationStatus.java

# Check how Reservation entity is mapped to ReservationDTO (look for mapper/converter)
fd -t f 'ReservationMapper\|ReservationConverter' --type f -E '*Test*'

# Search for ReservationDTO creation patterns - where status is set
rg -n 'new ReservationDTO|\.status\(' api-user/src/main/java/com/wellmeet/reservation/ --type=java -B2 -A2 | head -100

Length of output: 228


🏁 Script executed:

#!/bin/bash
# Find ReservationClient
fd -t f 'ReservationClient.java' --type f -E '*Test*'

# Check ReservationService.reserve() method in api-user
rg -n 'public CreateReservationResponse reserve' api-user/src/main/java/com/wellmeet/reservation/ --type=java -A 30

# Check if there's any exception handling for valueOf
rg -n 'IllegalArgumentException|try.*catch|valueOf' api-user/src/main/java/com/wellmeet/reservation/dto/CreateReservationResponse.java --type=java -B2 -A2

# Search for how status is set when creating ReservationDTO responses
rg -n 'getStatus\(\)|\.status' api-user/src/main/java/com/wellmeet/client/dto/ReservationDTO.java --type=java -B3 -A3

Length of output: 7893


🏁 Script executed:

#!/bin/bash
# Check ReservationClient implementation
cat api-user/src/main/java/com/wellmeet/client/ReservationClient.java

# Check if there's response entity mapping that could cause issues
rg -n 'ReservationDTO|getStatus' api-user/src/main/java/com/wellmeet/client/ReservationClient.java --type=java -B3 -A3

# Look for the full ReservationService.reserve method to see complete flow
cat api-user/src/main/java/com/wellmeet/reservation/ReservationService.java | grep -A 60 'public CreateReservationResponse reserve'

Length of output: 5505


ReservationStatus.valueOf()에서 예외 처리 추가 필요

ReservationDTOstatus 필드는 HTTP 응답으로 수신되는 문자열이며, 25번 줄에서 예외 처리 없이 ReservationStatus.valueOf(reservation.getStatus())를 호출합니다. 데이터베이스 데이터 불일치, 역직렬화 오류 또는 null 값이 발생할 경우 IllegalArgumentException이 발생합니다.

다음 중 하나를 적용하세요:

  • 생성자에서 try-catch로 예외 처리
  • ReservationDTO 역직렬화 시 enum 검증 추가
  • 또는 ReservationStatus.stream().filter(...).findFirst().orElseThrow() 패턴으로 안전한 변환 구현
🤖 Prompt for AI Agents
In
api-user/src/main/java/com/wellmeet/reservation/dto/CreateReservationResponse.java
around line 25, calling ReservationStatus.valueOf(reservation.getStatus()) can
throw IllegalArgumentException or NPE for null/invalid strings; replace this
with a safe conversion: either wrap the call in a try-catch and map invalid/null
values to a sensible default or throw a clear custom exception, or use a safe
lookup pattern (e.g., stream/filter/findFirst/orElseThrow) to validate the
incoming string before assigning to this.status so malformed input is handled
deterministically.

Comment on lines +21 to 27
public SummaryReservationResponse(ReservationDTO reservation, String restaurantName, AvailableDateDTO availableDate) {
this.id = reservation.getId();
this.restaurantName = restaurantName;
this.dateTime = LocalDateTime.of(availableDate.getDate(), availableDate.getTime());
this.partySize = reservation.getPartySize();
this.status = reservation.getStatus();
this.status = ReservationStatus.valueOf(reservation.getStatus());
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

상태 변환 시 예외 처리 검증이 필요합니다.

Line 26에서 ReservationStatus.valueOf(reservation.getStatus())는 잘못된 상태 문자열이 전달될 경우 IllegalArgumentException을 발생시킬 수 있습니다. DTO의 getStatus() 메서드가 반환하는 값이 항상 유효한 ReservationStatus 값임을 보장하는지 확인이 필요합니다.

다음 스크립트로 ReservationDTO의 status 필드 타입과 사용처를 확인해주세요:


🏁 Script executed:

#!/bin/bash
# ReservationDTO의 status 필드 타입 확인
ast-grep --pattern $'class ReservationDTO {
  $$$
  $_status$$$;
  $$$
}'

# ReservationStatus enum 정의 확인
ast-grep --pattern $'enum ReservationStatus {
  $$$
}'

# valueOf 호출 시 예외 처리 패턴 확인
rg -n -A3 -B3 'ReservationStatus\.valueOf' --type=java

Length of output: 3603


추가 검증이 필요합니다. ReservationDTO의 상태 필드 정의와 ReservationStatus enum 정의를 확인하겠습니다.

이제 더 구체적인 코드베이스 검증이 필요합니다. ReservationDTO 클래스와 ReservationStatus enum을 찾겠습니다.


---

🏁 Script executed:

```shell
#!/bin/bash
# ReservationDTO 클래스 검색
fd -type f -name "ReservationDTO.java" --exec cat {} \;

# ReservationStatus enum 검색
fd -type f -name "ReservationStatus.java" --exec cat {} \;

# 상태 필드 검증 로직 검색
rg -n -A5 -B5 'class ReservationDTO' --type=java -g '*.java'

Length of output: 2297


ReservationStatus enum과 상태 검증 로직을 찾겠습니다.


---

🏁 Script executed:

```shell
#!/bin/bash
# ReservationStatus enum 파일 찾기
find . -name "ReservationStatus.java" -type f -exec cat {} \;

# 상태 관련 검증 로직 검색
rg -n "enum ReservationStatus" 

# Status 필드 검증 로직 검색
rg -n -B5 -A10 "reservation\.getStatus()" 

# Exception handling 검색
rg -n -B5 -A5 "catch.*IllegalArgumentException" 

# 상태 값 설정 위치 검색
rg -n "\.setStatus\(" 

Length of output: 15114


상태 검증 및 예외 처리가 상위 계층에서 이루어지는지 확인하겠습니다.


---

🏁 Script executed:

```shell
#!/bin/bash
# 서비스/컨트롤러 레벨의 예외 처리 확인
rg -n -B5 -A5 "IllegalArgumentException" 

# ReservationDTO를 반환하는 서비스 메서드 확인
rg -n "ReservationDTO" | grep -i "service\|controller" | head -20

# 상태 검증 로직 확인
rg -n "status.*PENDING\|status.*CONFIRMED\|status.*CANCELED" 

# 데이터베이스에서 상태 값을 읽어오는 부분
rg -n "repository\|findBy.*Reservation" -B2 -A2

Length of output: 19666


상태 문자열의 안전하지 않은 enum 변환 - 4개 응답 클래스 모두 영향

ReservationDTO의 status는 유효성 검증 없는 String 필드이며, 데이터베이스나 외부 API에서 임의의 값이 올 수 있습니다. ReservationStatus enum은 PENDING, CONFIRMED, CANCELED만 정의되어 있는데, 현재 코드는 검증 없이 valueOf() 호출 시 잘못된 상태 문자열이 있으면 IllegalArgumentException을 발생시킵니다.

예외 핸들러가 존재하긴 하지만, 이는 사후 처리이며 다음 4개 위치에서 동일한 문제가 반복됩니다:

  • api-user/.../SummaryReservationResponse.java:26
  • api-user/.../CreateReservationResponse.java:25
  • api-user/.../ReservationResponse.java:39
  • api-owner/.../ReservationResponse.java:43

ReservationDTO에 @Pattern 같은 유효성 검증 추가 또는 Optional.ofNullable() 등 안전한 변환 방식 도입이 필요합니다.

Comment on lines +156 to 167
// 3. 중복 수정 체크 (BFF에서 직접 처리)
boolean alreadyUpdated = reservation.getRestaurantId().equals(request.getRestaurantId())
&& reservation.getAvailableDateId().equals(request.getAvailableDateId())
&& reservation.getPartySize() == request.getPartySize();
if (alreadyUpdated) {
RestaurantDTO restaurant = restaurantClient.getRestaurant(reservation.getRestaurantId());
AvailableDateDTO currentAvailableDate = restaurantClient.getAvailableDate(
reservation.getRestaurantId(),
reservation.getAvailableDateId()
);
return new CreateReservationResponse(reservation, restaurant.getName(), currentAvailableDate);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

특별 요청만 수정하면 변경이 무시됩니다

Line [156]의 alreadyUpdated 판별이 식당/시간/인원만 비교하고 있어, 사용자가 특별 요청(specialRequest)만 바꾸는 경우 Line [161]에서 그대로 반환되어 실제 업데이트가 이뤄지지 않습니다. 결과적으로 클라이언트는 성공 응답을 받지만 변경 사항이 반영되지 않는 기능 오류가 발생합니다. specialRequest 비교를 포함하도록 수정해 주세요 (Objects.equals 사용 시 import java.util.Objects; 추가 필요).

-        boolean alreadyUpdated = reservation.getRestaurantId().equals(request.getRestaurantId())
-                && reservation.getAvailableDateId().equals(request.getAvailableDateId())
-                && reservation.getPartySize() == request.getPartySize();
+        boolean alreadyUpdated = reservation.getRestaurantId().equals(request.getRestaurantId())
+                && reservation.getAvailableDateId().equals(request.getAvailableDateId())
+                && reservation.getPartySize() == request.getPartySize()
+                && Objects.equals(reservation.getSpecialRequest(), request.getSpecialRequest());
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// 3. 중복 수정 체크 (BFF에서 직접 처리)
boolean alreadyUpdated = reservation.getRestaurantId().equals(request.getRestaurantId())
&& reservation.getAvailableDateId().equals(request.getAvailableDateId())
&& reservation.getPartySize() == request.getPartySize();
if (alreadyUpdated) {
RestaurantDTO restaurant = restaurantClient.getRestaurant(reservation.getRestaurantId());
AvailableDateDTO currentAvailableDate = restaurantClient.getAvailableDate(
reservation.getRestaurantId(),
reservation.getAvailableDateId()
);
return new CreateReservationResponse(reservation, restaurant.getName(), currentAvailableDate);
}
// 3. 중복 수정 체크 (BFF에서 직접 처리)
boolean alreadyUpdated = reservation.getRestaurantId().equals(request.getRestaurantId())
&& reservation.getAvailableDateId().equals(request.getAvailableDateId())
&& reservation.getPartySize() == request.getPartySize()
&& Objects.equals(reservation.getSpecialRequest(), request.getSpecialRequest());
if (alreadyUpdated) {
RestaurantDTO restaurant = restaurantClient.getRestaurant(reservation.getRestaurantId());
AvailableDateDTO currentAvailableDate = restaurantClient.getAvailableDate(
reservation.getRestaurantId(),
reservation.getAvailableDateId()
);
return new CreateReservationResponse(reservation, restaurant.getName(), currentAvailableDate);
}
🤖 Prompt for AI Agents
In api-user/src/main/java/com/wellmeet/reservation/ReservationService.java
around lines 156 to 167, the alreadyUpdated check only compares restaurantId,
availableDateId and partySize so if only specialRequest changed the method
returns early and skips applying the update; include comparison of
specialRequest using Objects.equals(reservation.getSpecialRequest(),
request.getSpecialRequest()) in the alreadyUpdated boolean expression and add
import java.util.Objects; at the top of the file.

Comment on lines +186 to 205
UpdateReservationDTO updateRequest = new UpdateReservationDTO(
request.getRestaurantId(),
request.getAvailableDateId(),
request.getPartySize(),
request.getSpecialRequest()
);
ReservationDTO updatedReservation = reservationClient.updateReservation(reservationId, updateRequest);

Member member = memberDomainService.getById(memberId);
var restaurant = restaurantDomainService.getById(reservation.getRestaurantId());
LocalDateTime dateTime = LocalDateTime.of(availableDate.getDate(), availableDate.getTime());
// 7. 이벤트 발행
MemberDTO member = memberClient.getMember(memberId);
RestaurantDTO restaurant = restaurantClient.getRestaurant(reservation.getRestaurantId());
LocalDateTime dateTime = LocalDateTime.of(newAvailableDate.getDate(), newAvailableDate.getTime());
ReservationUpdatedEvent event = new ReservationUpdatedEvent(
reservation, member.getName(), restaurant.getName(), dateTime);
updatedReservation, member.getName(), restaurant.getName(), dateTime);
eventPublishService.publishReservationUpdatedEvent(event);
return new CreateReservationResponse(reservation, restaurant.getName(), availableDate);

return new CreateReservationResponse(updatedReservation, restaurant.getName(), newAvailableDate);
}

@Transactional
public void cancel(Long reservationId, String memberId) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

업데이트 실패 시 수용 인원 복구 누락

Line [180]에서 기존 슬롯 용량을 늘리고 Line [182]에서 새 슬롯 용량을 줄인 뒤 Line [193]에서 외부 업데이트를 호출합니다. 이 호출이 실패하면 기존 슬롯은 늘어난 채, 새 슬롯은 감소한 채로 남아 좌석 이중 할당이 일어나게 됩니다. 업데이트 실패 시 두 슬롯 모두 원상 복구하도록 예외 처리를 추가해 주세요.

         availableDateClient.increaseCapacity(new IncreaseCapacityRequest(
                 reservation.getAvailableDateId(), reservation.getPartySize()));
         availableDateClient.decreaseCapacity(new DecreaseCapacityRequest(
                 request.getAvailableDateId(), request.getPartySize()));
 
         // 6. Reservation 업데이트
         UpdateReservationDTO updateRequest = new UpdateReservationDTO(
                 request.getRestaurantId(),
                 request.getAvailableDateId(),
                 request.getPartySize(),
                 request.getSpecialRequest()
         );
-        ReservationDTO updatedReservation = reservationClient.updateReservation(reservationId, updateRequest);
+        ReservationDTO updatedReservation;
+        try {
+            updatedReservation = reservationClient.updateReservation(reservationId, updateRequest);
+        } catch (RuntimeException ex) {
+            availableDateClient.decreaseCapacity(new DecreaseCapacityRequest(
+                    reservation.getAvailableDateId(), reservation.getPartySize()));
+            availableDateClient.increaseCapacity(new IncreaseCapacityRequest(
+                    request.getAvailableDateId(), request.getPartySize()));
+            throw ex;
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
UpdateReservationDTO updateRequest = new UpdateReservationDTO(
request.getRestaurantId(),
request.getAvailableDateId(),
request.getPartySize(),
request.getSpecialRequest()
);
ReservationDTO updatedReservation = reservationClient.updateReservation(reservationId, updateRequest);
Member member = memberDomainService.getById(memberId);
var restaurant = restaurantDomainService.getById(reservation.getRestaurantId());
LocalDateTime dateTime = LocalDateTime.of(availableDate.getDate(), availableDate.getTime());
// 7. 이벤트 발행
MemberDTO member = memberClient.getMember(memberId);
RestaurantDTO restaurant = restaurantClient.getRestaurant(reservation.getRestaurantId());
LocalDateTime dateTime = LocalDateTime.of(newAvailableDate.getDate(), newAvailableDate.getTime());
ReservationUpdatedEvent event = new ReservationUpdatedEvent(
reservation, member.getName(), restaurant.getName(), dateTime);
updatedReservation, member.getName(), restaurant.getName(), dateTime);
eventPublishService.publishReservationUpdatedEvent(event);
return new CreateReservationResponse(reservation, restaurant.getName(), availableDate);
return new CreateReservationResponse(updatedReservation, restaurant.getName(), newAvailableDate);
}
@Transactional
public void cancel(Long reservationId, String memberId) {
UpdateReservationDTO updateRequest = new UpdateReservationDTO(
request.getRestaurantId(),
request.getAvailableDateId(),
request.getPartySize(),
request.getSpecialRequest()
);
ReservationDTO updatedReservation;
try {
updatedReservation = reservationClient.updateReservation(reservationId, updateRequest);
} catch (RuntimeException ex) {
availableDateClient.decreaseCapacity(new DecreaseCapacityRequest(
reservation.getAvailableDateId(), reservation.getPartySize()));
availableDateClient.increaseCapacity(new IncreaseCapacityRequest(
request.getAvailableDateId(), request.getPartySize()));
throw ex;
}
// 7. 이벤트 발행
MemberDTO member = memberClient.getMember(memberId);
RestaurantDTO restaurant = restaurantClient.getRestaurant(reservation.getRestaurantId());
LocalDateTime dateTime = LocalDateTime.of(newAvailableDate.getDate(), newAvailableDate.getTime());
ReservationUpdatedEvent event = new ReservationUpdatedEvent(
updatedReservation, member.getName(), restaurant.getName(), dateTime);
eventPublishService.publishReservationUpdatedEvent(event);
return new CreateReservationResponse(updatedReservation, restaurant.getName(), newAvailableDate);
}
public void cancel(Long reservationId, String memberId) {

Comment on lines +195 to 203
MemberDTO member = memberClient.getMember(memberId);
RestaurantDTO restaurant = restaurantClient.getRestaurant(reservation.getRestaurantId());
LocalDateTime dateTime = LocalDateTime.of(newAvailableDate.getDate(), newAvailableDate.getTime());
ReservationUpdatedEvent event = new ReservationUpdatedEvent(
reservation, member.getName(), restaurant.getName(), dateTime);
updatedReservation, member.getName(), restaurant.getName(), dateTime);
eventPublishService.publishReservationUpdatedEvent(event);
return new CreateReservationResponse(reservation, restaurant.getName(), availableDate);

return new CreateReservationResponse(updatedReservation, restaurant.getName(), newAvailableDate);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

업데이트 이벤트/응답에 구 식당 정보가 사용됩니다

Line [197]에서 reservation.getRestaurantId()로 식당 정보를 조회하는데, 이는 업데이트 이전의 식당 ID입니다. 사용자가 다른 식당으로 변경하면 이벤트와 응답이 모두 구 식당 이름을 포함하게 되어 잘못된 데이터가 내려갑니다. updatedReservation.getRestaurantId()로 조회 대상을 바꿔 주세요.

-        RestaurantDTO restaurant = restaurantClient.getRestaurant(reservation.getRestaurantId());
+        RestaurantDTO restaurant = restaurantClient.getRestaurant(updatedReservation.getRestaurantId());
🤖 Prompt for AI Agents
In api-user/src/main/java/com/wellmeet/reservation/ReservationService.java
around lines 195 to 203, the code fetches restaurant info using
reservation.getRestaurantId() (the old restaurant) which causes the event and
response to carry the previous restaurant name; change the lookup to use
updatedReservation.getRestaurantId() so restaurantClient.getRestaurant(...)
retrieves the new restaurant, then use that restaurant.getName() when
constructing ReservationUpdatedEvent and the CreateReservationResponse so both
the event and the response reflect the updated restaurant.

Comment on lines +218 to +224
// 3. 보상 트랜잭션: Capacity 복구
availableDateClient.increaseCapacity(new IncreaseCapacityRequest(
reservation.getAvailableDateId(), reservation.getPartySize()));

// 4. Reservation 취소
reservationClient.cancelReservation(reservationId);

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

예약 취소 실패 시 좌석이 풀려버립니다

Line [220]에서 수용 인원을 먼저 복구한 뒤 Line [223]에서 취소 요청을 보냅니다. 취소 호출이 실패하면 좌석은 이미 풀렸지만 예약은 그대로 남아 과예약이 발생합니다. 취소가 성공한 뒤에야 용량을 복구하도록 순서를 바꾸거나 실패 시 롤백을 넣어 주세요.

-        availableDateClient.increaseCapacity(new IncreaseCapacityRequest(
-                reservation.getAvailableDateId(), reservation.getPartySize()));
-
-        // 4. Reservation 취소
-        reservationClient.cancelReservation(reservationId);
+        // 4. Reservation 취소
+        reservationClient.cancelReservation(reservationId);
+
+        // 5. 보상 트랜잭션: Capacity 복구
+        availableDateClient.increaseCapacity(new IncreaseCapacityRequest(
+                reservation.getAvailableDateId(), reservation.getPartySize()));

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In api-user/src/main/java/com/wellmeet/reservation/ReservationService.java
around lines 218-224, the code increases capacity before calling
reservationClient.cancelReservation, which can leave seats freed if the cancel
call fails; change the flow to call
reservationClient.cancelReservation(reservationId) first and only call
availableDateClient.increaseCapacity(...) after a successful cancel, or if you
cannot reorder, wrap the increaseCapacity call in a try/catch and on
cancellation failure perform a compensating call
(availableDateClient.decreaseCapacity or a matching rollback request) to revert
the capacity change, ensure both operations handle and propagate exceptions
properly and add logging/metrics for any rollback attempts.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
api-user/src/main/java/com/wellmeet/restaurant/RestaurantService.java (2)

30-42: 확장성 문제: 모든 레스토랑을 메모리에서 필터링

Line 31에서 getAllRestaurants()를 호출하여 모든 레스토랑을 가져온 후 인메모리에서 거리 기준으로 필터링하고 있습니다. 레스토랑 수가 증가하면 메모리와 CPU 부하가 증가하며, 불필요한 네트워크 트래픽이 발생합니다.

domain-restaurant-service에서 좌표와 반경을 파라미터로 받아 데이터베이스 레벨에서 공간 인덱스를 활용한 필터링 API를 제공하는 것이 바람직합니다.


55-75: Chatty API 패턴으로 인한 지연 시간 증가

단일 응답을 생성하기 위해 5개의 개별 API 호출을 순차적으로 수행하고 있습니다 (Lines 56, 59, 61, 66, 71). 이러한 패턴은 높은 지연 시간을 유발합니다.

BFF 패턴의 일반적인 최적화 방법으로, domain-restaurant-service에서 레스토랑 상세 정보에 필요한 모든 데이터(리뷰, 메뉴, 평점)를 집계하여 단일 응답으로 제공하는 API를 고려하세요.

🧹 Nitpick comments (7)
api-user/src/main/resources/application-dev.yml (1)

18-24: Feign 클라이언트 기본 설정이 구성됨.

connectTimeout 5000ms, readTimeout 5000ms, loggerLevel BASIC으로 설정되어 있습니다. 개발 환경에서는 DEBUG 레벨의 로깅이 더 유용할 수 있으므로 필요시 조정을 고려하세요.

개발 환경에서 더 자세한 디버깅을 원할 경우, loggerLevel을 FULL로 변경하는 것을 검토해보세요:

feign:
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 5000
-       loggerLevel: BASIC
+       loggerLevel: FULL
api-user/src/main/resources/application-local.yml (1)

17-23: Feign 클라이언트 설정이 dev 프로필과 일관되게 구성됨.

타임아웃 및 로깅 설정이 dev 환경과 동일하게 유지되어 일관성이 있습니다. 다만 로컬 개발 환경에서는 FULL 로깅 레벨이 더 유용할 수 있습니다.

로컬 환경에서 Feign 클라이언트 호출 상세 로깅이 필요한 경우, loggerLevel을 FULL로 변경하세요:

feign:
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 5000
-       loggerLevel: BASIC
+       loggerLevel: FULL
api-user/src/test/java/com/wellmeet/global/event/listener/ReservationEventListenerTest.java (3)

37-41: 테스트의 결정성(deterministic)을 위해 고정된 시간 사용을 권장합니다.

LocalDateTime.now()를 사용하면 테스트 실행 시점마다 다른 시간 값이 생성되어 테스트의 재현성이 떨어질 수 있습니다.

테스트 클래스 상단에 고정된 시간 상수를 선언하여 사용하는 것을 권장합니다:

 @ExtendWith(MockitoExtension.class)
 class ReservationEventListenerTest {
 
+    private static final LocalDateTime FIXED_DATE_TIME = LocalDateTime.of(2024, 1, 15, 14, 30);
+
     @Mock
     private KafkaProducerService kafkaProducerService;

그리고 테스트 메서드에서 다음과 같이 사용:

         @Test
         void 예약_생성_이벤트를_처리하여_Kafka로_알림_메시지를_발송한다() {
             ReservationDTO reservation = createReservationDTO();
-            LocalDateTime dateTime = LocalDateTime.now().plusDays(1);
+            LocalDateTime dateTime = FIXED_DATE_TIME;
             ReservationCreatedEvent event = new ReservationCreatedEvent(
                     reservation, "홍길동", "맛집", dateTime
             );

Also applies to: 57-61, 77-81


45-48: 페이로드 내용 검증을 추가하면 테스트 커버리지가 향상됩니다.

현재 any(ReservationCreatedPayload.class) 등을 사용하여 페이로드 타입만 검증하고 있는데, 실제 페이로드의 내용(memberName, restaurantName, dateTime 등)을 검증하면 이벤트 리스너의 동작을 더 정확하게 테스트할 수 있습니다.

ArgumentCaptor를 사용하여 페이로드 내용을 검증하는 예시:

+import static org.assertj.core.api.Assertions.assertThat;
+import org.mockito.ArgumentCaptor;

         @Test
         void 예약_생성_이벤트를_처리하여_Kafka로_알림_메시지를_발송한다() {
             ReservationDTO reservation = createReservationDTO();
             LocalDateTime dateTime = LocalDateTime.now().plusDays(1);
             ReservationCreatedEvent event = new ReservationCreatedEvent(
                     reservation, "홍길동", "맛집", dateTime
             );
 
             reservationEventListener.handleReservationCreated(event);
 
+            ArgumentCaptor<ReservationCreatedPayload> payloadCaptor = 
+                    ArgumentCaptor.forClass(ReservationCreatedPayload.class);
             verify(kafkaProducerService).sendNotificationMessage(
                     eq(reservation.getRestaurantId()),
-                    any(ReservationCreatedPayload.class)
+                    payloadCaptor.capture()
             );
+            
+            ReservationCreatedPayload payload = payloadCaptor.getValue();
+            assertThat(payload.getMemberName()).isEqualTo("홍길동");
+            assertThat(payload.getRestaurantName()).isEqualTo("맛집");
         }

Also applies to: 65-68, 85-88


92-104: 헬퍼 메서드에서도 고정된 시간 사용을 권장합니다.

createReservationDTO() 메서드에서 LocalDateTime.now()를 사용하고 있어 동일한 비결정성 문제가 있습니다.

앞서 제안한 고정 상수를 활용하여 수정:

     private ReservationDTO createReservationDTO() {
         return ReservationDTO.builder()
                 .id(1L)
                 .restaurantId("restaurant-1")
                 .availableDateId(1L)
                 .memberId("member-1")
                 .partySize(4)
                 .specialRequest("창가 자리 부탁드립니다")
                 .status("CONFIRMED")
-                .createdAt(LocalDateTime.now())
-                .updatedAt(LocalDateTime.now())
+                .createdAt(FIXED_DATE_TIME)
+                .updatedAt(FIXED_DATE_TIME)
                 .build();
     }
api-user/src/main/java/com/wellmeet/client/FavoriteRestaurantClient.java (1)

21-22: POST 요청에 Request Body 사용을 고려하세요.

현재 @RequestParam을 사용하고 있어 기능상 문제는 없지만, RESTful 관례상 POST 요청은 @RequestBody와 DTO를 사용하는 것이 더 적합합니다. 향후 파라미터가 추가될 경우 확장성도 개선됩니다.

예시:

// DTO 추가
public record AddFavoriteRequest(String memberId, String restaurantId) {}

// 클라이언트 메서드 수정
@PostMapping
FavoriteRestaurantDTO addFavorite(@RequestBody AddFavoriteRequest request);
api-user/src/main/java/com/wellmeet/client/RestaurantClient.java (1)

19-60: 클라이언트 책임을 분리하는 것을 고려하세요.

RestaurantClient가 레스토랑, 리뷰, 메뉴 관련 엔드포인트를 모두 포함하고 있습니다. 특히 Lines 52-56은 /api/reviews, Line 58-59는 /api/menus로 시작하는 다른 도메인의 엔드포인트입니다.

단일 책임 원칙(SRP)을 준수하고 유지보수성을 높이기 위해 별도의 ReviewClientMenuClient로 분리하는 것을 권장합니다.

예시:

@FeignClient(name = "domain-restaurant-service", contextId = "reviewClient", path = "/api/reviews")
public interface ReviewClient {
    @GetMapping("/restaurant/{restaurantId}/average-rating")
    Double getAverageRating(@PathVariable("restaurantId") String restaurantId);
    
    @GetMapping("/restaurant/{restaurantId}")
    List<ReviewDTO> getReviewsByRestaurant(@PathVariable("restaurantId") String restaurantId);
}

@FeignClient(name = "domain-restaurant-service", contextId = "menuClient", path = "/api/menus")
public interface MenuClient {
    @GetMapping("/restaurant/{restaurantId}")
    List<MenuDTO> getMenusByRestaurant(@PathVariable("restaurantId") String restaurantId);
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 62493a8 and a18a8bd.

📒 Files selected for processing (14)
  • api-owner/src/main/resources/application-dev.yml (0 hunks)
  • api-owner/src/test/java/com/wellmeet/DataBaseCleaner.java (0 hunks)
  • api-user/src/main/java/com/wellmeet/client/AvailableDateClient.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/FavoriteRestaurantClient.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/MemberClient.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/client/RestaurantClient.java (1 hunks)
  • api-user/src/main/java/com/wellmeet/restaurant/RestaurantService.java (2 hunks)
  • api-user/src/main/resources/application-dev.yml (1 hunks)
  • api-user/src/main/resources/application-local.yml (1 hunks)
  • api-user/src/main/resources/application-test.yml (1 hunks)
  • api-user/src/test/java/com/wellmeet/BaseControllerTest.java (0 hunks)
  • api-user/src/test/java/com/wellmeet/BaseServiceTest.java (0 hunks)
  • api-user/src/test/java/com/wellmeet/DataBaseCleaner.java (0 hunks)
  • api-user/src/test/java/com/wellmeet/global/event/listener/ReservationEventListenerTest.java (4 hunks)
💤 Files with no reviewable changes (5)
  • api-owner/src/main/resources/application-dev.yml
  • api-owner/src/test/java/com/wellmeet/DataBaseCleaner.java
  • api-user/src/test/java/com/wellmeet/BaseControllerTest.java
  • api-user/src/test/java/com/wellmeet/DataBaseCleaner.java
  • api-user/src/test/java/com/wellmeet/BaseServiceTest.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • api-user/src/main/java/com/wellmeet/client/MemberClient.java
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-10T02:52:48.337Z
Learnt from: unifolio0
Repo: Team-soft-macaron/WellMeet-Backend PR: 14
File: src/main/java/com/wellmeet/recommend/dto/RecommendRestaurantResponse.java:3-3
Timestamp: 2025-07-10T02:52:48.337Z
Learning: The Restaurant class is located at `com.wellmeet.restaurant.domain.Restaurant` after the package refactoring in the WellMeet-Backend project, not in a nested model package structure.

Applied to files:

  • api-user/src/main/java/com/wellmeet/client/RestaurantClient.java
  • api-user/src/main/java/com/wellmeet/restaurant/RestaurantService.java
  • api-user/src/main/java/com/wellmeet/client/FavoriteRestaurantClient.java
🧬 Code graph analysis (1)
api-user/src/main/java/com/wellmeet/restaurant/RestaurantService.java (1)
api-user/src/main/java/com/wellmeet/common/util/DistanceCalculator.java (1)
  • DistanceCalculator (3-18)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-and-push
🔇 Additional comments (14)
api-user/src/main/resources/application-dev.yml (3)

2-3: 애플리케이션 이름 설정이 일관성 있게 변경됨.

BFF 패턴으로의 전환에 맞춰 application.name을 api-user-service로 명확하게 설정하여 마이크로서비스 아키텍처 내에서 서비스 식별이 용이하게 했습니다.


10-11: 서버 포트가 명시적으로 설정됨.

포트 8086은 다른 마이크로서비스와 구분되는 포트로 설정되어 있으며, BFF 패턴 전환 후 별도의 HTTP 포트 필요성에 부합합니다.


13-16: Eureka 클라이언트 설정이 적절하게 구성됨.

로컬/개발 환경에서 Eureka 서버(localhost:8761)에 정상적으로 등록되도록 설정되어 있습니다. 서비스 디스커버리가 정상 작동할 것으로 예상됩니다.

api-user/src/main/resources/application-local.yml (4)

2-3: 애플리케이션 이름이 dev 프로필과 일관되게 설정됨.

api-user-service로 설정되어 로컬 환경에서도 서비스 식별이 일관성 있게 유지됩니다.


9-10: 서버 포트가 dev 프로필과 일관되게 설정됨.

포트 8086으로 설정되어 로컬 환경에서도 개발/테스트 환경과 동일한 포트로 운영되어 일관성이 유지됩니다.


12-15: Eureka 설정이 dev 프로필과 동일하게 구성됨.

로컬 개발 환경에서도 Eureka 서비스 디스커버리가 정상 작동하도록 설정되어 있습니다.


6-7: 인프라 설정 임포트가 보존됨.

Redis와 Kafka 인프라 설정이 유지되어 캐싱 및 메시징 기능이 로컬 환경에서도 정상 작동할 것으로 예상됩니다. domain 설정의 제거는 BFF 패턴 전환 의도와 일치합니다.

api-user/src/test/java/com/wellmeet/global/event/listener/ReservationEventListenerTest.java (1)

1-31: 전체 테스트 구조가 잘 정리되어 있습니다.

DTO 기반 전환이 일관되게 적용되었고, @nested 클래스를 사용한 테스트 구조가 명확합니다.

api-user/src/main/resources/application-test.yml (3)

5-7: 도메인 테스트 설정 임포트 누락 확인 필요

AI 요약에서 "application-domain-test.yml 누락을 제거하여 복구"했다고 기술되어 있으나, 현재 코드의 임포트 섹션에는 application-infra-redis-test.ymlapplication-infra-kafka-test.yml만 포함되어 있습니다. BFF 패턴 전환 시 도메인 관련 테스트 설정이 필요한지 확인이 필요합니다.

도메인 테스트 설정 파일이 필요한 경우 다음과 같이 추가하세요:

  config:
    import:
      - classpath:application-infra-redis-test.yml
      - classpath:application-infra-kafka-test.yml
+     - classpath:application-domain-test.yml

8-11: DataSource/JPA 자동 구성 제외 설정 적절

BFF 패턴으로의 전환에서 이 모듈이 데이터베이스를 직접 사용하지 않고 Feign 클라이언트를 통해 마이크로서비스를 호출하도록 변경되었으므로, 데이터 소스 및 Hibernate JPA 자동 구성을 제외하는 것이 적절합니다.


25-31: Feign 클라이언트 타임아웃 설정은 합리적이나 수동 검증 필요

코드 분석 결과 api-user 모듈에서 6개의 Feign 클라이언트가 정의되어 있으며, 모두 5000ms 타임아웃으로 일관되게 설정되어 있습니다. 호출되는 다운스트림 서비스는 RestaurantClient, ReservationClient, OwnerClient, MemberClient, FavoriteRestaurantClient, AvailableDateClient이며, 대부분 단순한 ID 기반 조회나 생성 작업입니다.

5초 타임아웃은 마이크로서비스 아키텍처에서 표준적인 합리적 값입니다. 다만, 실제 적절성 판단을 위해서는 각 다운스트림 서비스의 평균 응답 시간 및 SLA를 확인하여 설정값이 이에 부합하는지 수동으로 검증하시기 바랍니다.

api-user/src/main/java/com/wellmeet/client/FavoriteRestaurantClient.java (1)

12-26: Feign 클라이언트 구조가 잘 구성되었습니다.

전반적인 인터페이스 설계가 명확하고, 적절한 HTTP 메서드와 엔드포인트 매핑이 사용되었습니다.

api-user/src/main/java/com/wellmeet/restaurant/RestaurantService.java (1)

46-47: Null 처리가 안전하게 구현되었습니다.

BooleanDouble 래퍼 타입에 대한 null 처리가 적절합니다. Line 57의 Boolean.TRUE.equals(isFavorite) 패턴과 Lines 47, 72의 삼항 연산자를 통한 기본값 처리가 NPE를 방지합니다.

Also applies to: 56-57, 71-72

api-user/src/main/java/com/wellmeet/client/AvailableDateClient.java (1)

13-24: Feign 클라이언트 구현이 우수합니다.

AvailableDateClient는 명확한 책임 분리와 적절한 HTTP 메서드 사용으로 잘 설계되었습니다. GET으로 조회, PUT으로 용량 변경을 수행하는 RESTful 패턴을 따르고 있습니다.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (2)
domain-reservation/src/main/resources/application-dev.yml (1)

44-55: 운영 고려사항: 개발 환경에서 관리 엔드포인트 노출

현재 설정에서 /actuator/health, /actuator/metrics, /actuator/prometheus 등이 노출되고 있습니다. 개발 환경에서는 적절하나, 프로덕션 환경 설정으로 전환할 때 이러한 엔드포인트의 접근 제어를 검토하시기 바랍니다. 특히 metrics과 prometheus 엔드포인트는 민감한 정보를 노출할 수 있으므로 인증이 필요할 수 있습니다.

domain-owner/src/main/resources/application-test.yml (1)

23-27: Eureka 설정에서 불필요한 중복 제거

enabled: false가 설정되어 있을 때, 하위의 register-with-eurekafetch-registry 속성은 무시됩니다. 더 간결한 구성을 위해 이 두 속성을 제거할 수 있습니다.

 eureka:
   client:
     enabled: false
-    register-with-eureka: false
-    fetch-registry: false
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a18a8bd and 706c1a4.

📒 Files selected for processing (26)
  • .github/workflows/Dev_Member_CD.yml (1 hunks)
  • .github/workflows/Dev_Owner_CD.yml (1 hunks)
  • .github/workflows/Dev_Owner_Domain_CD.yml (1 hunks)
  • .github/workflows/Dev_Reservation_CD.yml (1 hunks)
  • .github/workflows/Dev_Restaurant_CD.yml (1 hunks)
  • .github/workflows/Dev_User_CD.yml (1 hunks)
  • batch-reminder/src/main/resources/application-dev.yml (0 hunks)
  • batch-reminder/src/main/resources/application-local.yml (0 hunks)
  • batch-reminder/src/main/resources/application-test.yml (0 hunks)
  • domain-member/src/main/resources/application-dev.yml (1 hunks)
  • domain-member/src/main/resources/application-domain-test.yml (0 hunks)
  • domain-member/src/main/resources/application-local.yml (1 hunks)
  • domain-member/src/main/resources/application-test.yml (1 hunks)
  • domain-owner/src/main/resources/application-dev.yml (1 hunks)
  • domain-owner/src/main/resources/application-local.yml (1 hunks)
  • domain-owner/src/main/resources/application-test.yml (1 hunks)
  • domain-reservation/src/main/resources/application-dev.yml (1 hunks)
  • domain-reservation/src/main/resources/application-domain-dev.yml (0 hunks)
  • domain-reservation/src/main/resources/application-domain-local.yml (0 hunks)
  • domain-reservation/src/main/resources/application-domain-test.yml (0 hunks)
  • domain-reservation/src/main/resources/application-local.yml (1 hunks)
  • domain-reservation/src/main/resources/application-test.yml (1 hunks)
  • domain-restaurant/src/main/resources/application-dev.yml (1 hunks)
  • domain-restaurant/src/main/resources/application-domain-test.yml (0 hunks)
  • domain-restaurant/src/main/resources/application-local.yml (1 hunks)
  • domain-restaurant/src/main/resources/application-test.yml (1 hunks)
💤 Files with no reviewable changes (8)
  • batch-reminder/src/main/resources/application-local.yml
  • batch-reminder/src/main/resources/application-test.yml
  • batch-reminder/src/main/resources/application-dev.yml
  • domain-reservation/src/main/resources/application-domain-local.yml
  • domain-reservation/src/main/resources/application-domain-dev.yml
  • domain-member/src/main/resources/application-domain-test.yml
  • domain-restaurant/src/main/resources/application-domain-test.yml
  • domain-reservation/src/main/resources/application-domain-test.yml
✅ Files skipped from review due to trivial changes (5)
  • domain-member/src/main/resources/application-dev.yml
  • domain-restaurant/src/main/resources/application-local.yml
  • domain-reservation/src/main/resources/application-local.yml
  • domain-restaurant/src/main/resources/application-dev.yml
  • domain-owner/src/main/resources/application-dev.yml
🧰 Additional context used
🪛 actionlint (1.7.8)
.github/workflows/Dev_Member_CD.yml

63-63: label "dev-member" is unknown. available labels are "windows-latest", "windows-latest-8-cores", "windows-2025", "windows-2022", "windows-11-arm", "ubuntu-latest", "ubuntu-latest-4-cores", "ubuntu-latest-8-cores", "ubuntu-latest-16-cores", "ubuntu-24.04", "ubuntu-24.04-arm", "ubuntu-22.04", "ubuntu-22.04-arm", "macos-latest", "macos-latest-xl", "macos-latest-xlarge", "macos-latest-large", "macos-26-xlarge", "macos-26", "macos-15-intel", "macos-15-xlarge", "macos-15-large", "macos-15", "macos-14-xl", "macos-14-xlarge", "macos-14-large", "macos-14", "macos-13-xl", "macos-13-xlarge", "macos-13-large", "macos-13", "self-hosted", "x64", "arm", "arm64", "linux", "macos", "windows". if it is a custom label for self-hosted runner, set list of labels in actionlint.yaml config file

(runner-label)

.github/workflows/Dev_Restaurant_CD.yml

63-63: label "dev-restaurant" is unknown. available labels are "windows-latest", "windows-latest-8-cores", "windows-2025", "windows-2022", "windows-11-arm", "ubuntu-latest", "ubuntu-latest-4-cores", "ubuntu-latest-8-cores", "ubuntu-latest-16-cores", "ubuntu-24.04", "ubuntu-24.04-arm", "ubuntu-22.04", "ubuntu-22.04-arm", "macos-latest", "macos-latest-xl", "macos-latest-xlarge", "macos-latest-large", "macos-26-xlarge", "macos-26", "macos-15-intel", "macos-15-xlarge", "macos-15-large", "macos-15", "macos-14-xl", "macos-14-xlarge", "macos-14-large", "macos-14", "macos-13-xl", "macos-13-xlarge", "macos-13-large", "macos-13", "self-hosted", "x64", "arm", "arm64", "linux", "macos", "windows". if it is a custom label for self-hosted runner, set list of labels in actionlint.yaml config file

(runner-label)

.github/workflows/Dev_Owner_Domain_CD.yml

63-63: label "dev-owner-domain" is unknown. available labels are "windows-latest", "windows-latest-8-cores", "windows-2025", "windows-2022", "windows-11-arm", "ubuntu-latest", "ubuntu-latest-4-cores", "ubuntu-latest-8-cores", "ubuntu-latest-16-cores", "ubuntu-24.04", "ubuntu-24.04-arm", "ubuntu-22.04", "ubuntu-22.04-arm", "macos-latest", "macos-latest-xl", "macos-latest-xlarge", "macos-latest-large", "macos-26-xlarge", "macos-26", "macos-15-intel", "macos-15-xlarge", "macos-15-large", "macos-15", "macos-14-xl", "macos-14-xlarge", "macos-14-large", "macos-14", "macos-13-xl", "macos-13-xlarge", "macos-13-large", "macos-13", "self-hosted", "x64", "arm", "arm64", "linux", "macos", "windows". if it is a custom label for self-hosted runner, set list of labels in actionlint.yaml config file

(runner-label)

.github/workflows/Dev_Reservation_CD.yml

63-63: label "dev-reservation" is unknown. available labels are "windows-latest", "windows-latest-8-cores", "windows-2025", "windows-2022", "windows-11-arm", "ubuntu-latest", "ubuntu-latest-4-cores", "ubuntu-latest-8-cores", "ubuntu-latest-16-cores", "ubuntu-24.04", "ubuntu-24.04-arm", "ubuntu-22.04", "ubuntu-22.04-arm", "macos-latest", "macos-latest-xl", "macos-latest-xlarge", "macos-latest-large", "macos-26-xlarge", "macos-26", "macos-15-intel", "macos-15-xlarge", "macos-15-large", "macos-15", "macos-14-xl", "macos-14-xlarge", "macos-14-large", "macos-14", "macos-13-xl", "macos-13-xlarge", "macos-13-large", "macos-13", "self-hosted", "x64", "arm", "arm64", "linux", "macos", "windows". if it is a custom label for self-hosted runner, set list of labels in actionlint.yaml config file

(runner-label)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-and-push
🔇 Additional comments (25)
domain-reservation/src/main/resources/application-test.yml (1)

1-45: 테스트 프로필 설정이 적절하게 구성되었습니다.

이 파일은 domain-reservation 모듈의 테스트 환경을 위한 표준적인 Spring Boot 설정을 제공합니다. Eureka 비활성화, Flyway 마이그레이션 제거, create-drop 스키마 전략 등 테스트 프로필의 모범 사례를 따르고 있습니다.

다만 다음 항목들을 확인하시기 바랍니다:

  1. Line 9 - 빈 데이터베이스 비밀번호: 로컬 개발/테스트 환경을 위한 의도된 설정인지 확인하세요. 프로덕션 환경 설정이 아님을 다시 한 번 확인하세요.

  2. Line 18 - show-sql 활성화: 테스트 중 SQL 로깅은 표준 관행이지만, 고성능 테스트가 필요한 경우 검토를 고려하세요.

  3. api-user 모듈과의 포트 분리: 이 파일에서는 8085 포트를 사용하며, PR 요약에 따르면 api-user 모듈은 8086 포트를 사용합니다. 모듈 간 포트 충돌이 없음을 확인했습니다.

domain-owner/src/main/resources/application-local.yml (4)

7-7: 비표준 MySQL 포트 확인

MySQL이 3308 포트에서 실행 중인 것이 의도된 설정인지 확인하세요. 표준 포트는 3306입니다.


11-18: JPA/Hibernate 설정 양호

  • ddl-auto: validate - 스키마 검증 전용, 안전함 ✓
  • show-sql: false - 성능상 좋은 설정 ✓
  • open-in-view: false - 명시적 세션 관리, 모범 사례 ✓

23-33: Eureka 클라이언트 설정 확인

로컬 개발 환경용으로 적절합니다. 다만 http://localhost:8761/eureka/ 엔드포인트가 로컬에서 실행 중인지 확인하세요. BFF 전환 시 서비스 디스커버리가 제대로 작동해야 합니다.


44-47: 로깅 레벨 설정 양호

로컬 개발 환경에서 디버깅에 적합합니다. 운영 환경에서는 로깅 레벨을 조정하는 별도의 프로파일(application-prod.yml 등)을 사용하세요.

domain-reservation/src/main/resources/application-dev.yml (2)

44-65: 요약과 실제 코드 간 불일치 감지

AI 요약에서는 Actuator 설정 블록과 로깅 설정이 제거되었다고 명시했으나, 최종 코드에는 관리 엔드포인트(라인 44-55)와 로깅 설정(라인 57-65)이 여전히 존재합니다. 코드가 최종 상태를 나타내므로 이는 요약과의 불일치를 나타냅니다.


33-33: Eureka 클라이언트 활성화 — BFF 아키텍처에 적절함

Eureka 클라이언트를 활성화한 변경사항(라인 33)은 BFF 전환에 따른 마이크로서비스 환경에서의 서비스 디스커버리를 위해 적절합니다. Eureka 설정(service-url, register-with-eureka, fetch-registry)이 올바르게 구성되어 있습니다.

Also applies to: 31-42

domain-member/src/main/resources/application-test.yml (1)

1-41: 테스트 환경 설정이 적절하게 구성되었습니다.

포트 충돌 검증 결과:

  • 포트 8082는 고유하며 다른 서비스와 충돌하지 않습니다 (api-user: 8086, domain-owner: 8084, domain-reservation: 8085, domain-restaurant: 8083)
  • 도메인-멤버 서비스의 테스트 설정이 전반적으로 우수한 관행을 따릅니다:
    • Eureka 클라이언트 비활성화로 테스트 중 서비스 디스커버리 간섭 방지
    • create-drop DDL 정책으로 테스트 격리 보장
    • open-in-view: false 설정으로 N+1 쿼리 문제 방지
    • DEBUG 로깅 활성화로 테스트 진단 지원
.github/workflows/Dev_Owner_CD.yml (1)

8-11: api-owner 워크플로우에 인프라 모듈 의존성 추가됨

infra-redis/**infra-kafka/** 경로가 트리거 조건에 추가되었습니다. 이는 api-owner 모듈이 이제 인프라 컴포넌트에 의존한다는 것을 시사합니다. BFF 전환에 따른 마이크로서비스 통신 구조 변경과 일치하므로 적절해 보입니다.

.github/workflows/Dev_Restaurant_CD.yml (1)

1-79: CI/CD 워크플로우 구조 양호 — 커스텀 runner 레이블 설정 확인 필요

dev-restaurant-cd 워크플로우가 다른 도메인 모듈들과 일관성 있는 패턴을 따르고 있습니다. 빌드, 아티팩트 업로드, 배포 단계가 올바르게 구성되었습니다.

다만 정적 분석 도구(actionlint)에서 Line 63의 커스텀 runner 레이블 dev-restaurant을 인식하지 못하는 경고를 발생시킵니다. 이는 자체 호스팅 runner를 사용할 때 예상되는 경고이며, 리포지토리 설정에서 해당 runner 레이블이 올바르게 구성되어 있다면 문제없습니다.

.github/workflows/Dev_Member_CD.yml (1)

1-79: 일관성 있는 도메인 CD 파이프라인 패턴

dev-member-cd 워크플로우는 다른 도메인 모듈들과 동일한 구조와 설정을 유지하고 있으며, 테스트 → 빌드 → 배포 단계가 올바르게 구성되어 있습니다.

정적 분석 도구의 커스텀 runner 레이블(dev-member) 경고는 자체 호스팅 runner 사용 시 예상되는 것으로, 리포지토리에 해당 runner가 설정되어 있다면 문제가 되지 않습니다.

.github/workflows/Dev_Reservation_CD.yml (1)

1-79: 예약 도메인 CD 파이프라인 — 표준 패턴 준수

dev-reservation-cd 워크플로우가 확립된 도메인 배포 패턴을 일관성 있게 따르고 있습니다. JDK 21 설정, bootJar 빌드, 아티팩트 업로드, 배포 스크립트 실행이 모두 올바르게 구성되었습니다.

정적 분석의 커스텀 runner 레이블(dev-reservation) 경고는 자체 호스팅 runner 환경에서 예상되는 경고입니다.

.github/workflows/Dev_Owner_Domain_CD.yml (1)

1-79: 도메인 owner 배포 파이프라인 — BFF 아키텍처 지원

dev-owner-domain-cd 워크플로우가 다른 도메인 모듈 파이프라인과 일관성 있는 구조를 유지하고 있습니다. 이는 api-owner (BFF 모듈)와 별도로 domain-owner 서비스를 독립적으로 배포할 수 있게 해 줍니다.

정적 분석의 커스텀 runner 레이블(dev-owner-domain) 경고는 자체 호스팅 runner 사용 시 일반적인 경고입니다.

domain-member/src/main/resources/application-local.yml (5)

7-7: MySQL 포트 번호 확인이 필요합니다.

MySQL의 기본 포트는 3306이지만, 이 설정에서는 3307을 사용하고 있습니다. 이것이 의도적인 로컬 설정인지, 아니면 3306으로 수정해야 하는지 확인이 필요합니다.


11-18: JPA/Hibernate 설정이 모범 사례를 따릅니다.

ddl-auto: validate로 설정하여 스키마 자동 생성을 방지하고, show-sql: falseopen-in-view: false로 설정하여 성능과 안정성을 보장합니다. 이는 마이크로서비스 아키텍처에 적절한 구성입니다.


23-33: Eureka 서비스 디스커버리 설정이 올바르게 구성되었습니다.

마이크로서비스 등록, 레지스트리 페칭, 인스턴스 ID 및 리스 갱신 설정이 표준적이고 적절합니다. BFF 전환에 따른 서비스 간 통신에 필요한 설정이 잘 구성되어 있습니다.


35-42: Management 엔드포인트 설정이 적절합니다.

로컬 개발 환경에 필요한 health, info, metrics 엔드포인트가 노출되어 있고, show-details: always로 설정하여 디버깅에 도움이 됩니다.


44-47: 로깅 설정이 로컬 개발에 적합합니다.

com.wellmeet 패키지와 Hibernate SQL 쿼리를 DEBUG 레벨로 로깅하도록 설정하여 로컬 개발 시 디버깅에 유용합니다.

domain-restaurant/src/main/resources/application-test.yml (4)

11-19: JPA/Hibernate 테스트 설정이 적절합니다.

ddl-auto: create-drop, show-sql: true, open-in-view: false 등의 설정이 테스트 환경에 적합하게 구성되었습니다. 특히 create-drop은 각 테스트의 격리를 보장하고, open-in-view: false는 레이지 로딩 문제를 방지하는 권장 설정입니다.


29-42: Eureka 및 관리 엔드포인트 설정이 테스트 환경에 적합합니다.

Eureka 클라이언트 완전 비활성화, 제한된 관리 엔드포인트 노출(health, info, metrics), health 상세정보 활성화 등이 모두 테스트 환경에 적절한 구성입니다. 이는 마이크로서비스 디스커버리가 불필요한 테스트 환경에 맞는 설정입니다.


21-27: Jackson 설정은 적절하며, 서버 포트 충돌 우려는 없습니다.

포트 8083은 다른 모든 마이크로서비스 테스트 구성에서 고유하며, 전체 포트 할당이 8082-8086 범위에서 일관된 순차 패턴을 따릅니다. Jackson 설정(Asia/Seoul 시간대, ISO-8601 날짜 형식)도 표준적이고 적절합니다.


5-9: 리뷰 의견이 타당하지 않습니다. 포트 설정은 의도적이고 일관되어 있습니다.

검증 결과, domain-restaurant 서비스는 모든 환경(local, dev, test)에서 일관되게 포트 3309를 사용하고 있습니다. 이는 마이크로서비스 아키텍처에서 각 서비스의 데이터베이스를 격리하기 위한 의도적인 설계입니다:

  • domain-reservation: 3306
  • domain-restaurant: 3309
  • domain-member: 3307
  • domain-owner: 3308

각 서비스가 고유한 포트를 사용하는 것은 표준적이고 권장되는 패턴이므로, "다른 마이크로서비스 테스트 설정과 불일치"라는 우려는 근거가 없습니다.

Likely an incorrect or invalid review comment.

domain-owner/src/main/resources/application-test.yml (3)

11-18: 테스트용 JPA 설정 - 양호

테스트 환경에 적절한 Hibernate 설정입니다:

  • create-drop으로 각 테스트 실행 시 스키마 초기화
  • SQL 포맷팅과 표시로 디버깅 용이
  • open-in-view: false로 LazyInitializationException 방지

29-36: 관리 엔드포인트 설정 - 양호

테스트 환경에서 필요한 엔드포인트(health, info, metrics)만 노출하고 상세 정보 제공이 적절히 구성되어 있습니다.


38-41: 로깅 레벨 설정 - 양호

com.wellmeet 패키지와 Hibernate SQL에 대한 DEBUG 로깅이 테스트 환경에서의 디버깅을 충분히 지원합니다.

Comment on lines +9 to +11
- 'domain-common/**'
- 'infra-redis/**'
- 'infra-kafka/**'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

경로 트리거 변경이 실제 모듈 의존성과 일치하는지 확인이 필요합니다.

워크플로우 트리거가 domain/**domain-redis/** 패턴에서 domain-common/**, infra-redis/**, infra-kafka/**로 변경되었습니다. BFF 전환에 따른 변경으로 보이지만, 다음을 확인해 주세요:

  1. api-user의 실제 모듈 의존성이 이 세 모듈(domain-common, infra-redis, infra-kafka)만 포함하는지
  2. 이전의 다른 domain/** 모듈(예: domain-user, domain-restaurant 등)에 대한 의존성이 완전히 제거되었는지
  3. 새로 추가된 Feign 클라이언트나 마이크로서비스 통신이 이 모듈들만 필요로 하는지

다음 스크립트로 모듈 구조와 의존성을 확인해 주세요:

[/request_verification]


🏁 Script executed:

#!/bin/bash
# Description: Verify api-user module dependencies and structure

# Check settings.gradle to see all modules
echo "=== Modules in settings.gradle ==="
rg -n "include|:api-user|:domain|:infra" settings.gradle

# Check build.gradle for api-user dependencies
echo -e "\n=== api-user build.gradle dependencies ==="
fd "^build.gradle$" -x grep -l "api-user" {} \; 2>/dev/null || true
fd -u "^build.gradle$" | xargs grep -l "^include.*api-user" 2>/dev/null || grep -r "project.*api-user" --include="build.gradle" 2>/dev/null | head -5 || true

# List build.gradle files to understand structure
echo -e "\n=== build.gradle files in repository ==="
fd -u "^build.gradle$" | head -10

Length of output: 668


I need to check the actual dependencies in api-user/build.gradle to verify if the workflow trigger change is appropriate.

[/run_scripts]


🏁 Script executed:

#!/bin/bash
# Extract api-user dependencies from build.gradle

echo "=== api-user/build.gradle dependencies section ==="
grep -A 50 "dependencies" api-user/build.gradle | head -60

Length of output: 784


workflow 트리거에 domain-common/**을 포함하는 것은 제거하세요.

검증 결과, api-user/build.gradle의 실제 의존성은 infra-redis와 infra-kafka만 포함합니다. 어떤 domain 모듈도 의존하지 않습니다.

현재 설정:

- 'domain-common/**'
- 'infra-redis/**'
- 'infra-kafka/**'

올바른 설정:

- 'infra-redis/**'
- 'infra-kafka/**'

domain-common/**은 실제 의존성이 없으므로 제거하세요.

🤖 Prompt for AI Agents
.github/workflows/Dev_User_CD.yml around lines 9 to 11 currently includes
'domain-common/**' in the list of paths that trigger the workflow; remove that
entry so the triggers only include the actual dependencies 'infra-redis/**' and
'infra-kafka/**'. Edit the YAML to delete the 'domain-common/**' line, leaving
the two infra entries intact, and save the workflow file to ensure the workflow
no longer triggers on domain-common changes.

Comment on lines 8 to 9
username: root
password: password
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

데이터베이스 자격증명은 환경 변수로 외부화하세요.

로컬 환경 프로필이지만 하드코딩된 데이터베이스 자격증명(사용자명 및 비밀번호)이 버전 제어에 포함되는 것은 보안 위험입니다. 민감한 정보는 환경 변수나 외부 설정 서버(예: Spring Cloud Config)를 통해 관리하는 것이 권장됩니다.

환경 변수를 사용하도록 다음과 같이 수정하세요:

  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
-   url: jdbc:mysql://localhost:3307/wellmeet_member
-   username: root
-   password: password
+   url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3307}/wellmeet_member
+   username: ${DB_USERNAME:root}
+   password: ${DB_PASSWORD}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
username: root
password: password
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3307}/wellmeet_member
username: ${DB_USERNAME:root}
password: ${DB_PASSWORD}
🤖 Prompt for AI Agents
In domain-member/src/main/resources/application-local.yml around lines 8 to 9,
the DB username and password are hardcoded which is a security risk; change
these entries to read from environment variables (e.g., use Spring property
placeholders like ${DB_USERNAME} and ${DB_PASSWORD}, optionally with safe
non-sensitive defaults or no defaults), remove plaintext credentials from the
file, and update any README or .env.sample to show how to set DB_USERNAME and
DB_PASSWORD in the local environment before running.

Comment on lines 8 to 9
username: root
password: password
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

하드코딩된 데이터베이스 인증정보 제거 권장

로컬 개발 환경이더라도 평문 인증정보를 설정 파일에 저장하는 것은 보안 위험입니다. 환경 변수나 외부 설정 소스를 사용하여 민감한 정보를 관리하세요.

환경 변수 기반으로 마이그레이션하는 것을 고려하세요:

  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3308}/wellmeet_owner
    username: ${DB_USERNAME:root}
    password: ${DB_PASSWORD:password}

또는 로컬 개발 시에만 사용되는 .env.local 파일을 통해 값을 주입하는 방식을 추천합니다.

🤖 Prompt for AI Agents
In domain-owner/src/main/resources/application-local.yml around lines 8 to 9,
remove the hardcoded database credentials and replace them with
environment-variable placeholders (e.g. ${DB_USERNAME} and ${DB_PASSWORD}) with
optional safe defaults; update the datasource config to read URL/host/port from
env vars as well (e.g. ${DB_HOST}, ${DB_PORT}) or fallback values, and document
using a local .env or runtime environment variables for local dev so no
plaintext credentials remain in the repo.

Comment on lines 5 to 9
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3308/wellmeet_owner_test
username: root
password:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

데이터베이스 포트 및 자격증명 확인 요청

테스트 환경용으로 적절하지만, 다음 사항을 확인해주세요:

  • MySQL 포트 3308이 팀의 테스트 환경 기준과 일치하는지 확인 (표준 포트는 3306)
  • 빈 암호가 테스트 데이터베이스 설정과 일치하는지 확인

테스트 데이터베이스 설정을 확인하려면 다음 스크립트를 실행하세요:


🏁 Script executed:

#!/bin/bash
# Description: Verify test database configuration matches application-test.yml

# Check if there are other test configurations referencing MySQL
fd -e yml -e yaml | xargs grep -l "mysql" | head -10

# Search for database configuration references in tests or documentation
fd -e md -e txt | xargs grep -l "3308\|wellmeet_owner_test" 2>/dev/null || echo "No documentation references found"

Length of output: 526



🏁 Script executed:

#!/bin/bash
# Check docker-compose.yml for MySQL port configuration
echo "=== Docker Compose MySQL Configuration ==="
cat docker-compose.yml | grep -A 5 -B 2 "mysql\|3308\|MYSQL_ROOT_PASSWORD" || echo "Pattern not found in docker-compose"

echo -e "\n=== Comparing port/credentials across test configs ==="
for file in domain-owner/src/main/resources/application-test.yml domain-member/src/main/resources/application-test.yml domain-reservation/src/main/resources/application-test.yml; do
  echo "--- $file ---"
  grep -E "driver-class-name|url:|username:|password:" "$file" 2>/dev/null || echo "File not found"
done

echo -e "\n=== Check CLAUDE.md for test environment documentation ==="
grep -i -A 3 -B 3 "test\|3308\|database\|mysql" CLAUDE.md 2>/dev/null | head -30 || echo "No relevant documentation found"

Length of output: 5518


🏁 Script executed:

#!/bin/bash
# Inspect docker-compose.yml and test configs

echo "=== Docker Compose MySQL Configuration ==="
if [ -f "docker-compose.yml" ]; then
  cat docker-compose.yml
else
  echo "docker-compose.yml not found"
fi

echo -e "\n\n=== Test configs comparison ==="
echo "--- domain-owner/src/main/resources/application-test.yml ---"
cat domain-owner/src/main/resources/application-test.yml 2>/dev/null || echo "Not found"

echo -e "\n--- domain-member/src/main/resources/application-test.yml ---"
cat domain-member/src/main/resources/application-test.yml 2>/dev/null || echo "Not found"

echo -e "\n--- domain-reservation/src/main/resources/application-test.yml ---"
cat domain-reservation/src/main/resources/application-test.yml 2>/dev/null || echo "Not found"

Length of output: 7926


테스트 환경 설정의 암호 불일치 수정 필요

application-test.yml의 빈 암호 필드가 docker-compose.ymlMYSQL_ROOT_PASSWORD: password 설정과 맞지 않습니다. 포트 3308은 docker-compose.yml에서 mysql-owner 서비스로 올바르게 매핑되어 있으나, 암호가 일치해야 테스트 실행 시 데이터베이스 연결이 정상 작동합니다.

  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3308/wellmeet_owner_test
    username: root
    password: password
🤖 Prompt for AI Agents
In domain-owner/src/main/resources/application-test.yml around lines 5 to 9 the
datasource password is empty but docker-compose sets MYSQL_ROOT_PASSWORD to
"password"; update the password field to password so the test datasource
credentials match the running MySQL container (i.e., set password: password),
then verify tests connect to jdbc:mysql://localhost:3308/wellmeet_owner_test; if
you prefer not to commit plaintext secrets, replace with a reference to an
environment variable and document it in the test run instructions.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
discovery-server/src/main/resources/application-dev.yml (1)

15-22: 선택사항: 프로덕션 프로필에서는 management 엔드포인트 노출 범위를 제한하는 것을 고려하세요.

현재 설정에서 health 세부정보를 항상 표시(show-details: always)하고 metrics를 노출하는 것은 개발 환경에 적합합니다. 다만 프로덕션 프로필(예: application-prod.yml)에서는 민감한 정보 노출을 최소화하기 위해 엔드포인트 노출을 더 제한적으로 설정하기를 권장합니다.

.github/workflows/Dev_Discovery_CD.yml (1)

40-44: 빌드 아티팩트 명명의 모호성 해결

Line 44에서 *.jar 와일드카드를 사용하여 모든 JAR 파일을 app.jar로 이름 변경합니다. 만약 build/libs 디렉토리에 여러 JAR 파일이 존재하면(예: plain JAR와 bootJar), 예측 불가능한 동작이 발생할 수 있습니다. 보다 명확한 패턴을 사용하거나 gradle 빌드 설정에서 출력 JAR 이름을 명시적으로 지정하는 것이 좋습니다.

- name: Change artifact file name
- run: mv discovery-server/build/libs/*.jar discovery-server/build/libs/app.jar
+ name: Change artifact file name
+ run: mv discovery-server/build/libs/*-SNAPSHOT.jar discovery-server/build/libs/app.jar || mv discovery-server/build/libs/*.jar discovery-server/build/libs/app.jar

또는 build.gradle에서 bootJar 태스크의 출력 이름을 직접 설정하는 것을 권장합니다.

domain-member/src/main/resources/application-dev.yml (1)

1-50: 설정 파일 기본 구조 양호 - Jackson 타임존 설정 고려 권장

도메인 멤버 서비스의 개발 환경 설정이 표준 구조로 잘 구성되어 있습니다.

권장 사항: 현재 프로젝트에서 domain-restaurant 서비스(라인 24-27에서 확인 가능)처럼 Jackson 타임존 설정(time-zone: Asia/Seoul, write-dates-as-timestamps: false)을 추가하면 일관된 날짜/시간 직렬화를 보장할 수 있습니다. 특히 멤버 정보에 생성일자나 업데이트 시간이 포함되면 유용합니다.

  jpa:
    hibernate:
      ddl-auto: validate
    properties:
      hibernate:
        format_sql: true
    show-sql: false
    open-in-view: false

+  jackson:
+    time-zone: Asia/Seoul
+    serialization:
+      write-dates-as-timestamps: false

server:
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 706c1a4 and 37b1edd.

📒 Files selected for processing (15)
  • .github/workflows/Dev_Discovery_CD.yml (1 hunks)
  • api-owner/src/main/resources/application-dev.yml (1 hunks)
  • api-owner/src/main/resources/dev-secret.yml (1 hunks)
  • api-user/src/main/resources/application-dev.yml (1 hunks)
  • api-user/src/main/resources/dev-secret.yml (1 hunks)
  • discovery-server/src/main/resources/application-dev.yml (1 hunks)
  • discovery-server/src/main/resources/application-local.yml (1 hunks)
  • domain-member/src/main/resources/application-dev.yml (1 hunks)
  • domain-member/src/main/resources/dev-secret.yml (1 hunks)
  • domain-owner/src/main/resources/application-dev.yml (1 hunks)
  • domain-owner/src/main/resources/dev-secret.yml (1 hunks)
  • domain-reservation/src/main/resources/application-dev.yml (1 hunks)
  • domain-reservation/src/main/resources/dev-secret.yml (1 hunks)
  • domain-restaurant/src/main/resources/application-dev.yml (1 hunks)
  • domain-restaurant/src/main/resources/dev-secret.yml (1 hunks)
✅ Files skipped from review due to trivial changes (5)
  • domain-reservation/src/main/resources/dev-secret.yml
  • domain-member/src/main/resources/dev-secret.yml
  • discovery-server/src/main/resources/application-local.yml
  • api-user/src/main/resources/dev-secret.yml
  • domain-owner/src/main/resources/dev-secret.yml
🧰 Additional context used
🪛 actionlint (1.7.8)
.github/workflows/Dev_Discovery_CD.yml

62-62: label "dev-discovery-server" is unknown. available labels are "windows-latest", "windows-latest-8-cores", "windows-2025", "windows-2022", "windows-11-arm", "ubuntu-latest", "ubuntu-latest-4-cores", "ubuntu-latest-8-cores", "ubuntu-latest-16-cores", "ubuntu-24.04", "ubuntu-24.04-arm", "ubuntu-22.04", "ubuntu-22.04-arm", "macos-latest", "macos-latest-xl", "macos-latest-xlarge", "macos-latest-large", "macos-26-xlarge", "macos-26", "macos-15-intel", "macos-15-xlarge", "macos-15-large", "macos-15", "macos-14-xl", "macos-14-xlarge", "macos-14-large", "macos-14", "macos-13-xl", "macos-13-xlarge", "macos-13-large", "macos-13", "self-hosted", "x64", "arm", "arm64", "linux", "macos", "windows". if it is a custom label for self-hosted runner, set list of labels in actionlint.yaml config file

(runner-label)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-and-push
🔇 Additional comments (12)
discovery-server/src/main/resources/application-dev.yml (1)

1-22: 개발 환경 디스커버리 서버 설정이 적절하게 구성됨.

Eureka 디스커버리 서버를 위한 개발 환경 설정이 표준 구성을 따르고 있습니다. 다음 측면에서 좋은 설정입니다:

  • 표준 Eureka 포트(8761) 사용
  • 디스커버리 서버 자신이 레지스트리에 등록하지 않도록 설정 (register-with-eureka, fetch-registry: false)
  • Self-preservation 활성화로 네트워크 장애 시 서비스 정보 유지
  • 개발 환경에서의 관찰성을 위해 health, info, metrics 엔드포인트 노출

BFF 전환 시 마이크로서비스 간 서비스 디스커버리가 필요하므로 이 설정이 적절하게 지원합니다.

.github/workflows/Dev_Discovery_CD.yml (3)

13-17: 권한(Permissions) 설정 검토

현재 워크플로우 권한 설정에서 actions: read가 포함되어 있습니다. 이 워크플로우는 외부 액션(checkout, setup-java, upload-artifact, download-artifact)을 사용하지만, actions: read 권한이 실제로 필요한지 검증이 필요합니다. 일반적으로 이 워크플로우의 실제 필요 권한은 contents: readpull-requests: write 정도입니다.

최소 권한 원칙(Least Privilege)에 따라 다음 권한만 유지하는 것을 권장합니다:

 permissions:
   contents: read
-  checks: write
-  actions: read
   pull-requests: write

checks: write도 이 워크플로우에서 사용되지 않으므로 제거하는 것을 권장합니다.


20-21: 워크플로우 재사용 설정 검증 완료

Dev_CI.yml이 workflow_call 트리거로 올바르게 설정되어 있으며, 입력값이나 시크릿이 정의되어 있지 않습니다. Dev_Discovery_CD.yml에서 별도의 입력값 전달 없이 워크플로우를 재사용하는 것이 정상적인 구성입니다.


62-62: self-hosted 런너 구성 문서화하기

"dev-discovery-server"는 GitHub Actions의 표준 런너가 아닌 자체 호스팅 runner입니다. 현재 actionlint 구성이 없고 리포지토리 문서에 이 runner의 설정 방법이 기록되어 있지 않습니다. 이 pattern이 여러 배포 워크플로우에서 반복되므로, actionlint.yaml 설정 파일을 추가하거나 .github/ 문서에서 self-hosted runner 설정 가이드를 작성하여 CI/CD 인프라를 명확히 해야 합니다.

domain-restaurant/src/main/resources/dev-secret.yml (1)

5-5: 데이터베이스 포트 번호 검증 필요 (라인 5)

데이터베이스 URL에서 포트가 3309로 설정되어 있습니다. MySQL의 표준 포트는 3306입니다. 이것이 의도된 설정(예: 커스텀 포트)인지 오타인지 확인이 필요합니다.

또한, 이 파일은 개발 환경용 비밀 설정이므로 프로덕션 환경에서는 다른 보안 메커니즘(예: AWS Secrets Manager, HashiCorp Vault)을 통해 관리되어야 합니다.

domain-restaurant/src/main/resources/application-dev.yml (1)

1-49: 설정 파일 구조 양호 - Jackson 타임존 설정 우수

도메인 레스토랑 서비스의 개발 환경 설정이 명확하고 일관되게 구성되어 있습니다. 특히 라인 24-27의 Jackson 설정(time-zone: Asia/Seoul, write-dates-as-timestamps: false)은 한국 시간대에서의 정확한 날짜/시간 직렬화를 보장하므로 우수합니다.

Eureka instance-id가 ${spring.application.name}:${server.port} 형식으로 설정되어 있어 포트 기반 구분이 명확합니다.

domain-reservation/src/main/resources/application-dev.yml (1)

1-69: 검증 완료: 설정 파일 문제 없음

dev-secret.yml 파일이 정상적으로 존재하므로(./domain-reservation/src/main/resources/dev-secret.yml), 데이터베이스 및 Eureka 서버 URL 등의 비밀값이 정상 로드될 것입니다. 따라서 application-dev.yml의 설정은 적절하며, Flyway 마이그레이션, Eureka 클라이언트, 로깅 및 메트릭 설정이 개발 환경에 맞게 구성되어 있습니다.

domain-owner/src/main/resources/application-dev.yml (1)

14-21: JPA 설정에서 YAML 들여쓰기 오류 (라인 14-21)

show-sql, open-in-view 속성의 들여쓰기가 불일치합니다. 현재 구조에서:

  • 라인 19의 format_sql: trueproperties.hibernate 하위 ✓
  • 라인 20의 show-sql: falsejpa 직계 하위 (오류)
  • 라인 21의 open-in-view: falsejpa 직계 하위 ✓

YAML 파싱 시 show-sqljpa.show-sql 경로가 아닌 show-sql 글로벌 속성으로 인식될 수 있습니다.

  jpa:
    hibernate:
      ddl-auto: validate
    properties:
      hibernate:
        format_sql: true
+   show-sql: false
+   open-in-view: false
-   show-sql: false
-   open-in-view: false

또는 Hibernate 설정과 JPA 설정을 명확히 분리하는 것이 좋습니다:

  jpa:
    hibernate:
      ddl-auto: validate
    properties:
      hibernate:
        format_sql: true
+       show_sql: false
-   show-sql: false
    open-in-view: false

Likely an incorrect or invalid review comment.

api-owner/src/main/resources/application-dev.yml (1)

17-17: 설정 파일 구조가 일관성 있고 적절해 보입니다.

Secret 기반 설정 패턴을 따르고 있으며, Feign 마이크로서비스 클라이언트 설정(5초 타임아웃, BASIC 로깅 레벨)이 추가되었습니다. 다만 dev-secret.yml 파일의 실제 값 구성을 확인해야 합니다.

Also applies to: 21-27, 30-30

api-owner/src/main/resources/dev-secret.yml (1)

11-19: Kafka 프로듀서 설정이 잘 구성되었습니다.

idempotent producer 설정(enable-idempotence: true, acks: all)과 적절한 재시도 정책(retries: 3)으로 이벤트 기반 아키텍처에서 메시지 손실 방지와 중복 방지가 보장될 것으로 보입니다. LZ4 압축과 배치 설정도 적절합니다.

api-user/src/main/resources/application-dev.yml (2)

2-3: BFF 전환에 맞춰 설정이 적절히 구성되었습니다.

API 포트 할당(8086)이 명확하고, Eureka 서비스 디스커버리와 Feign 클라이언트 설정이 추가되었습니다. 또한 application-domain-dev.yml import 제거로 도메인 직접 호출 대신 마이크로서비스 클라이언트 기반 통신으로 전환된 것이 반영되었습니다.

다만 이 파일의 설정은 dev-secret.yml에서 제공되는 secret 값들에 의존하므로, secret 파일의 placeholder 값들이 실제로 채워져야 합니다.

Also applies to: 10-11, 13-24


1-27: api-owner와 api-user 설정이 일관성 있게 구성되었습니다.

두 서비스 모두:

  • Feign 클라이언트 설정이 동일한 구조 (connectTimeout/readTimeout 5초, BASIC 로깅)
  • Eureka 서비스 디스커버리를 위해 동일한 secret 기반 설정 패턴
  • 포트 충돌 방지 (api-owner: 8087, api-user: 8086)

이는 마이크로서비스 아키텍처에서 기대되는 일관된 구성입니다.

Comment on lines +77 to +78
- name: Replace application to latest
run: sudo sh ~/app/scripts/replace-new-version.sh
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

배포 단계의 sudo 사용 검토

Line 78에서 sudo sh ~/app/scripts/replace-new-version.sh를 실행합니다. sudo 권한으로 스크립트를 실행하는 것은 보안상 민감한 작업입니다. 다음 사항을 검증하세요:

  1. replace-new-version.sh 스크립트의 내용과 목적 검증
  2. 스크립트의 접근 제어 및 변조 방지 확인
  3. sudo 권한이 정말 필요한지 검토 (예: 포트 80/443에 바인딩, systemd 서비스 재시작 등)
  4. 에러 발생 시 처리 로직 추가 (현재는 암묵적 실패 처리)

🏁 Script executed:

#!/bin/bash
# Description: Check the deployment script for security and error handling

# Check if the deployment script exists in the repository
if [ -f "scripts/dev/replace-new-version.sh" ]; then
  echo "=== Deployment script found ==="
  echo "Script content:"
  cat scripts/dev/replace-new-version.sh
  echo ""
  echo "=== Script permissions ==="
  ls -la scripts/dev/replace-new-version.sh
else
  echo "Warning: Deployment script scripts/dev/replace-new-version.sh not found in repository"
fi

Length of output: 1042


배포 스크립트의 보안 및 에러 처리 검증 완료

검증 결과, 원래 리뷰 의견의 우려사항이 부분적으로 확인되었습니다:

확인된 문제점:

  1. 이중 sudo 사용: 워크플로우에서 sudo sh로 실행 후 스크립트 내부에서 다시 sudo nohup java 실행 - 불필요한 권한 상승
  2. 불완전한 에러 처리: kill 명령에만 에러 확인이 있고, Java 애플리케이션 실행 실패 시 처리 로직 부재
  3. 사전 검증 부족: JAR 파일 존재 여부 및 로그 디렉토리 존재 여부 검증 없음
  4. 전역 에러 처리 부재: set -e 또는 trap을 이용한 종합적 실패 처리 없음

권장사항:

  • 스크립트의 sudo 권한 재검토 (단계별 권한 명시)
  • 포트 8080 해제 시에만 sudo 필요 여부 확인
  • Java 실행 직전 JAR 파일 존재 검증 및 APP_LOG_DIR 생성
  • 전역 에러 처리 추가: set -e 또는 명시적 에러 체크
🤖 Prompt for AI Agents
.github/workflows/Dev_Discovery_CD.yml around lines 77-78: the workflow runs the
deploy script with an extra sudo which combined with the script's internal
sudo/nohup usage causes unnecessary privilege escalation and brittle error
handling; update the workflow/script to avoid double sudo (only escalate where
needed), add global failure handling (set -e or a trap to catch errors and exit
non-zero), ensure the deploy script validates the JAR exists and creates
APP_LOG_DIR before starting, and add explicit checks after kill/port-release and
after attempting to start the Java process to log failures and exit if Java
fails to launch.

Comment on lines +1 to +19
secret:
eureka:
server-url: http://[EC2-PRIVATE-IP]:8761/eureka/
cors:
origin: [CORS-ORIGIN]
redis:
host: [REDIS-HOST]
port: [REDIS-PORT]
kafka:
bootstrap-servers: [KAFKA-BOOTSTRAP-SERVERS]
producer:
acks: all
retries: 3
batch-size: 16384
linger-ms: 1
buffer-memory: 33554432
enable-idempotence: true
max-in-flight-requests-per-connection: 5
compression-type: lz4
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

⚠️ 임시 placeholder 값들이 실제 설정값으로 대체되어야 합니다.

dev-secret.yml 파일에 [EC2-PRIVATE-IP], [CORS-ORIGIN], [REDIS-HOST], [REDIS-PORT], [KAFKA-BOOTSTRAP-SERVERS]과 같은 placeholder 값들이 포함되어 있습니다. 이러한 값들이 실제로 채워지지 않으면 dev 환경에서 애플리케이션 시작이 실패할 것입니다.

다음 항목들이 실제 값으로 변경되어야 합니다:

  • Line 3: Eureka 서버의 실제 EC2 프라이빗 IP 또는 호스트명
  • Line 5: 개발 환경의 실제 CORS origin 값
  • Line 7-8: Redis 연결 정보
  • Line 10: Kafka 부트스트랩 서버 주소

또한 이 파일이 버전 관리 시스템에 커밋되는 경우, 실제 민감한 정보가 노출되지 않도록 주의가 필요합니다. 배포 파이프라인에서 이러한 값들이 어떻게 주입되는지 확인해주세요.


검증을 위해 저장소 구조를 탐색하겠습니다.


---

🏁 Script executed:

```shell
#!/bin/bash
# Find the dev-secret.yml file and check its content
fd -e yml -e yaml | grep -i "secret" | head -20

Length of output: 286


🏁 Script executed:

#!/bin/bash
# Search for deployment configuration files
fd -e gradle -e maven -e dockerfile -e "docker-compose" -e yaml -e yml | grep -E "(deploy|docker|compose|ci|cd)" | head -20

Length of output: 56


🏁 Script executed:

#!/bin/bash
# Look for README or documentation files
fd -e md -e txt | grep -iE "(readme|setup|guide|install|config)" | head -20

Length of output: 9


🏁 Script executed:

#!/bin/bash
# Search for .properties or .env files related to configuration
fd -e properties -e env | head -20

Length of output: 40


🏁 Script executed:

#!/bin/bash
# Check for CI/CD pipeline files
fd -type f | grep -E "(\\.github/workflows|\\.gitlab-ci|\\.circleci|Jenkinsfile)" | head -20

Length of output: 170


🏁 Script executed:

#!/bin/bash
# List directory structure to understand project layout
find . -maxdepth 3 -type d | grep -v "\.git" | sort | head -30

Length of output: 599


🏁 Script executed:

#!/bin/bash
# Search for any references to placeholder values in the codebase
rg -i "EC2-PRIVATE-IP|REDIS-HOST|KAFKA-BOOTSTRAP" -C 3 | head -30

Length of output: 2004


🏁 Script executed:

#!/bin/bash
# Check if dev-secret.yml exists and show its content
cat api-owner/src/main/resources/dev-secret.yml 2>/dev/null || echo "File not found at expected path"

Length of output: 443


🏁 Script executed:

#!/bin/bash
# Search for all secret-related yml/yaml files
fd -e yml -e yaml -path "*/resources/*" | head -20

Length of output: 168


🏁 Script executed:

#!/bin/bash
# Look for configuration class files that might reference these properties
rg -l "eureka|redis|kafka" --type=java | head -20

Length of output: 1583


🏁 Script executed:

#!/bin/bash
# Check for any kubernetes or deployment manifests
fd -e yaml -e yml | xargs grep -l "secret\|configmap" 2>/dev/null | head -20

Length of output: 729


🏁 Script executed:

#!/bin/bash
# Search for property placeholders being replaced
rg "\\[.*-.*\\]" --type=yaml -C 2 | head -40

Length of output: 2413


🏁 Script executed:

#!/bin/bash
# Look for gradle or maven files that might handle configuration
fd "build.gradle\|pom.xml\|settings.gradle" | head -20

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check application.yml or application-dev.yml for similar patterns
fd "application.*\\.yml\|application.*\\.yaml" | head -20

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for environment variable usage
rg "\\$\\{.*\\}" --type=yaml | head -20

Length of output: 2212


🏁 Script executed:

#!/bin/bash
# Look for spring cloud config or externalized configuration
rg "spring\\.config\\.import|spring\\.cloud\\.config" --type=yaml | head -20

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check if placeholder values are referenced in test files or documentation
rg "EC2-PRIVATE-IP|CORS-ORIGIN|REDIS-HOST|REDIS-PORT|KAFKA-BOOTSTRAP" -C 3 | head -40

Length of output: 2664


🏁 Script executed:

#!/bin/bash
# Look for any profiles or conditional configuration
fd "application-*.yml\|application-*.yaml" | head -20

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check the actual file content with full path search
find . -name "dev-secret.yml" -o -name "*secret*.yml" 2>/dev/null

Length of output: 298


🏁 Script executed:

#!/bin/bash
# Look for .gitignore to see if secret files are excluded
cat .gitignore 2>/dev/null | grep -E "secret|config|env" || echo "No .gitignore or no matching entries"

Length of output: 36


🏁 Script executed:

#!/bin/bash
# Search for documentation about dev environment setup
find . -type f \( -name "README*" -o -name "SETUP*" -o -name "DEV*" \) | head -20

Length of output: 11


🏁 Script executed:

#!/bin/bash
# Check for docker-compose or docker setup files
fd "docker\|compose" | head -20

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for any mention of how to configure dev environment in comments or docs
rg "dev.*setup|development.*config|configure.*dev" -C 2 | head -30

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check repository structure for api-owner specifically
find ./api-owner -type f -name "*.yml" -o -name "*.yaml" 2>/dev/null | head -30

Length of output: 201


🏁 Script executed:

#!/bin/bash
# Get current content of resource files
ls -la ./api-owner/src/main/resources/ 2>/dev/null || ls -la ./src/main/resources/ 2>/dev/null || echo "Looking for resources directory"

Length of output: 379


🏁 Script executed:

#!/bin/bash
# Search broadly for dev related configs
fd -type f | xargs grep -l "dev-secret\|dev.*config" 2>/dev/null | head -20

Length of output: 170


🏁 Script executed:

#!/bin/bash
# Check for any gradle tasks related to configuration
fd "build.gradle" -exec grep -l "secret\|config\|dev" {} \;

Length of output: 254


🏁 Script executed:

#!/bin/bash
# Look for dockerfile or container setup instructions
fd "Dockerfile\|docker-compose\|compose.yml" | head -20

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Final comprehensive check - what's at the api-owner path?
find . -path "*/api-owner/src/main/resources*" -type f 2>/dev/null | head -30

Length of output: 201



---

🏁 Script executed:

```shell
#!/bin/bash
# Check docker-compose.yml for configuration handling
cat docker-compose.yml | head -100

Length of output: 2153


🏁 Script executed:

#!/bin/bash
# Check README for dev setup instructions
head -80 README.md

Length of output: 1291


🏁 Script executed:

#!/bin/bash
# Check application-dev.yml to verify property binding
cat api-owner/src/main/resources/application-dev.yml

Length of output: 533


🏁 Script executed:

#!/bin/bash
# Check if there are any environment variable references or profiles in bootstrap files
find . -name "application.yml" -o -name "application.yaml" -o -name "bootstrap.yml" 2>/dev/null

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for any documentation or scripts about running dev environment
find . -name "*.sh" -o -name "*.md" | xargs grep -l "dev.*secret\|setup.*dev\|configure.*dev" 2>/dev/null | head -10

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check if dev-secret.yml should be in version control (look for template or example)
ls -la ./api-owner/src/main/resources/ | grep -E "example|template|sample"

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for any build.gradle or pom.xml that might reference these files
find . -name "build.gradle" -o -name "pom.xml" | xargs cat 2>/dev/null | grep -A 5 -B 5 "secret\|resource" | head -50

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check for any .env or environment setup files
find . -maxdepth 2 -name ".env*" -o -name "*.env" 2>/dev/null

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for documentation about secrets/configuration in comments
rg "placeholder|secret.*config|dev.*environment" -i --max-count=10 | head -30

Length of output: 0


Placeholder 값 교체 및 배포 메커니즘 확인 필요

검증 결과, dev-secret.yml의 placeholder 값들이 실제로 버전 관리에 커밋되어 있으며, 다음과 같은 문제가 확인되었습니다:

확인된 문제:

  • api-owner, api-user, domain-member, domain-owner, domain-reservation, domain-restaurant 6개 모듈 모두 동일한 placeholder 값 포함
  • .gitignore에서 dev-secret.yml이나 secret 파일 제외 규칙 없음 (보안 위험)
  • application-dev.yml에서 config.import: classpath:dev-secret.yml로 로드되며, 애플리케이션 시작 시 이 값들이 필요함
  • CI/CD 파이프라인 파일(.github/workflows, .gitlab-ci, Jenkinsfile) 미존재
  • 값 주입 메커니즘 문서화 없음

필수 조치:

  • Line 3, 5, 7-8, 10: Placeholder 값을 실제 값으로 교체하거나, 애플리케이션 배포/실행 시 환경변수로 주입되도록 구성
  • .gitignoredev-secret.yml 추가하여 실제 민감정보 노출 방지
  • 개발 환경 구성 방법과 배포 파이프라인의 값 주입 메커니즘을 README나 개발 가이드 문서에 명시
🤖 Prompt for AI Agents
In api-owner/src/main/resources/dev-secret.yml lines 1-19: this file contains
committed placeholder secrets used across six modules and is not ignored;
replace the inline placeholders (lines 3, 5, 7-8, 10) so they are not stored in
repo by changing the configuration to read values from environment variables or
an external secret manager at runtime, add dev-secret.yml to .gitignore to
prevent future commits of sensitive files, remove or rotate any real secrets if
already leaked, and update the project README/developer guide and CI/CD pipeline
documentation to describe how to inject these values (env vars / secret store)
during local development and deployment.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
.github/workflows/Dev_CI.yml (1)

30-30: Health check 설정의 비밀번호 일관성 검증

모든 MySQL 서비스의 health check에서 mysqladmin ping -ppassword 를 사용하고 있습니다. 비밀번호가 변경되는 경우 모든 health check 명령도 함께 업데이트해야 합니다.

향후 비밀번호 변경 시 일관성을 유지하기 위해 변수를 활용하거나 문서화하는 것을 권장합니다.

Also applies to: 43-43, 56-56, 69-69

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 37b1edd and a2faf97.

📒 Files selected for processing (9)
  • .github/workflows/Dev_CI.yml (1 hunks)
  • domain-member/src/main/resources/application-test.yml (1 hunks)
  • domain-member/src/test/java/com/wellmeet/domain/member/BaseRepositoryTest.java (1 hunks)
  • domain-owner/src/main/resources/application-test.yml (1 hunks)
  • domain-owner/src/test/java/com/wellmeet/domain/owner/BaseRepositoryTest.java (1 hunks)
  • domain-reservation/src/main/resources/application-test.yml (1 hunks)
  • domain-reservation/src/test/java/com/wellmeet/BaseRepositoryTest.java (1 hunks)
  • domain-restaurant/src/main/resources/application-test.yml (1 hunks)
  • domain-restaurant/src/test/java/com/wellmeet/BaseRepositoryTest.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • domain-member/src/main/resources/application-test.yml
  • domain-reservation/src/main/resources/application-test.yml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-and-push
🔇 Additional comments (14)
.github/workflows/Dev_CI.yml (1)

22-73: 마이크로서비스 아키텍처에 맞는 다중 데이터베이스 설정이 잘 구성되어 있습니다.

BFF 전환에 맞춰 각 도메인(member, owner, restaurant, reservation)별로 독립적인 MySQL 인스턴스를 배치한 점이 적절합니다. 포트 매핑(3306-3309)도 명확하고 충돌이 없습니다.

다만 health check 명령어에서 비밀번호를 입력해야 하는데, 환경에 맞게 설정되어 있는지 확인 부탁드립니다:

  • mysqladmin ping -ppassword에서 비밀번호와 MYSQL_ROOT_PASSWORD 값이 일치하는지 검증이 필요합니다.
domain-owner/src/main/resources/application-test.yml (4)

20-27: Eureka 설정이 올바르게 비활성화됨 ✓

테스트 환경에서 서비스 디스커버리를 비활성화하는 것이 적절합니다. 세 가지 설정(enabled: false, register-with-eureka: false, fetch-registry: false)이 모두 명시적으로 비활성화되어 테스트 독립성이 보장됩니다.


11-18: JPA/Hibernate 설정이 테스트 환경에 적합함 ✓

ddl-auto: create-drop 설정으로 각 테스트 실행 시 스키마를 재생성하여 테스트 격리성을 보장합니다. open-in-view: false로 설정하여 LazyInitializationException 방지 및 성능 최적화도 적절합니다.


38-41: DEBUG 로깅 레벨이 테스트 환경에 적합함 ✓

com.wellmeetorg.hibernate.SQL에 대해 DEBUG 로깅을 활성화하여 테스트 실행 중 상세한 로그 출력이 가능합니다. 이는 테스트 디버깅에 도움이 됩니다.


5-9: 리뷰 코멘트 오류 - 설정이 올바름

docker-compose.yml을 확인한 결과, MySQL 데이터베이스는 wellmeet_owner_test가 아닌 wellmeet_owner로 정의되어 있습니다. 현재 application-test.yml의 설정이 docker-compose 구성과 정확히 일치합니다:

  • ✓ 데이터베이스 이름: wellmeet_owner (docker-compose의 MYSQL_DATABASE와 동일)
  • ✓ 포트: 3308 (docker-compose 매핑과 일치)
  • ✓ 자격증명: root/password (docker-compose와 일치)
  • ✓ 다른 모듈들도 동일한 패턴: wellmeet_member, wellmeet_restaurant, wellmeet_reservation (모두 "_test" 접미사 없음)

설정을 변경할 필요가 없습니다.

domain-restaurant/src/main/resources/application-test.yml (5)

11-19: 하이버네이트 create-drop 설정의 테스트 환경 적절성 확인

ddl-auto: create-drop은 매 테스트마다 스키마를 재생성하므로 테스트 격리에는 적합하지만, 다음을 고려해주세요:

  • 테스트 실행 시간에 미치는 영향
  • 대규모 스키마 변경이 있을 경우 성능 영향
  • 다른 도메인 모듈(domain-member, domain-owner, domain-reservation)의 테스트 설정과 일관성 확인

open-in-view: false 설정은 적절합니다.


21-24: Jackson 타임존 및 직렬화 설정이 DTO 기반 구조와 정렬되었는지 확인

Asia/Seoul 타임존과 write-dates-as-timestamps: false 설정은 API 응답의 일관성을 위해 적절합니다. 이 설정이 다음과 관련이 있는지 확인해주세요:

  • Feign 클라이언트가 DTO를 직렬화할 때 동일한 설정 사용 여부
  • 도메인 간 날짜/시간 데이터 교환 시 포맷 일관성

29-33: Eureka 비활성화 설정 확인

테스트 환경에서 Eureka를 비활성화(enabled: false)하는 것은 통상적이고 적절합니다. 다만 다음을 확인해주세요:

  • 통합 테스트에서 서비스 간 통신이 필요한 경우, Feign 클라이언트가 올바르게 모킹되거나 스텁되었는지 확인
  • 다른 도메인 모듈의 테스트 설정에서도 동일하게 Eureka가 비활성화되어 있는지 확인

35-42: 액추에이터 엔드포인트 설정 검토

health, info, metrics 엔드포인트 노출은 테스트 모니터링 및 디버깅에 적절합니다. show-details: always 설정으로 상세 헬스 체크 정보를 얻을 수 있습니다.

개발 및 테스트 환경에서는 적절하나, 설정이 프로덕션 프로필과 명확히 분리되어 있는지 확인해주세요.


5-9: 포트 3309는 docker-compose.yml에서 의도적으로 restaurant 도메인에 할당된 테스트 설정입니다.

검증 결과, docker-compose.yml 51번 라인에서 "3309:3306" 포트 매핑이 명시되어 있습니다. 다른 도메인 모듈들도 유사한 패턴을 따릅니다:

  • domain-member: 3307 (docker-compose 25번)
  • domain-owner: 3308 (docker-compose 38번)
  • domain-reservation: 3306 (docker-compose 12번)

각 도메인이 테스트 환경에서 독립적인 MySQL 인스턴스로 격리되도록 의도적으로 설계되었습니다. application-local.yml도 동일하게 3309를 사용하며, 포트가 비표준이 아니라 도메인별 격리 전략의 일환입니다. 자격증명(root/password)도 테스트/로컬 환경 전용으로 적절합니다.

Likely an incorrect or invalid review comment.

domain-reservation/src/test/java/com/wellmeet/BaseRepositoryTest.java (1)

15-15: 테스트 프로파일 통일 확인됨

다른 도메인 모듈들과 동일하게 테스트 프로파일이 "test"로 변경되었습니다. 일관된 변경사항입니다.

domain-owner/src/test/java/com/wellmeet/domain/owner/BaseRepositoryTest.java (1)

15-15: 테스트 프로파일 변경 확인됨

다른 도메인 모듈들과 일관되게 테스트 프로파일이 "test"로 통일되었습니다.

domain-member/src/test/java/com/wellmeet/domain/member/BaseRepositoryTest.java (1)

15-15: 테스트 프로파일 변경 확인됨

다른 도메인 모듈들과 일관되게 테스트 프로파일이 "test"로 통일되었습니다.

domain-restaurant/src/test/java/com/wellmeet/BaseRepositoryTest.java (1)

15-15: 프로파일 마이그레이션 검증 완료 - 모든 설정 정상 확인

검증 결과, 테스트 프로파일 변경이 올바르게 이루어졌습니다:

  • ✓ 모든 4개 모듈에 application-test.yml 파일 존재
  • ✓ 각 파일에 완전한 설정 포함 (datasource, JPA, Eureka 설정 등)
  • ✓ 기존 domain-test 프로파일 파일 없음 (깔끔한 마이그레이션)
  • ✓ 모든 BaseRepositoryTest에서 일관되게 @ActiveProfiles("test") 적용
  • ✓ 각 모듈이 독립적인 테스트 데이터베이스 사용 (포트 분리: 3306, 3307, 3308, 3309)

MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
MYSQL_DATABASE: test
MYSQL_DATABASE: wellmeet_reservation
MYSQL_ROOT_PASSWORD: password
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

보안: 하드코딩된 비밀번호를 GitHub Secrets로 변경하세요.

CI 환경이지만, 모든 MySQL 서비스에 동일한 평문 비밀번호(password)를 하드코딩하는 것은 보안 안티패턴입니다. GitHub Actions Secrets를 사용하거나 최소한 기본값으로 변경하는 것이 좋습니다.

-          MYSQL_ROOT_PASSWORD: password
+          MYSQL_ROOT_PASSWORD: ${{ secrets.MYSQL_ROOT_PASSWORD || 'test-password' }}

또는 모든 서비스에서 일관성 있게:

-          MYSQL_ROOT_PASSWORD: password
+          MYSQL_ROOT_PASSWORD: test-password

Also applies to: 39-39, 52-52, 65-65

🤖 Prompt for AI Agents
.github/workflows/Dev_CI.yml lines 26 (and also update the same pattern at lines
39, 52, 65): the workflow hardcodes MYSQL_ROOT_PASSWORD: password; change it to
use a GitHub Actions secret (e.g. MYSQL_ROOT_PASSWORD: ${{
secrets.MYSQL_ROOT_PASSWORD }}), add that secret in the
repository/settings->Secrets and ensure any local CI default is documented in
README if needed; update every occurrence (lines 39, 52, 65) to the same secret
reference so all services use the secret consistently.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (1)
.github/workflows/Dev_API_User_CD.yml (1)

9-9: 'domain-common/**' 워크플로우 트리거에서 제거하세요.

이전 리뷰에서 검증된 바와 같이, api-user/build.gradle의 실제 의존성은 infra-redisinfra-kafka만 포함하며, domain-common에 대한 의존성은 없습니다. 이 경로를 트리거에 포함하면 불필요한 빌드와 배포가 발생합니다.

  paths:
    - 'api-user/**'
-   - 'domain-common/**'
    - 'infra-redis/**'
    - 'infra-kafka/**'
🧹 Nitpick comments (1)
.github/workflows/Dev_API_Owner_CD.yml (1)

1-1: 워크플로우 이름을 새로운 러너/API 이름과 일치하도록 업데이트하세요.

워크플로우 이름이 dev-owner-cd에서 변경되지 않았으나, 러너 라벨(line 69)과 파일명이 dev-api-owner로 변경되었습니다. 일관성을 위해 워크플로우 이름을 dev-api-owner-cd로 업데이트하는 것이 좋습니다.

다음 diff를 적용하세요:

-name: dev-owner-cd
+name: dev-api-owner-cd
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a2faf97 and 051e6ad.

📒 Files selected for processing (6)
  • .github/workflows/Dev_API_Owner_CD.yml (2 hunks)
  • .github/workflows/Dev_API_User_CD.yml (2 hunks)
  • .github/workflows/Dev_Domain_Member_CD.yml (1 hunks)
  • .github/workflows/Dev_Domain_Owner_CD.yml (1 hunks)
  • .github/workflows/Dev_Domain_Reservation_CD.yml (1 hunks)
  • .github/workflows/Dev_Domain_Restaurant_CD.yml (1 hunks)
🧰 Additional context used
🪛 actionlint (1.7.8)
.github/workflows/Dev_API_User_CD.yml

69-69: label "dev-api-user" is unknown. available labels are "windows-latest", "windows-latest-8-cores", "windows-2025", "windows-2022", "windows-11-arm", "ubuntu-latest", "ubuntu-latest-4-cores", "ubuntu-latest-8-cores", "ubuntu-latest-16-cores", "ubuntu-24.04", "ubuntu-24.04-arm", "ubuntu-22.04", "ubuntu-22.04-arm", "macos-latest", "macos-latest-xl", "macos-latest-xlarge", "macos-latest-large", "macos-26-xlarge", "macos-26", "macos-15-intel", "macos-15-xlarge", "macos-15-large", "macos-15", "macos-14-xl", "macos-14-xlarge", "macos-14-large", "macos-14", "macos-13-xl", "macos-13-xlarge", "macos-13-large", "macos-13", "self-hosted", "x64", "arm", "arm64", "linux", "macos", "windows". if it is a custom label for self-hosted runner, set list of labels in actionlint.yaml config file

(runner-label)

.github/workflows/Dev_Domain_Owner_CD.yml

63-63: label "dev-domain-owner" is unknown. available labels are "windows-latest", "windows-latest-8-cores", "windows-2025", "windows-2022", "windows-11-arm", "ubuntu-latest", "ubuntu-latest-4-cores", "ubuntu-latest-8-cores", "ubuntu-latest-16-cores", "ubuntu-24.04", "ubuntu-24.04-arm", "ubuntu-22.04", "ubuntu-22.04-arm", "macos-latest", "macos-latest-xl", "macos-latest-xlarge", "macos-latest-large", "macos-26-xlarge", "macos-26", "macos-15-intel", "macos-15-xlarge", "macos-15-large", "macos-15", "macos-14-xl", "macos-14-xlarge", "macos-14-large", "macos-14", "macos-13-xl", "macos-13-xlarge", "macos-13-large", "macos-13", "self-hosted", "x64", "arm", "arm64", "linux", "macos", "windows". if it is a custom label for self-hosted runner, set list of labels in actionlint.yaml config file

(runner-label)

.github/workflows/Dev_Domain_Member_CD.yml

63-63: label "dev-domain-member" is unknown. available labels are "windows-latest", "windows-latest-8-cores", "windows-2025", "windows-2022", "windows-11-arm", "ubuntu-latest", "ubuntu-latest-4-cores", "ubuntu-latest-8-cores", "ubuntu-latest-16-cores", "ubuntu-24.04", "ubuntu-24.04-arm", "ubuntu-22.04", "ubuntu-22.04-arm", "macos-latest", "macos-latest-xl", "macos-latest-xlarge", "macos-latest-large", "macos-26-xlarge", "macos-26", "macos-15-intel", "macos-15-xlarge", "macos-15-large", "macos-15", "macos-14-xl", "macos-14-xlarge", "macos-14-large", "macos-14", "macos-13-xl", "macos-13-xlarge", "macos-13-large", "macos-13", "self-hosted", "x64", "arm", "arm64", "linux", "macos", "windows". if it is a custom label for self-hosted runner, set list of labels in actionlint.yaml config file

(runner-label)

.github/workflows/Dev_Domain_Reservation_CD.yml

63-63: label "dev-domain-reservation" is unknown. available labels are "windows-latest", "windows-latest-8-cores", "windows-2025", "windows-2022", "windows-11-arm", "ubuntu-latest", "ubuntu-latest-4-cores", "ubuntu-latest-8-cores", "ubuntu-latest-16-cores", "ubuntu-24.04", "ubuntu-24.04-arm", "ubuntu-22.04", "ubuntu-22.04-arm", "macos-latest", "macos-latest-xl", "macos-latest-xlarge", "macos-latest-large", "macos-26-xlarge", "macos-26", "macos-15-intel", "macos-15-xlarge", "macos-15-large", "macos-15", "macos-14-xl", "macos-14-xlarge", "macos-14-large", "macos-14", "macos-13-xl", "macos-13-xlarge", "macos-13-large", "macos-13", "self-hosted", "x64", "arm", "arm64", "linux", "macos", "windows". if it is a custom label for self-hosted runner, set list of labels in actionlint.yaml config file

(runner-label)

.github/workflows/Dev_API_Owner_CD.yml

69-69: label "dev-api-owner" is unknown. available labels are "windows-latest", "windows-latest-8-cores", "windows-2025", "windows-2022", "windows-11-arm", "ubuntu-latest", "ubuntu-latest-4-cores", "ubuntu-latest-8-cores", "ubuntu-latest-16-cores", "ubuntu-24.04", "ubuntu-24.04-arm", "ubuntu-22.04", "ubuntu-22.04-arm", "macos-latest", "macos-latest-xl", "macos-latest-xlarge", "macos-latest-large", "macos-26-xlarge", "macos-26", "macos-15-intel", "macos-15-xlarge", "macos-15-large", "macos-15", "macos-14-xl", "macos-14-xlarge", "macos-14-large", "macos-14", "macos-13-xl", "macos-13-xlarge", "macos-13-large", "macos-13", "self-hosted", "x64", "arm", "arm64", "linux", "macos", "windows". if it is a custom label for self-hosted runner, set list of labels in actionlint.yaml config file

(runner-label)

.github/workflows/Dev_Domain_Restaurant_CD.yml

63-63: label "dev-domain-restaurant" is unknown. available labels are "windows-latest", "windows-latest-8-cores", "windows-2025", "windows-2022", "windows-11-arm", "ubuntu-latest", "ubuntu-latest-4-cores", "ubuntu-latest-8-cores", "ubuntu-latest-16-cores", "ubuntu-24.04", "ubuntu-24.04-arm", "ubuntu-22.04", "ubuntu-22.04-arm", "macos-latest", "macos-latest-xl", "macos-latest-xlarge", "macos-latest-large", "macos-26-xlarge", "macos-26", "macos-15-intel", "macos-15-xlarge", "macos-15-large", "macos-15", "macos-14-xl", "macos-14-xlarge", "macos-14-large", "macos-14", "macos-13-xl", "macos-13-xlarge", "macos-13-large", "macos-13", "self-hosted", "x64", "arm", "arm64", "linux", "macos", "windows". if it is a custom label for self-hosted runner, set list of labels in actionlint.yaml config file

(runner-label)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-and-push
🔇 Additional comments (8)
.github/workflows/Dev_API_Owner_CD.yml (2)

69-69: 자체 호스트 러너 라벨 존재 여부 확인 필요.

워크플로우가 실행될 dev-api-owner 라벨을 가진 러너가 GitHub 조직/리포지토리에 자체 호스트 러너로 구성되어 있는지 확인해주세요. 이 라벨이 존재하지 않으면 워크플로우 실행이 실패합니다. 라벨이 존재한다면, actionlint 설정에 추가하여 정적 분석 경고를 제거할 수 있습니다.


8-14: 트리거 경로 변경이 BFF 아키텍처 전환과 일치합니다.

domain-common/**, infra-redis/**, infra-kafka/** 경로 추가는 마이크로서비스 기반 BFF 아키텍처 전환과 맞게 공유 인프라 모듈 변경 시 배포를 트리거합니다. 워크플로우 파일 자체 참조 업데이트(Dev_Owner_CD.ymlDev_API_Owner_CD.yml)도 올바릅니다.

.github/workflows/Dev_Domain_Reservation_CD.yml (1)

63-63: Self-hosted 러너 레이블 설정 확인 필요

dev-domain-reservation 레이블은 조직의 self-hosted 러너에 등록된 커스텀 레이블입니다. actionlint 경고는 표준 GitHub 러너 목록에 없다고 표시하지만, 이는 self-hosted 환경이 올바르게 구성되었다면 정상입니다.

다만 다음 사항을 확인하세요:

  • Self-hosted 러너가 해당 레이블로 등록되었는지 확인
  • 필요시 actionlint 설정 파일(actionlint.yaml)에 커스텀 레이블 등록

Also applies to: 63-63

.github/workflows/Dev_Domain_Owner_CD.yml (1)

63-63: Self-hosted 러너 레이블 설정 확인 필요

dev-domain-owner 레이블이 조직의 self-hosted 러너에 올바르게 등록되었는지 확인하세요.

Also applies to: 63-63

.github/workflows/Dev_Domain_Member_CD.yml (1)

63-63: Self-hosted 러너 레이블 설정 확인 필요

dev-domain-member 레이블이 조직의 self-hosted 러너에 올바르게 등록되었는지 확인하세요.

Also applies to: 63-63

.github/workflows/Dev_Domain_Restaurant_CD.yml (1)

63-63: Self-hosted 러너 레이블 설정 확인 필요

dev-domain-restaurant 레이블이 조직의 self-hosted 러너에 올바르게 등록되었는지 확인하세요.

Also applies to: 63-63

.github/workflows/Dev_API_User_CD.yml (2)

14-14: 워크플로우 파일 자체를 트리거에 포함한 것은 좋은 관행입니다.

'Dev_API_User_CD.yml' 경로가 추가되어 워크플로우 파일 변경 시에도 트리거되도록 설정되었습니다. 이는 CI/CD 파이프라인의 변경사항이 즉시 반영되도록 하는 모범 사례입니다.


69-69: 자가 호스팅 러너 라벨 검증 완료: 설정은 의도된 것이며, actionlint 구성만 필요합니다

리포지토리 검증 결과:

  • 러너 라벨 확인됨: dev-api-user는 .github/workflows/Dev_API_User_CD.yml 69번 줄에서 사용 중입니다.
  • 패턴 일관성: 여러 워크플로우가 서비스별 맞춤 러너를 사용 중입니다 (dev-api-owner, dev-discovery-server, dev-domain-member, 등). 이는 마이크로서비스 배포 아키텍처의 표준 패턴입니다.
  • actionlint.yaml 부재: 저장소에서 actionlint 구성 파일을 찾을 수 없습니다. 이것이 정적 분석 도구가 라벨을 인식하지 못한 이유입니다.

조치 필요 사항:

  1. .github/actionlint.yaml을 생성하고 모든 맞춤 러너 라벨(dev-api-user, dev-api-owner, dev-discovery-server 등)을 등록하세요. 또는
  2. actionlint를 사용 중이 아니라면, 이 검토 의견은 무시해도 됩니다. 라벨은 실제 자가 호스팅 러너 인프라를 반영합니다.

- 'domain-common/**'
- 'build.gradle'
- 'settings.gradle'
- 'Dev_Domain_Member_CD.yml'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

트리거 경로 설정 수정 필요

line 12의 경로는 'Dev_Domain_Member_CD.yml'로 설정되어 있으나, 워크플로우 파일이 .github/workflows/ 디렉토리 내에 있으므로 트리거가 정상 작동하지 않을 가능성이 있습니다.

수정 권장사항:

-      - 'Dev_Domain_Member_CD.yml'
+      - '.github/workflows/Dev_Domain_Member_CD.yml'

Also applies to: 12-12

🤖 Prompt for AI Agents
.github/workflows/Dev_Domain_Member_CD.yml around line 12: the trigger path is
set to 'Dev_Domain_Member_CD.yml' which may not match because the workflow file
resides in .github/workflows; update the path to include the directory (e.g.
'.github/workflows/Dev_Domain_Member_CD.yml') or use a broader pattern like
'.github/workflows/**' in the workflow's trigger/paths so the event will
correctly match this file.

- 'domain-common/**'
- 'build.gradle'
- 'settings.gradle'
- 'Dev_Domain_Owner_CD.yml'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

트리거 경로 설정 수정 필요

line 12의 경로는 'Dev_Domain_Owner_CD.yml'로 설정되어 있으나, 워크플로우 파일이 .github/workflows/ 디렉토리 내에 있으므로 트리거가 정상 작동하지 않을 가능성이 있습니다.

수정 권장사항:

-      - 'Dev_Domain_Owner_CD.yml'
+      - '.github/workflows/Dev_Domain_Owner_CD.yml'

Also applies to: 12-12

🤖 Prompt for AI Agents
In .github/workflows/Dev_Domain_Owner_CD.yml around line 12, the trigger path is
set to 'Dev_Domain_Owner_CD.yml' which won't match the actual location; update
that value to the correct path under the workflows folder (for example
'.github/workflows/Dev_Domain_Owner_CD.yml' or an appropriate glob like
'.github/workflows/**') so the workflow trigger correctly matches the file
location.

- 'domain-common/**'
- 'build.gradle'
- 'settings.gradle'
- 'Dev_Domain_Reservation_CD.yml'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

트리거 경로 설정 수정 필요

line 12의 경로는 'Dev_Domain_Reservation_CD.yml'로 설정되어 있으나, 워크플로우 파일이 .github/workflows/ 디렉토리 내에 있으므로 트리거가 정상 작동하지 않을 가능성이 있습니다. 워크플로우 파일 자체의 변경을 감지하려면 올바른 상대 경로를 사용해야 합니다.

수정 권장사항:

-      - 'Dev_Domain_Reservation_CD.yml'
+      - '.github/workflows/Dev_Domain_Reservation_CD.yml'

Also applies to: 12-12

🤖 Prompt for AI Agents
.github/workflows/Dev_Domain_Reservation_CD.yml around line 12: the workflow
trigger references 'Dev_Domain_Reservation_CD.yml' which won't match changes to
the workflow file itself; update the path to the correct relative location
'.github/workflows/Dev_Domain_Reservation_CD.yml' wherever the trigger lists the
filename so changes to the workflow file are detected (also update any similar
occurrences for pull_request triggers if present).

- 'domain-common/**'
- 'build.gradle'
- 'settings.gradle'
- 'Dev_Domain_Restaurant_CD.yml'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

트리거 경로 설정 수정 필요

line 12의 경로는 'Dev_Domain_Restaurant_CD.yml'로 설정되어 있으나, 워크플로우 파일이 .github/workflows/ 디렉토리 내에 있으므로 트리거가 정상 작동하지 않을 가능성이 있습니다.

수정 권장사항:

-      - 'Dev_Domain_Restaurant_CD.yml'
+      - '.github/workflows/Dev_Domain_Restaurant_CD.yml'

Also applies to: 12-12

🤖 Prompt for AI Agents
.github/workflows/Dev_Domain_Restaurant_CD.yml lines 12-12: the trigger path is
set to 'Dev_Domain_Restaurant_CD.yml' which may not match the actual location
under .github/workflows; update the string on line 12 to the repository-relative
path '.github/workflows/Dev_Domain_Restaurant_CD.yml' (keeping quotes) so the
workflow trigger references the correct file location and will fire as expected.

@unifolio0 unifolio0 closed this by deleting the head repository Nov 5, 2025
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.

[FEAT] api-user BFF 전환

1 participant