Skip to content

feat: 건강 기록(통증부위, 운동시간) 작성, 조회 로직 구현 & 온기 조회 API 리팩토링 #22

Merged
oxomi merged 5 commits intomainfrom
refactor/ongi
Jul 17, 2025
Merged

feat: 건강 기록(통증부위, 운동시간) 작성, 조회 로직 구현 & 온기 조회 API 리팩토링 #22
oxomi merged 5 commits intomainfrom
refactor/ongi

Conversation

@oxomi
Copy link
Copy Markdown
Collaborator

@oxomi oxomi commented Jul 16, 2025

건강 기록 조회 로직 : 최근 일주일간의 기록을 조회하도록 수정 예정

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jul 16, 2025

Walkthrough

이번 변경사항은 건강 기록(통증 및 운동) 관련 신규 API와 엔티티, DTO, 서비스, 레포지토리 계층을 도입하고, 온도(Temperature) 기능의 API 및 서비스 구조를 가족 단위 집계 중심으로 대폭 리팩토링했습니다. 또한, IDE 및 Gradle 관련 설정 파일들이 새로 추가되었으며, 기존 온도 DTO와 테스트 코드도 새로운 구조에 맞게 수정 또는 삭제되었습니다.

Changes

파일/경로 그룹 변경 요약
.idea/... IntelliJ 프로젝트/모듈/Gradle/JAR/VCS/UI Designer 등 IDE 설정 파일 신규 추가
backend/ongi/gradle/wrapper/gradle-wrapper.properties
backend/ongi/gradlew
backend/ongi/gradlew.bat
Gradle 버전 8.14.2 → 8.5로 변경, Wrapper 스크립트 내부 경로 및 실행 방식 개선
backend/ongi/src/main/java/ongi/health/controller/HealthRecordController.java 건강 기록(통증/운동) 신규 REST 컨트롤러 추가
backend/ongi/src/main/java/ongi/health/dto/ExerciseRecordWithDiffResponse.java
backend/ongi/src/main/java/ongi/health/dto/PainRecordResponse.java
건강 기록 관련 응답 DTO 신규 추가
backend/ongi/src/main/java/ongi/health/entity/ExerciseRecord.java
backend/ongi/src/main/java/ongi/health/entity/PainRecord.java
건강 기록(운동/통증) JPA 엔티티 신규 추가 및 관련 enum 정의
backend/ongi/src/main/java/ongi/health/repository/ExerciseRecordRepository.java
backend/ongi/src/main/java/ongi/health/repository/PainRecordRepository.java
건강 기록용 JPA Repository 신규 추가
backend/ongi/src/main/java/ongi/health/service/HealthRecordService.java 건강 기록 서비스 신규 추가, 기록 등록 및 조회/차이 계산 기능 구현
backend/ongi/src/main/java/ongi/temperature/controller/TemperatureController.java 온도 컨트롤러: 엔드포인트 구조 변경(가족 중심), 기존 상세 조회 API 제거, 신규 집계 API 추가
backend/ongi/src/main/java/ongi/temperature/dto/FamilyTemperatureContributionResponse.java
backend/ongi/src/main/java/ongi/temperature/dto/FamilyTemperatureDailyResponse.java
가족 온도 집계용 신규 DTO 추가
backend/ongi/src/main/java/ongi/temperature/dto/FamilyTemperatureResponse.java 불필요한 공백 제거(실질적 로직 변경 없음)
backend/ongi/src/main/java/ongi/temperature/dto/MemberTemperatureResponse.java 멤버별 온도 상세 DTO 전체 삭제
backend/ongi/src/main/java/ongi/temperature/entity/Temperature.java activity 필드 삭제
backend/ongi/src/main/java/ongi/temperature/repository/TemperatureRepository.java 가족/멤버별 온도 상세 쿼리 제거, 최근 5일간 가족별/멤버별 집계용 쿼리 추가
backend/ongi/src/main/java/ongi/temperature/service/TemperatureService.java 온도 서비스: 멤버별 상세 조회 제거, 가족 집계/일별/기여도 API로 변경
backend/ongi/src/test/java/ongi/TemperatureControllerUnitTest.java MockMvc 기반 테스트 제거, 컨트롤러 직접 호출 및 DTO 단위 검증 방식으로 리팩토링, 신규 API 테스트 추가

Sequence Diagram(s)

sequenceDiagram
actor User
participant HealthRecordController
participant HealthRecordService
participant PainRecordRepository
participant ExerciseRecordRepository

User->>HealthRecordController: POST /health/pain (date, area, level)
HealthRecordController->>HealthRecordService: addPainRecord(parentId, date, area, level)
HealthRecordService->>PainRecordRepository: save()
PainRecordRepository-->>HealthRecordService: PainRecord
HealthRecordService-->>HealthRecordController: PainRecord
HealthRecordController-->>User: PainRecordResponse

User->>HealthRecordController: POST /health/exercise (date, duration)
HealthRecordController->>HealthRecordService: addExerciseRecord(parentId, date, duration)
HealthRecordService->>ExerciseRecordRepository: save()
ExerciseRecordRepository-->>HealthRecordService: ExerciseRecord
HealthRecordService-->>HealthRecordController: ExerciseRecord
HealthRecordController-->>User: ExerciseRecordWithDiffResponse

User->>HealthRecordController: GET /health/parents/pain (parentId, date)
HealthRecordController->>HealthRecordService: getPainRecords(parentId, date)
HealthRecordService->>PainRecordRepository: findByParentIdAndDate()
PainRecordRepository-->>HealthRecordService: List<PainRecord>
HealthRecordService-->>HealthRecordController: List<PainRecord>
HealthRecordController-->>User: List<PainRecordResponse>
Loading
sequenceDiagram
actor User
participant TemperatureController
participant TemperatureService
participant TemperatureRepository
participant FamilyRepository
participant UserRepository

User->>TemperatureController: GET /temperature/summary?familyId=...
TemperatureController->>TemperatureService: getFamilyTemperatureSummary(familyId)
TemperatureService->>FamilyRepository: findById()
FamilyRepository-->>TemperatureService: Family
TemperatureService->>TemperatureRepository: findByFamilyId()
TemperatureRepository-->>TemperatureService: List<Temperature>
TemperatureService->>UserRepository: findAllById()
UserRepository-->>TemperatureService: List<User>
TemperatureService-->>TemperatureController: FamilyTemperatureResponse
TemperatureController-->>User: FamilyTemperatureResponse

User->>TemperatureController: GET /temperature/daily?familyId=...
TemperatureController->>TemperatureService: getFamilyTemperatureDaily(familyId)
TemperatureService->>FamilyRepository: findById()
FamilyRepository-->>TemperatureService: Family
TemperatureService->>TemperatureRepository: getFamilyTemperatureDaily()
TemperatureRepository-->>TemperatureService: List<DailyTemperature>
TemperatureService-->>TemperatureController: FamilyTemperatureDailyResponse
TemperatureController-->>User: FamilyTemperatureDailyResponse
Loading

Poem

🐰
새로운 건강 기록이 쏙쏙,
가족 온도도 한눈에 쏙!
DTO와 엔티티, 서비스도
토끼처럼 깡총깡총 뛰었죠.
테스트도 새로 단장했으니
깔끔한 코드밭에서
오늘도 행복한 개발을!

( ˘ ³˘)ノ 🥕

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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 for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in 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 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 for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 14

♻️ Duplicate comments (2)
backend/ongi/src/main/java/ongi/temperature/controller/TemperatureController.java (2)

24-27: familyId 파라미터 검증 누락

위와 동일한 검증 문제가 있습니다.


30-33: familyId 파라미터 검증 누락

위와 동일한 검증 문제가 있습니다.

🧹 Nitpick comments (21)
.idea/vcs.xml (1)

1-6: IDE 설정 파일은 저장소에서 제외하는 것을 권장합니다
.idea 디렉터리는 개발자 또는 CI 환경마다 달라지는 사용자·환경 의존 설정을 포함하므로 버전 관리 대상이 아니어도 됩니다. 팀 간 충돌·불필요한 diff 발생을 막기 위해 .gitignore 에 추가하여 커밋을 피하는 방안을 고려해주세요.

+# IntelliJ IDEA
+.idea/
.idea/jarRepositories.xml (1)

1-20: IDE 전용 jarRepositories.xml 커밋 여부 재검토
원격 Maven repository 설정은 Gradle repositories {} 블록으로 통일 관리하는 편이 IDE 의존성을 줄이고, 빌드 도구 및 CLI 환경과의 일관성을 보장합니다. IDE 설정 파일을 커밋하지 않도록 .idea/ 전체를 ignore 하는 것을 다시 한 번 고려해 주세요.

.idea/uiDesigner.xml (1)

1-124: UI Designer 팔레트 설정 파일도 공유 필요성이 낮습니다
Swing GUI 빌드용 팔레트 정의는 일반적으로 개인 개발 환경에 국한됩니다.
공유가 불가피한 합의가 없다면, 이 파일 역시 저장소에서 제외하여 PR 변경량을 최소화하는 것이 좋습니다.

.idea/misc.xml (1)

1-10: 프로젝트 출력 디렉터리 등 IDE 내부 설정은 .idea 커밋 시 발생할 수 있는 충돌 주의
특히 FrameworkDetectionExcludesConfiguration 등은 사용자 별로 달라질 가능성이 높아 merge conflict 원인이 됩니다. 팀 규칙에 따라 IDE 설정을 버전 관리할지 재확인해 주세요.

.idea/modules.xml (1)

1-9: modules.xml 커밋 시 모듈 경로 충돌 가능성
개발자마다 경로 구조가 다를 수 있어, 이 파일을 공유하면 인텔리제이에서 모듈 경로 오류가 발생할 수 있습니다. Gradle settings.gradle (or settings.gradle.kts) 기준으로 모듈을 관리하면 IDE가 자동 동기화할 수 있으니, 저장소 포함 여부를 재검토하세요.

.idea/PNUSW-2025-OnGi-10.iml (1)

1-8: IDE 전용 설정 파일은 VCS에 포함하지 않는 것을 권장합니다

.iml 파일은 개발자 로컬 IDE 환경에 강하게 결합되어 있어 팀 간 불필요한 충돌을 유발하거나 CI 서버에 불필요한 메타데이터를 노출할 수 있습니다. 가능하면 루트 .gitignore에 추가해 VCS 추적 대상에서 제외해주세요.

.idea/compiler.xml (1)

7-9: 사용자 절대 경로가 하드코딩되어 있습니다

$USER_HOME$/.gradle/.../lombok-1.18.38.jar 경로는 각 개발자 PC마다 달라질 수 있습니다. IDE가 자동 생성하므로 VCS에 굳이 올릴 필요가 없으며, 커밋할 경우 다른 개발자 환경에서 경로 오류가 발생할 수 있습니다.

.idea/gradle.xml (1)

7-15: Gradle JVM 설정 값이 고정-경로 및 개인 설정에 의존합니다

gradleJvm="temurin-17" 과 같은 IDE-특화 설정은 팀원마다 상이할 수 있으며, VCS에 포함되면 충돌과 불필요한 변경 내역이 지속적으로 발생합니다. .idea 디렉터리 전체를 무시하거나, 공유가 꼭 필요하다면 gradle.properties 등 표준 Gradle 설정으로 옮기는 것을 권장합니다.

backend/ongi/src/main/java/ongi/temperature/entity/Temperature.java (1)

21-24: 클래스 선언 포맷팅 개선 필요

클래스 선언 부분의 포맷팅이 비정상적입니다. 가독성을 위해 표준적인 형태로 수정하는 것이 좋겠습니다.

다음과 같이 수정하세요:

-public class
-
-
-Temperature {
+public class Temperature {
backend/ongi/src/main/java/ongi/temperature/dto/FamilyTemperatureDailyResponse.java (1)

8-19: DTO 일관성을 위한 어노테이션 추가 권장

다른 DTO 클래스들(FamilyTemperatureResponse)과 일관성을 위해 @Builder@NoArgsConstructor 어노테이션 추가를 고려해보세요. 이는 향후 유연성을 제공할 수 있습니다.

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

 @Getter
+@Builder
+@NoArgsConstructor
 @AllArgsConstructor
 public class FamilyTemperatureDailyResponse {
     private List<DailyTemperature> dailyTemperatures;

     @Getter
+    @Builder
+    @NoArgsConstructor
     @AllArgsConstructor
     public static class DailyTemperature {
         private LocalDate date;
         private Double totalTemperature;
     }
 }
backend/ongi/src/main/java/ongi/temperature/dto/FamilyTemperatureContributionResponse.java (1)

9-21: DTO 일관성을 위한 어노테이션 추가 권장

FamilyTemperatureResponse와 일관성을 위해 @Builder@NoArgsConstructor 어노테이션 추가를 고려해보세요.

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

 @Getter
+@Builder
+@NoArgsConstructor
 @AllArgsConstructor
 public class FamilyTemperatureContributionResponse {
     private List<Contribution> contributions;

     @Getter
+    @Builder
+    @NoArgsConstructor
     @AllArgsConstructor
     public static class Contribution {
         private LocalDate date;
         private UUID userId;
         private Double contributed;
     }
 }
backend/ongi/src/test/java/ongi/TemperatureControllerUnitTest.java (1)

23-23: 불필요한 @activeprofiles 어노테이션

순수 단위 테스트에서는 @ActiveProfiles가 필요하지 않습니다. 이는 주로 Spring 컨텍스트가 필요한 통합 테스트에서 사용됩니다.

Mock을 사용하는 단위 테스트이므로 이 어노테이션을 제거하세요:

-@ActiveProfiles("test")
 class TemperatureControllerUnitTest {
backend/ongi/src/main/java/ongi/temperature/service/TemperatureService.java (3)

54-55: 불필요한 ArrayList 생성

userTemperatures.keySet()을 새로운 ArrayList로 변환할 필요가 없습니다.

다음과 같이 최적화하세요:

-List<UUID> userIds = new ArrayList<>(userTemperatures.keySet());
-Map<UUID, User> users = userRepository.findAllById(userIds).stream()
+Map<UUID, User> users = userRepository.findAllById(userTemperatures.keySet()).stream()

87-87: 매직 넘버 사용

"최근 5일"을 계산하기 위해 매직 넘버 4를 사용하고 있습니다.

상수로 정의하여 가독성과 유지보수성을 향상시키세요:

+private static final int DAYS_TO_RETRIEVE = 5;

-java.time.LocalDateTime fromDate = java.time.LocalDate.now().minusDays(4).atStartOfDay(); // 최근 5일
+java.time.LocalDateTime fromDate = java.time.LocalDate.now().minusDays(DAYS_TO_RETRIEVE - 1).atStartOfDay();

Also applies to: 96-96


105-145: 다수의 미구현 TODO 메서드

온도 증가/감소 관련 여러 메서드가 TODO로 남아있습니다. 이러한 메서드들은 시스템의 핵심 기능으로 보입니다.

이러한 TODO 항목들을 추적하기 위한 이슈를 생성하시겠습니까? 각 메서드의 구현 우선순위와 요구사항을 정리할 수 있습니다.

backend/ongi/src/main/java/ongi/health/dto/PainRecordResponse.java (1)

16-17: 열거형 문자열 표현 방식을 검토해주세요.

enum.name() 메서드는 코드에서 정의된 열거형 이름을 그대로 반환합니다. 사용자에게 표시되는 응답이라면 국제화나 사용자 친화적인 문자열을 고려해보세요.

열거형에 사용자 친화적인 문자열을 반환하는 메서드를 추가하거나, 별도의 매핑 로직을 사용하는 것을 고려해보세요.

backend/ongi/src/main/java/ongi/health/entity/ExerciseRecord.java (1)

25-26: 운동 시간 필드에 대한 유효성 검증을 고려해주세요.

주석에서 duration 값이 0, 30, 60 등의 특정 값만 허용됨을 시사하고 있습니다. 잘못된 값이 입력되지 않도록 유효성 검증을 추가하는 것을 고려해보세요.

Bean Validation을 사용하여 허용 가능한 값들을 제한할 수 있습니다:

@Column(nullable = false)
+@Min(0)
+@Max(1440) // 24시간 * 60분
private int duration; // 0, 30, 60, ...

또는 enum이나 커스텀 유효성 검증을 고려해보세요.

backend/ongi/src/main/java/ongi/health/entity/PainRecord.java (2)

19-23: 데이터 무결성을 위한 추가 검증 고려

필드에 nullable = false 설정은 좋지만, 추가적인 유효성 검증 어노테이션(@NotNull, @SiZe 등)과 데이터베이스 제약 조건을 고려해보세요.

+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.PastOrPresent;
+
 @Column(nullable = false)
+@NotNull
 private UUID parentId;

 @Column(nullable = false)
+@NotNull
+@PastOrPresent
 private LocalDate date;

33-39: Enum 값의 명명 규칙 개선 제안

Enum 값들이 의미가 명확하지만, 일부 값의 명명을 더 직관적으로 개선할 수 있습니다.

 public enum PainLevel {
-    STRONG, MID_STRONG, MID_WEAK, WEAK
+    SEVERE, MODERATE_HIGH, MODERATE_LOW, MILD
 }

또한 각 enum에 한글 설명을 추가하면 더 유용합니다:

 public enum PainArea {
-    HEAD, NECK, SHOULDER, CHEST, BACK, ARM, HAND, ABDOMEN, WAIST, LEG, KNEE, FOOT, NONE
+    HEAD("머리"), NECK("목"), SHOULDER("어깨"), CHEST("가슴"), BACK("등"), 
+    ARM("팔"), HAND("손"), ABDOMEN("복부"), WAIST("허리"), LEG("다리"), 
+    KNEE("무릎"), FOOT("발"), NONE("없음");
+    
+    private final String description;
+    
+    PainArea(String description) {
+        this.description = description;
+    }
 }
backend/ongi/src/main/java/ongi/health/service/HealthRecordService.java (1)

57-64: 데이터베이스 쿼리 최적화 고려

현재 구현에서는 동일한 parentId로 두 번의 개별 쿼리를 실행합니다. 성능 최적화를 위해 배치 조회를 고려해보세요.

 public ExerciseRecordWithDiffResponse getExerciseRecordWithDiff(UUID parentId, LocalDate date) {
-    ExerciseRecord today = exerciseRecordRepository.findByParentIdAndDate(parentId, date).orElse(null);
-    ExerciseRecord prev = exerciseRecordRepository.findByParentIdAndDate(parentId, date.minusDays(1)).orElse(null);
+    // 리포지토리에 배치 조회 메서드 추가를 고려
+    List<ExerciseRecord> records = exerciseRecordRepository.findByParentIdAndDateBetween(
+        parentId, date.minusDays(1), date);
+    
+    ExerciseRecord today = records.stream()
+        .filter(r -> r.getDate().equals(date))
+        .findFirst().orElse(null);
+    ExerciseRecord prev = records.stream()
+        .filter(r -> r.getDate().equals(date.minusDays(1)))
+        .findFirst().orElse(null);
+        
     int prevDuration = prev != null ? prev.getDuration() : 0;
     int todayDuration = today != null ? today.getDuration() : 0;
     int diff = todayDuration - prevDuration;
     return new ExerciseRecordWithDiffResponse(today, prevDuration, diff);
 }
backend/ongi/src/main/java/ongi/health/controller/HealthRecordController.java (1)

39-50: API 응답 일관성 개선

운동 기록 추가 시 diff 정보를 0으로 설정하는 것보다는 별도의 응답 DTO를 사용하는 것이 더 명확합니다.

운동 기록 추가용 별도 응답 DTO를 만들거나, 기존 DTO에 플래그를 추가하여 diff 정보의 유효성을 나타내는 것을 고려해보세요:

 ExerciseRecordWithDiffResponse response = new ExerciseRecordWithDiffResponse(
-    record.getId(), record.getDate(), record.getDuration(), 0, 0);
+    record.getId(), record.getDate(), record.getDuration(), null, null);

또는 별도의 ExerciseRecordResponse DTO를 생성하여 사용하는 것이 더 명확할 수 있습니다.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 58b3515 and 99b6fa4.

⛔ Files ignored due to path filters (1)
  • backend/ongi/gradle/wrapper/gradle-wrapper.jar is excluded by !**/*.jar
📒 Files selected for processing (29)
  • .idea/.gitignore (1 hunks)
  • .idea/PNUSW-2025-OnGi-10.iml (1 hunks)
  • .idea/compiler.xml (1 hunks)
  • .idea/gradle.xml (1 hunks)
  • .idea/jarRepositories.xml (1 hunks)
  • .idea/misc.xml (1 hunks)
  • .idea/modules.xml (1 hunks)
  • .idea/uiDesigner.xml (1 hunks)
  • .idea/vcs.xml (1 hunks)
  • backend/ongi/gradle/wrapper/gradle-wrapper.properties (1 hunks)
  • backend/ongi/gradlew (4 hunks)
  • backend/ongi/gradlew.bat (2 hunks)
  • backend/ongi/src/main/java/ongi/health/controller/HealthRecordController.java (1 hunks)
  • backend/ongi/src/main/java/ongi/health/dto/ExerciseRecordWithDiffResponse.java (1 hunks)
  • backend/ongi/src/main/java/ongi/health/dto/PainRecordResponse.java (1 hunks)
  • backend/ongi/src/main/java/ongi/health/entity/ExerciseRecord.java (1 hunks)
  • backend/ongi/src/main/java/ongi/health/entity/PainRecord.java (1 hunks)
  • backend/ongi/src/main/java/ongi/health/repository/ExerciseRecordRepository.java (1 hunks)
  • backend/ongi/src/main/java/ongi/health/repository/PainRecordRepository.java (1 hunks)
  • backend/ongi/src/main/java/ongi/health/service/HealthRecordService.java (1 hunks)
  • backend/ongi/src/main/java/ongi/temperature/controller/TemperatureController.java (1 hunks)
  • backend/ongi/src/main/java/ongi/temperature/dto/FamilyTemperatureContributionResponse.java (1 hunks)
  • backend/ongi/src/main/java/ongi/temperature/dto/FamilyTemperatureDailyResponse.java (1 hunks)
  • backend/ongi/src/main/java/ongi/temperature/dto/FamilyTemperatureResponse.java (1 hunks)
  • backend/ongi/src/main/java/ongi/temperature/dto/MemberTemperatureResponse.java (0 hunks)
  • backend/ongi/src/main/java/ongi/temperature/entity/Temperature.java (1 hunks)
  • backend/ongi/src/main/java/ongi/temperature/repository/TemperatureRepository.java (1 hunks)
  • backend/ongi/src/main/java/ongi/temperature/service/TemperatureService.java (3 hunks)
  • backend/ongi/src/test/java/ongi/TemperatureControllerUnitTest.java (3 hunks)
💤 Files with no reviewable changes (1)
  • backend/ongi/src/main/java/ongi/temperature/dto/MemberTemperatureResponse.java
🧰 Additional context used
🧬 Code Graph Analysis (3)
backend/ongi/src/main/java/ongi/temperature/dto/FamilyTemperatureDailyResponse.java (2)
backend/ongi/src/main/java/ongi/temperature/dto/FamilyTemperatureContributionResponse.java (2)
  • Getter (9-21)
  • Getter (14-20)
backend/ongi/src/main/java/ongi/temperature/dto/FamilyTemperatureResponse.java (2)
  • Getter (11-30)
  • Getter (20-29)
backend/ongi/src/main/java/ongi/health/entity/ExerciseRecord.java (1)
backend/ongi/src/main/java/ongi/health/entity/PainRecord.java (1)
  • Entity (8-40)
backend/ongi/src/main/java/ongi/temperature/dto/FamilyTemperatureContributionResponse.java (2)
backend/ongi/src/main/java/ongi/temperature/dto/FamilyTemperatureDailyResponse.java (2)
  • Getter (8-19)
  • Getter (13-18)
backend/ongi/src/main/java/ongi/temperature/dto/FamilyTemperatureResponse.java (2)
  • Getter (11-30)
  • Getter (20-29)
🔇 Additional comments (21)
.idea/.gitignore (1)

1-8: 루트 .gitignore와 중복 여부 확인 필요

이 규칙들은 유용하지만, 동일한 패턴이 이미 루트 .gitignore 에 존재한다면 중복 관리가 발생할 수 있습니다. 한 곳에서만 관리하도록 정리하면 유지보수가 수월해집니다.

.idea/gradle.xml (1)

18-22: #JAVA_HOME 토큰 사용 시 CI 환경과 일관성 확인 필요

두 번째 프로젝트 설정에서 gradleJvm 에 환경변수 토큰이 사용되고 있습니다. CI/CD 파이프라인에서도 동일한 환경변수가 정의돼 있지 않으면 빌드 실패가 발생할 수 있으니 확인 부탁드립니다.

backend/ongi/gradle/wrapper/gradle-wrapper.properties (1)

3-3: Gradle 릴리즈 노트 보안 이슈 검토 필요

기존 스크립트로 8.5→8.14.2 사이의 보안 키워드를 검색했으나, HTML 전체가 출력되어 신뢰할 수 있는 결과를 얻기 어렵습니다.
아래 스크립트로 “security|vulnerabilit|CVE” 키워드를 재검증하시고, 필요 시 Gradle 보안 고지 문서도 함께 확인해주세요.

#!/bin/bash
for version in 8.5 8.6 8.7 8.8 8.9 8.10 8.11 8.12 8.13 8.14 8.14.1 8.14.2; do
  echo "=== Gradle $version ==="
  curl -s "https://docs.gradle.org/$version/release-notes.html" \
    | grep -E -i "security|vulnerability|CVE" \
    || echo "No security entries"
done

위 검토 후에도 다운그레이드가 의도된 변경인지, 보안·호환성 리스크가 없는지 최종 확인 부탁드립니다.

backend/ongi/gradlew.bat (4)

46-50: 에러 메시지 포맷팅 개선

에러 메시지를 여러 줄로 분리하고 명시적인 stderr 리다이렉션을 제거하여 가독성을 향상시켰습니다.


60-64: 일관된 에러 메시지 포맷팅

JAVA_HOME 관련 에러 메시지도 동일한 형식으로 개선되어 일관성이 향상되었습니다.


71-71: 명시적 CLASSPATH 설정

CLASSPATH를 명시적으로 gradle-wrapper.jar로 설정하여 실행 환경을 더욱 안정적으로 만들었습니다.


75-75: Java 실행 방식 개선

-jar 옵션 대신 메인 클래스를 직접 호출하는 방식으로 변경하여 더 명확한 실행 구조를 제공합니다.

backend/ongi/gradlew (5)

58-58: Gradle 템플릿 소스 URL 업데이트

Gradle 레포지토리 내 템플릿 소스 경로가 새로운 위치로 업데이트되었습니다.


87-87: 경로 해결 방식 개선

cd -P ... && printf '%s\n' "$PWD"에서 cd ... && pwd -P로 변경하여 더 간결하고 표준적인 방식으로 절대 경로를 해결합니다.


115-115: 명시적 CLASSPATH 설정

CLASSPATH를 명시적으로 gradle-wrapper.jar로 설정하여 실행 환경의 안정성을 향상시켰습니다.


206-206: 주석 내용 수정

환경 변수 목록에서 중복된 JAVA_OPTS 항목을 수정하여 문서의 정확성을 개선했습니다.


214-214: Java 실행 방식 개선

-jar 옵션 대신 메인 클래스 org.gradle.wrapper.GradleWrapperMain을 직접 호출하는 방식으로 변경하여 더 명확한 실행 구조를 제공합니다.

backend/ongi/src/main/java/ongi/temperature/dto/FamilyTemperatureResponse.java (1)

19-19: 코드 정리 완료

불필요한 공백 제거로 코드가 깔끔해졌습니다.

backend/ongi/src/main/java/ongi/temperature/repository/TemperatureRepository.java (1)

4-5: Import 문 추가 완료

새로운 DTO 클래스들을 사용하기 위한 import 문이 적절히 추가되었습니다.

backend/ongi/src/test/java/ongi/TemperatureControllerUnitTest.java (1)

39-161: 테스트 구현이 우수합니다

테스트가 잘 구조화되어 있고, given-when-then 패턴을 따르며, 성공 및 실패 케이스를 모두 다루고 있습니다.

backend/ongi/src/main/java/ongi/health/repository/ExerciseRecordRepository.java (1)

12-16: 코드 구조가 올바르게 구현되었습니다.

Spring Data JPA 리포지토리 인터페이스가 표준 규칙에 따라 잘 구현되었습니다. 쿼리 메서드 명명 규칙과 반환 타입이 적절합니다.

backend/ongi/src/main/java/ongi/health/repository/PainRecordRepository.java (2)

13-13: 통증 기록의 날짜별 다중성 설계가 일관성 있게 구현되었습니다.

findByParentIdAndDate 메서드가 List<PainRecord>를 반환하는 것은 하루에 여러 통증 기록이 가능함을 의미합니다. 이는 ExerciseRecordRepositoryOptional<ExerciseRecord> 반환과 대조적인데, 비즈니스 로직상 합리적인 설계로 보입니다.


11-15: 리포지토리 인터페이스가 올바르게 구현되었습니다.

Spring Data JPA 표준을 따르고 있으며, 쿼리 메서드 명명 규칙과 반환 타입이 적절합니다.

backend/ongi/src/main/java/ongi/health/dto/ExerciseRecordWithDiffResponse.java (1)

13-21: null 안전성이 잘 구현되었습니다.

편의 생성자에서 entity != null 체크를 통해 NPE를 방지하고 있으며, 적절한 기본값(null 또는 0)을 제공하고 있습니다. 운동 기록 간 차이 계산을 위한 설계가 잘 되어 있습니다.

backend/ongi/src/main/java/ongi/health/entity/ExerciseRecord.java (1)

8-27: 엔티티 설계가 일관성 있게 구현되었습니다.

JPA 엔티티 구조가 PainRecord 엔티티와 일관성 있게 설계되었고, Lombok 애노테이션 사용과 필드 정의가 적절합니다.

backend/ongi/src/main/java/ongi/health/entity/PainRecord.java (1)

8-14: 엔티티 설계가 잘 구성되어 있습니다.

JPA 엔티티 어노테이션과 Lombok을 적절히 활용하여 보일러플레이트 코드를 줄였습니다. Builder 패턴 지원으로 객체 생성이 편리합니다.

Comment on lines +28 to +32
// 최근 5일간 가족 구성원별 온도 기여 내역
@Query("SELECT new ongi.temperature.dto.FamilyTemperatureContributionResponse.Contribution(CAST(t.createdAt AS date), t.userId, SUM(t.temperature)) " +
"FROM Temperature t WHERE t.familyId = :familyId AND t.createdAt >= :fromDate " +
"GROUP BY CAST(t.createdAt AS date), t.userId ORDER BY CAST(t.createdAt AS date) DESC")
List<FamilyTemperatureContributionResponse.Contribution> getFamilyTemperatureContributions(@Param("familyId") String familyId, @Param("fromDate") java.time.LocalDateTime fromDate);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

집계 쿼리 최적화 권장

대용량 데이터에서 성능 문제가 발생할 수 있습니다. 다음 사항을 고려해보세요:

  1. (familyId, createdAt) 복합 인덱스 생성
  2. 페이징 처리 고려 (현재는 5일로 제한되어 있지만)
  3. 쿼리 실행 계획 검토

인덱스 생성 예시:

CREATE INDEX idx_temperature_family_created 
ON temperatures(family_id, created_at DESC);
🤖 Prompt for AI Agents
In
backend/ongi/src/main/java/ongi/temperature/repository/TemperatureRepository.java
around lines 28 to 32, the query for recent 5-day family temperature
contributions may cause performance issues on large datasets. To fix this,
create a composite index on the temperature table for (familyId, createdAt) with
createdAt in descending order to optimize filtering and ordering. Additionally,
consider implementing pagination in the query method to limit result size and
review the query execution plan to ensure efficient execution.


@RestController
@RequestMapping("/api/temperatures")
@RequestMapping("/temperature")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

API 경로 변경으로 인한 하위 호환성 문제

기존 /api/temperatures에서 /temperature로 변경되었습니다. 이는 기존 클라이언트에 대한 breaking change입니다.

하위 호환성을 위해 다음 중 하나를 고려하세요:

-@RequestMapping("/temperature")
+@RequestMapping("/api/temperature")

또는 기존 경로도 지원하도록 설정을 추가하세요.

🤖 Prompt for AI Agents
In
backend/ongi/src/main/java/ongi/temperature/controller/TemperatureController.java
at line 12, the API path was changed from /api/temperatures to /temperature,
causing a breaking change for existing clients. To fix this, either revert to
the original path or configure the controller to support both paths by adding an
additional @RequestMapping annotation or adjusting the mapping to include both
endpoints, ensuring backward compatibility.

Comment on lines +18 to +21
@GetMapping("/summary")
public ResponseEntity<FamilyTemperatureResponse> getFamilyTemperatureSummary(@RequestParam String familyId) {
return ResponseEntity.ok(temperatureService.getFamilyTemperatureSummary(familyId));
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

familyId 파라미터 검증 누락

familyId 파라미터에 대한 입력 검증이 없습니다. 빈 문자열이나 잘못된 형식의 ID가 전달될 수 있습니다.

다음과 같이 검증을 추가하세요:

-public ResponseEntity<FamilyTemperatureResponse> getFamilyTemperatureSummary(@RequestParam String familyId) {
+public ResponseEntity<FamilyTemperatureResponse> getFamilyTemperatureSummary(
+        @RequestParam @NotBlank(message = "가족 ID는 필수입니다") String familyId) {

컨트롤러 클래스에 @Validated 어노테이션도 추가해야 합니다.

📝 Committable suggestion

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

Suggested change
@GetMapping("/summary")
public ResponseEntity<FamilyTemperatureResponse> getFamilyTemperatureSummary(@RequestParam String familyId) {
return ResponseEntity.ok(temperatureService.getFamilyTemperatureSummary(familyId));
}
@GetMapping("/summary")
public ResponseEntity<FamilyTemperatureResponse> getFamilyTemperatureSummary(
@RequestParam @NotBlank(message = "가족 ID는 필수입니다") String familyId) {
return ResponseEntity.ok(temperatureService.getFamilyTemperatureSummary(familyId));
}
🤖 Prompt for AI Agents
In
backend/ongi/src/main/java/ongi/temperature/controller/TemperatureController.java
around lines 18 to 21, the familyId parameter lacks input validation, allowing
empty or invalid IDs. Add validation annotations such as @NotBlank to the
familyId parameter to ensure it is not empty, and annotate the controller class
with @Validated to enable validation processing. This will enforce proper input
checks before proceeding with the service call.

@@ -1,13 +1,9 @@
package ongi;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

테스트 클래스 패키지 위치 오류

테스트 클래스가 잘못된 패키지에 위치해 있습니다. 컨트롤러 클래스와 동일한 패키지 구조를 따라야 합니다.

다음과 같이 수정하세요:

-package ongi;
+package ongi.temperature.controller;
📝 Committable suggestion

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

Suggested change
package ongi;
-package ongi;
+package ongi.temperature.controller;
🤖 Prompt for AI Agents
In backend/ongi/src/test/java/ongi/TemperatureControllerUnitTest.java at line 1,
the test class is placed in the wrong package. Change the package declaration to
match the controller class's package structure so that the test class resides in
the correct package hierarchy aligned with the controller.

Comment on lines +41 to +49
@Transactional
public ExerciseRecord addExerciseRecord(UUID parentId, LocalDate date, int duration) {
ExerciseRecord record = ExerciseRecord.builder()
.parentId(parentId)
.date(date)
.duration(duration)
.build();
return exerciseRecordRepository.save(record);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

운동 시간 유효성 검증 추가

운동 시간(duration)에 대한 범위 검증이 필요합니다.

 @Transactional
 public ExerciseRecord addExerciseRecord(UUID parentId, LocalDate date, int duration) {
+    Assert.notNull(parentId, "Parent ID는 필수입니다");
+    Assert.notNull(date, "날짜는 필수입니다");
+    Assert.isTrue(duration >= 0, "운동 시간은 0 이상이어야 합니다");
+    Assert.isTrue(duration <= 1440, "운동 시간은 1440분(24시간)을 초과할 수 없습니다");
+    
     ExerciseRecord record = ExerciseRecord.builder()
             .parentId(parentId)
             .date(date)
             .duration(duration)
             .build();
     return exerciseRecordRepository.save(record);
 }
📝 Committable suggestion

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

Suggested change
@Transactional
public ExerciseRecord addExerciseRecord(UUID parentId, LocalDate date, int duration) {
ExerciseRecord record = ExerciseRecord.builder()
.parentId(parentId)
.date(date)
.duration(duration)
.build();
return exerciseRecordRepository.save(record);
}
@Transactional
public ExerciseRecord addExerciseRecord(UUID parentId, LocalDate date, int duration) {
Assert.notNull(parentId, "Parent ID는 필수입니다");
Assert.notNull(date, "날짜는 필수입니다");
Assert.isTrue(duration >= 0, "운동 시간은 0 이상이어야 합니다");
Assert.isTrue(duration <= 1440, "운동 시간은 1440분(24시간)을 초과할 수 없습니다");
ExerciseRecord record = ExerciseRecord.builder()
.parentId(parentId)
.date(date)
.duration(duration)
.build();
return exerciseRecordRepository.save(record);
}
🤖 Prompt for AI Agents
In backend/ongi/src/main/java/ongi/health/service/HealthRecordService.java
around lines 41 to 49, the addExerciseRecord method lacks validation for the
duration parameter. Add a validation step to check that duration is within a
valid range (e.g., positive and reasonable upper limit). If the duration is
invalid, throw an appropriate exception before creating and saving the
ExerciseRecord.

Comment on lines +24 to +33
@Transactional
public PainRecord addPainRecord(UUID parentId, LocalDate date, PainRecord.PainArea area, PainRecord.PainLevel level) {
PainRecord record = PainRecord.builder()
.parentId(parentId)
.date(date)
.painArea(area)
.painLevel(level)
.build();
return painRecordRepository.save(record);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

입력 유효성 검증 추가 필요

서비스 메서드에서 입력 파라미터에 대한 검증이 없습니다. null 값이나 잘못된 값이 전달될 수 있습니다.

+import org.springframework.util.Assert;
+
 @Transactional
 public PainRecord addPainRecord(UUID parentId, LocalDate date, PainRecord.PainArea area, PainRecord.PainLevel level) {
+    Assert.notNull(parentId, "Parent ID는 필수입니다");
+    Assert.notNull(date, "날짜는 필수입니다");
+    Assert.notNull(area, "통증 부위는 필수입니다");
+    Assert.notNull(level, "통증 정도는 필수입니다");
+    
     PainRecord record = PainRecord.builder()
             .parentId(parentId)
             .date(date)
             .painArea(area)
             .painLevel(level)
             .build();
     return painRecordRepository.save(record);
 }
📝 Committable suggestion

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

Suggested change
@Transactional
public PainRecord addPainRecord(UUID parentId, LocalDate date, PainRecord.PainArea area, PainRecord.PainLevel level) {
PainRecord record = PainRecord.builder()
.parentId(parentId)
.date(date)
.painArea(area)
.painLevel(level)
.build();
return painRecordRepository.save(record);
}
import org.springframework.util.Assert;
@Transactional
public PainRecord addPainRecord(UUID parentId, LocalDate date, PainRecord.PainArea area, PainRecord.PainLevel level) {
Assert.notNull(parentId, "Parent ID는 필수입니다");
Assert.notNull(date, "날짜는 필수입니다");
Assert.notNull(area, "통증 부위는 필수입니다");
Assert.notNull(level, "통증 정도는 필수입니다");
PainRecord record = PainRecord.builder()
.parentId(parentId)
.date(date)
.painArea(area)
.painLevel(level)
.build();
return painRecordRepository.save(record);
}
🤖 Prompt for AI Agents
In backend/ongi/src/main/java/ongi/health/service/HealthRecordService.java
around lines 24 to 33, the addPainRecord method lacks input validation for its
parameters. Add checks to ensure none of the parameters (parentId, date, area,
level) are null or invalid before proceeding. If any parameter is invalid, throw
an appropriate exception to prevent saving incorrect data.

Comment on lines +65 to +74
// 자녀용: 부모 운동 기록 + 전날 대비 증감 조회
@GetMapping("/parents/exercise")
public ResponseEntity<ExerciseRecordWithDiffResponse> getParentExerciseRecordForChild(
@RequestParam UUID parentId,
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date
) {
ExerciseRecordWithDiffResponse resp = healthRecordService.getExerciseRecordWithDiff(parentId, date);
return ResponseEntity.ok(resp);
}
} No newline at end of file
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

동일한 보안 이슈 존재

운동 기록 조회 엔드포인트에서도 동일한 권한 검증 문제가 있습니다.

 @GetMapping("/parents/exercise")
 public ResponseEntity<ExerciseRecordWithDiffResponse> getParentExerciseRecordForChild(
+        @AuthenticationPrincipal CustomUserDetails userDetails,
         @RequestParam UUID parentId,
         @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date
 ) {
+    if (!hasAccessToParent(userDetails.getUser(), parentId)) {
+        return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
+    }
+    
     ExerciseRecordWithDiffResponse resp = healthRecordService.getExerciseRecordWithDiff(parentId, date);
     return ResponseEntity.ok(resp);
 }
🤖 Prompt for AI Agents
In backend/ongi/src/main/java/ongi/health/controller/HealthRecordController.java
around lines 65 to 74, the getParentExerciseRecordForChild method lacks proper
authorization checks, leading to a security issue. Add appropriate security
annotations or explicit permission checks to verify that the requesting user has
the right to access the parent's exercise records before returning the response.

Comment on lines +26 to +36
@PostMapping("/pain")
public ResponseEntity<PainRecordResponse> addPainRecord(
@AuthenticationPrincipal CustomUserDetails userDetails,
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date,
@RequestParam PainRecord.PainArea area,
@RequestParam PainRecord.PainLevel level
) {
PainRecord record = healthRecordService.addPainRecord(userDetails.getUser().getUuid(), date, area, level);
PainRecordResponse response = new PainRecordResponse(record);
return ResponseEntity.ok(response);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

입력 검증 및 예외 처리 추가 필요

컨트롤러에서 입력 파라미터에 대한 검증이 부족하고 예외 처리가 없습니다.

+import org.springframework.validation.annotation.Validated;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotNull;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.http.HttpStatus;
+
+@Validated
 @RestController
 @RequestMapping("/health")
 @RequiredArgsConstructor
 public class HealthRecordController {
 
 @PostMapping("/pain")
 public ResponseEntity<PainRecordResponse> addPainRecord(
         @AuthenticationPrincipal CustomUserDetails userDetails,
-        @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date,
-        @RequestParam PainRecord.PainArea area,
-        @RequestParam PainRecord.PainLevel level
+        @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) @NotNull LocalDate date,
+        @RequestParam @NotNull PainRecord.PainArea area,
+        @RequestParam @NotNull PainRecord.PainLevel level
 ) {
+    try {
         PainRecord record = healthRecordService.addPainRecord(userDetails.getUser().getUuid(), date, area, level);
         PainRecordResponse response = new PainRecordResponse(record);
         return ResponseEntity.ok(response);
+    } catch (Exception e) {
+        // 적절한 예외 처리 로직 추가
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
+    }
 }
📝 Committable suggestion

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

Suggested change
@PostMapping("/pain")
public ResponseEntity<PainRecordResponse> addPainRecord(
@AuthenticationPrincipal CustomUserDetails userDetails,
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date,
@RequestParam PainRecord.PainArea area,
@RequestParam PainRecord.PainLevel level
) {
PainRecord record = healthRecordService.addPainRecord(userDetails.getUser().getUuid(), date, area, level);
PainRecordResponse response = new PainRecordResponse(record);
return ResponseEntity.ok(response);
}
import org.springframework.validation.annotation.Validated;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.http.HttpStatus;
@Validated
@RestController
@RequestMapping("/health")
@RequiredArgsConstructor
public class HealthRecordController {
@PostMapping("/pain")
public ResponseEntity<PainRecordResponse> addPainRecord(
@AuthenticationPrincipal CustomUserDetails userDetails,
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) @NotNull LocalDate date,
@RequestParam @NotNull PainRecord.PainArea area,
@RequestParam @NotNull PainRecord.PainLevel level
) {
try {
PainRecord record = healthRecordService.addPainRecord(
userDetails.getUser().getUuid(), date, area, level
);
PainRecordResponse response = new PainRecordResponse(record);
return ResponseEntity.ok(response);
} catch (Exception e) {
// 적절한 예외 처리 로직 추가
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
}
🤖 Prompt for AI Agents
In backend/ongi/src/main/java/ongi/health/controller/HealthRecordController.java
around lines 26 to 36, the addPainRecord method lacks input validation and
exception handling for the request parameters. Add validation annotations or
manual checks to ensure the parameters are valid and handle potential exceptions
gracefully by returning appropriate HTTP error responses. This will improve
robustness and user feedback on invalid inputs.

Comment on lines +52 to +63
// 자녀용: 부모 통증 기록 조회
@GetMapping("/parents/pain")
public ResponseEntity<List<PainRecordResponse>> getParentPainRecordsForChild(
@RequestParam UUID parentId,
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date
) {
List<PainRecord> records = healthRecordService.getPainRecords(parentId, date);
List<PainRecordResponse> response = records.stream()
.map(PainRecordResponse::new)
.toList();
return ResponseEntity.ok(response);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

보안 권한 검증 필요

자녀가 부모의 기록을 조회하는 엔드포인트에서 권한 검증이 없습니다. 임의의 parentId로 다른 사용자의 데이터에 접근할 수 있습니다.

 @GetMapping("/parents/pain")
 public ResponseEntity<List<PainRecordResponse>> getParentPainRecordsForChild(
+        @AuthenticationPrincipal CustomUserDetails userDetails,
         @RequestParam UUID parentId,
         @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date
 ) {
+    // 현재 사용자가 해당 부모에 접근할 권한이 있는지 확인
+    if (!hasAccessToParent(userDetails.getUser(), parentId)) {
+        return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
+    }
+    
     List<PainRecord> records = healthRecordService.getPainRecords(parentId, date);
     List<PainRecordResponse> response = records.stream()
         .map(PainRecordResponse::new)
         .toList();
     return ResponseEntity.ok(response);
 }
+
+private boolean hasAccessToParent(User user, UUID parentId) {
+    // 부모-자녀 관계 검증 로직 구현 필요
+    return true; // 임시 구현
+}
🤖 Prompt for AI Agents
In backend/ongi/src/main/java/ongi/health/controller/HealthRecordController.java
around lines 52 to 63, the getParentPainRecordsForChild method lacks
authorization checks, allowing access to any parent's pain records by specifying
parentId. Add security validation to verify that the requesting user is
authorized to access the specified parent's data, such as checking the
authenticated user's identity or roles against the parentId before fetching
records, and return an appropriate error response if unauthorized.

@oxomi oxomi merged commit adc4c8c into main Jul 17, 2025
4 of 6 checks passed
@oxomi oxomi deleted the refactor/ongi branch July 17, 2025 00:46
Neibce pushed a commit to 2025-PNU-SW-Hackathon/PNUSW-2025-OnGi-10 that referenced this pull request Aug 25, 2025
* feat: 건강 기록(통증부위, 운동시간) 작성/조회 로직 구현
fix: Temperature 엔티티에 불필요한 칼럼 제거

* refactor: 온기 조회 시스템 리팩토링 및 엔드포인트 추가

* fix: 쿼리문 오류 수정
feat: 온도 조회 controller 테스트코드 추가

* fix: 쿼리문 오류 수정 2차
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.

1 participant