diff --git a/src/main/java/net/teumteum/alert/app/AlertHandler.java b/src/main/java/net/teumteum/alert/app/AlertHandler.java new file mode 100644 index 0000000..2c18336 --- /dev/null +++ b/src/main/java/net/teumteum/alert/app/AlertHandler.java @@ -0,0 +1,84 @@ +package net.teumteum.alert.app; + +import static net.teumteum.alert.app.AlertExecutorConfigurer.ALERT_EXECUTOR; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import lombok.RequiredArgsConstructor; +import net.teumteum.alert.domain.Alert; +import net.teumteum.alert.domain.AlertPublisher; +import net.teumteum.alert.domain.AlertService; +import net.teumteum.alert.domain.AlertType; +import net.teumteum.alert.domain.UserAlertService; +import net.teumteum.meeting.domain.BeforeMeetingAlerted; +import net.teumteum.meeting.domain.EndMeetingAlerted; +import net.teumteum.user.UserRecommended; +import org.springframework.context.annotation.Profile; +import org.springframework.context.event.EventListener; +import org.springframework.data.util.Pair; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +@Service +@Profile("prod") +@RequiredArgsConstructor +public class AlertHandler { + + private final UserAlertService userAlertService; + private final AlertService alertService; + private final AlertPublisher alertPublisher; + + @Async(ALERT_EXECUTOR) + @EventListener(BeforeMeetingAlerted.class) + public void handleBeforeMeetingAlerts(BeforeMeetingAlerted alerted) { + userAlertService.findAllByUserId(alerted.userIds()) + .stream() + .map(userAlert -> Pair.of(userAlert.getToken(), + new Alert(null, userAlert.getUserId(), "5분 뒤에 모임이 시작돼요!", + "모임 장소로 가서 틈틈 모임을 준비해주세요.", AlertType.BEFORE_MEETING))) + .map(tokenAndAlert -> Pair.of(tokenAndAlert.getFirst(), alertService.save(tokenAndAlert.getSecond()))) + .forEach( + tokenAndAlert -> alertPublisher.publish(tokenAndAlert.getFirst(), tokenAndAlert.getSecond(), Map.of()) + ); + } + + @Async(ALERT_EXECUTOR) + @EventListener(EndMeetingAlerted.class) + public void handleStartMeetingAlerts(EndMeetingAlerted alerted) { + userAlertService.findAllByUserId(alerted.userIds()) + .stream() + .map(userAlert -> Pair.of(userAlert.getToken(), + new Alert(null, userAlert.getUserId(), alerted.meetingTitle(), + "모임이 종료되었어요", AlertType.END_MEETING))) + .map(tokenAndAlert -> Pair.of(tokenAndAlert.getFirst(), alertService.save(tokenAndAlert.getSecond()))) + .forEach(tokenAndAlert -> + alertPublisher.publish(tokenAndAlert.getFirst(), tokenAndAlert.getSecond(), + Map.of("meetingId", alerted.meetingId().toString(), "participants", + toCommaString(alerted.userIds().stream().toList()))) + ); + } + + private String toCommaString(List ids) { + var stringBuilder = new StringBuilder(); + for (int i = 0; i < ids.size() - 1; i++) { + stringBuilder.append(ids.get(i)).append(","); + } + stringBuilder.append(ids.getLast()); + return stringBuilder.toString(); + } + + @Async(ALERT_EXECUTOR) + @EventListener(UserRecommended.class) + public void handleUserRecommended(UserRecommended alerted) { + userAlertService.findAllByUserId(Set.of(alerted.userId())) + .stream() + .map(userAlert -> Pair.of(userAlert.getToken(), + new Alert(null, userAlert.getUserId(), "틈 채우기", + alerted.recommenderName() + "님이 당신을 추천했어요!", AlertType.RECOMMEND_USER))) + .map(tokenAndAlert -> Pair.of(tokenAndAlert.getFirst(), alertService.save(tokenAndAlert.getSecond()))) + .forEach(tokenAndAlert -> + alertPublisher.publish(tokenAndAlert.getFirst(), tokenAndAlert.getSecond(), Map.of()) + ); + } +} diff --git a/src/main/java/net/teumteum/alert/app/BeforeMeetingAlertHandler.java b/src/main/java/net/teumteum/alert/app/BeforeMeetingAlertHandler.java deleted file mode 100644 index eb92855..0000000 --- a/src/main/java/net/teumteum/alert/app/BeforeMeetingAlertHandler.java +++ /dev/null @@ -1,33 +0,0 @@ -package net.teumteum.alert.app; - -import static net.teumteum.alert.app.AlertExecutorConfigurer.ALERT_EXECUTOR; - -import java.time.Instant; -import lombok.RequiredArgsConstructor; -import net.teumteum.alert.domain.AlertPublisher; -import net.teumteum.alert.domain.AlertService; -import net.teumteum.alert.domain.BeforeMeetingAlert; -import net.teumteum.meeting.domain.MeetingAlerted; -import org.springframework.context.annotation.Profile; -import org.springframework.context.event.EventListener; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Service; - -@Service -@Profile("prod") -@RequiredArgsConstructor -public class BeforeMeetingAlertHandler { - - private final AlertService alertService; - private final AlertPublisher alertPublisher; - - @Async(ALERT_EXECUTOR) - @EventListener(MeetingAlerted.class) - public void alert(MeetingAlerted alerted) { - alertService.findAllByUserId(alerted.userIds()) - .stream() - .map(userAlert -> new BeforeMeetingAlert(userAlert.getUserId(), userAlert.getToken(), Instant.now())) - .forEach(alertPublisher::publish); - } - -} diff --git a/src/main/java/net/teumteum/alert/controller/AlertController.java b/src/main/java/net/teumteum/alert/controller/AlertController.java index bf998ea..9c543dc 100644 --- a/src/main/java/net/teumteum/alert/controller/AlertController.java +++ b/src/main/java/net/teumteum/alert/controller/AlertController.java @@ -3,7 +3,7 @@ import io.sentry.Sentry; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; -import net.teumteum.alert.domain.AlertService; +import net.teumteum.alert.domain.UserAlertService; import net.teumteum.alert.domain.request.RegisterAlertRequest; import net.teumteum.alert.domain.request.UpdateAlertTokenRequest; import net.teumteum.core.error.ErrorResponse; @@ -20,7 +20,7 @@ @RequiredArgsConstructor public class AlertController { - private final AlertService alertService; + private final UserAlertService alertService; private final SecurityService securityService; @PostMapping("/alerts") diff --git a/src/main/java/net/teumteum/alert/domain/Alert.java b/src/main/java/net/teumteum/alert/domain/Alert.java new file mode 100644 index 0000000..dd488d7 --- /dev/null +++ b/src/main/java/net/teumteum/alert/domain/Alert.java @@ -0,0 +1,40 @@ +package net.teumteum.alert.domain; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import net.teumteum.core.entity.TimeBaseEntity; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "alert") +@Entity(name = "alert") +public class Alert extends TimeBaseEntity { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "userId", nullable = false) + private Long userId; + + @Column(name = "title", nullable = false, length = 20) + private String title; + + @Column(name = "body", nullable = false, length = 20) + private String body; + + @Column(name = "type") + @Enumerated(EnumType.STRING) + private AlertType type; +} diff --git a/src/main/java/net/teumteum/alert/domain/AlertPublisher.java b/src/main/java/net/teumteum/alert/domain/AlertPublisher.java index 8c69ac5..4321cd7 100644 --- a/src/main/java/net/teumteum/alert/domain/AlertPublisher.java +++ b/src/main/java/net/teumteum/alert/domain/AlertPublisher.java @@ -1,8 +1,10 @@ package net.teumteum.alert.domain; +import java.util.Map; + @FunctionalInterface -public interface AlertPublisher { +public interface AlertPublisher { - void publish(T alertable); + void publish(String token, Alert alert, Map data); } diff --git a/src/main/java/net/teumteum/alert/domain/AlertRepository.java b/src/main/java/net/teumteum/alert/domain/AlertRepository.java index 33c34cf..6d999a9 100644 --- a/src/main/java/net/teumteum/alert/domain/AlertRepository.java +++ b/src/main/java/net/teumteum/alert/domain/AlertRepository.java @@ -1,22 +1,7 @@ package net.teumteum.alert.domain; -import jakarta.persistence.LockModeType; -import java.util.List; -import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Lock; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -public interface AlertRepository extends JpaRepository { - - @Query("select u from user_alert as u where u.userId in :userIds") - List findAllByUserId(@Param("userIds") Iterable userIds); - - @Lock(LockModeType.PESSIMISTIC_WRITE) - @Query("select u from user_alert as u where u.userId = :userId") - Optional findByUserIdWithLock(@Param("userId") Long userId); - - Optional findByUserId(@Param("userId") Long userId); +public interface AlertRepository extends JpaRepository { } diff --git a/src/main/java/net/teumteum/alert/domain/AlertService.java b/src/main/java/net/teumteum/alert/domain/AlertService.java index 65d0b8e..55d7f97 100644 --- a/src/main/java/net/teumteum/alert/domain/AlertService.java +++ b/src/main/java/net/teumteum/alert/domain/AlertService.java @@ -1,10 +1,6 @@ package net.teumteum.alert.domain; -import java.util.List; -import java.util.Set; import lombok.RequiredArgsConstructor; -import net.teumteum.alert.domain.request.RegisterAlertRequest; -import net.teumteum.alert.domain.request.UpdateAlertTokenRequest; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -15,26 +11,8 @@ public class AlertService { private final AlertRepository alertRepository; - @Transactional - public void registerAlert(Long userId, RegisterAlertRequest registerAlertRequest) { - alertRepository.findByUserId(userId) - .ifPresentOrElse(userAlert -> { - throw new IllegalArgumentException("이미 토큰이 생성된 user입니다. \"" + userId +"\""); - }, () -> { - var alert = new UserAlert(null, userId, registerAlertRequest.token()); - alertRepository.save(alert); - }); + public Alert save(Alert alert) { + return alertRepository.save(alert); } - @Transactional - public void updateAlertToken(Long userId, UpdateAlertTokenRequest updateAlertTokenRequest) { - var userAlert = alertRepository.findByUserIdWithLock(userId) - .orElseThrow(() -> new IllegalArgumentException("userId에 해당하는 토큰을 찾을 수 없습니다.")); - - userAlert.updateToken(updateAlertTokenRequest.token()); - } - - public List findAllByUserId(Set userIds) { - return alertRepository.findAllByUserId(userIds); - } } diff --git a/src/main/java/net/teumteum/alert/domain/AlertType.java b/src/main/java/net/teumteum/alert/domain/AlertType.java new file mode 100644 index 0000000..b32fea2 --- /dev/null +++ b/src/main/java/net/teumteum/alert/domain/AlertType.java @@ -0,0 +1,9 @@ +package net.teumteum.alert.domain; + +public enum AlertType { + + BEFORE_MEETING, + END_MEETING, + RECOMMEND_USER, + ; +} diff --git a/src/main/java/net/teumteum/alert/domain/Alertable.java b/src/main/java/net/teumteum/alert/domain/Alertable.java deleted file mode 100644 index a0cf7e1..0000000 --- a/src/main/java/net/teumteum/alert/domain/Alertable.java +++ /dev/null @@ -1,12 +0,0 @@ -package net.teumteum.alert.domain; - -public interface Alertable { - - String token(); - - String title(); - - String body(); - - String type(); -} diff --git a/src/main/java/net/teumteum/alert/domain/BeforeMeetingAlert.java b/src/main/java/net/teumteum/alert/domain/BeforeMeetingAlert.java deleted file mode 100644 index 7f863fd..0000000 --- a/src/main/java/net/teumteum/alert/domain/BeforeMeetingAlert.java +++ /dev/null @@ -1,25 +0,0 @@ -package net.teumteum.alert.domain; - -import java.time.Instant; - -public record BeforeMeetingAlert( - Long userId, - String token, - Instant publishedAt -) implements Alertable { - - @Override - public String title() { - return "5분 뒤에 모임이 시작돼요!"; - } - - @Override - public String body() { - return "모임 장소로 가서 틈틈 모임을 준비해주세요."; - } - - @Override - public String type() { - return "BEFORE_MEETING"; - } -} diff --git a/src/main/java/net/teumteum/alert/domain/UserAlertRepository.java b/src/main/java/net/teumteum/alert/domain/UserAlertRepository.java new file mode 100644 index 0000000..520e841 --- /dev/null +++ b/src/main/java/net/teumteum/alert/domain/UserAlertRepository.java @@ -0,0 +1,22 @@ +package net.teumteum.alert.domain; + +import jakarta.persistence.LockModeType; +import java.util.List; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Lock; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +public interface UserAlertRepository extends JpaRepository { + + @Query("select u from user_alert as u where u.userId in :userIds") + List findAllByUserId(@Param("userIds") Iterable userIds); + + @Lock(LockModeType.PESSIMISTIC_WRITE) + @Query("select u from user_alert as u where u.userId = :userId") + Optional findByUserIdWithLock(@Param("userId") Long userId); + + Optional findByUserId(@Param("userId") Long userId); + +} diff --git a/src/main/java/net/teumteum/alert/domain/UserAlertService.java b/src/main/java/net/teumteum/alert/domain/UserAlertService.java new file mode 100644 index 0000000..4c6cb18 --- /dev/null +++ b/src/main/java/net/teumteum/alert/domain/UserAlertService.java @@ -0,0 +1,40 @@ +package net.teumteum.alert.domain; + +import java.util.List; +import java.util.Set; +import lombok.RequiredArgsConstructor; +import net.teumteum.alert.domain.request.RegisterAlertRequest; +import net.teumteum.alert.domain.request.UpdateAlertTokenRequest; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class UserAlertService { + + private final UserAlertRepository alertRepository; + + @Transactional + public void registerAlert(Long userId, RegisterAlertRequest registerAlertRequest) { + alertRepository.findByUserId(userId) + .ifPresentOrElse(userAlert -> { + throw new IllegalArgumentException("이미 토큰이 생성된 user입니다. \"" + userId +"\""); + }, () -> { + var alert = new UserAlert(null, userId, registerAlertRequest.token()); + alertRepository.save(alert); + }); + } + + @Transactional + public void updateAlertToken(Long userId, UpdateAlertTokenRequest updateAlertTokenRequest) { + var userAlert = alertRepository.findByUserIdWithLock(userId) + .orElseThrow(() -> new IllegalArgumentException("userId에 해당하는 토큰을 찾을 수 없습니다.")); + + userAlert.updateToken(updateAlertTokenRequest.token()); + } + + public List findAllByUserId(Set userIds) { + return alertRepository.findAllByUserId(userIds); + } +} diff --git a/src/main/java/net/teumteum/alert/infra/FcmAlertPublisher.java b/src/main/java/net/teumteum/alert/infra/FcmAlertPublisher.java index aabf074..977731a 100644 --- a/src/main/java/net/teumteum/alert/infra/FcmAlertPublisher.java +++ b/src/main/java/net/teumteum/alert/infra/FcmAlertPublisher.java @@ -14,8 +14,9 @@ import com.google.firebase.messaging.Notification; import jakarta.annotation.PostConstruct; import java.io.IOException; +import java.util.Map; +import net.teumteum.alert.domain.Alert; import net.teumteum.alert.domain.AlertPublisher; -import net.teumteum.alert.domain.BeforeMeetingAlert; import org.springframework.context.annotation.Profile; import org.springframework.core.io.ClassPathResource; import org.springframework.lang.Nullable; @@ -24,18 +25,30 @@ @Service @Profile("prod") -public class FcmAlertPublisher implements AlertPublisher { +public class FcmAlertPublisher implements AlertPublisher { private static final int MAX_RETRY_COUNT = 5; private static final String FCM_TOKEN_PATH = "teum-teum-12611-firebase-adminsdk-cjyx3-ea066f25ef.json"; @Override @Async(FCM_ALERT_EXECUTOR) - public void publish(BeforeMeetingAlert beforeMeetingAlert) { - var message = buildMessage(beforeMeetingAlert); + public void publish(String token, Alert alert, Map data) { + var message = buildMessage(token, alert, data); publishWithRetry(0, message, null); } + private Message buildMessage(String token, Alert alert, Map data) { + return Message.builder() + .setToken(token) + .setNotification(buildNotification(alert)) + .setAndroidConfig(buildAndroidConfig(alert)) + .putData("publishedAt", alert.getCreatedAt().toString()) + .putData("userId", alert.getUserId().toString()) + .putData("type", alert.getType().toString()) + .putAllData(data) + .build(); + } + private void publishWithRetry(int currentRetryCount, Message message, @Nullable ErrorCode errorCode) { if (MAX_RETRY_COUNT == currentRetryCount) { return; @@ -53,28 +66,18 @@ private void publishWithRetry(int currentRetryCount, Message message, @Nullable } } - private Message buildMessage(BeforeMeetingAlert beforeMeetingAlert) { - return Message.builder() - .setToken(beforeMeetingAlert.token()) - .setNotification(buildNotification(beforeMeetingAlert)) - .setAndroidConfig(buildAndroidConfig(beforeMeetingAlert)) - .putData("publishedAt", beforeMeetingAlert.publishedAt().toString()) - .putData("userId", beforeMeetingAlert.userId().toString()) - .build(); - } - - private Notification buildNotification(BeforeMeetingAlert beforeMeetingAlert) { + private Notification buildNotification(Alert alert) { return Notification.builder() - .setTitle(beforeMeetingAlert.title()) - .setBody(beforeMeetingAlert.body()) + .setTitle(alert.getTitle()) + .setBody(alert.getBody()) .build(); } - private AndroidConfig buildAndroidConfig(BeforeMeetingAlert beforeMeetingAlert) { + private AndroidConfig buildAndroidConfig(Alert alert) { return AndroidConfig.builder() .setNotification(AndroidNotification.builder() - .setTitle(beforeMeetingAlert.title()) - .setBody(beforeMeetingAlert.body()) + .setTitle(alert.getTitle()) + .setBody(alert.getBody()) .setClickAction("push_click") .build()) .build(); diff --git a/src/main/java/net/teumteum/meeting/domain/MeetingAlerted.java b/src/main/java/net/teumteum/meeting/domain/BeforeMeetingAlerted.java similarity index 53% rename from src/main/java/net/teumteum/meeting/domain/MeetingAlerted.java rename to src/main/java/net/teumteum/meeting/domain/BeforeMeetingAlerted.java index 7461ff0..abbeeab 100644 --- a/src/main/java/net/teumteum/meeting/domain/MeetingAlerted.java +++ b/src/main/java/net/teumteum/meeting/domain/BeforeMeetingAlerted.java @@ -2,6 +2,6 @@ import java.util.Set; -public record MeetingAlerted(Set userIds) { +public record BeforeMeetingAlerted(Set userIds) { } diff --git a/src/main/java/net/teumteum/meeting/domain/EndMeetingAlerted.java b/src/main/java/net/teumteum/meeting/domain/EndMeetingAlerted.java new file mode 100644 index 0000000..3562473 --- /dev/null +++ b/src/main/java/net/teumteum/meeting/domain/EndMeetingAlerted.java @@ -0,0 +1,11 @@ +package net.teumteum.meeting.domain; + +import java.util.Set; + +public record EndMeetingAlerted( + Long meetingId, + String meetingTitle, + Set userIds +) { + +} diff --git a/src/main/java/net/teumteum/meeting/domain/MeetingRepository.java b/src/main/java/net/teumteum/meeting/domain/MeetingRepository.java index b12c037..a427ac1 100644 --- a/src/main/java/net/teumteum/meeting/domain/MeetingRepository.java +++ b/src/main/java/net/teumteum/meeting/domain/MeetingRepository.java @@ -13,7 +13,7 @@ public interface MeetingRepository extends JpaRepository, JpaSpec @Query("select m from meeting as m " + "where :startPromiseDate <= m.promiseDateTime and m.promiseDateTime < :endPromiseDate") - List findAlertMeetings(@Param("startPromiseDate") LocalDateTime currentTime, + List findAlertMeetings(@Param("startPromiseDate") LocalDateTime startPromiseDate, @Param("endPromiseDate") LocalDateTime endPromiseDate); boolean existsById(Long id); diff --git a/src/main/java/net/teumteum/meeting/service/MeetingAlertPublisher.java b/src/main/java/net/teumteum/meeting/service/MeetingAlertPublisher.java index 3d162de..f8d8192 100644 --- a/src/main/java/net/teumteum/meeting/service/MeetingAlertPublisher.java +++ b/src/main/java/net/teumteum/meeting/service/MeetingAlertPublisher.java @@ -2,7 +2,8 @@ import java.time.LocalDateTime; import lombok.RequiredArgsConstructor; -import net.teumteum.meeting.domain.MeetingAlerted; +import net.teumteum.meeting.domain.BeforeMeetingAlerted; +import net.teumteum.meeting.domain.EndMeetingAlerted; import net.teumteum.meeting.domain.MeetingRepository; import org.springframework.context.ApplicationEventPublisher; import org.springframework.scheduling.annotation.Scheduled; @@ -15,18 +16,35 @@ public class MeetingAlertPublisher { private static final String EVERY_ONE_MINUTES = "0 * * * * *"; + private static final String EVERY_12PM = "0 0 12 * * *"; private final MeetingRepository meetingRepository; private final ApplicationEventPublisher eventPublisher; @Scheduled(cron = EVERY_ONE_MINUTES) - public void alertMeeting() { + public void alertBeforeMeeting() { var alertStart = LocalDateTime.now().plusMinutes(5).withNano(0).withSecond(0); var alertEnd = alertStart.plusMinutes(1).withNano(0).withSecond(0); var alertTargets = meetingRepository.findAlertMeetings(alertStart, alertEnd); alertTargets.forEach(meeting -> eventPublisher.publishEvent( - new MeetingAlerted(meeting.getParticipantUserIds()) + new BeforeMeetingAlerted(meeting.getParticipantUserIds()) ) ); } + + @Scheduled(cron = EVERY_12PM) + public void alertEndMeeting() { + var today = LocalDateTime.now() + .withNano(0) + .withSecond(0) + .withMinute(0) + .withHour(0); + + var yesterday = today.minusDays(1); + + var alertTargets = meetingRepository.findAlertMeetings(yesterday, today); + alertTargets.forEach(meeting -> eventPublisher.publishEvent( + new EndMeetingAlerted(meeting.getId(), meeting.getTitle(), meeting.getParticipantUserIds()) + )); + } } diff --git a/src/main/java/net/teumteum/user/UserRecommended.java b/src/main/java/net/teumteum/user/UserRecommended.java new file mode 100644 index 0000000..afb9064 --- /dev/null +++ b/src/main/java/net/teumteum/user/UserRecommended.java @@ -0,0 +1,8 @@ +package net.teumteum.user; + +public record UserRecommended( + Long userId, + String recommenderName +) { + +} diff --git a/src/main/resources/db/migration/V11_create_alert.sql b/src/main/resources/db/migration/V11_create_alert.sql new file mode 100644 index 0000000..195cc38 --- /dev/null +++ b/src/main/resources/db/migration/V11_create_alert.sql @@ -0,0 +1,10 @@ +create table if not exists alert( + id bigint not null auto_increment, + userId bigint not null, + title varchar(20) not null, + `body` varchar(20) not null, + type enum('BEFORE_MEETING'), + created_at timestamp(6) not null, + updated_at timestamp(6) not null, + primary key (id) +); diff --git a/src/test/java/net/teumteum/alert/domain/AlertRepositoryTest.java b/src/test/java/net/teumteum/alert/domain/UserAlertRepositoryTest.java similarity index 90% rename from src/test/java/net/teumteum/alert/domain/AlertRepositoryTest.java rename to src/test/java/net/teumteum/alert/domain/UserAlertRepositoryTest.java index baff4e6..5d9cbb7 100644 --- a/src/test/java/net/teumteum/alert/domain/AlertRepositoryTest.java +++ b/src/test/java/net/teumteum/alert/domain/UserAlertRepositoryTest.java @@ -12,11 +12,11 @@ @DataJpaTest @ExtendWith(SpringExtension.class) -@DisplayName("AlertRepository 클래스의") -class AlertRepositoryTest { +@DisplayName("UserAlertRepository 클래스의") +class UserAlertRepositoryTest { @Autowired - private AlertRepository alertRepository; + private UserAlertRepository alertRepository; @Autowired private EntityManager entityManager; diff --git a/src/test/resources/schema.sql b/src/test/resources/schema.sql index dbf1fcb..8726e9b 100644 --- a/src/test/resources/schema.sql +++ b/src/test/resources/schema.sql @@ -93,3 +93,14 @@ create table if not exists users_reviews foreign key (users_id) references users (id) on delete cascade ); + +create table if not exists alert( + id bigint not null auto_increment, + userId bigint not null, + title varchar(20) not null, + `body` varchar(20) not null, + type enum('BEFORE_MEETING'), + created_at timestamp(6) not null, + updated_at timestamp(6) not null, + primary key (id) +);