Skip to content

Fix/#101 - 실시간 클릭수 API 이상 클릭값 무시 버그 수정#102

Merged
ojy0903 merged 4 commits intodevelopfrom
fix/#101
Mar 28, 2026
Merged

Fix/#101 - 실시간 클릭수 API 이상 클릭값 무시 버그 수정#102
ojy0903 merged 4 commits intodevelopfrom
fix/#101

Conversation

@ojy0903
Copy link
Copy Markdown
Collaborator

@ojy0903 ojy0903 commented Mar 26, 2026

📌 관련 이슈

🚀 개요

이번 PR에서 변경된 핵심 내용을 요약해주세요.

ClickConsumer 에서 이상 클릭에 대한 정보를 Redis 에 적재하는 부분이 빠져있는 것을 확인해 Redis 에 적절하게 정보를 적재하는 로직추가

📄 작업 내용

구체적인 작업 내용을 설명해주세요.

  • ClickConsumer 내부 이상 클릭 정보 Redis 에 적재하는 로직 추가
  • Spring OSIV 비활성화로 발생하는 오류 방지 위해 AdContentRepository 내부 fetch join 사용한 조회 메서드 추가

📸 스크린샷 / 테스트 결과 (선택)

결과물 확인을 위한 사진이나 테스트 로그를 첨부해주세요.

수정 이후 Postman 을 통해 Redirect URL 에 요청을 보내면 정상적으로 이상 클릭 정보가 출력됩니다.
image
image

✅ 체크리스트

  • [✅] 브랜치 전략(GitHub Flow)을 준수했나요?
  • [✅] 메서드 단위로 코드가 잘 쪼개져 있나요?
  • [✅] 테스트 통과 확인
  • [✅] 서버 실행 확인
  • [✅] API 동작 확인

🔍 리뷰 포인트 (Review Points)

리뷰어가 중점적으로 확인했으면 하는 부분을 적어주세요. (P1~P4 적용 가이드)

  • SSE 로직을 처음 써보는 거라 관련한 버그가 많은 것 같습니다...죄송합니다ㅠㅠ
  • ClickConsumer 쪽에 Redis 데이터 적재 쪽 주로 봐주시면 될 것 같습니다...
  • 광고 플랫폼 API 연동이랑 관련 엔티티 작업은 이 PR 머지하고 진행하겠습니다...

💬 리뷰어 가이드 (P-Rules)
P1: 필수 반영 (Critical) - 버그 가능성, 컨벤션 위반. 해결 전 머지 불가.
P2: 적극 권장 (Recommended) - 더 나은 대안 제시. 가급적 반영 권장.
P3: 제안 (Suggestion) - 아이디어 공유. 반영 여부는 드라이버 자율.
P4: 단순 확인/칭찬 (Nit) - 사소한 오타, 칭찬 등 피드백.

Summary by CodeRabbit

변경 사항

  • 신기능

    • 의심스러운 클릭 활동을 실시간으로 감지하고 조직별 짧은 알림(60초 보관)을 생성하여 대시보드에 반영
  • 성능 개선

    • 광고 관련 연관 정보(그룹·캠페인)를 함께 조회해 클릭 처리 흐름이 더 효율적으로 동작
  • 문서

    • 실시간 클릭 스트림의 의심 정보 필드 구성(provider, campaignName, adName, message) 명확화

@ojy0903 ojy0903 self-assigned this Mar 26, 2026
@ojy0903 ojy0903 added the 🐛 Bug 버그 수정 label Mar 26, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 26, 2026

Walkthrough

OSIV 비활성화 환경 대응으로 AdContent와 연관 엔티티를 한 번에 조회하는 리포지토리 메서드를 추가하고, Kafka 클릭 소비자에서 의심 클릭 발생 시 캠페인/광고 정보를 포함한 JSON을 Redis에 TTL(60초)로 저장하는 로직을 추가했습니다.

Changes

Cohort / File(s) Summary
Repository 쿼리 추가
src/main/java/com/whereyouad/WhereYouAd/domains/advertisement/persistence/repository/AdContentRepository.java
findByIdWithGroupAndCampaign(Long id) 추가 — JPQL JOIN FETCHAdContentadGroup, adCampaign을 즉시 로드하도록 함.
Kafka 소비자 · Redis 적재 로직
src/main/java/com/whereyouad/WhereYouAd/infrastructure/client/kafka/ClickConsumer.java
ObjectMapper 주입 및 Map 기반 페이로드 생성 추가. findByIdWithGroupAndCampaign(...) 사용으로 관련 엔티티 확보 후, isSuspect==true && orgId!=null일 때 click:suspect:alert:org:{orgId} 키로 직렬화된 JSON을 TTL 60초로 Redis에 저장(예외 처리 및 에러 로깅 포함). 기존 ClickLog 생성/저장 흐름 유지.
API 문서(설명 보강)
src/main/java/com/whereyouad/WhereYouAd/domains/dashboard/presentation/docs/DashboardControllerDocs.java
SSE 응답 suspectDetail 필드 구조 문서화: 내부 필드로 provider, campaignName, adName, message 명시. 문서 설명만 변경.

Sequence Diagram(s)

sequenceDiagram
    participant Kafka
    participant ClickConsumer as Consumer
    participant AdRepo as AdContentRepository
    participant ClickLogRepo as ClickLogRepository
    participant Redis
    Kafka->>Consumer: 이벤트 전달
    Consumer->>AdRepo: findByIdWithGroupAndCampaign(id)
    AdRepo-->>Consumer: AdContent + AdGroup + AdCampaign
    alt isSuspect && orgId != null
        Consumer->>Redis: SET click:suspect:alert:org:{orgId} (JSON) EX 60
        Redis-->>Consumer: OK
    end
    Consumer->>ClickLogRepo: save(ClickLog)
    ClickLogRepo-->>Consumer: 저장 완료
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • jinnieusLab
  • kingmingyu

추가 코멘트(간단히): JOIN FETCH로 OSIV 비활성화 이슈를 직접 해결한 설계는 적절합니다. Redis에 저장되는 페이로드의 null 가능성(adGroup/adCampaign 이름 등)과 ObjectMapper 설정(custom serializer 포함)을 리뷰에서 한번만 확인해 주세요.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 핵심 변경사항(이상 클릭값 버그 수정)을 명확하게 요약하고 있으며, 이슈 번호로 추적 가능합니다.
Linked Issues check ✅ Passed 모든 주요 목표가 충족되었습니다: (1) ClickConsumer에 Redis 적재 로직 추가 [#101], (2) AdContentRepository에 fetch join 조회 메서드 추가 [#101], (3) Postman 검증으로 이상 클릭 정보 정상 출력 확인 [#101].
Out of Scope Changes check ✅ Passed 모든 변경사항이 이슈 #101의 범위 내에 있습니다. AdContentRepository 메서드 추가, ClickConsumer 로직 개선, 그리고 문서화 업데이트는 모두 이상 클릭 처리와 직접적으로 관련 있습니다.
Description check ✅ Passed PR 설명이 제공된 템플릿의 모든 필수 섹션을 충실히 따르고 있으며, 구체적인 작업 내용, 테스트 결과 스크린샷, 완성된 체크리스트를 포함하고 있습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/#101

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@ojy0903 ojy0903 changed the title Fix/#101 Fix/#101 - 실시간 클릭수 API 이상 클릭값 무시 버그 수정 Mar 26, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
src/main/java/com/whereyouad/WhereYouAd/infrastructure/client/kafka/ClickConsumer.java (2)

113-115: 예외 처리 전략이 적절합니다.

Redis 저장 실패 시에도 메인 로직(ClickLog DB 저장)이 계속 진행되도록 한 것은 장애 격리(Fault Isolation) 관점에서 올바른 설계입니다. 알림 기능의 일시적 실패가 핵심 비즈니스 로직(클릭 로그 저장)에 영향을 주지 않습니다.

다만, 운영 모니터링을 위해 log.error에 추가 컨텍스트(예: orgId, adContentId)를 포함하면 디버깅에 도움이 됩니다:

💡 로깅 개선 제안
 } catch (Exception e) {
-    log.error("봇 알림 JSON 변환/저장 실패", e);
+    log.error("봇 알림 JSON 변환/저장 실패 - orgId={}, adContentId={}", 
+              event.getOrgId(), event.getAdContentId(), e);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/whereyouad/WhereYouAd/infrastructure/client/kafka/ClickConsumer.java`
around lines 113 - 115, In the catch block inside ClickConsumer where Redis save
failures are logged (the catch(Exception e) that currently calls log.error("봇 알림
JSON 변환/저장 실패", e)), augment the log message with contextual identifiers (e.g.,
orgId and adContentId extracted from the surrounding scope or the parsed DTO) so
the error record includes those values; update the log.error invocation to
include the context fields alongside the exception while keeping the existing
behavior (do not rethrow so ClickLog DB save continues).

83-100: NPE 방어 코드가 깔끔하게 작성되었습니다! 👏

기본값을 미리 설정하고 연관 엔티티를 단계별로 체크하는 방식이 안전합니다. findByIdWithGroupAndCampaign이 Fetch Join을 사용하므로 정상적인 경우 adGroupadCampaign이 null일 가능성은 낮지만, 데이터 정합성 문제나 예외 상황에 대비한 방어적 프로그래밍으로 좋은 습관입니다.

한 가지 팁: 반복되는 adContent.getAdGroup().getAdCampaign() 호출을 지역 변수로 추출하면 가독성이 더 좋아질 수 있습니다:

♻️ 선택적 리팩토링 제안
 if (adContent.getAdGroup() != null && adContent.getAdGroup().getAdCampaign() != null) {
+    var campaign = adContent.getAdGroup().getAdCampaign();

     // 캠페인 이름 추출
-    if (adContent.getAdGroup().getAdCampaign().getName() != null) {
-        campaignNameStr = adContent.getAdGroup().getAdCampaign().getName();
+    if (campaign.getName() != null) {
+        campaignNameStr = campaign.getName();
     }

     // 플랫폼(Provider) 추출
-    if (adContent.getAdGroup().getAdCampaign().getProvider() != null) {
-        providerStr = String.valueOf(adContent.getAdGroup().getAdCampaign().getProvider());
+    if (campaign.getProvider() != null) {
+        providerStr = String.valueOf(campaign.getProvider());
     }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/whereyouad/WhereYouAd/infrastructure/client/kafka/ClickConsumer.java`
around lines 83 - 100, The repeated chained calls
adContent.getAdGroup().getAdCampaign() should be hoisted into a local variable
to improve readability and avoid redundant accessor calls; create a local
variable (e.g., AdCampaign adCampaign = adContent.getAdGroup() != null ?
adContent.getAdGroup().getAdCampaign() : null), then use adCampaign to set
providerStr and campaignNameStr, and keep the existing adNameStr logic intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@src/main/java/com/whereyouad/WhereYouAd/infrastructure/client/kafka/ClickConsumer.java`:
- Around line 113-115: In the catch block inside ClickConsumer where Redis save
failures are logged (the catch(Exception e) that currently calls log.error("봇 알림
JSON 변환/저장 실패", e)), augment the log message with contextual identifiers (e.g.,
orgId and adContentId extracted from the surrounding scope or the parsed DTO) so
the error record includes those values; update the log.error invocation to
include the context fields alongside the exception while keeping the existing
behavior (do not rethrow so ClickLog DB save continues).
- Around line 83-100: The repeated chained calls
adContent.getAdGroup().getAdCampaign() should be hoisted into a local variable
to improve readability and avoid redundant accessor calls; create a local
variable (e.g., AdCampaign adCampaign = adContent.getAdGroup() != null ?
adContent.getAdGroup().getAdCampaign() : null), then use adCampaign to set
providerStr and campaignNameStr, and keep the existing adNameStr logic intact.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c644e6a3-2565-4207-a669-3fb9de9c0af2

📥 Commits

Reviewing files that changed from the base of the PR and between 0161177 and ef68e6f.

📒 Files selected for processing (2)
  • src/main/java/com/whereyouad/WhereYouAd/domains/advertisement/persistence/repository/AdContentRepository.java
  • src/main/java/com/whereyouad/WhereYouAd/infrastructure/client/kafka/ClickConsumer.java

Copy link
Copy Markdown
Collaborator

@jinnieusLab jinnieusLab left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P4: 오 고생하셨습니다! OSIV 설정이 꺼져 있는 상태에서 이상 클릭 정보를 Redis에 넣는 기능에서 생길 수 있는 지연 로딩을 방지해주실려고 한번에 관련 정보까지 가져오도록 수정하신 거군요..!
덕분에 실시간 데이터를 SSE로 오랫동안 전달할 때 db 점유 문제와 해결 방법 관련해서 공부할 수 있었습니다!! 👍

Copy link
Copy Markdown
Collaborator

@kingmingyu kingmingyu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P4: 고생하셨습니다..! 저도 sse 관련 코드나 osiv 설정은 처음 봐서 많이 배워갑니다!!

@ojy0903 ojy0903 merged commit 68c1a1d into develop Mar 28, 2026
2 checks passed
@ojy0903 ojy0903 deleted the fix/#101 branch March 28, 2026 13:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🐛 Bug 버그 수정

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: 실시간 클릭수 API 이상 클릭값 무시 버그 수정 - 실시간 클릭수 API에서 이상 클릭값 출력되지 않는 버그 수정

3 participants