💻 뚝딱뚝딱/북북클럽 (bookbookclub)
[개발일지 #044] 알림 서비스 만들기 (Kafka 활용)
뚜루리
2025. 6. 17. 17:42
728x90
320x100
🎯 오늘의 개발 내용 (요약)
- Kafka 알림 시스템 구현
🧩 도입 배경
BookBookClub은 책에 대한 피드와 소셜 기능을 제공하는 SNS로, 피드 작성, 좋아요, 팔로우 이벤트에 대해 사용자에게 실시간 알림을 제공하고자 알림 기능을 구현하게 되었음.
🏛️ 아키텍처 구조
[post-service / user-service] --> Kafka Event 발행 --> [notification-service] 소비 및 저장
- post-service: 피드 작성/좋아요 발생 시 Kafka 이벤트 발행
- user-service: 팔로우 생성 시 Kafka 이벤트 발행
- notification-service: Kafka Listener로 이벤트 수신 → DB 저장
즉, notification-service로 별도 모듈을 생성하고 Kafka에서 이벤트를 발생함과 동시에 데이터베이스에도 저장하는 구조임.
🔄 구현 흐름
1. Kafka 이벤트 발행 (예: 좋아요 이벤트 발생 시)
피드 등록 서비스에서 해당 메세드 추가
// post-service
likeEventProducer.sendLikeCreated(feedId, userId);
// 이벤트 클래스 (common module)
public record LikeCreatedEvent(Long senderUserId, Long receiverUserId, Long feedId) {}
2. Kafka 리스너 수신 및 알림 저장
@Slf4j
@Service
@RequiredArgsConstructor
public class LikeCreatedEventListener {
private final NotificationService notificationService;
@KafkaListener(topics = "like.created", groupId = "notification-group")
public void handleLikeCreatedEvent(LikeCreatedEvent event) {
log.info("👍 좋아요 이벤트 수신! feedId={}, senderUserId={}, receiverUserId={}",
event.feedId(), event.senderUserId(), event.receiverUserId());
String content = "누군가 회원님의 피드에 좋아요를 눌렀어요!";
notificationService.saveNotification(event.receiverUserId(), event.feedId(), content, NotificationType.LIKE);
}
}
3. 알림 저장 엔티티
package com.bookbookclub.bbcnotificationservice.notification.entity;
import com.bookbookclub.bbcnotificationservice.notification.enums.NotificationType;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Entity
@Getter
@NoArgsConstructor
@Table(name = "notifications")
public class Notification {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/** 알림을 받는 유저 ID */
@Column(nullable = false)
private Long userId;
/** 피드 ID (알림 대상) */
private Long feedId;
/** 알림 내용 */
@Column(nullable = false)
private String content;
/** 읽음 여부 */
@Column(name = "is_read", nullable = false)
private boolean isRead = false;
/** 알림 유형 */
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private NotificationType type;
/** 삭제 여부 */
@Column(name = "is_deleted", nullable = false)
private boolean isDeleted = false;
/** 생성일시 */
private LocalDateTime createdAt;
public void markAsRead() {
this.isRead = true;
}
public void delete() {
this.isDeleted = true;
}
/**
* 생성자: 기본적으로 읽지 않은 상태로 생성
*/
private Notification(Long userId, Long feedId, String content, NotificationType type) {
this.userId = userId;
this.feedId = feedId;
this.content = content;
this.type = type;
this.createdAt = LocalDateTime.now();
this.isRead = false;
}
/**
* 정적 팩토리 메서드
*/
public static Notification from(Long userId, Long feedId, String content, NotificationType type) {
return new Notification(userId, feedId, content, type);
}
}
✅ 주요 구현 포인트
항목 | 설명 |
MSA 구조 | 알림 서비스는 독립 모듈로 분리되어 동작 |
Kafka 이벤트 기반 | 서비스 간 강결합 없이 이벤트 발행 및 수신 |
Enum 기반 타입 분리 | NotificationType(enum) 도입으로 알림 종류 명확화 |
JWT 인증 연동 | 토큰 파싱 후 유저 식별하여 알림 분기 처리 |
논리 삭제 적용 | 삭제는 DB 삭제 대신 isDeleted = true 플래그로 처리 |
728x90
320x100