Conversation
WalkthroughAttendance-check 기능에 NOT_FOUND 에러 코드를 추가하고, Swagger 응답 정의를 갱신했습니다. 오늘의 한마디 생성 API의 응답 DTO/결과 DTO를 확장했으며, 서비스 로직에서 사용자 정보 조회, 저장 후 재조회(getByIdOrThrow)로 응답 데이터를 채우도록 제어 흐름을 수정했습니다. 포트/어댑터에 findById/getByIdOrThrow를 추가했습니다. Changes
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/>없을 때 예외 처리
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes(없음) Possibly related PRs
Suggested reviewers
Poem
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 unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
Test Results411 tests 411 ✅ 32s ⏱️ Results for commit 9007a16. |
There was a problem hiding this comment.
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) → savedAttendanceCheckJava 관례에 맞게 변수명을 소문자 카멜케이스로 수정해 주세요.
다음 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.
📒 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 추가 반영 OKATTENDANCE_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: 매핑 순서/필드 대응 정확 — LGTMResult의 필드가 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 제공)과도 일치하고, 예외 매핑이 일관적입니다.
#️⃣ 연관된 이슈
📝 작업 내용
📸 스크린샷
💬 리뷰 요구사항
📌 PR 진행 시 이러한 점들을 참고해 주세요
Summary by CodeRabbit