Skip to content

Feat/#125 타임라인 내 성과 상태 판별 구현#136

Merged
jinnieusLab merged 4 commits into
developfrom
feat/#125
May 19, 2026
Merged

Feat/#125 타임라인 내 성과 상태 판별 구현#136
jinnieusLab merged 4 commits into
developfrom
feat/#125

Conversation

@jinnieusLab
Copy link
Copy Markdown
Collaborator

@jinnieusLab jinnieusLab commented May 18, 2026

📌 관련 이슈

🚀 개요

Timeline 생성 및 수정 시 사용자가 선택한 지표값들에 대해 비교 기준 기간과 비교하여, 성과 상태를 평균 이상/이하인지 판별하는 로직을 구현하였습니다.

📄 작업 내용

  • Timeline 생성 및 수정 시 PerformaceStatus 반영
  • TimelineUtil 내에 클릭수/전환수/노출수/ROAS를 기준 기간과 비교하는 로직 (calculatePerformanceStatus) 구현

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

image

Timeline 생성 api 테스트

image

Timeline 생성 api 테스트 결과

✅ 체크리스트

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

🔍 리뷰 포인트 (Review Points)

성과 상태 (PerformanceStatus) 판단 시 사용자가 선택한 지표들(ex. 클릭수, ROAS...)에서 전체 평균을 내서 기준 기간(ex. 지난주, 지난달 등..)과 비교해 10% 이상, 이하로 차이가 나는지 확인하도록 하였는데 이 로직이 괜찮을지 확인해주시면 감사하겠습니다!

if (avgRate >= 1.1) {
            return PerformanceStatus.ABOVE_AVG;
        } else if (avgRate <= 0.9) {
            return PerformanceStatus.UNDERPERFORM;
        } else {
            return PerformanceStatus.ON_TRACK;
        }

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

Summary by CodeRabbit

  • 버그 수정
    • 타임라인 생성/수정 시 현재 및 과거 기간의 집계 성과를 비교해 클릭·전환·노출·ROAS 기준으로 성과 상태를 정확히 재계산하여 반영합니다.
    • 기간별 성과 집계 로직을 확장해 필요한 합계 데이터가 정확히 조회되도록 개선했습니다.

Review Change Stack

@jinnieusLab jinnieusLab self-assigned this May 18, 2026
@jinnieusLab jinnieusLab added the ✨ Feature 새로운 기능 추가 label May 18, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 18, 2026

Walkthrough

타임라인 생성/수정 시 현재·비교 기간의 MetricSumProjection 집계값을 조회해 클릭/전환/노출/ROAS 비율을 비교하고, 평균 비율 기준으로 PerformanceStatus를 계산하여 타임라인에 반영하도록 구현했다.

Changes

타임라인 성과 상태 판별 로직 구현

Layer / File(s) Summary
PerformanceStatus 판별 알고리즘
src/main/java/com/whereyouad/WhereYouAd/domains/timeline/domain/util/TimelineUtil.java
calculatePerformanceStatus(Timeline, MetricSumProjection currentFacts, MetricSumProjection pastFacts) 구현: 현재-과거 지표 비율을 누적해 평균을 계산하고, avgRate >= 1.1 → ABOVE_AVG, <= 0.9 → UNDERPERFORM, 그 외 → ON_TRACK. null/0 방어 로직 포함.
집계 조회 쿼리 추가
src/main/java/com/whereyouad/WhereYouAd/domains/advertisement/persistence/repository/MetricFactRepository.java
findMetricsSumByOrgIdAndDateRange(orgId, startDate, endDate, orgStatus) 오버로드 추가: impressions/clicks/conversions/spend/revenue 합계를 MetricSumProjection으로 반환(AdCampaign.status 조건 제외).
Timeline 생성/수정 시 성과 상태 동적 설정
src/main/java/com/whereyouad/WhereYouAd/domains/timeline/domain/service/TimelineServiceImpl.java
createTimeline/updateTimeline에서 past/current MetricSumProjection 조회 추가, 조회 결과 검증(isProjectionEmpty) 후 timelineUtil.calculatePerformanceStatus(timeline, currentFacts, pastFacts) 호출로 PerformanceStatus 재계산 및 엔티티 반영.

Sequence Diagram

sequenceDiagram
  participant Client
  participant TimelineServiceImpl
  participant MetricFactRepository
  participant TimelineUtil
  participant Database

  Client->>TimelineServiceImpl: createTimeline/updateTimeline 요청
  TimelineServiceImpl->>MetricFactRepository: past 기간 집계 조회 (MetricSumProjection)
  MetricFactRepository->>Database: JPQL 집계 쿼리 실행
  Database-->>MetricFactRepository: pastFacts
  TimelineServiceImpl->>MetricFactRepository: current 기간 집계 조회 (MetricSumProjection)
  MetricFactRepository->>Database: JPQL 집계 쿼리 실행
  Database-->>MetricFactRepository: currentFacts
  TimelineServiceImpl->>TimelineUtil: calculatePerformanceStatus(timeline, currentFacts, pastFacts)
  TimelineUtil-->>TimelineServiceImpl: PerformanceStatus
  TimelineServiceImpl->>TimelineServiceImpl: timeline.setPerformanceStatus(...)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

🗄️ DB

Suggested reviewers

  • kingmingyu
  • ojy0903
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.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 제목이 주요 변경사항(성과 상태 판별 로직 구현)을 명확하고 간결하게 요약하고 있습니다.
Description check ✅ Passed PR 설명이 템플릿의 주요 섹션(관련 이슈, 개요, 작업 내용, 테스트 결과, 체크리스트, 리뷰 포인트)을 모두 포함하고 있습니다.
Linked Issues check ✅ Passed 변경사항이 #125의 모든 핵심 요구사항(MetricFact 조회, 성과 지표 데이터 판별, 비교 기간 설정)을 충족하고 있습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 #125의 요구사항 범위 내에서 이루어졌으며, 성과 상태 판별 로직 구현에만 집중되어 있습니다.

✏️ 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 feat/#125

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.

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/java/com/whereyouad/WhereYouAd/domains/timeline/domain/service/TimelineServiceImpl.java (1)

73-77: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

비교 데이터 존재 검증 조건과 합계 조회 조건이 달라 오판정될 수 있습니다.

비교 데이터 존재 여부는 상태 조건 없이 조회하고, 실제 성과 합계는 OrgStatus.ACTIVE + Status.ON_GOING으로만 조회하고 있습니다. 이 불일치 때문에 “비교 데이터 있음”으로 통과했는데 계산 시에는 사실상 데이터가 없는 케이스가 발생할 수 있습니다. 두 쿼리의 조건을 동일하게 맞춰주세요.

🔧 제안 수정 예시
- boolean hasComparisonData = metricFactRepository.existsByTimeBucketBetweenAndOrg(
+ boolean hasComparisonData = metricFactRepository.existsByTimeBucketBetweenAndOrgIdAndStatus(
         comparisonDates.start().atStartOfDay(),
         comparisonDates.end().atTime(LocalTime.MAX),
-        orgId
+        orgId,
+        OrgStatus.ACTIVE,
+        Status.ON_GOING
 );

Also applies to: 83-98, 142-146, 151-166

🤖 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
`@src/main/java/com/whereyouad/WhereYouAd/domains/timeline/domain/service/TimelineServiceImpl.java`
around lines 73 - 77, The existence check using
metricFactRepository.existsByTimeBucketBetweenAndOrg is missing the same status
filters used when computing sums, causing mismatches; update the existsBy...
calls to include the same OrgStatus.ACTIVE and Status.ON_GOING predicates (e.g.,
use or add an existsByTimeBucketBetweenAndOrgAndOrgStatusAndStatus-style method
or include the same spec/criteria used by the sum methods) so the
“hasComparisonData” and other existence checks match the sum queries exactly;
apply this same change to the other occurrences noted (the other existsBy...
checks around the ranges referenced: lines corresponding to the 83-98, 142-146,
and 151-166 blocks) so all existence checks mirror the sum query filters.
🤖 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.

Outside diff comments:
In
`@src/main/java/com/whereyouad/WhereYouAd/domains/timeline/domain/service/TimelineServiceImpl.java`:
- Around line 73-77: The existence check using
metricFactRepository.existsByTimeBucketBetweenAndOrg is missing the same status
filters used when computing sums, causing mismatches; update the existsBy...
calls to include the same OrgStatus.ACTIVE and Status.ON_GOING predicates (e.g.,
use or add an existsByTimeBucketBetweenAndOrgAndOrgStatusAndStatus-style method
or include the same spec/criteria used by the sum methods) so the
“hasComparisonData” and other existence checks match the sum queries exactly;
apply this same change to the other occurrences noted (the other existsBy...
checks around the ranges referenced: lines corresponding to the 83-98, 142-146,
and 151-166 blocks) so all existence checks mirror the sum query filters.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 80cf9388-4139-44ee-8cd1-edabaeabb1f4

📥 Commits

Reviewing files that changed from the base of the PR and between fdad8c6 and 4e500bd.

📒 Files selected for processing (2)
  • src/main/java/com/whereyouad/WhereYouAd/domains/timeline/domain/service/TimelineServiceImpl.java
  • src/main/java/com/whereyouad/WhereYouAd/domains/timeline/domain/util/TimelineUtil.java

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: 고생하셨습니다! 초기 설정으로 10프로면 무난하고 좋은 것 같습니다!
궁금한 점이 있는데 과거 데이터도 조회할 때 광고 현재 상태가 ON_GOING인 데이터만 받아오고 있는데 만약 1년전 데이터 등과 비교할 때도 동일하게 현재까지도 ON_GOING인 데이터만 가져오는 것이 괜찮을까요? 과거 데이터는 status 관련 없이 받아와서 현재 진행중인 광고 데이터와 비교하는 건 어떤가요?
지금도 진행 중인 광고 데이터만 비교하고 싶다는 의도면 괜찮은 것 같습니다!

Copy link
Copy Markdown
Collaborator

@ojy0903 ojy0903 left a comment

Choose a reason for hiding this comment

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

P4: 고생하셨어요! MetricSumProjection 사용해서 깔끔하게 구현된거 같습니다!!
제가 보기에도 비교 기준 10% 정도가 적당한거 같고, 민규님이 리뷰에서 말해주신 과거 데이터를 status 관련은 제 생각에는... 일단 지금대로 과거 지표 데이터도 ON_GOING 으로 조회하는거는 어떨까요? 과거 값을 Status 상관 없이 집계하면 지금 중단된 광고의 과거 지표가 포함되면서 전반적으로 지표 비교가 UNDERPERFORM 으로 나올 수 있을 거 같아서요...
민규님이랑 의견이 다르니... 최종 결정은 지민님에게 맡기겠습니다... 🥲

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.

Actionable comments posted: 1

🤖 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
`@src/main/java/com/whereyouad/WhereYouAd/domains/advertisement/persistence/repository/MetricFactRepository.java`:
- Around line 63-81: The query in MetricFactRepository's
findMetricsSumByOrgIdAndDateRange filters p.organization.status but not the
campaign status; if requirements are to exclude completed campaigns add a
campaign status filter (e.g., join or reference the AdCampaign status via
m.adCampaign.status) to the WHERE clause and add a corresponding parameter
(e.g., `@Param`("campaignStatus") OrgStatus campaignStatus) or hard-code the
allowed statuses (e.g., ON_GOING) in the predicate; update the method signature
and query accordingly to reference m.adCampaign.status when filtering.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0d94d547-e328-4239-9059-337634eca012

📥 Commits

Reviewing files that changed from the base of the PR and between 4e500bd and f2f4036.

📒 Files selected for processing (2)
  • src/main/java/com/whereyouad/WhereYouAd/domains/advertisement/persistence/repository/MetricFactRepository.java
  • src/main/java/com/whereyouad/WhereYouAd/domains/timeline/domain/service/TimelineServiceImpl.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/com/whereyouad/WhereYouAd/domains/timeline/domain/service/TimelineServiceImpl.java

@jinnieusLab
Copy link
Copy Markdown
Collaborator Author

P4: 고생하셨습니다! 초기 설정으로 10프로면 무난하고 좋은 것 같습니다! 궁금한 점이 있는데 과거 데이터도 조회할 때 광고 현재 상태가 ON_GOING인 데이터만 받아오고 있는데 만약 1년전 데이터 등과 비교할 때도 동일하게 현재까지도 ON_GOING인 데이터만 가져오는 것이 괜찮을까요? 과거 데이터는 status 관련 없이 받아와서 현재 진행중인 광고 데이터와 비교하는 건 어떤가요? 지금도 진행 중인 광고 데이터만 비교하고 싶다는 의도면 괜찮은 것 같습니다!

P4: 고생하셨어요! MetricSumProjection 사용해서 깔끔하게 구현된거 같습니다!! 제가 보기에도 비교 기준 10% 정도가 적당한거 같고, 민규님이 리뷰에서 말해주신 과거 데이터를 status 관련은 제 생각에는... 일단 지금대로 과거 지표 데이터도 ON_GOING 으로 조회하는거는 어떨까요? 과거 값을 Status 상관 없이 집계하면 지금 중단된 광고의 과거 지표가 포함되면서 전반적으로 지표 비교가 UNDERPERFORM 으로 나올 수 있을 거 같아서요... 민규님이랑 의견이 다르니... 최종 결정은 지민님에게 맡기겠습니다... 🥲

넵 피드백 감사합니다! 고민해봤을 때 과거에 집행했지만 종료된 데이터까지 현재와 비교하지 않으면 비교할 과거 데이터의 양이 많지 않을 수도 있고, 또 타임라인을 만드는 유저는 결국 캠페인 중단 여부로 생긴 광고 성과나 과거와 달라진 액션으로 생긴 광고 성과 등을 비교하려는 의도가 있을 듯 하여, 과거 데이터는 Status 상관 없이 집계하도록 하겠습니다..!

@jinnieusLab jinnieusLab merged commit 0b2dc0c into develop May 19, 2026
2 checks passed
@jinnieusLab jinnieusLab deleted the feat/#125 branch May 19, 2026 17:17
@jinnieusLab jinnieusLab changed the title Feat/#125 성과 상태 판별 구현 Feat/#125 타임라인 내 성과 상태 판별 구현 May 19, 2026
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.

feat: 타임라인 데이터 판별 로직 구현

3 participants