Skip to content

[Feat] 약물노트 조회/검색/수정/삭제 기능 구현 - #60

Merged
kangcheolung merged 8 commits into
developfrom
feature/59
Jul 9, 2026
Merged

kangcheolung merged 8 commits into
developfrom
feature/59

Conversation

@kangcheolung

@kangcheolung kangcheolung commented Jul 9, 2026 •

Copy link
Copy Markdown
Member

🔍️ 작업 내용

✨ 상세 설명

약물노트 목록 조회 — GET /api/medications/notes

  • 시니어의 등록 약 전체(활성/비활성 모두)를 startDate + hospitalName 기준으로 그룹화하여 반환
  • 비활성 약도 리스트에 포함시켜, 프론트에서 isActive 값으로 "복용중" 뱃지 / "약물 재등록" 버튼을 구분 노출할 수 있도록 함

약물노트 검색 — GET /api/medications/notes/search

  • 약 이름/약 별명/병원명 키워드 검색 (LIKE, 대소문자 무시)
  • 기간 필터 지원 (period: 1w/1m/3m/1y, 기본값 1y)
  • 검색 결과도 동일하게 startDate+병원 기준 그룹화

약 수정 — PATCH /api/medications/{medicationId}

  • 소유권 검증 후, null이 아닌 필드만 부분 수정 (dirty checking)
  • startDate/totalDays 변경 시 endDate 자동 재계산
  • timesPerDay 변경 시 기존 스케줄 삭제 후 재생성

약 삭제 — DELETE /api/medications/{medicationId}

  • Figma 플로우("삭제한 데이터는 복구 불가능")에 맞춰 소프트 삭제가 아닌 하드 삭제로 구현
  • 연결된 MedicationSchedule 먼저 삭제 후 Medication 완전 삭제

변경 파일

  • Medication 엔티티 — update() 메서드 추가
  • MedicationUpdateRequest, MedicationNoteGroupResponse, MedicationNoteItemResponse — DTO 신규
  • MedicationConverter — toNoteItemResponse 추가
  • MedicationRepository — findAllBySeniorId(활성/비활성 전체 조회), searchByKeyword 수정(isActive 조건 제거)
  • MedicationScheduleRepository — 스케줄 삭제 메서드 활용
  • MedicationCommandService — update, delete 추가
  • MedicationQueryService — getNoteList, searchNotes 추가
  • MedicationController — 4개 엔드포인트 추가

🛠️ 추후 리팩토링 및 고도화 계획

  • OCR 처방일(prescriptionDate) 파싱 기능 추가 시, 그룹화 기준을 startDate → prescriptionDate ?? startDate로 전환 검토
  • 복용 기간 만료 시 자동으로 isActive = false 처리하는 배치/스케줄러 로직 (현재 deactivate() 메서드는 준비만 되어 있고 호출부 없음)
  • 약 재등록 원클릭 기능 구현 시 현재 구조(비활성 약 조회 가능) 그대로 활용 가능

📸 스크린샷 (선택)

💬 리뷰 요구사항

  • 삭제를 소프트 삭제가 아닌 하드 삭제로 결정한 부분 — Figma 플로우 근거로 판단했는데 이견 있으면 의견 부탁
  • findAllBySeniorId에서 isActive 필터를 뺀 것이 다른 기능(예: 리포트, 홈카드)에 영향 없는지 확인 필요

Summary by CodeRabbit

  • 새 기능

    • 약물 노트 목록 조회 및 검색 기능이 추가되었습니다.
    • 약 정보 수정 및 삭제 기능이 추가되었습니다.
    • 약물 노트가 날짜와 병원명 기준으로 묶여 보여집니다.
  • 버그 수정

    • 수정 시 일부 항목만 입력하면 해당 항목만 반영되도록 개선되었습니다.
    • 복용 횟수 변경 시 일정이 자동으로 다시 생성되도록 처리되었습니다.
    • 삭제 시 관련 일정도 함께 정리되도록 변경되었습니다.

kangcheolung and others added 7 commits July 9, 2026 23:00
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
MedicationUpdateRequest, MedicationNoteGroupResponse, MedicationNoteItemResponse 추가
MedicationNoteItemResponse에 isActive 포함 — 프론트 재등록 버튼 노출 판단용

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
findAllBySeniorId — 활성/비활성 전체 조회 (isActive 조건 제거)
searchByKeyword — 약 이름/별명/병원명 키워드 + 기간 필터
deleteAllByMedication_Id — 약 삭제 시 스케줄 일괄 제거용

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
update — null 필드 유지, timesPerDay 변경 시 스케줄 재생성, endDate 자동 재계산
delete — 스케줄 먼저 삭제 후 Medication 하드 삭제 (Figma 스펙 기준 복구 불가)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
getNoteList — 전체 약 startDate+병원 기준 그룹화 반환
searchNotes — 키워드 + 기간 필터(1w/1m/3m/1y) 검색

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GET  /api/medications/notes
GET  /api/medications/notes/search
PATCH  /api/medications/{medicationId}
DELETE /api/medications/{medicationId}

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 9, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@kangcheolung, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 52 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 9cfd7de2-2384-41d6-96db-f0e77ae604f6

📥 Commits

Reviewing files that changed from the base of the PR and between 394158e and 0abff88.

📒 Files selected for processing (4)
  • src/main/java/com/piuda/callcare/domain/medication/controller/MedicationController.java
  • src/main/java/com/piuda/callcare/domain/medication/dto/request/MedicationUpdateRequest.java
  • src/main/java/com/piuda/callcare/domain/medication/service/command/MedicationCommandService.java
  • src/main/java/com/piuda/callcare/domain/medication/service/query/MedicationQueryService.java
📝 Walkthrough

Walkthrough

약물노트 목록/검색 조회, 약 정보 수정, 약 삭제 기능이 추가되었습니다. MedicationController에 신규 엔드포인트 4개가 추가되고, MedicationQueryService와 MedicationCommandService에 각각 조회/그룹화 로직과 수정/삭제 로직이 구현되었으며, 관련 DTO·저장소 쿼리·엔티티 업데이트 메서드가 함께 추가되었습니다.

Changes

약물노트 API 구현

Layer / File(s) Summary
약물노트 응답 DTO 정의
dto/response/MedicationNoteGroupResponse.java, dto/response/MedicationNoteItemResponse.java
처방일/병원 기준 그룹 카드 응답과 개별 약 항목 응답을 위한 record DTO를 Swagger @Schema 설명과 함께 신규 정의함.
변환 로직 추가
converter/MedicationConverter.java
Medication을 MedicationNoteItemResponse로 변환하는 toNoteItemResponse 메서드를 추가함.
저장소 조회 쿼리
repository/MedicationRepository.java
시니어 ID 기준 전체 약물 조회(findAllBySeniorId)와 키워드+시작일 필터 검색(searchByKeyword) 쿼리를 startDate 내림차순/hospitalName 오름차순(NULLS LAST) 정렬로 추가함.
조회/검색 서비스 로직
service/query/MedicationQueryService.java
getNoteList, searchNotes를 추가해 시니어 검증 후 저장소 조회 결과를 (startDate|hospitalName) 키로 그룹화하고, resolveFromDate로 기간(1w/1m/3m/기본 1y) 기준 날짜를 계산함.
수정 요청 계약 및 엔티티 갱신
dto/request/MedicationUpdateRequest.java, entity/Medication.java
약 수정 요청 record DTO를 정의하고, Medication.update(...)에서 null이 아닌 필드만 조건부로 갱신하도록 구현함.
수정/삭제 커맨드 서비스 및 스케줄 삭제
repository/MedicationScheduleRepository.java, service/command/MedicationCommandService.java
deleteAllByMedication_Id 파생 삭제 메서드를 추가하고, MedicationCommandService.update/delete에서 소유권 검증, endDate 재계산, 스케줄 삭제 및 재생성을 처리함.
컨트롤러 엔드포인트
controller/MedicationController.java
GET /notes, GET /notes/search, PATCH /{medicationId}, DELETE /{medicationId} 엔드포인트를 추가해 각각 Query/Command 서비스로 위임함.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant MedicationController
  participant MedicationQueryService
  participant MedicationRepository
  participant MedicationConverter

  Client->>MedicationController: GET /api/medications/notes/search?keyword&period
  MedicationController->>MedicationQueryService: searchNotes(userId, seniorId, keyword, period)
  MedicationQueryService->>MedicationQueryService: resolveFromDate(period)
  MedicationQueryService->>MedicationRepository: searchByKeyword(seniorId, keyword, fromDate)
  MedicationRepository-->>MedicationQueryService: List<Medication>
  MedicationQueryService->>MedicationConverter: toNoteItemResponse(각 Medication)
  MedicationQueryService-->>MedicationController: List<MedicationNoteGroupResponse>
  MedicationController-->>Client: ok(응답)
Loading
sequenceDiagram
  participant Client
  participant MedicationController
  participant MedicationCommandService
  participant MedicationRepository
  participant MedicationScheduleRepository

  Client->>MedicationController: DELETE /api/medications/{medicationId}
  MedicationController->>MedicationCommandService: delete(userId, medicationId)
  MedicationCommandService->>MedicationRepository: findById + 소유권 검증
  MedicationCommandService->>MedicationScheduleRepository: deleteAllByMedication_Id(medicationId)
  MedicationCommandService->>MedicationRepository: 약 엔티티 삭제
  MedicationCommandService-->>MedicationController: void
  MedicationController-->>Client: noContent
Loading

Possibly related PRs

  • PIUDAProject/Backend#46: MedicationController와 MedicationCommandService에 약 등록(배치) 기능을 추가하며 동일한 약 도메인 클래스를 확장함.
  • PIUDAProject/Backend#51: Medication.hospitalName 필드를 다루는 리팩터링으로, 본 PR의 그룹화/수정 로직이 사용하는 필드와 직접 관련됨.

Suggested labels: ✨ Feature

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning 조회/검색/수정/삭제는 구현됐지만 최근 검색어 저장·조회와 동일 병원 그룹 단위 수정 요구가 누락되었습니다. 최근 검색어 저장/조회(최대 5개)와 동일 병원 그룹 단위 수정 API/로직을 추가하고 Swagger 반영 범위를 재점검하세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 63.16% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목이 약물노트의 조회/검색/수정/삭제 구현이라는 핵심 변경을 정확히 요약합니다.
Out of Scope Changes check ✅ Passed 변경사항이 약물노트 관련 API, DTO, 엔티티, 저장소, 서비스 범위에 한정되어 있습니다.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/59

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

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/main/java/com/piuda/callcare/domain/medication/controller/MedicationController.java`:
- Around line 73-82: Add validation to the MedicationController update endpoint
by annotating the MedicationUpdateRequest parameter in update() with `@Valid`,
matching the existing registerBatch() pattern. This ensures Bean Validation on
non-null PATCH fields is applied before medicationCommandService.update(userId,
medicationId, request) runs, while keeping the controller’s request handling
consistent.

In
`@src/main/java/com/piuda/callcare/domain/medication/dto/request/MedicationUpdateRequest.java`:
- Around line 17-20: `MedicationUpdateRequest`의 `timesPerDay`와 `totalDays`는
null만 허용하고 0 같은 무효값은 막아야 합니다. 해당 DTO 필드에 최소값 검증 어노테이션(`@Min(1)` 또는 `@Positive`)을
추가해 `null`은 유지하되 1 미만 값이 통과하지 않도록 수정하세요. `timesPerDay`, `totalDays` 선언부를 중심으로
검토하고, 다른 update request DTO에도 동일한 패턴이 있는지 함께 확인하세요.

In
`@src/main/java/com/piuda/callcare/domain/medication/service/command/MedicationCommandService.java`:
- Around line 122-125: `MedicationCommandService`의 날짜 계산 로직에서
`request.startDate()`가 없을 때 `medication.getStartDate()`가 null이면
`effectiveStart.plusDays(...)`에서 NPE가 발생합니다. `updateMedication`(해당 계산 블록)에서
`effectiveStart`를 사용하기 전에 null 가드를 추가하고, `request.totalDays()`만 들어온 경우에도
`medication.getStartDate()`가 없으면 안전하게 처리하거나 명시적으로 예외를 반환하도록 수정하세요.
`effectiveStart`, `effectiveDays`, `newEndDate` 계산 순서를 점검해 null인 경우를 먼저 방어하면
됩니다.

In
`@src/main/java/com/piuda/callcare/domain/medication/service/query/MedicationQueryService.java`:
- Around line 80-88: `MedicationQueryService.resolveFromDate` is treating
`period` case-sensitively, so uppercase inputs like "1W" fall through to the
default path. Normalize the incoming `period` to lowercase before the switch
(while still handling null safely) so `1w`, `1m`, and `3m` are matched
consistently and only truly unknown values use the default branch.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 57228a13-0502-4c28-b147-6e190df374df

📥 Commits

Reviewing files that changed from the base of the PR and between 3251ecb and 394158e.

📒 Files selected for processing (10)
  • src/main/java/com/piuda/callcare/domain/medication/controller/MedicationController.java
  • src/main/java/com/piuda/callcare/domain/medication/converter/MedicationConverter.java
  • src/main/java/com/piuda/callcare/domain/medication/dto/request/MedicationUpdateRequest.java
  • src/main/java/com/piuda/callcare/domain/medication/dto/response/MedicationNoteGroupResponse.java
  • src/main/java/com/piuda/callcare/domain/medication/dto/response/MedicationNoteItemResponse.java
  • src/main/java/com/piuda/callcare/domain/medication/entity/Medication.java
  • src/main/java/com/piuda/callcare/domain/medication/repository/MedicationRepository.java
  • src/main/java/com/piuda/callcare/domain/medication/repository/MedicationScheduleRepository.java
  • src/main/java/com/piuda/callcare/domain/medication/service/command/MedicationCommandService.java
  • src/main/java/com/piuda/callcare/domain/medication/service/query/MedicationQueryService.java

- update 엔드포인트에 @Valid 추가
- MedicationUpdateRequest timesPerDay/totalDays에 @min(1) 추가
- effectiveStart null 가드 추가로 NPE 방지
- resolveFromDate period 소문자 정규화

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@kangcheolung
kangcheolung merged commit 7d00944 into develop Jul 9, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] 약물노트 조회/검색/수정/삭제 API 구현

1 participant