Skip to content

[REFACTOR] 별점 EMA 도입#189

Merged
88guri merged 10 commits intodevelopfrom
refact/#79/add-review-ema
Jan 23, 2026
Merged

[REFACTOR] 별점 EMA 도입#189
88guri merged 10 commits intodevelopfrom
refact/#79/add-review-ema

Conversation

@88guri
Copy link
Copy Markdown
Collaborator

@88guri 88guri commented Jan 22, 2026

📌 관련 이슈

✨ 변경 사항

📸 테스트 증명 (필수)

image image image

📚 리뷰어 참고 사항

✅ 체크리스트

  • 브랜치 전략(git flow)을 따랐나요? (develop -> feat/...)
  • 로컬에서 빌드 및 실행이 정상적으로 되나요?
  • 불필요한 주석(TODO 등)이나 더미 코드는 제거했나요?
  • 컨벤션(커밋 메시지, 코드 스타일)을 지켰나요?

Summary by CodeRabbit

  • 새로운 기능

    • 공동구매 게시물에 대한 별점 등록 기능 추가(평균·카운트 자동집계)
    • 리뷰 작성 시 게시물 별점이 즉시 반영되어 판매자 평가에 기여
    • 게시물별 기여도 기반으로 판매자 평점 가중치 적용 및 갱신
  • 버그 수정

    • 별점 입력 범위 유효성 강화(1~5점만 허용)

✏️ Tip: You can customize this high-level summary in your review settings.

@88guri 88guri requested a review from PBEM22 January 22, 2026 23:16
@88guri 88guri self-assigned this Jan 22, 2026
@88guri 88guri added ♻️ Refactor 코드 리팩토링 (기능 변경 없음) ☁️ P2 시간 남으면 진행 (고도화) 🐵 시현 시현이에요 🌟Review 리뷰 labels Jan 22, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 22, 2026

📝 Walkthrough

Walkthrough

리뷰 생성 시 그룹바이 포스트와 판매자 평점에 가중평균(EMA) 방식으로 기여도를 반영하도록 새 엔티티·필드·서비스와 비관적 잠금을 도입했습니다. 리뷰 생성 흐름을 ApplicationService로 이동해 여러 서비스 간 트랜잭션을 조정합니다.

Changes

코호트 / 파일(s) 변경 요약
GroupBuyPost 엔티티
src/main/java/org/sopt/poti/domain/groupbuy/entity/GroupBuyPost.java
ratingAvg, ratingSum, ratingCount 필드 추가 및 addRating(int) / validateScore(int) 구현 (평점 집계 및 검증)
GroupBuyRepository
src/main/java/org/sopt/poti/domain/groupbuy/repository/GroupBuyRepository.java
findByIdWithLock(Long) 메서드 추가, @Lock(LockModeType.PESSIMISTIC_WRITE) + custom @Query로 포스트 행 잠금 조회
GroupBuyService
src/main/java/org/sopt/poti/domain/groupbuy/service/GroupBuyService.java
addPostRating, getPostWithLock, countPostsByLeader 공개 메서드 추가, 트랜잭션 경계 내에서 잠금 이용
리뷰 계층 재구성
src/main/java/org/sopt/poti/domain/review/application/ReviewApplicationService.java, .../controller/ReviewController.java, .../service/ReviewService.java, .../repository/ReviewRepository.java
ApplicationService 도입으로 리뷰 생성 흐름 이동. ReviewService는 엔티티 생성만 담당하도록 축소(메서드 시그니처 변경). ReviewRepository의 avgScoreBySellerId 제거
판매자 평점 가중치 시스템
src/main/java/org/sopt/poti/domain/user/entity/User.java, .../service/UserService.java
사용자 엔티티에 ratingSum, ratingCount, ratingWeightedSum, ratingWeightTotal 추가. addRatingWeightedDeltaapplyPostContribution(기여도 계산·적용) 추가, 내부 computeAlpha 구현
판매자-포스트 기여도 엔티티/레포지토리
src/main/java/org/sopt/poti/domain/user/entity/SellerPostRatingContribution.java, .../repository/SellerPostRatingContributionRepository.java
신규 엔티티(seller_post_rating_contributions, unique constraint) 및 레포지토리 추가, findBySellerIdAndPostIdWithLock(pessimistic write) 포함
UserRepository 잠금 조회
src/main/java/org/sopt/poti/domain/user/repository/UserRepository.java
findByIdWithLock(Long) 추가, @Lock(PESSIMISTIC_WRITE) + @Query 사용
에러 상태
src/main/java/org/sopt/poti/global/error/ErrorStatus.java
INVALID_RATING_SCORE(40019) 추가 — 평점 유효성 에러

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client
    participant Controller as ReviewController
    participant AppSvc as ReviewApplicationService
    participant OrderSvc as OrderService
    participant ReviewSvc as ReviewService
    participant GroupSvc as GroupBuyService
    participant UserSvc as UserService
    participant DB as Database

    Client->>Controller: POST /reviews (writerId, orderId, score)
    Controller->>AppSvc: createReview(writerId, request)
    AppSvc->>OrderSvc: validate & get Order
    OrderSvc-->>AppSvc: Order
    AppSvc->>ReviewSvc: createReviewEntity(writerId, Order, score)
    ReviewSvc->>DB: INSERT Review
    DB-->>ReviewSvc: reviewId
    ReviewSvc-->>AppSvc: reviewId
    AppSvc->>GroupSvc: addPostRating(postId, score)
    GroupSvc->>DB: select GroupBuyPost for update (pessimistic lock)
    DB-->>GroupSvc: GroupBuyPost
    GroupSvc->>GroupSvc: post.addRating(score) // update ratingSum/count/avg
    GroupSvc->>DB: save GroupBuyPost
    AppSvc->>GroupSvc: getPostWithLock(postId)
    GroupSvc->>DB: select GroupBuyPost (pessimistic lock)
    DB-->>GroupSvc: updated GroupBuyPost
    AppSvc->>GroupSvc: countPostsByLeader(sellerId)
    GroupSvc-->>AppSvc: postCount
    AppSvc->>UserSvc: applyPostContribution(sellerId, postId, postAvg, reviewCount, postCount)
    UserSvc->>DB: select User for update (pessimistic lock)
    DB-->>UserSvc: User
    UserSvc->>DB: select/create SellerPostRatingContribution for update
    DB-->>UserSvc: SellerPostRatingContribution
    UserSvc->>UserSvc: computeAlpha(...)
    UserSvc->>UserSvc: addRatingWeightedDelta(deltaWeightedSum, deltaWeight)
    UserSvc->>DB: save User and Contribution
    UserSvc-->>AppSvc: done
    AppSvc-->>Controller: reviewId
    Controller-->>Client: 201 Created
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

⭐️ P1

Suggested reviewers

  • PBEM22
🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.34% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 주요 변경사항인 EMA(지수이동평균) 도입을 명확하게 반영하고 있으며, 간결하고 구체적입니다.
Linked Issues check ✅ Passed 코드 변경사항들이 이슈 #79의 요구사항인 '별점 시스템에 EMA 도입'을 충분히 구현하고 있습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 EMA 도입이라는 범위 내에서 일관되게 진행되었으며, 범위를 벗어난 변경은 없습니다.

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

✨ Finishing touches
  • 📝 Generate docstrings

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.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@src/main/java/org/sopt/poti/domain/groupbuy/entity/GroupBuyPost.java`:
- Around line 207-220: The addRating currently computes a simple arithmetic mean
using ratingSum and ratingCount; to implement EMA change addRating(int score) to
first call validateScore(score) then update ratingAvg using the EMA formula
(ratingAvg = alpha * score + (1 - alpha) * ratingAvg) with a defined alpha
(e.g., a private static final double ALPHA = ...), handling the initial case
when ratingCount==0 by setting ratingAvg = score; you can still increment
ratingCount and optionally keep ratingSum for legacy purposes, but replace the
arithmetic-average calculation with the EMA update in the addRating method and
leave validateScore unchanged.
- Around line 72-79: Existing rows in the group_buy_posts table will not get the
new NOT NULL defaults, so create and run an explicit migration/backfill to set
rating_avg=0.0, rating_sum=0, rating_count=0 for all existing records before
deploying the GroupBuyPost field changes: implement a SQL migration (e.g.,
Flyway/V1__backfill_group_buy_ratings.sql or equivalent) that runs UPDATE
group_buy_posts SET rating_avg = 0.0, rating_sum = 0, rating_count = 0 WHERE
rating_avg IS NULL OR rating_sum IS NULL OR rating_count IS NULL, then verify
and only after that apply the schema change that makes ratingAvg, ratingSum,
ratingCount non-nullable in the GroupBuyPost entity.

In `@src/main/java/org/sopt/poti/domain/user/entity/User.java`:
- Around line 59-63: The User entity declares ratingSum and ratingCount but they
are never used; either remove these unused fields to avoid adding unnecessary DB
columns (delete ratingSum and ratingCount from class and update DB
migration/schema) or, if intended to track user ratings like GroupBuyPost, add
explicit usages: implement methods in User such as addRating(long delta) /
incrementRatingCount() / getAverageRating() and ensure service/repository code
updates these fields (referencing the User class and its ratingSum/ratingCount
symbols) so they are actually maintained; choose one approach and apply
corresponding schema migration changes.
🧹 Nitpick comments (1)
src/main/java/org/sopt/poti/domain/user/entity/User.java (1)

127-140: 부동소수점 비교와 입력 유효성 검증에 대해 검토가 필요해요.

몇 가지 엣지 케이스 고려해보면 좋을 것 같아요:

  1. 부동소수점 정밀도 이슈: ratingWeightTotal <= 0.0 비교가 여러 번의 delta 연산 후 부동소수점 오차로 인해 미세하게 양수(예: 0.0000000001)가 되면 의도치 않게 0으로 나누는 상황이 발생할 수 있어요. 아주 작은 양수에 대한 임계값(threshold) 비교를 고려해볼 수 있어요.

  2. 입력 유효성: deltaWeightedSum이나 deltaWeightNaN 또는 Infinity일 경우 데이터가 오염될 수 있어요.

♻️ 개선 제안
  public void addRatingWeightedDelta(double deltaWeightedSum, double deltaWeight) {
+   if (Double.isNaN(deltaWeightedSum) || Double.isInfinite(deltaWeightedSum) ||
+       Double.isNaN(deltaWeight) || Double.isInfinite(deltaWeight)) {
+     throw new IllegalArgumentException("Invalid delta values");
+   }
+
    this.ratingWeightedSum += deltaWeightedSum;
    this.ratingWeightTotal += deltaWeight;

-   if (this.ratingWeightTotal <= 0.0) {
+   // 부동소수점 오차를 고려한 임계값 비교
+   if (this.ratingWeightTotal < 1e-9) {
      this.ratingWeightedSum = 0.0;
      this.ratingWeightTotal = 0.0;
      this.ratingAvg = 0.0;
      return;
    }

    double avg = this.ratingWeightedSum / this.ratingWeightTotal;
    this.ratingAvg = Math.round(avg * 10) / 10.0;
  }

Comment thread src/main/java/org/sopt/poti/domain/groupbuy/entity/GroupBuyPost.java Outdated
Comment on lines +59 to +63
@Column(name = "rating_sum", nullable = false)
private long ratingSum = 0L;

@Column(name = "rating_count", nullable = false)
private int ratingCount = 0;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for ratingSum and ratingCount usages across the codebase

echo "=== Searching for ratingSum usages ==="
rg -n --type=java 'ratingSum' -C 2

echo ""
echo "=== Searching for ratingCount usages ==="
rg -n --type=java 'ratingCount' -C 2

Repository: team-poti/POTI-SERVER

Length of output: 3467


ratingSumratingCount 필드가 User 엔티티 내에서 사용되고 있지 않아요.

이 두 필드는 선언만 되어 있고 User 클래스의 어떤 메서드에서도 실제로 사용되지 않고 있네요. 흥미롭게도 GroupBuyPost 엔티티에는 동일한 필드들이 있고 여기서는 적극적으로 사용 중입니다 (rating 계산에서 합계와 개수를 누적하는 형태).

혹시 다른 레이어(서비스, 리포지토리)에서 이 필드들을 사용 중이라면 괜찮지만, 엔티티 단에서 전혀 사용되지 않는다면 불필요한 DB 컬럼 추가가 될 수 있습니다. 한 번 확인해 보시는 게 좋을 것 같아요.

🤖 Prompt for AI Agents
In `@src/main/java/org/sopt/poti/domain/user/entity/User.java` around lines 59 -
63, The User entity declares ratingSum and ratingCount but they are never used;
either remove these unused fields to avoid adding unnecessary DB columns (delete
ratingSum and ratingCount from class and update DB migration/schema) or, if
intended to track user ratings like GroupBuyPost, add explicit usages: implement
methods in User such as addRating(long delta) / incrementRatingCount() /
getAverageRating() and ensure service/repository code updates these fields
(referencing the User class and its ratingSum/ratingCount symbols) so they are
actually maintained; choose one approach and apply corresponding schema
migration changes.

…to refact/#79/add-review-ema

# Conflicts:
#	src/main/java/org/sopt/poti/domain/participation/service/ParticipationService.java
Copy link
Copy Markdown
Collaborator

@PBEM22 PBEM22 left a comment

Choose a reason for hiding this comment

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

믿습니다.

@88guri
Copy link
Copy Markdown
Collaborator Author

88guri commented Jan 23, 2026

@PBEM22 믿지마세요

@88guri 88guri merged commit c67d7b5 into develop Jan 23, 2026
2 checks passed
PBEM22 added a commit that referenced this pull request Jan 23, 2026
…ema"

This reverts commit c67d7b5, reversing
changes made to 7da1e70.
@coderabbitai coderabbitai bot mentioned this pull request Jan 23, 2026
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

☁️ P2 시간 남으면 진행 (고도화) ♻️ Refactor 코드 리팩토링 (기능 변경 없음) 🌟Review 리뷰 🐵 시현 시현이에요

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[REFACTOR] 별점에 EMA 도입

2 participants