Skip to content

refactor: 스케줄러 정리#573

Merged
JanooGwan merged 5 commits intodevelopfrom
refactor/schedulings
Apr 26, 2026
Merged

refactor: 스케줄러 정리#573
JanooGwan merged 5 commits intodevelopfrom
refactor/schedulings

Conversation

@JanooGwan
Copy link
Copy Markdown
Contributor

@JanooGwan JanooGwan commented Apr 26, 2026

🔍 개요

  • OAuth 정리 스케줄러와 스터디 랭킹 초기화 스케줄러의 중복 실행과 낭비 작업을 줄입니다.

🚀 주요 변경 내용

  • Apple 토큰 revoke와 만료 OAuth 계정 cleanup을 UserScheduler 단일 작업으로 통합했습니다.
  • Apple revoke 실패 계정은 refresh token을 보존해 다음 스케줄 실행에서 재시도할 수 있도록 cleanup 대상에서 제외했습니다.
  • 스터디 랭킹 초기화 스케줄러를 매일 1회 실행으로 통합하고, 월초에는 일간/월간 랭킹을 함께 초기화하도록 변경했습니다.
  • 랭킹 초기화는 엔티티 전체 조회 대신 JPQL bulk update로 수행하도록 변경했습니다.

💬 참고 사항


✅ Checklist (완료 조건)

  • 코드 스타일 가이드 준수
  • 테스트 코드 포함
  • Reviewers / Assignees / Labels 지정 완료
  • 보안 및 민감 정보 검증(API 키, 환경 변수, 개인정보 등)

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 26, 2026

📝 Walkthrough

Walkthrough

일일/월간 스터디 시간 리셋을 엔티티-순회에서 JPQL 벌크 업데이트로 전환하고, 두 스케줄을 통합한 단일 잡으로 변경했습니다. 또한 Apple 관련 withdrawn OAuth 계정 삭제 조건을 변경하고 관련 스케줄/서비스 흐름을 재구성하며 단위 테스트를 추가했습니다.

Changes

Cohort / File(s) Summary
스터디타임: 리포지토리·서비스·스케줄러
src/main/java/gg/agit/konect/domain/studytime/repository/StudyTimeRankingRepository.java, src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java, src/main/java/gg/agit/konect/domain/studytime/scheduler/StudyTimeScheduler.java
리포지토리에 resetDailySeconds()·resetDailyAndMonthlySeconds() JPQL 벌크 업데이트 추가. 서비스 로직을 엔티티 순회에서 벌크 호출로 교체하고, 일일/월간 스케줄러 메서드를 하나의 resetStudyTimeRanking()으로 통합.
사용자 OAuth: 레포지토리·서비스·스케줄러 통합/변경
src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java, src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java, src/main/java/gg/agit/konect/domain/user/scheduler/UserScheduler.java, src/main/java/gg/agit/konect/domain/user/service/UserSchedulerService.java
삭제 대상 쿼리 시 Apple 제공자 조건 추가로 서브셋 삭제(deleteRevokedExpiredWithdrawnOAuthAccountsBefore(...))로 변경. 기존 별도 cleanup 스케줄러 클래스 제거 및 정리 로직을 UserScheduler/UserSchedulerService로 통합·리네임(복구 창 관련 로직 및 cron 변경). 서비스에서 토큰 철회 순서 및 정리 호출 흐름 재구성.
스케줄러 클래스 삭제
src/main/java/gg/agit/konect/domain/user/scheduler/UserOAuthAccountCleanupScheduler.java
별도 OAuth cleanup 스케줄러 클래스가 삭제됨(스케줄 진입점 제거).
단위 테스트 추가·수정
src/test/java/gg/agit/konect/unit/domain/studytime/service/StudyTimeSchedulerServiceTest.java, src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java, src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
스터디타임 서비스에 대한 월초/비월초 분기 검증 테스트 추가. User 관련 테스트를 Apple 제공자 대상 삭제 호출(및 호출 순서/예외 흐름) 검증하도록 추가/수정.

Sequence Diagram(s)

sequenceDiagram
    participant Cron as Cron
    participant Scheduler as StudyTimeScheduler / UserScheduler
    participant Service as StudyTimeSchedulerService / UserSchedulerService
    participant Repo as Repository (StudyTimeRanking / UserOAuthAccount)
    participant DB as Database

    Cron->>Scheduler: cron trigger
    Scheduler->>Service: resetStudyTimeRanking(today) / cleanupExpiredWithdrawnOAuthAccounts(now)
    Service->>Repo: call bulk update / delete JPQL
    Repo->>DB: execute JPQL bulk update/delete
    DB-->>Repo: rows affected (int)
    Repo-->>Service: return updatedCount
    Service-->>Scheduler: return result
    Scheduler-->>Cron: log result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

테스트

Poem

나는 토끼, 코드 사이를 뛰며 🐇
벌크로 숫자들 싹 초기화하고
스케줄 하나로 합쳐 춤을 추네
Apple 토큰도 정리 정돈하며
테스트로 안전하게 도약한다! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed 제목 'refactor: 스케줄러 정리'는 PR의 주요 변경 내용을 정확하게 반영하고 있으며, 여러 스케줄러를 정리하고 통합하는 리팩토링 작업의 핵심을 간결하게 표현하고 있습니다.
Description check ✅ Passed PR 설명이 변경 사항과 충분히 관련이 있으며, OAuth 스케줄러 통합과 스터디 랭킹 리셋 리팩토링의 목적을 명확하게 설명합니다.

✏️ 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 refactor/schedulings

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.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 26, 2026

🧪 JaCoCo Coverage Report (Changed Files)

Summary

  • Overall Coverage: 86.1% ✅
  • Covered Lines: 118 / 137
  • Changed Files: 8

Coverage by File

Class Coverage Lines Status
StudyTimeScheduler
gg.agit.konect.domain.studytime.scheduler
11.1% 1/9
UserScheduler
gg.agit.konect.domain.user.scheduler
12.5% 1/8
UserSchedulerService
gg.agit.konect.domain.user.service
92.0% 23/25
UserOAuthAccountService
gg.agit.konect.domain.user.service
97.8% 90/92
StudyTimeSchedulerService
gg.agit.konect.domain.studytime.service
100.0% 3/3

📊 View Workflow Run

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: 2

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/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java (1)

99-112: ⚠️ Potential issue | 🔴 Critical

두 쿼리의 비교 연산자 불일치로 경계값 처리 오류 발생

같은 스케줄러에서 threshold = now.minusDays(7)로 계산한 후, findAppleAccountsToRevoke()deletedAt < :threshold(strict), deleteRevokedExpiredWithdrawnUsersBefore()deletedAt <= :expiredAt(inclusive)를 사용합니다. 정확히 7일 경계의 사용자(예: deletedAt == now.minusDays(7))는 revoke 대상에서 제외되었다가 cleanup 단계에서 삭제되어, 토큰 취소 없이 OAuth 계정 연결이 제거되는 오류가 발생합니다. 두 쿼리의 비교 연산자를 <로 통일하십시오.

♻️ 제안 수정
     `@Query`("""
         DELETE
         FROM UserOAuthAccount uoa
         WHERE uoa.user.deletedAt IS NOT NULL
-        AND uoa.user.deletedAt <= :expiredAt
+        AND uoa.user.deletedAt < :expiredAt
         AND (
             uoa.provider <> :appleProvider
             OR uoa.appleRefreshToken IS NULL
         )
         """)
     int deleteRevokedExpiredWithdrawnUsersBefore(
         `@Param`("expiredAt") LocalDateTime expiredAt,
         `@Param`("appleProvider") Provider appleProvider
     );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java`
around lines 99 - 112, The two queries use different boundary operators causing
a race: update the delete query in deleteRevokedExpiredWithdrawnUsersBefore() so
its deletedAt comparison matches findAppleAccountsToRevoke() by changing
"uoa.user.deletedAt <= :expiredAt" to a strict "< :expiredAt"; ensure the SQL in
the `@Query` for UserOAuthAccountRepository reflects the strict less-than operator
to avoid deleting accounts at the exact threshold before they are revoked.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java`:
- Around line 26-34: Delete the two redundant methods
resetStudyTimeRankingDaily() and resetStudyTimeRankingMonthly() from
StudyTimeSchedulerService: they duplicate logic now handled by
resetStudyTimeRanking(LocalDate). Remove these methods and any internal calls to
them; if any external callers exist, update them to call
resetStudyTimeRanking(LocalDate) with the appropriate date or to use
studyTimeRankingRepository.resetDailySeconds()/resetDailyAndMonthlySeconds()
through the single resetStudyTimeRanking path. Keep references to
studyTimeRankingRepository and the single resetStudyTimeRanking(LocalDate)
method as the sole entry point for reset logic to avoid diverging policies.

In
`@src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java`:
- Around line 109-112: Rename the repository method int
deleteRevokedExpiredWithdrawnUsersBefore(LocalDateTime expiredAt, Provider
appleProvider) in UserOAuthAccountRepository to a more explicit name like
deleteRevokedExpiredWithdrawnOAuthAccountsBefore to reflect that it deletes
OAuth accounts; update all call sites to the new method name and ensure any
query annotation or mapping that references the old method name is updated
accordingly while keeping the same parameters (`@Param`("expiredAt") and
`@Param`("appleProvider")) and return type.

---

Outside diff comments:
In
`@src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java`:
- Around line 99-112: The two queries use different boundary operators causing a
race: update the delete query in deleteRevokedExpiredWithdrawnUsersBefore() so
its deletedAt comparison matches findAppleAccountsToRevoke() by changing
"uoa.user.deletedAt <= :expiredAt" to a strict "< :expiredAt"; ensure the SQL in
the `@Query` for UserOAuthAccountRepository reflects the strict less-than operator
to avoid deleting accounts at the exact threshold before they are revoked.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: c7089999-bfb5-4f61-afe2-8682cfaeffb3

📥 Commits

Reviewing files that changed from the base of the PR and between 65ae8f7 and addb645.

📒 Files selected for processing (11)
  • src/main/java/gg/agit/konect/domain/studytime/repository/StudyTimeRankingRepository.java
  • src/main/java/gg/agit/konect/domain/studytime/scheduler/StudyTimeScheduler.java
  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
  • src/main/java/gg/agit/konect/domain/user/scheduler/UserOAuthAccountCleanupScheduler.java
  • src/main/java/gg/agit/konect/domain/user/scheduler/UserScheduler.java
  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/main/java/gg/agit/konect/domain/user/service/UserSchedulerService.java
  • src/test/java/gg/agit/konect/unit/domain/studytime/service/StudyTimeSchedulerServiceTest.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
💤 Files with no reviewable changes (1)
  • src/main/java/gg/agit/konect/domain/user/scheduler/UserOAuthAccountCleanupScheduler.java
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: coverage
  • GitHub Check: Analyze (java-kotlin)
🧰 Additional context used
📓 Path-based instructions (2)
src/main/java/**/*.java

⚙️ CodeRabbit configuration file

src/main/java/**/*.java: 아래 원칙으로 리뷰 코멘트를 작성한다.

  • 코멘트는 반드시 한국어로 작성한다.
  • 반드시 수정이 필요한 항목만 코멘트로 남기고, 단순 취향 차이는 지적하지 않는다.
  • 각 코멘트 첫 줄에 심각도를 [LEVEL: high|medium|low] 형식으로 반드시 표기한다.
  • 심각도 기준: high=운영 장애 가능, medium=품질 저하, low=개선 권고.
  • 각 코멘트는 "문제 -> 영향 -> 제안" 순서로 3문장 이내로 간결하게 작성한다.
  • 가능하면 재현 조건 및 실패 시나리오도 포함한다.
  • 제안은 현재 코드베이스(Spring Boot + JPA + Flyway) 패턴과 일치해야 한다.
  • 보안, 트랜잭션 경계, 예외 처리, N+1, 성능 회귀 가능성을 우선 점검한다.
  • 가독성: 변수/메서드 이름이 의도를 바로 드러내는지, 중첩과 메서드 길이가 과도하지 않은지 점검한다.
  • 단순화: 불필요한 추상화, 중복 로직, 과한 방어 코드가 있으면 더 단순한 대안을 제시한다.
  • 확장성: 새 요구사항 추가 시 변경 범위가 최소화되는 구조인지(하드코딩 분기/값 여부 포함) 점검한다.

Files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/main/java/gg/agit/konect/domain/user/scheduler/UserScheduler.java
  • src/main/java/gg/agit/konect/domain/studytime/repository/StudyTimeRankingRepository.java
  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
  • src/main/java/gg/agit/konect/domain/studytime/scheduler/StudyTimeScheduler.java
  • src/main/java/gg/agit/konect/domain/user/service/UserSchedulerService.java
**/*

⚙️ CodeRabbit configuration file

**/*: 공통 리뷰 톤 가이드:

  • 모든 코멘트는 첫 줄에 [LEVEL: ...] 태그를 포함한다.
  • 과장된 표현 없이 사실 기반으로 작성한다.
  • 한 코멘트에는 하나의 이슈만 다룬다.
  • 코드 예시가 필요하면 최소 수정 예시를 제시한다.
  • 가독성/단순화/확장성 이슈를 발견하면 우선순위를 높여 코멘트한다.

Files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/test/java/gg/agit/konect/unit/domain/studytime/service/StudyTimeSchedulerServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/scheduler/UserScheduler.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
  • src/main/java/gg/agit/konect/domain/studytime/repository/StudyTimeRankingRepository.java
  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
  • src/main/java/gg/agit/konect/domain/studytime/scheduler/StudyTimeScheduler.java
  • src/main/java/gg/agit/konect/domain/user/service/UserSchedulerService.java
🧠 Learnings (38)
📓 Common learnings
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*user*scheduler*/**/*.{ts,tsx,js,jsx} : Apple token revoke scheduler at 00:00 daily must revoke refresh tokens for withdrawn Apple accounts past 7 days; clear saved token on success
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*user*scheduler*/**/*.{ts,tsx,js,jsx} : Scheduler at 00:10 must delete OAuth account connections for withdrawn users past 7-day grace period
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*user*/**/*.{ts,tsx,js,jsx} : Upon user withdrawal, immediately attempt to revoke Apple OAuth account refresh token if present

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/main/java/gg/agit/konect/domain/user/scheduler/UserScheduler.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/service/UserSchedulerService.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*user*scheduler*/**/*.{ts,tsx,js,jsx} : Apple token revoke scheduler at 00:00 daily must revoke refresh tokens for withdrawn Apple accounts past 7 days; clear saved token on success

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/main/java/gg/agit/konect/domain/user/scheduler/UserScheduler.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
  • src/main/java/gg/agit/konect/domain/studytime/scheduler/StudyTimeScheduler.java
  • src/main/java/gg/agit/konect/domain/user/service/UserSchedulerService.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*user*/**/*.{ts,tsx,js,jsx} : If account is withdrawn for 7+ days OR on stage profile, do not recover; instead delete OAuth account linkage to allow new linking

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/service/UserSchedulerService.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*user*/**/*.{ts,tsx,js,jsx} : Withdrawn user has 7-day recovery grace period; within 7 days, recover existing user if same providerId/provider+oauthEmail is found during OAuth flow

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/main/java/gg/agit/konect/domain/user/scheduler/UserScheduler.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/service/UserSchedulerService.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*user*scheduler*/**/*.{ts,tsx,js,jsx} : Scheduler at 00:10 must delete OAuth account connections for withdrawn users past 7-day grace period

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/main/java/gg/agit/konect/domain/user/scheduler/UserScheduler.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
  • src/main/java/gg/agit/konect/domain/studytime/scheduler/StudyTimeScheduler.java
  • src/main/java/gg/agit/konect/domain/user/service/UserSchedulerService.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*oauth*/**/*.{ts,tsx,js,jsx} : When linking Apple OAuth account, update with Apple refresh token if present

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/main/java/gg/agit/konect/domain/user/scheduler/UserScheduler.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/service/UserSchedulerService.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*user*/**/*repository*.{ts,tsx,js,jsx} : Withdrawn users must not be returned from standard `getById()` lookups; filter by `deletedAt IS NULL`

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*oauth*/**/*.{ts,tsx,js,jsx} : When same user already has provider account, update existing account; if existing providerId is empty, populate it with new providerId

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
📚 Learning: 2026-04-24T12:50:59.743Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.743Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*oauth*/**/*.{ts,tsx,js,jsx} : When linking OAuth accounts via general linkOAuthAccount(), require providerId; primary account creation without providerId is exceptional

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/service/UserSchedulerService.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*oauth*/**/*.{ts,tsx,js,jsx} : Block OAuth account linking if existing account has different non-empty providerId (conflict); prevent providerId collision

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: Execute unit tests with filter 'gg.agit.konect.unit.domain.studytime.*' to validate study time domain policies

Applied to files:

  • src/test/java/gg/agit/konect/unit/domain/studytime/service/StudyTimeSchedulerServiceTest.java
  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
  • src/main/java/gg/agit/konect/domain/studytime/scheduler/StudyTimeScheduler.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: When implementing unit tests for study time domain, ensure tests cover: duplicate timer start failure, time mismatch timer deletion without ranking effects, personal name masking, and scheduler cache-only reset behavior

Applied to files:

  • src/test/java/gg/agit/konect/unit/domain/studytime/service/StudyTimeSchedulerServiceTest.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: Ensure that running timer state (`StudyTimer`), daily accumulated time (`StudyTimeDaily`), ranking cache (`StudyTimeRanking`), ranking type (`RankingType`), accumulated event (`StudyTimeAccumulatedEvent`), and ranking reset scheduler all operate in sync when making changes to study time logic

Applied to files:

  • src/test/java/gg/agit/konect/unit/domain/studytime/service/StudyTimeSchedulerServiceTest.java
  • src/main/java/gg/agit/konect/domain/studytime/repository/StudyTimeRankingRepository.java
  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
  • src/main/java/gg/agit/konect/domain/studytime/scheduler/StudyTimeScheduler.java
📚 Learning: 2026-04-25T06:58:54.393Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/notification/AGENTS.md:0-0
Timestamp: 2026-04-25T06:58:54.393Z
Learning: Applies to src/main/java/gg/agit/konect/domain/notification/**/*IntegrationTest*.java : Add regression tests for: club application event rollback resulting in zero notifications created (AFTER_COMMIT integration test), inbox list/unread count/bulk read excluding chat-related types (repository integration test), Expo push partial ticket failures logged without whole-request exception propagation, group chat token vs target user count mismatch in current policy.

Applied to files:

  • src/test/java/gg/agit/konect/unit/domain/studytime/service/StudyTimeSchedulerServiceTest.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: Reset ranking cache only in `study_time_ranking` table; never reset original `StudyTimeDaily` cumulative data during scheduler execution

Applied to files:

  • src/test/java/gg/agit/konect/unit/domain/studytime/service/StudyTimeSchedulerServiceTest.java
  • src/main/java/gg/agit/konect/domain/studytime/repository/StudyTimeRankingRepository.java
  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
  • src/main/java/gg/agit/konect/domain/studytime/scheduler/StudyTimeScheduler.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: When changing recovery grace period policy, update immediate withdrawal, OAuth conflict handling, scheduler deletion, and token revocation timings together

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/scheduler/UserScheduler.java
  • src/main/java/gg/agit/konect/domain/user/service/UserSchedulerService.java
📚 Learning: 2026-04-24T12:50:59.743Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.743Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*oauth*/**/*.{ts,tsx,js,jsx} : Always validate both providerId AND oauthEmail for OAuth duplicate conflict detection; checking only one is insufficient

Applied to files:

  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: Daily summary returns today's `StudyTimeDaily` row; monthly summary returns sum of `StudyTimeDaily.totalSeconds` from 1st of current month to today; total summary returns sum of all `StudyTimeDaily.totalSeconds` for the user

Applied to files:

  • src/main/java/gg/agit/konect/domain/studytime/repository/StudyTimeRankingRepository.java
  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: Update `StudyTimeRanking` target_name when personal ranking user name changes to maintain cache consistency

Applied to files:

  • src/main/java/gg/agit/konect/domain/studytime/repository/StudyTimeRankingRepository.java
  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: Publish `StudyTimeAccumulatedEvent` only after successful sync or stop operations when time is actually accumulated to `StudyTimeDaily`

Applied to files:

  • src/main/java/gg/agit/konect/domain/studytime/repository/StudyTimeRankingRepository.java
  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
  • src/main/java/gg/agit/konect/domain/studytime/scheduler/StudyTimeScheduler.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: Schedule daily ranking cache reset of all `dailySeconds` to 0 at 00:00 every day

Applied to files:

  • src/main/java/gg/agit/konect/domain/studytime/repository/StudyTimeRankingRepository.java
  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
  • src/main/java/gg/agit/konect/domain/studytime/scheduler/StudyTimeScheduler.java
📚 Learning: 2026-04-24T12:50:59.743Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.743Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*user*/**/*repository*.{ts,tsx,js,jsx} : `UserRepository.getById()` must filter by `deletedAt IS NULL` to return only active users

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
📚 Learning: 2026-04-24T12:50:59.743Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.743Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*user*/**/*.{ts,tsx,js,jsx} : Soft delete users by setting `deletedAt` timestamp instead of hard deleting the row

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: On successful sync, update only the `startedAt` timestamp to current time and accumulate only the interval since last sync to `StudyTimeDaily`

Applied to files:

  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
  • src/main/java/gg/agit/konect/domain/studytime/scheduler/StudyTimeScheduler.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: Exclude unsync'd timer time from summary queries; only include accumulated time from `StudyTimeDaily` in daily/monthly/total calculations

Applied to files:

  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
  • src/main/java/gg/agit/konect/domain/studytime/scheduler/StudyTimeScheduler.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: Schedule monthly ranking cache reset of all `monthlySeconds` to 0 at 00:00 on the 1st of every month

Applied to files:

  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
  • src/main/java/gg/agit/konect/domain/studytime/scheduler/StudyTimeScheduler.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: Sort daily rankings by: dailySeconds DESC, monthlySeconds DESC, targetId ASC; sort monthly rankings by: monthlySeconds DESC, dailySeconds DESC, targetId ASC

Applied to files:

  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
📚 Learning: 2026-04-25T06:58:54.393Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/notification/AGENTS.md:0-0
Timestamp: 2026-04-25T06:58:54.393Z
Learning: Applies to src/main/java/gg/agit/konect/domain/notification/**/*Test*.java : Notification domain tests must cover: token registration/update/deletion and Expo token format rejection, both `ExponentPushToken[...]` and `ExpoPushToken[...]` format acceptance, excluding push for users in chatroom or with mute enabled, group chat sender/presence/mute filtering, Unicode emoji handling in 30 code point preview, club application inbox/SSE/push coordination, in-app notification/SSE persistence when push token absent, SSE resubscription and completed emitter cleanup, inbox save/saveAll/read operations.

Applied to files:

  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
📚 Learning: 2026-04-24T12:50:59.743Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.743Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*user*/**/*.{ts,tsx,js,jsx} : Verify `UnRegisteredUser` lookup uses correct email/provider combination (Google/Naver/Kakao) or providerId (Apple) as identifier

Applied to files:

  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*signup*/**/*.{ts,tsx,js,jsx} : Preserve Apple user's name and refresh token from initial login in temporary user or OAuth account during signup

Applied to files:

  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/service/UserSchedulerService.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: Ranking cache reset scheduler must catch all exceptions, log them via `scheduler.studytime` logger, and not rethrow to maintain scheduler execution flow

Applied to files:

  • src/main/java/gg/agit/konect/domain/studytime/scheduler/StudyTimeScheduler.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*oauth*/**/*.{ts,tsx,js,jsx} : OAuth account linking request must validate token using provider-specific verifier before saving

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserSchedulerService.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*oauth*/**/*.{ts,tsx,js,jsx} : Prevent creating primary OAuth account without providerId; require providerId for general OAuth account linking via linkOAuthAccount()

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserSchedulerService.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*oauth*/**/*.{ts,tsx,js,jsx} : One user can have at most one OAuth account per provider; providerId and oauthEmail must not conflict with other active users

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserSchedulerService.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*google*drive*/**/*.{ts,tsx,js,jsx} : Google Drive OAuth uses same `UserOAuthAccount` row as login Google OAuth via `googleDriveRefreshToken` field, not separate account

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserSchedulerService.java
📚 Learning: 2026-04-24T12:50:59.743Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.743Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*oauth*/**/*.{ts,tsx,js,jsx} : Apple OAuth registration requires providerId to be present; treat registration as failed if providerId is missing

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserSchedulerService.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*oauth*/**/*.{ts,tsx,js,jsx} : Prevent OAuth account linking if another active user already uses same providerId or provider/oauthEmail combination

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserSchedulerService.java

Comment on lines +109 to +112
int deleteRevokedExpiredWithdrawnUsersBefore(
@Param("expiredAt") LocalDateTime expiredAt,
@Param("appleProvider") Provider appleProvider
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

[LEVEL: low] 메서드 이름의 Users가 OAuth 계정 삭제 의미를 흐립니다. 호출부에서 의미를 다시 해석해야 해 가독성이 떨어집니다. deleteRevokedExpiredWithdrawnOAuthAccountsBefore 같은 이름이 실제 삭제 대상을 더 정확히 드러냅니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java`
around lines 109 - 112, Rename the repository method int
deleteRevokedExpiredWithdrawnUsersBefore(LocalDateTime expiredAt, Provider
appleProvider) in UserOAuthAccountRepository to a more explicit name like
deleteRevokedExpiredWithdrawnOAuthAccountsBefore to reflect that it deletes
OAuth accounts; update all call sites to the new method name and ensure any
query annotation or mapping that references the old method name is updated
accordingly while keeping the same parameters (`@Param`("expiredAt") and
`@Param`("appleProvider")) and return type.

@JanooGwan JanooGwan self-assigned this Apr 26, 2026
@JanooGwan JanooGwan added the 리팩토링 리팩터링을 위한 이슈입니다. label Apr 26, 2026
@JanooGwan JanooGwan requested a review from Copilot April 26, 2026 06:13
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

OAuth 정리 스케줄러(Apple revoke + 만료 OAuth 계정 cleanup)와 스터디 랭킹 초기화 스케줄러를 통합/최적화하여 중복 실행과 불필요한 작업을 줄이려는 PR입니다.

Changes:

  • Apple 토큰 revoke와 만료 OAuth 계정 cleanup을 단일 스케줄 실행으로 묶고, revoke 실패 계정은 재시도 가능하도록 cleanup 대상에서 제외
  • 스터디 랭킹 초기화를 일간 스케줄러로 통합하고, 전체 조회 대신 JPQL bulk update로 리셋 수행
  • 관련 단위 테스트 추가 및 기존 cleanup 테스트 갱신

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/main/java/gg/agit/konect/domain/user/service/UserSchedulerService.java revoke + cleanup을 한 서비스 메서드로 통합하고 실행 로그/카운트 추가
src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java 탈퇴 유예기간 경과 OAuth 계정 삭제 로직을 “Apple refresh token 상태”를 고려하도록 변경
src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java Apple revoke 실패 계정(토큰 유지)을 삭제에서 제외하는 조건을 포함한 delete JPQL로 변경
src/main/java/gg/agit/konect/domain/user/scheduler/UserScheduler.java 기존 Apple revoke 스케줄을 “통합 cleanup 스케줄”로 변경(00:10 실행)
src/main/java/gg/agit/konect/domain/user/scheduler/UserOAuthAccountCleanupScheduler.java 통합으로 인해 기존 cleanup 스케줄러 제거
src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java 랭킹 리셋을 날짜 기반 단일 메서드로 통합하고 bulk update 호출로 변경
src/main/java/gg/agit/konect/domain/studytime/scheduler/StudyTimeScheduler.java 일간 스케줄만 유지하고 월초에 월간까지 포함해 한 번에 리셋하도록 변경
src/main/java/gg/agit/konect/domain/studytime/repository/StudyTimeRankingRepository.java 일간/월간 리셋을 위한 JPQL bulk update 메서드 추가
src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java 통합된 UserSchedulerService 동작(성공/실패 케이스) 테스트 추가
src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java cleanup 삭제 조건 변경에 맞춰 테스트 업데이트
src/test/java/gg/agit/konect/unit/domain/studytime/service/StudyTimeSchedulerServiceTest.java 월초/비월초 분기 로직 테스트 추가

}

@Transactional
public int resetStudyTimeRankingMonthly() {
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

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

resetStudyTimeRankingMonthly()라는 이름과 달리 내부에서 resetDailyAndMonthlySeconds()를 호출해 일간(dailySeconds)까지 함께 0으로 초기화합니다. 현재 사용처가 없어도 public API라서 추후 오용 시 버그로 이어질 수 있으니, (1) 월간만 초기화하는 별도 쿼리/메서드를 만들거나 (2) 메서드명을 “일간+월간 초기화” 의미로 변경하거나 (3) 더 이상 필요 없다면 제거하는 쪽으로 정리해 주세요.

Suggested change
public int resetStudyTimeRankingMonthly() {
public int resetStudyTimeRankingDailyAndMonthly() {

Copilot uses AI. Check for mistakes.
Comment on lines +59 to +63
// then
verify(appleTokenRevocationService).revoke("apple-refresh-token");
verify(userSchedulerTxService).clearAppleRefreshTokenIfMatches(account.getId(), "apple-refresh-token");
verify(userOAuthAccountService).cleanupExpiredWithdrawnUserOAuthAccounts(now);
}
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

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

테스트 이름/설명은 “revoke 후 같은 실행에서 cleanup” 순서를 보장하는 것으로 읽히는데, 현재는 각 메서드 호출 여부만 verify하고 호출 순서는 검증하지 않습니다. InOrder를 사용해 revoke → refreshToken clear → cleanup 순서가 보장되는지까지 검증하도록 테스트를 강화해 주세요.

Copilot uses AI. Check for mistakes.
return;
}
public void cleanupExpiredWithdrawnOAuthAccountsAfterRestoreWindow(LocalDateTime now) {
LocalDateTime threshold = now.minusDays(RESTORE_WINDOW_DAYS);
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

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

현재 threshold를 now.minusDays(7)로 계산하고 있는데, UserOAuthAccountRepository.findAppleAccountsToRevoke 쿼리가 user.deletedAt < :threshold 조건(엄격한 <)이라면 탈퇴 시각이 threshold와 정확히 같은 계정은 이번 실행에서 revoke 대상에서 제외됩니다. 이번 PR에서 Apple 계정 삭제가 “refresh token이 NULL인 경우”로 제한되면서(삭제 쿼리 조건) 해당 경계 케이스가 최소 1일 더 남게 될 수 있으니, 정책이 “7일 이상(>=)”이라면 revoke 조회 조건을 <= 로 맞추거나 threshold 계산을 조정해 주세요.

Suggested change
LocalDateTime threshold = now.minusDays(RESTORE_WINDOW_DAYS);
LocalDateTime threshold = now.minusDays(RESTORE_WINDOW_DAYS).plusNanos(1);

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

coderabbitai[bot]
coderabbitai Bot previously requested changes Apr 26, 2026
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 the current code and only fix it if needed.

Inline comments:
In
`@src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java`:
- Around line 81-92: Test currently stubs appleTokenRevocationService.revoke to
throw but doesn't verify the revoke was actually attempted; add explicit
verifications for appleTokenRevocationService.revoke("apple-refresh-token") and
userSchedulerTxService.findAccountsToRevoke(now.minusDays(7)) to lock the test
into the failure path, and remove the unnecessary stubbing
given(userOAuthAccountService.cleanupExpiredWithdrawnUserOAuthAccounts(now)).willReturn(0)
since its return value isn't asserted and may be flagged as an unnecessary stub.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 0e341c52-31fb-4ccf-a312-0a682cd16c46

📥 Commits

Reviewing files that changed from the base of the PR and between addb645 and 545fb0c.

📒 Files selected for processing (5)
  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: coverage
  • GitHub Check: Analyze (java-kotlin)
🧰 Additional context used
📓 Path-based instructions (2)
src/main/java/**/*.java

⚙️ CodeRabbit configuration file

src/main/java/**/*.java: 아래 원칙으로 리뷰 코멘트를 작성한다.

  • 코멘트는 반드시 한국어로 작성한다.
  • 반드시 수정이 필요한 항목만 코멘트로 남기고, 단순 취향 차이는 지적하지 않는다.
  • 각 코멘트 첫 줄에 심각도를 [LEVEL: high|medium|low] 형식으로 반드시 표기한다.
  • 심각도 기준: high=운영 장애 가능, medium=품질 저하, low=개선 권고.
  • 각 코멘트는 "문제 -> 영향 -> 제안" 순서로 3문장 이내로 간결하게 작성한다.
  • 가능하면 재현 조건 및 실패 시나리오도 포함한다.
  • 제안은 현재 코드베이스(Spring Boot + JPA + Flyway) 패턴과 일치해야 한다.
  • 보안, 트랜잭션 경계, 예외 처리, N+1, 성능 회귀 가능성을 우선 점검한다.
  • 가독성: 변수/메서드 이름이 의도를 바로 드러내는지, 중첩과 메서드 길이가 과도하지 않은지 점검한다.
  • 단순화: 불필요한 추상화, 중복 로직, 과한 방어 코드가 있으면 더 단순한 대안을 제시한다.
  • 확장성: 새 요구사항 추가 시 변경 범위가 최소화되는 구조인지(하드코딩 분기/값 여부 포함) 점검한다.

Files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
**/*

⚙️ CodeRabbit configuration file

**/*: 공통 리뷰 톤 가이드:

  • 모든 코멘트는 첫 줄에 [LEVEL: ...] 태그를 포함한다.
  • 과장된 표현 없이 사실 기반으로 작성한다.
  • 한 코멘트에는 하나의 이슈만 다룬다.
  • 코드 예시가 필요하면 최소 수정 예시를 제시한다.
  • 가독성/단순화/확장성 이슈를 발견하면 우선순위를 높여 코멘트한다.

Files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
🧠 Learnings (31)
📓 Common learnings
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*user*scheduler*/**/*.{ts,tsx,js,jsx} : Scheduler at 00:10 must delete OAuth account connections for withdrawn users past 7-day grace period
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*user*scheduler*/**/*.{ts,tsx,js,jsx} : Apple token revoke scheduler at 00:00 daily must revoke refresh tokens for withdrawn Apple accounts past 7 days; clear saved token on success
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: When changing recovery grace period policy, update immediate withdrawal, OAuth conflict handling, scheduler deletion, and token revocation timings together
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*user*/**/*.{ts,tsx,js,jsx} : Upon user withdrawal, immediately attempt to revoke Apple OAuth account refresh token if present

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*oauth*/**/*.{ts,tsx,js,jsx} : When linking Apple OAuth account, update with Apple refresh token if present

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*user*/**/*.{ts,tsx,js,jsx} : Withdrawn user has 7-day recovery grace period; within 7 days, recover existing user if same providerId/provider+oauthEmail is found during OAuth flow

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*user*scheduler*/**/*.{ts,tsx,js,jsx} : Scheduler at 00:10 must delete OAuth account connections for withdrawn users past 7-day grace period

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*user*scheduler*/**/*.{ts,tsx,js,jsx} : Apple token revoke scheduler at 00:00 daily must revoke refresh tokens for withdrawn Apple accounts past 7 days; clear saved token on success

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*user*/**/*.{ts,tsx,js,jsx} : If account is withdrawn for 7+ days OR on stage profile, do not recover; instead delete OAuth account linkage to allow new linking

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*user*/**/*repository*.{ts,tsx,js,jsx} : Withdrawn users must not be returned from standard `getById()` lookups; filter by `deletedAt IS NULL`

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*oauth*/**/*.{ts,tsx,js,jsx} : When same user already has provider account, update existing account; if existing providerId is empty, populate it with new providerId

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
📚 Learning: 2026-04-24T12:50:59.743Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.743Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*oauth*/**/*.{ts,tsx,js,jsx} : When linking OAuth accounts via general linkOAuthAccount(), require providerId; primary account creation without providerId is exceptional

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*oauth*/**/*.{ts,tsx,js,jsx} : Block OAuth account linking if existing account has different non-empty providerId (conflict); prevent providerId collision

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: Ensure that running timer state (`StudyTimer`), daily accumulated time (`StudyTimeDaily`), ranking cache (`StudyTimeRanking`), ranking type (`RankingType`), accumulated event (`StudyTimeAccumulatedEvent`), and ranking reset scheduler all operate in sync when making changes to study time logic

Applied to files:

  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: Reset ranking cache only in `study_time_ranking` table; never reset original `StudyTimeDaily` cumulative data during scheduler execution

Applied to files:

  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: Schedule monthly ranking cache reset of all `monthlySeconds` to 0 at 00:00 on the 1st of every month

Applied to files:

  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: Schedule daily ranking cache reset of all `dailySeconds` to 0 at 00:00 every day

Applied to files:

  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: Daily summary returns today's `StudyTimeDaily` row; monthly summary returns sum of `StudyTimeDaily.totalSeconds` from 1st of current month to today; total summary returns sum of all `StudyTimeDaily.totalSeconds` for the user

Applied to files:

  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: Sort daily rankings by: dailySeconds DESC, monthlySeconds DESC, targetId ASC; sort monthly rankings by: monthlySeconds DESC, dailySeconds DESC, targetId ASC

Applied to files:

  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: Exclude unsync'd timer time from summary queries; only include accumulated time from `StudyTimeDaily` in daily/monthly/total calculations

Applied to files:

  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: Update `StudyTimeRanking` target_name when personal ranking user name changes to maintain cache consistency

Applied to files:

  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: Execute unit tests with filter 'gg.agit.konect.unit.domain.studytime.*' to validate study time domain policies

Applied to files:

  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: Publish `StudyTimeAccumulatedEvent` only after successful sync or stop operations when time is actually accumulated to `StudyTimeDaily`

Applied to files:

  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: On successful sync, update only the `startedAt` timestamp to current time and accumulate only the interval since last sync to `StudyTimeDaily`

Applied to files:

  • src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*oauth*/**/*.{ts,tsx,js,jsx} : OAuth account link status query must return linked status for all supported Provider types

Applied to files:

  • src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java
📚 Learning: 2026-04-24T12:50:59.743Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.743Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*user*/**/*repository*.{ts,tsx,js,jsx} : `UserRepository.getById()` must filter by `deletedAt IS NULL` to return only active users

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*user*/**/*.{ts,tsx,js,jsx} : User withdrawal must not delete the row; instead set `deletedAt` to current timestamp (soft delete)

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
📚 Learning: 2026-04-24T12:50:59.743Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.743Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*user*/**/*entity*.{ts,tsx,js,jsx} : `User.getName()` must not expose original name of withdrawn users; return '탈퇴한 사용자' instead

Applied to files:

  • src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java
📚 Learning: 2026-04-25T06:58:54.393Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/notification/AGENTS.md:0-0
Timestamp: 2026-04-25T06:58:54.393Z
Learning: Applies to src/main/java/gg/agit/konect/domain/notification/**/*IntegrationTest*.java : Add regression tests for: club application event rollback resulting in zero notifications created (AFTER_COMMIT integration test), inbox list/unread count/bulk read excluding chat-related types (repository integration test), Expo push partial ticket failures logged without whole-request exception propagation, group chat token vs target user count mismatch in current policy.

Applied to files:

  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
📚 Learning: 2026-04-24T12:50:59.744Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.744Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*signup*/**/*.{ts,tsx,js,jsx} : Preserve Apple user's name and refresh token from initial login in temporary user or OAuth account during signup

Applied to files:

  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
📚 Learning: 2026-04-25T06:58:54.393Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/notification/AGENTS.md:0-0
Timestamp: 2026-04-25T06:58:54.393Z
Learning: Applies to src/main/java/gg/agit/konect/domain/notification/**/*Test*.java : Notification domain tests must cover: token registration/update/deletion and Expo token format rejection, both `ExponentPushToken[...]` and `ExpoPushToken[...]` format acceptance, excluding push for users in chatroom or with mute enabled, group chat sender/presence/mute filtering, Unicode emoji handling in 30 code point preview, club application inbox/SSE/push coordination, in-app notification/SSE persistence when push token absent, SSE resubscription and completed emitter cleanup, inbox save/saveAll/read operations.

Applied to files:

  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
📚 Learning: 2026-04-24T12:50:59.743Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/user/AGENTS.md:0-0
Timestamp: 2026-04-24T12:50:59.743Z
Learning: Applies to src/main/java/gg/agit/konect/domain/user/**/*user*/**/*.{ts,tsx,js,jsx} : Verify `UnRegisteredUser` lookup uses correct email/provider combination (Google/Naver/Kakao) or providerId (Apple) as identifier

Applied to files:

  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
📚 Learning: 2026-04-25T06:01:13.789Z
Learnt from: CR
Repo: BCSDLab/KONECT_BACK_END PR: 0
File: src/main/java/gg/agit/konect/domain/studytime/AGENTS.md:0-0
Timestamp: 2026-04-25T06:01:13.789Z
Learning: When implementing unit tests for study time domain, ensure tests cover: duplicate timer start failure, time mismatch timer deletion without ranking effects, personal name masking, and scheduler cache-only reset behavior

Applied to files:

  • src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java
🔇 Additional comments (6)
src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.java (1)

18-24: [LEVEL: low]
단일 진입점 통합 및 벌크 업데이트 전환 적절합니다.

이전 리뷰에서 지적된 중복 메서드 제거가 반영되어 resetStudyTimeRanking(LocalDate) 한 곳에서 1일/그 외 분기를 처리하고, 엔티티 순회 대신 JPQL 벌크 업데이트로 위임해 정책이 일원화됐습니다. 학습 가이드(매월 1일 00:00 monthlySeconds 리셋, 매일 00:00 dailySeconds 리셋, study_time_ranking에만 영향)와도 일치합니다.

src/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.java (2)

99-112: LGTM

provider <> :appleProvider OR uoa.appleRefreshToken IS NULL 조건으로 비-Apple 계정은 모두 정리하면서, Apple은 refresh token이 비워진(=revoke 성공) 경우에만 삭제하도록 잘 분리되어 있어 PR 의도와 일치합니다. 경계도 <=로 통일되어 다음 스케줄 재시도 흐름과 모순되지 않습니다.


126-138: LGTM

user.deletedAt <= :threshold로 변경되어 cleanupExpiredWithdrawnOAuthAccountsBefore<=와 boundary가 일치합니다. 7일 정각에 복구 불가 판정(canRestoreisAfter() 반환 false)과도 일관됩니다.

src/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.java (1)

82-91: LGTM

Provider.APPLE 인자 전달은 리포지토리 쿼리의 의미(=Apple만 토큰 보존 분기)와 일치하며, flush() 호출과 반환 카운트 처리도 그대로 유지되어 호출부 영향이 없습니다.

src/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.java (1)

244-265: LGTM

새 시그니처(expiredAt, Provider.APPLE)에 맞게 stub과 verify가 정확히 갱신되었고, 기대 카운트(3)와 flush() 검증이 그대로 유지되어 회귀를 잘 막아줍니다.

src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java (1)

42-66: LGTM

InOrder로 revoke → clearAppleRefreshTokenIfMatchescleanupExpiredWithdrawnUserOAuthAccounts가 한 실행 안에서 순서대로 호출됨을 검증해 통합된 스케줄러 흐름을 잘 보호합니다.

Comment on lines +81 to +92
given(userSchedulerTxService.findAccountsToRevoke(now.minusDays(7))).willReturn(List.of(account));
given(userOAuthAccountService.cleanupExpiredWithdrawnUserOAuthAccounts(now)).willReturn(0);
willThrow(new IllegalStateException("Apple revoke failed"))
.given(appleTokenRevocationService).revoke("apple-refresh-token");

// when
userSchedulerService.cleanupExpiredWithdrawnOAuthAccountsAfterRestoreWindow(now);

// then
verify(userSchedulerTxService, never()).clearAppleRefreshTokenIfMatches(account.getId(), "apple-refresh-token");
verify(userOAuthAccountService).cleanupExpiredWithdrawnUserOAuthAccounts(now);
}
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

[LEVEL: low] revoke 실패 시 clearAppleRefreshTokenIfMatches가 호출되지 않는 것은 검증되어 있지만, 정작 appleTokenRevocationService.revoke("apple-refresh-token")가 실제로 시도되었는지에 대한 explicit verify가 빠져 있습니다. 영향: 향후 SUT가 예외를 일으키는 경로 자체를 우회하도록 변경되어도 본 테스트가 통과해 회귀 감지를 놓칠 수 있습니다. 제안: 아래와 같이 revoke 호출과 findAccountsToRevoke 호출을 함께 verify해 실패 경로 진입을 고정하세요.

🔧 최소 수정 예시
         // then
+        verify(userSchedulerTxService).findAccountsToRevoke(now.minusDays(7));
+        verify(appleTokenRevocationService).revoke("apple-refresh-token");
         verify(userSchedulerTxService, never()).clearAppleRefreshTokenIfMatches(account.getId(), "apple-refresh-token");
         verify(userOAuthAccountService).cleanupExpiredWithdrawnUserOAuthAccounts(now);

또한 line 82의 given(userOAuthAccountService.cleanupExpiredWithdrawnUserOAuthAccounts(now)).willReturn(0)은 반환값이 단언되지 않고 int 기본값이 0이라 사실상 무용한 stubbing입니다(strict stubbing 환경이면 UnnecessaryStubbingException 가능). 함께 제거를 권장합니다.

As per coding guidelines, 한 코멘트에는 하나의 이슈를 다루어야 하지만 두 항목이 동일 테스트의 검증 강화 측면에서 같이 처리되는 편이 효율적이라 묶었습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.java`
around lines 81 - 92, Test currently stubs appleTokenRevocationService.revoke to
throw but doesn't verify the revoke was actually attempted; add explicit
verifications for appleTokenRevocationService.revoke("apple-refresh-token") and
userSchedulerTxService.findAccountsToRevoke(now.minusDays(7)) to lock the test
into the failure path, and remove the unnecessary stubbing
given(userOAuthAccountService.cleanupExpiredWithdrawnUserOAuthAccounts(now)).willReturn(0)
since its return value isn't asserted and may be flagged as an unnecessary stub.

@JanooGwan JanooGwan changed the title refactor: 스케줄러 정리 작업 통합 refactor: 스케줄러 정리 Apr 26, 2026
@JanooGwan JanooGwan merged commit bc98f3a into develop Apr 26, 2026
5 checks passed
@JanooGwan JanooGwan deleted the refactor/schedulings branch April 26, 2026 11:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

리팩토링 리팩터링을 위한 이슈입니다.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants