Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
a9339ff
commerce-batch ๋ชจ๋“ˆ์„ ์ถ”๊ฐ€ํ•˜๋ฉฐ, ๋ฐ๋ชจ Batch Job ๋ฐ ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
hubtwork Dec 31, 2025
3f9eb4f
commerce-batch ๋ชจ๋“ˆ์— ๋Œ€ํ•ด README ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
hubtwork Dec 31, 2025
569eb94
refactor: ์ผ๋ณ„ ๋ฉ”ํŠธ๋ฆญ ํ…Œ์ด๋ธ” ๊ตฌ์กฐ ๊ฐœ์„ 
junoade Jan 1, 2026
8206004
init : ๋ฐฐ์น˜ ์ž‘์—… ๊ฐœ๋ฐœ๊ณ„ ๋ฐ์ดํ„ฐ๋กœ๋“œ
junoade Jan 1, 2026
0a98c34
feat: MV ๋„๋ฉ”์ธ, ๋ ˆํฌ ์ถ”๊ฐ€
junoade Jan 1, 2026
8472ca2
refactor: ๋‚ ์งœ ๊ด€๋ จ ๋ณ€๊ฒฝ
junoade Jan 1, 2026
500f4b5
feat: ์ฃผ๊ฐ„ ์ง‘๊ณ„ ๋ฐฐ์น˜ ์žก ๊ตฌํ˜„
junoade Jan 1, 2026
0979b35
refactor: mv ํ…Œ์ด๋ธ” ๋‚ด score์ปฌ๋Ÿผ ์ถ”๊ฐ€
junoade Jan 1, 2026
35541d6
feat: processor, mv ํ…Œ์ด๋ธ” ๋‚ด score ๊ณ„์‚ฐ ๋ฐ writer ์ฝ”๋“œ ์ถ”๊ฐ€
junoade Jan 1, 2026
a99b224
fix: stepListener ๊ฐœ์„ 
junoade Jan 1, 2026
1abf6d0
feat: ์›”๊ฐ„ ์ง‘๊ณ„ ๋ฐฐ์น˜ ๊ตฌํ˜„
junoade Jan 1, 2026
ff0d7d3
refactor: Materialized View ๋ชจ๋“ˆ ์œ„์น˜ ๋ณ€๊ฒฝ
junoade Jan 1, 2026
e3d4b05
feat: ์ƒํ’ˆ์ •๋ณด ์กฐํšŒ API - ์ผ๊ฐ„, ์ฃผ๊ฐ„, ์›”๊ฐ„ ๋žญํ‚น ์ œ๊ณต ๊ธฐ๋Šฅ ์ถ”๊ฐ€
junoade Jan 1, 2026
ca9b019
Merge pull request #36 from junoade/week10-batch
junoade Jan 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ docker-compose -f ./docker/monitoring-compose.yml up
Root
โ”œโ”€โ”€ apps ( spring-applications )
โ”‚ โ”œโ”€โ”€ ๐Ÿ“ฆ commerce-api
โ”‚ โ”œโ”€โ”€ ๐Ÿ“ฆ commerce-batch
โ”‚ โ””โ”€โ”€ ๐Ÿ“ฆ commerce-streamer
โ”œโ”€โ”€ modules ( reusable-configurations )
โ”‚ โ”œโ”€โ”€ ๐Ÿ“ฆ jpa
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.loopers.application.ranking;

public enum RankingPeriod {
DAILY,
WEEKLY,
MONTHLY
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.loopers.application.ranking;

import java.time.LocalDate;

public record RankingQuery(
RankingPeriod period,
String key,
LocalDate date,
int limit
) { }
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package com.loopers.application.ranking;

import com.loopers.application.like.event.ProductLikeEvent;
import com.loopers.application.product.ProductLikeSummary;
import com.loopers.application.product.ProductQueryService;
import com.loopers.domain.product.ProductSortType;
import com.loopers.ranking.DailyRankingResponse;
import com.loopers.application.ranking.strategy.RankingFetchStrategyResolver;
import com.loopers.ranking.RankingEntry;
import com.loopers.ranking.RankingZSetRepository;
import com.loopers.support.error.CoreException;
Expand All @@ -16,8 +14,6 @@

import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.OptionalDouble;
Expand All @@ -29,17 +25,20 @@ public class RankingQueryService {
private final RankingZSetRepository rankingZSetRepository;
private final ProductQueryService productQueryService;

private final RankingFetchStrategyResolver rankingResolver;

@Transactional(readOnly = true)
public RankingQueryResponse getDailyPopularProducts(String date, int size) {
LocalDate target = initLocalDate(date);
public RankingQueryResponse getDailyPopularProducts(RankingPeriod period, String date, int size) {
log.debug("Get {} popular products for {}", period, date);

int limit = (size <= 0) ? 20 : Math.min(size, 100);
RankingFetchStrategyResolver.Resolved resolved = rankingResolver.resolve(period, date, size);
RankingQuery rankingQuery = resolved.rankingQuery();

List<RankingEntry> rankingEntries = rankingZSetRepository.findTopDailyAllByLimit(target, limit);
List<RankingEntry> rankingEntries = resolved.policy().fetchRankingEntries(rankingQuery.key(), rankingQuery.limit());
List<ProductLikeSummary> productLikeSummaries = findProductSummaryFrom(rankingEntries);

return new RankingQueryResponse(
target,
rankingQuery.date(),
rankingEntries,
productLikeSummaries
);
Expand All @@ -51,17 +50,6 @@ public OptionalDouble getDailyRankingScore(Long productId) {
return rankingZSetRepository.findDailyRanking(now, productId);
}

private boolean hasValidDate(String date) {
return date == null || date.isBlank();
}

private LocalDate initLocalDate(String date) {
return (hasValidDate(date))
? LocalDate.now(ZoneId.systemDefault())
: LocalDate.parse(date, DateTimeFormatter.BASIC_ISO_DATE);

}

private List<ProductLikeSummary> findProductSummaryFrom(List<RankingEntry> rankingEntries) {
List<ProductLikeSummary> result = new ArrayList<>();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.loopers.application.ranking.strategy;

import com.loopers.application.ranking.RankingPeriod;
import com.loopers.ranking.RankingEntry;
import com.loopers.ranking.RankingZSetRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.List;

@Component
@RequiredArgsConstructor
public class DailyRankingFetcher implements RankingFetchStrategy {
private final RankingZSetRepository rankingZSetRepository;

@Override
public RankingPeriod getRankingPeriod() {
return RankingPeriod.DAILY;
}

@Override
public List<RankingEntry> fetchRankingEntries(String key, int limit) {
LocalDate target = initLocalDate(key);
return rankingZSetRepository.findTopDailyAllByLimit(target, limit);
}

private LocalDate initLocalDate(String date) {
return (hasValidDate(date))
? LocalDate.now(ZoneId.systemDefault())
: LocalDate.parse(date, DateTimeFormatter.BASIC_ISO_DATE);
}

private boolean hasValidDate(String date) {
return date == null || date.isBlank();
}
Comment on lines +30 to +38
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue | ๐ŸŸ  Major

๋ฉ”์„œ๋“œ ์ด๋ฆ„์ด ์‹ค์ œ ๋™์ž‘๊ณผ ๋ฐ˜๋Œ€์ž…๋‹ˆ๋‹ค.

hasValidDate() ๋ฉ”์„œ๋“œ๋Š” date๊ฐ€ null์ด๊ฑฐ๋‚˜ blank์ผ ๋•Œ true๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” "์œ ํšจํ•œ ๋‚ ์งœ๊ฐ€ ์žˆ๋Š”์ง€"๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ "๋‚ ์งœ๊ฐ€ ์—†๋Š”์ง€"๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด๋ฏ€๋กœ, ๋ฉ”์„œ๋“œ ์ด๋ฆ„์ด ๋กœ์ง๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š์•„ ํ˜ผ๋ž€์„ ์•ผ๊ธฐํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ ๋‚ ์งœ ํŒŒ์‹ฑ ์‹œ DateTimeParseException์— ๋Œ€ํ•œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๊ฐ€ ์—†์–ด, ์ž˜๋ชป๋œ ํ˜•์‹์˜ ๋‚ ์งœ๊ฐ€ ์ „๋‹ฌ๋  ๊ฒฝ์šฐ ์ ์ ˆํ•œ ์—๋Ÿฌ ์‘๋‹ต ์—†์ด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ”Ž ์ œ์•ˆํ•˜๋Š” ๊ฐœ์„ ์‚ฌํ•ญ
 private LocalDate initLocalDate(String date) {
-    return (hasValidDate(date))
+    return (isDateMissing(date))
             ? LocalDate.now(ZoneId.systemDefault())
-            : LocalDate.parse(date, DateTimeFormatter.BASIC_ISO_DATE);
+            : parseDate(date);
 }

-private boolean hasValidDate(String date) {
+private boolean isDateMissing(String date) {
     return date == null || date.isBlank();
 }

+private LocalDate parseDate(String date) {
+    try {
+        return LocalDate.parse(date, DateTimeFormatter.BASIC_ISO_DATE);
+    } catch (DateTimeParseException e) {
+        throw new IllegalArgumentException(
+            "Invalid date format. Expected format: yyyyMMdd, but got: " + date, e);
+    }
+}
๐Ÿ“ Committable suggestion

โ€ผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private LocalDate initLocalDate(String date) {
return (hasValidDate(date))
? LocalDate.now(ZoneId.systemDefault())
: LocalDate.parse(date, DateTimeFormatter.BASIC_ISO_DATE);
}
private boolean hasValidDate(String date) {
return date == null || date.isBlank();
}
private LocalDate initLocalDate(String date) {
return (isDateMissing(date))
? LocalDate.now(ZoneId.systemDefault())
: parseDate(date);
}
private boolean isDateMissing(String date) {
return date == null || date.isBlank();
}
private LocalDate parseDate(String date) {
try {
return LocalDate.parse(date, DateTimeFormatter.BASIC_ISO_DATE);
} catch (DateTimeParseException e) {
throw new IllegalArgumentException(
"Invalid date format. Expected format: yyyyMMdd, but got: " + date, e);
}
}
๐Ÿค– Prompt for AI Agents
In
apps/commerce-api/src/main/java/com/loopers/application/ranking/strategy/DailyRankingFetcher.java
around lines 30-38, the helper method name and logic are inverted and there is
no parsing error handling: rename or flip hasValidDate so its name matches its
behavior (e.g., isBlankOrNull -> retains current boolean) or change its logic to
return true when the input is a valid non-blank date, then update initLocalDate
to use the corrected predicate; additionally wrap LocalDate.parse in a try/catch
for DateTimeParseException and handle it by throwing a controlled application
exception or returning a clear error value (or fallback) with a descriptive
message so malformed dates do not propagate raw exceptions.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.loopers.application.ranking.strategy;

import com.loopers.application.ranking.RankingPeriod;
import com.loopers.infrastructure.ranking.ProductRankMonthlyRepository;
import com.loopers.ranking.RankingEntry;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Component;

import java.util.List;

@Slf4j
@Component
@RequiredArgsConstructor
public class MonthlyRankingFetcher implements RankingFetchStrategy {
private final ProductRankMonthlyRepository monthlyRankingRepository;

@Override
public RankingPeriod getRankingPeriod() {
return RankingPeriod.MONTHLY;
}

@Override
public List<RankingEntry> fetchRankingEntries(String key, int limit) {
log.debug("Fetching ranking entries for key {}", key);
return monthlyRankingRepository.findTopByYearMonth(key, PageRequest.of(0, limit));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.loopers.application.ranking.strategy;

import com.loopers.application.ranking.RankingPeriod;
import com.loopers.ranking.RankingEntry;

import java.util.List;


public interface RankingFetchStrategy {
RankingPeriod getRankingPeriod();
List<RankingEntry> fetchRankingEntries(String key, int limit);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package com.loopers.application.ranking.strategy;

import com.loopers.application.ranking.RankingPeriod;
import com.loopers.application.ranking.RankingQuery;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.WeekFields;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Component
public class RankingFetchStrategyResolver {
private static final DateTimeFormatter YYYYMMDD = DateTimeFormatter.BASIC_ISO_DATE;
private static final DateTimeFormatter YYYYMM = DateTimeFormatter.ofPattern("yyyyMM");
private final Map<RankingPeriod, RankingFetchStrategy> policies;

public RankingFetchStrategyResolver(List<RankingFetchStrategy> policies) {
this.policies = policies.stream()
.collect(Collectors.toMap(RankingFetchStrategy::getRankingPeriod, Function.identity()));
}

/**
* ๋žญํ‚น ์กฐํšŒ ๋ฐฉ๋ฒ•์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.
* @param period
* @param date
* @param size
* @return
*/
public Resolved resolve(RankingPeriod period, String date, int size) {
LocalDate target = initLocalDate(date);
int limit = normalizeSize(size);

String key = switch (period) {
case DAILY -> target.format(YYYYMMDD);
case WEEKLY -> yearWeekKey(target); // 2026-W01
case MONTHLY -> target.format(YYYYMM); // 202601
};

RankingFetchStrategy policy = policies.get(period);
if (policy == null) throw new IllegalArgumentException("Unsupported period: " + period);

return new Resolved(new RankingQuery(period, key, target, limit), policy);
}

public record Resolved(RankingQuery rankingQuery, RankingFetchStrategy policy) {}

/**
* ์ตœ๋Œ€ ์ƒํ•œ์„  TOP-100 ์œผ๋กœ ์„ค์ •
* @param size
* @return
*/
private int normalizeSize(int size) {
if (size <= 0) return 20;
return Math.min(size, 100);
}

private LocalDate initLocalDate(String date) {
return (hasValidDate(date))
? LocalDate.now(ZoneId.systemDefault())
: LocalDate.parse(date, DateTimeFormatter.BASIC_ISO_DATE);
}

private String yearWeekKey(LocalDate date) {
WeekFields wf = WeekFields.ISO;
int y = date.get(wf.weekBasedYear());
int w = date.get(wf.weekOfWeekBasedYear());
return "%d-W%02d".formatted(y, w);
}

private boolean hasValidDate(String date) {
return date == null || date.isBlank();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.loopers.application.ranking.strategy;

import com.loopers.application.ranking.RankingPeriod;
import com.loopers.infrastructure.ranking.ProductRankWeeklyRepository;
import com.loopers.ranking.RankingEntry;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Component;

import java.util.List;

@Slf4j
@Component
@RequiredArgsConstructor
public class WeeklyRankingFetcher implements RankingFetchStrategy {
private final ProductRankWeeklyRepository weeklyRankingRepository;

@Override
public RankingPeriod getRankingPeriod() {
return RankingPeriod.WEEKLY;
}

@Override
public List<RankingEntry> fetchRankingEntries(String key, int limit) {
log.debug("Fetching ranking entries for key {}", key);
return weeklyRankingRepository.findTopByYearWeek(key, PageRequest.of(0, limit));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.loopers.domain.mv;

import jakarta.persistence.Column;
import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Entity
@Table(name = "mv_product_rank_monthly")
@Getter
@NoArgsConstructor
public class ProductRankMonthly {

@EmbeddedId
private ProductRankMonthlyId id;

@Column(name = "view_count", nullable = false)
private long viewCount;

@Column(name = "like_count", nullable = false)
private long likeCount;

@Column(name = "order_count", nullable = false)
private long orderCount;

@Column(name = "score", nullable = false)
private double score;

@Column(name = "created_at", nullable = false)
private LocalDateTime createdAt;

@Column(name = "updated_at", nullable = false)
private LocalDateTime updatedAt;

public static ProductRankMonthly of(String yearMonth, Long productId,
long viewCount, long likeCount, long orderCount) {
ProductRankMonthly e = new ProductRankMonthly();
e.id = new ProductRankMonthlyId(yearMonth, productId);
e.viewCount = viewCount;
e.likeCount = likeCount;
e.orderCount = orderCount;
e.createdAt = LocalDateTime.now();
e.updatedAt = LocalDateTime.now();
return e;
}
Comment on lines +39 to +49
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue | ๐Ÿ”ด Critical

์น˜๋ช…์ : score ํ•„๋“œ๊ฐ€ ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

score ํ•„๋“œ๋Š” nullable = false๋กœ ์„ ์–ธ๋˜์–ด ์žˆ์ง€๋งŒ of() ๋ฉ”์„œ๋“œ์—์„œ ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์—”ํ‹ฐํ‹ฐ ์ €์žฅ ์‹œ ์ œ์•ฝ์กฐ๊ฑด ์œ„๋ฐ˜(constraint violation)์„ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

๋ฐฐ์น˜ ์ž‘์—…์˜ RankMonthlyProcessor์—์„œ ์ ์ˆ˜๋ฅผ ๊ณ„์‚ฐํ•˜๋ฏ€๋กœ, ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ๊ฐ€ score ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ฐ›์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ”Ž ์ œ์•ˆํ•˜๋Š” ์ˆ˜์ •์‚ฌํ•ญ
 public static ProductRankMonthly of(String yearMonth, Long productId,
-                                    long viewCount, long likeCount, long orderCount) {
+                                    long viewCount, long likeCount, long orderCount, double score) {
     ProductRankMonthly e = new ProductRankMonthly();
     e.id = new ProductRankMonthlyId(yearMonth, productId);
     e.viewCount = viewCount;
     e.likeCount = likeCount;
     e.orderCount = orderCount;
+    e.score = score;
     e.createdAt = LocalDateTime.now();
     e.updatedAt = LocalDateTime.now();
     return e;
 }

๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ProductRankWeekly.java์—๋„ ์กด์žฌํ•˜๋ฏ€๋กœ ํ•จ๊ป˜ ์ˆ˜์ •์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“ Committable suggestion

โ€ผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public static ProductRankMonthly of(String yearMonth, Long productId,
long viewCount, long likeCount, long orderCount) {
ProductRankMonthly e = new ProductRankMonthly();
e.id = new ProductRankMonthlyId(yearMonth, productId);
e.viewCount = viewCount;
e.likeCount = likeCount;
e.orderCount = orderCount;
e.createdAt = LocalDateTime.now();
e.updatedAt = LocalDateTime.now();
return e;
}
public static ProductRankMonthly of(String yearMonth, Long productId,
long viewCount, long likeCount, long orderCount, double score) {
ProductRankMonthly e = new ProductRankMonthly();
e.id = new ProductRankMonthlyId(yearMonth, productId);
e.viewCount = viewCount;
e.likeCount = likeCount;
e.orderCount = orderCount;
e.score = score;
e.createdAt = LocalDateTime.now();
e.updatedAt = LocalDateTime.now();
return e;
}
๐Ÿค– Prompt for AI Agents
In apps/commerce-api/src/main/java/com/loopers/domain/mv/ProductRankMonthly.java
around lines 39-49, the factory method of(...) fails to initialize the
non-nullable score field causing constraint violations; update the method
signature to accept a score parameter (e.g., double or appropriate numeric
type), set e.score = score before returning, and ensure callers (including
RankMonthlyProcessor batch code) pass the computed score; apply the identical
change to ProductRankWeekly to keep both factory methods consistent.


public void overwrite(long viewCount, long likeCount, long orderCount) {
this.viewCount = viewCount;
this.likeCount = likeCount;
this.orderCount = orderCount;
this.updatedAt = LocalDateTime.now();
}
Comment on lines +51 to +56
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue | ๐Ÿ”ด Critical

์น˜๋ช…์ : score ํ•„๋“œ๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

overwrite() ๋ฉ”์„œ๋“œ์—์„œ ์นด์šดํŠธ ํ•„๋“œ๋“ค์„ ์—…๋ฐ์ดํŠธํ•˜์ง€๋งŒ score ํ•„๋“œ๋Š” ์—…๋ฐ์ดํŠธํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์นด์šดํŠธ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ์ ์ˆ˜๋„ ์žฌ๊ณ„์‚ฐ๋˜์–ด์•ผ ํ•˜๋ฏ€๋กœ, score ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ”Ž ์ œ์•ˆํ•˜๋Š” ์ˆ˜์ •์‚ฌํ•ญ
-public void overwrite(long viewCount, long likeCount, long orderCount) {
+public void overwrite(long viewCount, long likeCount, long orderCount, double score) {
     this.viewCount = viewCount;
     this.likeCount = likeCount;
     this.orderCount = orderCount;
+    this.score = score;
     this.updatedAt = LocalDateTime.now();
 }

๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ProductRankWeekly.java์˜ overwrite() ๋ฉ”์„œ๋“œ์—๋„ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“ Committable suggestion

โ€ผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public void overwrite(long viewCount, long likeCount, long orderCount) {
this.viewCount = viewCount;
this.likeCount = likeCount;
this.orderCount = orderCount;
this.updatedAt = LocalDateTime.now();
}
public void overwrite(long viewCount, long likeCount, long orderCount, double score) {
this.viewCount = viewCount;
this.likeCount = likeCount;
this.orderCount = orderCount;
this.score = score;
this.updatedAt = LocalDateTime.now();
}
๐Ÿค– Prompt for AI Agents
In apps/commerce-api/src/main/java/com/loopers/domain/mv/ProductRankMonthly.java
around lines 51โ€“56, the overwrite(...) method updates viewCount, likeCount,
orderCount and updatedAt but does not update the score; change the method
signature to accept a score parameter (e.g., double or long matching the score
field type), assign this.score = score inside the method, and update updatedAt
as now; also search for and update all callsites to pass the recalculated score,
and apply the same change to ProductRankWeekly.java's overwrite(...) to keep
behavior consistent.


public Long productId() {
return id.getProductId();
}

public String yearMonth() {
return id.getYearMonth();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.loopers.domain.mv;

import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import lombok.*;

import java.io.Serializable;

@Embeddable
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@EqualsAndHashCode
public class ProductRankMonthlyId implements Serializable {

@Column(name = "year_month_key", length = 8, nullable = false)
private String yearMonth; // e.g. 202601

@Column(name = "product_id", nullable = false)
private Long productId;
}
Loading