Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
bce7dbc
feat : λ‹‰λ„€μž„ 쀑볡 체크 (nickname unique), μΈμ¦μ½”λ“œ 검사 μ˜ˆμ™Έμ²˜λ¦¬ μΆ”κ°€
yyytir777 Dec 8, 2025
3573613
fix : user_id IDENTITY strategy & dev redis host 이름변경 (localhost -> r…
yyytir777 Dec 8, 2025
08cfb63
testμ½”λ“œ 생성 & swagger url μ‚­μ œ & ν™˜κ²½λ³€μˆ˜ 쀑볡 μ‚­μ œ
yyytir777 Dec 8, 2025
ac96fa0
fix : μ—”λ“œν¬μΈνŠΈ μΆ”κ°€
yyytir777 Dec 9, 2025
43e75ed
Merge pull request #27 from tinybite-2025/feature/13-user
yyytir777 Dec 9, 2025
a70941b
Feature/26 notification (#29)
marshmallowing Dec 11, 2025
cbbf597
feat : google login κ΅¬ν˜„ μ™„λ£Œ
yyytir777 Dec 11, 2025
d03fd30
fix : main push μ‹œμ—λ§Œ workflow trigger
yyytir777 Dec 11, 2025
00cc289
Merge branch 'main' of https://github.com/tinybite-2025/tinybite-serv…
yyytir777 Dec 11, 2025
729ae0a
Feature/#28 google apple login
yyytir777 Dec 16, 2025
b5c29db
Merge branch 'main' into develop
yyytir777 Dec 16, 2025
2e5da55
Merge branch 'develop' of https://github.com/tinybite-2025/tinybite-s…
yyytir777 Dec 18, 2025
1fbd896
merge main into develop : main의 ν•«ν”½μŠ€ 변경사항 develop에 반영
yyytir777 Dec 18, 2025
dd9771a
workflow μ€„λ°”κΏˆ μ—λŸ¬ μˆ˜μ •
yyytir777 Dec 18, 2025
38de611
hotifx : μ—λŸ¬ 핸듀링 μˆ˜μ • 및 무쀑단 배포 μ‚­μ œ (λ¦¬μ†ŒμŠ€ λ„ˆλ¬΄ 많이 먹음)
yyytir777 Dec 19, 2025
91b8cba
main의 ν•«ν”½μŠ€ develop에 반영
yyytir777 Dec 22, 2025
fbc5e90
μˆ˜μ •μ‚¬ν•­ 반영 (API 인증 κ΄€λ ¨, db schema, μ˜ˆμ™Έ 처리 λ“±..)
yyytir777 Dec 23, 2025
7b9fb7b
main브랜치 ν•«ν”½μŠ€ 반영
yyytir777 Dec 24, 2025
bbb080f
Feature/35 term (#38)
yyytir777 Dec 24, 2025
4c352aa
fix : docker compose λͺ…λ Ήμ–΄ μˆ˜μ •
yyytir777 Dec 24, 2025
27dfcbb
Feature : νŒŒν‹° κΈ°λŠ₯ (#42)
milowon Dec 27, 2025
0de3a43
Merge branch 'main' into develop
milowon Dec 31, 2025
2f27dee
hotfix : url parser 경둜 제거
milowon Dec 31, 2025
6eb0d8d
Merge branch 'main' of https://github.com/tinybite-2025/tinybite-serv…
milowon Jan 1, 2026
3f69bc1
Merge branch 'main' of https://github.com/tinybite-2025/tinybite-serv…
milowon Jan 2, 2026
45191a9
hotfix : νŒŒν‹° 거리 계산 둜직 μž„μ‹œ 주석 처리
milowon Jan 2, 2026
3a9a6e6
Merge branch 'main' of https://github.com/tinybite-2025/tinybite-serv…
milowon Jan 2, 2026
b2ca1f4
hotfix : νŒŒν‹° μˆ˜μ •, μ‚­μ œ controller μΆ”κ°€
milowon Jan 2, 2026
38ab16c
hotfix : 선택 값듀이 μ‘΄μž¬ν• λ•Œλ§Œ 넣도둝 μˆ˜μ •
milowon Jan 2, 2026
037d2e4
hotfix : μœ„λ„, 경도 둜직 μ‚­μ œ
milowon Jan 2, 2026
9d305f8
Feat : λ§ˆμ΄νŽ˜μ΄μ§€ 참여쀑인 νŒŒν‹° 쑰회 (#50)
milowon Jan 2, 2026
1cee657
hotfix : user service에 transactional μ–΄λ…Έν…Œμ΄μ…˜ μΆ”κ°€
milowon Jan 2, 2026
5213214
Merge branch 'main' of https://github.com/tinybite-2025/tinybite-serv…
milowon Jan 2, 2026
ed3a399
hotfix : 참여쀑 νŒŒν‹° 쑰회 λ°˜ν™˜ ν˜•μ‹ 톡일
milowon Jan 2, 2026
374f720
hotfix : νŒŒν‹° 생성, 쑰회 μ‹œ, 거리 계산 둜직 반영
milowon Jan 2, 2026
4ddfa39
Hotfix: μœ μ € μ’Œν‘œ μž…λ ₯ requestParam ν˜•μ‹μœΌλ‘œ λ³€κ²½
milowon Jan 2, 2026
42bc4d4
Merge branch 'main' into develop
milowon Jan 2, 2026
9ee078a
Merge branch 'main' into develop
milowon Jan 2, 2026
3be9d38
hotfix : λˆ„λ½λœ swagger λ¬Έμ„œ μˆ˜μ •μ‚¬ν•­ 반영
milowon Jan 2, 2026
89bbef3
Merge branch 'main' into develop
milowon Jan 2, 2026
b281a29
feat : νšŒμ› νƒˆν‡΄ 및 μž¬κ°€μž… λ°©μ§€, 검증 (#65)
milowon Jan 2, 2026
35a62b7
fix : νŒŒν‹° μˆ˜μ • 버그 ν”½μŠ€ (#67)
milowon Jan 2, 2026
a4f3582
hotfix : νƒˆν‡΄ μœ μ € λ§ˆμŠ€ν‚Ή 둜직 λ³€κ²½
milowon Jan 3, 2026
9f05a6a
Merge branch 'main' of https://github.com/tinybite-2025/tinybite-serv…
milowon Jan 3, 2026
d802e15
feat : λ§ˆμ΄νŽ˜μ΄μ§€μ—μ„œ 참여쀑,호슀트인 νŒŒν‹° κ΅¬λΆ„ν•΄μ„œ 쑰회 (#71)
milowon Jan 4, 2026
8715584
Feature/73 search party (#74)
yyytir777 Jan 4, 2026
78349d6
fix : μŠ€μ›¨κ±° description μΆ”κ°€
yyytir777 Jan 4, 2026
ba3d9d8
Merge branch 'main' into develop
yyytir777 Jan 4, 2026
c15e45b
Feature/73 search party (#76)
yyytir777 Jan 4, 2026
92bef29
Merge branch 'main' into develop
yyytir777 Jan 4, 2026
bd136de
Fix : 호슀트만 μžˆμ„λ•ŒλŠ” νŒŒν‹° μˆ˜μ •ν•  수 μžˆλ„λ‘ λ³€κ²½ (#78)
milowon Jan 4, 2026
5d3e13d
fix : νŒŒν‹° μ‚­μ œμ‹œ ν˜ΈμŠ€νŠΈλŠ” ν˜„μž¬μΈμ›μ—μ„œ μ œμ™Έν•˜λ„λ‘ μˆ˜μ • (#80)
milowon Jan 4, 2026
1e5b600
hotfix : jpa 넀이밍 및 쿼리 μˆ˜μ •
yyytir777 Jan 4, 2026
ba4ed25
hotfix : jpa 넀이밍 및 쿼리 μˆ˜μ •
yyytir777 Jan 4, 2026
c2d9465
Merge branch 'main' into develop
yyytir777 Jan 4, 2026
0b783c7
feat : νŒŒν‹° μΉ΄ν…Œκ³ λ¦¬, μ΅œμ‹ μˆœ, 거리순 μ •λ ¬ (#83)
milowon Jan 4, 2026
4474664
Merge branch 'main' of https://github.com/tinybite-2025/tinybite-serv…
milowon Jan 4, 2026
3353068
Feature/44 chat (#82)
yyytir777 Jan 6, 2026
6e2450c
hotfix : νŒŒν‹° μ‚­μ œ λ˜μ§€ μ•ŠλŠ” 문제 μˆ˜μ • (#86)
milowon Jan 6, 2026
b9630cf
hotfix : νŒŒν‹° μˆ˜μ •μ‚¬ν•­μ΄ db에 반영 λ˜μ§€ μ•ŠλŠ” 문제 μˆ˜μ •
milowon Jan 6, 2026
866bb84
feat : μœ μ € ν”„λ‘œν•„ 이미지 μˆ˜μ •, μ‚­μ œ (#89)
milowon Jan 6, 2026
e1fc441
Fix : μœ μ € ν”„λ‘œν•„ μˆ˜μ •, μ‚­μ œ (#91)
milowon Jan 6, 2026
64449d4
Merge branch 'main' into develop
milowon Jan 6, 2026
85f9a6e
hotfix: μœ μ € 정보 μ‘°νšŒμ‹œ ν”„λ‘œν•„ 이미지 λ°˜ν™˜ν•˜λ„λ‘ μˆ˜μ •
milowon Jan 9, 2026
17485c9
Fix/party search (#94)
yyytir777 Jan 9, 2026
e77c560
feat: νŒŒν‹° μ°Έμ—¬, 거절, μ’…λ£Œ μ•Œλ¦Ό μ—°κ²° (#97)
marshmallowing Jan 10, 2026
2826cae
fix : λ§ˆμ΄νŽ˜μ΄μ§€μ—μ„œ 참여쀑, 호슀트 νŒŒν‹° μ‘°νšŒμ‹œ μ΅œμ‹ μˆœμœΌλ‘œ μ‘°νšŒλ˜λ„λ‘ μˆ˜μ • (#98)
milowon Jan 10, 2026
cf0f51d
Merge branch 'main' into develop
milowon Jan 10, 2026
f02e7eb
feat : νŒŒν‹° μƒμ„±μ‹œ 이미지 없을 경우 λ””ν΄νŠΈ 이미지 λ°˜ν™˜ν•˜λ„λ‘ μˆ˜μ • (#100)
milowon Jan 10, 2026
72accaf
feat: μ±„νŒ… μ•Œλ¦Ό 단체/개인 ꡬ뢄 (#102)
marshmallowing Jan 10, 2026
8fa6f24
fix : μ±„νŒ…λ°© μœ ν˜• 별 μ•Œλ¦Ό λ³€κ²½
yyytir777 Jan 10, 2026
0707f62
Feat : νŒŒν‹° λͺ©λ‘ λ””ν΄νŠΈ 이미지 ν•„λ“œ μΆ”κ°€ (#104)
milowon Jan 10, 2026
02c3e16
Fix : νŒŒν‹° 썸넀일 이미지 μ£Όμž…λ˜λ„λ‘ valueκ°’ μˆ˜μ • (#106)
milowon Jan 10, 2026
5c230a6
Merge branch 'main' into develop
milowon Jan 10, 2026
7611fd9
Feature/44 chat (#107)
yyytir777 Jan 10, 2026
0a416c4
hotfix: νŒŒν‹° μ„ΈλΆ€ μ‘°νšŒμ‹œ λ””ν΄νŠΈ 이미지 ν•„λ“œ μˆ˜μ •
milowon Jan 10, 2026
69c48b8
Feature/103 νŒŒν‹°μž₯ λ¦¬λ§ˆμΈλ“œ μ•Œλ¦Ό (#110)
marshmallowing Jan 10, 2026
0f4ea15
Merge branch 'main' into develop
yyytir777 Jan 10, 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
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package ita.tinybite.domain.notification.infra.fcm; // λ³„λ„μ˜ scheduler νŒ¨ν‚€μ§€ ꢌμž₯
package ita.tinybite.domain.notification.infra.scheduler;

import ita.tinybite.domain.notification.service.FcmTokenService;
import lombok.RequiredArgsConstructor;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package ita.tinybite.domain.notification.infra.scheduler;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.Set;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.fasterxml.jackson.databind.ObjectMapper;

import ita.tinybite.domain.notification.service.facade.NotificationFacade;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Component
@RequiredArgsConstructor
@Slf4j
public class NotificationScheduler {

private final RedisTemplate<String, String> redisTemplate;
private final ObjectMapper objectMapper;
private final NotificationFacade notificationFacade;

@Scheduled(cron = "0 * * * * *") // 1λΆ„λ§ˆλ‹€
public void processPendingApprovalReminders() {
Set<String> keys = redisTemplate.keys("pending_reminder:*");
if (keys.isEmpty()) return;

LocalDateTime now = LocalDateTime.now();

for (String key : keys) {
try {
// Redisμ—μ„œ JSON λ¬Έμžμ—΄ κ°€μ Έμ˜€κΈ°
String jsonValue = redisTemplate.opsForValue().get(key);
if (jsonValue == null) continue;

Map<String, Object> data = objectMapper.readValue(jsonValue, Map.class);

Long hostId = Long.valueOf(data.get("hostId").toString());
Long partyId = Long.valueOf(data.get("partyId").toString());
Long requesterId = Long.valueOf(data.get("requesterId").toString());
String requesterNickname = (String) data.get("requesterNickname");
int retryCount = (int) data.get("retryCount");
LocalDateTime lastSentAt = LocalDateTime.parse((String) data.get("lastSentAt"));

// 10λΆ„ 확인
if (now.isAfter(lastSentAt.plusMinutes(10))) {

if (retryCount >= 3) {
log.info("λ¦¬λ§ˆμΈλ“œ 3회 초과둜 μžλ™ μ‚­μ œ: {}", key);
redisTemplate.delete(key);
continue;
}

notificationFacade.notifyPendingApprovalReminder(
hostId,
partyId,
requesterId,
requesterNickname
);

data.put("retryCount", retryCount + 1);
data.put("lastSentAt", now.toString());

redisTemplate.opsForValue().set(key, objectMapper.writeValueAsString(data));

log.info("λ¦¬λ§ˆμΈλ“œ μ•Œλ¦Ό λ°œμ†‘ 및 데이터 κ°±μ‹  μ™„λ£Œ: {}회차", retryCount + 1);
}
} catch (Exception e) {
log.error("λ¦¬λ§ˆμΈλ“œ μŠ€μΌ€μ€„λŸ¬ 처리 쀑 μ—λŸ¬ λ°œμƒ (Key: {}): {}", key, e.getMessage());
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
package ita.tinybite.domain.notification.service;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.firebase.messaging.BatchResponse;

import ita.tinybite.domain.notification.dto.request.NotificationMulticastRequest;
import ita.tinybite.domain.notification.enums.NotificationType;
import ita.tinybite.domain.notification.infra.fcm.FcmNotificationSender;
import ita.tinybite.domain.notification.infra.helper.NotificationTransactionHelper;
import ita.tinybite.domain.notification.service.manager.PartyMessageManager;
import ita.tinybite.domain.user.entity.User;
import ita.tinybite.domain.user.repository.UserRepository;
import ita.tinybite.global.exception.BusinessException;
import ita.tinybite.global.exception.errorcode.CommonErrorCode;
import ita.tinybite.global.exception.errorcode.UserErrorCode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

Expand All @@ -25,6 +36,9 @@ public class PartyNotificationService {
private final PartyMessageManager partyMessageManager;
private final NotificationLogService notificationLogService;
private final NotificationTransactionHelper notificationTransactionHelper;
private final RedisTemplate<String, String> redisTemplate;
private final ObjectMapper objectMapper; // JSON λ³€ν™˜μ„ μœ„ν•΄
private final UserRepository userRepository;

//
@Transactional
Expand Down Expand Up @@ -202,4 +216,46 @@ public void sendMemberLeaveNotification(Long managerId, Long partyId, String lea
BatchResponse response = fcmNotificationSender.send(request);
notificationTransactionHelper.handleBatchResponse(response, tokens);
}

@Transactional
public void reservePendingApprovalReminder(Long managerId, Long requesterId, Long partyId) {
User requester = userRepository.findById(requesterId)
.orElseThrow(() -> new BusinessException(UserErrorCode.USER_NOT_EXISTS));

String key = "pending_reminder:" + partyId + ":" + requesterId;

Map<String, Object> reminderData = new HashMap<>();
reminderData.put("hostId", managerId);
reminderData.put("requesterId", requesterId);
reminderData.put("requesterNickname", requester.getNickname());
reminderData.put("partyId", partyId);
reminderData.put("lastSentAt", LocalDateTime.now().toString());
reminderData.put("retryCount", 0);

try {
String jsonValue = objectMapper.writeValueAsString(reminderData);
redisTemplate.opsForValue().set(key, jsonValue);
} catch (JsonProcessingException e) {
throw new BusinessException(CommonErrorCode.INTERNAL_SERVER_ERROR);
}
}

@Transactional
public void sendPendingApprovalReminder(Long managerId, String requesterNickname, Long partyId) {
String title = "⏰ μ°Έμ—¬ μš”μ²­μ΄ 기닀리고 μžˆμ–΄μš”";
String detail = String.format("%sλ‹˜μ΄ 아직 응닡을 기닀리고 μžˆμ–΄μš”", requesterNickname);

notificationLogService.saveLog(managerId, "PENDING_APPROVAL_REMINDER", title, detail);

List<String> tokens = fcmTokenService.getTokensAndLogIfEmpty(managerId);
if (tokens.isEmpty()) {
return;
}

NotificationMulticastRequest request =
partyMessageManager.createPendingApprovalReminderRequest(tokens, partyId, title, detail);

BatchResponse response = fcmNotificationSender.send(request);
notificationTransactionHelper.handleBatchResponse(response, tokens);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

import java.util.List;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import ita.tinybite.domain.notification.service.ChatNotificationService;
import ita.tinybite.domain.notification.service.PartyNotificationService;
import ita.tinybite.domain.party.entity.Party;
import ita.tinybite.domain.party.enums.ParticipantStatus;
import ita.tinybite.domain.party.repository.PartyParticipantRepository;
import ita.tinybite.domain.party.repository.PartyRepository;
import ita.tinybite.domain.user.entity.User;
import ita.tinybite.domain.user.repository.UserRepository;
Expand All @@ -31,6 +34,9 @@ public class NotificationFacade {

private final PartyRepository partyRepository;
private final UserRepository userRepository;
private final PartyParticipantRepository partyParticipantRepository;

private final RedisTemplate<String, String> redisTemplate;

@Transactional
public void notifyNewPartyRequest(Long managerId, Long requesterId, Long partyId) {
Expand All @@ -48,7 +54,6 @@ public void notifyNewPartyRequest(Long managerId, Long requesterId, Long partyId
);
}

@Transactional
public void notifyApproval(Long targetUserId, Long partyId) {
Party party = partyRepository.findById(partyId)
.orElseThrow(() -> new BusinessException(PartyErrorCode.PARTY_NOT_FOUND));
Expand All @@ -62,7 +67,6 @@ public void notifyRejection(Long targetUserId, Long partyId) {
}

// 인원 λͺ¨μ§‘ μ™„λ£Œ
@Transactional
public void notifyPartyAutoClose(List<Long> memberIds, Long partyId, Long managerId) {
Party party = partyRepository.findById(partyId)
.orElseThrow(() -> new BusinessException(PartyErrorCode.PARTY_NOT_FOUND));
Expand All @@ -71,39 +75,25 @@ public void notifyPartyAutoClose(List<Long> memberIds, Long partyId, Long manage
}

// νŒŒν‹° μ’…λ£Œ
@Transactional
public void notifyPartyComplete(List<Long> memberIds, Long partyId) {
Party party = partyRepository.findById(partyId)
.orElseThrow(() -> new BusinessException(PartyErrorCode.PARTY_NOT_FOUND));

partyNotificationService.sendPartyCompleteNotification(memberIds, party.getTitle(), partyId);
}

@Transactional
public void notifyOrderComplete(List<Long> memberIds, Long partyId) {
partyNotificationService.sendOrderCompleteNotification(memberIds, partyId);
}

@Transactional
public void notifyDeliveryReminder(List<Long> memberIds, Long partyId, Long managerId) {
partyNotificationService.sendDeliveryReminderNotification(memberIds, partyId, managerId);
}

@Transactional
public void notifyMemberLeave(Long managerId, Long partyId, String leaverName) {
partyNotificationService.sendMemberLeaveNotification(managerId, partyId, leaverName);
}

/*
public void notifyNewChatMessage(
Long targetUserId,
Long chatRoomId,
String senderName,
String messageContent
) {
chatNotificationService.sendNewChatMessage(targetUserId, chatRoomId, senderName, messageContent);
}*/

// 1:1 μ±„νŒ…
public void notifyOneToOneChat(Long targetUserId, Long chatRoomId, String senderName, String content) {
chatNotificationService.sendOneToOneChatMessage(targetUserId, chatRoomId, senderName, content);
Expand All @@ -124,10 +114,39 @@ public void notifyGroupImage(Long targetUserId, Long chatRoomId, String partyTit
chatNotificationService.sendGroupChatImage(targetUserId, chatRoomId, partyTitle, senderName);
}

// 승인 λŒ€κΈ° λ¦¬λ§ˆμΈλ“œ 생성(λ ˆλ””μŠ€ 등둝)
public void reservePartyRequestReminder(Long managerId, Long requesterId, Long partyId) {
partyNotificationService.reservePendingApprovalReminder(
managerId,
requesterId,
partyId
);
}

// μŠ€μΌ€μ€„λŸ¬κ°€ 호좜
public void notifyPendingApprovalReminder(Long hostId, Long partyId, Long requesterId, String requesterNickname) {
// PENDING 확인
boolean isStillPending = partyParticipantRepository
.existsByParty_IdAndUser_UserIdAndStatus(partyId, requesterId, ParticipantStatus.PENDING);

if (isStillPending) {
partyNotificationService.sendPendingApprovalReminder(hostId, requesterNickname, partyId);
} else {
// 이미 승인/κ±°μ ˆλ˜μ—ˆλ‹€λ©΄ Redisμ—μ„œ μ‚­μ œ
String key = "pending_reminder:" + partyId + ":" + requesterId;
redisTemplate.delete(key);
}
}

// μŠ€μΌ€μ€„λŸ¬/μ±„νŒ… μ„œλΉ„μŠ€κ°€ ν˜ΈμΆœν•˜λ©°, μ•Œλ¦Ό 도메인은 μ „μ†‘λ§Œ 처리(보λ₯˜)
@Transactional
public void notifyUnreadReminder(Long targetUserId, Long chatRoomId) {
chatNotificationService.sendUnreadReminderNotification(targetUserId, chatRoomId);
}

@Transactional
public void cancelPendingApprovalReminder(Long partyId, Long requesterId) {
String key = "pending_reminder:" + partyId + ":" + requesterId;
redisTemplate.delete(key);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,13 @@ public NotificationMulticastRequest createMemberLeaveRequest(List<String> tokens

return requestConverter.toMulticastRequest(tokens, title, detail, data);
}

public NotificationMulticastRequest createPendingApprovalReminderRequest(List<String> tokens, Long partyId, String title, String detail) {
Map<String, String> data = new HashMap<>();
data.put(KEY_PARTY_ID, String.valueOf(partyId));

data.put(KEY_EVENT_TYPE, "PENDING_APPROVAL_REMINDER");

return requestConverter.toMulticastRequest(tokens, title, detail, data);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,10 @@ List<PartyParticipant> findActivePartiesByUserIdExcludingHost(
int countByPartyIdAndStatusAndUser_UserIdNot(Long partyId, ParticipantStatus participantStatus, Long userId);

List<PartyParticipant> findAllByPartyAndStatus(Party party, ParticipantStatus status);

boolean existsByParty_IdAndUser_UserIdAndStatus(
Long partyId,
Long userId,
ParticipantStatus status
);
}
14 changes: 14 additions & 0 deletions src/main/java/ita/tinybite/domain/party/service/PartyService.java
Original file line number Diff line number Diff line change
Expand Up @@ -243,12 +243,20 @@ public Long joinParty(Long partyId, Long userId) {

PartyParticipant saved = partyParticipantRepository.save(participant);

// μ¦‰μ‹œ μ•Œλ¦Ό λ°œμ†‘
notificationFacade.notifyNewPartyRequest(
party.getHost().getUserId(), // νŒŒν‹°μž₯ ID
userId, // μ‹ μ²­μž ID
partyId
);

// λ¦¬λ§ˆμΈλ“œ 등둝
notificationFacade.reservePartyRequestReminder(
party.getHost().getUserId(),
userId,
partyId
);

return oneToOneChatRoom.getId();
}

Expand Down Expand Up @@ -459,6 +467,9 @@ public void approveParticipant(Long partyId, Long participantId, Long hostId) {
// 단체 μ±„νŒ…λ°©μ— μ°Έμ—¬μž μΆ”κ°€
groupChatRoom.addMember(participant.getUser());

// λ¦¬λ§ˆμΈλ“œ μ˜ˆμ•½ μ‚­μ œ
notificationFacade.cancelPendingApprovalReminder(partyId, participant.getUser().getUserId());

// 승인 μ•Œλ¦Ό
notificationFacade.notifyApproval(
participant.getUser().getUserId(),
Expand Down Expand Up @@ -492,6 +503,9 @@ public void rejectParticipant(Long partyId, Long participantId, Long hostId) {
participant.getOneToOneChatRoom().deactivate();
}

// λ¦¬λ§ˆμΈλ“œ μ˜ˆμ•½ μ‚­μ œ
notificationFacade.cancelPendingApprovalReminder(partyId, participant.getUser().getUserId());

notificationFacade.notifyRejection(
participant.getUser().getUserId(),
partyId
Expand Down