-
Notifications
You must be signed in to change notification settings - Fork 4
[Feat] 알림 비활성화 API 추가 #368
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
워크스루사용자별 알림 유형 비활성화 기능을 추가합니다. UserDisabledAlarm 엔티티와 저장소를 도입하고, 알림 비활성화/활성화 API를 노출하며, notifyAlarm에서 사용자가 비활성화한 알림 유형을 확인하여 조기 반환합니다. 변경사항
시퀀스 다이어그램sequenceDiagram
actor Client
participant Controller as AlarmController
participant Service as AlarmService
participant Repo as UserDisabledAlarmRepository
participant DB as Database
rect rgb(220, 240, 255)
Note over Client,DB: 알림 비활성화/활성화 토글
Client->>Controller: PATCH /disable<br/>{alarmType}
Controller->>Service: disableAlarm(userDetails, request)
Service->>Repo: findByUserAndAlarmType(user, alarmType)
Repo->>DB: SELECT UserDisabledAlarm
DB-->>Repo: Optional<UserDisabledAlarm>
alt 이미 비활성화됨
Repo->>DB: DELETE UserDisabledAlarm
DB-->>Repo: ✓
Service-->>Controller: PatchDisableAlarmResponse<br/>(isDisabled=false)
else 활성화됨
Service->>Repo: save(new UserDisabledAlarm)
Repo->>DB: INSERT UserDisabledAlarm
DB-->>Repo: UserDisabledAlarm
Service-->>Controller: PatchDisableAlarmResponse<br/>(isDisabled=true)
end
Controller-->>Client: BaseResponse{data}
end
rect rgb(240, 255, 240)
Note over Client,DB: 사용자의 비활성화된 알림 목록 조회
Client->>Controller: GET /disable
Controller->>Service: findDisableAlarm(userDetails)
Service->>Repo: findByUser(user)
Repo->>DB: SELECT UserDisabledAlarm WHERE user_id=?
DB-->>Repo: List<UserDisabledAlarm>
Service->>Service: convert to GetAlarmDisableResponse
Service-->>Controller: GetAlarmDisableResponse
Controller-->>Client: BaseResponse{disabledAlarmType}
end
rect rgb(255, 240, 240)
Note over Service,DB: 알림 발송 시 비활성화 여부 확인
Service->>Service: notifyAlarm(user, alarmType, ...)
Service->>Service: isDisableAlarm(user, alarmType)
Service->>Repo: findByUserAndAlarmType(user, alarmType)
Repo->>DB: SELECT UserDisabledAlarm
DB-->>Repo: Optional<UserDisabledAlarm>
alt 비활성화됨
Service->>Service: return early
else 활성화됨
Service->>Service: send FCM message
end
end
예상 코드 리뷰 난이도🎯 3 (중간) | ⏱️ ~25분 관련 가능성 있는 PR
제안 리뷰어
시
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 2 inconclusive)
✅ 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
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/ku_rum/backend/domain/alarm/application/AlarmService.java (1)
229-239: 버그: 조건문이 항상 false로 평가됨
LAST_KNOWN_LENGTH는 상수2로 정의되어 있어,LAST_KNOWN_LENGTH != 2조건은 항상false입니다. 의도한 검증은parts.length != LAST_KNOWN_LENGTH인 것으로 보입니다.🔎 제안된 수정
if (lastKnown != null) { String[] parts = lastKnown.split("_"); - if (LAST_KNOWN_LENGTH != 2) { + if (parts.length != LAST_KNOWN_LENGTH) { throw new GlobalException(BaseExceptionResponseStatus.INVALID_CURSOR_FORMAT); }
🧹 Nitpick comments (9)
src/test/java/ku_rum/backend/domain/alarm/presentation/AlarmControllerTest.java (3)
203-204: 불필요한Boolean.valueOf(true)사용
Boolean.valueOf(true)대신true를 직접 사용하면 됩니다. 자동 박싱이 처리됩니다.🔎 제안된 수정
- PatchDisableAlarmResponse response = new PatchDisableAlarmResponse(1L, AlarmType.NEW_NOTICE, - Boolean.valueOf(true)); + PatchDisableAlarmResponse response = new PatchDisableAlarmResponse(1L, AlarmType.NEW_NOTICE, true);
252-254: 사용되지 않는 변수request
request변수가 선언되었지만 테스트에서 사용되지 않습니다. 불필요한 코드는 제거하는 것이 좋습니다.🔎 제안된 수정
- PatchDisableAlarmRequest request = new PatchDisableAlarmRequest(AlarmType.NEW_NOTICE); given(alarmService.findDisableAlarm(any())) .willReturn(response);
225-241: REST Docs에 request body 필드 문서화 누락
patchDisableAlarm테스트에서 request body에alarmType필드를 전송하지만,requestFields문서화가 누락되었습니다. API 문서 완성도를 위해 추가하는 것이 좋습니다.🔎 제안된 수정
ResourceSnippetParameters.builder() .tag("알림 조회 API") .description("특정 알림 활성화 또는 비활성화한다") .requestHeaders( headerWithName("Authorization").description("발급 받은 액세스 토큰입니다.") ) + .requestFields( + fieldWithPath("alarmType").description("알림 타입") + ) .responseFields(src/main/java/ku_rum/backend/domain/alarm/dto/request/PatchDisableAlarmRequest.java (1)
5-6:alarmType필드에 유효성 검사 누락
alarmType이 null로 전달될 경우 서비스 레이어에서 예기치 않은 동작이 발생할 수 있습니다.@NotNull어노테이션을 추가하고, 컨트롤러에서@Valid를 사용하여 요청을 검증하는 것이 좋습니다.🔎 제안된 수정
package ku_rum.backend.domain.alarm.dto.request; +import jakarta.validation.constraints.NotNull; import ku_rum.backend.domain.alarm.domain.AlarmType; -public record PatchDisableAlarmRequest(AlarmType alarmType) { +public record PatchDisableAlarmRequest(@NotNull AlarmType alarmType) { }src/main/java/ku_rum/backend/domain/alarm/presentation/AlarmController.java (2)
83-88: GET 엔드포인트 메서드명 변경 권장PATCH와 GET 엔드포인트 모두
disableAlarm이라는 동일한 메서드명을 사용하고 있습니다. 컴파일은 되지만, 가독성과 유지보수성을 위해 GET 메서드는getDisabledAlarms또는findDisabledAlarms로 명명하는 것이 좋습니다.🔎 제안된 수정
@GetMapping("/disable") - public BaseResponse<GetAlarmDisableResponse> disableAlarm( + public BaseResponse<GetAlarmDisableResponse> getDisabledAlarms( @AuthenticationPrincipal final CustomUserDetails userDetails) { GetAlarmDisableResponse response = alarmService.findDisableAlarm(userDetails); return BaseResponse.ok(response); }
75-81:@Valid어노테이션 누락
PatchDisableAlarmRequest에 유효성 검사 어노테이션이 추가되면, 컨트롤러에서@Valid를 사용하여 요청 본문을 검증해야 합니다.🔎 제안된 수정
@PatchMapping("/disable") public BaseResponse<PatchDisableAlarmResponse> disableAlarm( @AuthenticationPrincipal final CustomUserDetails userDetails, - @RequestBody PatchDisableAlarmRequest request) { + @Valid @RequestBody PatchDisableAlarmRequest request) { PatchDisableAlarmResponse response = alarmService.disableAlarm(userDetails, request); return BaseResponse.ok(response); }src/main/java/ku_rum/backend/domain/alarm/application/AlarmService.java (2)
295-301: 메서드 간소화 가능
isDisableAlarm메서드를 한 줄로 간소화할 수 있습니다.🔎 제안된 수정
private boolean isDisableAlarm(AlarmType alarmType, User user) { - Optional<UserDisabledAlarm> optional = userDisabledAlarmRepository.findByUserAndAlarmType(user, alarmType); - if (optional.isPresent()) { - return true; - } - return false; + return userDisabledAlarmRepository.findByUserAndAlarmType(user, alarmType).isPresent(); }
143-168:@Transactional(readOnly = true)적용 권장
findDisableAlarm메서드는 읽기 전용 작업입니다.@Transactional(readOnly = true)를 추가하면 JPA가 더티 체킹을 건너뛰어 성능이 향상됩니다.🔎 제안된 수정
+ @Transactional(readOnly = true) public GetAlarmDisableResponse findDisableAlarm(CustomUserDetails userDetails) { User user = userService.getUser(); List<UserDisabledAlarm> userDisabledAlarms = userDisabledAlarmRepository.findByUser(user); return GetAlarmDisableResponse.from(userDisabledAlarms); }src/main/java/ku_rum/backend/domain/alarm/domain/UserDisabledAlarm.java (1)
19-35: 데이터베이스 레벨에서 중복 방지를 위한 유니크 제약조건 추가 권장현재
(user, alarmType)조합의 고유성은 서비스 레이어에서만 보장됩니다. 데이터 무결성을 위해 데이터베이스 레벨에서 유니크 제약조건을 추가하는 것이 좋습니다.🔎 제안된 수정
@Entity +@Table(uniqueConstraints = @UniqueConstraint(columnNames = {"user_id", "alarm_type"})) @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor(access = AccessLevel.PRIVATE) @Builder @Getter public class UserDisabledAlarm extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") private User user; @Enumerated(EnumType.STRING) + @Column(name = "alarm_type") private AlarmType alarmType; }필요한 import 추가:
import jakarta.persistence.Column; import jakarta.persistence.JoinColumn; import jakarta.persistence.Table; import jakarta.persistence.UniqueConstraint;
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
src/main/java/ku_rum/backend/domain/alarm/application/AlarmService.javasrc/main/java/ku_rum/backend/domain/alarm/domain/UserDisabledAlarm.javasrc/main/java/ku_rum/backend/domain/alarm/domain/repository/UserDisabledAlarmRepository.javasrc/main/java/ku_rum/backend/domain/alarm/dto/request/PatchDisableAlarmRequest.javasrc/main/java/ku_rum/backend/domain/alarm/dto/response/GetAlarmDisableResponse.javasrc/main/java/ku_rum/backend/domain/alarm/dto/response/PatchDisableAlarmResponse.javasrc/main/java/ku_rum/backend/domain/alarm/presentation/AlarmController.javasrc/test/java/ku_rum/backend/domain/alarm/presentation/AlarmControllerTest.java
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (3)
src/main/java/ku_rum/backend/domain/alarm/dto/response/GetAlarmDisableResponse.java (1)
7-13: LGTM!팩토리 메서드 패턴을 사용하여 엔티티에서 DTO로의 변환을 깔끔하게 처리하고 있습니다.
src/main/java/ku_rum/backend/domain/alarm/domain/repository/UserDisabledAlarmRepository.java (1)
11-17: LGTM!Spring Data JPA 네이밍 규칙을 따르는 적절한 리포지토리 인터페이스입니다.
@Repository어노테이션은JpaRepository를 확장할 때 선택 사항이지만, 명시적으로 표시해도 문제없습니다.src/main/java/ku_rum/backend/domain/alarm/dto/response/PatchDisableAlarmResponse.java (1)
6-11: LGTM!엔티티에서 응답 DTO로의 변환을 위한 팩토리 메서드가 적절하게 구현되어 있습니다.
Test Results 37 files 37 suites 10s ⏱️ Results for commit deb4044. |
kmw10693
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
고생하셨습니다~
#️⃣ 연관된 이슈
closes #367
📝작업 내용
작업 상세 내용
상세 내용을 입력해주세요.
💬리뷰 요구사항
Summary by CodeRabbit
릴리스 노트
✏️ Tip: You can customize this high-level summary in your review settings.