Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
3d8d038
[BE] [REFACTOR] 불필요한 스케줄러 제거 및 통합
Yooonjeong Jan 19, 2026
adccd84
[BE] [FEAT] UserBet에 베팅 무승부 처리 메서드 추가
Yooonjeong Jan 19, 2026
50e1f6a
[BE] [FEAT] BetRound에 무승부 상태 판단 메서드 추가
Yooonjeong Jan 19, 2026
78ffca0
[BE] [FEAT] 낙관적 락 예외 발생 시 재시도 처리를 위한 어노테이션 정의
Yooonjeong Jan 19, 2026
f987439
[BE] [FEAT] 낙관적 락 예외 발생 시 재시도 처리를 위한 Aspect 정의
Yooonjeong Jan 19, 2026
f756370
[BE] [REFACTOR] 포인트 업데이트 시 @Retryable 및 @Recover -> 어노테이션으로 대체
Yooonjeong Jan 19, 2026
7c565e6
[BE] [FEAT] 배당률에 따른 베팅 보상 포인트 계산 로직 추가
Yooonjeong Jan 19, 2026
cb76ed2
[BE] [FEAT] 베팅 정산 시 가격 변동이 없으면 전원 포인트 환불 로직 추가
Yooonjeong Jan 19, 2026
077682c
[BE] [REFACTOR] 불필요 메서드 삭제
Yooonjeong Jan 19, 2026
e95ed9d
[BE] [FEAT] 포인트 업데이트 포함된 메서드에 @OptimisticRetry 어노테이션 적용
Yooonjeong Jan 19, 2026
c0b27ca
[BE] [FEAT] 베팅 취소 시 직접 낙관적 락 예외를 잡는 방식에서 @OptimisticRetry으로 변경
Yooonjeong Jan 19, 2026
2d435b9
[BE] [FIX] 스케줄러 동작 시간 수정
Yooonjeong Jan 19, 2026
595706e
[BE] [REFACTOR] 스케줄러 메서드명 수정
Yooonjeong Jan 19, 2026
b55b49b
[BE] [REFACTOR] 스케줄러 현재 시간 판단 시 타임존(Asia/Seoul) 명시
Yooonjeong Jan 21, 2026
c6daf86
[BE] [REFACTOR] 여러 활성 라운드에 대한 사용자 베팅을 IN절로 한 번에 조회하도록 쿼리 수정
Yooonjeong Jan 21, 2026
2a038aa
[BE] [REFACTOR] FETCH JOIN으로 UserBet 및 BetRound 한 번에 조회하도록 쿼리 수정
Yooonjeong Jan 21, 2026
6f56b48
[BE] [REFACTOR] 베팅 서비스 조회 메서드들에 readOnly @Transactional 추가
Yooonjeong Jan 21, 2026
afbd860
[BE] [REFACTOR] @Transactional 추가하여 더티 체킹으로 업데이트
Yooonjeong Jan 21, 2026
77ed0f5
[BE] [REFACTOR] DB 접근 전 단순 포인트 검증 먼저 하도록 수정
Yooonjeong Jan 21, 2026
597e9cb
[BE] [REFACTOR] userBet DB 조회 전 베팅 라운드 검증 먼저 수행하도록 변경
Yooonjeong Jan 21, 2026
4833f57
[BE] [REFACTOR] 추가 BetRound 조회 없이 FETCH JOIN으로 한 번에 조회하도록 수정
Yooonjeong Jan 21, 2026
e45b5d5
[BE] [REFACTOR] 활성 라운드의 전체 베팅 한 번에 조회하여 메모리에서 라운드별 필터링하도록 수정
Yooonjeong Jan 21, 2026
6d612f4
[BE] [REFACTOR] 더티체킹 -> 명시적 save 제거
Yooonjeong Jan 21, 2026
5ad339f
[BE] [FIX] 베팅 무승부 포인트 환불 시 조건 추가
Yooonjeong Jan 21, 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
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ public boolean isClosed() {
return !this.status;
}

// 라운드가 무승부로 종료되었는지 여부 반환
// TODO: flyway 도입 시 BetOption에 DRAW 상태 추가 고려
public boolean isDraw() {
return this.settleAt != null && this.resultOption == null;
}

// 베팅 시작
public void open() {
this.status = true;
Expand Down Expand Up @@ -152,7 +158,8 @@ public void settle(BigDecimal finalPrice) {
// 결과 판정 로직 - 이전 종가와 비교하여 상승/하락 결정
private BetOption determineResult(BigDecimal finalPrice) {
int compare = finalPrice.compareTo(previousClosePrice);
if (compare >= 0) return BetOption.RISE;
return BetOption.FALL;
if (compare > 0) return BetOption.RISE;
else if (compare < 0) return BetOption.FALL;
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ public void lose() {
this.betStatus = BetStatus.CLOSED;
}

public void draw() {
this.payoutPoints = this.stakePoints;
this.isCorrect = false;
this.betStatus = BetStatus.CLOSED;
}

// 취소 상태 변경 메서드
public void cancel() {
this.betStatus = BetStatus.DELETED;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import org.sejongisc.backend.betting.entity.BetRound;
import org.sejongisc.backend.betting.entity.UserBet;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;
import java.util.Optional;
Expand All @@ -11,11 +13,14 @@
public interface UserBetRepository extends JpaRepository<UserBet, UUID> {
Optional<UserBet> findByRoundAndUserId(BetRound round, UUID userId);

Optional<UserBet> findByUserBetIdAndUserId(UUID userBetId, UUID userId);
@Query(
"SELECT ub FROM UserBet ub " +
"JOIN FETCH ub.round " +
"WHERE ub.userBetId = :userBetId " +
"AND ub.userId = :userId")
Optional<UserBet> findByUserBetIdAndUserIdWithRound(@Param("userBetId") UUID userBetId, @Param("userId") UUID userId);

List<UserBet> findAllByUserIdOrderByRound_SettleAtDesc(UUID userId);

List<UserBet> findAllByRound(BetRound round);


List<UserBet> findAllByRoundIn(List<BetRound> rounds);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.ZoneId;

@Component
@Slf4j
@RequiredArgsConstructor
Expand All @@ -14,33 +18,23 @@ public class BettingScheduler {
private final BettingService bettingService;

@Scheduled(cron = "0 0 9 * * MON-FRI", zone = "Asia/Seoul")
public void dailyOpenScheduler() {
public void openScheduler() {
// 일일 라운드 생성
bettingService.createBetRound(Scope.DAILY);
// log.info("✅ 스케줄러 정상 작동 중: {}", LocalDateTime.now());
}

@Scheduled(cron = "0 0 9 * * MON", zone = "Asia/Seoul")
public void weeklyOpenScheduler() {
bettingService.createBetRound(Scope.WEEKLY);
// 월요일: 주간 라운드 생성
if (LocalDate.now(ZoneId.of("Asia/Seoul")).getDayOfWeek() == DayOfWeek.MONDAY) {
bettingService.createBetRound(Scope.WEEKLY);
}
}

@Scheduled(cron = "0 0 22 * * MON-FRI", zone = "Asia/Seoul")
public void dailyCloseScheduler() {
bettingService.closeBetRound();
}

@Scheduled(cron = "0 0 22 * * FRI", zone = "Asia/Seoul")
public void weeklyCloseScheduler() {
public void closeScheduler() {
bettingService.closeBetRound();
}

@Scheduled(cron = "0 5 22 * * MON-FRI", zone = "Asia/Seoul")
public void dailySettleScheduler() {
bettingService.settleUserBets();
}

@Scheduled(cron = "0 5 22 * * FRI", zone = "Asia/Seoul")
public void weeklySettleScheduler() {
public void settleScheduler() {
bettingService.settleUserBets();
}

Expand Down
Loading