Skip to content

[Hotfix] 오늘의 한마디 작성 response 수정#264

Merged
hd0rable merged 4 commits intodevelopfrom
hotfix/#256-attendance-check-response-fix
Aug 19, 2025
Merged

[Hotfix] 오늘의 한마디 작성 response 수정#264
hd0rable merged 4 commits intodevelopfrom
hotfix/#256-attendance-check-response-fix

Conversation

@hd0rable
Copy link
Member

@hd0rable hd0rable commented Aug 19, 2025

#️⃣ 연관된 이슈

closes #256

📝 작업 내용

  • 오늘의 한마디 작성 response를 수정했습니다

📸 스크린샷

💬 리뷰 요구사항

리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해주세요

📌 PR 진행 시 이러한 점들을 참고해 주세요

* P1 : 꼭 반영해 주세요 (Request Changes) - 이슈가 발생하거나 취약점이 발견되는 케이스 등
* P2 : 반영을 적극적으로 고려해 주시면 좋을 것 같아요 (Comment)
* P3 : 이런 방법도 있을 것 같아요~ 등의 사소한 의견입니다 (Chore)

Summary by CodeRabbit

  • New Features
    • 출석체크 생성 응답에 작성자 정보(닉네임, 프로필 이미지), 오늘의 한마디, 게시 날짜/로컬 날짜, 작성자 여부 등이 추가되었습니다.
    • 존재하지 않는 출석체크 요청 시 404 오류 코드가 반환됩니다.
  • Documentation
    • Swagger 문서에 출석체크 생성 응답 필드와 신규 404 오류 코드가 반영되었습니다.

@coderabbitai
Copy link

coderabbitai bot commented Aug 19, 2025

Walkthrough

Attendance-check 기능에 NOT_FOUND 에러 코드를 추가하고, Swagger 응답 정의를 갱신했습니다. 오늘의 한마디 생성 API의 응답 DTO/결과 DTO를 확장했으며, 서비스 로직에서 사용자 정보 조회, 저장 후 재조회(getByIdOrThrow)로 응답 데이터를 채우도록 제어 흐름을 수정했습니다. 포트/어댑터에 findById/getByIdOrThrow를 추가했습니다.

Changes

Cohort / File(s) Summary
Error/Swagger 업데이트
src/main/java/konkuk/thip/common/exception/code/ErrorCode.java, src/main/java/konkuk/thip/common/swagger/SwaggerResponseDescription.java
ATTENDANCE_CHECK_NOT_FOUND 에러 코드(404, 195001) 추가 및 Swagger ATTENDANCE_CHECK_CREATE 오류 집합에 포함
응답 DTO 확장
src/main/java/konkuk/thip/roompost/adapter/in/web/response/AttendanceCheckCreateResponse.java
응답 레코드 필드 확장(creator*, todayComment, postDate, date, isWriter 등) 및 팩토리 메서드 업데이트
결과 DTO 확장
src/main/java/konkuk/thip/roompost/application/port/in/dto/attendancecheck/AttendanceCheckCreateResult.java
결과 레코드 필드 확장 및 순서 조정(LocalDate date, isWriter 추가 등)
포트/어댑터 조회 기능 추가
src/main/java/konkuk/thip/roompost/application/port/out/AttendanceCheckCommandPort.java, src/main/java/konkuk/thip/roompost/adapter/out/persistence/AttendanceCheckCommandPersistenceAdapter.java
Optional 기반 findById 및 기본 메서드 getByIdOrThrow 추가, JPA 위임 구현
서비스 로직 보강
src/main/java/konkuk/thip/roompost/application/service/AttendanceCheckCreateService.java
User 조회로 작성자 정보 채움, 저장 후 엔티티 재조회, postDate/date 계산, isWriter 설정

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant C as Client
    participant Ctl as Controller
    participant S as AttendanceCheckCreateService
    participant U as UserCommandPort
    participant Rm as RoomMembership/Validation
    participant P as AttendanceCheckCommandPort
    participant D as DateUtil

    C->>Ctl: POST /attendance-check
    Ctl->>S: create(command)
    S->>U: findById(creatorId)
    U-->>S: User(nickname, profileImage)
    S->>Rm: validateMembership(user, roomId)
    S->>P: save(AttendanceCheck)
    P-->>S: savedId
    S->>P: getByIdOrThrow(savedId)
    P-->>S: SavedAttendanceCheck(createdAt, ...)
    S->>D: formatBeforeTime(createdAt)
    D-->>S: postDate(string)
    S-->>Ctl: AttendanceCheckCreateResult → ResponseDTO(확장 필드 포함)
    Ctl-->>C: 200 OK (확장된 응답)
    
    note right of P: getByIdOrThrow는<br/>ATTENDANCE_CHECK_NOT_FOUND로<br/>없을 때 예외 처리
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Assessment against linked issues

Objective Addressed Explanation
오늘의 한마디 작성 API의 response 수정 (#256)

Assessment against linked issues: Out-of-scope changes

(없음)

Possibly related PRs

Suggested reviewers

  • buzz0331

Poem

새벽에 톡톡, 키보드 쿵쾅—깡총!
응답이 길어졌지, 닉네임까지 쏙—깡총!
저장 후 다시 보니 날짜도 반짝,
못 찾으면 404로 살짝 깡총 점프.
오늘의 한마디, 토실토실 완성! 🥕

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch hotfix/#256-attendance-check-response-fix

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
🪧 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.
    • 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.
  • 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 the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

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

CodeRabbit Commands (Invoked using PR/Issue comments)

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

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

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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.

@github-actions
Copy link

Test Results

411 tests   411 ✅  32s ⏱️
123 suites    0 💤
123 files      0 ❌

Results for commit 9007a16.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (9)
src/main/java/konkuk/thip/roompost/adapter/in/web/response/AttendanceCheckCreateResponse.java (2)

23-25: 불리언 계산 단순화

가독성을 위해 한 줄로 축약 가능합니다.

-        boolean isFirstWrite = false;
-        if (result.todayWriteCountOfUser() == 1) isFirstWrite = true;
+        boolean isFirstWrite = result.todayWriteCountOfUser() == 1;

17-18: LocalDate 직렬화 형식 고정: @jsonformat 추가 권장
전역 Jackson 설정(JavaTimeModule 등록 여부, WRITE_DATES_AS_TIMESTAMPS 비활성화 등)을 확인한 결과, 명시적으로 문자열 포맷(yyyy-MM-dd)으로 직렬화를 보장할 설정을 찾지 못했습니다. 핫픽스 성격으로 해당 필드에 @jsonformat을 추가하여 응답 포맷을 안정화하세요.

  • 파일: src/main/java/konkuk/thip/roompost/adapter/in/web/response/AttendanceCheckCreateResponse.java
    -    @Schema(description = "작성 날짜(yyyy-MM-dd)", example = "2025-08-17")
    -    LocalDate date,        // 해당 오늘의 한마디 데이터의 작성 날짜
    +    @Schema(description = "작성 날짜(yyyy-MM-dd)", example = "2025-08-17")
  • @jsonformat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
  • LocalDate date, // 해당 오늘의 한마디 데이터의 작성 날짜
- import 추가:
```java
import com.fasterxml.jackson.annotation.JsonFormat;
src/main/java/konkuk/thip/roompost/adapter/out/persistence/AttendanceCheckCommandPersistenceAdapter.java (1)

44-48: 읽기 전용 트랜잭션 부여 고려

조회 시 Lazy 로딩/영속성 컨텍스트가 필요한 경우를 대비해 readOnly 트랜잭션을 붙이는 것을 권장합니다. 어댑터 레이어에서 명시하면 서비스 의존 없이도 안전합니다.

     @Override
+    @Transactional(readOnly = true)
     public Optional<AttendanceCheck> findById(Long id) {
         return attendanceCheckJpaRepository.findById(id)
                 .map(attendanceCheckMapper::toDomainEntity);
     }

추가 import:

import org.springframework.transaction.annotation.Transactional;
src/main/java/konkuk/thip/roompost/application/port/out/AttendanceCheckCommandPort.java (1)

16-19: 기능 명세를 JavaDoc으로 명시하면 가독성이 더 좋아집니다

메서드 동작(미존재 시 ATTENDANCE_CHECK_NOT_FOUND 예외)을 JavaDoc으로 간단히 표기하면 호출부에서 의도 파악이 쉬워집니다.

다음과 같이 주석 추가를 고려해 주세요:

     default AttendanceCheck getByIdOrThrow(Long id) {
-        return findById(id)
+        // 존재하지 않으면 ATTENDANCE_CHECK_NOT_FOUND 예외를 던집니다.
+        return findById(id)
                 .orElseThrow(() -> new EntityNotFoundException(ATTENDANCE_CHECK_NOT_FOUND));
     }
src/main/java/konkuk/thip/roompost/application/service/AttendanceCheckCreateService.java (5)

39-41: 저장 직후 재조회 패턴은 동작은 안전하나 1회 불필요 조회가 추가됩니다

Auditing 필드(createdAt 등)를 채우기 위해 재조회하는 접근은 이해되지만, 퍼시스턴스 어댑터에서 저장 시점의 엔티티(도메인 매핑 포함)를 반환하도록 바꾸면 DB 왕복을 줄일 수 있습니다. 핫픽스 맥락에서는 현 상태 유지도 타당하므로 추후 리팩터링 대상으로 고려하면 좋겠습니다.


40-50: 지역변수명 카멜케이스 불일치(SavedattendanceCheck) → savedAttendanceCheck

Java 관례에 맞게 변수명을 소문자 카멜케이스로 수정해 주세요.

다음 diff를 적용하면 됩니다:

-        AttendanceCheck SavedattendanceCheck = attendanceCheckCommandPort.getByIdOrThrow(attendanceCheckCommandPort.save(attendanceCheck));
+        AttendanceCheck savedAttendanceCheck = attendanceCheckCommandPort.getByIdOrThrow(attendanceCheckCommandPort.save(attendanceCheck));
@@
-                .attendanceCheckId(SavedattendanceCheck.getId())
+                .attendanceCheckId(savedAttendanceCheck.getId())
@@
-                .postDate(DateUtil.formatBeforeTime(SavedattendanceCheck.getCreatedAt()))
+                .postDate(DateUtil.formatBeforeTime(savedAttendanceCheck.getCreatedAt()))
@@
-                .date(SavedattendanceCheck.getCreatedAt().toLocalDate())
+                .date(savedAttendanceCheck.getCreatedAt().toLocalDate())

46-48: NPE 가능성: user.getAlias() null 대비 필요 여부 확인

user.getAlias().getImageUrl() 체인은 Alias가 null일 경우 NPE가 납니다. 도메인 불변식으로 Alias가 항상 존재한다면 문제없지만, 그렇지 않다면 null-safe 접근으로 방어해 주세요.

아래처럼 로컬 변수를 두고 빌더에 주입하는 방식을 권장합니다:

-        return AttendanceCheckCreateResult.builder()
+        String profileImageUrl = (user.getAlias() != null) ? user.getAlias().getImageUrl() : null;
+        return AttendanceCheckCreateResult.builder()
@@
-                .creatorProfileImageUrl(user.getAlias().getImageUrl())
+                .creatorProfileImageUrl(profileImageUrl)

49-51: 상대시간 및 현재시각 호출 개선 필요

DateUtil의 상대시간 포맷 메서드와 AttendanceCheckQueryPersistenceAdapter에서 LocalDateTime.now()를 직접 사용하고 있어,

  • 서버 타임존 의존성
  • 단위 테스트 비결정성

문제가 발생할 수 있습니다. 장기적으로는 Clock을 주입하거나 현재 시각을 호출자가 인자로 전달하도록 리팩터링을 고려해주세요.

주요 대상:

  • src/main/java/konkuk/thip/common/util/DateUtil.java
    • formatBeforeTime(LocalDateTime)
    • formatAfterTime(LocalDate)
    • RecruitingRoomFormatAfterTime(LocalDate)
  • src/main/java/konkuk/thip/roompost/adapter/out/persistence/AttendanceCheckQueryPersistenceAdapter.java
    • 당일 출석 조회 로직(LocalDateTime.now().toLocalDate().atStartOfDay())

31-33: UserCommandPort 예외 처리 일관성 확보 및 getByIdOrThrow 도입 검토

현재 UserCommandPort.findById()는 User를 직접 반환하며, 조회 실패 시 null 반환 또는 예외 매핑 방식이 불분명합니다. 다른 도메인 포트들처럼 Optional 반환 후 default getByIdOrThrow(Long id) 메서드를 추가하여 404 매핑을 일관화하거나, 호출부에서 명시적 예외 처리를 구현하는 방안을 검토해주세요.

수정이 필요한 위치 예시:

  • src/main/java/konkuk/thip/user/application/port/out/UserCommandPort.java
    • findById를 Optional 반환으로 변경
    • default User getByIdOrThrow(Long id) 메서드 추가
  • src/main/java/konkuk/thip/roompost/application/service/AttendanceCheckCreateService.java:31
    • userCommandPort.findById(...) → userCommandPort.getByIdOrThrow(...) 또는 예외 처리 로직 적용
📜 Review details

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

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b474ce6 and 9007a16.

📒 Files selected for processing (7)
  • src/main/java/konkuk/thip/common/exception/code/ErrorCode.java (1 hunks)
  • src/main/java/konkuk/thip/common/swagger/SwaggerResponseDescription.java (1 hunks)
  • src/main/java/konkuk/thip/roompost/adapter/in/web/response/AttendanceCheckCreateResponse.java (1 hunks)
  • src/main/java/konkuk/thip/roompost/adapter/out/persistence/AttendanceCheckCommandPersistenceAdapter.java (2 hunks)
  • src/main/java/konkuk/thip/roompost/application/port/in/dto/attendancecheck/AttendanceCheckCreateResult.java (1 hunks)
  • src/main/java/konkuk/thip/roompost/application/port/out/AttendanceCheckCommandPort.java (1 hunks)
  • src/main/java/konkuk/thip/roompost/application/service/AttendanceCheckCreateService.java (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-03T03:05:05.031Z
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#43
File: src/main/java/konkuk/thip/book/application/port/out/BookCommandPort.java:0-0
Timestamp: 2025-07-03T03:05:05.031Z
Learning: THIP 프로젝트에서는 CQRS Port 분리 시 다음 컨벤션을 따름: CommandPort에는 findByXXX를 통해 도메인 엔티티를 찾아오는 메서드를 추가하고, QueryPort에는 조회 API의 response에 해당하는 데이터들을 DB로부터 조회하는 메서드를 추가함.

Applied to files:

  • src/main/java/konkuk/thip/roompost/application/port/out/AttendanceCheckCommandPort.java
🧬 Code Graph Analysis (2)
src/main/java/konkuk/thip/roompost/application/port/out/AttendanceCheckCommandPort.java (1)
src/main/java/konkuk/thip/common/exception/EntityNotFoundException.java (1)
  • EntityNotFoundException (5-10)
src/main/java/konkuk/thip/roompost/application/service/AttendanceCheckCreateService.java (1)
src/main/java/konkuk/thip/common/util/DateUtil.java (1)
  • DateUtil (12-85)
🔇 Additional comments (8)
src/main/java/konkuk/thip/common/exception/code/ErrorCode.java (2)

200-200: ATTENDANCE_CHECK_NOT_FOUND 추가 적절 — 404/도메인 코드 배치 모두 일관적입니다

의미/메시지/HTTP 상태값 일관성 좋아요. AttendanceCheck 도메인 내 코드 범위(195xxx) 유지도 적절합니다.


200-200: 에러 코드 중복 확인 완료

스크립트를 실행한 결과 총 112개의 에러 코드에서 중복되는 값이 없는 것을 확인했습니다. ✅

src/main/java/konkuk/thip/common/swagger/SwaggerResponseDescription.java (1)

297-299: Swagger에 NOT_FOUND 추가 반영 OK

ATTENDANCE_CHECK_CREATE에 WRITE_LIMIT와 NOT_FOUND 모두 명시되어 있어 문서화가 잘 되었습니다. Create 과정에서 재조회 실패 가능성을 대비한 문서 추가로 보입니다.

src/main/java/konkuk/thip/roompost/application/port/in/dto/attendancecheck/AttendanceCheckCreateResult.java (1)

5-19: 빌더 호출 및 접근자 검증 완료 — 변경된 필드가 모두 반영되었습니다
서비스의 AttendanceCheckCreateResult.builder() 체인에 새로 추가된 필드(todayComment, postDate, date, todayWriteCountOfUser, isWriter)가 모두 설정되어 있고, 어댑터에서의 result.isWriter() 호출도 정상 동작하므로 추가 수정이 필요하지 않습니다.

src/main/java/konkuk/thip/roompost/adapter/in/web/response/AttendanceCheckCreateResponse.java (1)

26-37: 매핑 순서/필드 대응 정확 — LGTM

Result의 필드가 Response 순서대로 정확히 매핑되었습니다. isFirstWrite 계산도 의도에 맞습니다.

src/main/java/konkuk/thip/roompost/adapter/out/persistence/AttendanceCheckCommandPersistenceAdapter.java (1)

44-48: findById 구현 적절 — Optional 매핑 깔끔합니다

JPA 조회 → Mapper 변환 흐름이 단순명확합니다.

src/main/java/konkuk/thip/roompost/application/port/out/AttendanceCheckCommandPort.java (2)

3-9: 필요한 import 및 NOT_FOUND 에러 코드 매핑 적절합니다

엔티티 미존재 시 ATTENDANCE_CHECK_NOT_FOUND를 던지도록 준비된 import 구성이 명확합니다.


14-19: getByIdOrThrow 기본 메서드 추가로 Port 사용성이 좋아졌습니다

CQRS 컨벤션(커맨드 포트에 findByXXX 제공)과도 일치하고, 예외 매핑이 일관적입니다.

@hd0rable hd0rable merged commit c404714 into develop Aug 19, 2025
4 checks passed
@hd0rable hd0rable deleted the hotfix/#256-attendance-check-response-fix branch August 19, 2025 07:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[THIP2025-304] [refactor] 오늘의 한마디 작성 api response 수정

1 participant