package com.ga.common.notification; import com.ga.common.exception.BizException; import com.ga.common.exception.ErrorCode; import com.ga.common.util.SecurityUtil; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; /** * 앱 내(in-app) 알림 서비스. *

* 신입 메모: 이건 화면 종(벨) 아이콘에 쌓이는 "사내 알림"을 DB에 적재/조회하는 기능이다. * 외부로 나가는 SMS/알림톡/푸시(adapter 패키지)와는 별개이며, 보통 업무 이벤트가 나면 * {@link #send}로 알림을 한 건 적재하고, 사용자는 목록/안읽음 개수를 조회하고 읽음 처리한다. * 대부분의 메서드는 {@link SecurityUtil}로 현재 로그인 사용자를 기준으로 동작한다. */ @Service @RequiredArgsConstructor public class NotificationService { private final NotificationMapper mapper; /** 현재 사용자의 알림 목록. 미로그인 시 UNAUTHORIZED. */ public List myNotifications() { Long userId = SecurityUtil.getCurrentUserId(); if (userId == null) throw new BizException(ErrorCode.UNAUTHORIZED); return mapper.selectByUser(userId); } /** 현재 사용자의 안읽음 알림 개수 (벨 배지용). 미로그인 시 0. */ public int unreadCount() { Long userId = SecurityUtil.getCurrentUserId(); if (userId == null) return 0; return mapper.countUnread(userId); } /** 특정 알림 1건을 읽음 처리 (본인 알림만). */ @Transactional public void markRead(Long notiId) { Long userId = SecurityUtil.getCurrentUserId(); if (userId == null) throw new BizException(ErrorCode.UNAUTHORIZED); mapper.markRead(notiId, userId); } /** 현재 사용자의 모든 알림을 읽음 처리. */ @Transactional public void markAllRead() { Long userId = SecurityUtil.getCurrentUserId(); if (userId == null) throw new BizException(ErrorCode.UNAUTHORIZED); mapper.markAllRead(userId); } /** 알림 1건 적재(발송). 다른 도메인이 업무 이벤트 발생 시 호출한다. linkUrl은 클릭 시 이동 경로. */ @Transactional public void send(Long userId, String type, String title, String content, String linkUrl) { NotificationVO vo = new NotificationVO(); vo.setUserId(userId); vo.setNotiType(type); vo.setTitle(title); vo.setContent(content); vo.setLinkUrl(linkUrl); mapper.insert(vo); } /** 여러 사용자에게 한 번에 알림 적재 (정산 완료 등 대량 발송용). 빈 목록은 무시. */ @Transactional public void sendBatch(List list) { if (list == null || list.isEmpty()) return; mapper.insertBatch(list); } }