From 83a97fa12140667d67654e8e92451786c1e322b7 Mon Sep 17 00:00:00 2001 From: "gt.park" Date: Sat, 19 Jul 2025 20:49:56 +0900 Subject: [PATCH 1/3] =?UTF-8?q?:sparkles:=20=EC=84=B8=EC=85=98=20=EB=81=9D?= =?UTF-8?q?=EB=82=98=EA=B8=B0=20=EC=A0=84,=20=EC=84=B8=EC=85=98=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EB=A6=AC=EB=A7=88=EC=9D=B8=EB=93=9C=20?= =?UTF-8?q?=EC=8A=A4=EC=BC=80=EC=A4=84=EB=9F=AC=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reservation/ReservationFacade.java | 19 ++++++++++++ .../domain/notification/Notification.java | 19 ++++++++++++ .../NotificationStrategyHandler.java | 6 ++++ .../command/NotificationCommand.java | 29 +++++++++++++++++++ .../reservation/ReservationService.java | 12 ++++++-- .../reservation/ReservationController.java | 2 +- .../scheduler/ReservationScheduler.java | 8 +++++ 7 files changed, 92 insertions(+), 3 deletions(-) diff --git a/src/main/java/spring/fitlinkbe/application/reservation/ReservationFacade.java b/src/main/java/spring/fitlinkbe/application/reservation/ReservationFacade.java index ccb06347..5c84b564 100644 --- a/src/main/java/spring/fitlinkbe/application/reservation/ReservationFacade.java +++ b/src/main/java/spring/fitlinkbe/application/reservation/ReservationFacade.java @@ -31,6 +31,7 @@ import static spring.fitlinkbe.domain.common.enums.UserRole.MEMBER; import static spring.fitlinkbe.domain.common.enums.UserRole.TRAINER; import static spring.fitlinkbe.domain.notification.Notification.Reason.RESERVATION_CANCEL; +import static spring.fitlinkbe.domain.reservation.Reservation.Status.RESERVATION_APPROVED; @Component @RequiredArgsConstructor @@ -423,4 +424,22 @@ public List releaseFixedReservation(Long reservationId) { return reservationService.releaseFixedReservation(reservationId); } + @Transactional + public void sendSessionCompleteReminder() { + List inProgressReservations = reservationService.getInProgressReservations(); + + inProgressReservations.forEach(r -> { + Session session = reservationService.getSession(RESERVATION_APPROVED, r.getReservationId()); + PersonalDetail trainerDetail = trainerService.getTrainerDetail(r.getTrainer().getTrainerId()); + Token token = authService.getTokenByPersonalDetailId(trainerDetail.getPersonalDetailId()); + + notificationService.sendNotification(NotificationCommand.SessionCompleteReminder.of( + trainerDetail, + session.getSessionId(), + r.getMember().getMemberId(), + r.getName(), + token.getPushToken())); + }); + } + } diff --git a/src/main/java/spring/fitlinkbe/domain/notification/Notification.java b/src/main/java/spring/fitlinkbe/domain/notification/Notification.java index 706e8a26..8cfd74e0 100644 --- a/src/main/java/spring/fitlinkbe/domain/notification/Notification.java +++ b/src/main/java/spring/fitlinkbe/domain/notification/Notification.java @@ -181,6 +181,24 @@ public static Notification requestReservation(PersonalDetail trainerDetail, Long .build(); } + public static Notification completeReminderSession(PersonalDetail trainerDetail, Long sessionId, + Long memberId, String name) { + + String content = " %s 회원님의 PT가 곧 종료됩니다. 세션 참석 여부를 확인해주세요.".formatted(name); + + return Notification.builder() + .refId(sessionId) + .refType(ReferenceType.SESSION) + .target(UserRole.TRAINER) + .notificationType(NotificationType.SESSION_FINISHED) + .personalDetail(trainerDetail) + .partnerId(memberId) + .name(NotificationType.SESSION_FINISHED.name) + .content(content) + .sendDate(LocalDateTime.now()) + .build(); + } + public static Notification completeSession(PersonalDetail memberDetail, Long sessionId, Long memberId, String name) { @@ -342,6 +360,7 @@ public enum NotificationType { CONNECT("트레이너 연동 요청", "트레이너와 연동 요청이 왔습니다."), CONNECT_RESPONSE("트레이너 연동 처리", "트레이너와 연동 요청 결과가 생성되었습니다."), DISCONNECT("트레이너 연동 해제", "회원과 연동이 해제되었습니다."), + SESSION_FINISHED("세션 곧 종료", "곧 세션이 종료됩니다. 세션 완료 여부를 처리해주세요."), //회원 RESERVATION_CHANGE_REQUEST_APPROVED("예약 변경 요청 승인", "예약 변경 요청이 승인 되었습니다"), diff --git a/src/main/java/spring/fitlinkbe/domain/notification/NotificationStrategyHandler.java b/src/main/java/spring/fitlinkbe/domain/notification/NotificationStrategyHandler.java index 8f8dd5b2..a0b6e8bc 100644 --- a/src/main/java/spring/fitlinkbe/domain/notification/NotificationStrategyHandler.java +++ b/src/main/java/spring/fitlinkbe/domain/notification/NotificationStrategyHandler.java @@ -31,6 +31,7 @@ public void init() { strategyMap.put(Notification.NotificationType.RESERVATION_REQUESTED, this::handleRequestReservation); strategyMap.put(Notification.NotificationType.SESSION_COMPLETED, this::handleCompleteSession); strategyMap.put(Notification.NotificationType.SESSION_DEDUCTED, this::handleDeductSession); + strategyMap.put(Notification.NotificationType.SESSION_FINISHED, this::handleCompleteReminderSession); strategyMap.put(Notification.NotificationType.RESERVATION_CHANGE_REQUEST, this::handleChangeRequestReservation); strategyMap.put(Notification.NotificationType.RESERVATION_CANCEL_REQUEST_APPROVED, this::handleCancelApproveReservation); strategyMap.put(Notification.NotificationType.RESERVATION_CANCEL_REQUEST_REFUSED, this::handleCancelApproveReservation); @@ -102,6 +103,11 @@ private Notification handleCompleteSession(NotificationRequest request) { return Notification.completeSession(dto.trainerDetail(), dto.sessionId(), dto.memberId(), dto.name()); } + private Notification handleCompleteReminderSession(NotificationRequest request) { + NotificationCommand.SessionCompleteReminder dto = (NotificationCommand.SessionCompleteReminder) request; + return Notification.completeReminderSession(dto.trainerDetail(), dto.sessionId(), dto.memberId(), dto.name()); + } + private Notification handleDeductSession(NotificationRequest request) { NotificationCommand.DeductSession dto = (NotificationCommand.DeductSession) request; return Notification.deductSession(dto.memberDetail(), dto.sessionId(), dto.trainerId()); diff --git a/src/main/java/spring/fitlinkbe/domain/notification/command/NotificationCommand.java b/src/main/java/spring/fitlinkbe/domain/notification/command/NotificationCommand.java index ce79da9c..6e6442af 100644 --- a/src/main/java/spring/fitlinkbe/domain/notification/command/NotificationCommand.java +++ b/src/main/java/spring/fitlinkbe/domain/notification/command/NotificationCommand.java @@ -448,4 +448,33 @@ public static SessionChargeReminder of(PersonalDetail memberDetail, Long session } } + + @Builder + public record SessionCompleteReminder(PersonalDetail trainerDetail, Long sessionId, Long memberId, + String name, + String pushToken) + implements NotificationRequest { + @Override + public Notification.NotificationType getType() { + return Notification.NotificationType.SESSION_FINISHED; + } + + @Override + public String getPushToken() { + return this.pushToken; + } + + public static SessionCompleteReminder of(PersonalDetail trainerDetail, Long sessionId, Long memberId, + String name, + String pushToken) { + return SessionCompleteReminder.builder() + .trainerDetail(trainerDetail) + .sessionId(sessionId) + .memberId(memberId) + .name(name) + .pushToken(pushToken) + .build(); + } + + } } diff --git a/src/main/java/spring/fitlinkbe/domain/reservation/ReservationService.java b/src/main/java/spring/fitlinkbe/domain/reservation/ReservationService.java index 2dc6faeb..0706177a 100644 --- a/src/main/java/spring/fitlinkbe/domain/reservation/ReservationService.java +++ b/src/main/java/spring/fitlinkbe/domain/reservation/ReservationService.java @@ -25,8 +25,7 @@ import static spring.fitlinkbe.domain.common.exception.ErrorCode.RESERVATION_WAITING_MEMBERS_EMPTY; import static spring.fitlinkbe.domain.common.exception.ErrorCode.SESSION_CREATE_FAILED; import static spring.fitlinkbe.domain.reservation.Reservation.Status; -import static spring.fitlinkbe.domain.reservation.Reservation.Status.DISABLED_TIME_RESERVATION; -import static spring.fitlinkbe.domain.reservation.Reservation.Status.RESERVATION_WAITING; +import static spring.fitlinkbe.domain.reservation.Reservation.Status.*; import static spring.fitlinkbe.domain.reservation.Reservation.getEndDate; import static spring.fitlinkbe.domain.reservation.Session.Status.SESSION_WAITING; @@ -355,6 +354,15 @@ public void cancelLastFixedReservation(Long memberId, String message) { } } + public List getInProgressReservations() { + List reservations = reservationRepository.getReservations(); + + return reservations.stream() + .filter(r -> r.getStatus() == RESERVATION_APPROVED) + .filter(r -> r.getConfirmDate().getHour() == LocalDateTime.now().getHour()) + .toList(); + } + /** * Related Session */ diff --git a/src/main/java/spring/fitlinkbe/interfaces/controller/reservation/ReservationController.java b/src/main/java/spring/fitlinkbe/interfaces/controller/reservation/ReservationController.java index 136c7a11..b89ab0ab 100644 --- a/src/main/java/spring/fitlinkbe/interfaces/controller/reservation/ReservationController.java +++ b/src/main/java/spring/fitlinkbe/interfaces/controller/reservation/ReservationController.java @@ -57,7 +57,7 @@ public ApiResultResponse> getReservations(@ @RoleCheck(allowedRoles = {UserRole.MEMBER}) @GetMapping("/trainers") public ApiResultResponse> getTrainerReservations(@RequestParam LocalDate date, - @Login SecurityUser user) { + @Login SecurityUser user) { List result = reservationFacade.getTrainerReservations(date, user); diff --git a/src/main/java/spring/fitlinkbe/interfaces/scheduler/ReservationScheduler.java b/src/main/java/spring/fitlinkbe/interfaces/scheduler/ReservationScheduler.java index a1033616..e7a1c157 100644 --- a/src/main/java/spring/fitlinkbe/interfaces/scheduler/ReservationScheduler.java +++ b/src/main/java/spring/fitlinkbe/interfaces/scheduler/ReservationScheduler.java @@ -30,4 +30,12 @@ public void sessionReminder() { reservationFacade.checkTodaySessionReminder(); } + /** + * 매일 매 50분마다, 세션 완료 처리를 해야한다는 알림을 보낸다. + */ + @Scheduled(cron = "0 50 * * * *") // 매일 00:50:00에 실행 + public void confirmSessionReminder() { + reservationFacade.sendSessionCompleteReminder(); + } + } \ No newline at end of file From b0d514adcd28bb66c840280e06673c1a9f22f700 Mon Sep 17 00:00:00 2001 From: "gt.park" Date: Sat, 19 Jul 2025 20:50:58 +0900 Subject: [PATCH 2/3] =?UTF-8?q?:white=5Fcheck=5Fmark:=20=EC=8A=A4=EC=BC=80?= =?UTF-8?q?=EC=A4=84=EB=9F=AC=20=EA=B4=80=EB=A0=A8=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../integration/MemberIntegrationTest.java | 1 - .../ReservationIntegrationTest.java | 289 +++++++++++------- 2 files changed, 172 insertions(+), 118 deletions(-) diff --git a/src/test/java/spring/fitlinkbe/integration/MemberIntegrationTest.java b/src/test/java/spring/fitlinkbe/integration/MemberIntegrationTest.java index 7cd4830b..f356e31b 100644 --- a/src/test/java/spring/fitlinkbe/integration/MemberIntegrationTest.java +++ b/src/test/java/spring/fitlinkbe/integration/MemberIntegrationTest.java @@ -31,7 +31,6 @@ import java.time.LocalTime; import java.util.List; import java.util.Objects; - import java.util.stream.Stream; public class MemberIntegrationTest extends BaseIntegrationTest { diff --git a/src/test/java/spring/fitlinkbe/integration/ReservationIntegrationTest.java b/src/test/java/spring/fitlinkbe/integration/ReservationIntegrationTest.java index c34b9764..89ed2d4b 100644 --- a/src/test/java/spring/fitlinkbe/integration/ReservationIntegrationTest.java +++ b/src/test/java/spring/fitlinkbe/integration/ReservationIntegrationTest.java @@ -2582,123 +2582,130 @@ void approveReservationAlreadyApprovedReservation() { @Nested @DisplayName("진행한 PT 처리 Integration TEST") class CompleteSessionIntegrationTest { -// @Test -// @DisplayName("트레이너의 PT 처리 성공 - 회원이 PT 참석한 경우") -// void completeSessionWithJoinSession() { -// // given -// PersonalDetail personalDetail = personalDetailRepository.getTrainerDetail(1L) -// .orElseThrow(); -// -// String accessToken = tokenProvider.createAccessToken(PersonalDetail.Status.NORMAL, -// personalDetail.getPersonalDetailId(), personalDetail.getUserRole()); -// -// ReservationRequestDto.Complete request = ReservationRequestDto.Complete.builder() -// .memberId(1L) -// .isJoin(true) -// .build(); -// -// // 예약 생성 -// Reservation reservation = Reservation.builder() -// .reservationDates(List.of(LocalDateTime.now().plusSeconds(2))) -// .trainer(Trainer.builder().trainerId(1L).build()) -// .member(Member.builder().memberId(1L).build()) -// .status(RESERVATION_APPROVED) -// .createdAt(LocalDateTime.now().plusSeconds(2)) -// .build(); -// -// Reservation savedReservation = reservationRepository.saveReservation(reservation).orElseThrow(); -// -// // 세션 생성 -// Session session = Session.builder() -// .reservation(savedReservation) -// .status(SESSION_WAITING) -// .build(); -// -// reservationRepository.saveSession(session); -// -// // when -// ExtractableResponse result = post(LOCAL_HOST + port + PATH + "/%s/sessions/complete".formatted(1), -// request, -// accessToken); -// -// // then -// assertSoftly(softly -> { -// //예약이 잘 승인됐는지 확인 -// softly.assertThat(result.statusCode()).isEqualTo(200); -// -// ReservationResponseDto.SuccessSession content = result.body().jsonPath() -// .getObject("data", ReservationResponseDto.SuccessSession.class); -// -// softly.assertThat(content.sessionId()).isEqualTo(1L); -// softly.assertThat(content.status()).isEqualTo(Notification.NotificationType.SESSION_COMPLETED.getName()); -// -// // 세션 차감 알림이 잘 생성됐는지 확인 -// PersonalDetail memberDetail = personalDetailRepository.getMemberDetail(1L).orElseThrow(); -// Notification notification = notificationRepository.getNotification(memberDetail.getPersonalDetailId(), -// SESSION_DEDUCTED); -// softly.assertThat(notification).isNotNull(); -// softly.assertThat(notification.getNotificationType()).isEqualTo(SESSION_DEDUCTED); -// -// }); -// } - -// @Test -// @DisplayName("트레이너의 PT 처리 성공 - 회원이 PT 참석하지 않은 경우") -// void completeSessionWithNotJoinSession() { -// // given -// PersonalDetail personalDetail = personalDetailRepository.getTrainerDetail(1L) -// .orElseThrow(); -// -// String accessToken = tokenProvider.createAccessToken(PersonalDetail.Status.NORMAL, -// personalDetail.getPersonalDetailId(), personalDetail.getUserRole()); -// -// ReservationRequestDto.Complete request = ReservationRequestDto.Complete.builder() -// .memberId(1L) -// .isJoin(false) -// .build(); -// -// // 예약 생성 -// Reservation reservation = Reservation.builder() -// .reservationDates(List.of(LocalDateTime.now().plusSeconds(2))) -// .trainer(Trainer.builder().trainerId(1L).build()) -// .member(Member.builder().memberId(1L).build()) -// .status(RESERVATION_APPROVED) -// .createdAt(LocalDateTime.now().plusSeconds(2)) -// .build(); -// -// Reservation savedReservation = reservationRepository.saveReservation(reservation).orElseThrow(); -// -// // 세션 생성 -// Session session = Session.builder() -// .reservation(savedReservation) -// .status(SESSION_WAITING) -// .build(); -// -// reservationRepository.saveSession(session); -// -// // when -// ExtractableResponse result = post(LOCAL_HOST + port + PATH + "/%s/sessions/complete".formatted(1), -// request, -// accessToken); -// -// // then -// assertSoftly(softly -> { -// //예약이 잘 승인됐는지 확인 -// softly.assertThat(result.statusCode()).isEqualTo(200); -// -// ReservationResponseDto.SuccessSession content = result.body().jsonPath() -// .getObject("data", ReservationResponseDto.SuccessSession.class); -// -// softly.assertThat(content.sessionId()).isEqualTo(1L); -// softly.assertThat(content.status()).isEqualTo(SESSION_NOT_ATTEND.getName()); -// -// // 알림이 잘 생성됐는지 확인 -// List notifications = notificationRepository.getNotification(content.sessionId(), -// UserRole.MEMBER, Notification.ReferenceType.SESSION); -// softly.assertThat(notifications.get(0)).isNotNull(); -// softly.assertThat(notifications.get(0).getNotificationType()).isEqualTo(SESSION_DEDUCTED); -// }); -// } + @Test + @DisplayName("트레이너의 PT 처리 성공 - 회원이 PT 참석한 경우") + void completeSessionWithJoinSession() { + // given + PersonalDetail personalDetail = personalDetailRepository.getTrainerDetail(1L) + .orElseThrow(); + + String accessToken = tokenProvider.createAccessToken(PersonalDetail.Status.NORMAL, + personalDetail.getPersonalDetailId(), personalDetail.getUserRole()); + + ReservationRequestDto.Complete request = ReservationRequestDto.Complete.builder() + .memberId(1L) + .isJoin(true) + .build(); + + // 예약 생성 + Reservation reservation = Reservation.builder() + .reservationDates(List.of(LocalDateTime.now().plusSeconds(2))) + .trainer(Trainer.builder().trainerId(1L).build()) + .member(Member.builder().memberId(1L).build()) + .status(RESERVATION_APPROVED) + .createdAt(LocalDateTime.now().plusSeconds(2)) + .build(); + + Reservation savedReservation = reservationRepository.saveReservation(reservation).orElseThrow(); + + // 세션 생성 + Session session = Session.builder() + .reservation(savedReservation) + .status(SESSION_WAITING) + .build(); + + reservationRepository.saveSession(session); + + // 알림 생성 + PersonalDetail memberDetail = personalDetailRepository.getMemberDetail(1L).orElseThrow(); + Notification notification = Notification.approveReservation(memberDetail, savedReservation.getReservationId(), + reservation.getReservationDate(), 1L, true); + notificationRepository.save(notification); + + // when + ExtractableResponse result = post(LOCAL_HOST + port + PATH + "/%s/sessions/complete".formatted(1), + request, + accessToken); + + // then + assertSoftly(softly -> { + //예약이 잘 승인됐는지 확인 + softly.assertThat(result.statusCode()).isEqualTo(200); + + ReservationResponseDto.SuccessSession content = result.body().jsonPath() + .getObject("data", ReservationResponseDto.SuccessSession.class); + + softly.assertThat(content.sessionId()).isEqualTo(1L); + softly.assertThat(content.status()).isEqualTo(Notification.NotificationType.SESSION_COMPLETED.getName()); + softly.assertThat(notification).isNotNull(); + softly.assertThat(notification.getNotificationType()).isEqualTo(RESERVATION_APPROVE); + + }); + } + + @Test + @DisplayName("트레이너의 PT 처리 성공 - 회원이 PT 참석하지 않은 경우") + void completeSessionWithNotJoinSession() { + // given + PersonalDetail personalDetail = personalDetailRepository.getTrainerDetail(1L) + .orElseThrow(); + + String accessToken = tokenProvider.createAccessToken(PersonalDetail.Status.NORMAL, + personalDetail.getPersonalDetailId(), personalDetail.getUserRole()); + + ReservationRequestDto.Complete request = ReservationRequestDto.Complete.builder() + .memberId(1L) + .isJoin(false) + .build(); + + // 예약 생성 + Reservation reservation = Reservation.builder() + .reservationDates(List.of(LocalDateTime.now().plusSeconds(2))) + .trainer(Trainer.builder().trainerId(1L).build()) + .member(Member.builder().memberId(1L).build()) + .status(RESERVATION_APPROVED) + .createdAt(LocalDateTime.now().plusSeconds(2)) + .build(); + + Reservation savedReservation = reservationRepository.saveReservation(reservation).orElseThrow(); + + // 세션 생성 + Session session = Session.builder() + .reservation(savedReservation) + .status(SESSION_WAITING) + .build(); + + reservationRepository.saveSession(session); + + // 알림 생성 + PersonalDetail memberDetail = personalDetailRepository.getMemberDetail(1L).orElseThrow(); + Notification notification = Notification.approveReservation(memberDetail, savedReservation.getReservationId(), + reservation.getReservationDate(), 1L, true); + notificationRepository.save(notification); + + // when + ExtractableResponse result = post(LOCAL_HOST + port + PATH + "/%s/sessions/complete".formatted(1), + request, + accessToken); + + // then + assertSoftly(softly -> { + //예약이 잘 승인됐는지 확인 + softly.assertThat(result.statusCode()).isEqualTo(200); + + ReservationResponseDto.SuccessSession content = result.body().jsonPath() + .getObject("data", ReservationResponseDto.SuccessSession.class); + + softly.assertThat(content.sessionId()).isEqualTo(1L); + softly.assertThat(content.status()).isEqualTo(SESSION_NOT_ATTEND.getName()); + + // 알림이 잘 생성됐는지 확인 + List notifications = notificationRepository.getNotification(content.sessionId(), + UserRole.MEMBER, Notification.ReferenceType.SESSION); + softly.assertThat(notifications.get(0)).isNotNull(); + softly.assertThat(notifications.get(0).getNotificationType()).isEqualTo(SESSION_DEDUCTED); + }); + } @Test @DisplayName("트레이너의 PT 처리 실패 - 세션 정보 없음") @@ -3909,4 +3916,52 @@ void releaseFixedReservation() { }); } } + + @Nested + @DisplayName("세션 완료 리마인드 스케줄러 Integration TEST") + class SendSessionCompleteReminderIntegrationTest { + @Test + @DisplayName("세션 완료 리마인드 알림 성공") + void sendSessionCompleteReminder() { + // given + // 예약 생성 + Reservation reservation = Reservation.builder() + .reservationDates(List.of(LocalDateTime.now().plusSeconds(2))) + .trainer(Trainer.builder().trainerId(1L).build()) + .name("김민수") + .member(Member.builder().memberId(1L).build()) + .status(RESERVATION_APPROVED) + .confirmDate(LocalDateTime.now().plusSeconds(2)) + .createdAt(LocalDateTime.now().plusSeconds(2)) + .build(); + + Reservation savedReservation = reservationRepository.saveReservation(reservation).orElseThrow(); + + // 세션 생성 + Session session = Session.builder() + .reservation(savedReservation) + .status(SESSION_WAITING) + .build(); + + reservationRepository.saveSession(session); + + // 알림 생성 + PersonalDetail memberDetail = personalDetailRepository.getMemberDetail(1L).orElseThrow(); + Notification notification = Notification.approveReservation(memberDetail, savedReservation.getReservationId(), + reservation.getReservationDate(), 1L, true); + notificationRepository.save(notification); + + // when + reservationScheduler.confirmSessionReminder(); + + // then + assertSoftly(softly -> { + List contents = notificationRepository.getNotification(1L, + Notification.ReferenceType.SESSION); + + softly.assertThat(contents.get(0).getName()).isEqualTo(SESSION_FINISHED.getName()); + + }); + } + } } From 3fcd5ee10dd482e3308deafdb95de34f6eb30a9f Mon Sep 17 00:00:00 2001 From: "gt.park" Date: Sat, 19 Jul 2025 20:55:35 +0900 Subject: [PATCH 3/3] =?UTF-8?q?:sparkles:=20=EA=B4=80=EB=A0=A8=20enum=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20DDL=EC=97=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker/mysql/initdb.d/create_table.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/mysql/initdb.d/create_table.sql b/docker/mysql/initdb.d/create_table.sql index 3ad9e559..67d6e248 100644 --- a/docker/mysql/initdb.d/create_table.sql +++ b/docker/mysql/initdb.d/create_table.sql @@ -194,7 +194,7 @@ CREATE TABLE notification name VARCHAR(255), content VARCHAR(255), notification_type ENUM ('RESERVATION_REQUESTED','RESERVATION_CANCEL_REQUEST','RESERVATION_CHANGE_REQUEST', - 'SESSION_COMPLETED','CONNECT', 'CONNECT_RESPONSE','DISCONNECT','RESERVATION_CHANGE_REQUEST_APPROVED','RESERVATION_CHANGE_REQUEST_REFUSED', + 'SESSION_COMPLETED','SESSION_FINISHED', 'CONNECT', 'CONNECT_RESPONSE','DISCONNECT','RESERVATION_CHANGE_REQUEST_APPROVED','RESERVATION_CHANGE_REQUEST_REFUSED', 'RESERVATION_APPROVE','RESERVATION_CANCEL', 'RESERVATION_REFUSE', 'SESSION_DEDUCTED','SESSION_REMINDER', 'RESERVATION_CANCEL_REQUEST_APPROVED','RESERVATION_CANCEL_REQUEST_REFUSED','SESSION_REMAIN_5','SESSION_EDITED', 'DISCONNECT_TRAINER'),