Skip to content

20260301 #262 정규세션 전체 인원 추가#263

Merged
discipline24 merged 18 commits intomainfrom
20260301_#262_정규세션_전체_인원_추가
Mar 2, 2026

Hidden character warning

The head ref may contain hidden characters: "20260301_#262_\uc815\uaddc\uc138\uc158_\uc804\uccb4_\uc778\uc6d0_\ucd94\uac00"
Merged

20260301 #262 정규세션 전체 인원 추가#263
discipline24 merged 18 commits intomainfrom
20260301_#262_정규세션_전체_인원_추가

Conversation

@daye200
Copy link
Contributor

@daye200 daye200 commented Mar 1, 2026

#262

Summary by CodeRabbit

Release Notes

  • 새로운 기능
    • 모든 활성 사용자를 참석 세션에 일괄 추가하는 기능이 추가되었습니다. 이 기능은 President 권한이 있는 사용자만 사용할 수 있습니다.

@daye200 daye200 requested a review from discipline24 as a code owner March 1, 2026 14:06
@coderabbitai
Copy link

coderabbitai bot commented Mar 1, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2d58d88 and 23ee214.

📒 Files selected for processing (1)
  • backend/src/main/java/org/sejongisc/backend/user/controller/UserController.java
✅ Files skipped from review due to trivial changes (1)
  • backend/src/main/java/org/sejongisc/backend/user/controller/UserController.java

목차별 분석

Walkthrough

출석 세션에 모든 활성 사용자를 일괄 추가하는 새로운 기능을 도입합니다. 프레지던트 역할 기반 접근 제어와 함께 컨트롤러 엔드포인트, 서비스 로직, 저장소 메서드를 추가하여 세션 사용자 관리 기능을 확장합니다.

Changes

집합 / 파일(s) 요약
컨트롤러 엔드포인트
backend/src/main/java/org/sejongisc/backend/attendance/controller/AttendanceSessionController.java
POST /{sessionId}/add-all-users 엔드포인트 추가. PRESIDENT 역할 기반 접근 제어 적용. JWT 기반 인증으로 adminUserId 추출 및 서비스 위임.
서비스 비즈니스 로직
backend/src/main/java/org/sejongisc/backend/attendance/service/AttendanceSessionService.java
addAllUsers 메서드 추가. 관리자 권한 검증, 세션 조회, 모든 ACTIVE 사용자 조회, 중복 여부 확인 후 SessionUser 생성 및 저장 로직 구현.
저장소 쿼리 메서드
backend/src/main/java/org/sejongisc/backend/attendance/repository/SessionUserRepository.java
existsByAttendanceSessionAndUser 메서드 추가. 세션과 사용자 조합이 이미 존재하는지 확인하는 존재성 검사 메서드.
서식 정정
backend/src/main/java/org/sejongisc/backend/user/controller/UserController.java
파일 끝에 개행 문자 추가. 로직 변경 없음.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Controller as AttendanceSessionController
    participant Service as AttendanceSessionService
    participant AuthService as AttendanceAuthorizationService
    participant SessionRepo as AttendanceSessionRepository
    participant UserRepo as UserRepository
    participant SessionUserRepo as SessionUserRepository
    participant Database as Database

    Client->>Controller: POST /{sessionId}/add-all-users
    Controller->>Service: addAllUsers(sessionId, adminUserId)
    Service->>AuthService: ensureAdmin(adminUserId)
    AuthService-->>Service: 권한 검증 완료
    Service->>SessionRepo: findById(sessionId)
    SessionRepo->>Database: 세션 조회
    Database-->>SessionRepo: AttendanceSession 반환
    SessionRepo-->>Service: 세션 객체
    Service->>UserRepo: findAllByStatus(ACTIVE)
    UserRepo->>Database: 활성 사용자 조회
    Database-->>UserRepo: 사용자 목록
    UserRepo-->>Service: 모든 활성 사용자
    loop 각 사용자마다
        Service->>SessionUserRepo: existsByAttendanceSessionAndUser(session, user)
        SessionUserRepo->>Database: 중복 확인
        Database-->>SessionUserRepo: 존재 여부
        SessionUserRepo-->>Service: boolean 반환
        alt 사용자가 세션에 미추가
            Service->>SessionUserRepo: save(새로운 SessionUser)
            SessionUserRepo->>Database: SessionUser 저장
            Database-->>SessionUserRepo: 저장 완료
        end
    end
    Service-->>Controller: 처리 완료
    Controller-->>Client: 200 OK / ResponseEntity<Void>
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Poem

🐰 모든 사용자를 한 번에,
세션에 함께 모으는 마법,
권한은 지켜, 중복은 피하고,
데이터베이스에 쏙쏙 저장되네! ✨
출석 관리, 이제 한결 편해졌어!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 실제 변경 사항의 핵심을 명확하게 반영하고 있습니다. 새로운 API 엔드포인트를 통해 정규 세션에 전체 사용자를 추가하는 기능이 구현되었으며, 제목이 이를 정확하게 설명합니다.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 20260301_#262_정규세션_전체_인원_추가

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
backend/src/main/java/org/sejongisc/backend/user/service/UserService.java (2)

197-203: ⚠️ Potential issue | 🟡 Minor

로그 메시지가 불완전합니다.

log.debug(fieldName)는 필드명만 출력하여 디버깅에 유용하지 않습니다. 어떤 검증이 실패했는지 명확한 메시지를 포함해야 합니다.

🔧 개선 제안
     private String validateNotBlank(String value, String fieldName) {
         if (value == null || value.trim().isEmpty()) {
-            log.debug(fieldName);
+            log.debug("필수 입력값 누락: {}", fieldName);
             throw new CustomException(ErrorCode.INVALID_INPUT);
         }
         return value.trim();
     }
🤖 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/user/service/UserService.java`
around lines 197 - 203, The log in validateNotBlank currently only emits the
field name; replace it with a descriptive message that includes the field being
validated and context (e.g., "Validation failed: <fieldName> is null/blank") so
debugging is meaningful; update the log call in the validateNotBlank method to
include the fieldName in a formatted message (and consider logging at debug or
warn as appropriate) before throwing the
CustomException(ErrorCode.INVALID_INPUT).

205-222: ⚠️ Potential issue | 🟡 Minor

이 메서드들은 사용되지 않는 코드이므로 제거하세요.

getEmailFromRedisdeleteResetTokenFromRedis 메서드는 코드 베이스 어디에서도 호출되지 않습니다. 새로운 비밀번호 재설정 플로우(resetPasswordByCode)에서는 redisTemplate.opsForValue().get() 등을 직접 사용하고 있어, 이 두 메서드는 리팩토링 후 불필요한 코드입니다.

🤖 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/user/service/UserService.java`
around lines 205 - 222, Remove the two unused Redis helper methods
getEmailFromRedis and deleteResetTokenFromRedis from UserService: locate the
methods named getEmailFromRedis(String token) and
deleteResetTokenFromRedis(String token) in the UserService class and delete
their definitions (including try/catch blocks and imports only used by them);
ensure no other code references these symbols (adjust or remove any now-unused
imports like RedisKey or redisService if they become unused) and run
tests/compile to confirm no references remain.
backend/src/test/java/org/sejongisc/backend/user/service/UserServiceTest.java (1)

1-358: 🛠️ Refactor suggestion | 🟠 Major

새로운 비밀번호 재설정 플로우에 대한 테스트가 누락되었습니다.

UserServicepasswordResetSendCoderesetPasswordByCode 메서드가 추가되었으나, 해당 기능에 대한 테스트가 없습니다. Redis 기반 인증코드 검증 로직은 다양한 시나리오(성공, 코드 만료, 코드 불일치, 사용자 미존재 등)에 대한 테스트가 필요합니다.

테스트 코드 작성을 도와드릴까요? 또는 이를 추적할 새 이슈를 생성하시겠습니까?

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

In
`@backend/src/test/java/org/sejongisc/backend/user/service/UserServiceTest.java`
around lines 1 - 358, Add unit tests for the new password-reset flow: create
tests targeting UserService.passwordResetSendCode and
UserService.resetPasswordByCode that mock RedisService, UserRepository,
PasswordEncoder and verify behavior for (1) successful send/code verify and
password change (ensure passwordEncoder.encode called, userRepository.save
invoked, redisService.get/validate and delete called), (2) expired/missing code
(redisService.get returns null -> expect CustomException with appropriate
ErrorCode), (3) mismatched code (redisService.get returns different code ->
expect CustomException), and (4) non-existent user id/email
(userRepository.findById/findByEmail returns Optional.empty -> expect
CustomException); for each test assert correct ErrorCode, mock interactions
(verify(...) and verifyNoMoreInteractions where appropriate), and reuse patterns
from existing signup/update tests (use when(...).thenReturn / thenThrow and
thenAnswer stubs) to validate state and side effects.
🧹 Nitpick comments (7)
backend/src/main/java/org/sejongisc/backend/attendance/controller/AttendanceController.java (1)

61-89: 문서화 개선 LGTM!

OpenAPI 문서가 인증, 권한, 파라미터, 요청 바디, 동작 설명, 응답을 상세하게 기술하고 있어 API 사용자에게 유용합니다.

다만, AI 요약에 따르면 AttendanceSessionController의 관리자 엔드포인트는 @PreAuthorize를 사용하고 있습니다. 일관성을 위해 이 엔드포인트에도 @PreAuthorize 어노테이션 추가를 고려해 보세요. 현재는 서비스 레이어에서 권한 검증이 이루어지는 것으로 보이나, 컨트롤러 레벨에서 명시적으로 선언하면 보안 의도가 더 명확해집니다.

,

♻️ (선택) `@PreAuthorize` 추가 예시
+ import org.springframework.security.access.prepost.PreAuthorize;

  `@Operation`(
      summary = "출석 상태 수정",
      description = """
        ...
        """)
+ `@PreAuthorize`("hasRole('ADMIN') or hasRole('OWNER')")
  `@PutMapping`("/rounds/{roundId}/users/{userId}")
  public ResponseEntity<AttendanceResponse> updateAttendanceStatus(
🤖 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/controller/AttendanceController.java`
around lines 61 - 89, The controller's "출석 상태 수정" endpoint in
AttendanceController lacks a controller-level authorization annotation while
similar admin endpoints (e.g., in AttendanceSessionController) use
`@PreAuthorize`; add a `@PreAuthorize` annotation to the attendance update handler
method in AttendanceController (the method that implements the "출석 상태 수정"
Operation) to mirror the same role/authority check used elsewhere (for example
hasRole/hasAnyRole or hasAuthority checks that include session OWNER and session
admin), ensuring the controller explicitly enforces the same security constraint
as the service layer.
backend/src/main/java/org/sejongisc/backend/user/dto/PasswordResetConfirmRequest.java (1)

26-27: studentId 필드에 @Schema 어노테이션 누락

다른 필드들과 일관성을 위해 studentId 필드에도 Swagger 문서화를 위한 @Schema 어노테이션을 추가하는 것을 권장합니다.

📝 `@Schema` 어노테이션 추가
+        `@Schema`(
+                example = "20231234",
+                description = "사용자의 학번"
+        )
         `@NotBlank`(message = "학번은 필수입니다.")
         String studentId,
🤖 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/user/dto/PasswordResetConfirmRequest.java`
around lines 26 - 27, PasswordResetConfirmRequest 클래스의 studentId 필드에 Swagger
문서화를 위한 `@Schema` 어노테이션이 빠져 있습니다; PasswordResetConfirmRequest의 String studentId
필드에 다른 필드들과 동일한 형식으로 `@Schema`(description = "...", example = "...", required =
true 등 필요한 속성)를 추가해 Swagger UI와 API 문서에 반영되도록 수정하세요.
backend/src/main/java/org/sejongisc/backend/attendance/service/AttendanceSessionService.java (1)

174-185: 배치 저장으로 성능 개선을 권장합니다.

현재 구현은 각 사용자마다 개별 save() 호출을 수행하여 N개의 INSERT 쿼리가 발생합니다. 활성 사용자 수가 많을 경우 성능 저하가 발생할 수 있습니다.

또한 Line 183의 개별 로그 출력은 사용자 수가 많을 때 로그가 과도하게 생성될 수 있습니다.

♻️ 배치 저장 및 요약 로깅으로 개선
+    List<SessionUser> toSave = new ArrayList<>();
     for (User user : allUsers) {
       boolean alreadyAdded = sessionUserRepository.existsByAttendanceSessionAndUser(session, user);
       if (!alreadyAdded) {
         SessionUser su = SessionUser.builder()
             .attendanceSession(session)
             .user(user)
             .sessionRole(SessionRole.PARTICIPANT)
             .build();
-        sessionUserRepository.save(su);
-        log.info("사용자 {} 세션에 추가됨", user.getUserId());
+        toSave.add(su);
       }
     }
+    sessionUserRepository.saveAll(toSave);
+    log.info("{}명의 사용자가 세션에 추가됨", toSave.size());
 
     log.info("세션에 모든 사용자 추가 완료: 세션ID={}", sessionId);
🤖 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/AttendanceSessionService.java`
around lines 174 - 185, The current loop in AttendanceSessionService uses
sessionUserRepository.existsByAttendanceSessionAndUser(...) and
sessionUserRepository.save(...) per user causing N separate queries and many
logs; instead, fetch existing session users for the session once (e.g., via a
repository method like findAllByAttendanceSession or a projection of user IDs),
build a List<SessionUser> of new SessionUser instances using the
SessionUser.builder(...) for users not already present, call
sessionUserRepository.saveAll(newList) to perform a batch insert, and replace
per-user log.info(...) with a single summary log stating how many users were
added.
backend/src/main/java/org/sejongisc/backend/common/auth/service/EmailService.java (1)

132-136: RedisService와 RedisTemplate 혼용

기존 코드에서는 RedisService를 사용하여 Redis 작업을 수행하는데, 비밀번호 재설정 로직에서만 RedisTemplate을 직접 사용합니다. 일관성을 위해 RedisService를 사용하거나, RedisService에 reset 관련 메서드를 추가하는 것을 고려해 주세요.

🤖 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/common/auth/service/EmailService.java`
around lines 132 - 136, EmailService currently mixes direct RedisTemplate usage
(creating key via emailProperties.getKeyPrefix().getReset() + email and calling
hasKey/delete/opsForValue().set) with a higher-level RedisService; replace the
direct redisTemplate calls by using RedisService (or add a reset-specific method
on RedisService) so all Redis access is consistent. Specifically, move the logic
that checks for existence, deletes the key, and sets the code with expiration
into RedisService (e.g., add a method like setWithExpire(key, value, duration)
or resetKeyForEmail(key, value, ttl)) and call that from EmailService instead of
using redisTemplate.hasKey/delete/opsForValue().set; keep the same key
construction using emailProperties.getKeyPrefix().getReset() + email and
preserve emailProperties.getCodeExpire() for TTL.
backend/src/test/java/org/sejongisc/backend/user/service/UserServiceTest.java (1)

235-301: 주석 처리된 테스트 코드는 삭제하거나 별도 이슈로 추적하는 것이 좋습니다.

OAuth 관련 테스트가 주석 처리되어 있습니다. 더 이상 필요하지 않다면 삭제하고, 추후 재활성화가 필요하다면 별도 이슈/TODO로 추적하는 것이 바람직합니다.

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

In
`@backend/src/test/java/org/sejongisc/backend/user/service/UserServiceTest.java`
around lines 235 - 301, The commented OAuth tests (methods
findOrCreateUser_existingUser and findOrCreateUser_newUser in UserServiceTest)
should be either removed or tracked with a TODO/issue; delete the large
commented blocks if they are obsolete, or replace the comment with a short TODO
referencing a ticket/issue ID and a brief reason (e.g., "disabled; re-enable via
ISSUE-XXXX") so they are tracked; ensure any mocked symbols referenced
(OauthUserInfo, oauthAccountRepository, userRepository, UserOauthAccount) are
not left orphaned in imports or setup after removal.
backend/src/main/java/org/sejongisc/backend/user/dto/PasswordResetSendRequest.java (1)

16-17: studentId 필드에 @Schema 어노테이션이 누락되었습니다.

email 필드에는 @Schema 어노테이션이 있지만 studentId에는 없어 Swagger 문서가 불완전합니다. API 문서 일관성을 위해 추가하는 것을 권장합니다.

📝 `@Schema` 어노테이션 추가 제안
         String email,
+        `@Schema`(
+                example = "21012345",
+                description = "사용자의 학번"
+        )
         `@NotBlank`(message = "학번은 필수입니다.")
         String studentId
🤖 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/user/dto/PasswordResetSendRequest.java`
around lines 16 - 17, Add a `@Schema` annotation to the studentId field in the
PasswordResetSendRequest DTO so Swagger docs include it; update the studentId
declaration (in class PasswordResetSendRequest) to annotate it with `@Schema`
(provide a brief description and example and mark required=true as appropriate)
mirroring the existing email field's usage to keep API documentation consistent.
backend/src/main/java/org/sejongisc/backend/common/config/security/SecurityConstants.java (1)

10-10: 중복된 URL 패턴이 존재합니다.

Line 10의 /api/user/password/reset/** 와일드카드 패턴이 이미 Lines 20-21에 추가된 /api/user/password/reset/confirm/api/user/password/reset/send를 포함합니다. 새로 추가된 두 항목은 불필요한 중복입니다.

🔧 중복 항목 제거 제안
             "/favicon.ico",
-            "/api/user/password/reset/confirm",
-            "/api/user/password/reset/send",
             "/actuator",

Also applies to: 20-21

🤖 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/common/config/security/SecurityConstants.java`
at line 10, SecurityConstants에 정의된 URL 패턴 목록에서 중복된 엔트리를 정리하세요: 현재
"/api/user/password/reset/**" 와일드카드는 이미 "/api/user/password/reset/confirm" 및
"/api/user/password/reset/send"를 포함하므로 이 두 개의 개별 문자열 중 하나를 제거해야 합니다; 수정 방법은
SecurityConstants의 패턴 배열(또는 리스트)에서 중복되는 "/api/user/password/reset/confirm" 및
"/api/user/password/reset/send" 항목을 삭제하거나 대신 와일드카드 항목을 제거하여 명시적 엔드포인트만 유지하는 방식으로
일관되게 처리하세요.
🤖 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/common/auth/service/EmailService.java`:
- Around line 129-145: In sendResetEmail (EmailService.sendResetEmail) add a
user existence check via your user lookup (e.g., UserRepository or
UserService.findByEmail); if the user exists, proceed as now (generate code, set
redisTemplate key, createResetMessage and mailSender.send); if the user does not
exist, avoid sending an actual email but return the same success flow/response
to the caller to prevent enumeration (for example skip
createResetMessage/mailSender.send and do not store a real reset token, or store
a dummy value with identical timing), ensuring exceptions and logging remain
identical; keep references to createResetMessage, mailSender, redisTemplate and
emailProperties so you change only the presence-check behavior while preserving
external behavior and timing.

In
`@backend/src/main/java/org/sejongisc/backend/user/controller/UserController.java`:
- Around line 109-111: The API docs inside UserController.java currently list
the request body as PasswordResetSendRequest but the controller method actually
accepts PasswordResetConfirmRequest; update the documentation to match the code
by replacing PasswordResetSendRequest with PasswordResetConfirmRequest (or, if
the intended DTO is PasswordResetSendRequest, change the method parameter in the
relevant controller method to PasswordResetSendRequest) so the doc and the
method signature (PasswordResetConfirmRequest reference) are consistent.

In `@backend/src/main/java/org/sejongisc/backend/user/service/UserService.java`:
- Around line 113-115: The debug log in UserService that calls log.debug with
nEmail and nStudentId (inside the existsByEmailAndStudentId failure branch)
exposes PII; change the logging to avoid raw email/studentId by either removing
them or replacing with masked values (e.g., mask most of nEmail and nStudentId
or log only hash/partial suffix) before calling log.debug, so update the code
around userRepository.existsByEmailAndStudentId, the log.debug invocation, and
any helpers to produce maskedEmail/maskedStudentId or a non-PII hash for safe
logging.

---

Outside diff comments:
In `@backend/src/main/java/org/sejongisc/backend/user/service/UserService.java`:
- Around line 197-203: The log in validateNotBlank currently only emits the
field name; replace it with a descriptive message that includes the field being
validated and context (e.g., "Validation failed: <fieldName> is null/blank") so
debugging is meaningful; update the log call in the validateNotBlank method to
include the fieldName in a formatted message (and consider logging at debug or
warn as appropriate) before throwing the
CustomException(ErrorCode.INVALID_INPUT).
- Around line 205-222: Remove the two unused Redis helper methods
getEmailFromRedis and deleteResetTokenFromRedis from UserService: locate the
methods named getEmailFromRedis(String token) and
deleteResetTokenFromRedis(String token) in the UserService class and delete
their definitions (including try/catch blocks and imports only used by them);
ensure no other code references these symbols (adjust or remove any now-unused
imports like RedisKey or redisService if they become unused) and run
tests/compile to confirm no references remain.

In
`@backend/src/test/java/org/sejongisc/backend/user/service/UserServiceTest.java`:
- Around line 1-358: Add unit tests for the new password-reset flow: create
tests targeting UserService.passwordResetSendCode and
UserService.resetPasswordByCode that mock RedisService, UserRepository,
PasswordEncoder and verify behavior for (1) successful send/code verify and
password change (ensure passwordEncoder.encode called, userRepository.save
invoked, redisService.get/validate and delete called), (2) expired/missing code
(redisService.get returns null -> expect CustomException with appropriate
ErrorCode), (3) mismatched code (redisService.get returns different code ->
expect CustomException), and (4) non-existent user id/email
(userRepository.findById/findByEmail returns Optional.empty -> expect
CustomException); for each test assert correct ErrorCode, mock interactions
(verify(...) and verifyNoMoreInteractions where appropriate), and reuse patterns
from existing signup/update tests (use when(...).thenReturn / thenThrow and
thenAnswer stubs) to validate state and side effects.

---

Nitpick comments:
In
`@backend/src/main/java/org/sejongisc/backend/attendance/controller/AttendanceController.java`:
- Around line 61-89: The controller's "출석 상태 수정" endpoint in
AttendanceController lacks a controller-level authorization annotation while
similar admin endpoints (e.g., in AttendanceSessionController) use
`@PreAuthorize`; add a `@PreAuthorize` annotation to the attendance update handler
method in AttendanceController (the method that implements the "출석 상태 수정"
Operation) to mirror the same role/authority check used elsewhere (for example
hasRole/hasAnyRole or hasAuthority checks that include session OWNER and session
admin), ensuring the controller explicitly enforces the same security constraint
as the service layer.

In
`@backend/src/main/java/org/sejongisc/backend/attendance/service/AttendanceSessionService.java`:
- Around line 174-185: The current loop in AttendanceSessionService uses
sessionUserRepository.existsByAttendanceSessionAndUser(...) and
sessionUserRepository.save(...) per user causing N separate queries and many
logs; instead, fetch existing session users for the session once (e.g., via a
repository method like findAllByAttendanceSession or a projection of user IDs),
build a List<SessionUser> of new SessionUser instances using the
SessionUser.builder(...) for users not already present, call
sessionUserRepository.saveAll(newList) to perform a batch insert, and replace
per-user log.info(...) with a single summary log stating how many users were
added.

In
`@backend/src/main/java/org/sejongisc/backend/common/auth/service/EmailService.java`:
- Around line 132-136: EmailService currently mixes direct RedisTemplate usage
(creating key via emailProperties.getKeyPrefix().getReset() + email and calling
hasKey/delete/opsForValue().set) with a higher-level RedisService; replace the
direct redisTemplate calls by using RedisService (or add a reset-specific method
on RedisService) so all Redis access is consistent. Specifically, move the logic
that checks for existence, deletes the key, and sets the code with expiration
into RedisService (e.g., add a method like setWithExpire(key, value, duration)
or resetKeyForEmail(key, value, ttl)) and call that from EmailService instead of
using redisTemplate.hasKey/delete/opsForValue().set; keep the same key
construction using emailProperties.getKeyPrefix().getReset() + email and
preserve emailProperties.getCodeExpire() for TTL.

In
`@backend/src/main/java/org/sejongisc/backend/common/config/security/SecurityConstants.java`:
- Line 10: SecurityConstants에 정의된 URL 패턴 목록에서 중복된 엔트리를 정리하세요: 현재
"/api/user/password/reset/**" 와일드카드는 이미 "/api/user/password/reset/confirm" 및
"/api/user/password/reset/send"를 포함하므로 이 두 개의 개별 문자열 중 하나를 제거해야 합니다; 수정 방법은
SecurityConstants의 패턴 배열(또는 리스트)에서 중복되는 "/api/user/password/reset/confirm" 및
"/api/user/password/reset/send" 항목을 삭제하거나 대신 와일드카드 항목을 제거하여 명시적 엔드포인트만 유지하는 방식으로
일관되게 처리하세요.

In
`@backend/src/main/java/org/sejongisc/backend/user/dto/PasswordResetConfirmRequest.java`:
- Around line 26-27: PasswordResetConfirmRequest 클래스의 studentId 필드에 Swagger 문서화를
위한 `@Schema` 어노테이션이 빠져 있습니다; PasswordResetConfirmRequest의 String studentId 필드에 다른
필드들과 동일한 형식으로 `@Schema`(description = "...", example = "...", required = true 등
필요한 속성)를 추가해 Swagger UI와 API 문서에 반영되도록 수정하세요.

In
`@backend/src/main/java/org/sejongisc/backend/user/dto/PasswordResetSendRequest.java`:
- Around line 16-17: Add a `@Schema` annotation to the studentId field in the
PasswordResetSendRequest DTO so Swagger docs include it; update the studentId
declaration (in class PasswordResetSendRequest) to annotate it with `@Schema`
(provide a brief description and example and mark required=true as appropriate)
mirroring the existing email field's usage to keep API documentation consistent.

In
`@backend/src/test/java/org/sejongisc/backend/user/service/UserServiceTest.java`:
- Around line 235-301: The commented OAuth tests (methods
findOrCreateUser_existingUser and findOrCreateUser_newUser in UserServiceTest)
should be either removed or tracked with a TODO/issue; delete the large
commented blocks if they are obsolete, or replace the comment with a short TODO
referencing a ticket/issue ID and a brief reason (e.g., "disabled; re-enable via
ISSUE-XXXX") so they are tracked; ensure any mocked symbols referenced
(OauthUserInfo, oauthAccountRepository, userRepository, UserOauthAccount) are
not left orphaned in imports or setup after removal.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fe0bd41 and 3a0f5ba.

📒 Files selected for processing (16)
  • backend/src/main/java/org/sejongisc/backend/attendance/controller/AttendanceController.java
  • backend/src/main/java/org/sejongisc/backend/attendance/controller/AttendanceRoundController.java
  • backend/src/main/java/org/sejongisc/backend/attendance/controller/AttendanceSessionController.java
  • backend/src/main/java/org/sejongisc/backend/attendance/repository/SessionUserRepository.java
  • backend/src/main/java/org/sejongisc/backend/attendance/service/AttendanceSessionService.java
  • backend/src/main/java/org/sejongisc/backend/common/auth/service/EmailService.java
  • backend/src/main/java/org/sejongisc/backend/common/config/EmailProperties.java
  • backend/src/main/java/org/sejongisc/backend/common/config/security/SecurityConstants.java
  • backend/src/main/java/org/sejongisc/backend/common/exception/ErrorCode.java
  • backend/src/main/java/org/sejongisc/backend/user/controller/UserController.java
  • backend/src/main/java/org/sejongisc/backend/user/dto/PasswordResetConfirmRequest.java
  • backend/src/main/java/org/sejongisc/backend/user/dto/PasswordResetSendRequest.java
  • backend/src/main/java/org/sejongisc/backend/user/entity/User.java
  • backend/src/main/java/org/sejongisc/backend/user/repository/UserRepository.java
  • backend/src/main/java/org/sejongisc/backend/user/service/UserService.java
  • backend/src/test/java/org/sejongisc/backend/user/service/UserServiceTest.java

@daye200 daye200 linked an issue Mar 1, 2026 that may be closed by this pull request
Copy link

@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

🤖 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/AttendanceSessionService.java`:
- Around line 168-176: The loop in AttendanceSessionService that calls
sessionUserRepository.existsByAttendanceSessionAndUser for each User causes N+1
queries and a check-then-act race; instead, query existing session user IDs once
(e.g., via a repository method like findUserIdsByAttendanceSession or
findAllByAttendanceSession) and build a List<SessionUser> for only the missing
users (using SessionUser.builder() with attendanceSession, user,
SessionRole.PARTICIPANT), then call sessionUserRepository.saveAll(...) to batch
insert; also ensure the DB has a unique constraint on (attendanceSessionId,
userId) so concurrent inserts are safely rejected and optionally catch
DataIntegrityViolationException to ignore duplicates.

In
`@backend/src/main/java/org/sejongisc/backend/common/auth/service/EmailService.java`:
- Line 36: The EmailService class declares a field RedisTemplate<String, String>
(symbol: redisTemplate) but the import for RedisTemplate is missing; add the
appropriate import for org.springframework.data.redis.core.RedisTemplate at the
top of EmailService.java so the class compiles, and then recompile to verify the
cannot find symbol error is resolved.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3a0f5ba and 2d58d88.

📒 Files selected for processing (4)
  • backend/src/main/java/org/sejongisc/backend/attendance/controller/AttendanceSessionController.java
  • backend/src/main/java/org/sejongisc/backend/attendance/service/AttendanceSessionService.java
  • backend/src/main/java/org/sejongisc/backend/common/auth/service/EmailService.java
  • backend/src/main/java/org/sejongisc/backend/user/controller/UserController.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • backend/src/main/java/org/sejongisc/backend/user/controller/UserController.java
  • backend/src/main/java/org/sejongisc/backend/attendance/controller/AttendanceSessionController.java

Removed an empty line before the prePersist method.
Removed unused redisTemplate field from EmailService.
Removed the password reset operation documentation and its related method.
Copy link
Contributor

@discipline24 discipline24 left a comment

Choose a reason for hiding this comment

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

고생하셨습니다~

@discipline24 discipline24 merged commit a093597 into main Mar 2, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

⚙️ [기능추가][출석] 정규세션 전체 인원 추가

2 participants