20260303-#264-라운드-종료-후-결석처리#276
Hidden character warning
Conversation
Walkthrough세 개의 repository 및 service 파일을 수정하여 출석 관리 기능을 확장했습니다. AttendanceRepository와 AttendanceRoundRepository에 새로운 쿼리 메서드를 추가하고, AttendanceRoundService에 라운드 종료 시 결석 사용자를 자동으로 표시하는 배치 처리 로직을 구현했습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant Scheduler as Quartz Scheduler
participant Service as AttendanceRoundService
participant RoundRepo as AttendanceRoundRepository
participant UserRepo as SessionUserRepository
participant AttendanceRepo as AttendanceRepository
participant DB as Database
Scheduler->>Service: closeExpiredRounds()
Service->>RoundRepo: findByRoundStatusAndCloseAtBefore(ACTIVE, now)
RoundRepo->>DB: Query rounds with ACTIVE status<br/>and closeAt < current time
DB-->>RoundRepo: List<AttendanceRound>
RoundRepo-->>Service: roundsToClose
loop For each round to close
Service->>Service: Update round status to CLOSED
Service->>Service: processAbsentees(round)
Service->>UserRepo: Get all users in session
UserRepo->>DB: Query session users
DB-->>UserRepo: List<SessionUser>
UserRepo-->>Service: sessionUsers
Service->>AttendanceRepo: Check attendance existence<br/>for each user in round
AttendanceRepo->>DB: Query attendance records
DB-->>AttendanceRepo: Existing attendance
AttendanceRepo-->>Service: Attendance status
Service->>Service: Identify absent users<br/>(users without records)
Service->>AttendanceRepo: Create ABSENT records<br/>for missing users
AttendanceRepo->>DB: Persist ABSENT attendance
DB-->>AttendanceRepo: Success
AttendanceRepo-->>Service: Batch saved
end
Service-->>Scheduler: Complete
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). 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 |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
backend/src/main/java/org/sejongisc/backend/attendance/repository/AttendanceRoundRepository.java (1)
41-41: 들여쓰기 불일치새로 추가된 메서드가 2칸 들여쓰기를 사용하고 있으나, 파일 내 다른 메서드들은 4칸 들여쓰기를 사용합니다.
🔧 들여쓰기 수정 제안
- List<AttendanceRound> findByRoundStatusAndCloseAtBefore(RoundStatus status, LocalDateTime dateTime); + List<AttendanceRound> findByRoundStatusAndCloseAtBefore(RoundStatus status, LocalDateTime dateTime);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/src/main/java/org/sejongisc/backend/attendance/repository/AttendanceRoundRepository.java` at line 41, AttendanceRoundRepository contains the newly added method findByRoundStatusAndCloseAtBefore(RoundStatus status, LocalDateTime dateTime) with 2-space indentation while the rest of the file uses 4-space indentation; update the method's leading indentation to match the file's 4-space style so formatting is consistent (edit the AttendanceRoundRepository declaration block and align the method signature with other repository methods).backend/src/main/java/org/sejongisc/backend/attendance/service/AttendanceRoundService.java (1)
242-246: 주석 명확화 필요주석에 "PRESENT, LATE 등"이라고 명시되어 있으나,
findAllByAttendanceRound는ABSENT상태를 포함한 모든 출석 기록을 반환합니다. 이는 멱등성을 위해 올바른 동작이지만, 주석이 오해를 유발할 수 있습니다.📝 주석 수정 제안
- // 현재 라운드에 이미 출석 기록(PRESENT, LATE 등)이 있는 SessionUser의 ID 추출 + // 현재 라운드에 이미 출석 기록이 있는 SessionUser의 ID 추출 (PRESENT, LATE, ABSENT 등 모든 상태 포함) Set<UUID> attendedUserIds = attendanceRepository.findAllByAttendanceRound(round)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/src/main/java/org/sejongisc/backend/attendance/service/AttendanceRoundService.java` around lines 242 - 246, Update the misleading comment in AttendanceRoundService where attendedUserIds is populated from attendanceRepository.findAllByAttendanceRound(round): clarify that findAllByAttendanceRound returns all attendance records (including ABSENT) and that we intentionally collect all SessionUser IDs (not just PRESENT/LATE) to ensure idempotent handling; reference the attendedUserIds variable and the call to attendanceRepository.findAllByAttendanceRound(round) so readers understand the behavior and intent.backend/src/main/java/org/sejongisc/backend/attendance/repository/AttendanceRepository.java (1)
32-33: @query를 파생 쿼리 메서드로 단순화 가능해당
@Query는 Spring Data JPA 파생 쿼리 메서드 명명 규칙으로 동일하게 구현할 수 있습니다.♻️ 파생 쿼리 메서드로 변경 제안
- // 라운드별 특정 사용자 출석 확인 - `@Query`("SELECT a FROM Attendance a WHERE a.attendanceRound.roundId = :roundId AND a.user = :user") - Optional<Attendance> findByAttendanceRound_RoundIdAndUser(`@Param`("roundId") UUID roundId, `@Param`("user") User user); + // 라운드별 특정 사용자 출석 확인 + Optional<Attendance> findByAttendanceRound_RoundIdAndUser(UUID roundId, User user);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/src/main/java/org/sejongisc/backend/attendance/repository/AttendanceRepository.java` around lines 32 - 33, 현재 정의한 `@Query`("SELECT a FROM Attendance a WHERE a.attendanceRound.roundId = :roundId AND a.user = :user")을 직접 작성할 필요가 없으니 `@Query` 어노테이션과 `@Param` 어노테이션을 제거하고 파생 쿼리 메서드로 대체하세요: 유지할 메서드 이름은 findByAttendanceRound_RoundIdAndUser(UUID roundId, User user) 또는 findByAttendanceRoundRoundIdAndUser(UUID roundId, User user)처럼 두 인자를 직접 받아 Spring Data JPA가 자동으로 쿼리를 생성하도록 변경하면 됩니다; 관련된 메서드 서명(Attendance, attendanceRound.roundId, user)을 그대로 참조해 구현을 단순화하세요.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@backend/src/main/java/org/sejongisc/backend/attendance/service/AttendanceRoundService.java`:
- Around line 236-265: processAbsentees can violate the Attendance
(round_id,user_id) unique constraint (uk_attendance_round_user) when run twice;
fix by ensuring idempotency: before creating Attendance records, exclude users
who already have an Attendance for that round (use
attendanceRepository.findAllByAttendanceRound(round) results or
attendanceRepository.existsByAttendanceRoundAndUser(user, round) to filter), and
additionally wrap the saveAll call (attendanceRepository.saveAll) in a try/catch
that handles DataIntegrityViolationException/ConstraintViolationException to
ignore duplicate-insert race conditions and log/debug instead of failing the
job; update processAbsentees to perform the pre-insert existence check and add
the exception handling fallback.
- Around line 206-215: The loop in AttendanceRoundService that calls
attendanceRoundRepository.findByRoundStatusAndCloseAtBefore and then
round.changeStatus/processAbsentees is racy in a clustered environment; add a
concurrency-safe guard: add an optimistic lock field (e.g., private `@Version`
Long version) to the AttendanceRound entity, persist schema change, and wrap the
status change + processAbsentees save in a transactional block that catches
OptimisticLockingFailureException and skips already-updated rounds;
alternatively implement an atomic repository update method (e.g.,
updateStatusByIdAndRoundStatus(id, RoundStatus.ACTIVE, RoundStatus.CLOSED) that
returns affected row count and only call processAbsentees when the update
returns 1, or enable Quartz clustering via
spring.quartz.properties.org.quartz.jobStore.isClustered=true — pick one
approach and apply it to AttendanceRoundService (where round.changeStatus and
processAbsentees are invoked).
---
Nitpick comments:
In
`@backend/src/main/java/org/sejongisc/backend/attendance/repository/AttendanceRepository.java`:
- Around line 32-33: 현재 정의한 `@Query`("SELECT a FROM Attendance a WHERE
a.attendanceRound.roundId = :roundId AND a.user = :user")을 직접 작성할 필요가 없으니 `@Query`
어노테이션과 `@Param` 어노테이션을 제거하고 파생 쿼리 메서드로 대체하세요: 유지할 메서드 이름은
findByAttendanceRound_RoundIdAndUser(UUID roundId, User user) 또는
findByAttendanceRoundRoundIdAndUser(UUID roundId, User user)처럼 두 인자를 직접 받아
Spring Data JPA가 자동으로 쿼리를 생성하도록 변경하면 됩니다; 관련된 메서드 서명(Attendance,
attendanceRound.roundId, user)을 그대로 참조해 구현을 단순화하세요.
In
`@backend/src/main/java/org/sejongisc/backend/attendance/repository/AttendanceRoundRepository.java`:
- Line 41: AttendanceRoundRepository contains the newly added method
findByRoundStatusAndCloseAtBefore(RoundStatus status, LocalDateTime dateTime)
with 2-space indentation while the rest of the file uses 4-space indentation;
update the method's leading indentation to match the file's 4-space style so
formatting is consistent (edit the AttendanceRoundRepository declaration block
and align the method signature with other repository methods).
In
`@backend/src/main/java/org/sejongisc/backend/attendance/service/AttendanceRoundService.java`:
- Around line 242-246: Update the misleading comment in AttendanceRoundService
where attendedUserIds is populated from
attendanceRepository.findAllByAttendanceRound(round): clarify that
findAllByAttendanceRound returns all attendance records (including ABSENT) and
that we intentionally collect all SessionUser IDs (not just PRESENT/LATE) to
ensure idempotent handling; reference the attendedUserIds variable and the call
to attendanceRepository.findAllByAttendanceRound(round) so readers understand
the behavior and intent.
ℹ️ Review info
Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 4a65cd9b-fa6d-4d88-8585-e61f4dcc310e
📒 Files selected for processing (3)
backend/src/main/java/org/sejongisc/backend/attendance/repository/AttendanceRepository.javabackend/src/main/java/org/sejongisc/backend/attendance/repository/AttendanceRoundRepository.javabackend/src/main/java/org/sejongisc/backend/attendance/service/AttendanceRoundService.java
#264
Summary by CodeRabbit
주요 변경사항