From 91224c861bf828c3f63c3778cba6de741065b052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=98=A4=EC=A4=80=EC=98=81?= Date: Tue, 7 Jul 2026 17:19:42 +0900 Subject: [PATCH 1/8] =?UTF-8?q?:recycle:=20refactor:=20MetricFactRepositor?= =?UTF-8?q?y=20=EB=82=B4=EB=B6=80=20=EB=8C=80=EC=8B=9C=EB=B3=B4=EB=93=9C?= =?UTF-8?q?=EC=9A=A9=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/MetricFactRepository.java | 71 ++++++++++--------- 1 file changed, 37 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/whereyouad/WhereYouAd/domains/advertisement/persistence/repository/MetricFactRepository.java b/src/main/java/com/whereyouad/WhereYouAd/domains/advertisement/persistence/repository/MetricFactRepository.java index 95fe1130..58d81769 100644 --- a/src/main/java/com/whereyouad/WhereYouAd/domains/advertisement/persistence/repository/MetricFactRepository.java +++ b/src/main/java/com/whereyouad/WhereYouAd/domains/advertisement/persistence/repository/MetricFactRepository.java @@ -29,12 +29,15 @@ public interface MetricFactRepository extends JpaRepository { BigDecimal sumSpendsByUserIdAndOrgIdAndProvider(@Param("userId") Long userId, @Param("orgId") Long orgId, @Param("provider") Provider provider); - //전체 지표 조회 로직에서 사용 - // 해당 프로젝트의 가장 최신 데이터 날짜를 가져오는 쿼리 - @Query("SELECT MAX(m.timeBucket) FROM MetricFact m") - Optional findLatestTimeBucket(); - - // orgId에 속한 모든 프로젝트의 지표중 해당 MetricFact 가 속한 AdCampaign 의 status 가 ON_GOING 인 지표를 지정된 기간 범위 합산 + @Query("SELECT MAX(m.timeBucket) FROM MetricFact m " + + "JOIN m.adContent ac " + + "JOIN ac.adGroup ag " + + "JOIN ag.adCampaign camp " + + "WHERE camp.organization.id = :orgId") + Optional findLatestTimeBucketByOrgId(@Param("orgId") Long orgId); + + // orgId 에 속한 광고(adCampaign) 중 status 가 ON_GOING 인 지표를 지정된 기간 범위 합산 + // project 유무와 무관하게 adCampaign 이 조직에 속하면 집계 (status 서브쿼리를 조인으로 흡수) @Query("SELECT " + "COALESCE(SUM(m.impressions), 0) AS totalImpressions, " + "COALESCE(SUM(m.clicks), 0) AS totalClicks, " + @@ -42,17 +45,15 @@ BigDecimal sumSpendsByUserIdAndOrgIdAndProvider(@Param("userId") Long userId, @P "COALESCE(SUM(m.spend), 0) AS totalSpend, " + "COALESCE(SUM(m.revenue), 0) AS totalRevenue " + "FROM MetricFact m " + - "JOIN m.project p " + - "WHERE p.organization.id = :orgId " + - "AND p.organization.status = :orgStatus " + - "AND m.timeBucket >= :startDate AND m.timeBucket < :endDate " + - "AND m.adContent.id IN (" + - " SELECT ac.id " + - " FROM AdContent ac " + - " JOIN ac.adGroup ag " + - " JOIN ag.adCampaign camp " + - " WHERE camp.status = :status" + ")" - ) + "JOIN m.adContent ac " + + "JOIN ac.adGroup ag " + + "JOIN ag.adCampaign camp " + + "JOIN camp.organization o " + + "WHERE o.id = :orgId " + + "AND o.status = :orgStatus " + + "AND camp.status = :status " + + "AND m.timeBucket >= :startDate AND m.timeBucket < :endDate" + ) MetricSumProjection findMetricsSumByOrgIdAndDateRange( @Param("orgId") Long orgId, @Param("startDate") LocalDateTime startDate, @@ -61,7 +62,8 @@ MetricSumProjection findMetricsSumByOrgIdAndDateRange( @Param("status") Status status ); - // orgId에 속한 모든 프로젝트의 지표중 해당 MetricFact 가 속한 AdCampaign 지표를 지정된 기간 범위 합산 (status 고려 x) + // orgId 에 속한 광고(adCampaign) 지표를 지정된 기간 범위 합산 (campaign status 고려 x) + // project 유무와 무관하게 adCampaign 이 조직에 속하면 집계 @Query("SELECT " + "COALESCE(SUM(m.impressions), 0) AS totalImpressions, " + "COALESCE(SUM(m.clicks), 0) AS totalClicks, " + @@ -69,10 +71,13 @@ MetricSumProjection findMetricsSumByOrgIdAndDateRange( "COALESCE(SUM(m.spend), 0) AS totalSpend, " + "COALESCE(SUM(m.revenue), 0) AS totalRevenue " + "FROM MetricFact m " + - "JOIN m.project p " + - "WHERE p.organization.id = :orgId " + - "AND p.organization.status = :orgStatus " + - "AND m.timeBucket >= :startDate AND m.timeBucket < :endDate " + "JOIN m.adContent ac " + + "JOIN ac.adGroup ag " + + "JOIN ag.adCampaign camp " + + "JOIN camp.organization o " + + "WHERE o.id = :orgId " + + "AND o.status = :orgStatus " + + "AND m.timeBucket >= :startDate AND m.timeBucket < :endDate" ) MetricSumProjection findMetricsSumByOrgIdAndDateRange( @Param("orgId") Long orgId, @@ -81,7 +86,7 @@ MetricSumProjection findMetricsSumByOrgIdAndDateRange( @Param("orgStatus") OrgStatus orgStatus ); - //orgId 와 provider 가 일치하고 해당 MetricFact 가 속한 AdCampaign 의 status 가 ON_GOING 인 지표에 대해 지정된 기간 범위 합산 + // orgId 와 provider 가 일치하고 해당 광고(adCampaign) 의 status 가 ON_GOING 인 지표에 대해 지정된 기간 범위 합산 @Query("SELECT " + "COALESCE(SUM(m.impressions), 0) AS totalImpressions, " + "COALESCE(SUM(m.clicks), 0) AS totalClicks, " + @@ -89,18 +94,16 @@ MetricSumProjection findMetricsSumByOrgIdAndDateRange( "COALESCE(SUM(m.spend), 0) AS totalSpend, " + "COALESCE(SUM(m.revenue), 0) AS totalRevenue " + "FROM MetricFact m " + - "JOIN m.project p " + - "WHERE p.organization.id = :orgId " + - "AND p.organization.status = :orgStatus " + + "JOIN m.adContent ac " + + "JOIN ac.adGroup ag " + + "JOIN ag.adCampaign camp " + + "JOIN camp.organization o " + + "WHERE o.id = :orgId " + + "AND o.status = :orgStatus " + "AND m.provider = :provider " + - "AND m.timeBucket >= :startDate AND m.timeBucket < :endDate " + - "AND m.adContent.id IN (" + - " SELECT ac.id " + - " FROM AdContent ac " + - " JOIN ac.adGroup ag " + - " JOIN ag.adCampaign camp " + - " WHERE camp.status = :status" + ")" - ) + "AND camp.status = :status " + + "AND m.timeBucket >= :startDate AND m.timeBucket < :endDate" + ) MetricSumProjection findMetricsSumByOrgIdAndProvider( @Param("orgId") Long orgId, @Param("provider") Provider provider, From cc72a326a87afcd1412edc5e992b5fb07cda0c7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=98=A4=EC=A4=80=EC=98=81?= Date: Tue, 7 Jul 2026 17:20:35 +0900 Subject: [PATCH 2/8] =?UTF-8?q?:recycle:=20refactor:=20DashboardServiceImp?= =?UTF-8?q?l=20=EB=82=B4=EB=B6=80=20=EC=A1=B0=EC=A7=81=20=EB=8B=A8?= =?UTF-8?q?=EC=9C=84=EB=A1=9C=20Metricfact=20=EC=B5=9C=EC=8B=A0=20?= =?UTF-8?q?=EC=8B=9C=EA=B0=84=20=EA=B0=92=20=EB=B6=88=EB=9F=AC=EC=98=A4?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard/domain/service/DashboardServiceImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/whereyouad/WhereYouAd/domains/dashboard/domain/service/DashboardServiceImpl.java b/src/main/java/com/whereyouad/WhereYouAd/domains/dashboard/domain/service/DashboardServiceImpl.java index 49e63ac9..99347456 100644 --- a/src/main/java/com/whereyouad/WhereYouAd/domains/dashboard/domain/service/DashboardServiceImpl.java +++ b/src/main/java/com/whereyouad/WhereYouAd/domains/dashboard/domain/service/DashboardServiceImpl.java @@ -109,11 +109,11 @@ public DashboardResponse.AggregatedSummaryResponse getAggregatedMetrics(Long use throw new DashboardException(ProjectErrorCode.ACCESS_FORBIDDEN); } - //DB 내부 Mock data 중 가장 최근의 timeBucket 값 추출 - LocalDateTime latestDate = metricFactRepository.findLatestTimeBucket() + //DB 내부 Mock data 중 조직별로 가장 최근의 timeBucket 값 추출 + LocalDateTime latestDate = metricFactRepository.findLatestTimeBucketByOrgId(orgId) .orElse(LocalDateTime.now()); - //DB 내부 Mock data 중 가장 최근의 timeBucket 값 기반 한달전, 두달전 기준 정립 + //DB 내부 조직별 Mock data 중 가장 최근의 timeBucket 값 기반 한달전, 두달전 기준 정립 LocalDateTime oneMonthAgo = latestDate.minusMonths(1); LocalDateTime twoMonthsAgo = latestDate.minusMonths(2); From 9f89cef115366791d293c7f5fc1a3a0354425616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=98=A4=EC=A4=80=EC=98=81?= Date: Tue, 7 Jul 2026 17:20:57 +0900 Subject: [PATCH 3/8] =?UTF-8?q?:recycle:=20refactor:=20=EB=AF=B8=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=20import=20=EB=AC=B8=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domains/dashboard/domain/service/DashboardServiceImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/whereyouad/WhereYouAd/domains/dashboard/domain/service/DashboardServiceImpl.java b/src/main/java/com/whereyouad/WhereYouAd/domains/dashboard/domain/service/DashboardServiceImpl.java index 99347456..523cd967 100644 --- a/src/main/java/com/whereyouad/WhereYouAd/domains/dashboard/domain/service/DashboardServiceImpl.java +++ b/src/main/java/com/whereyouad/WhereYouAd/domains/dashboard/domain/service/DashboardServiceImpl.java @@ -3,7 +3,6 @@ import com.whereyouad.WhereYouAd.domains.advertisement.domain.constant.Status; import com.whereyouad.WhereYouAd.domains.advertisement.exception.AdvertisementHandler; import com.whereyouad.WhereYouAd.domains.advertisement.exception.code.AdvertisementErrorCode; -import com.whereyouad.WhereYouAd.domains.advertisement.domain.constant.BudgetFieldType; import com.whereyouad.WhereYouAd.domains.advertisement.persistence.entity.BudgetHistory; import com.whereyouad.WhereYouAd.domains.advertisement.persistence.repository.AdCampaignRepository; import com.whereyouad.WhereYouAd.domains.advertisement.domain.constant.Provider; From 265ac3de3fcd0aeaf209f1b6f32fb02f383d3fef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=98=A4=EC=A4=80=EC=98=81?= Date: Tue, 7 Jul 2026 20:33:27 +0900 Subject: [PATCH 4/8] =?UTF-8?q?:recycle:=20refactor:=20=EC=A7=91=EA=B3=84?= =?UTF-8?q?=20=EA=B8=B0=EC=A4=80=20=EB=82=A0=EC=A7=9C=20=EC=B5=9C=EC=A0=81?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/service/DashboardServiceImpl.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/whereyouad/WhereYouAd/domains/dashboard/domain/service/DashboardServiceImpl.java b/src/main/java/com/whereyouad/WhereYouAd/domains/dashboard/domain/service/DashboardServiceImpl.java index 523cd967..d4bb9709 100644 --- a/src/main/java/com/whereyouad/WhereYouAd/domains/dashboard/domain/service/DashboardServiceImpl.java +++ b/src/main/java/com/whereyouad/WhereYouAd/domains/dashboard/domain/service/DashboardServiceImpl.java @@ -112,10 +112,12 @@ public DashboardResponse.AggregatedSummaryResponse getAggregatedMetrics(Long use LocalDateTime latestDate = metricFactRepository.findLatestTimeBucketByOrgId(orgId) .orElse(LocalDateTime.now()); - //DB 내부 조직별 Mock data 중 가장 최근의 timeBucket 값 기반 한달전, 두달전 기준 정립 - LocalDateTime oneMonthAgo = latestDate.minusMonths(1); + //집계 상한(endDate)은 exclusive(< endDate)이므로, 최신 버킷까지 포함하려면 하루 뒤를 상한으로 사용 + LocalDateTime currentEnd = latestDate.plusDays(1); - LocalDateTime twoMonthsAgo = latestDate.minusMonths(2); + //가장 최근 timeBucket 기준 한달전, 두달전 기준 정립 + LocalDateTime oneMonthAgo = currentEnd.minusMonths(1); + LocalDateTime twoMonthsAgo = currentEnd.minusMonths(2); MetricSumProjection currentProjection; MetricSumProjection pastProjection; @@ -124,7 +126,7 @@ public DashboardResponse.AggregatedSummaryResponse getAggregatedMetrics(Long use //시간값들과 회원이 속한 project 리스트 기반 projection 으로 DB 에서 //TotalImpressions, TotalClicks, TotalConversions, TotalSpend, TotalRevenue 를 집계해서 가져오기 currentProjection = metricFactRepository.findMetricsSumByOrgIdAndDateRange( - orgId, oneMonthAgo, latestDate, OrgStatus.ACTIVE, Status.ON_GOING + orgId, oneMonthAgo, currentEnd, OrgStatus.ACTIVE, Status.ON_GOING ); //가장 최근 ~ 한달 전의 집계 projection pastProjection = metricFactRepository.findMetricsSumByOrgIdAndDateRange( @@ -140,7 +142,7 @@ public DashboardResponse.AggregatedSummaryResponse getAggregatedMetrics(Long use throw new DashboardException(DashboardErrorCode.PROVIDER_NOT_VALID); } currentProjection = metricFactRepository.findMetricsSumByOrgIdAndProvider( - orgId, provider, oneMonthAgo, latestDate, OrgStatus.ACTIVE, Status.ON_GOING); + orgId, provider, oneMonthAgo, currentEnd, OrgStatus.ACTIVE, Status.ON_GOING); pastProjection = metricFactRepository.findMetricsSumByOrgIdAndProvider( orgId, provider, twoMonthsAgo, oneMonthAgo, OrgStatus.ACTIVE, Status.ON_GOING); } From def455654da1594edd19bcb258865a1e6e4f4cb2 Mon Sep 17 00:00:00 2001 From: ojy0903 Date: Tue, 7 Jul 2026 20:36:07 +0900 Subject: [PATCH 5/8] =?UTF-8?q?:art:=20style:=20=EC=A3=BC=EC=84=9D=20?= =?UTF-8?q?=EB=82=B4=EC=9A=A9=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domains/dashboard/domain/service/DashboardServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/whereyouad/WhereYouAd/domains/dashboard/domain/service/DashboardServiceImpl.java b/src/main/java/com/whereyouad/WhereYouAd/domains/dashboard/domain/service/DashboardServiceImpl.java index d4bb9709..eaa8effd 100644 --- a/src/main/java/com/whereyouad/WhereYouAd/domains/dashboard/domain/service/DashboardServiceImpl.java +++ b/src/main/java/com/whereyouad/WhereYouAd/domains/dashboard/domain/service/DashboardServiceImpl.java @@ -112,7 +112,7 @@ public DashboardResponse.AggregatedSummaryResponse getAggregatedMetrics(Long use LocalDateTime latestDate = metricFactRepository.findLatestTimeBucketByOrgId(orgId) .orElse(LocalDateTime.now()); - //집계 상한(endDate)은 exclusive(< endDate)이므로, 최신 버킷까지 포함하려면 하루 뒤를 상한으로 사용 + //집계에서 가장 최신 timeBucket 을 포함하기 위해 하루 뒤를 상한으로 사용 LocalDateTime currentEnd = latestDate.plusDays(1); //가장 최근 timeBucket 기준 한달전, 두달전 기준 정립 From 6e69ffab2041e46f307a2f87a137e82094ef13c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=98=A4=EC=A4=80=EC=98=81?= Date: Wed, 8 Jul 2026 14:03:24 +0900 Subject: [PATCH 6/8] =?UTF-8?q?Revert=20":recycle:=20refactor:=20MetricFac?= =?UTF-8?q?tRepository=20=EB=82=B4=EB=B6=80=20=EB=8C=80=EC=8B=9C=EB=B3=B4?= =?UTF-8?q?=EB=93=9C=EC=9A=A9=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 91224c861bf828c3f63c3778cba6de741065b052. --- .../repository/MetricFactRepository.java | 71 +++++++++---------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/src/main/java/com/whereyouad/WhereYouAd/domains/advertisement/persistence/repository/MetricFactRepository.java b/src/main/java/com/whereyouad/WhereYouAd/domains/advertisement/persistence/repository/MetricFactRepository.java index 58d81769..95fe1130 100644 --- a/src/main/java/com/whereyouad/WhereYouAd/domains/advertisement/persistence/repository/MetricFactRepository.java +++ b/src/main/java/com/whereyouad/WhereYouAd/domains/advertisement/persistence/repository/MetricFactRepository.java @@ -29,15 +29,12 @@ public interface MetricFactRepository extends JpaRepository { BigDecimal sumSpendsByUserIdAndOrgIdAndProvider(@Param("userId") Long userId, @Param("orgId") Long orgId, @Param("provider") Provider provider); - @Query("SELECT MAX(m.timeBucket) FROM MetricFact m " + - "JOIN m.adContent ac " + - "JOIN ac.adGroup ag " + - "JOIN ag.adCampaign camp " + - "WHERE camp.organization.id = :orgId") - Optional findLatestTimeBucketByOrgId(@Param("orgId") Long orgId); - - // orgId 에 속한 광고(adCampaign) 중 status 가 ON_GOING 인 지표를 지정된 기간 범위 합산 - // project 유무와 무관하게 adCampaign 이 조직에 속하면 집계 (status 서브쿼리를 조인으로 흡수) + //전체 지표 조회 로직에서 사용 + // 해당 프로젝트의 가장 최신 데이터 날짜를 가져오는 쿼리 + @Query("SELECT MAX(m.timeBucket) FROM MetricFact m") + Optional findLatestTimeBucket(); + + // orgId에 속한 모든 프로젝트의 지표중 해당 MetricFact 가 속한 AdCampaign 의 status 가 ON_GOING 인 지표를 지정된 기간 범위 합산 @Query("SELECT " + "COALESCE(SUM(m.impressions), 0) AS totalImpressions, " + "COALESCE(SUM(m.clicks), 0) AS totalClicks, " + @@ -45,15 +42,17 @@ BigDecimal sumSpendsByUserIdAndOrgIdAndProvider(@Param("userId") Long userId, @P "COALESCE(SUM(m.spend), 0) AS totalSpend, " + "COALESCE(SUM(m.revenue), 0) AS totalRevenue " + "FROM MetricFact m " + - "JOIN m.adContent ac " + - "JOIN ac.adGroup ag " + - "JOIN ag.adCampaign camp " + - "JOIN camp.organization o " + - "WHERE o.id = :orgId " + - "AND o.status = :orgStatus " + - "AND camp.status = :status " + - "AND m.timeBucket >= :startDate AND m.timeBucket < :endDate" - ) + "JOIN m.project p " + + "WHERE p.organization.id = :orgId " + + "AND p.organization.status = :orgStatus " + + "AND m.timeBucket >= :startDate AND m.timeBucket < :endDate " + + "AND m.adContent.id IN (" + + " SELECT ac.id " + + " FROM AdContent ac " + + " JOIN ac.adGroup ag " + + " JOIN ag.adCampaign camp " + + " WHERE camp.status = :status" + ")" + ) MetricSumProjection findMetricsSumByOrgIdAndDateRange( @Param("orgId") Long orgId, @Param("startDate") LocalDateTime startDate, @@ -62,8 +61,7 @@ MetricSumProjection findMetricsSumByOrgIdAndDateRange( @Param("status") Status status ); - // orgId 에 속한 광고(adCampaign) 지표를 지정된 기간 범위 합산 (campaign status 고려 x) - // project 유무와 무관하게 adCampaign 이 조직에 속하면 집계 + // orgId에 속한 모든 프로젝트의 지표중 해당 MetricFact 가 속한 AdCampaign 지표를 지정된 기간 범위 합산 (status 고려 x) @Query("SELECT " + "COALESCE(SUM(m.impressions), 0) AS totalImpressions, " + "COALESCE(SUM(m.clicks), 0) AS totalClicks, " + @@ -71,13 +69,10 @@ MetricSumProjection findMetricsSumByOrgIdAndDateRange( "COALESCE(SUM(m.spend), 0) AS totalSpend, " + "COALESCE(SUM(m.revenue), 0) AS totalRevenue " + "FROM MetricFact m " + - "JOIN m.adContent ac " + - "JOIN ac.adGroup ag " + - "JOIN ag.adCampaign camp " + - "JOIN camp.organization o " + - "WHERE o.id = :orgId " + - "AND o.status = :orgStatus " + - "AND m.timeBucket >= :startDate AND m.timeBucket < :endDate" + "JOIN m.project p " + + "WHERE p.organization.id = :orgId " + + "AND p.organization.status = :orgStatus " + + "AND m.timeBucket >= :startDate AND m.timeBucket < :endDate " ) MetricSumProjection findMetricsSumByOrgIdAndDateRange( @Param("orgId") Long orgId, @@ -86,7 +81,7 @@ MetricSumProjection findMetricsSumByOrgIdAndDateRange( @Param("orgStatus") OrgStatus orgStatus ); - // orgId 와 provider 가 일치하고 해당 광고(adCampaign) 의 status 가 ON_GOING 인 지표에 대해 지정된 기간 범위 합산 + //orgId 와 provider 가 일치하고 해당 MetricFact 가 속한 AdCampaign 의 status 가 ON_GOING 인 지표에 대해 지정된 기간 범위 합산 @Query("SELECT " + "COALESCE(SUM(m.impressions), 0) AS totalImpressions, " + "COALESCE(SUM(m.clicks), 0) AS totalClicks, " + @@ -94,16 +89,18 @@ MetricSumProjection findMetricsSumByOrgIdAndDateRange( "COALESCE(SUM(m.spend), 0) AS totalSpend, " + "COALESCE(SUM(m.revenue), 0) AS totalRevenue " + "FROM MetricFact m " + - "JOIN m.adContent ac " + - "JOIN ac.adGroup ag " + - "JOIN ag.adCampaign camp " + - "JOIN camp.organization o " + - "WHERE o.id = :orgId " + - "AND o.status = :orgStatus " + + "JOIN m.project p " + + "WHERE p.organization.id = :orgId " + + "AND p.organization.status = :orgStatus " + "AND m.provider = :provider " + - "AND camp.status = :status " + - "AND m.timeBucket >= :startDate AND m.timeBucket < :endDate" - ) + "AND m.timeBucket >= :startDate AND m.timeBucket < :endDate " + + "AND m.adContent.id IN (" + + " SELECT ac.id " + + " FROM AdContent ac " + + " JOIN ac.adGroup ag " + + " JOIN ag.adCampaign camp " + + " WHERE camp.status = :status" + ")" + ) MetricSumProjection findMetricsSumByOrgIdAndProvider( @Param("orgId") Long orgId, @Param("provider") Provider provider, From c046e986a853cc3bc7da35ee8d81cd1fe501d994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=98=A4=EC=A4=80=EC=98=81?= Date: Wed, 8 Jul 2026 14:10:11 +0900 Subject: [PATCH 7/8] =?UTF-8?q?:recycle:=20refactor:=20MetricFactRepositor?= =?UTF-8?q?y=20=EC=BB=A4=EB=B0=8B=20revert=20=EB=B0=8F=20=EA=B0=80?= =?UTF-8?q?=EC=9E=A5=20=EC=B5=9C=EA=B7=BC=20timeBucket=20=EA=B0=92=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EC=8B=9C=20project=20=EB=A5=BC=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=B4=20organization=20=EA=B3=BC=20?= =?UTF-8?q?=EC=97=B0=EA=B4=80=EC=84=B1=EC=9D=84=20=EC=B0=BE=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../persistence/repository/MetricFactRepository.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/whereyouad/WhereYouAd/domains/advertisement/persistence/repository/MetricFactRepository.java b/src/main/java/com/whereyouad/WhereYouAd/domains/advertisement/persistence/repository/MetricFactRepository.java index 95fe1130..65ba9b1d 100644 --- a/src/main/java/com/whereyouad/WhereYouAd/domains/advertisement/persistence/repository/MetricFactRepository.java +++ b/src/main/java/com/whereyouad/WhereYouAd/domains/advertisement/persistence/repository/MetricFactRepository.java @@ -29,10 +29,12 @@ public interface MetricFactRepository extends JpaRepository { BigDecimal sumSpendsByUserIdAndOrgIdAndProvider(@Param("userId") Long userId, @Param("orgId") Long orgId, @Param("provider") Provider provider); - //전체 지표 조회 로직에서 사용 + // 전체 지표 조회 로직에서 사용 // 해당 프로젝트의 가장 최신 데이터 날짜를 가져오는 쿼리 - @Query("SELECT MAX(m.timeBucket) FROM MetricFact m") - Optional findLatestTimeBucket(); + @Query("SELECT MAX(m.timeBucket) FROM MetricFact m " + + "JOIN m.project p " + + "WHERE p.organization.id = :orgId") + Optional findLatestTimeBucketByOrgId(@Param("orgId") Long orgId); // orgId에 속한 모든 프로젝트의 지표중 해당 MetricFact 가 속한 AdCampaign 의 status 가 ON_GOING 인 지표를 지정된 기간 범위 합산 @Query("SELECT " + From 1ce752eca7739fb61c50d9c5048d2732cef9e7e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=98=A4=EC=A4=80=EC=98=81?= Date: Wed, 8 Jul 2026 15:04:24 +0900 Subject: [PATCH 8/8] =?UTF-8?q?:art:=20style:=20=EC=A3=BC=EC=84=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../persistence/repository/MetricFactRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/whereyouad/WhereYouAd/domains/advertisement/persistence/repository/MetricFactRepository.java b/src/main/java/com/whereyouad/WhereYouAd/domains/advertisement/persistence/repository/MetricFactRepository.java index 65ba9b1d..e3010e24 100644 --- a/src/main/java/com/whereyouad/WhereYouAd/domains/advertisement/persistence/repository/MetricFactRepository.java +++ b/src/main/java/com/whereyouad/WhereYouAd/domains/advertisement/persistence/repository/MetricFactRepository.java @@ -30,7 +30,7 @@ BigDecimal sumSpendsByUserIdAndOrgIdAndProvider(@Param("userId") Long userId, @P @Param("provider") Provider provider); // 전체 지표 조회 로직에서 사용 - // 해당 프로젝트의 가장 최신 데이터 날짜를 가져오는 쿼리 + // 해당 조직(orgId)의 가장 최신 timeBucket을 가져오는 쿼리 @Query("SELECT MAX(m.timeBucket) FROM MetricFact m " + "JOIN m.project p " + "WHERE p.organization.id = :orgId")