Conversation
📝 WalkthroughWalkthrough일일/월간 스터디 시간 리셋을 엔티티-순회에서 JPQL 벌크 업데이트로 전환하고, 두 스케줄을 통합한 단일 잡으로 변경했습니다. 또한 Apple 관련 withdrawn OAuth 계정 삭제 조건을 변경하고 관련 스케줄/서비스 흐름을 재구성하며 단위 테스트를 추가했습니다. Changes
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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
🧪 JaCoCo Coverage Report (Changed Files)Summary
Coverage by File
|
There was a problem hiding this comment.
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
📒 Files selected for processing (11)
src/main/java/gg/agit/konect/domain/studytime/repository/StudyTimeRankingRepository.javasrc/main/java/gg/agit/konect/domain/studytime/scheduler/StudyTimeScheduler.javasrc/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.javasrc/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.javasrc/main/java/gg/agit/konect/domain/user/scheduler/UserOAuthAccountCleanupScheduler.javasrc/main/java/gg/agit/konect/domain/user/scheduler/UserScheduler.javasrc/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.javasrc/main/java/gg/agit/konect/domain/user/service/UserSchedulerService.javasrc/test/java/gg/agit/konect/unit/domain/studytime/service/StudyTimeSchedulerServiceTest.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.javasrc/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.javasrc/main/java/gg/agit/konect/domain/user/scheduler/UserScheduler.javasrc/main/java/gg/agit/konect/domain/studytime/repository/StudyTimeRankingRepository.javasrc/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.javasrc/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.javasrc/main/java/gg/agit/konect/domain/studytime/scheduler/StudyTimeScheduler.javasrc/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.javasrc/test/java/gg/agit/konect/unit/domain/studytime/service/StudyTimeSchedulerServiceTest.javasrc/main/java/gg/agit/konect/domain/user/scheduler/UserScheduler.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.javasrc/main/java/gg/agit/konect/domain/studytime/repository/StudyTimeRankingRepository.javasrc/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.javasrc/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.javasrc/main/java/gg/agit/konect/domain/studytime/scheduler/StudyTimeScheduler.javasrc/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.javasrc/main/java/gg/agit/konect/domain/user/scheduler/UserScheduler.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.javasrc/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.javasrc/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.javasrc/main/java/gg/agit/konect/domain/user/scheduler/UserScheduler.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.javasrc/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.javasrc/main/java/gg/agit/konect/domain/studytime/scheduler/StudyTimeScheduler.javasrc/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.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.javasrc/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.javasrc/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.javasrc/main/java/gg/agit/konect/domain/user/scheduler/UserScheduler.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.javasrc/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.javasrc/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.javasrc/main/java/gg/agit/konect/domain/user/scheduler/UserScheduler.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.javasrc/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.javasrc/main/java/gg/agit/konect/domain/studytime/scheduler/StudyTimeScheduler.javasrc/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.javasrc/main/java/gg/agit/konect/domain/user/scheduler/UserScheduler.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.javasrc/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserSchedulerServiceTest.javasrc/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.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.javasrc/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.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.javasrc/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.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.javasrc/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.javasrc/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.javasrc/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.javasrc/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.javasrc/main/java/gg/agit/konect/domain/studytime/repository/StudyTimeRankingRepository.javasrc/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.javasrc/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.javasrc/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.javasrc/main/java/gg/agit/konect/domain/studytime/repository/StudyTimeRankingRepository.javasrc/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.javasrc/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.javasrc/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.javasrc/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.javasrc/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.javasrc/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.javasrc/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.javasrc/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.javasrc/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.javasrc/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.javasrc/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.javasrc/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.javasrc/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
| int deleteRevokedExpiredWithdrawnUsersBefore( | ||
| @Param("expiredAt") LocalDateTime expiredAt, | ||
| @Param("appleProvider") Provider appleProvider | ||
| ); |
There was a problem hiding this comment.
🧹 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.
There was a problem hiding this comment.
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() { |
There was a problem hiding this comment.
resetStudyTimeRankingMonthly()라는 이름과 달리 내부에서 resetDailyAndMonthlySeconds()를 호출해 일간(dailySeconds)까지 함께 0으로 초기화합니다. 현재 사용처가 없어도 public API라서 추후 오용 시 버그로 이어질 수 있으니, (1) 월간만 초기화하는 별도 쿼리/메서드를 만들거나 (2) 메서드명을 “일간+월간 초기화” 의미로 변경하거나 (3) 더 이상 필요 없다면 제거하는 쪽으로 정리해 주세요.
| public int resetStudyTimeRankingMonthly() { | |
| public int resetStudyTimeRankingDailyAndMonthly() { |
| // then | ||
| verify(appleTokenRevocationService).revoke("apple-refresh-token"); | ||
| verify(userSchedulerTxService).clearAppleRefreshTokenIfMatches(account.getId(), "apple-refresh-token"); | ||
| verify(userOAuthAccountService).cleanupExpiredWithdrawnUserOAuthAccounts(now); | ||
| } |
There was a problem hiding this comment.
테스트 이름/설명은 “revoke 후 같은 실행에서 cleanup” 순서를 보장하는 것으로 읽히는데, 현재는 각 메서드 호출 여부만 verify하고 호출 순서는 검증하지 않습니다. InOrder를 사용해 revoke → refreshToken clear → cleanup 순서가 보장되는지까지 검증하도록 테스트를 강화해 주세요.
| return; | ||
| } | ||
| public void cleanupExpiredWithdrawnOAuthAccountsAfterRestoreWindow(LocalDateTime now) { | ||
| LocalDateTime threshold = now.minusDays(RESTORE_WINDOW_DAYS); |
There was a problem hiding this comment.
현재 threshold를 now.minusDays(7)로 계산하고 있는데, UserOAuthAccountRepository.findAppleAccountsToRevoke 쿼리가 user.deletedAt < :threshold 조건(엄격한 <)이라면 탈퇴 시각이 threshold와 정확히 같은 계정은 이번 실행에서 revoke 대상에서 제외됩니다. 이번 PR에서 Apple 계정 삭제가 “refresh token이 NULL인 경우”로 제한되면서(삭제 쿼리 조건) 해당 경계 케이스가 최소 1일 더 남게 될 수 있으니, 정책이 “7일 이상(>=)”이라면 revoke 조회 조건을 <= 로 맞추거나 threshold 계산을 조정해 주세요.
| LocalDateTime threshold = now.minusDays(RESTORE_WINDOW_DAYS); | |
| LocalDateTime threshold = now.minusDays(RESTORE_WINDOW_DAYS).plusNanos(1); |
There was a problem hiding this comment.
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
📒 Files selected for processing (5)
src/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.javasrc/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.javasrc/main/java/gg/agit/konect/domain/user/service/UserOAuthAccountService.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.javasrc/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.javasrc/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.javasrc/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.javasrc/main/java/gg/agit/konect/domain/studytime/service/StudyTimeSchedulerService.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.javasrc/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.javasrc/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.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.javasrc/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.javasrc/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.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.javasrc/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.javasrc/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.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.javasrc/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.javasrc/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.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.javasrc/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.javasrc/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.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.javasrc/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.javasrc/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.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.javasrc/main/java/gg/agit/konect/domain/user/repository/UserOAuthAccountRepository.javasrc/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.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.javasrc/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.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.javasrc/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.javasrc/test/java/gg/agit/konect/unit/domain/user/service/UserOAuthAccountServiceTest.javasrc/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일 정각에 복구 불가 판정(canRestore의isAfter()반환 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 →clearAppleRefreshTokenIfMatches→cleanupExpiredWithdrawnUserOAuthAccounts가 한 실행 안에서 순서대로 호출됨을 검증해 통합된 스케줄러 흐름을 잘 보호합니다.
| 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); | ||
| } |
There was a problem hiding this comment.
[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.
🔍 개요
🚀 주요 변경 내용
UserScheduler단일 작업으로 통합했습니다.💬 참고 사항
✅ Checklist (완료 조건)