From 7a75a2cc2148aa3aaf1f450780b5c2edc20a91ef Mon Sep 17 00:00:00 2001 From: kangcheolung Date: Thu, 9 Jul 2026 16:16:48 +0900 Subject: [PATCH 1/6] =?UTF-8?q?refactor:=20MedicationDetailResponse=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0,=20MedicationGroupItemResponse=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DrugInfo 기반 상세 응답 폐기, 약물노트 그룹 상세 조회용 DTO로 교체 Co-Authored-By: Claude Sonnet 4.6 --- .../response/MedicationDetailResponse.java | 23 ----------- .../response/MedicationGroupItemResponse.java | 39 +++++++++++++++++++ 2 files changed, 39 insertions(+), 23 deletions(-) delete mode 100644 src/main/java/com/piuda/callcare/domain/medication/dto/response/MedicationDetailResponse.java create mode 100644 src/main/java/com/piuda/callcare/domain/medication/dto/response/MedicationGroupItemResponse.java diff --git a/src/main/java/com/piuda/callcare/domain/medication/dto/response/MedicationDetailResponse.java b/src/main/java/com/piuda/callcare/domain/medication/dto/response/MedicationDetailResponse.java deleted file mode 100644 index 9caeb76..0000000 --- a/src/main/java/com/piuda/callcare/domain/medication/dto/response/MedicationDetailResponse.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.piuda.callcare.domain.medication.dto.response; - -import io.swagger.v3.oas.annotations.media.Schema; - -@Schema(description = "약 상세 정보 응답 — drugName은 항상 반환, DrugInfo 미연결 시 의약품 정보 필드 null") -public record MedicationDetailResponse( - - @Schema(description = "약품명") - String drugName, - - @Schema(description = "효능·효과 (없으면 null)") - String efcyQesitm, - - @Schema(description = "용법·용량 (없으면 null)") - String useMethodQesitm, - - @Schema(description = "주의사항 (없으면 null)") - String atpnQesitm, - - @Schema(description = "부작용 (없으면 null)") - String seQesitm -) { -} diff --git a/src/main/java/com/piuda/callcare/domain/medication/dto/response/MedicationGroupItemResponse.java b/src/main/java/com/piuda/callcare/domain/medication/dto/response/MedicationGroupItemResponse.java new file mode 100644 index 0000000..d5f5f74 --- /dev/null +++ b/src/main/java/com/piuda/callcare/domain/medication/dto/response/MedicationGroupItemResponse.java @@ -0,0 +1,39 @@ +package com.piuda.callcare.domain.medication.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; + +import java.time.LocalDate; + +@Schema(description = "그룹 내 약 단건 응답") +public record MedicationGroupItemResponse( + + @Schema(description = "약 ID") + Long medicationId, + + @Schema(description = "약 이름") + String drugName, + + @Schema(description = "약 종류 (없으면 null)") + String drugType, + + @Schema(description = "약 이미지 URL (없으면 null)") + String imageUrl, + + @Schema(description = "1일 복용 횟수") + Integer timesPerDay, + + @Schema(description = "1회 복용량 (예: 1정, 5ml)") + String dosagePerTime, + + @Schema(description = "복용 시작일") + LocalDate startDate, + + @Schema(description = "복용 종료일 (없으면 null)") + LocalDate endDate, + + @Schema(description = "총 복용 일수 (없으면 null)") + Integer totalDays, + + @Schema(description = "메모 — OCR 자동 생성 또는 사용자 직접 입력 (없으면 null)") + String memo +) {} From 822bae23d73772ba1591a25f5b9fa8a4e91b7cb9 Mon Sep 17 00:00:00 2001 From: kangcheolung Date: Thu, 9 Jul 2026 16:17:05 +0900 Subject: [PATCH 2/6] =?UTF-8?q?feat:=20=EC=95=BD=EB=AC=BC=EB=85=B8?= =?UTF-8?q?=ED=8A=B8=20=EA=B7=B8=EB=A3=B9=20=EC=83=81=EC=84=B8=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=BF=BC=EB=A6=AC=20=EC=B6=94=EA=B0=80=20(findByGr?= =?UTF-8?q?oup)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 병원명 + 처방일 조합으로 그룹 조회, null 파라미터 처리 포함 Co-Authored-By: Claude Sonnet 4.6 --- .../repository/MedicationRepository.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/com/piuda/callcare/domain/medication/repository/MedicationRepository.java b/src/main/java/com/piuda/callcare/domain/medication/repository/MedicationRepository.java index edba5c0..0ccf481 100644 --- a/src/main/java/com/piuda/callcare/domain/medication/repository/MedicationRepository.java +++ b/src/main/java/com/piuda/callcare/domain/medication/repository/MedicationRepository.java @@ -1,5 +1,6 @@ package com.piuda.callcare.domain.medication.repository; +import java.time.LocalDate; import java.util.List; import com.piuda.callcare.domain.medication.entity.Medication; @@ -27,4 +28,17 @@ public interface MedicationRepository extends JpaRepository { AND m.isActive = true """) List findActiveWithDrugInfoBySeniorId(@Param("seniorId") Long seniorId); + + // 약물노트 그룹 상세 조회: 병원명 + 처방일 조합이 그룹 키 (둘 다 null 가능) + @Query(""" + SELECT m FROM Medication m + WHERE m.senior.id = :seniorId + AND ((:hospitalName IS NULL AND m.hospitalName IS NULL) OR m.hospitalName = :hospitalName) + AND ((:prescriptionDate IS NULL AND m.prescriptionDate IS NULL) OR m.prescriptionDate = :prescriptionDate) + AND m.isActive = true + ORDER BY m.createdAt ASC + """) + List findByGroup(@Param("seniorId") Long seniorId, + @Param("hospitalName") String hospitalName, + @Param("prescriptionDate") LocalDate prescriptionDate); } From b56a58e9a8916f4838eced4021c43c265dfa4553 Mon Sep 17 00:00:00 2001 From: kangcheolung Date: Thu, 9 Jul 2026 16:17:08 +0900 Subject: [PATCH 3/6] =?UTF-8?q?refactor:=20toDetailResponse=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0,=20toGroupItemResponse=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../converter/MedicationConverter.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/piuda/callcare/domain/medication/converter/MedicationConverter.java b/src/main/java/com/piuda/callcare/domain/medication/converter/MedicationConverter.java index 7b70b87..5319793 100644 --- a/src/main/java/com/piuda/callcare/domain/medication/converter/MedicationConverter.java +++ b/src/main/java/com/piuda/callcare/domain/medication/converter/MedicationConverter.java @@ -1,7 +1,6 @@ package com.piuda.callcare.domain.medication.converter; -import com.piuda.callcare.domain.druginfo.entity.DrugInfo; -import com.piuda.callcare.domain.medication.dto.response.MedicationDetailResponse; +import com.piuda.callcare.domain.medication.dto.response.MedicationGroupItemResponse; import com.piuda.callcare.domain.medication.dto.response.MedicationResponse; import com.piuda.callcare.domain.medication.entity.Medication; import com.piuda.callcare.domain.medication.entity.MedicationSchedule; @@ -13,18 +12,19 @@ @Component public class MedicationConverter { - // Medication → MedicationDetailResponse (약 상세 조회용, DrugInfo 없으면 전 필드 null) - public MedicationDetailResponse toDetailResponse(Medication medication) { - DrugInfo drugInfo = medication.getDrugInfo(); - if (drugInfo == null) { - return new MedicationDetailResponse(medication.getDrugName(), null, null, null, null); - } - return new MedicationDetailResponse( + // Medication → MedicationGroupItemResponse (약물노트 그룹 상세 조회용) + public MedicationGroupItemResponse toGroupItemResponse(Medication medication) { + return new MedicationGroupItemResponse( + medication.getId(), medication.getDrugName(), - drugInfo.getEfcyQesitm(), - drugInfo.getUseMethodQesitm(), - drugInfo.getAtpnQesitm(), - drugInfo.getSeQesitm() + medication.getDrugType(), + medication.getImageUrl(), + medication.getTimesPerDay(), + medication.getDosagePerTime(), + medication.getStartDate(), + medication.getEndDate(), + medication.getTotalDays(), + medication.getMemo() ); } From ab374a6058049f0eaae79e1a2eade6c8b63b4c3c Mon Sep 17 00:00:00 2001 From: kangcheolung Date: Thu, 9 Jul 2026 16:17:15 +0900 Subject: [PATCH 4/6] =?UTF-8?q?refactor:=20getDetail=20=EC=A0=9C=EA=B1=B0,?= =?UTF-8?q?=20getGroup=EC=9C=BC=EB=A1=9C=20=EA=B5=90=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 병원명 + 처방일 기준 그룹 내 약 리스트 조회, userId 소유권 검증 포함 Co-Authored-By: Claude Sonnet 4.6 --- .../service/query/MedicationQueryService.java | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/piuda/callcare/domain/medication/service/query/MedicationQueryService.java b/src/main/java/com/piuda/callcare/domain/medication/service/query/MedicationQueryService.java index 9ed22d0..023f2a3 100644 --- a/src/main/java/com/piuda/callcare/domain/medication/service/query/MedicationQueryService.java +++ b/src/main/java/com/piuda/callcare/domain/medication/service/query/MedicationQueryService.java @@ -1,29 +1,36 @@ package com.piuda.callcare.domain.medication.service.query; import com.piuda.callcare.domain.medication.converter.MedicationConverter; -import com.piuda.callcare.domain.medication.dto.response.MedicationDetailResponse; +import com.piuda.callcare.domain.medication.dto.response.MedicationGroupItemResponse; import com.piuda.callcare.domain.medication.entity.Medication; import com.piuda.callcare.domain.medication.repository.MedicationRepository; +import com.piuda.callcare.domain.senior.repository.SeniorRepository; import com.piuda.callcare.global.exception.CallCareException; import com.piuda.callcare.global.exception.ErrorCode; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDate; +import java.util.List; + @Service @Transactional(readOnly = true) @RequiredArgsConstructor public class MedicationQueryService { private final MedicationRepository medicationRepository; + private final SeniorRepository seniorRepository; private final MedicationConverter medicationConverter; - public MedicationDetailResponse getDetail(Long userId, Long medicationId) { - Medication medication = medicationRepository.findById(medicationId) - .orElseThrow(() -> new CallCareException(ErrorCode.MEDICATION_NOT_FOUND)); - if (userId != null && !medication.getSenior().getUser().getId().equals(userId)) { - throw new CallCareException(ErrorCode.FORBIDDEN); + public List getGroup(Long userId, Long seniorId, String hospitalName, LocalDate prescriptionDate) { + if (userId != null) { + seniorRepository.findByIdAndUser_Id(seniorId, userId) + .orElseThrow(() -> new CallCareException(ErrorCode.SENIOR_NOT_FOUND)); } - return medicationConverter.toDetailResponse(medication); + List medications = medicationRepository.findByGroup(seniorId, hospitalName, prescriptionDate); + return medications.stream() + .map(medicationConverter::toGroupItemResponse) + .toList(); } } From f0af12457dcd186b58866adfbd76afa42da649ee Mon Sep 17 00:00:00 2001 From: kangcheolung Date: Thu, 9 Jul 2026 16:17:24 +0900 Subject: [PATCH 5/6] =?UTF-8?q?refactor:=20GET=20/detail=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0,=20GET=20/group=20=EC=97=94=EB=93=9C=ED=8F=AC?= =?UTF-8?q?=EC=9D=B8=ED=8A=B8=EB=A1=9C=20=EA=B5=90=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../controller/MedicationController.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/piuda/callcare/domain/medication/controller/MedicationController.java b/src/main/java/com/piuda/callcare/domain/medication/controller/MedicationController.java index 422a668..96eb833 100644 --- a/src/main/java/com/piuda/callcare/domain/medication/controller/MedicationController.java +++ b/src/main/java/com/piuda/callcare/domain/medication/controller/MedicationController.java @@ -1,7 +1,7 @@ package com.piuda.callcare.domain.medication.controller; import com.piuda.callcare.domain.medication.dto.request.MedicationCreateRequest; -import com.piuda.callcare.domain.medication.dto.response.MedicationDetailResponse; +import com.piuda.callcare.domain.medication.dto.response.MedicationGroupItemResponse; import com.piuda.callcare.domain.medication.dto.response.MedicationResponse; import com.piuda.callcare.domain.medication.service.command.MedicationCommandService; import com.piuda.callcare.domain.medication.service.query.MedicationQueryService; @@ -11,10 +11,12 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; +import java.time.LocalDate; import java.util.List; @Tag(name = "Medication", description = "약 등록 API") @@ -35,12 +37,14 @@ public ResponseEntity>> registerBatch( return ResponseUtils.created(medicationCommandService.registerBatch(userId, requests)); } - @Operation(summary = "약 상세 정보 조회", description = "약 카드 클릭 시 주의사항/부작용/용법·용량/효능·효과를 반환합니다. DrugInfo 미연결 약은 의약품 정보 필드 null로 반환됩니다.") - @GetMapping("/{medicationId}/detail") - public ResponseEntity> getDetail( + @Operation(summary = "약물노트 그룹 상세 조회", description = "병원+처방일 그룹 카드 클릭 시 해당 그룹의 약 리스트와 각 약의 메모를 반환합니다. hospitalName/prescriptionDate 미전달 시 null 그룹 조회.") + @GetMapping("/group") + public ResponseEntity>> getGroup( @AuthenticationPrincipal Long userId, - @PathVariable Long medicationId + @RequestParam Long seniorId, + @RequestParam(required = false) String hospitalName, + @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate prescriptionDate ) { - return ResponseUtils.ok(medicationQueryService.getDetail(userId, medicationId)); + return ResponseUtils.ok(medicationQueryService.getGroup(userId, seniorId, hospitalName, prescriptionDate)); } } From af55d56d229d9f937255f737e275513402b937aa Mon Sep 17 00:00:00 2001 From: kangcheolung Date: Thu, 9 Jul 2026 16:32:14 +0900 Subject: [PATCH 6/6] =?UTF-8?q?fix:=20getGroup=20userId=20null=20=EC=8B=9C?= =?UTF-8?q?=20FORBIDDEN=20=EC=98=88=EC=99=B8=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 인증 없는 요청으로 타인 약물 데이터 조회 방지 Co-Authored-By: Claude Sonnet 4.6 --- .../medication/service/query/MedicationQueryService.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/piuda/callcare/domain/medication/service/query/MedicationQueryService.java b/src/main/java/com/piuda/callcare/domain/medication/service/query/MedicationQueryService.java index 023f2a3..7bebaf0 100644 --- a/src/main/java/com/piuda/callcare/domain/medication/service/query/MedicationQueryService.java +++ b/src/main/java/com/piuda/callcare/domain/medication/service/query/MedicationQueryService.java @@ -24,10 +24,11 @@ public class MedicationQueryService { private final MedicationConverter medicationConverter; public List getGroup(Long userId, Long seniorId, String hospitalName, LocalDate prescriptionDate) { - if (userId != null) { - seniorRepository.findByIdAndUser_Id(seniorId, userId) - .orElseThrow(() -> new CallCareException(ErrorCode.SENIOR_NOT_FOUND)); + if (userId == null) { + throw new CallCareException(ErrorCode.FORBIDDEN); } + seniorRepository.findByIdAndUser_Id(seniorId, userId) + .orElseThrow(() -> new CallCareException(ErrorCode.SENIOR_NOT_FOUND)); List medications = medicationRepository.findByGroup(seniorId, hospitalName, prescriptionDate); return medications.stream() .map(medicationConverter::toGroupItemResponse)