Skip to content

[WTH-20] 알림 유형별 수신 설정 및 비동기 1 - #136

Open
soo0711 wants to merge 5 commits into
devfrom
feat/WTH-20-알림-유형별-수신-설정-및-비동기

Hidden character warning

The head ref may contain hidden characters: "feat/WTH-20-\uc54c\ub9bc-\uc720\ud615\ubcc4-\uc218\uc2e0-\uc124\uc815-\ubc0f-\ube44\ub3d9\uae30"
Open

soo0711 wants to merge 5 commits into
devfrom
feat/WTH-20-알림-유형별-수신-설정-및-비동기

Conversation

@soo0711

@soo0711 soo0711 commented Nov 8, 2026 •

Copy link
Copy Markdown
Collaborator

📌 Summary

어떤 작업인지 한 줄 요약해 주세요.

공지 알림 발송을 Transactional Outbox와 SQS 기반으로 분리하고 중복 처리 방지·재시도·실패 추적을 구현했습니다.

📝 Changes

변경사항을 what, why, how로 구분해 작성해 주세요.

What

  • 알림 이벤트 선점 및 Delivery·Target·Outbox 저장 모델 추가
  • SQS 게시 Relay와 전용 발송 워커 구현
  • FCM 토큰별 성공·일시 실패·영구 실패 결과 반영
  • 재시도 소진 작업의 DLQ 감사 및 명시적 재처리 지원
  • 재처리 세대 분리 및 Relay 선점 범위 제한

Why

  • 요청 트랜잭션 이후 서버가 종료되어도 발송 작업을 복구하기 위해
  • 외부 발송 지연이 사용자 요청 응답에 영향을 주지 않도록 하기 위해
  • 성공한 토큰의 중복 재시도와 만료된 워커의 결과 덮어쓰기를 방지하기 위해

How

  • 앱 내 알림·Delivery·Outbox를 원본 트랜잭션에 함께 저장합니다.
  • Relay가 커밋된 Outbox를 최대 10개씩 선점하고 트랜잭션 밖에서 SQS에 게시합니다.
  • 워커가 수신 설정·회원 자격·토큰 정보를 재확인한 뒤 FCM을 호출합니다.
  • lease·claim token·heartbeat로 선점을 관리하고 결과 커밋 후 메시지를 삭제합니다.
  • 일시 실패는 기본 5회까지 backoff와 jitter를 적용해 재시도하며 성공 토큰은 제외합니다.
  • 재처리 시 세대를 증가시켜 과거 큐·DLQ 메시지가 새 작업에 영향을 주지 않도록 합니다.

📸 Screenshots / Logs

필요시 스크린샷 or 로그를 첨부해주세요.

💡 Reviewer 참고사항

리뷰에 참고할 내용을 작성해주세요.

  • 전체 변경량이 커서 PR을 1차·2차로 나누어 진행합니다.

✅ Checklist

  • PR 제목 설정 완료 (WTH-123 인증 필터 설정)
  • 테스트 구현 완료
  • 리뷰어 등록 완료
  • 자체 코드 리뷰 완료

@soo0711
soo0711 requested review from hyxklee and woneeeee November 8, 2026 15:43
@soo0711 soo0711 self-assigned this Nov 8, 2026
@soo0711 soo0711 added the ✨ Feature 새로운 기능 추가 label Nov 8, 2026
@coderabbitai

coderabbitai Bot commented Nov 8, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 108 files, which is 8 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 81a10e5e-3ad2-4b7a-959b-dfc382ccb52e
Commits

Reviewing files that changed from the base of the PR and between 871fe04 and 2e25d7a.

Files selected for processing: 108

  • build.gradle.kts
  • src/main/kotlin/com/weeth/domain/notification/application/dispatch/NotificationDeliveryProcessor.kt
  • src/main/kotlin/com/weeth/domain/notification/application/dispatch/NotificationDeliveryWorker.kt
  • src/main/kotlin/com/weeth/domain/notification/application/dispatch/NotificationDispatchMaintenance.kt
  • src/main/kotlin/com/weeth/domain/notification/application/dispatch/NotificationOutboxRelay.kt
  • src/main/kotlin/com/weeth/domain/notification/application/dto/request/NotificationPreferenceItemRequest.kt
  • src/main/kotlin/com/weeth/domain/notification/application/dto/request/UpdateNotificationPreferencesRequest.kt
  • src/main/kotlin/com/weeth/domain/notification/application/dto/response/NotificationCategoryPreferenceResponse.kt
  • src/main/kotlin/com/weeth/domain/notification/application/dto/response/NotificationPreferencesResponse.kt
  • src/main/kotlin/com/weeth/domain/notification/application/event/CreateNoticeNotificationEventListener.kt
  • src/main/kotlin/com/weeth/domain/notification/application/event/NotificationCreatedEvent.kt
  • src/main/kotlin/com/weeth/domain/notification/application/event/SendPushNotificationEventListener.kt
  • src/main/kotlin/com/weeth/domain/notification/application/exception/InvalidNotificationPreferenceException.kt
  • src/main/kotlin/com/weeth/domain/notification/application/exception/NotificationErrorCode.kt
  • src/main/kotlin/com/weeth/domain/notification/application/mapper/NotificationPreferenceMapper.kt
  • src/main/kotlin/com/weeth/domain/notification/application/usecase/command/CreateNotificationUseCase.kt
  • src/main/kotlin/com/weeth/domain/notification/application/usecase/command/EnqueueNotificationDeliveryUseCase.kt
  • src/main/kotlin/com/weeth/domain/notification/application/usecase/command/ManageNotificationDeliveryUseCase.kt
  • src/main/kotlin/com/weeth/domain/notification/application/usecase/command/ManageNotificationOutboxUseCase.kt
  • src/main/kotlin/com/weeth/domain/notification/application/usecase/command/ManageNotificationPreferenceUseCase.kt
  • src/main/kotlin/com/weeth/domain/notification/application/usecase/query/GetNotificationPreferenceQueryService.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/entity/NotificationDelivery.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/entity/NotificationDeliveryTarget.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/entity/NotificationEvent.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/entity/NotificationFailure.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/entity/NotificationOutbox.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/entity/NotificationPreference.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/entity/NotificationQueueIncident.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/entity/NotificationSetting.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/entity/UserNotification.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/enums/NotificationCategory.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/enums/NotificationChannel.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/enums/NotificationDeliveryAction.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/enums/NotificationDeliveryStatus.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/enums/NotificationOutboxStatus.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/enums/NotificationPreferenceUpdateFailure.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/enums/NotificationTargetStatus.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/enums/NotificationTemplateFailureReason.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/enums/NotificationType.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/enums/PushTargetStatus.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/port/NotificationQueuePort.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/port/NotificationTemplateProvider.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/repository/NotificationDeliveryRepository.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/repository/NotificationDeliveryTargetRepository.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/repository/NotificationEventRepository.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/repository/NotificationFailureRepository.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/repository/NotificationOutboxRepository.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/repository/NotificationPreferenceRepository.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/repository/NotificationQueueIncidentRepository.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/repository/NotificationSettingRepository.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/repository/NotificationTokenRepository.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/service/NotificationPreferencePolicy.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/service/NotificationRecipientPolicy.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/service/NotificationRetryPolicy.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/service/NotificationTemplateRenderer.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/vo/NotificationContent.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/vo/NotificationDeliveryAttempt.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/vo/NotificationDeliveryPreparation.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/vo/NotificationOutboxDispatch.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/vo/NotificationQueueMessage.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/vo/NotificationQueueReceipt.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/vo/NotificationRenderingResult.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/vo/NotificationRequest.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/vo/NotificationTemplate.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/vo/NotificationTokenSnapshot.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/vo/PushNotificationResult.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/vo/PushTargetOutcome.kt
  • src/main/kotlin/com/weeth/domain/notification/domain/vo/RenderedNotification.kt
  • src/main/kotlin/com/weeth/domain/notification/infrastructure/CodeNotificationTemplateProvider.kt
  • src/main/kotlin/com/weeth/domain/notification/infrastructure/FcmPushNotificationSenderAdapter.kt
  • src/main/kotlin/com/weeth/domain/notification/infrastructure/JdbcUserNotificationBulkWriterAdapter.kt
  • src/main/kotlin/com/weeth/domain/notification/infrastructure/SqsNotificationQueueAdapter.kt
  • src/main/kotlin/com/weeth/domain/notification/presentation/NotificationPreferenceController.kt
  • src/main/kotlin/com/weeth/domain/notification/presentation/NotificationResponseCode.kt
  • src/main/kotlin/com/weeth/global/config/FirebaseConfig.kt
  • src/main/kotlin/com/weeth/global/config/NotificationDispatchConfig.kt
  • src/main/kotlin/com/weeth/global/config/NotificationDispatchProperties.kt
  • src/main/resources/db/migration/V23__add_notification_preferences.sql
  • src/main/resources/db/migration/V24__add_notification_templates_and_failures.sql
  • src/main/resources/db/migration/V25__add_notification_outbox_and_delivery.sql
  • src/main/resources/db/migration/V26__add_notification_dispatch_generation.sql
  • src/test/kotlin/com/weeth/domain/notification/application/dispatch/NotificationDeliveryProcessorTest.kt
  • src/test/kotlin/com/weeth/domain/notification/application/dispatch/NotificationDeliveryWorkerTest.kt
  • src/test/kotlin/com/weeth/domain/notification/application/dispatch/NotificationOutboxRelayTest.kt
  • src/test/kotlin/com/weeth/domain/notification/application/event/CreateNoticeNotificationEventListenerTest.kt
  • src/test/kotlin/com/weeth/domain/notification/application/event/SendPushNotificationEventListenerTest.kt
  • src/test/kotlin/com/weeth/domain/notification/application/usecase/NotificationDispatchIntegrationTest.kt
  • src/test/kotlin/com/weeth/domain/notification/application/usecase/NotificationGenerationIntegrationTest.kt
  • src/test/kotlin/com/weeth/domain/notification/application/usecase/NotificationPreferenceIntegrationTest.kt
  • src/test/kotlin/com/weeth/domain/notification/application/usecase/command/CreateNotificationUseCaseTest.kt
  • src/test/kotlin/com/weeth/domain/notification/application/usecase/command/ManageNotificationPreferenceUseCaseTest.kt
  • src/test/kotlin/com/weeth/domain/notification/application/usecase/query/GetNotificationPreferenceQueryServiceTest.kt
  • src/test/kotlin/com/weeth/domain/notification/domain/entity/NotificationDeliveryTest.kt
  • src/test/kotlin/com/weeth/domain/notification/domain/entity/NotificationOutboxTest.kt
  • src/test/kotlin/com/weeth/domain/notification/domain/repository/NotificationDispatchMigrationTest.kt
  • src/test/kotlin/com/weeth/domain/notification/domain/repository/NotificationPreferenceMigrationTest.kt
  • src/test/kotlin/com/weeth/domain/notification/domain/repository/NotificationTemplateMigrationTest.kt
  • src/test/kotlin/com/weeth/domain/notification/domain/service/NotificationPreferencePolicyTest.kt
  • src/test/kotlin/com/weeth/domain/notification/domain/service/NotificationRecipientPolicyTest.kt
  • src/test/kotlin/com/weeth/domain/notification/domain/service/NotificationTemplateRendererTest.kt
  • src/test/kotlin/com/weeth/domain/notification/fixture/NotificationEventProbe.kt
  • src/test/kotlin/com/weeth/domain/notification/fixture/NotificationPreferenceTestFixture.kt
  • src/test/kotlin/com/weeth/domain/notification/fixture/NotificationRequestTestFixture.kt
  • src/test/kotlin/com/weeth/domain/notification/infrastructure/FcmPushNotificationClassificationTest.kt
  • src/test/kotlin/com/weeth/domain/notification/infrastructure/JdbcUserNotificationBulkWriterAdapterTest.kt
  • src/test/kotlin/com/weeth/domain/notification/infrastructure/SqsNotificationQueueAdapterTest.kt
  • src/test/kotlin/com/weeth/domain/notification/infrastructure/SqsNotificationQueueIntegrationTest.kt
  • src/test/kotlin/com/weeth/domain/notification/presentation/NotificationPreferenceControllerTest.kt

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 새로운 기능 추가

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant