Conversation
- 알림 목록 조회 (커서처리) - 알림 단건 Read API 개발 - 전체 알림 Read API 개발 - 읽지 않은 알림 개수 조회 API 개발 - notificaitons Entity 일부 수정 (테이블, 필드) - .http 테스트 작성 및 정상 동작 확인
Walkthrough알림 도메인(엔티티, DTO, 저장소, 서비스, 컨트롤러, 예외)과 에러코드가 추가되었고, 인증 컨트롤러의 리프레시 토큰 쿠키에 도메인(".wego.monster")이 설정되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Controller as NotificationController
participant Service as NotificationService
participant Repo as NotificationRepository
participant DB as Database
rect rgb(230,240,255)
Note over Client,DB: 알림 목록 조회 (커서 기반)
Client->>Controller: GET /api/v1/notifications?cursor=&size=
Controller->>Service: notificationList(userId, cursor, size)
Service->>Repo: findNotificationList(userId, cursor, size)
Repo->>DB: QueryDSL SELECT (join actor) with cursor & limit
DB-->>Repo: List<NotificationResponse>
Repo-->>Service: 반환
Service->>Controller: NotificationListResponse (notifications + nextCursor)
Controller-->>Client: 200 OK
end
rect rgb(230,255,230)
Note over Client,DB: 단건 읽음 처리
Client->>Controller: POST /api/v1/notifications/{id}/read
Controller->>Service: readNotification(userId, id)
Service->>Repo: findById(id)
DB-->>Repo: Notification 엔티티
Repo-->>Service: Notification
Service->>Service: 소유자 검증
alt 소유자 일치
Service->>Service: notification.markAsRead() (readAt = now)
Service->>Repo: save(notification)
Repo->>DB: UPDATE read_at
DB-->>Repo: OK
Service-->>Controller: void
Controller-->>Client: 204 No Content
else 불일치
Service-->>Controller: NotificationAccessDeniedException
Controller-->>Client: 403 Forbidden
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related issues
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/main/java/team/wego/wegobackend/notification/presentation/NotificationController.java (1)
30-35:@Validated어노테이션 누락으로@Min/@Max검증이 동작하지 않습니다.
@RequestParam에 적용된@Min(1),@Max(100)검증이 동작하려면 컨트롤러 클래스에@Validated어노테이션이 필요합니다.🔎 제안된 수정
+import org.springframework.validation.annotation.Validated; + @Tag(name = "SSE 엔드포인트", description = "SSE 연결을 위한 엔드포인트") @Slf4j @RestController @RequiredArgsConstructor +@Validated @RequestMapping("/api/v1/notifications") public class NotificationController {
♻️ Duplicate comments (1)
src/main/java/team/wego/wegobackend/auth/presentation/AuthController.java (1)
144-153: 일관성 있음: 도메인이 생성 메서드와 동일하게 설정되었습니다.쿠키 삭제 시 생성 시와 동일한 도메인을 사용하는 것이 올바른 구현입니다. 단, 위의
createRefreshTokenCookie코멘트에서 제안한 도메인 외부화를 함께 적용하시면 일관성 있게 관리할 수 있습니다.</review_comment_end -->
🧹 Nitpick comments (8)
src/main/java/team/wego/wegobackend/auth/presentation/AuthController.java (1)
130-139: 도메인 설정을 외부 설정으로 외부화하세요.쿠키 도메인이 ".wego.monster"로 하드코딩되어 있습니다. 개발, 스테이징, 운영 환경마다 다른 도메인을 사용할 가능성이 있으므로,
application.properties또는 환경 변수로 외부화하는 것이 좋습니다.🔎 제안 수정 방법
Step 1:
application.properties에 도메인 설정 추가cookie.domain=.wego.monsterStep 2:
@Value또는@ConfigurationProperties로 주입@Slf4j @RestController @RequiredArgsConstructor @RequestMapping("/api/v1/auth") public class AuthController implements AuthControllerDocs { private final AuthService authService; private final JwtTokenProvider jwtTokenProvider; + @Value("${cookie.domain}") + private String cookieDomain; // ... 다른 코드 ... private Cookie createRefreshTokenCookie(String refreshToken) { Cookie cookie = new Cookie("refreshToken", refreshToken); cookie.setHttpOnly(true); cookie.setSecure(true); cookie.setPath("/"); - cookie.setDomain(".wego.monster"); + cookie.setDomain(cookieDomain); cookie.setMaxAge((int) jwtTokenProvider.getRefreshTokenExpiration()); cookie.setAttribute("SameSite", "Strict"); return cookie; }src/main/java/team/wego/wegobackend/notification/domain/Notification.java (2)
50-51:LocalDateTime대신ZonedDateTime사용을 고려하세요.
LocalDateTime은 타임존 정보가 없어서 서버가 여러 타임존에 배포된 경우 일관성 문제가 발생할 수 있습니다.ZonedDateTime을 사용하면 명확한 시점을 저장할 수 있습니다.🔎 제안하는 변경사항
-import java.time.LocalDateTime; +import java.time.ZonedDateTime; -@Column(name = "read_at") -private LocalDateTime readAt; +@Column(name = "read_at") +private ZonedDateTime readAt;그리고
markAsRead()메서드도 함께 수정:public void markAsRead() { - this.readAt = LocalDateTime.now(); + this.readAt = ZonedDateTime.now(); }
27-82: 가독성 향상을 위한 헬퍼 메서드 추가를 고려하세요.
readAt필드의 null 체크를 여러 곳에서 반복하게 될 수 있습니다.isUnread()또는isRead()헬퍼 메서드를 추가하면 코드 가독성이 향상됩니다.🔎 제안하는 헬퍼 메서드
+public boolean isUnread() { + return this.readAt == null; +} + +public boolean isRead() { + return this.readAt != null; +} + public void markAsRead() { this.readAt = LocalDateTime.now(); }src/main/java/team/wego/wegobackend/notification/application/dto/response/NotificationListResponse.java (1)
5-7: 간결하고 적절한 DTO 구현입니다.커서 기반 페이지네이션을 위한
nextCursor필드가 올바르게 설계되었습니다. 필요하다면nextCursor가 null일 때(마지막 페이지)의 의미를 명확히 하는 Javadoc 추가를 고려해보세요.src/main/java/team/wego/wegobackend/notification/repository/NotificationRepositoryImpl.java (2)
27-40: 오래된 주석 - 정리 필요주석에 오타("rivate" → "private")가 있고,
isRead가readAt으로 변경되었지만 주석이 업데이트되지 않았습니다. 불필요한 주석은 제거하거나 최신 상태로 유지해 주세요.
67-71: 메서드 이름이 Java 네이밍 컨벤션을 따르지 않습니다.
ItCursor는 대문자로 시작하여 클래스명처럼 보입니다. Java 메서드 네이밍 컨벤션에 따라 camelCase인ltCursor또는lessThanCursor로 변경하는 것을 권장합니다.🔎 제안된 수정
- private BooleanExpression ItCursor(Long cursorNotificationId) { + private BooleanExpression ltCursor(Long cursorNotificationId) { return cursorNotificationId == null ? null : QNotification.notification.id.lt(cursorNotificationId); }Line 60도 함께 수정:
- ItCursor(cursorNotificationId) + ltCursor(cursorNotificationId)src/main/java/team/wego/wegobackend/notification/application/NotificationService.java (2)
65-70: 사용되지 않는 변수resultCount
markAllAsRead결과값을 저장하지만 사용하지 않습니다. 로깅이나 반환값으로 활용하거나, 필요 없다면 제거해 주세요.🔎 제안된 수정
public void readAllNotification(Long userId) { User user = userRepository.findById(userId).orElseThrow(UserNotFoundException::new); - int resultCount = notificationRepository.markAllAsRead(user.getId()); + notificationRepository.markAllAsRead(user.getId()); }
27-37: 인증된 userId에 대한 User 조회의 필요성 검토
userId는@AuthenticationPrincipal에서 제공되므로 유효한 사용자임이 보장됩니다. 모든 메서드에서userRepository.findById()를 호출하는 것이 필요한지 검토해 주세요. 단, User 엔티티의 다른 필드가 필요하거나 존재 확인이 비즈니스 요구사항이라면 현재 방식이 적절합니다.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
src/main/java/team/wego/wegobackend/auth/presentation/AuthController.javasrc/main/java/team/wego/wegobackend/common/exception/AppErrorCode.javasrc/main/java/team/wego/wegobackend/notification/application/NotificationService.javasrc/main/java/team/wego/wegobackend/notification/application/dto/response/NotificationListResponse.javasrc/main/java/team/wego/wegobackend/notification/application/dto/response/NotificationResponse.javasrc/main/java/team/wego/wegobackend/notification/domain/Notification.javasrc/main/java/team/wego/wegobackend/notification/exception/NotificationAccessDeniedException.javasrc/main/java/team/wego/wegobackend/notification/exception/NotificationNotFoundException.javasrc/main/java/team/wego/wegobackend/notification/presentation/NotificationController.javasrc/main/java/team/wego/wegobackend/notification/repository/NotificationRepository.javasrc/main/java/team/wego/wegobackend/notification/repository/NotificationRepositoryCustom.javasrc/main/java/team/wego/wegobackend/notification/repository/NotificationRepositoryImpl.javasrc/main/resources/application.ymlsrc/test/http/noti/noti-api.http
🔇 Additional comments (13)
src/main/java/team/wego/wegobackend/notification/exception/NotificationAccessDeniedException.java (1)
6-11: 구현이 올바릅니다.표준 예외 패턴을 따르고 있으며,
USER_ACCESS_DENIED에러 코드를 적절히 사용하고 있습니다.src/main/java/team/wego/wegobackend/common/exception/AppErrorCode.java (1)
39-42: 에러 코드 추가가 적절합니다.
USER_ACCESS_DENIED는FORBIDDEN(403)상태를 사용하여 권한 부족을 올바르게 표현하고 있습니다.NOT_FOUND_NOTIFICATION은NOT_FOUND(404)상태를 사용하여 리소스 부재를 정확히 나타냅니다.- 후행 쉼표(trailing comma) 추가는 향후 enum 확장 시 diff를 깔끔하게 유지하는 좋은 관례입니다.
src/main/java/team/wego/wegobackend/notification/domain/Notification.java (1)
79-81: 중복 읽음 처리 시 타임스탬프 덮어쓰기 동작을 확인하세요.
markAsRead()를 여러 번 호출하면 최초 읽은 시간이 덮어씌워집니다. 만약 "최초 읽음 시간"을 보존해야 한다면 조건부 설정이 필요합니다.🔎 최초 읽음 시간 보존이 필요한 경우
public void markAsRead() { + if (this.readAt == null) { this.readAt = LocalDateTime.now(); + } }src/main/java/team/wego/wegobackend/notification/exception/NotificationNotFoundException.java (1)
6-11: 구현이 올바릅니다.표준 예외 패턴을 따르고 있으며,
NOT_FOUND_NOTIFICATION에러 코드를 적절히 사용하고 있습니다.src/main/java/team/wego/wegobackend/notification/repository/NotificationRepositoryCustom.java (1)
6-13: 커스텀 리포지토리 인터페이스 설계가 적절합니다.커서 기반 페이지네이션을 위한 메서드 시그니처가 명확하며,
cursorNotificationId를 통한 다음 페이지 조회가 가능하도록 설계되었습니다.src/main/java/team/wego/wegobackend/notification/repository/NotificationRepository.java (1)
11-17:countUnread쿼리가 올바르게 구현되었습니다.
readAt is null조건을 사용하여 읽지 않은 알림을 정확히 카운트하고 있으며, 새로운 필드 설계와 일관성을 유지하고 있습니다.src/main/java/team/wego/wegobackend/notification/repository/NotificationRepositoryImpl.java (1)
56-64:actor가 null인 경우 알림이 누락될 수 있습니다.
join(notification.actor, user)는 inner join으로 동작하여,actor가 null인 알림은 결과에서 제외됩니다. 시스템 알림처럼 actor가 없는 경우도 조회되어야 한다면leftJoin으로 변경이 필요합니다.🔎 leftJoin 사용 제안
.from(notification) - .join(notification.actor, user) + .leftJoin(notification.actor, user) .where(src/main/java/team/wego/wegobackend/notification/presentation/NotificationController.java (2)
68-80: 알림 목록 조회 - 구현이 적절합니다.커서 기반 페이지네이션과 size 검증이 잘 적용되었습니다.
@Validated추가 후 정상 동작할 것입니다.
110-113: 204 NO_CONTENT 응답에 body 포함은 비일관적입니다.HTTP 204는 일반적으로 응답 본문이 없음을 의미합니다.
ApiResponse.success(204, null)을 body로 반환하면 일부 클라이언트에서 혼란을 줄 수 있습니다. 프로젝트의 API 응답 패턴 일관성을 확인해 주세요.src/main/java/team/wego/wegobackend/notification/application/dto/response/NotificationResponse.java (2)
47-61:from(User)테스트 메서드에서readAt필드가 설정되지 않았습니다.테스트용 알림 응답 생성 시
readAt이 null로 남습니다. 클라이언트에서readAt을 기대하는 경우 문제가 될 수 있습니다. 의도적인 것인지 확인해 주세요.🔎 readAt 명시적 설정 제안
.type(NotificationType.TEST) .message("테스트 알림 응답") + .readAt(null) // 명시적으로 읽지 않음 상태 .relatedId(null)
63-90: QueryProjection 생성자 - LGTM!QueryDSL projection을 위한 생성자가 올바르게 구현되었습니다. 필드 순서가
NotificationRepositoryImpl의 projection과 일치합니다.src/main/java/team/wego/wegobackend/notification/application/NotificationService.java (2)
49-63: 단건 읽음 처리 로직 - 접근 제어가 잘 구현되었습니다.사용자가 본인의 알림만 읽음 처리할 수 있도록 검증하고, 권한 없는 경우 적절한 예외를 발생시킵니다.
34-34: Java 21 호환성 확인: 문제없음프로젝트의 build.gradle에서
languageVersion = JavaLanguageVersion.of(21)로 설정되어 있으므로,List.getLast()사용에는 호환성 문제가 없습니다. 현재 코드는 정확합니다.Likely an incorrect or invalid review comment.
| @Modifying(clearAutomatically = true, flushAutomatically = true) | ||
| @Query(""" | ||
| update Notification n | ||
| set n.readAt = CURRENT_TIMESTAMP | ||
| where n.receiver.id = :userId | ||
| and n.readAt is null | ||
| """) | ||
| int markAllAsRead(@Param("userId") Long userId); |
There was a problem hiding this comment.
CURRENT_TIMESTAMP 사용 시 일관성 및 데이터베이스 호환성을 확인하세요.
Line 22에서 CURRENT_TIMESTAMP를 사용하고 있는데, 이는 다음 문제를 야기할 수 있습니다:
-
일관성 문제: 엔티티의
markAsRead()메서드는 Java의LocalDateTime.now()를 사용하는 반면, 벌크 업데이트는 DB의CURRENT_TIMESTAMP를 사용합니다. 이 둘은 애플리케이션 서버와 DB 서버의 시간 차이로 인해 약간 다를 수 있습니다. -
데이터베이스 호환성:
CURRENT_TIMESTAMP는 MySQL에서 작동하지만, H2(테스트용), PostgreSQL 등 다른 데이터베이스에서는 함수명이나 동작이 다를 수 있습니다.
🔎 일관성을 개선하는 방법
방법 1 (권장): 애플리케이션 레벨에서 타임스탬프를 생성하여 파라미터로 전달:
-@Modifying(clearAutomatically = true, flushAutomatically = true)
-@Query("""
- update Notification n
- set n.readAt = CURRENT_TIMESTAMP
- where n.receiver.id = :userId
- and n.readAt is null
-""")
-int markAllAsRead(@Param("userId") Long userId);
+@Modifying(clearAutomatically = true, flushAutomatically = true)
+@Query("""
+ update Notification n
+ set n.readAt = :readAt
+ where n.receiver.id = :userId
+ and n.readAt is null
+""")
+int markAllAsRead(@Param("userId") Long userId, @Param("readAt") LocalDateTime readAt);그리고 서비스 레이어에서:
LocalDateTime now = LocalDateTime.now();
notificationRepository.markAllAsRead(userId, now);방법 2: JPA 표준 함수 사용 (DB 독립적):
- set n.readAt = CURRENT_TIMESTAMP
+ set n.readAt = CURRENT_TIMESTAMP()단, 이 경우에도 애플리케이션과 DB 시간 차이 문제는 여전히 존재합니다.
| profiles: | ||
| active: local |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, check the application.yml file structure and content
cat -n src/main/resources/application.ymlRepository: WeGo-Together/WeGo_BackEnd
Length of output: 2573
🏁 Script executed:
# Check for profile-specific configuration files
fd -e yml -e yaml -e properties "^application-" src/main/resources/Repository: WeGo-Together/WeGo_BackEnd
Length of output: 52
🏁 Script executed:
# Look for any deployment or build configuration
find . -type f \( -name "*.yml" -o -name "*.yaml" -o -name "*.properties" \) | grep -E "(deploy|build|env|config)" | head -20Repository: WeGo-Together/WeGo_BackEnd
Length of output: 105
🏁 Script executed:
# Check for environment setup in gradle or maven build files
find . -type f \( -name "pom.xml" -o -name "build.gradle*" \) -exec head -50 {} \;Repository: WeGo-Together/WeGo_BackEnd
Length of output: 1692
🏁 Script executed:
# Check for Docker files
fd -e dockerfile "Dockerfile*" .Repository: WeGo-Together/WeGo_BackEnd
Length of output: 52
🏁 Script executed:
# Check for GitHub Actions workflows
find .github/workflows -type f -name "*.yml" -o -name "*.yaml" 2>/dev/null | head -10Repository: WeGo-Together/WeGo_BackEnd
Length of output: 100
🏁 Script executed:
# Look for kubernetes or deployment configs
find . -type f \( -name "*.k8s.yml" -o -name "deployment.yml" -o -name "docker-compose*" \)Repository: WeGo-Together/WeGo_BackEnd
Length of output: 90
🏁 Script executed:
# Check GitHub workflows for deployment scripts
cat .github/workflows/*.yml 2>/dev/null | head -100Repository: WeGo-Together/WeGo_BackEnd
Length of output: 1398
🏁 Script executed:
# Check docker-compose setup
cat docker-compose.ymlRepository: WeGo-Together/WeGo_BackEnd
Length of output: 406
🏁 Script executed:
# Search for any production or profile-specific configs
find . -type f -name "*.yml" -o -name "*.yaml" | xargs grep -l "prod\|production" 2>/dev/null | head -10Repository: WeGo-Together/WeGo_BackEnd
Length of output: 52
프로덕션 배포 시 local 프로필이 활성화되어 애플리케이션이 실패합니다.
배포 스크립트가 스프링 프로필을 오버라이드하지 않기 때문에, 현재 설정으로 프로덕션에 배포되면 다음 문제가 발생합니다:
- Redis가
localhost:6379를 가리킴 (프로덕션 서버에 존재하지 않음) → 연결 실패 - JPA
ddl-auto: update가 활성화되어 운영 데이터베이스 스키마가 자동 수정됨 → 위험 - 개발 전용 설정들이 프로덕션에서 실행됨
필수 조치:
- 프로필 분리:
application-local.yml,application-prod.yml생성 - 배포 스크립트 수정: 배포 시
--spring.profiles.active=prod명시java -jar "$JAR" --server.port="$APP_PORT" --spring.profiles.active=prod - 프로덕션 설정 파일: Redis, DB, JPA 설정을 프로덕션 환경에 맞게 구성
🤖 Prompt for AI Agents
src/main/resources/application.yml lines 5-6: 현재 프로파일이 "local"로 고정되어 있어 프로덕션 배포
시 잘못된 설정이 적용됩니다; 이를 해결하려면 로컬 전용 설정을 application-local.yml로 옮기고 production 전용 설정을
application-prod.yml로 생성한 뒤 기본 application.yml에서 active 프로파일을 제거(또는 비워 둠)하여 환경별
프로파일로 분리하고, 배포 스크립트에서 항상 --spring.profiles.active=prod 를 명시하도록 수정하며(production에서
Redis, DB, JPA 등 민감한 설정을 application-prod.yml에 맞게 구성) 개발용 ddl-auto: update 같은
위험한 설정은 production 파일에서 제거하거나 안전한 값으로 변경하세요.
| ### 읽음 처리 (단건) | ||
| POST http://localhost:8080/api/v1/notifications/1/read | ||
| Content-Type: application/json | ||
| Authorization: Bearer {{accessToken}} |
There was a problem hiding this comment.
하드코딩된 알림 ID 사용에 주의하세요.
Line 63에서 notificationId=1을 하드코딩하고 있습니다. 실제 생성된 알림 ID는 테스트 실행 시마다 달라질 수 있으므로, 이전 단계(Line 52-55의 알림 목록 조회)에서 반환된 ID를 동적으로 추출하여 사용하는 것이 좋습니다.
🔎 제안하는 개선사항
알림 목록 조회 후 응답에서 ID를 추출:
### 알림 목록 조회
GET http://localhost:8080/api/v1/notifications?size=20
Content-Type: application/json
Authorization: Bearer {{accessToken}}
+> {%
+ client.global.set("notificationId", response.body.data.notifications[0].notificationId);
+%}
+
### 읽지 않은 알림 개수 조회
GET http://localhost:8080/api/v1/notifications/unread-count
Content-Type: application/json
Authorization: Bearer {{accessToken}}
### 읽음 처리 (단건)
-POST http://localhost:8080/api/v1/notifications/1/read
+POST http://localhost:8080/api/v1/notifications/{{notificationId}}/read
Content-Type: application/json
Authorization: Bearer {{accessToken}}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/test/http/noti/noti-api.http around lines 62 to 65, the request hardcodes
notification ID `1`; replace this with the ID extracted from the earlier
notification-list response (lines ~52-55) so tests use the actual created
notification. Update the read-request to reference a variable (e.g.,
{{notificationId}}) and add a step after the list call that parses the list
response to set that variable from the first/desired item's id using your HTTP
client’s response-extraction feature (JSONPath or similar); ensure the
extraction handles empty lists and fails the test early if no ID is found.
+ SSE test 엔드포인트 제거
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
src/main/java/team/wego/wegobackend/notification/presentation/NotificationController.java (1)
98-108: 204 NO_CONTENT 응답에 body를 포함하는 것이 적절한지 확인하세요.단건 읽음 처리와 동일한 이슈입니다. HTTP 204 NO_CONTENT 상태 코드 사용 시 응답 본문을 포함하지 않는 것이 표준이므로, API 설계 일관성과 HTTP 표준 준수 사이의 트레이드오프를 고려하세요.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/main/java/team/wego/wegobackend/notification/presentation/NotificationController.javasrc/main/java/team/wego/wegobackend/notification/presentation/NotificationControllerDocs.java
🔇 Additional comments (4)
src/main/java/team/wego/wegobackend/notification/presentation/NotificationController.java (3)
48-63: LGTM! 커서 기반 페이지네이션 구현이 적절합니다.알림 목록 조회 엔드포인트가 커서 기반 페이지네이션과 적절한 유효성 검증(1-100 범위의 size)을 사용하여 올바르게 구현되었습니다.
65-78: LGTM! 읽지 않은 알림 개수 조회 구현이 올바릅니다.간단하고 명확한 구현입니다.
85-96: 204 NO_CONTENT 응답에 body를 포함하는 것이 적절한지 확인하세요.HTTP 204 NO_CONTENT는 RFC 7231 표준에 따라 응답 본문을 포함하지 않아야 합니다. 현재
ApiResponse.success(204, null)을 사용하고 있는데, 이는 API 일관성을 위한 것으로 보이지만 표준과 다를 수 있습니다. Spring은 204 응답에서 body를 무시할 수 있으나, 명시적으로 body 없이 반환하거나 다른 상태 코드(예: 200 OK)를 사용하는 것을 고려하세요.대안:
- Body 없이 204 반환:
ResponseEntity.noContent().build()- 200 OK와 성공 메시지 반환:
ResponseEntity.ok(ApiResponse.success(200, null))src/main/java/team/wego/wegobackend/notification/presentation/NotificationControllerDocs.java (1)
22-52: LGTM! API 문서화 인터페이스가 잘 구성되었습니다.모든 엔드포인트가 적절한 Swagger 어노테이션과 명확한 한글 설명으로 문서화되어 있으며, 메서드 시그니처가 컨트롤러 구현과 정확히 일치합니다.
|
|
||
| private final SseEmitterService sseEmitterService; | ||
| private final NotificationService notificationService; | ||
| private final UserRepository userRepository; //TEST 의존성 주입 |
There was a problem hiding this comment.
테스트용 의존성을 프로덕션 코드에서 제거하세요.
UserRepository가 "TEST 의존성 주입" 주석과 함께 선언되어 있지만, 컨트롤러 내에서 실제로 사용되지 않습니다. 테스트용 의존성은 프로덕션 코드에 포함되어서는 안 됩니다.
🔎 제안하는 수정
private final SseEmitterService sseEmitterService;
private final NotificationService notificationService;
- private final UserRepository userRepository; //TEST 의존성 주입📝 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.
| private final UserRepository userRepository; //TEST 의존성 주입 | |
| private final SseEmitterService sseEmitterService; | |
| private final NotificationService notificationService; |
🤖 Prompt for AI Agents
In
src/main/java/team/wego/wegobackend/notification/presentation/NotificationController.java
around line 38, the private final UserRepository field marked "TEST 의존성 주입" is
unused in the controller; remove this test-only dependency from production code
by deleting the UserRepository field and removing it from the constructor
parameter list and assignments, then clean up the now-unused import(s) and any
references in the class or tests that relied on constructor injection (move test
wiring to test configuration or mocks instead).
| import team.wego.wegobackend.common.security.CustomUserDetails; | ||
| import team.wego.wegobackend.notification.application.dto.response.NotificationListResponse; | ||
|
|
||
| @Tag(name = "알림 API", description = "알림와 관련된 API 리스트 \uD83D\uDC08") |
There was a problem hiding this comment.
한글 문법 오류를 수정하세요.
"알림와"는 잘못된 표현입니다. "알림과"로 수정해야 합니다.
🔎 제안하는 수정
-@Tag(name = "알림 API", description = "알림와 관련된 API 리스트 🐈")
+@Tag(name = "알림 API", description = "알림과 관련된 API 리스트 🐈")📝 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.
| @Tag(name = "알림 API", description = "알림와 관련된 API 리스트 \uD83D\uDC08") | |
| @Tag(name = "알림 API", description = "알림과 관련된 API 리스트 \uD83D\uDC08") |
🤖 Prompt for AI Agents
In
src/main/java/team/wego/wegobackend/notification/presentation/NotificationControllerDocs.java
around line 19, the @Tag description contains a Korean grammar error: replace
"알림와" with the correct "알림과" so the description reads "알림과 관련된 API 리스트 🐈"
(ensure the Unicode emoji remains intact).
📝 Pull Request
📌 PR 종류
해당하는 항목에 체크해주세요.
✨ 변경 내용
알림 도메인 요구사항 건 개발 진행했습니다.
추가된 엔드포인트는 아래와 같습니다.
알림 목록 조회읽지 않은 알림 개수 조회단건 읽음 처리전체 읽음 처리주요 변경점은 아래와 같습니다.
Refresh Token 쿠키 관련 이슈 수정 있습니다. (쿠키 도메인 지정 건)
알림 Entity 일부 수정 있습니다. (테이블명 notification -> notifications, 필드 is_read -> read_at)
🔍 관련 이슈
해당 PR이 해결하는 이슈가 있다면 연결해주세요.
#162
🧪 테스트
변경된 기능에 대한 테스트 범위 또는 테스트 결과를 작성해주세요.
.http로 시나리오 테스트 진행 (팔로우 요청으로 알림 2개 생성, 알림 목록 조회, 읽지않은 알림 개수 조회, 알림 단건 읽음, 전체 알림 읽음)
readAt 동작 여부 테스트 완료

🚨 확인해야 할 사항 (Checklist)
PR을 제출하기 전에 아래 항목들을 확인해주세요.
🙋 기타 참고 사항
기능명세에 대해서는 아래 Discussions 참고하면됩니다.
추가 기능 - 알림 기능 명세서
Summary by CodeRabbit
릴리스 노트
새로운 기능
보안 개선
문서·테스트
오류 처리
✏️ Tip: You can customize this high-level summary in your review settings.