Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
2bbe0d6
feat: Feed 도메인 이벤트 구조 추가
jj0526 Feb 8, 2026
5e78777
feat: 알림 발행을 위한 Port 인터페이스 및 DTO 추가
jj0526 Feb 8, 2026
e957861
feat: 알림 발행 정책 및 Publisher 중앙화
jj0526 Feb 8, 2026
3a186b7
feat: 코루틴 기반 NotificationService 구현
jj0526 Feb 8, 2026
f9cae6f
feat: Feed 도메인 이벤트를 알림으로 변환하는 어댑터 추가
jj0526 Feb 8, 2026
fd0b3eb
refactor: Notification 엔티티 구조 단순화
jj0526 Feb 8, 2026
78df67d
feat: getContent 메소드 추가
jj0526 Feb 8, 2026
a4713ff
refactor: FeedUsecase에서 직접 호출을 이벤트 발행으로 전환
jj0526 Feb 8, 2026
4c3d8ed
refactor: NotificationType 코틀린 마이그레이션
jj0526 Feb 8, 2026
2756c0b
refactor: NotificationType 디렉토리 위치 변경
jj0526 Feb 8, 2026
7ba0535
refactor: SqsMessageEvent 생성자 생성
jj0526 Feb 8, 2026
b0a2cb1
refactor: markNotificationAsRead() 메서드 notificationUseCase로 이동
jj0526 Feb 9, 2026
af84645
feat: Feed 도메인 이벤트에 previousReactionCount 추가
jj0526 Feb 9, 2026
1f4fa72
refactor: NotificationEntityContent 삭제
jj0526 Feb 9, 2026
e973728
refactor: FEED_REACTION_COUNT 알림 중복 체크 및 집계 로직 개선
jj0526 Feb 9, 2026
e1ad234
알림 로직 개선
jj0526 Feb 9, 2026
01d2b01
refactor: 사용하지 않는 주석 제거 및 리팩토링
jj0526 Feb 9, 2026
8a8687a
feat: sendOrUpdate 메서드 추가
jj0526 Feb 9, 2026
cb055bd
refactor: ktlint 포맷으로 변경
jj0526 Feb 9, 2026
7760fdc
Merge branch 'dev' into LNK-71-Leenk-domain-notification-코틀린-마이그레이션
jj0526 Feb 9, 2026
23f21ef
refactor: 알림 시스템을 어댑터 패턴 기반 이벤트 구조로 전환
jj0526 Feb 9, 2026
1cee64a
chore: gradle.properties 삭제
jj0526 Feb 9, 2026
0a2450e
refactor: FeedUsecaseTest에 eventPublisher 추가
jj0526 Feb 9, 2026
0ecce79
test: 알림 저장 검증을 이벤트 발행 검증으로 변경
jj0526 Feb 11, 2026
2c27215
refactor: FeedUseCase.java 삭제
jj0526 Feb 11, 2026
904a626
refactor: FeedUseCase에서 feedNotificationUsecase 의존성 삭제
jj0526 Feb 11, 2026
135491a
refactor: NotificationController에서 미사용 feedNotificationUsecase 삭제
jj0526 Feb 11, 2026
16b3f1a
refactor: 리플렉션 제거후 user.getToken으로 변경
jj0526 Feb 11, 2026
6cbcb68
refactor: NotificationType.formatContent()를 named parameter 방식으로 변경
jj0526 Feb 11, 2026
18099c3
feat: UserSetting 기반 알림 필터링 구현
jj0526 Feb 11, 2026
5172409
test: 알림에 테스트 추가
jj0526 Feb 11, 2026
29eb1e5
refactor: FeedNotificationAdapter -> FeedNotificationEventListener로 클…
jj0526 Feb 11, 2026
b7c8449
refactor: e.printStackTrace()를 SLF4J 로거로 변경
jj0526 Feb 11, 2026
a12e2a9
refactor: 사용자 알림 설정 중복 체크 로직 제거
jj0526 Feb 11, 2026
80e8843
refactor: 알림 발행 로그 추가 (NotificationPublisher)
jj0526 Feb 11, 2026
7be63af
refactor: 알림 마일스톤 검사 로직을 구조화된 필드 기반으로 개선
jj0526 Feb 11, 2026
1e83fe0
refactor: 마이그레이션 완료된 파일 사용하지 않는 메소드 삭제
jj0526 Feb 11, 2026
b8dde76
refactor: 알림 저장 트랜잭션 처리하도록 수정
jj0526 Feb 11, 2026
6a8f274
style: 개행추가
jj0526 Feb 11, 2026
7ef2c53
refactor: FeedDomainEvent를 sealed class로 변경
jj0526 Feb 12, 2026
5bd6876
refactor: UserSettingGetService import 추가
jj0526 Feb 12, 2026
8194de3
refactor: NotificationEntity에 deleteDate 추가
jj0526 Feb 12, 2026
d585c83
refactor: Feed 공감 이벤트의 totalReactionCount 계산 로직 개선
jj0526 Feb 12, 2026
cddb6d6
refactor: MongoDB 알림 처리 로직 개선 및 동시성 이슈 해결
jj0526 Feb 12, 2026
6bae775
refactor: sendBatch()에 푸시 알림 발송 추가
jj0526 Feb 12, 2026
c2fa607
refactor: sendOrUpdateWithMultiplePush 메서드로 DB 1회 저장, 푸시 개별 발행 지원
jj0526 Feb 12, 2026
74559ae
refactor: SQS 이벤트 리스너 트랜잭션 처리 방식 변경
jj0526 Feb 12, 2026
72e3936
fix: 알림 발행 시 경로 참조 위치 수정 (notificationType -> content)
jj0526 Feb 12, 2026
e215a3c
feat: 알림 서비스 예외 처리에 runCatching 추가
jj0526 Feb 12, 2026
8780959
refactor: suspend 함수와 트랜잭션 분리하여 코루틴 안정성 개선
jj0526 Feb 12, 2026
e51b6fe
test: 이벤트 발행 검증을 구체적인 타입으로 개선
jj0526 Feb 12, 2026
98c051a
test: 코루틴 기반 테스트 수정
jj0526 Feb 12, 2026
dbfd30d
test: sendOrUpdate 실패 시나리오 테스트 추가
jj0526 Feb 12, 2026
3ce17aa
test: NotificationServiceTest에서 runBlocking 제거 후 suspend delay로 교체
jj0526 Feb 22, 2026
16cdcdf
refactor: Race Condition 발생 시 pushDetails 반환 방식을 명시적으로 변경
jj0526 Feb 23, 2026
0d291b2
refactor: 마일스톤 필터 조건을 범위 검사로 변경
jj0526 Feb 23, 2026
5da3012
refactor: count 타입을 Any?에서 Long?으로 변경
jj0526 Feb 23, 2026
4697206
refactor: markNotificationAsRead를 markAsRead로 메소드명 변경
jj0526 Feb 23, 2026
11b5758
Merge branch 'dev' into LNK-71-Leenk-domain-notification-코틀린-마이그레이션
jj0526 Feb 23, 2026
1880574
refactor: !! 단언 제거 및 requireId 함수로 명시적 예외 처리
jj0526 Feb 23, 2026
1027e22
refactor: mongoTemplate 호출을 Kotlin 확장 함수로 변경
jj0526 Feb 23, 2026
28c2769
refactor: NotificationPublisher를 아웃바운드 포트 구조로 개선
jj0526 Feb 23, 2026
ff92ce1
style: ktlint 코드 스타일 오류 수정
jj0526 Feb 23, 2026
7334555
test: reactionCount 타입 Long으로 변경
jj0526 Feb 23, 2026
871db61
test: FeedNotificationEventListenerTest 및 FeedDomainEventFixture 추가
jj0526 Feb 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")

// Kotlin Coroutines
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:1.8.0")

// Spring
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public FeedFirstReactionDetail toFeedFirstReactionDetail(User user) {
.userId(user.getId())
.name(user.getName())
.title(NotificationType.FEED_FIRST_REACTION.getTitle())
.body(NotificationType.FEED_FIRST_REACTION.getContent())
.body(NotificationType.FEED_FIRST_REACTION.formatContent(user.getName(), null, null))
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public FeedReactionCountDetail toFeedReactionCountDetail(Long reactionCount) {
return FeedReactionCountDetail.builder()
.reactionCount(reactionCount)
.title(NotificationType.FEED_REACTION_COUNT.getTitle())
.body(NotificationType.FEED_REACTION_COUNT.getFormattedContent(reactionCount))
.body(NotificationType.FEED_REACTION_COUNT.formatContent(null, null, reactionCount))
.build();
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import leets.leenk.domain.notification.domain.entity.Notification;
import leets.leenk.domain.notification.domain.service.NotificationCountGetService;
import leets.leenk.domain.notification.domain.service.NotificationGetService;
import leets.leenk.domain.notification.domain.service.NotificationMarkReadService;
import leets.leenk.domain.user.domain.entity.User;
import leets.leenk.domain.user.domain.service.user.UserGetService;
import lombok.RequiredArgsConstructor;
Expand All @@ -22,6 +23,7 @@ public class NotificationUseCase {

private final UserGetService userGetService;
private final NotificationGetService notificationGetService;
private final NotificationMarkReadService notificationMarkReadService;

private final NotificationCountGetService notificationCountGetService;
private final NotificationResponseMapper notificationResponseMapper;
Expand All @@ -39,4 +41,10 @@ public NotificationCountResponse getNotificationCount(long userId) {
User user = userGetService.findById(userId);
return notificationResponseMapper.toCountResponse(notificationCountGetService.getNotificationCount(user));
}

@Transactional
public void markAsRead(Long userId, String notificationId) {
User user = userGetService.findById(userId);
notificationMarkReadService.markReadNotification(user, notificationId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,8 @@ public void markRead() {
this.isRead = true;
}

public NotificationContent getContent() {
return this.content;
}

}

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import leets.leenk.domain.notification.application.dto.response.NotificationCountResponse;
import leets.leenk.domain.notification.application.dto.response.NotificationListResponse;
import leets.leenk.domain.notification.application.exception.NotificationErrorCode;
import leets.leenk.domain.notification.application.usecase.FeedNotificationUsecase;
import leets.leenk.domain.notification.application.usecase.NotificationUseCase;
import leets.leenk.global.auth.application.annotation.CurrentUserId;
import leets.leenk.global.common.exception.ApiErrorCodeExample;
Expand All @@ -23,7 +22,6 @@
@RequiredArgsConstructor
public class NotificationController {

private final FeedNotificationUsecase feedNotificationUsecase;
private final NotificationUseCase notificationUseCase;

@Operation(summary = "최근 알림 조회 API [무한스크롤] / 사용자의 최근 알림 목록을 페이지 단위로 조회합니다. pageNumber: 0부터 시작")
Expand All @@ -46,7 +44,7 @@ public CommonResponse<NotificationCountResponse> getNotificationCount(@Parameter
@PatchMapping("/{notificationId}")
public CommonResponse<Void> markAsRead(@Parameter(hidden = true) @CurrentUserId Long userId,
@PathVariable String notificationId) {
feedNotificationUsecase.markNotificationAsRead(userId, notificationId);
notificationUseCase.markAsRead(userId, notificationId);
return CommonResponse.success(NotificationResponseCode.NOTIFICATION_MARK_AS_READ_SUCCESS);
}
}
12 changes: 12 additions & 0 deletions src/main/java/leets/leenk/domain/user/domain/entity/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -202,4 +202,16 @@ public void reRegisterFromApple(String name) {
public boolean isAgree() {
return this.termsAgreement && this.privacyAgreement;
}

// TODO: 코틀린 자바 롬복 문제. 추후 마이그레이션 후 삭제
public Long getId() {
return id;
}

public Long requireId() {
if (id == null) {
throw new IllegalStateException("영속화되지 않은 User 엔티티입니다");
}
return id;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,12 @@ public class SqsMessageEvent {
private final String path;
private final Long id;

public SqsMessageEvent(String title, String content, String fcmToken, String path, Long id) {
this.title = title;
this.content = content;
this.fcmToken = fcmToken;
this.path = path;
this.id = id;
}

}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package leets.leenk.global.sqs.application.handler;

import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;

import leets.leenk.global.sqs.application.mapper.AwsSqsManager;
import leets.leenk.global.sqs.application.dto.SqsMessageEvent;
Expand All @@ -17,7 +16,7 @@ public class SqsEventHandler {

private final AwsSqsManager awsSqsManager;

@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
@EventListener
public void handleEvent(SqsMessageEvent event) {
try {
SendMessageRequest request = awsSqsManager.createPushAlarmMessageRequest(event);
Expand Down
Loading