feat: [NDGL-135] 사용자 컨텐츠 요청 시 디스코드 알림 전송#74
Hidden character warning
Conversation
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
설명이 PR은 사용자 제안 템플릿 생성 이벤트를 Discord로 비동기 전송하는 완전한 알림 시스템을 구현합니다. 변경사항Discord 알림 시스템
시퀀스 다이어그램sequenceDiagram
participant Client as 사용자
participant Facade as UserSuggestedTemplateFacade
participant Service as UserSuggestedTemplateService
participant Publisher as UserSuggestedTemplateEventPublisher
participant EventBus as ApplicationEventPublisher
participant Listener as UserSuggestedTemplateEventListener
participant Notifier as DiscordNotifier
participant WebhookClient as DiscordWebhookClient
participant Discord as Discord Webhook
Client->>Facade: createUserSuggestedTemplate()
Facade->>Service: createUserSuggestedTemplate()
Service-->>Facade: templateId
Facade->>Publisher: publish(templateId, videoId, uuid, request)
Publisher->>EventBus: publishEvent(UserSuggestedTemplateCreatedEvent)
EventBus->>Listener: handleUserSuggestedTemplateCreatedEvent(event)
Listener->>Notifier: notify(UserSuggestedTemplateNotification)
Notifier->>WebhookClient: send(DiscordWebhookRequest)
WebhookClient->>Discord: POST JSON
Discord-->>WebhookClient: 200 OK
예상 코드 리뷰 시간🎯 3 (보통) | ⏱️ ~20분 시
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
clients/src/main/java/com/yapp/ndgl/clients/discord/config/DiscordWebhookConfig.java (1)
16-17: 💤 Low value타임아웃 값이 프로덕션 환경에 적합한지 확인 필요
연결 타임아웃 3초와 읽기 타임아웃 5초는 webhook 호출에는 적절해 보이지만, 네트워크 상황에 따라 짧을 수 있습니다. 프로덕션 환경에서 Discord API의 응답 시간을 모니터링하여 타임아웃 값이 충분한지 확인하는 것을 권장합니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@clients/src/main/java/com/yapp/ndgl/clients/discord/config/DiscordWebhookConfig.java` around lines 16 - 17, The hardcoded CONNECT_TIMEOUT_SECONDS (3) and READ_TIMEOUT_SECONDS (5) in DiscordWebhookConfig may be too short for production; make these timeouts configurable and use safer defaults: replace the constants with configurable properties (e.g., injected via environment, application properties, or constructor args) and expose names like discord.webhook.connect-timeout and discord.webhook.read-timeout so operators can tune them; ensure the code that uses CONNECT_TIMEOUT_SECONDS/READ_TIMEOUT_SECONDS (the webhook HTTP client creation logic in DiscordWebhookConfig) reads the injected values (prefer Duration or seconds parsing) and document the property keys and sensible defaults.clients/src/main/java/com/yapp/ndgl/clients/discord/request/DiscordWebhookRequest.java (1)
14-16: ⚡ Quick win
embeds는 방어적 복사로 고정해 주세요.레코드가 외부의 가변
List참조를 그대로 들고 있으면, 생성 후 payload가 의도치 않게 바뀔 수 있습니다. 생성자에서List.copyOf(...)로 고정하는 편이 안전합니다.제안 패치
public DiscordWebhookRequest { content = TextUtils.truncate(content, DiscordPayloadConstraints.CONTENT_MAX); + embeds = embeds == null ? null : List.copyOf(embeds); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@clients/src/main/java/com/yapp/ndgl/clients/discord/request/DiscordWebhookRequest.java` around lines 14 - 16, The record DiscordWebhookRequest currently assigns the external mutable embeds List directly which can allow later mutation of the payload; in the canonical constructor for DiscordWebhookRequest, defensively copy the embeds list using List.copyOf(embeds) (or Collections.emptyList() when null) and assign that to the embeds field, leaving the existing TextUtils.truncate(content, DiscordPayloadConstraints.CONTENT_MAX) handling intact so the record holds an unmodifiable snapshot of embeds.clients/src/main/java/com/yapp/ndgl/clients/discord/DiscordNotifier.java (1)
18-23: ⚡ Quick win빈 페이로드(content/embeds 모두 없음) 전송은 사전 차단해 주세요.
현재 계약상 구현체가 빈 페이로드를 반환해도 그대로 전송됩니다. 전송 전에 유효성 가드를 두는 편이 안전합니다.
제안 패치
+import java.util.List; + +import org.springframework.util.StringUtils; import org.springframework.stereotype.Component; @@ public void notify(final DiscordNotification notification) { - DiscordWebhookRequest request = DiscordWebhookRequest.of( - notification.createContent(), - notification.createEmbeds() - ); + final String content = notification.createContent(); + final List<com.yapp.ndgl.clients.discord.request.DiscordEmbed> embeds = notification.createEmbeds(); + if (!StringUtils.hasText(content) && (embeds == null || embeds.isEmpty())) { + return; + } + DiscordWebhookRequest request = DiscordWebhookRequest.of(content, embeds); discordWebhookClient.send(request); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@clients/src/main/java/com/yapp/ndgl/clients/discord/DiscordNotifier.java` around lines 18 - 23, notify 메서드가 DiscordWebhookRequest를 빈 페이로드(둘 다 없음)로 생성해 그대로 전송하므로, DiscordNotifier.notify에서 DiscordNotification.createContent()와 createEmbeds() 결과를 검사하여 둘 다 비어있거나 null이면 전송하지 않도록 유효성 가드를 추가하세요; 구체적으로 notify 내부에서 content와 embeds를 판정하고(예: null 또는 empty 목록/빈 문자열), 둘 다 비어있을 때 discordWebhookClient.send 호출을 건너뛰고 적절히 로그 또는 반환하도록 변경하세요(대상 심볼: DiscordNotifier.notify, DiscordNotification.createContent, DiscordNotification.createEmbeds, DiscordWebhookRequest, discordWebhookClient.send).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@application/src/main/java/com/yapp/ndgl/application/domains/travel/event/UserSuggestedTemplateNotification.java`:
- Around line 41-42: The notification currently calls
maskUuid(event.suggesterUuid()) in UserSuggestedTemplateNotification
(Field.of("제안자", maskUuid(event.suggesterUuid()), false)) which still exposes a
partial UUID; remove that raw/partially masked identifier from the Discord
payload or replace it with a non-reversible value: compute a server-side salted
one-way hash (e.g., HMAC-SHA256 using a stored salt/secret) of
event.suggesterUuid() and use that hashed token in the Field instead, or simply
omit the Field; update the code in UserSuggestedTemplateNotification to stop
using maskUuid() for external payloads and ensure the chosen salt/secret is
loaded from secure config.
In `@common/src/main/java/com/yapp/ndgl/common/util/TextUtils.java`:
- Around line 16-24: The truncate method in TextUtils currently allows max <= 0
which causes StringIndexOutOfBoundsException; update TextUtils.truncate to
validate the max parameter at the start (e.g., if (max < 1) throw new
IllegalArgumentException("max must be >= 1")) or normalize it (e.g., treat any
value <1 as 1) and document the behavior; ensure the validation occurs before
any substring calls and include a clear error message referencing the max
parameter so callers see the contract.
---
Nitpick comments:
In
`@clients/src/main/java/com/yapp/ndgl/clients/discord/config/DiscordWebhookConfig.java`:
- Around line 16-17: The hardcoded CONNECT_TIMEOUT_SECONDS (3) and
READ_TIMEOUT_SECONDS (5) in DiscordWebhookConfig may be too short for
production; make these timeouts configurable and use safer defaults: replace the
constants with configurable properties (e.g., injected via environment,
application properties, or constructor args) and expose names like
discord.webhook.connect-timeout and discord.webhook.read-timeout so operators
can tune them; ensure the code that uses
CONNECT_TIMEOUT_SECONDS/READ_TIMEOUT_SECONDS (the webhook HTTP client creation
logic in DiscordWebhookConfig) reads the injected values (prefer Duration or
seconds parsing) and document the property keys and sensible defaults.
In `@clients/src/main/java/com/yapp/ndgl/clients/discord/DiscordNotifier.java`:
- Around line 18-23: notify 메서드가 DiscordWebhookRequest를 빈 페이로드(둘 다 없음)로 생성해 그대로
전송하므로, DiscordNotifier.notify에서 DiscordNotification.createContent()와
createEmbeds() 결과를 검사하여 둘 다 비어있거나 null이면 전송하지 않도록 유효성 가드를 추가하세요; 구체적으로 notify
내부에서 content와 embeds를 판정하고(예: null 또는 empty 목록/빈 문자열), 둘 다 비어있을 때
discordWebhookClient.send 호출을 건너뛰고 적절히 로그 또는 반환하도록 변경하세요(대상 심볼:
DiscordNotifier.notify, DiscordNotification.createContent,
DiscordNotification.createEmbeds, DiscordWebhookRequest,
discordWebhookClient.send).
In
`@clients/src/main/java/com/yapp/ndgl/clients/discord/request/DiscordWebhookRequest.java`:
- Around line 14-16: The record DiscordWebhookRequest currently assigns the
external mutable embeds List directly which can allow later mutation of the
payload; in the canonical constructor for DiscordWebhookRequest, defensively
copy the embeds list using List.copyOf(embeds) (or Collections.emptyList() when
null) and assign that to the embeds field, leaving the existing
TextUtils.truncate(content, DiscordPayloadConstraints.CONTENT_MAX) handling
intact so the record holds an unmodifiable snapshot of embeds.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 719de956-e562-4041-81b1-63f7f5aa8f95
📒 Files selected for processing (19)
application/src/main/java/com/yapp/ndgl/application/common/aop/DistributedLockAspect.javaapplication/src/main/java/com/yapp/ndgl/application/domains/travel/event/UserSuggestedTemplateCreatedEvent.javaapplication/src/main/java/com/yapp/ndgl/application/domains/travel/event/UserSuggestedTemplateNotification.javaapplication/src/main/java/com/yapp/ndgl/application/domains/travel/event/listener/TravelTemplateEventListener.javaapplication/src/main/java/com/yapp/ndgl/application/domains/travel/event/listener/UserSuggestedTemplateEventListener.javaapplication/src/main/java/com/yapp/ndgl/application/domains/travel/event/publisher/UserSuggestedTemplateEventPublisher.javaapplication/src/main/java/com/yapp/ndgl/application/domains/travel/facade/UserSuggestedTemplateFacade.javaapplication/src/main/java/com/yapp/ndgl/application/domains/travel/service/UserSuggestedTemplateService.javaapplication/src/main/resources/application.ymlclients/src/main/java/com/yapp/ndgl/clients/discord/DiscordNotification.javaclients/src/main/java/com/yapp/ndgl/clients/discord/DiscordNotifier.javaclients/src/main/java/com/yapp/ndgl/clients/discord/DiscordPayloadConstraints.javaclients/src/main/java/com/yapp/ndgl/clients/discord/DiscordWebhookClient.javaclients/src/main/java/com/yapp/ndgl/clients/discord/config/DiscordWebhookConfig.javaclients/src/main/java/com/yapp/ndgl/clients/discord/config/DiscordWebhookProperties.javaclients/src/main/java/com/yapp/ndgl/clients/discord/request/DiscordEmbed.javaclients/src/main/java/com/yapp/ndgl/clients/discord/request/DiscordWebhookRequest.javacommon/src/main/java/com/yapp/ndgl/common/util/TextUtils.javadomain/domain-rdb/src/main/java/com/yapp/ndgl/domain/common/lock/NamedLockRepository.java
요약
사용자 제안 템플릿 생성 시 Discord로 알림을 발송하도록 이벤트 기반 인프라와 Discord 클라이언트를 추가하고 생성 흐름을 이벤트 발행으로 연결했습니다.
변경 내용
참고 사항
Summary by CodeRabbit
새 기능
리팩토링