Repository: Sparta-CareNest/carnest-backend
Pull request #118: Feature/caregiver/accept
Author: login: codejomo99
Labels: name: feat📌
description: 개발
Created: 2025-04-21T02:33:32Z | Merged: 2025-04-21T03:06:08Z

## PR Type
어떤 변경 사항이 있나요?

- [x] 새로운 기능 추가  
- [ ] 버그 수정  
- [ ] 코드에 영향을 주지 않는 변경사항(오타 수정, 탭 사이즈 변경, 변수명 변경)  
- [x] 코드 리팩토링  
- [ ] 주석 추가 및 수정  
- [ ] 문서 수정  
- [ ] 테스트 추가, 테스트 리팩토링  
- [ ] 빌드 부분 혹은 패키지 매니저 수정  
- [ ] 파일 혹은 폴더명 수정  
- [ ] 파일 혹은 폴더 삭제  

## 변경 내용
- **as-is**  
  - 간병인 승인/거절 이벤트 기능이 미구현되어 있었음  
  - 이벤트 네이밍이 일정하지 않고, 토픽 설정 및 발행/수신 로직 부재  
  - 수신된 이벤트를 저장할 DB 테이블 및 조회 API 미확보  
  - ReservationService 연동을 위한 DTO, Feign 설정, Gateway 라우팅이 없었음  
  - 간병인별 예약 조회 기능 미구현  

- **to-be**  
  - 간병인 승인/거절 이벤트 생성 및 Kafka 토픽 설정 추가  
  - Producer/Consumer 구현으로 이벤트 발행·수신 로직 완성  
  - 수신된 승인/거절 이벤트를 DB에 저장하는 로직 추가
  - ReservationClient DTO 생성 및 Feign Config 설정  
  - 간병인 기준 예약 조회 API(`GET /api/v1/caregiver-approvals/pending`) 구현  

## 이슈 넘버
- close #114


<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

- **신규 기능**
  - 보호사 승인 내역을 조회할 수 있는 신규 API가 추가되었습니다.
  - 보호사 승인 관리 및 예약 정보 연동 기능이 도입되었습니다.
  - 보호사 승인 관련 Kafka 메시지 소비 및 발행 기능이 추가되었습니다.

- **버그 수정**
  - 보호사 평점 이벤트 메시지 타입이 일관되게 변경되었습니다.

- **기타**
  - 외부 API 연동 및 오류 처리 방식이 개선되었습니다.
  - 신규 Enum 및 DTO가 도입되어 예약/결제/승인 데이터 표현이 강화되었습니다.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Linked issue #114: [Caregiver] 승인/거절 API
## 📝 Description
결제 완료 시 `ReservationService`에서 예약 상태를 변경하고 Kafka에 `CaregiverPendingEvent`를 발행하면,  
`CaregiverService`에서 이를 수신해 `PendingApproval` 테이블에 `PENDING` 레코드를 저장하고,  
간병인 UI를 통해 “수락”/“거부”를 동기 방식으로 처리합니다.

### 흐름 요약
1. **ReservationService**  
   - 결제 완료 → 예약 상태 변경
   - `CaregiverPendingEvent` 발행  
2. **CaregiverService**  
   - Kafka 리스너로 이벤트 수신  
   - `PendingApproval` 테이블에 `PENDING` 레코드 저장  
3. **Caregiver UI 가 존재한다면**  
   - `GET /v1/caregiver-approvals/pending` 호출 → 대기 목록 조회  
   - “수락”/“거부” 버튼 표시  
4. **CaregiverService**  
   - `PATCH /v1/caregiver-approvals/{reservationId}/accept` 또는 `/reject` 호출  
   - `PendingApproval.status`를 `APPROVED`/`REJECTED`로 업데이트  

## ✅ Todo
- [x] **ReservationService**: `ReservationStatusChangedEvent` 발행 로직 구현  
- [x] **CaregiverService**:  
  - KafkaListener로 이벤트 수신 후 `PendingApproval` 저장  
  - `GET /v1/caregiver-approvals/pending` API 구현  

## 🏷 Labels
- `feature`  

Diff:
diff --git a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverApprovalService.java b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverApprovalService.java
new file mode 100644
index 00000000..82926a20
--- /dev/null
+++ b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverApprovalService.java
@@ -0,0 +1,14 @@
+package com.carenest.business.caregiverservice.application.service;
+
+import java.util.List;
+import java.util.UUID;
+
+import com.carenest.business.caregiverservice.presentation.dto.response.PendingApprovalResponse;
+import com.carenest.business.common.event.caregiver.CaregiverPendingEvent;
+
+public interface CaregiverApprovalService {
+
+	void createCaregiverApproval(CaregiverPendingEvent event);
+
+	List<PendingApprovalResponse> getPendingApprovals(UUID userId);
+}
diff --git a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverApprovalServiceImpl.java b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverApprovalServiceImpl.java
new file mode 100644
index 00000000..41b3904b
--- /dev/null
+++ b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverApprovalServiceImpl.java
@@ -0,0 +1,79 @@
+package com.carenest.business.caregiverservice.application.service;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.carenest.business.caregiverservice.domain.model.Caregiver;
+import com.carenest.business.caregiverservice.domain.model.CaregiverApproval;
+import com.carenest.business.caregiverservice.exception.CaregiverException;
+import com.carenest.business.caregiverservice.exception.ErrorCode;
+import com.carenest.business.caregiverservice.infrastructure.client.ReservationClient;
+import com.carenest.business.caregiverservice.infrastructure.client.dto.reservation.ReservationResponse;
+import com.carenest.business.caregiverservice.infrastructure.repository.CaregiverApprovalRepository;
+import com.carenest.business.caregiverservice.infrastructure.repository.CaregiverRepository;
+import com.carenest.business.caregiverservice.presentation.dto.response.PendingApprovalResponse;
+import com.carenest.business.common.event.caregiver.CaregiverPendingEvent;
+
+import feign.FeignException;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class CaregiverApprovalServiceImpl implements CaregiverApprovalService{
+	private final CaregiverRepository caregiverRepository;
+	private final CaregiverApprovalRepository caregiverApprovalRepository;
+	private final ReservationClient reservationClient;
+
+	@Override
+	@Transactional
+	public void createCaregiverApproval(CaregiverPendingEvent event) {
+		// 중복 방지
+		if (caregiverApprovalRepository.existsById(event.getReservationId())) {
+			return;
+		}
+		CaregiverApproval  caregiverApproval = CaregiverApproval.builder()
+			.reservationId(event.getReservationId())
+			.caregiverId(event.getCaregiverId())
+			.message(event.getMessage())
+			.build();
+
+		caregiverApprovalRepository.save(caregiverApproval);
+	}
+
+	@Override
+	@Transactional(readOnly = true)
+	public List<PendingApprovalResponse> getPendingApprovals(UUID userId) {
+
+		// 1. 간병인 찾기
+		Caregiver caregiver = caregiverRepository.findByUserId(userId)
+			.orElseThrow(() -> new CaregiverException(ErrorCode.NOT_FOUND));
+
+		// 2. 간병인 ID로 존재하는 승인/거부 조회
+		List<CaregiverApproval> approvals = caregiverApprovalRepository.findByCaregiverId(caregiver.getId());
+
+		return approvals.stream()
+			.map(approval -> {
+				try{
+					// 예약 정보 조회
+					ReservationResponse resp = reservationClient.getReservationDetails(approval.getReservationId()).getData();
+					return new PendingApprovalResponse(
+						approval.getReservationId(),
+						approval.getCaregiverId(),
+						resp.getPatientCondition(),
+						resp.getCareAddress(),
+						resp.getServiceRequests(),
+						resp.getTotalAmount(),
+						resp.getServiceFee()
+					);
+				}catch (FeignException e){
+					log.warn("예약 정보 조회 실패: userId={}, error={}", userId, e.getMessage());
+					throw  new CaregiverException(ErrorCode.EXTERNAL_API_ERROR);
+				}
+			}).toList();
+	}
+}
diff --git a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverConsumerService.java b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverConsumerService.java
index 4da17ebb..6b2a1fbd 100644
--- a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverConsumerService.java
+++ b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverConsumerService.java
@@ -1,7 +1,7 @@
 package com.carenest.business.caregiverservice.application.service;
 
-import com.carenest.business.common.event.caregiver.CaregiverRatingMessage;
+import com.carenest.business.common.event.caregiver.CaregiverRatingEvent;
 
 public interface CaregiverConsumerService{
-	void handleCaregiverRatingUpdate(CaregiverRatingMessage message);
+	void handleCaregiverRatingUpdate(CaregiverRatingEvent message);
 }
diff --git a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverConsumerServiceImpl.java b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverConsumerServiceImpl.java
index 6456c0d3..04a63e15 100644
--- a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverConsumerServiceImpl.java
+++ b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverConsumerServiceImpl.java
@@ -8,7 +8,7 @@
 import com.carenest.business.caregiverservice.exception.CaregiverException;
 import com.carenest.business.caregiverservice.exception.ErrorCode;
 import com.carenest.business.caregiverservice.infrastructure.repository.CaregiverRepository;
-import com.carenest.business.common.event.caregiver.CaregiverRatingMessage;
+import com.carenest.business.common.event.caregiver.CaregiverRatingEvent;
 
 import lombok.RequiredArgsConstructor;
 
@@ -21,7 +21,7 @@ public class CaregiverConsumerServiceImpl implements CaregiverConsumerService {
 
 	@Override
 	@Transactional
-	public void handleCaregiverRatingUpdate(CaregiverRatingMessage message) {
+	public void handleCaregiverRatingUpdate(CaregiverRatingEvent message) {
 		// 도메인 서비스로 위임해서 갱신 로직 실행
 		Caregiver caregiver = caregiverRepository.findById(message.getCaregiverId())
 			.orElseThrow(() -> new CaregiverException(ErrorCode.NOT_FOUND));
diff --git a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/config/ConsumerKafkaConfig.java b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/config/ConsumerKafkaConfig.java
index 9bccfcaa..49aede8c 100644
--- a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/config/ConsumerKafkaConfig.java
+++ b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/config/ConsumerKafkaConfig.java
@@ -1,5 +1,8 @@
 package com.carenest.business.caregiverservice.config;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import org.apache.kafka.clients.consumer.ConsumerConfig;
 import org.apache.kafka.common.serialization.StringDeserializer;
 import org.springframework.beans.factory.annotation.Value;
@@ -11,10 +14,8 @@
 import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
 import org.springframework.kafka.support.serializer.JsonDeserializer;
 
-import java.util.HashMap;
-import java.util.Map;
-
-import com.carenest.business.common.event.caregiver.CaregiverRatingMessage;
+import com.carenest.business.common.event.caregiver.CaregiverPendingEvent;
+import com.carenest.business.common.event.caregiver.CaregiverRatingEvent;
 
 @EnableKafka
 @Configuration
@@ -25,7 +26,7 @@ public class ConsumerKafkaConfig {
 	private String bootstrapServers;
 
 	@Bean
-	public ConsumerFactory<String, CaregiverRatingMessage> consumerFactory() {
+	public ConsumerFactory<String, CaregiverRatingEvent> consumerFactory() {
 		Map<String, Object> props = new HashMap<>();
 		props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
 		props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
@@ -36,9 +37,29 @@ public ConsumerFactory<String, CaregiverRatingMessage> consumerFactory() {
 	}
 
 	@Bean
-	public ConcurrentKafkaListenerContainerFactory<String, CaregiverRatingMessage> kafkaListenerConsumerContainerFactory() {
-		var factory = new ConcurrentKafkaListenerContainerFactory<String, CaregiverRatingMessage>();
+	public ConcurrentKafkaListenerContainerFactory<String, CaregiverRatingEvent> kafkaListenerConsumerContainerFactory() {
+		var factory = new ConcurrentKafkaListenerContainerFactory<String, CaregiverRatingEvent>();
 		factory.setConsumerFactory(consumerFactory());
 		return factory;
 	}
+
+	@Bean
+	public ConsumerFactory<String, CaregiverPendingEvent> caregiverPendingConsumerFactory() {
+		Map<String, Object> props = new HashMap<>();
+		props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
+		props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
+		props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
+		props.put(JsonDeserializer.VALUE_DEFAULT_TYPE, CaregiverPendingEvent.class.getName());
+		props.put(JsonDeserializer.TRUSTED_PACKAGES, "*");
+
+		return new DefaultKafkaConsumerFactory<>(props);
+	}
+
+	@Bean
+	public ConcurrentKafkaListenerContainerFactory<String, CaregiverPendingEvent>
+	caregiverPendingKafkaListenerContainerFactory() {
+		var factory = new ConcurrentKafkaListenerContainerFactory<String, CaregiverPendingEvent>();
+		factory.setConsumerFactory(caregiverPendingConsumerFactory());
+		return factory;
+	}
 }
\ No newline at end of file
diff --git a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/config/FeignConfig.java b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/config/FeignConfig.java
new file mode 100644
index 00000000..86241bb0
--- /dev/null
+++ b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/config/FeignConfig.java
@@ -0,0 +1,29 @@
+package com.carenest.business.caregiverservice.config;
+
+import org.springframework.beans.factory.ObjectFactory;
+import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
+import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
+import org.springframework.cloud.openfeign.support.SpringDecoder;
+import org.springframework.cloud.openfeign.support.SpringEncoder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+
+import feign.codec.Decoder;
+import feign.codec.Encoder;
+
+@Configuration
+public class FeignConfig {
+	@Bean
+	public Decoder feignDecoder() {
+		ObjectFactory<HttpMessageConverters> factory =
+			() -> new HttpMessageConverters(new MappingJackson2HttpMessageConverter());
+		return new ResponseEntityDecoder(new SpringDecoder(factory));
+	}
+	@Bean
+	public Encoder feignEncoder() {
+		ObjectFactory<HttpMessageConverters> factory =
+			() -> new HttpMessageConverters(new MappingJackson2HttpMessageConverter());
+		return new SpringEncoder(factory);
+	}
+}
diff --git a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/config/FeignErrorDecoderConfig.java b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/config/FeignErrorDecoderConfig.java
new file mode 100644
index 00000000..0d064939
--- /dev/null
+++ b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/config/FeignErrorDecoderConfig.java
@@ -0,0 +1,39 @@
+package com.carenest.business.caregiverservice.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import com.carenest.business.caregiverservice.exception.CaregiverException;
+import com.carenest.business.caregiverservice.exception.ErrorCode;
+
+import feign.Response;
+import feign.codec.ErrorDecoder;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Configuration
+public class FeignErrorDecoderConfig {
+
+	@Bean
+	public ErrorDecoder errorDecoder() {
+		return new CustomErrorDecoder();
+	}
+
+	public static class CustomErrorDecoder implements ErrorDecoder {
+		@Override
+		public Exception decode(String methodKey, Response response) {
+			log.error("Feign client error: {} - {}", response.status(), methodKey);
+
+			if (response.status() >= 500) {
+				log.error("서버 오류 발생: 서비스={}, 상태코드={}", methodKey, response.status());
+				return new CaregiverException(ErrorCode.EXTERNAL_API_ERROR);
+			} else if (response.status() >= 400) {
+				log.error("클라이언트 오류 발생: 서비스={}, 상태코드={}", methodKey, response.status());
+				return new CaregiverException(ErrorCode.EXTERNAL_API_ERROR);
+			}
+
+			log.error("알 수 없는 오류 발생: 서비스={}, 상태코드={}", methodKey, response.status());
+			return new CaregiverException(ErrorCode.EXTERNAL_API_ERROR);
+		}
+	}
+}
\ No newline at end of file
diff --git a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/domain/model/CaregiverApproval.java b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/domain/model/CaregiverApproval.java
new file mode 100644
index 00000000..9b062d7a
--- /dev/null
+++ b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/domain/model/CaregiverApproval.java
@@ -0,0 +1,55 @@
+package com.carenest.business.caregiverservice.domain.model;
+
+import java.util.UUID;
+
+import org.hibernate.annotations.SQLRestriction;
+import org.springframework.data.jpa.domain.support.AuditingEntityListener;
+
+import com.carenest.business.common.entity.BaseEntity;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EntityListeners;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.Id;
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@Entity
+@Builder
+@AllArgsConstructor
+@SQLRestriction("is_deleted = false")
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@EntityListeners(AuditingEntityListener.class)
+public class CaregiverApproval extends BaseEntity {
+
+	@Id
+	@Column(name = "reservation_id")
+	private UUID reservationId;
+
+	@Column(name = "caregiver_id", nullable = false)
+	private UUID caregiverId;
+
+	@Enumerated(EnumType.STRING)
+	@Column(nullable = false)
+	@Builder.Default
+	private Status status = Status.PENDING;
+
+	@Column(length = 255)
+	private String message;
+
+
+	public enum Status {
+		PENDING,
+		APPROVED,
+		REJECTED
+	}
+}
+
diff --git a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/exception/ErrorCode.java b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/exception/ErrorCode.java
index b3df2226..0182aa85 100644
--- a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/exception/ErrorCode.java
+++ b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/exception/ErrorCode.java
@@ -17,7 +17,10 @@ public enum ErrorCode {
 	NOT_FOUND_LOCATION("CL-001", "해당 지역을 찾을 수 없습니다.", HttpStatus.NOT_FOUND),
 
 	UPLOAD_IMAGE_FAILED("C-004", "이미지 파일 업로드에 실패하였습니다.", HttpStatus.INTERNAL_SERVER_ERROR),
-	EXTERNAL_API_ERROR("E-001","서비스 호출에 실패 했습니다." ,HttpStatus.INTERNAL_SERVER_ERROR);
+	EXTERNAL_API_ERROR("E-001","서비스 호출에 실패 했습니다." ,HttpStatus.INTERNAL_SERVER_ERROR),
+
+	NOT_EXISTS_PENDING("CP-001","예약이 존재하지 않습니다.",HttpStatus.NOT_FOUND);
+
 
 	private final String errorCode;
 	private final String message;
diff --git a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/ReservationClient.java b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/ReservationClient.java
new file mode 100644
index 00000000..4d90da91
--- /dev/null
+++ b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/ReservationClient.java
@@ -0,0 +1,21 @@
+package com.carenest.business.caregiverservice.infrastructure.client;
+
+import java.util.UUID;
+
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+
+import com.carenest.business.caregiverservice.config.FeignConfig;
+import com.carenest.business.caregiverservice.infrastructure.client.dto.reservation.ReservationResponse;
+import com.carenest.business.common.response.ResponseDto;
+
+@FeignClient(
+	name = "reservation-service",
+	configuration = FeignConfig.class
+)
+public interface ReservationClient {
+
+	@GetMapping("/api/v1/internal/reservations/{reservationId}")
+	ResponseDto<ReservationResponse> getReservationDetails(@PathVariable UUID reservationId);
+}
diff --git a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/Gender.java b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/Gender.java
new file mode 100644
index 00000000..95574e62
--- /dev/null
+++ b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/Gender.java
@@ -0,0 +1,5 @@
+package com.carenest.business.caregiverservice.infrastructure.client.dto.reservation;
+
+public enum Gender {
+	MALE, FEMALE
+}
diff --git a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/PaymentStatus.java b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/PaymentStatus.java
new file mode 100644
index 00000000..a37433f2
--- /dev/null
+++ b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/PaymentStatus.java
@@ -0,0 +1,8 @@
+package com.carenest.business.caregiverservice.infrastructure.client.dto.reservation;
+
+public enum PaymentStatus {
+    PENDING,
+    PAID,
+    CANCELLED,
+    REFUNDED
+}
\ No newline at end of file
diff --git a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/ReservationResponse.java b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/ReservationResponse.java
new file mode 100644
index 00000000..77fe403a
--- /dev/null
+++ b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/ReservationResponse.java
@@ -0,0 +1,43 @@
+package com.carenest.business.caregiverservice.infrastructure.client.dto.reservation;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.UUID;
+
+@Getter
+@Setter
+@NoArgsConstructor
+public class ReservationResponse {
+	private UUID reservationId;
+	private UUID guardianId;
+	private String guardianName;
+	private UUID caregiverId;
+	private String caregiverName;
+	private String patientName;
+	private Integer patientAge;
+	private Gender patientGender;
+	private String patientCondition;
+	private String careAddress;
+	private LocalDateTime startedAt;
+	private LocalDateTime endedAt;
+	private ServiceType serviceType;
+	private String serviceRequests;
+	private BigDecimal totalAmount;
+	private BigDecimal serviceFee;
+	private ReservationStatus status;
+	private LocalDateTime acceptedAt;
+	private LocalDateTime rejectedAt;
+	private LocalDateTime completedAt;
+	private String cancelReason;
+	private String rejectionReason;
+	private String caregiverNote;
+	private LocalDateTime createdAt;
+	private LocalDateTime updatedAt;
+	private UUID paymentId;
+	private PaymentStatus paymentStatus;
+}
+
diff --git a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/ReservationStatus.java b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/ReservationStatus.java
new file mode 100644
index 00000000..e660b09f
--- /dev/null
+++ b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/ReservationStatus.java
@@ -0,0 +1,10 @@
+package com.carenest.business.caregiverservice.infrastructure.client.dto.reservation;
+
+public enum ReservationStatus {
+    PENDING_PAYMENT,
+    PENDING_ACCEPTANCE,
+    CONFIRMED,
+    COMPLETED,
+    CANCELLED,
+    REJECTED
+}
\ No newline at end of file
diff --git a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/ServiceType.java b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/ServiceType.java
new file mode 100644
index 00000000..23b7dd46
--- /dev/null
+++ b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/ServiceType.java
@@ -0,0 +1,5 @@
+package com.carenest.business.caregiverservice.infrastructure.client.dto.reservation;
+
+public enum ServiceType {
+    HOUR, DAY
+}
\ No newline at end of file
diff --git a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/kafka/CaregiverConsumer.java b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/kafka/CaregiverConsumer.java
new file mode 100644
index 00000000..895af312
--- /dev/null
+++ b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/kafka/CaregiverConsumer.java
@@ -0,0 +1,49 @@
+package com.carenest.business.caregiverservice.infrastructure.kafka;
+
+import org.springframework.kafka.annotation.KafkaListener;
+import org.springframework.stereotype.Component;
+
+import com.carenest.business.caregiverservice.application.service.CaregiverApprovalService;
+import com.carenest.business.caregiverservice.application.service.CaregiverConsumerService;
+import com.carenest.business.common.event.caregiver.CaregiverPendingEvent;
+import com.carenest.business.common.event.caregiver.CaregiverRatingEvent;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class CaregiverConsumer {
+
+	private final CaregiverConsumerService caregiverConsumerService;
+	private final CaregiverApprovalService caregiverApprovalService;
+
+	@KafkaListener(
+		topics = "review-rating-update",
+		groupId = "caregiver-service-group",
+		containerFactory = "kafkaListenerConsumerContainerFactory"
+	)
+	public void handleCaregiverRatingUpdate(CaregiverRatingEvent message) {
+		log.info("간병인 평점 업데이트 이벤트 수신: {}", message);
+		caregiverConsumerService.handleCaregiverRatingUpdate(message);
+	}
+
+
+	@KafkaListener(
+		topics = "caregiver-accept",
+		groupId = "caregiver-service-group",
+		containerFactory = "caregiverPendingKafkaListenerContainerFactory"
+	)
+	public void handleCaregiverAccept(CaregiverPendingEvent event){
+		try {
+			log.info("간병인 승인 요청 이벤트 수신: {}", event);
+			caregiverApprovalService.createCaregiverApproval(event);
+		} catch (Exception ex) {
+			log.error("CaregiverPendingEvent 처리 실패: {}", event, ex);
+			throw ex;
+		}
+	}
+
+
+}
diff --git a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/kafka/CaregiverRatingConsumer.java b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/kafka/CaregiverRatingConsumer.java
deleted file mode 100644
index 6ca08380..00000000
--- a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/kafka/CaregiverRatingConsumer.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.carenest.business.caregiverservice.infrastructure.kafka;
-
-import org.springframework.kafka.annotation.KafkaListener;
-import org.springframework.stereotype.Component;
-
-import com.carenest.business.caregiverservice.application.service.CaregiverConsumerService;
-import com.carenest.business.common.event.caregiver.CaregiverRatingMessage;
-
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@Component
-@RequiredArgsConstructor
-public class CaregiverRatingConsumer {
-
-	private final CaregiverConsumerService caregiverConsumerService;
-
-	@KafkaListener(
-		topics = "review-rating-update",
-		groupId = "review-service-group",
-		containerFactory = "kafkaListenerConsumerContainerFactory"
-	)
-	public void handleCaregiverRatingUpdate(CaregiverRatingMessage message) {
-		log.info("받은 메시지: {}", message);
-		caregiverConsumerService.handleCaregiverRatingUpdate(message);
-	}
-}
diff --git a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/repository/CaregiverApprovalRepository.java b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/repository/CaregiverApprovalRepository.java
new file mode 100644
index 00000000..940f632f
--- /dev/null
+++ b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/repository/CaregiverApprovalRepository.java
@@ -0,0 +1,15 @@
+package com.carenest.business.caregiverservice.infrastructure.repository;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import com.carenest.business.caregiverservice.domain.model.CaregiverApproval;
+
+@Repository
+public interface CaregiverApprovalRepository extends JpaRepository<CaregiverApproval, UUID> {
+
+	List<CaregiverApproval> findByCaregiverId(UUID caregiverId);
+}
diff --git a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/presentation/controller/CaregiverApprovalController.java b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/presentation/controller/CaregiverApprovalController.java
new file mode 100644
index 00000000..ab13f8e7
--- /dev/null
+++ b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/presentation/controller/CaregiverApprovalController.java
@@ -0,0 +1,32 @@
+package com.carenest.business.caregiverservice.presentation.controller;
+
+import java.util.List;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.carenest.business.caregiverservice.application.service.CaregiverApprovalService;
+import com.carenest.business.caregiverservice.presentation.dto.response.PendingApprovalResponse;
+import com.carenest.business.common.annotation.AuthUser;
+import com.carenest.business.common.annotation.AuthUserInfo;
+import com.carenest.business.common.response.ResponseDto;
+
+import lombok.RequiredArgsConstructor;
+
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/api/v1/caregiver-approvals")
+public class CaregiverApprovalController {
+
+	private final CaregiverApprovalService caregiverApprovalService;
+
+	@GetMapping("/pending")
+	public ResponseDto<List<PendingApprovalResponse>> getPendingApprovals(
+		@AuthUser AuthUserInfo authUserInfo
+	){
+		List<PendingApprovalResponse> responses = caregiverApprovalService.getPendingApprovals(authUserInfo.getUserId());
+		return ResponseDto.success(responses);
+	}
+
+}
diff --git a/caregiver-service/src/main/java/com/carenest/business/caregiverservice/presentation/dto/response/PendingApprovalResponse.java b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/presentation/dto/response/PendingApprovalResponse.java
new file mode 100644
index 00000000..ad077366
--- /dev/null
+++ b/caregiver-service/src/main/java/com/carenest/business/caregiverservice/presentation/dto/response/PendingApprovalResponse.java
@@ -0,0 +1,22 @@
+package com.carenest.business.caregiverservice.presentation.dto.response;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+public record PendingApprovalResponse (
+
+	UUID reservationId,
+	UUID caregiverId,
+	String patientCondition,
+	String careAddress,
+	String serviceRequests,
+	BigDecimal totalAmount,
+	BigDecimal serviceFee
+
+
+) {
+
+
+
+
+}
diff --git a/common/src/main/java/com/carenest/business/common/event/caregiver/CaregiverPendingEvent.java b/common/src/main/java/com/carenest/business/common/event/caregiver/CaregiverPendingEvent.java
new file mode 100644
index 00000000..9b3b5875
--- /dev/null
+++ b/common/src/main/java/com/carenest/business/common/event/caregiver/CaregiverPendingEvent.java
@@ -0,0 +1,18 @@
+package com.carenest.business.common.event.caregiver;
+
+import java.util.UUID;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class CaregiverPendingEvent {
+	private UUID reservationId;
+	private UUID caregiverId;
+	private String message;
+}
diff --git a/common/src/main/java/com/carenest/business/common/event/caregiver/CaregiverRatingMessage.java b/common/src/main/java/com/carenest/business/common/event/caregiver/CaregiverRatingEvent.java
similarity index 76%
rename from common/src/main/java/com/carenest/business/common/event/caregiver/CaregiverRatingMessage.java
rename to common/src/main/java/com/carenest/business/common/event/caregiver/CaregiverRatingEvent.java
index 289f415a..941f3fe2 100644
--- a/common/src/main/java/com/carenest/business/common/event/caregiver/CaregiverRatingMessage.java
+++ b/common/src/main/java/com/carenest/business/common/event/caregiver/CaregiverRatingEvent.java
@@ -10,12 +10,12 @@
 
 @Getter
 @NoArgsConstructor
-public class CaregiverRatingMessage extends BaseEvent {
+public class CaregiverRatingEvent extends BaseEvent {
 	private UUID caregiverId;
 	private Double rating;
 
 	@Builder
-	public CaregiverRatingMessage(UUID caregiverId, Double rating) {
+	public CaregiverRatingEvent(UUID caregiverId, Double rating) {
 		super("REVIEW_RATING_UPDATE");
 		this.caregiverId = caregiverId;
 		this.rating = rating;
diff --git a/gateway-service/src/main/java/com/carenest/business/gatewayservice/GatewayConfig.java b/gateway-service/src/main/java/com/carenest/business/gatewayservice/GatewayConfig.java
index cf38756b..c2e1a727 100644
--- a/gateway-service/src/main/java/com/carenest/business/gatewayservice/GatewayConfig.java
+++ b/gateway-service/src/main/java/com/carenest/business/gatewayservice/GatewayConfig.java
@@ -26,7 +26,7 @@ public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
                 .route("notification-service", r -> r.path("/api/v1/notifications/**")
                         .filters(f -> f.filter(jwtAuthFilter))
                         .uri("lb://notification-service"))
-                .route("caregiver-service", r -> r.path("/api/v1/caregivers/**","/internal/v1/caregivers/**")
+                .route("caregiver-service", r -> r.path("/api/v1/caregivers/**","/api/v1/caregiver-approvals/**")
                     .filters(f -> f.filter(jwtAuthFilter))
                         .uri("lb://caregiver-service"))
                 .route("payment-service", r -> r.path("/api/v1/payments/**")
diff --git a/payment-service/src/main/java/com/carenest/business/paymentservice/application/service/PaymentServiceImpl.java b/payment-service/src/main/java/com/carenest/business/paymentservice/application/service/PaymentServiceImpl.java
index 5aa23cfc..e503093d 100644
--- a/payment-service/src/main/java/com/carenest/business/paymentservice/application/service/PaymentServiceImpl.java
+++ b/payment-service/src/main/java/com/carenest/business/paymentservice/application/service/PaymentServiceImpl.java
@@ -1,5 +1,19 @@
 package com.carenest.business.paymentservice.application.service;
 
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
 import com.carenest.business.paymentservice.application.dto.request.PaymentCompleteRequest;
 import com.carenest.business.paymentservice.application.dto.request.PaymentCreateRequest;
 import com.carenest.business.paymentservice.application.dto.request.RefundRequest;
@@ -11,7 +25,11 @@
 import com.carenest.business.paymentservice.domain.model.PaymentHistory;
 import com.carenest.business.paymentservice.domain.model.PaymentStatus;
 import com.carenest.business.paymentservice.domain.service.PaymentDomainService;
-import com.carenest.business.paymentservice.exception.*;
+import com.carenest.business.paymentservice.exception.DuplicatePaymentException;
+import com.carenest.business.paymentservice.exception.InvalidPaymentStatusException;
+import com.carenest.business.paymentservice.exception.PaymentErrorCode;
+import com.carenest.business.paymentservice.exception.PaymentException;
+import com.carenest.business.paymentservice.exception.PaymentNotFoundException;
 import com.carenest.business.paymentservice.infrastructure.client.ReservationInternalClient;
 import com.carenest.business.paymentservice.infrastructure.client.UserInternalClient;
 import com.carenest.business.paymentservice.infrastructure.client.dto.response.ReservationDetailsResponseDto;
@@ -22,16 +40,9 @@
 import com.carenest.business.paymentservice.infrastructure.repository.PaymentRepository;
 import com.carenest.business.paymentservice.infrastructure.service.NotificationService;
 import com.fasterxml.jackson.databind.ObjectMapper;
+
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageImpl;
-import org.springframework.data.domain.Pageable;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.time.LocalDateTime;
-import java.util.*;
 
 @Slf4j
 @Service
@@ -252,6 +263,16 @@ public PaymentResponse completePayment(UUID paymentId, PaymentCompleteRequest re
                 // 이벤트 발행 실패는 결제 완료 자체에 영향을 주지 않도록 예외 처리
             }
 
+            // 간병인 수락/거절 이벤트
+            try {
+                paymentEventProducer.sendCaregiverPendingEvent(savedPayment);
+                log.info("간병인 수락 대기 이벤트 발행 완료: reservationId={}, caregiverId={}",
+                    savedPayment.getReservationId(), savedPayment.getCaregiverId());
+            } catch (Exception e) {
+                log.error("간병인 이벤트 발행 실패: reservationId={}, 에러={}",
+                    savedPayment.getReservationId(), e.getMessage(), e);
+            }
+
             log.info("결제 완료 처리 성공: paymentId={}, reservationId={}",
                     paymentId, payment.getReservationId());
 
diff --git a/payment-service/src/main/java/com/carenest/business/paymentservice/infrastructure/config/KafkaConfig.java b/payment-service/src/main/java/com/carenest/business/paymentservice/infrastructure/config/KafkaConfig.java
index 68eb95f8..ddd610f8 100644
--- a/payment-service/src/main/java/com/carenest/business/paymentservice/infrastructure/config/KafkaConfig.java
+++ b/payment-service/src/main/java/com/carenest/business/paymentservice/infrastructure/config/KafkaConfig.java
@@ -54,6 +54,14 @@ public NewTopic reservationCancelledTopic() {
                 .build();
     }
 
+    @Bean
+    public NewTopic caregiverAccept() {
+        return TopicBuilder.name("caregiver-accept")
+            .partitions(3)
+            .replicas(1)
+            .build();
+    }
+
     @Bean
     public ProducerFactory<String, Object> producerFactory() {
         Map<String, Object> configProps = new HashMap<>();
diff --git a/payment-service/src/main/java/com/carenest/business/paymentservice/infrastructure/kafka/PaymentEventProducer.java b/payment-service/src/main/java/com/carenest/business/paymentservice/infrastructure/kafka/PaymentEventProducer.java
index e056dd09..61f34270 100644
--- a/payment-service/src/main/java/com/carenest/business/paymentservice/infrastructure/kafka/PaymentEventProducer.java
+++ b/payment-service/src/main/java/com/carenest/business/paymentservice/infrastructure/kafka/PaymentEventProducer.java
@@ -1,5 +1,6 @@
 package com.carenest.business.paymentservice.infrastructure.kafka;
 
+import com.carenest.business.common.event.caregiver.CaregiverPendingEvent;
 import com.carenest.business.common.event.payment.PaymentCancelledEvent;
 import com.carenest.business.paymentservice.domain.model.Payment;
 import lombok.RequiredArgsConstructor;
@@ -87,4 +88,34 @@ public void sendPaymentCancelledEvent(Payment payment) {
                     payment.getPaymentId(), e.getMessage(), e);
         }
     }
+
+	public void sendCaregiverPendingEvent(Payment payment) {
+        try{
+
+            log.info("간병인 승인/거절 이벤트 발행 시작: reservationId={}, caregiverId={}",
+                payment.getReservationId(), payment.getCaregiverId());
+
+            CaregiverPendingEvent event = CaregiverPendingEvent.builder()
+                .reservationId(payment.getReservationId())
+                .caregiverId(payment.getCaregiverId())
+                .message("새 예약이 수락 대기 상태입니다. 예약 ID: " + payment.getReservationId())
+                .build();
+
+            String key = payment.getPaymentId().toString();
+            CompletableFuture<SendResult<String, Object>> future = kafkaTemplate.send("caregiver-accept", key, event);
+
+            future.whenComplete((result, ex) -> {
+                if (ex == null) {
+                    log.info("간병인 승인/거절 이벤트 발행 성공: reservationId={}, caregiverId={}",
+                        payment.getReservationId(), payment.getCaregiverId());
+                } else {
+                    log.error("간병인 승인/거절 이벤트 발행 실패: paymentId={}", payment.getPaymentId(), ex);
+                }
+            });
+
+        }catch (Exception e){
+            log.error("간병인 승인/거절 이벤트 생성 중 예외 발생: paymentId={}, 에러={}",
+                payment.getPaymentId(), e.getMessage(), e);
+        }
+	}
 }
\ No newline at end of file
diff --git a/review-service/src/main/java/com/carenest/business/reviewservice/infrastructure/kafka/CaregiverRatingProducer.java b/review-service/src/main/java/com/carenest/business/reviewservice/infrastructure/kafka/CaregiverRatingProducer.java
index 69a5cede..ec491fda 100644
--- a/review-service/src/main/java/com/carenest/business/reviewservice/infrastructure/kafka/CaregiverRatingProducer.java
+++ b/review-service/src/main/java/com/carenest/business/reviewservice/infrastructure/kafka/CaregiverRatingProducer.java
@@ -11,7 +11,7 @@
 import org.springframework.stereotype.Component;
 import org.springframework.util.Assert;
 
-import com.carenest.business.common.event.caregiver.CaregiverRatingMessage;
+import com.carenest.business.common.event.caregiver.CaregiverRatingEvent;
 
 @Component
 @Slf4j
@@ -23,7 +23,7 @@ public class CaregiverRatingProducer {
 
     public void sendReviewUpdateEvent(UUID caregiverId, Double rating){
 
-        CaregiverRatingMessage message = CaregiverRatingMessage.builder()
+        CaregiverRatingEvent message = CaregiverRatingEvent.builder()
             .caregiverId(caregiverId)
             .rating(rating)
             .build();


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 5**

<details>
<summary>🔭 Outside diff range comments (2)</summary><blockquote>

<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/config/ConsumerKafkaConfig.java (2)</summary><blockquote>

`29-37`: _🛠️ Refactor suggestion_

**첫 번째 ConsumerFactory에도 VALUE_DEFAULT_TYPE 설정을 추가하는 것이 좋습니다.**

두 번째 ConsumerFactory(caregiverPendingConsumerFactory)에서는 `JsonDeserializer.VALUE_DEFAULT_TYPE`을 명시적으로 설정했지만, 첫 번째 ConsumerFactory에서는 이 설정이 누락되었습니다. 일관성과 안전한 역직렬화를 위해 첫 번째 ConsumerFactory에도 이 설정을 추가하는 것이 좋습니다.

```diff
	@Bean
	public ConsumerFactory<String, CaregiverRatingEvent> consumerFactory() {
		Map<String, Object> props = new HashMap<>();
		props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
		props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
		props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
+		props.put(JsonDeserializer.VALUE_DEFAULT_TYPE, CaregiverRatingEvent.class.getName());
		props.put(JsonDeserializer.TRUSTED_PACKAGES, "*");

		return new DefaultKafkaConsumerFactory<>(props);
	}
```

---

`35-35`: _🛠️ Refactor suggestion_

**보안 강화를 위해 TRUSTED_PACKAGES 설정을 제한하세요.**

현재 `JsonDeserializer.TRUSTED_PACKAGES`가 "*"로 설정되어 있어 모든 패키지에서 클래스 역직렬화를 허용합니다. 이는 보안 취약점이 될 수 있으므로, 필요한 패키지만 명시적으로 지정하는 것이 좋습니다.

```diff
-		props.put(JsonDeserializer.TRUSTED_PACKAGES, "*");
+		props.put(JsonDeserializer.TRUSTED_PACKAGES, "com.carenest.business.common.event");
```


Also applies to: 53-53

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (24)</summary><blockquote>

<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/exception/ErrorCode.java (1)</summary><blockquote>

`20-22`: **문구 및 공백 정리**  
`EXTERNAL_API_ERROR("E-001","서비스 호출에 실패 했습니다." ,HttpStatus.INTERNAL_SERVER_ERROR),`는 메시지 중간의 공백 및 쉼표 앞뒤 공백 처리가 일관되지 않습니다. 또한 `실패 했습니다`는 `실패했습니다`로 붙여 쓰는 것이 맞습니다. 다음과 같이 수정을 제안합니다:

```diff
-    EXTERNAL_API_ERROR("E-001","서비스 호출에 실패 했습니다." ,HttpStatus.INTERNAL_SERVER_ERROR),
+    EXTERNAL_API_ERROR("E-001", "서비스 호출에 실패했습니다.", HttpStatus.INTERNAL_SERVER_ERROR),
```

</blockquote></details>
<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/ReservationResponse.java (1)</summary><blockquote>

`11-42`: **DTO 필드 매핑 및 날짜/시간 형식 지정 검토**  
- `LocalDateTime` 타입 필드(`startedAt`, `endedAt`, `acceptedAt` 등)가 기본 Jackson 설정으로 올바르게 (de)직렬화되는지 확인하세요.  
- 필요시 `@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")` 등을 사용해 명시적인 포맷을 지정하는 것을 권장합니다.  
- ReservationService의 JSON 속성명과 DTO 필드명이 완전히 일치하는지 함께 검증해 주세요.

</blockquote></details>
<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/Gender.java (1)</summary><blockquote>

`3-5`: **Javadoc 문서화 및 젠더 표현의 포괄성 고려가 필요합니다.**

이 열거형에 대한 Javadoc 문서화를 추가하는 것이 좋습니다. 또한 현재 이진법적 젠더 옵션(MALE, FEMALE)만 포함되어 있는데, 애플리케이션 요구사항에 따라 더 포괄적인 젠더 옵션(예: NON_BINARY, OTHER 등)을 추가하는 것이 좋을 수 있습니다. 이는 다양한 사용자 정체성을 존중하는 데 도움이 됩니다.


```diff
package com.carenest.business.caregiverservice.infrastructure.client.dto.reservation;

+/**
+ * 환자의 성별을 나타내는 열거형입니다.
+ */
public enum Gender {
	MALE, FEMALE
}
```

</blockquote></details>
<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/ServiceType.java (1)</summary><blockquote>

`3-5`: **서비스 타입에 대한 문서화가 필요합니다.**

이 열거형에 대한 Javadoc 문서화를 추가하는 것이 좋습니다. HOUR와 DAY가 각각 어떤 서비스 유형을 나타내는지 설명이 필요합니다. 문서화는 코드의 가독성과 유지보수성을 높이는 데 도움이 됩니다.


```diff
package com.carenest.business.caregiverservice.infrastructure.client.dto.reservation;

+/**
+ * 간병 서비스의 요금 계산 단위를 나타내는 열거형입니다.
+ * HOUR: 시간당 요금 계산
+ * DAY: 일당 요금 계산
+ */
public enum ServiceType {
    HOUR, DAY
}
```

</blockquote></details>
<details>
<summary>payment-service/src/main/java/com/carenest/business/paymentservice/infrastructure/config/KafkaConfig.java (1)</summary><blockquote>

`57-63`: **Bean 이름의 일관성을 위한 수정이 필요합니다.**

새 Kafka 토픽 빈의 이름이 다른 토픽 빈들의 명명 규칙과 일치하지 않습니다. 다른 토픽 빈들은 모두 'Topic' 접미사를 사용하고 있으므로(예: `paymentCompletedTopic`, `paymentCancelledTopic`), 일관성을 위해 이 빈도 `caregiverAcceptTopic`으로 이름을 변경하는 것이 좋습니다.


```diff
@Bean
-public NewTopic caregiverAccept() {
+public NewTopic caregiverAcceptTopic() {
    return TopicBuilder.name("caregiver-accept")
        .partitions(3)
        .replicas(1)
        .build();
}
```

</blockquote></details>
<details>
<summary>payment-service/src/main/java/com/carenest/business/paymentservice/application/service/PaymentServiceImpl.java (1)</summary><blockquote>

`266-275`: **간병인 수락/거절 이벤트 발행 로직 추가가 적절합니다.**

결제 완료 후 간병인 수락 대기 이벤트를 발행하는 로직이 추가되었습니다. 예외 처리를 통해 이벤트 발행 실패가 결제 완료 프로세스 자체에 영향을 주지 않도록 한 점이 좋습니다. 이는 PR 목표에 명시된 "간병인 승인/거절 이벤트 기능 구현"을 달성합니다.

다만, 이벤트 발행 실패 시 추가적인 복구 메커니즘(예: 재시도 로직)이나 알림을 고려해 볼 수 있습니다.


이벤트 발행 실패 시 재시도 메커니즘이나 운영팀 알림을 고려해보세요:

```diff
try {
    paymentEventProducer.sendCaregiverPendingEvent(savedPayment);
    log.info("간병인 수락 대기 이벤트 발행 완료: reservationId={}, caregiverId={}",
        savedPayment.getReservationId(), savedPayment.getCaregiverId());
} catch (Exception e) {
    log.error("간병인 이벤트 발행 실패: reservationId={}, 에러={}",
        savedPayment.getReservationId(), e.getMessage(), e);
+   // TODO: 이벤트 발행 실패 시 재시도 메커니즘 또는 운영팀 알림 추가 고려
}
```

</blockquote></details>
<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/presentation/dto/response/PendingApprovalResponse.java (1)</summary><blockquote>

`6-22`: **필드 검증 및 문서화가 필요합니다.**

이 DTO 클래스에는 다음과 같은 개선이 필요합니다:
1. 핵심 필드에 대한 Bean Validation 어노테이션(예: `@NotNull`)이 없습니다.
2. 각 필드의 목적과, 이 응답 객체가 전체적으로 무엇을 나타내는지 설명하는 Javadoc 주석이 없습니다.
3. 불필요한 공백 라인이 여러 곳에 있습니다.


다음과 같이 코드를 개선해 보세요:

```diff
 package com.carenest.business.caregiverservice.presentation.dto.response;

 import java.math.BigDecimal;
 import java.util.UUID;
+import jakarta.validation.constraints.NotNull;

+/**
+ * 간병인의 승인 대기 중인 예약 정보를 나타내는 응답 DTO입니다.
+ */
 public record PendingApprovalResponse (
-
+    @NotNull
 	UUID reservationId,
+    @NotNull
 	UUID caregiverId,
 	String patientCondition,
 	String careAddress,
 	String serviceRequests,
+    @NotNull
 	BigDecimal totalAmount,
+    @NotNull
 	BigDecimal serviceFee
-
-
-
-
-
 ) {
}
```

</blockquote></details>
<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/repository/CaregiverApprovalRepository.java (1)</summary><blockquote>

`11-15`: **승인 상태에 따른 조회 메소드 추가 고려**

현재 구현된 `findByCaregiverId` 메소드는 간병인 ID로 모든 승인 내역을 조회합니다. 그러나 PR 목적에 따르면 대기 중인 승인만 조회하는 기능이 필요할 것으로 보입니다.


승인 상태(PENDING)에 따른 조회 메소드를 추가하여 성능을 개선하세요:

```diff
 @Repository
 public interface CaregiverApprovalRepository extends JpaRepository<CaregiverApproval, UUID> {
-
 	List<CaregiverApproval> findByCaregiverId(UUID caregiverId);
+    
+    /**
+     * 특정 간병인의 대기 중인 승인 내역만 조회합니다.
+     */
+    List<CaregiverApproval> findByCaregiverIdAndStatus(UUID caregiverId, CaregiverApprovalStatus status);
 }
```

또한 데이터가 많아질 경우를 대비해 페이징 지원 메소드도 고려해보세요:

```java
Page<CaregiverApproval> findByCaregiverIdAndStatus(UUID caregiverId, CaregiverApprovalStatus status, Pageable pageable);
```

</blockquote></details>
<details>
<summary>payment-service/src/main/java/com/carenest/business/paymentservice/infrastructure/kafka/PaymentEventProducer.java (1)</summary><blockquote>

`92-120`: **일관성 있는 코드 스타일 및 로깅 적용 필요**

새로 추가된 `sendCaregiverPendingEvent` 메소드에 다음과 같은 개선이 필요합니다:
1. 들여쓰기가 일관되지 않습니다(공백과 탭이 혼합된 것으로 보임)
2. try-catch 블록 사이에 불필요한 공백 라인이 있습니다(93-94라인)
3. `sendPaymentCancelledEvent` 메소드와 달리 상세 로깅(topic, partition, offset)이 누락되었습니다


일관성 있는 코드 스타일과 로깅을 적용하세요:

```diff
 public void sendCaregiverPendingEvent(Payment payment) {
-        try{
+    try {
-
-            log.info("간병인 승인/거절 이벤트 발행 시작: reservationId={}, caregiverId={}",
-                payment.getReservationId(), payment.getCaregiverId());
+        log.info("간병인 승인/거절 이벤트 발행 시작: reservationId={}, caregiverId={}",
+            payment.getReservationId(), payment.getCaregiverId());
 
-            CaregiverPendingEvent event = CaregiverPendingEvent.builder()
-                .reservationId(payment.getReservationId())
-                .caregiverId(payment.getCaregiverId())
-                .message("새 예약이 수락 대기 상태입니다. 예약 ID: " + payment.getReservationId())
-                .build();
+        CaregiverPendingEvent event = CaregiverPendingEvent.builder()
+            .reservationId(payment.getReservationId())
+            .caregiverId(payment.getCaregiverId())
+            .message("새 예약이 수락 대기 상태입니다. 예약 ID: " + payment.getReservationId())
+            .build();
 
-            String key = payment.getPaymentId().toString();
-            CompletableFuture<SendResult<String, Object>> future = kafkaTemplate.send("caregiver-accept", key, event);
+        String key = payment.getPaymentId().toString();
+        CompletableFuture<SendResult<String, Object>> future = kafkaTemplate.send("caregiver-accept", key, event);
 
-            future.whenComplete((result, ex) -> {
-                if (ex == null) {
-                    log.info("간병인 승인/거절 이벤트 발행 성공: reservationId={}, caregiverId={}",
-                        payment.getReservationId(), payment.getCaregiverId());
-                } else {
-                    log.error("간병인 승인/거절 이벤트 발행 실패: paymentId={}", payment.getPaymentId(), ex);
-                }
-            });
+        future.whenComplete((result, ex) -> {
+            if (ex == null) {
+                log.info("간병인 승인/거절 이벤트 발행 성공: reservationId={}, caregiverId={}",
+                    payment.getReservationId(), payment.getCaregiverId());
+                log.debug("메시지 발행 완료: topic={}, partition={}, offset={}",
+                    result.getRecordMetadata().topic(),
+                    result.getRecordMetadata().partition(),
+                    result.getRecordMetadata().offset());
+            } else {
+                log.error("간병인 승인/거절 이벤트 발행 실패: paymentId={}", payment.getPaymentId(), ex);
+            }
+        });
-
-        }catch (Exception e){
-            log.error("간병인 승인/거절 이벤트 생성 중 예외 발생: paymentId={}, 에러={}",
-                payment.getPaymentId(), e.getMessage(), e);
-        }
-	}
+    } catch (Exception e) {
+        log.error("간병인 승인/거절 이벤트 생성 중 예외 발생: paymentId={}, 에러={}",
+            payment.getPaymentId(), e.getMessage(), e);
+    }
+}
```

</blockquote></details>
<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/ReservationClient.java (1)</summary><blockquote>

`13-21`: **API 문서화 개선 제안**

메서드에 Javadoc 주석을 추가하여 이 API가 어떤 목적으로 사용되는지, 그리고 가능한 오류 상황(예: 존재하지 않는 reservationId)에 대한 처리 방법을 명확히 문서화하면 좋겠습니다.


```diff
@FeignClient(
	name = "reservation-service",
	configuration = FeignConfig.class
)
public interface ReservationClient {

+	/**
+	 * 예약 ID로 예약 상세 정보를 조회합니다.
+	 * 
+	 * @param reservationId 조회할 예약의 UUID
+	 * @return 예약 상세 정보를 포함한 응답
+	 * @throws FeignException 예약 서비스 호출 실패 시 발생
+	 */
	@GetMapping("/api/v1/internal/reservations/{reservationId}")
	ResponseDto<ReservationResponse> getReservationDetails(@PathVariable UUID reservationId);
}
```

</blockquote></details>
<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/config/FeignConfig.java (1)</summary><blockquote>

`17-28`: **코드 중복 개선 제안**

`feignDecoder`와 `feignEncoder` 메서드에서 `HttpMessageConverters` 객체 생성 로직이 중복됩니다. 이를 별도의 메서드로 추출하여 중복을 제거하는 것이 좋겠습니다.


```diff
@Configuration
public class FeignConfig {
+	private ObjectFactory<HttpMessageConverters> messageConverters() {
+		return () -> new HttpMessageConverters(new MappingJackson2HttpMessageConverter());
+	}
+
	@Bean
	public Decoder feignDecoder() {
-		ObjectFactory<HttpMessageConverters> factory =
-			() -> new HttpMessageConverters(new MappingJackson2HttpMessageConverter());
-		return new ResponseEntityDecoder(new SpringDecoder(factory));
+		return new ResponseEntityDecoder(new SpringDecoder(messageConverters()));
	}
	@Bean
	public Encoder feignEncoder() {
-		ObjectFactory<HttpMessageConverters> factory =
-			() -> new HttpMessageConverters(new MappingJackson2HttpMessageConverter());
-		return new SpringEncoder(factory);
+		return new SpringEncoder(messageConverters());
	}
}
```

</blockquote></details>
<details>
<summary>common/src/main/java/com/carenest/business/common/event/caregiver/CaregiverPendingEvent.java (1)</summary><blockquote>

`14-18`: **필드 문서화 제안**

각 필드의 목적과 용도를 명확히 하기 위해 필드에 Javadoc 주석을 추가하는 것이 좋겠습니다. 특히 `message` 필드가 어떤 정보를 담는지 명확히 하면 좋겠습니다.


```diff
@Builder
public class CaregiverPendingEvent {
+	/** 예약 식별자 */
	private UUID reservationId;
+	/** 간병인 식별자 */
	private UUID caregiverId;
+	/** 이벤트 메시지 (예: 승인 대기 사유나 상세 정보) */
	private String message;
}
```

</blockquote></details>
<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/presentation/controller/CaregiverApprovalController.java (2)</summary><blockquote>

`24-30`: **코드 형식과 API 문서화 개선 제안**

1. 코드 형식을 일관성 있게 유지하기 위해 27-28라인의 괄호와 중괄호 사이에 공백을 추가하는 것이 좋겠습니다.
2. API 엔드포인트의 목적과 동작을 명확히 문서화하기 위해 Javadoc 또는 Swagger 주석을 추가하는 것이 좋겠습니다.


```diff
+	/**
+	 * 인증된 간병인 사용자의 대기 중인 승인 목록을 조회합니다.
+	 * 
+	 * @param authUserInfo 인증된 사용자 정보
+	 * @return 대기 중인 승인 목록
+	 */
	@GetMapping("/pending")
	public ResponseDto<List<PendingApprovalResponse>> getPendingApprovals(
		@AuthUser AuthUserInfo authUserInfo
-	){
+	) {
		List<PendingApprovalResponse> responses = caregiverApprovalService.getPendingApprovals(authUserInfo.getUserId());
		return ResponseDto.success(responses);
	}
```

---

`24-30`: **페이지네이션 지원 고려 필요**

대기 중인 승인 목록은 시간이 지남에 따라 많은 수의 항목을 반환할 수 있습니다. 페이지네이션을 추가하여 대량의 데이터를 효율적으로 처리하고 API 성능을 개선하는 것을 고려해 보세요.


```diff
+	/**
+	 * 인증된 간병인 사용자의 대기 중인 승인 목록을 페이징하여 조회합니다.
+	 * 
+	 * @param authUserInfo 인증된 사용자 정보
+	 * @param pageable 페이지 정보 (페이지 번호, 크기, 정렬)
+	 * @return 페이징된 대기 중인 승인 목록
+	 */
	@GetMapping("/pending")
	public ResponseDto<Page<PendingApprovalResponse>> getPendingApprovals(
		@AuthUser AuthUserInfo authUserInfo,
+		@PageableDefault(size = 10, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable
	) {
-		List<PendingApprovalResponse> responses = caregiverApprovalService.getPendingApprovals(authUserInfo.getUserId());
+		Page<PendingApprovalResponse> responses = caregiverApprovalService.getPendingApprovals(authUserInfo.getUserId(), pageable);
		return ResponseDto.success(responses);
	}
```

</blockquote></details>
<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/kafka/CaregiverConsumer.java (2)</summary><blockquote>

`22-30`: **이벤트 핸들러의 로깅 개선**

이벤트 처리 시작과 완료 시점에 로깅을 추가하면 모니터링과 디버깅에 도움이 됩니다.


```diff
@KafkaListener(
    topics = "review-rating-update",
    groupId = "caregiver-service-group",
    containerFactory = "kafkaListenerConsumerContainerFactory"
)
public void handleCaregiverRatingUpdate(CaregiverRatingEvent message) {
    log.info("간병인 평점 업데이트 이벤트 수신: {}", message);
    caregiverConsumerService.handleCaregiverRatingUpdate(message);
+   log.info("간병인 평점 업데이트 이벤트 처리 완료: caregiverId={}", message.getCaregiverId());
}
```

---

`33-46`: **이벤트 ID를 활용한 로깅 개선**

이벤트 식별을 위해 이벤트 ID나 고유 식별자를 로그에 포함하면 디버깅과 추적이 더 용이해집니다.


```diff
@KafkaListener(
    topics = "caregiver-accept",
    groupId = "caregiver-service-group",
    containerFactory = "caregiverPendingKafkaListenerContainerFactory"
)
public void handleCaregiverAccept(CaregiverPendingEvent event){
    try {
-       log.info("간병인 승인 요청 이벤트 수신: {}", event);
+       log.info("간병인 승인 요청 이벤트 수신: reservationId={}, caregiverId={}", 
+                event.getReservationId(), event.getCaregiverId());
        caregiverApprovalService.createCaregiverApproval(event);
+       log.info("간병인 승인 요청 이벤트 처리 완료: reservationId={}", event.getReservationId());
    } catch (Exception ex) {
-       log.error("CaregiverPendingEvent 처리 실패: {}", event, ex);
+       log.error("CaregiverPendingEvent 처리 실패: reservationId={}, caregiverId={}", 
+                event.getReservationId(), event.getCaregiverId(), ex);
        throw ex;
    }
}
```

</blockquote></details>
<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/config/FeignErrorDecoderConfig.java (1)</summary><blockquote>

`24-37`: **응답 본문 파싱 추가**

현재 구현에서는 응답 본문을 파싱하여 상세 오류 정보를 추출하지 않고 있습니다. Feign의 응답 본문에서 더 자세한 오류 정보를 추출하면 디버깅에 도움이 됩니다.


```diff
public Exception decode(String methodKey, Response response) {
    log.error("Feign client error: {} - {}", response.status(), methodKey);

+   // 응답 본문에서 오류 메시지 추출
+   String errorBody = null;
+   try {
+       if (response.body() != null) {
+           errorBody = Util.toString(response.body().asReader(StandardCharsets.UTF_8));
+           log.error("오류 응답 본문: {}", errorBody);
+       }
+   } catch (IOException e) {
+       log.error("응답 본문 파싱 실패", e);
+   }

    if (response.status() >= 500) {
        log.error("서버 오류 발생: 서비스={}, 상태코드={}", methodKey, response.status());
-       return new CaregiverException(ErrorCode.EXTERNAL_API_ERROR);
+       return new CaregiverException(ErrorCode.EXTERNAL_API_ERROR, errorBody);
    } else if (response.status() >= 400) {
        log.error("클라이언트 오류 발생: 서비스={}, 상태코드={}", methodKey, response.status());
-       return new CaregiverException(ErrorCode.EXTERNAL_API_ERROR);
+       return new CaregiverException(ErrorCode.EXTERNAL_API_ERROR, errorBody);
    }

    log.error("알 수 없는 오류 발생: 서비스={}, 상태코드={}", methodKey, response.status());
-   return new CaregiverException(ErrorCode.EXTERNAL_API_ERROR);
+   return new CaregiverException(ErrorCode.EXTERNAL_API_ERROR, errorBody);
}
```

CaregiverException 클래스에 상세 메시지를 포함하는 생성자가 필요합니다.

</blockquote></details>
<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/domain/model/CaregiverApproval.java (2)</summary><blockquote>

`40-44`: **상태 전이 로직 추가 고려**

현재 Status enum은 상태 값만 정의하고 있습니다. 상태 전이 로직을 추가하면 비즈니스 규칙을 더 명확하게 표현할 수 있습니다.


```diff
private Status status = Status.PENDING;

+ /**
+  * 승인 상태를 업데이트합니다.
+  * @param newStatus 새 상태
+  * @param message 상태 변경 메시지 (선택사항)
+  * @return 업데이트된 엔티티
+  * @throws IllegalStateException 유효하지 않은 상태 전이인 경우
+  */
+ public CaregiverApproval updateStatus(Status newStatus, String message) {
+     // PENDING 상태에서만 APPROVED 또는 REJECTED로 변경 가능
+     if (this.status != Status.PENDING) {
+         throw new IllegalStateException("이미 처리된 승인 요청입니다: " + this.status);
+     }
+     this.status = newStatus;
+     this.message = message;
+     return this;
+ }
```

---

`31-54`: **유효성 검증 추가**

현재 구현에는 필드에 대한 유효성 검증이 충분하지 않습니다. Bean Validation API를 활용하여 유효성 검증을 강화할 수 있습니다.


```diff
@Id
@Column(name = "reservation_id")
private UUID reservationId;

@Column(name = "caregiver_id", nullable = false)
private UUID caregiverId;

@Enumerated(EnumType.STRING)
@Column(nullable = false)
@Builder.Default
private Status status = Status.PENDING;

- @Column(length = 255)
+ @Column(length = 255)
+ @Size(max = 255, message = "메시지는 255자를 초과할 수 없습니다")
private String message;


public enum Status {
    PENDING,
    APPROVED,
    REJECTED
}
```

</blockquote></details>
<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverApprovalServiceImpl.java (2)</summary><blockquote>

`32-46`: **멱등성 확인에 대한 로깅 추가**

현재 구현에서는
 기존 승인 레코드 확인 시 로깅 없이 조용히 반환합니다. 로그를 추가하면 디버깅과 중복 이벤트 처리 추적에 도움이 됩니다.


```diff
@Override
@Transactional
public void createCaregiverApproval(CaregiverPendingEvent event) {
    // 중복 방지
    if (caregiverApprovalRepository.existsById(event.getReservationId())) {
+       log.info("이미 존재하는 승인 요청입니다: reservationId={}, caregiverId={}", 
+                event.getReservationId(), event.getCaregiverId());
        return;
    }
    CaregiverApproval  caregiverApproval = CaregiverApproval.builder()
        .reservationId(event.getReservationId())
        .caregiverId(event.getCaregiverId())
        .message(event.getMessage())
        .build();

    caregiverApprovalRepository.save(caregiverApproval);
+   log.info("새로운 승인 요청이 생성되었습니다: reservationId={}, caregiverId={}", 
+            event.getReservationId(), event.getCaregiverId());
}
```

---

`59-77`: **예외 처리 무결성 개선**

현재 구현에서는 스트림 처리 중 한 예약 정보 조회가 실패하면 전체 처리가 중단됩니다. 더 유연한 방식으로 예외를 처리하면 일부 데이터라도 사용자에게 제공할 수 있습니다.


```diff
return approvals.stream()
    .map(approval -> {
        try{
            // 예약 정보 조회
            ReservationResponse resp = reservationClient.getReservationDetails(approval.getReservationId()).getData();
            return new PendingApprovalResponse(
                approval.getReservationId(),
                approval.getCaregiverId(),
                resp.getPatientCondition(),
                resp.getCareAddress(),
                resp.getServiceRequests(),
                resp.getTotalAmount(),
                resp.getServiceFee()
            );
        }catch (FeignException e){
            log.warn("예약 정보 조회 실패: userId={}, error={}", userId, e.getMessage());
-           throw  new CaregiverException(ErrorCode.EXTERNAL_API_ERROR);
+           // 개별 오류는 해당 항목만 건너뛰도록 처리
+           return null;
        }
-   }).toList();
+   })
+   .filter(Objects::nonNull) // null 객체 제거
+   .toList();
```

</blockquote></details>
<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/config/ConsumerKafkaConfig.java (3)</summary><blockquote>

`46-64`: **공통 설정 속성을 추출하여 코드 중복을 줄이세요.**

두 ConsumerFactory 메서드 간에 설정 속성이 중복됩니다. 공통 속성을 설정하는 private 메서드를 추출하여 코드 중복을 줄이고 유지보수성을 향상시키는 것이 좋습니다.

```diff
+	private Map<String, Object> getCommonConsumerConfig() {
+		Map<String, Object> props = new HashMap<>();
+		props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
+		props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
+		props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
+		props.put(JsonDeserializer.TRUSTED_PACKAGES, "com.carenest.business.common.event");
+		return props;
+	}

	@Bean
	public ConsumerFactory<String, CaregiverRatingEvent> consumerFactory() {
-		Map<String, Object> props = new HashMap<>();
-		props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
-		props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
-		props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
-		props.put(JsonDeserializer.TRUSTED_PACKAGES, "*");
+		Map<String, Object> props = getCommonConsumerConfig();
+		props.put(JsonDeserializer.VALUE_DEFAULT_TYPE, CaregiverRatingEvent.class.getName());

		return new DefaultKafkaConsumerFactory<>(props);
	}

	@Bean
	public ConsumerFactory<String, CaregiverPendingEvent> caregiverPendingConsumerFactory() {
-		Map<String, Object> props = new HashMap<>();
-		props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
-		props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
-		props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
+		Map<String, Object> props = getCommonConsumerConfig();
		props.put(JsonDeserializer.VALUE_DEFAULT_TYPE, CaregiverPendingEvent.class.getName());
-		props.put(JsonDeserializer.TRUSTED_PACKAGES, "*");

		return new DefaultKafkaConsumerFactory<>(props);
	}
```

---

`25-26`: **필드 주입 대신 생성자 주입을 사용하세요.**

Spring에서는 필드 주입보다 생성자 주입을 권장합니다. 생성자 주입을 사용하면 의존성이 명확하게 드러나고, 테스트가 용이해집니다.

```diff
@EnableKafka
@Configuration
public class ConsumerKafkaConfig {

-	@Value("${spring.kafka.bootstrap-servers}")
-	private String bootstrapServers;
+	private final String bootstrapServers;
+	
+	public ConsumerKafkaConfig(@Value("${spring.kafka.bootstrap-servers}") String bootstrapServers) {
+		this.bootstrapServers = bootstrapServers;
+	}
```

---

`59-63`: **메서드 서명을 한 줄로 간결하게 작성하세요.**

현재 `caregiverPendingKafkaListenerContainerFactory` 메서드 서명이 두 줄로 나뉘어져 있어 가독성이 떨어집니다. 메서드 서명을 한 줄로 작성하여 코드를 더 깔끔하게 만드는 것이 좋습니다.

```diff
-	public ConcurrentKafkaListenerContainerFactory<String, CaregiverPendingEvent>
-	caregiverPendingKafkaListenerContainerFactory() {
+	public ConcurrentKafkaListenerContainerFactory<String, CaregiverPendingEvent> caregiverPendingKafkaListenerContainerFactory() {
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between e50e0961d60afdeb6e57a8b6fdd9f8486ca4c360 and 230803755b32c3dd678dd8fd32d178ad48b0d2a0.

</details>

<details>
<summary>📒 Files selected for processing (27)</summary>

* `caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverApprovalService.java` (1 hunks)
* `caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverApprovalServiceImpl.java` (1 hunks)
* `caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverConsumerService.java` (1 hunks)
* `caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverConsumerServiceImpl.java` (2 hunks)
* `caregiver-service/src/main/java/com/carenest/business/caregiverservice/config/ConsumerKafkaConfig.java` (4 hunks)
* `caregiver-service/src/main/java/com/carenest/business/caregiverservice/config/FeignConfig.java` (1 hunks)
* `caregiver-service/src/main/java/com/carenest/business/caregiverservice/config/FeignErrorDecoderConfig.java` (1 hunks)
* `caregiver-service/src/main/java/com/carenest/business/caregiverservice/domain/model/CaregiverApproval.java` (1 hunks)
* `caregiver-service/src/main/java/com/carenest/business/caregiverservice/exception/ErrorCode.java` (1 hunks)
* `caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/ReservationClient.java` (1 hunks)
* `caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/Gender.java` (1 hunks)
* `caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/PaymentStatus.java` (1 hunks)
* `caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/ReservationResponse.java` (1 hunks)
* `caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/ReservationStatus.java` (1 hunks)
* `caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/ServiceType.java` (1 hunks)
* `caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/kafka/CaregiverConsumer.java` (1 hunks)
* `caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/kafka/CaregiverRatingConsumer.java` (0 hunks)
* `caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/repository/CaregiverApprovalRepository.java` (1 hunks)
* `caregiver-service/src/main/java/com/carenest/business/caregiverservice/presentation/controller/CaregiverApprovalController.java` (1 hunks)
* `caregiver-service/src/main/java/com/carenest/business/caregiverservice/presentation/dto/response/PendingApprovalResponse.java` (1 hunks)
* `common/src/main/java/com/carenest/business/common/event/caregiver/CaregiverPendingEvent.java` (1 hunks)
* `common/src/main/java/com/carenest/business/common/event/caregiver/CaregiverRatingEvent.java` (1 hunks)
* `gateway-service/src/main/java/com/carenest/business/gatewayservice/GatewayConfig.java` (1 hunks)
* `payment-service/src/main/java/com/carenest/business/paymentservice/application/service/PaymentServiceImpl.java` (4 hunks)
* `payment-service/src/main/java/com/carenest/business/paymentservice/infrastructure/config/KafkaConfig.java` (1 hunks)
* `payment-service/src/main/java/com/carenest/business/paymentservice/infrastructure/kafka/PaymentEventProducer.java` (2 hunks)
* `review-service/src/main/java/com/carenest/business/reviewservice/infrastructure/kafka/CaregiverRatingProducer.java` (2 hunks)

</details>

<details>
<summary>💤 Files with no reviewable changes (1)</summary>

* caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/kafka/CaregiverRatingConsumer.java

</details>

<details>
<summary>🔇 Additional comments (15)</summary><blockquote>

<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/PaymentStatus.java (1)</summary>

`3-8`: **enum 매핑 검증: 외부 API와의 값 일치 여부 확인 필요**  
`PaymentStatus`의 enum 상수가 ReservationService에서 반환하는 상태 문자열과 정확히 매핑되는지 확인하세요. Jackson 직렬화/역직렬화 시 대소문자나 언더스코어 여부가 다르면 매핑 오류가 발생할 수 있으므로, 필요시 `@JsonProperty` 등을 사용해 명시적으로 매핑을 지정하십시오.

</details>
<details>
<summary>common/src/main/java/com/carenest/business/common/event/caregiver/CaregiverRatingEvent.java (1)</summary>

`12-18`: **@NoArgsConstructor 사용 시 BaseEvent 기본 생성자 호출 검증**  
`@NoArgsConstructor`로 생성되는 파라미터 없는 생성자가 `BaseEvent`의 생성자 로직을 올바르게 처리하는지 확인이 필요합니다. 만약 `BaseEvent`에 디폴트 생성자가 없으면 JSON 역직렬화 시 예외가 발생할 수 있으므로, `@NoArgsConstructor(force = true)` 또는 `@JsonCreator` 등으로 보완을 고려해 주세요.

</details>
<details>
<summary>review-service/src/main/java/com/carenest/business/reviewservice/infrastructure/kafka/CaregiverRatingProducer.java (1)</summary>

`14-14`: **KafkaTemplate JSON 직렬화 설정 확인**  
`KafkaTemplate<String, Object>`를 통해 `CaregiverRatingEvent` 객체를 전송하고 있는데, 프로듀서 측 `ProducerFactory` 혹은 `application.yml` 설정에 `JsonSerializer`/`JsonDeserializer`가 올바르게 등록되어 있는지 검증하세요. 그렇지 않으면 소비자 측에서 타입 매핑 오류가 발생할 수 있습니다.  



Also applies to: 26-29

</details>
<details>
<summary>gateway-service/src/main/java/com/carenest/business/gatewayservice/GatewayConfig.java (1)</summary>

`29-29`: **라우트 구성 변경이 적절하게 이루어졌습니다.**

케어기버 승인 관련 새 API 경로(`/api/v1/caregiver-approvals/**`)가 적절하게 추가되었습니다. RESTful API 네이밍 규칙을 잘 따르고 있으며 JWT 인증이 올바르게 유지되고 있습니다.

</details>
<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/dto/reservation/ReservationStatus.java (1)</summary>

`3-10`: **예약 상태 열거형 구현이 적절합니다.**

예약의 모든 가능한 상태를 명확하게 정의하여 시스템 전반에서 일관된 상태 관리가 가능하도록 했습니다. 특히 `PENDING_ACCEPTANCE` 상태는 이번에 추가된 간병인 승인 프로세스를 위한 중요한 상태입니다.

</details>
<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverConsumerService.java (1)</summary>

`3-7`: **이벤트 네이밍 표준화가 적절하게 적용되었습니다.**

`CaregiverRatingMessage`에서 `CaregiverRatingEvent`로 변경한 것은 이벤트 명명 규칙의 일관성을 높이는 좋은 리팩토링입니다. 이는 PR 목표에 명시된 "이벤트 네이밍 일관성 개선"에 부합합니다.

</details>
<details>
<summary>payment-service/src/main/java/com/carenest/business/paymentservice/application/service/PaymentServiceImpl.java (1)</summary>

`3-16`: **와일드카드 임포트 대신 명시적 임포트 사용이 좋습니다.**

Java 표준 및 Spring 프레임워크 클래스들을 와일드카드 임포트가 아닌 명시적 임포트로 변경함으로써 코드 가독성과 유지보수성이 향상되었습니다.

</details>
<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverConsumerServiceImpl.java (2)</summary>

`11-11`: **이벤트 클래스 임포트가 적절하게 업데이트되었습니다.**

`CaregiverRatingMessage`에서 `CaregiverRatingEvent`로 임포트를 변경하여 인터페이스 변경사항과 일관성을 유지했습니다.

---

`24-24`: **메서드 시그니처가 인터페이스와 일치하도록 업데이트되었습니다.**

`handleCaregiverRatingUpdate` 메서드의 파라미터 타입을 `CaregiverRatingEvent`로 변경하여 인터페이스 정의와 구현이 동기화되었습니다. 이는 이벤트 네이밍 표준화에 따른 적절한 변경입니다.

</details>
<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/client/ReservationClient.java (1)</summary>

`13-21`: **Feign 클라이언트 인터페이스가 명확하게 정의되었습니다.**

Feign 클라이언트를 사용하여 예약 서비스와의 통신이 잘 구현되었습니다. API 엔드포인트와 응답 타입이 적절하게 정의되어 있습니다.

</details>
<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/config/FeignConfig.java (1)</summary>

`15-29`: **Feign 설정이 적절하게 구현되었습니다.**

Jackson을 사용한 JSON 변환 설정이 올바르게 구현되어 있습니다.

</details>
<details>
<summary>common/src/main/java/com/carenest/business/common/event/caregiver/CaregiverPendingEvent.java (1)</summary>

`10-18`: **이벤트 클래스가 적절하게 구현되었습니다.**

`CaregiverPendingEvent` 클래스가 필요한 필드와 롬복 애노테이션을 사용하여 깔끔하게 구현되었습니다.

</details>
<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/presentation/controller/CaregiverApprovalController.java (1)</summary>

`17-32`: **컨트롤러가 적절하게 구현되었습니다.**

인증된 사용자의 대기 중인 승인 목록을 조회하는 API가 잘 구현되어 있습니다. 서비스 계층으로 비즈니스 로직을 위임하는 구조도 적절합니다.

</details>
<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/domain/model/CaregiverApproval.java (1)</summary>

`31-46`: **멱등성 보장을 위한 로직 강화**

현재 구현은 reservationId를 @Id로 사용하여 멱등성을 보장하고 있습니다. 이는 좋은 접근 방식이지만, 추가적인 로직이 필요할 수 있습니다.


reservationId를 기본 키로 사용하는 것은 동일한 예약에 대한 중복 승인/거절을 방지하는 좋은 설계입니다. 이는 이벤트가 중복으로 수신되더라도 데이터 일관성을 유지할 수 있게 해줍니다.

</details>
<details>
<summary>caregiver-service/src/main/java/com/carenest/business/caregiverservice/config/ConsumerKafkaConfig.java (1)</summary>

`17-18`: <details>
<summary>✅ Verification successful</summary>

**이벤트 클래스 이름 변경이 일관되게 적용되었는지 확인하세요.**

`CaregiverRatingMessage`에서 `CaregiverRatingEvent`로 이벤트 클래스 이름이 변경되었는데, 코드베이스 전체에서 이 변경이 일관되게 적용되었는지 확인하는 것이 좋겠습니다. 이 변경으로 인해 다른 서비스나 컴포넌트에서 예기치 않은 오류가 발생할 수 있습니다.




Also applies to: 29-29

---

🏁 Script executed:

```shell
#!/bin/bash
# 코드베이스에서 CaregiverRatingMessage와 CaregiverRatingEvent의 사용 여부 확인
echo "코드베이스에서 CaregiverRatingMessage 검색 결과:"
rg "CaregiverRatingMessage" --type java

echo "코드베이스에서 CaregiverRatingEvent 검색 결과:"
rg "CaregiverRatingEvent" --type java
```

Length of output: 2847

---



</details>

**CaregiverRatingEvent로의 이벤트 클래스 이름 변경이 코드베이스 전반에 일관되게 적용되었습니다.**  
코드베이스에서 `CaregiverRatingMessage` 검색 시 결과가 없으며, 모든 참조가 `CaregiverRatingEvent`로 업데이트된 것을 확인했습니다. 추가 조치가 필요 없습니다.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-21T02:37:29Z

Review comments:
diff_hunk: @@ -0,0 +1,14 @@
+package com.carenest.business.caregiverservice.application.service;
+
+import java.util.List;
+import java.util.UUID;
+
+import com.carenest.business.caregiverservice.presentation.dto.response.PendingApprovalResponse;
+import com.carenest.business.common.event.caregiver.CaregiverPendingEvent;
+
+public interface CaregiverApprovalService {
+
+	void createCaregiverApproval(CaregiverPendingEvent event);
+
+	List<PendingApprovalResponse> getPendingApprovals(UUID userId);
+}
path: caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverApprovalService.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**승인/거절 처리 메소드 및 문서화 필요**

현재 인터페이스에는 승인 생성과 조회 메소드만 있고, PR 요약에 언급된 승인 및 거절 기능이 정의되어 있지 않습니다. 또한 각 메소드의 목적과 동작을 설명하는 Javadoc이 없습니다.


승인/거절 처리 메소드를 추가하고 각 메소드에 문서화를 추가하세요:

```diff
 public interface CaregiverApprovalService {
+    /**
+     * 간병인 승인 대기 상태를 생성합니다.
+     * 
+     * @param event 승인 대기 이벤트
+     */
 	void createCaregiverApproval(CaregiverPendingEvent event);
 
+    /**
+     * 특정 간병인의 승인 대기 중인 예약 목록을 조회합니다.
+     * 
+     * @param userId 간병인 ID
+     * @return 승인 대기 중인 예약 정보 목록
+     */
 	List<PendingApprovalResponse> getPendingApprovals(UUID userId);
+    
+    /**
+     * 간병인이 예약을 승인합니다.
+     * 
+     * @param approvalId 승인 ID
+     * @param caregiverId 간병인 ID
+     */
+    void acceptReservation(UUID approvalId, UUID caregiverId);
+    
+    /**
+     * 간병인이 예약을 거절합니다.
+     * 
+     * @param approvalId 승인 ID
+     * @param caregiverId 간병인 ID
+     * @param reason 거절 사유
+     */
+    void rejectReservation(UUID approvalId, UUID caregiverId, String reason);
 }
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **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.

`````suggestion
public interface CaregiverApprovalService {

    /**
     * 간병인 승인 대기 상태를 생성합니다.
     *
     * @param event 승인 대기 이벤트
     */
    void createCaregiverApproval(CaregiverPendingEvent event);

    /**
     * 특정 간병인의 승인 대기 중인 예약 목록을 조회합니다.
     *
     * @param userId 간병인 ID
     * @return 승인 대기 중인 예약 정보 목록
     */
    List<PendingApprovalResponse> getPendingApprovals(UUID userId);

    /**
     * 간병인이 예약을 승인합니다.
     *
     * @param approvalId 승인 ID
     * @param caregiverId 간병인 ID
     */
    void acceptReservation(UUID approvalId, UUID caregiverId);

    /**
     * 간병인이 예약을 거절합니다.
     *
     * @param approvalId 승인 ID
     * @param caregiverId 간병인 ID
     * @param reason 거절 사유
     */
    void rejectReservation(UUID approvalId, UUID caregiverId, String reason);
}
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-21T02:37:28Z
author_association: NONE
diff_hunk: @@ -0,0 +1,49 @@
+package com.carenest.business.caregiverservice.infrastructure.kafka;
+
+import org.springframework.kafka.annotation.KafkaListener;
+import org.springframework.stereotype.Component;
+
+import com.carenest.business.caregiverservice.application.service.CaregiverApprovalService;
+import com.carenest.business.caregiverservice.application.service.CaregiverConsumerService;
+import com.carenest.business.common.event.caregiver.CaregiverPendingEvent;
+import com.carenest.business.common.event.caregiver.CaregiverRatingEvent;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class CaregiverConsumer {
+
+	private final CaregiverConsumerService caregiverConsumerService;
+	private final CaregiverApprovalService caregiverApprovalService;
+
+	@KafkaListener(
+		topics = "review-rating-update",
+		groupId = "caregiver-service-group",
+		containerFactory = "kafkaListenerConsumerContainerFactory"
+	)
+	public void handleCaregiverRatingUpdate(CaregiverRatingEvent message) {
+		log.info("간병인 평점 업데이트 이벤트 수신: {}", message);
+		caregiverConsumerService.handleCaregiverRatingUpdate(message);
+	}
+
+
+	@KafkaListener(
+		topics = "caregiver-accept",
+		groupId = "caregiver-service-group",
+		containerFactory = "caregiverPendingKafkaListenerContainerFactory"
+	)
+	public void handleCaregiverAccept(CaregiverPendingEvent event){
+		try {
+			log.info("간병인 승인 요청 이벤트 수신: {}", event);
+			caregiverApprovalService.createCaregiverApproval(event);
+		} catch (Exception ex) {
+			log.error("CaregiverPendingEvent 처리 실패: {}", event, ex);
+			throw ex;
+		}
+	}
path: caregiver-service/src/main/java/com/carenest/business/caregiverservice/infrastructure/kafka/CaregiverConsumer.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**예외 처리 메커니즘의 개선 필요**

현재 구현에서는 예외를 로깅하고 그대로 다시 던지고 있습니다. 이로 인해 재시도 메커니즘이 구현되어 있지 않다면, 해당 이벤트가 영구적으로 실패할 수 있습니다. 이벤트 처리의 안정성을 높이기 위해 다음과 같은 방법을 고려해보세요:


```diff
public void handleCaregiverAccept(CaregiverPendingEvent event){
    try {
        log.info("간병인 승인 요청 이벤트 수신: {}", event);
        caregiverApprovalService.createCaregiverApproval(event);
    } catch (Exception ex) {
        log.error("CaregiverPendingEvent 처리 실패: {}", event, ex);
-       throw ex;
+       // 이벤트 처리 실패 시 데드레터 큐로 보내거나, 재시도 카운트를 증가시키는 로직 추가
+       // 심각한 오류인 경우에만 예외를 다시 throw
+       if (isNonRecoverableError(ex)) {
+           throw ex;
+       }
    }
}

+ private boolean isNonRecoverableError(Exception ex) {
+     // 복구 불가능한 오류(예: 유효하지 않은 데이터 형식)인지 확인하는 로직
+     return ex instanceof IllegalArgumentException || ex instanceof NullPointerException;
+ }
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **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.

`````suggestion
	public void handleCaregiverAccept(CaregiverPendingEvent event){
		try {
			log.info("간병인 승인 요청 이벤트 수신: {}", event);
			caregiverApprovalService.createCaregiverApproval(event);
		} catch (Exception ex) {
			log.error("CaregiverPendingEvent 처리 실패: {}", event, ex);
			// 이벤트 처리 실패 시 데드레터 큐로 보내거나, 재시도 카운트를 증가시키는 로직 추가
			// 심각한 오류인 경우에만 예외를 다시 throw
			if (isNonRecoverableError(ex)) {
				throw ex;
			}
		}
	}

	private boolean isNonRecoverableError(Exception ex) {
		// 복구 불가능한 오류(예: 유효하지 않은 데이터 형식)인지 확인하는 로직
		return ex instanceof IllegalArgumentException || ex instanceof NullPointerException;
	}
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-21T02:37:28Z
author_association: NONE
diff_hunk: @@ -0,0 +1,39 @@
+package com.carenest.business.caregiverservice.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import com.carenest.business.caregiverservice.exception.CaregiverException;
+import com.carenest.business.caregiverservice.exception.ErrorCode;
+
+import feign.Response;
+import feign.codec.ErrorDecoder;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Configuration
+public class FeignErrorDecoderConfig {
+
+	@Bean
+	public ErrorDecoder errorDecoder() {
+		return new CustomErrorDecoder();
+	}
+
+	public static class CustomErrorDecoder implements ErrorDecoder {
+		@Override
+		public Exception decode(String methodKey, Response response) {
+			log.error("Feign client error: {} - {}", response.status(), methodKey);
+
+			if (response.status() >= 500) {
+				log.error("서버 오류 발생: 서비스={}, 상태코드={}", methodKey, response.status());
+				return new CaregiverException(ErrorCode.EXTERNAL_API_ERROR);
+			} else if (response.status() >= 400) {
+				log.error("클라이언트 오류 발생: 서비스={}, 상태코드={}", methodKey, response.status());
+				return new CaregiverException(ErrorCode.EXTERNAL_API_ERROR);
+			}
+
+			log.error("알 수 없는 오류 발생: 서비스={}, 상태코드={}", methodKey, response.status());
+			return new CaregiverException(ErrorCode.EXTERNAL_API_ERROR);
+		}
path: caregiver-service/src/main/java/com/carenest/business/caregiverservice/config/FeignErrorDecoderConfig.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Feign 오류 처리 세분화 필요**

현재 구현에서는 모든 오류 상황에 대해 동일한 `EXTERNAL_API_ERROR` 코드를 사용하고 있습니다. 상황에 따라 더 세분화된 오류 코드와 메시지를 제공하면 디버깅과 문제 해결에 도움이 됩니다.


```diff
public Exception decode(String methodKey, Response response) {
    log.error("Feign client error: {} - {}", response.status(), methodKey);

    if (response.status() >= 500) {
        log.error("서버 오류 발생: 서비스={}, 상태코드={}", methodKey, response.status());
-       return new CaregiverException(ErrorCode.EXTERNAL_API_ERROR);
+       return new CaregiverException(ErrorCode.EXTERNAL_SERVER_ERROR);
    } else if (response.status() >= 400) {
        log.error("클라이언트 오류 발생: 서비스={}, 상태코드={}", methodKey, response.status());
-       return new CaregiverException(ErrorCode.EXTERNAL_API_ERROR);
+       // HTTP 상태 코드별 더 구체적인 오류 처리
+       switch (response.status()) {
+           case 404:
+               return new CaregiverException(ErrorCode.RESOURCE_NOT_FOUND);
+           case 401:
+           case 403:
+               return new CaregiverException(ErrorCode.UNAUTHORIZED_ACCESS);
+           default:
+               return new CaregiverException(ErrorCode.EXTERNAL_CLIENT_ERROR);
+       }
    }

    log.error("알 수 없는 오류 발생: 서비스={}, 상태코드={}", methodKey, response.status());
    return new CaregiverException(ErrorCode.EXTERNAL_API_ERROR);
}
```

ErrorCode enum에 더 세분화된 에러 코드를 추가해야 합니다.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **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.

`````suggestion
	public static class CustomErrorDecoder implements ErrorDecoder {
		@Override
		public Exception decode(String methodKey, Response response) {
			log.error("Feign client error: {} - {}", response.status(), methodKey);

			if (response.status() >= 500) {
				log.error("서버 오류 발생: 서비스={}, 상태코드={}", methodKey, response.status());
				return new CaregiverException(ErrorCode.EXTERNAL_SERVER_ERROR);
			} else if (response.status() >= 400) {
				log.error("클라이언트 오류 발생: 서비스={}, 상태코드={}", methodKey, response.status());
				// HTTP 상태 코드별 더 구체적인 오류 처리
				switch (response.status()) {
					case 404:
						return new CaregiverException(ErrorCode.RESOURCE_NOT_FOUND);
					case 401:
					case 403:
						return new CaregiverException(ErrorCode.UNAUTHORIZED_ACCESS);
					default:
						return new CaregiverException(ErrorCode.EXTERNAL_CLIENT_ERROR);
				}
			}

			log.error("알 수 없는 오류 발생: 서비스={}, 상태코드={}", methodKey, response.status());
			return new CaregiverException(ErrorCode.EXTERNAL_API_ERROR);
		}
	}
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-21T02:37:28Z
author_association: NONE
diff_hunk: @@ -0,0 +1,79 @@
+package com.carenest.business.caregiverservice.application.service;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.carenest.business.caregiverservice.domain.model.Caregiver;
+import com.carenest.business.caregiverservice.domain.model.CaregiverApproval;
+import com.carenest.business.caregiverservice.exception.CaregiverException;
+import com.carenest.business.caregiverservice.exception.ErrorCode;
+import com.carenest.business.caregiverservice.infrastructure.client.ReservationClient;
+import com.carenest.business.caregiverservice.infrastructure.client.dto.reservation.ReservationResponse;
+import com.carenest.business.caregiverservice.infrastructure.repository.CaregiverApprovalRepository;
+import com.carenest.business.caregiverservice.infrastructure.repository.CaregiverRepository;
+import com.carenest.business.caregiverservice.presentation.dto.response.PendingApprovalResponse;
+import com.carenest.business.common.event.caregiver.CaregiverPendingEvent;
+
+import feign.FeignException;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class CaregiverApprovalServiceImpl implements CaregiverApprovalService{
+	private final CaregiverRepository caregiverRepository;
+	private final CaregiverApprovalRepository caregiverApprovalRepository;
+	private final ReservationClient reservationClient;
+
+	@Override
+	@Transactional
+	public void createCaregiverApproval(CaregiverPendingEvent event) {
+		// 중복 방지
+		if (caregiverApprovalRepository.existsById(event.getReservationId())) {
+			return;
+		}
+		CaregiverApproval  caregiverApproval = CaregiverApproval.builder()
+			.reservationId(event.getReservationId())
+			.caregiverId(event.getCaregiverId())
+			.message(event.getMessage())
+			.build();
+
+		caregiverApprovalRepository.save(caregiverApproval);
+	}
+
+	@Override
+	@Transactional(readOnly = true)
+	public List<PendingApprovalResponse> getPendingApprovals(UUID userId) {
+
+		// 1. 간병인 찾기
+		Caregiver caregiver = caregiverRepository.findByUserId(userId)
+			.orElseThrow(() -> new CaregiverException(ErrorCode.NOT_FOUND));
+
+		// 2. 간병인 ID로 존재하는 승인/거부 조회
+		List<CaregiverApproval> approvals = caregiverApprovalRepository.findByCaregiverId(caregiver.getId());
+
+		return approvals.stream()
+			.map(approval -> {
+				try{
+					// 예약 정보 조회
+					ReservationResponse resp = reservationClient.getReservationDetails(approval.getReservationId()).getData();
+					return new PendingApprovalResponse(
+						approval.getReservationId(),
+						approval.getCaregiverId(),
+						resp.getPatientCondition(),
+						resp.getCareAddress(),
+						resp.getServiceRequests(),
+						resp.getTotalAmount(),
+						resp.getServiceFee()
+					);
+				}catch (FeignException e){
+					log.warn("예약 정보 조회 실패: userId={}, error={}", userId, e.getMessage());
+					throw  new CaregiverException(ErrorCode.EXTERNAL_API_ERROR);
+				}
+			}).toList();
+	}
path: caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverApprovalServiceImpl.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**예약 정보 조회 최적화**

현재 구현은 각 승인 건마다 개별적으로 예약 서비스를 호출합니다. 대기 중인 승인이 많을 경우 성능 문제가 발생할 수 있습니다. 일괄 처리 방식으로 개선하는 것이 좋습니다.


```diff
@Override
@Transactional(readOnly = true)
public List<PendingApprovalResponse> getPendingApprovals(UUID userId) {

    // 1. 간병인 찾기
    Caregiver caregiver = caregiverRepository.findByUserId(userId)
        .orElseThrow(() -> new CaregiverException(ErrorCode.NOT_FOUND));

    // 2. 간병인 ID로 존재하는 승인/거부 조회
    List<CaregiverApproval> approvals = caregiverApprovalRepository.findByCaregiverId(caregiver.getId());

+   if (approvals.isEmpty()) {
+       log.info("대기 중인 승인 요청이 없습니다: userId={}, caregiverId={}", userId, caregiver.getId());
+       return List.of();
+   }
+
+   // 3. 모든 예약 ID 수집
+   List<UUID> reservationIds = approvals.stream()
+       .map(CaregiverApproval::getReservationId)
+       .toList();
+
+   // 4. 예약 ID 목록으로 한 번에 조회 (ReservationClient에 새 메서드 추가 필요)
+   try {
+       Map<UUID, ReservationResponse> reservationsMap = reservationClient.getReservationsDetails(reservationIds)
+           .getData().stream()
+           .collect(Collectors.toMap(
+               ReservationResponse::getReservationId,
+               Function.identity()
+           ));
+
+       // 5. 응답 생성
+       return approvals.stream()
+           .map(approval -> {
+               ReservationResponse resp = reservationsMap.get(approval.getReservationId());
+               if (resp == null) {
+                   log.warn("예약 정보를 찾을 수 없습니다: reservationId={}", approval.getReservationId());
+                   return null;
+               }
+               return new PendingApprovalResponse(
+                   approval.getReservationId(),
+                   approval.getCaregiverId(),
+                   resp.getPatientCondition(),
+                   resp.getCareAddress(),
+                   resp.getServiceRequests(),
+                   resp.getTotalAmount(),
+                   resp.getServiceFee()
+               );
+           })
+           .filter(Objects::nonNull)
+           .toList();
+
+   } catch (FeignException e) {
+       log.warn("예약 정보 조회 실패: userId={}, error={}", userId, e.getMessage());
+       throw new CaregiverException(ErrorCode.EXTERNAL_API_ERROR);
+   }

-   return approvals.stream()
-       .map(approval -> {
-           try{
-               // 예약 정보 조회
-               ReservationResponse resp = reservationClient.getReservationDetails(approval.getReservationId()).getData();
-               return new PendingApprovalResponse(
-                   approval.getReservationId(),
-                   approval.getCaregiverId(),
-                   resp.getPatientCondition(),
-                   resp.getCareAddress(),
-                   resp.getServiceRequests(),
-                   resp.getTotalAmount(),
-                   resp.getServiceFee()
-               );
-           }catch (FeignException e){
-               log.warn("예약 정보 조회 실패: userId={}, error={}", userId, e.getMessage());
-               throw  new CaregiverException(ErrorCode.EXTERNAL_API_ERROR);
-           }
-       }).toList();
}
```

ReservationClient 인터페이스에 다음 메서드를 추가해야 합니다:
```java
ApiResponse<List<ReservationResponse>> getReservationsDetails(List<UUID> reservationIds);
```

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-21T02:37:29Z
author_association: NONE
diff_hunk: @@ -0,0 +1,79 @@
+package com.carenest.business.caregiverservice.application.service;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.carenest.business.caregiverservice.domain.model.Caregiver;
+import com.carenest.business.caregiverservice.domain.model.CaregiverApproval;
+import com.carenest.business.caregiverservice.exception.CaregiverException;
+import com.carenest.business.caregiverservice.exception.ErrorCode;
+import com.carenest.business.caregiverservice.infrastructure.client.ReservationClient;
+import com.carenest.business.caregiverservice.infrastructure.client.dto.reservation.ReservationResponse;
+import com.carenest.business.caregiverservice.infrastructure.repository.CaregiverApprovalRepository;
+import com.carenest.business.caregiverservice.infrastructure.repository.CaregiverRepository;
+import com.carenest.business.caregiverservice.presentation.dto.response.PendingApprovalResponse;
+import com.carenest.business.common.event.caregiver.CaregiverPendingEvent;
+
+import feign.FeignException;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class CaregiverApprovalServiceImpl implements CaregiverApprovalService{
+	private final CaregiverRepository caregiverRepository;
+	private final CaregiverApprovalRepository caregiverApprovalRepository;
+	private final ReservationClient reservationClient;
+
+	@Override
+	@Transactional
+	public void createCaregiverApproval(CaregiverPendingEvent event) {
+		// 중복 방지
+		if (caregiverApprovalRepository.existsById(event.getReservationId())) {
+			return;
+		}
+		CaregiverApproval  caregiverApproval = CaregiverApproval.builder()
+			.reservationId(event.getReservationId())
+			.caregiverId(event.getCaregiverId())
+			.message(event.getMessage())
+			.build();
+
+		caregiverApprovalRepository.save(caregiverApproval);
+	}
path: caregiver-service/src/main/java/com/carenest/business/caregiverservice/application/service/CaregiverApprovalServiceImpl.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**입력 값 유효성 검사 추가**

현재 이벤트 데이터에 대한 유효성 검사가 누락되어 있습니다. 비즈니스 로직을 수행하기 전에 입력 값의 유효성을 검사하여 애플리케이션의 안정성을 높이세요.


```diff
@Override
@Transactional
public void createCaregiverApproval(CaregiverPendingEvent event) {
+   // 입력 값 유효성 검사
+   if (event == null) {
+       throw new IllegalArgumentException("이벤트가 null입니다");
+   }
+   if (event.getReservationId() == null) {
+       throw new IllegalArgumentException("예약 ID가 null입니다");
+   }
+   if (event.getCaregiverId() == null) {
+       throw new IllegalArgumentException("간병인 ID가 null입니다");
+   }
+
    // 중복 방지
    if (caregiverApprovalRepository.existsById(event.getReservationId())) {
        return;
    }
    CaregiverApproval  caregiverApproval = CaregiverApproval.builder()
        .reservationId(event.getReservationId())
        .caregiverId(event.getCaregiverId())
        .message(event.getMessage())
        .build();

    caregiverApprovalRepository.save(caregiverApproval);
}
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **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.

`````suggestion
	@Transactional
	public void createCaregiverApproval(CaregiverPendingEvent event) {
		// 입력 값 유효성 검사
		if (event == null) {
			throw new IllegalArgumentException("이벤트가 null입니다");
		}
		if (event.getReservationId() == null) {
			throw new IllegalArgumentException("예약 ID가 null입니다");
		}
		if (event.getCaregiverId() == null) {
			throw new IllegalArgumentException("간병인 ID가 null입니다");
		}

		// 중복 방지
		if (caregiverApprovalRepository.existsById(event.getReservationId())) {
			return;
		}
		CaregiverApproval  caregiverApproval = CaregiverApproval.builder()
			.reservationId(event.getReservationId())
			.caregiverId(event.getCaregiverId())
			.message(event.getMessage())
			.build();

		caregiverApprovalRepository.save(caregiverApproval);
	}
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-21T02:37:29Z
author_association: NONE

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-04-21T02:33:38Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough

이번 변경에서는 결제 완료 이후 예약 승인/거절 프로세스를 위한 간병인 승인(PendingApproval) 도메인 및 API가 도입되었습니다. 결제 서비스에서 결제 완료 시 `CaregiverPendingEvent`를 Kafka로 발행하고, 간병인 서비스에서는 해당 이벤트를 수신하여 `CaregiverApproval` 엔티티에 `PENDING` 상태로 저장합니다. 또한, 간병인별 대기 승인 목록을 조회하는 REST API(`/api/v1/caregiver-approvals/pending`)가 추가되었으며, 외부 예약 서비스와의 연동을 위한 Feign 클라이언트 및 관련 DTO/enum, 예외 처리, Kafka 설정 등이 추가되었습니다. 기존 리뷰 평점 처리 이벤트의 네이밍도 일관성 있게 변경되었습니다.

## Changes

| 파일/경로 요약 | 변경 요약 |
|---|---|
| `.../CaregiverApprovalService.java`, `.../CaregiverApprovalServiceImpl.java`, `.../CaregiverApprovalRepository.java`, `.../CaregiverApprovalController.java`, `.../PendingApprovalResponse.java`, `.../CaregiverApproval.java` | 간병인 승인(PendingApproval) 도메인, 서비스, 저장소, 컨트롤러, DTO 신설 및 구현 |
| `.../CaregiverConsumer.java`, (삭제) `.../CaregiverRatingConsumer.java` | Kafka 이벤트 통합 소비자 신설, 기존 평점 소비자 삭제 |
| `.../CaregiverConsumerService.java`, `.../CaregiverConsumerServiceImpl.java`, `.../ConsumerKafkaConfig.java` | 평점 이벤트 네이밍(`CaregiverRatingEvent`) 통일 및 Kafka 컨슈머 설정 개선, 신규 이벤트(`CaregiverPendingEvent`) 수신 설정 추가 |
| `.../FeignConfig.java`, `.../FeignErrorDecoderConfig.java`, `.../ReservationClient.java`, `.../dto/reservation/*` | 예약 서비스 연동용 Feign 클라이언트, DTO, enum, 오류 디코더 등 신설 |
| `.../ErrorCode.java` | 예약 미존재 오류 코드(`NOT_EXISTS_PENDING`) 추가 |
| `common/.../CaregiverPendingEvent.java`, `common/.../CaregiverRatingEvent.java` | 이벤트 클래스 신설 및 네이밍 일관화 |
| `payment-service/.../PaymentEventProducer.java`, `.../KafkaConfig.java`, `.../PaymentServiceImpl.java` | 결제 완료 시 `CaregiverPendingEvent` 발행 로직 및 Kafka 토픽 설정 추가 |
| `gateway-service/.../GatewayConfig.java` | 간병인 승인 API 라우팅 추가 |
| `review-service/.../CaregiverRatingProducer.java` | 평점 이벤트 네이밍(`CaregiverRatingEvent`) 일치화 |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant PaymentService
    participant Kafka
    participant CaregiverService
    participant DB
    participant ReservationService

    PaymentService->>Kafka: CaregiverPendingEvent 발행 (caregiver-accept)
    Kafka->>CaregiverService: CaregiverPendingEvent 수신
    CaregiverService->>DB: CaregiverApproval(PENDING) 저장
    UI->>CaregiverService: GET /api/v1/caregiver-approvals/pending
    CaregiverService->>DB: CaregiverApproval 조회
    CaregiverService->>ReservationService: 예약 상세 조회(Feign)
    CaregiverService->>UI: PendingApproval 목록 반환
```

## Assessment against linked issues

| Objective | Addressed | Explanation |
|---|---|---|
| CaregiverService: KafkaListener로 이벤트 수신 후 PendingApproval 저장 (#114) | ✅ |  |
| CaregiverService: GET /v1/caregiver-approvals/pending API 구현 (#114) | ✅ |  |

## Suggested labels

`refactor ⚙`, `feature`

## Poem

> 🐇  
> 새로운 승인 흐름이 왔어요,  
> 결제 끝나면 이벤트 타고,  
> 대기 목록에 살포시 저장,  
> 간병인 마음은 두근두근!  
> API도 새로 생겼으니,  
> 오늘도 변화에 귀 쫑긋,  
> 코드밭에 봄바람 솔솔!  
>

<!-- walkthrough_end -->

<!-- announcements_start -->

> [!TIP]
> <details>
> <summary>⚡💬 Agentic Chat (Pro Plan, General Availability)</summary>
> 
> - We're introducing multi-step agentic chat in review comments and issue comments, within and outside of PR's. This feature enhances review and issue discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments and add commits to existing pull requests.
> 
> </details>

<!-- announcements_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=Sparta-CareNest/carnest-backend&utm_content=118):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: NONE
user: login: mango606
created_at: 2025-04-21T02:44:12Z
body: 제가 이해한 게 맞다면 간병인에서 수락/거절을 담당하면, 결제하면 바로 예약이 체결되게 예약쪽 status 부분을 수정해 보겠습니다. 고생하셨어요!
author_association: MEMBER