-
Notifications
You must be signed in to change notification settings - Fork 1
Main #261
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
[FIX] #209: ์ค๋ณต email ๊ฒ์ฆ ์ค๋ฅ ํด๊ฒฐ
[FEAT]: ์ฝ์ด ๋ฉค๋ฒ ๋ชจ์ง ํผ ์์ฑ ๋ฐ ํ์ผ ์ ๋ก๋ api ์ถ๊ฐ
[FEAT]: ์ฝ์ด ๋ฆฌ์ฟ ๋ฅดํธ ์ง์์ ์กฐํ API ์ถ๊ฐ
Merge branch 'develop'
Merge branch 'develop'
Merge branch 'develop'
Merge branch 'develop'
Merge branch 'develop'
- AuthController์ /auth/{role} ์๋ํฌ์ธํธ ์ถ๊ฐ
- ์์ฒญ๋ role๊ณผ ํ ํฐ ๋ด ์ฌ์ฉ์ ๊ถํ์ ๋น๊ตํ์ฌ ์ ๊ทผ ๊ฐ๋ฅ ์ฌ๋ถ ํ๋จ
- ์์ ๊ถํ ์ฌ์ฉ์๋ ํ์ ๊ถํ ํ์ด์ง ์ ๊ทผ ํ์ฉ, ๊ทธ๋ ์ง ์์ผ๋ฉด 403 ๋ฐํ
- UserRole enum์ ๊ถํ ์์ ๊ธฐ๋ฐ ๋น๊ต ๋ก์ง ์ถ๊ฐ (ordinal ๊ฐ ํ์ฉ)
Feat: ๊ถํ ๊ฒ์ฆ ์๋ํฌ์ธํธ ์ถ๊ฐ ๋ฐ UserRole ๊ธฐ๋ฐ ๋น๊ต ๋ก์ง ๊ฐ์
fix(core-attendance): Postgres unnest ํ๋ผ๋ฏธํฐ ์ค๋ฅ ํด๊ฒฐ โ ๋ฐฐ์ด+์บ์คํ ์ ์ฉ
feat(core-attendance): refine controller endpoints & auth-aware team โฆ
feat(core-attendance): ๋ ์ง ์์ฑ ๊ถํ ์ฒดํฌ ์ถ๊ฐ
[FEAT] ์ฌ์ฉ์ ๊ถํ ๊ด๋ฆฌ ๊ธฐ๋ฅ ์ถ๊ฐ ๋ฐ ์ธ์ฆ/๋ฆฌํฌ๋ฃจํ ๊ถํ ๊ตฌ์กฐ ๊ฐ์
feat(user-admin): ์ฌ์ฉ์ ์ญ์ ๋ฉ์๋ ์ถ๊ฐ (Controller ๋ฐ Service ๊ณ์ธต)
fix(user-admin): User role ์ ๋ ฌ ์ ์ฉ pagination
fix(user-admin): ์ฌ์ฉ์ ๋ชฉ๋ก ์ ๋ ฌ ๋ฐ ๊ถํ๋ณ ์ ๊ทผ ๋ก์ง ๊ฐ์
fix(manito): csv ํ์ผ ํ์ฑ ์ค๋ฅ ์์
fix(manito): csv ํ์ผ ํ์ฑ ์ค๋ฅ ์์
fix(manito): csv ํ์ผ ํ์ฑ ์ค๋ฅ ์์
fix(manito): ๋ฏธ์ ์ค๋ฅ ์์ ์ค
fix(manito): ๋ฏธ์ ์ค๋ฅ ์์ ์ค
fix: ๋๋ฒ๊น ์ค์ ๋ณ๊ฒฝ
fix: ๋๋ฒ๊น ์ค์ ๋ณ๊ฒฝ
fix(manito): ํ ์ ๊ทํ ๋ก์ง ์์กด์ฑ ์ถ๊ฐ
fix(security-config): ๋ง๋๋ ํ์ธ ํ์ด์ง ํํฐ๋ง
fix(manito): ํ ํ์ธ ๋ก๊ทธ
fix(manito): Lob ์ญ์ ๋ฐ Transactional ์ถ๊ฐ
fix(manito): unexpected token ํด๊ฒฐ
fix(manito): UI/UX ๊ฐ์ ์ ๋ฐ๋ฅธ ๋ณ๊ฒฝ์ฌํญ ๋ฐ์
์ํฌ์ค๋ฃจ์ด PR์ ๋ง๋๋ ์์คํ (์ธ์ ๋ฐ ์ฐธ์ฌ์ ๊ด๋ฆฌ), ์ฌ์ฉ์ ๊ด๋ฆฌ ๊ธฐ๋ฅ, ์ธ์ฆยท์ธ๊ฐ ๊ฐํ๋ฅผ ๋์ ํฉ๋๋ค. ๋ํ ์ถ์ ์์คํ ์์ ORGANIZER/LEAD ์ญํ ์ง์์ ํ๋ํ๊ณ , ๋ชจ์ง ๋ชจ๋์ ๊ถํ์ ์ํํ๋ฉฐ, ์ฌ์ฉ์ ์ญํ ๊ณ์ธต ๊ฒ์ฆ ๋ฉ์ปค๋์ฆ์ ์ถ๊ฐํฉ๋๋ค. ๋ณ๊ฒฝ ์ฌํญ
์์ ์ฝ๋ ๋ฆฌ๋ทฐ ๋ ธ๋ ฅ๐ฏ 4 (๋ณต์กํจ) | โฑ๏ธ ~50๋ถ ์ฃผ์๊ฐ ํ์ํ ์์ญ:
๊ด๋ จ ๊ฐ๋ฅ์ฑ ์๋ PR
์ ์ ๋ ์ด๋ธ
์
Pre-merge checks and finishing touchesโ Failed checks (1 warning, 1 inconclusive)
โ Passed checks (1 passed)
โจ Finishing touches
๐งช 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 |
|
CI status |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 13
๐งน Nitpick comments (12)
src/main/java/inha/gdgoc/domain/user/repository/UserRepository.java (1)
39-46: ํ์ด์ง๋ค์ด์ ์ฟผ๋ฆฌ๊ฐ ์ ๊ตฌํ๋์ด ์์ต๋๋ค.JPQL ์์ฑ์ ํํ์์ ์ฌ์ฉํ DTO ํ๋ก์ ์ ๊ณผ ์ ํ์ ์ด๋ฆ ํํฐ๋ง์ด ์ ์ ํ๊ฒ ๊ตฌํ๋์ด ์์ต๋๋ค.
Line 44์
LIKEํจํด์ ์์ชฝ ์์ผ๋์นด๋('%', :q, '%')๊ฐ ์์ด ์ธ๋ฑ์ค ํ์ฉ์ด ์ ํ๋ฉ๋๋ค. ์ฌ์ฉ์ ํ ์ด๋ธ์ด ๋งค์ฐ ํฐ ๊ฒฝ์ฐ ์ ๋ฌธ ๊ฒ์ ์๋ฃจ์ (Full-text search) ๊ณ ๋ ค๋ฅผ ๊ถ์ฅํฉ๋๋ค.src/main/java/inha/gdgoc/domain/core/attendance/controller/CoreAttendanceController.java (1)
71-71: ์ญํ ๊ฒ์ฆ ๋ก์ง ์ค๋ณต์ ํฌํผ ๋ฉ์๋๋ก ์ถ์ถํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค.
me.getRole() == UserRole.LEAD && me.getTeam() != TeamType.HRํจํด์ด ์ด ์ปจํธ๋กค๋ฌ์์ 6๋ฒ ๋ฐ๋ณต๋ฉ๋๋ค (lines 71, 82, 95, 113, 120, 133). ๊ฐ๋ ์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ ์ํด ํฌํผ ๋ฉ์๋๋ก ์ถ์ถํ๋ ๊ฒ์ด ์ข์ต๋๋ค.๐ ํฌํผ ๋ฉ์๋ ์ถ์ถ ์ ์
/* ===== helpers ===== */ +private static boolean isLeadExceptHr(CustomUserDetails me) { + return me.getRole() == UserRole.LEAD && me.getTeam() != TeamType.HR; +} + private static TeamType requiredTeamFrom(CustomUserDetails me) { if (me.getTeam() == null) throw new IllegalArgumentException("LEAD ๊ถํ ํ ํฐ์ team ์ ๋ณด๊ฐ ์์ต๋๋ค."); return me.getTeam(); }์ฌ์ฉ ์์:
-List<TeamResponse> list = (me.getRole() == UserRole.LEAD && me.getTeam() != TeamType.HR) ? ... +List<TeamResponse> list = isLeadExceptHr(me) ? ...src/main/java/inha/gdgoc/domain/user/controller/UserAdminController.java (2)
6-6: ์ฌ์ฉ๋์ง ์๋ import๊ฐ ์์ต๋๋ค.
TeamType์ด import๋์์ง๋ง ์ด ํด๋์ค์์ ์ฌ์ฉ๋์ง ์์ต๋๋ค.๐ ์์ ์ ์
-import inha.gdgoc.domain.user.enums.TeamType;
43-43: ๋ฉ์์ง ์์ ์ฌ์ฉ์ ๊ถ์ฅํฉ๋๋ค.๋ค๋ฅธ ์ปจํธ๋กค๋ฌ๋ค(์:
CoreAttendanceController,RecruitMemberController)์ ๋ฉ์์ง ํด๋์ค์์ ์์๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ผ๊ด์ฑ์ ์ํดUserAdminMessageํด๋์ค๋ฅผ ๋ง๋ค์ด ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค.// ์์: UserAdminMessage.java public class UserAdminMessage { public static final String USER_SUMMARY_LIST_RETRIEVED = "์ฌ์ฉ์ ๋ชฉ๋ก ์กฐํ ์ฑ๊ณต"; public static final String USER_ROLE_TEAM_UPDATED = "์ฌ์ฉ์ ์ญํ /ํ ์์ ์ฑ๊ณต"; public static final String USER_ROLE_UPDATED = "์ฌ์ฉ์ ์ญํ ์์ ์ฑ๊ณต"; public static final String USER_DELETED = "์ฌ์ฉ์ ์ญ์ ์ฑ๊ณต"; }src/main/java/inha/gdgoc/domain/manito/service/ManitoAdminService.java (2)
225-225: ๋ถํ์ํ ๋ฌธ์์ด ์ธ์ฝ๋ฉ/๋์ฝ๋ฉ์ ์ ๊ฑฐํ์ธ์.
sb.toString()์ ์ด๋ฏธ String์ ๋ฐํํ๋ฏ๋ก UTF-8๋ก ๋ณํ ํ ๋ค์ String์ผ๋ก ๋ง๋๋ ์์ ์ ๋ถํ์ํฉ๋๋ค.๐ ์์ ์ ์
- return new String(sb.toString().getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8); + return sb.toString();
193-195: ๋ง๋๋ ๋งค์นญ์SecureRandom์ฌ์ฉ์ ๊ณ ๋ คํ์ธ์.
Collections.shuffle()์ ๊ธฐ๋ณธ์ ์ผ๋กThreadLocalRandom์ ์ฌ์ฉํ๋๋ฐ, ๋ง๋๋ ๋งค์นญ์ ์์ธก ๊ฐ๋ฅ์ฑ์ด ์ค์ํ๋ค๋ฉดSecureRandom์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ์ฃผ์์๋ ์ธ๊ธ๋์ด ์์ผ๋ ๋ณด์ ์๊ตฌ์ฌํญ์ ๋ฐ๋ผ ๊ฒฐ์ ํ์ธ์.๐ ์์ ์ ์
+import java.security.SecureRandom; + List<ManitoAssignment> shuffled = new ArrayList<>(participants); - Collections.shuffle(shuffled); // ํ์ํ๋ฉด SecureRandom ์ฌ์ฉํด๋ ๋จ + Collections.shuffle(shuffled, new SecureRandom());src/main/java/inha/gdgoc/domain/user/service/UserAdminService.java (2)
166-169:@Transactional์ปจํ ์คํธ ๋ด์์save()ํธ์ถ์ ์ ํ์ฌํญ์ ๋๋ค.JPA dirty checking์ด ํธ๋์ญ์ ์ปค๋ฐ ์ ๋ณ๊ฒฝ์ฌํญ์ ์๋์ผ๋ก ๋ฐ์ํ๋ฏ๋ก, ๋ช ์์
save()ํธ์ถ์ด ๋ฐ๋์ ํ์ํ์ง๋ ์์ต๋๋ค. ์ฝ๋ ๋ช ํ์ฑ์ ์ํด ์ ์งํ ์ ์์ง๋ง, ๋ถํ์ํ ํธ์ถ์์ ์ธ์งํ์ธ์.
44-52:UserRoleenum๊ณผ CASE ๋ฌธ์ด ํ์ฌ ๋๊ธฐํ๋์ด ์์ง๋ง, ํ๋์ฝ๋ฉ๋ ์ญํ ๊ฐ์ผ๋ก ์ธํ ์ ์ง๋ณด์ ์ํ์ด ์กด์ฌํฉ๋๋ค.UserRole enum์ ๋ชจ๋ ๊ฐ(GUEST, MEMBER, CORE, LEAD, ORGANIZER, ADMIN)์ด CASE ๋ฌธ์ ๋ฌธ์์ด๊ณผ ์ผ์นํฉ๋๋ค. ๊ทธ๋ฌ๋ enum ์์๊ฐ ๋ณ๊ฒฝ๋๋ฉด ์ด SQL ์ฟผ๋ฆฌ๊ฐ ๊นจ์ง ๊ฐ๋ฅ์ฑ์ด ์์ผ๋ฏ๋ก, enum.name()์ ํ์ฉํ๊ฑฐ๋ ์์๋ก ๊ด๋ฆฌํ๋ ๋ฆฌํฉํ ๋ง์ ๊ณ ๋ คํ์ธ์.
src/main/java/inha/gdgoc/domain/auth/controller/AuthController.java (2)
127-127: ๋ฉ์๋ ์ด๋ฆresponseResponseEntity๊ฐ ์๋ฏธ๋ฅผ ๋ช ํํ ์ ๋ฌํ์ง ๋ชปํฉ๋๋ค.
sendPasswordResetCode๋๋requestPasswordReset๊ณผ ๊ฐ์ด ๊ธฐ๋ฅ์ ๋ช ํํ ๋ํ๋ด๋ ์ด๋ฆ์ผ๋ก ๋ณ๊ฒฝํ์ธ์.๐ ์์ ์ ์
- public ResponseEntity<ApiResponse<Void, Void>> responseResponseEntity(@RequestBody SendingCodeRequest sendingCodeRequest) { + public ResponseEntity<ApiResponse<Void, Void>> requestPasswordResetCode(@RequestBody SendingCodeRequest sendingCodeRequest) {
171-175: ์ธ์ฆ ์คํจ ์ ์์ธ๋ฅผ ๋์ง๋ ๋ฐฉ์์ ๊ณ ๋ คํ์ธ์.์ง์
ResponseEntity๋ฅผ ๊ตฌ์ฑํ๋ ๋์AuthException์ ๋์ง๋ฉด ์ผ๊ด๋ ์๋ฌ ์๋ต ํ์์ ์ ์งํ ์ ์์ต๋๋ค. ํ์ฌ ๋ฐฉ์๋ ๋์ํ์ง๋ง, ๋ค๋ฅธ ์๋ํฌ์ธํธ์์ ์ผ๊ด์ฑ์ ์ํด ์์ธ ๊ธฐ๋ฐ ์ฒ๋ฆฌ๋ฅผ ๊ณ ๋ คํด ๋ณด์ธ์.๐ ์์ ์ ์
// 1) ์ธ์ฆ ์ฒดํฌ if (me == null) { - return ResponseEntity.status(HttpStatus.UNAUTHORIZED) - .body(ApiResponse.error(GlobalErrorCode.UNAUTHORIZED_USER.getStatus() - .value(), GlobalErrorCode.UNAUTHORIZED_USER.getMessage(), null)); + throw new AuthException(UNAUTHORIZED_USER); }src/main/java/inha/gdgoc/domain/core/attendance/service/CoreAttendanceService.java (2)
226-227: ๋ถํ์ํ UTF-8 ์ธ์ฝ๋ฉ ๋ณํ์ ์ ๊ฑฐํ์ธ์.
sb.toString()์ ์ด๋ฏธ ์ฌ๋ฐ๋ฅธ ๋ฌธ์์ด์ ๋ฐํํ๋ฉฐ, UTF-8 ๋ฐ์ดํธ๋ก ๋ณํ ํ ๋ค์ ๋ฌธ์์ด๋ก ๋ณํํ๋ ๊ฒ์ ๋ถํ์ํฉ๋๋ค. ์ด ์์ ์ ์ค์ ๋ก ์๋ฌด๋ฐ ํจ๊ณผ๊ฐ ์์ผ๋ฉฐ,sb.toString()๋ง ๋ฐํํ๋ฉด ๋ฉ๋๋ค.๐ ์ ์ํ๋ ์์
- return new String(sb.toString().getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8); + return sb.toString();
229-302: ์ ์ฒด ์ถ์ ๋งคํธ๋ฆญ์ค CSV ์์ฑ ๋ก์ง์ ํ์ธํ์ธ์.์ ๋ฐ์ ์ธ ๋ก์ง์ ์ฌ๋ฐ๋ฅด๋, ๋ค์ ์ฌํญ๋ค์ ํ์ธํด์ฃผ์ธ์:
๋ถํ์ํ UTF-8 ๋ณํ (301๋ฒ ๋ผ์ธ):
buildSummaryCsv์ ๋์ผํ๊ฒ ๋ถํ์ํ ์ธ์ฝ๋ฉ ๋ณํ์ด ์์ต๋๋ค.sb.toString()๋ง ๋ฐํํ๋ฉด ๋ฉ๋๋ค.๋์ฉ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์ ์ฑ๋ฅ: ์ฌ์ฉ์ ์์ ๋ ์ง ์๊ฐ ๋ง์ ๊ฒฝ์ฐ (์: ์ฌ์ฉ์ 1000๋ช ร ๋ ์ง 50๊ฐ), ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋๊ณผ ์ฒ๋ฆฌ ์๊ฐ์ด ์ฆ๊ฐํ ์ ์์ต๋๋ค. 259-261๋ฒ ๋ผ์ธ์ ๋ฃจํ์์ ๊ฐ ๋ ์ง๋ง๋ค ๋ณ๋์ ์ฟผ๋ฆฌ๋ฅผ ์คํํ๋ฏ๋ก N+1 ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
๐ ์ ์ํ๋ ์์
1. UTF-8 ๋ณํ ์ ๊ฑฐ:
- return new String(sb.toString().getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8); + return sb.toString();2. ์ฑ๋ฅ ๊ฐ์ ๊ณ ๋ ค์ฌํญ:
- ๋์ฉ๋ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํด์ผ ํ๋ค๋ฉด, ๋ฐฐ์น ์ฟผ๋ฆฌ๋ฅผ ํตํด ๋ชจ๋ ๋ ์ง์ ์ถ์ ๋ฐ์ดํฐ๋ฅผ ํ ๋ฒ์ ๊ฐ์ ธ์ค๋ ๊ฒ์ ๊ณ ๋ คํ์ธ์.
- ์ฌ์ฉ์ ์๊ฐ ๋ง์ ๊ฒฝ์ฐ ํ์ด์ง๋ค์ด์ ๋๋ ์คํธ๋ฆฌ๋ฐ ๋ฐฉ์์ CSV ์์ฑ์ ๊ณ ๋ คํ์ธ์.
๐ Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
๐ Files selected for processing (34)
src/main/java/inha/gdgoc/domain/auth/controller/AuthController.java(8 hunks)src/main/java/inha/gdgoc/domain/core/attendance/controller/CoreAttendanceController.java(5 hunks)src/main/java/inha/gdgoc/domain/core/attendance/repository/AttendanceRecordRepository.java(1 hunks)src/main/java/inha/gdgoc/domain/core/attendance/service/CoreAttendanceService.java(6 hunks)src/main/java/inha/gdgoc/domain/core/recruit/controller/CoreRecruitController.java(2 hunks)src/main/java/inha/gdgoc/domain/manito/controller/ManitoAdminController.java(1 hunks)src/main/java/inha/gdgoc/domain/manito/controller/ManitoVerifyController.java(1 hunks)src/main/java/inha/gdgoc/domain/manito/controller/message/ManitoMessage.java(1 hunks)src/main/java/inha/gdgoc/domain/manito/dto/request/ManitoSessionCreateRequest.java(1 hunks)src/main/java/inha/gdgoc/domain/manito/dto/request/ManitoVerifyRequest.java(1 hunks)src/main/java/inha/gdgoc/domain/manito/dto/response/ManitoSessionResponse.java(1 hunks)src/main/java/inha/gdgoc/domain/manito/dto/response/ManitoVerifyResponse.java(1 hunks)src/main/java/inha/gdgoc/domain/manito/entity/ManitoAssignment.java(1 hunks)src/main/java/inha/gdgoc/domain/manito/entity/ManitoSession.java(1 hunks)src/main/java/inha/gdgoc/domain/manito/repository/ManitoAssignmentRepository.java(1 hunks)src/main/java/inha/gdgoc/domain/manito/repository/ManitoSessionRepository.java(1 hunks)src/main/java/inha/gdgoc/domain/manito/service/ManitoAdminService.java(1 hunks)src/main/java/inha/gdgoc/domain/manito/service/ManitoPinPolicy.java(1 hunks)src/main/java/inha/gdgoc/domain/manito/service/ManitoUserService.java(1 hunks)src/main/java/inha/gdgoc/domain/recruit/controller/RecruitMemberController.java(3 hunks)src/main/java/inha/gdgoc/domain/user/controller/UserAdminController.java(1 hunks)src/main/java/inha/gdgoc/domain/user/dto/request/UpdateRoleRequest.java(1 hunks)src/main/java/inha/gdgoc/domain/user/dto/request/UpdateUserRoleTeamRequest.java(1 hunks)src/main/java/inha/gdgoc/domain/user/dto/response/UserSummaryResponse.java(1 hunks)src/main/java/inha/gdgoc/domain/user/entity/User.java(1 hunks)src/main/java/inha/gdgoc/domain/user/enums/TeamType.java(2 hunks)src/main/java/inha/gdgoc/domain/user/enums/UserRole.java(1 hunks)src/main/java/inha/gdgoc/domain/user/repository/UserRepository.java(2 hunks)src/main/java/inha/gdgoc/domain/user/service/UserAdminService.java(1 hunks)src/main/java/inha/gdgoc/global/config/jwt/TokenProvider.java(5 hunks)src/main/java/inha/gdgoc/global/exception/BusinessException.java(1 hunks)src/main/java/inha/gdgoc/global/exception/GlobalErrorCode.java(1 hunks)src/main/java/inha/gdgoc/global/security/SecurityConfig.java(1 hunks)src/main/resources/application-prod.yml(1 hunks)
๐งฐ Additional context used
๐ง Learnings (2)
๐ Learning: 2025-08-30T10:43:25.889Z
Learnt from: kaswhy
Repo: GDGoCINHA/24-2_GDGoC_Server PR: 207
File: src/main/java/inha/gdgoc/global/security/TokenAuthenticationFilter.java:31-39
Timestamp: 2025-08-30T10:43:25.889Z
Learning: The GDGoCINHA project has a consistent security architecture where public endpoints are handled in two layers: 1) SecurityConfig uses .permitAll() for paths like /api/v1/auth/**, /api/v1/game/**, /api/v1/apply/**, /api/v1/check/** and 2) TokenAuthenticationFilter excludes the same paths in shouldNotFilter(). This dual-layer approach is correct and intentional.
Applied to files:
src/main/java/inha/gdgoc/global/security/SecurityConfig.java
๐ Learning: 2025-08-30T10:43:25.889Z
Learnt from: kaswhy
Repo: GDGoCINHA/24-2_GDGoC_Server PR: 207
File: src/main/java/inha/gdgoc/global/security/TokenAuthenticationFilter.java:31-39
Timestamp: 2025-08-30T10:43:25.889Z
Learning: In the GDGoCINHA project, the following API paths are intentionally designed as public endpoints that should not require authentication: /api/v1/auth/, /api/v1/test/, /api/v1/game/, /api/v1/apply/, /api/v1/check/. These paths are correctly excluded from the TokenAuthenticationFilter in shouldNotFilter() method.
Applied to files:
src/main/java/inha/gdgoc/global/security/SecurityConfig.java
๐งฌ Code graph analysis (14)
src/main/java/inha/gdgoc/global/security/SecurityConfig.java (1)
src/main/java/inha/gdgoc/global/security/TokenAuthenticationFilter.java (1)
Override(24-47)
src/main/java/inha/gdgoc/global/exception/GlobalErrorCode.java (2)
src/main/java/inha/gdgoc/global/exception/GlobalExceptionHandler.java (1)
ExceptionHandler(116-126)src/main/java/inha/gdgoc/global/exception/ErrorCode.java (1)
ErrorCode(5-10)
src/main/java/inha/gdgoc/domain/manito/controller/ManitoVerifyController.java (2)
src/main/java/inha/gdgoc/domain/manito/controller/ManitoAdminController.java (1)
RestController(14-53)src/main/java/inha/gdgoc/domain/user/controller/UserController.java (2)
RequestMapping(25-60)PostMapping(43-50)
src/main/java/inha/gdgoc/domain/manito/dto/request/ManitoVerifyRequest.java (2)
src/main/java/inha/gdgoc/domain/core/attendance/dto/request/CreateDateRequest.java (1)
Getter(8-14)src/main/java/inha/gdgoc/domain/core/recruit/dto/request/CoreRecruitApplicationRequest.java (2)
Builder(47-62)Getter(10-63)
src/main/java/inha/gdgoc/domain/user/controller/UserAdminController.java (4)
src/main/java/inha/gdgoc/domain/user/controller/UserController.java (1)
RequestMapping(25-60)src/main/java/inha/gdgoc/domain/game/controller/GameUserController.java (1)
RequestMapping(19-41)src/main/java/inha/gdgoc/domain/study/controller/StudyController.java (1)
RequestMapping(38-108)src/main/java/inha/gdgoc/domain/user/service/UserService.java (1)
Slf4j(23-83)
src/main/java/inha/gdgoc/domain/core/attendance/controller/CoreAttendanceController.java (2)
src/main/java/inha/gdgoc/domain/core/attendance/controller/message/CoreAttendanceMessage.java (1)
CoreAttendanceMessage(3-22)src/main/java/inha/gdgoc/domain/core/attendance/dto/response/DaySummaryResponse.java (1)
Getter(19-27)
src/main/java/inha/gdgoc/domain/manito/controller/ManitoAdminController.java (4)
src/main/java/inha/gdgoc/domain/manito/controller/ManitoVerifyController.java (1)
RestController(16-34)src/main/java/inha/gdgoc/domain/resource/controller/FileUploadController.java (1)
RestController(16-34)src/main/java/inha/gdgoc/domain/user/controller/UserController.java (1)
RequestMapping(25-60)src/main/java/inha/gdgoc/domain/game/controller/GameUserController.java (1)
RequestMapping(19-41)
src/main/java/inha/gdgoc/domain/manito/repository/ManitoSessionRepository.java (5)
src/main/java/inha/gdgoc/domain/core/attendance/repository/MeetingRepository.java (1)
MeetingRepository(8-9)src/main/java/inha/gdgoc/domain/recruit/repository/RecruitMemberRepository.java (2)
RecruitMemberRepository(8-12)existsByStudentId(9-9)src/main/java/inha/gdgoc/domain/recruit/repository/AnswerRepository.java (1)
AnswerRepository(9-15)src/main/java/inha/gdgoc/domain/core/recruit/repository/CoreRecruitApplicationRepository.java (1)
CoreRecruitApplicationRepository(8-10)src/main/java/inha/gdgoc/domain/user/service/UserService.java (1)
Slf4j(23-83)
src/main/java/inha/gdgoc/domain/manito/repository/ManitoAssignmentRepository.java (2)
src/main/java/inha/gdgoc/domain/recruit/repository/RecruitMemberRepository.java (1)
RecruitMemberRepository(8-12)src/main/java/inha/gdgoc/domain/recruit/repository/AnswerRepository.java (1)
AnswerRepository(9-15)
src/main/java/inha/gdgoc/global/exception/BusinessException.java (4)
src/main/java/inha/gdgoc/domain/auth/exception/AuthException.java (2)
AuthException(8-10)AuthException(6-11)src/main/java/inha/gdgoc/domain/user/exception/UserException.java (2)
UserException(6-11)UserException(8-10)src/main/java/inha/gdgoc/domain/resource/exception/ResourceException.java (2)
ResourceException(8-10)ResourceException(6-11)src/main/java/inha/gdgoc/domain/study/exception/StudyException.java (2)
StudyException(6-11)StudyException(8-10)
src/main/java/inha/gdgoc/domain/manito/entity/ManitoSession.java (1)
src/main/java/inha/gdgoc/domain/manito/entity/ManitoAssignment.java (1)
Entity(10-60)
src/main/java/inha/gdgoc/domain/manito/entity/ManitoAssignment.java (1)
src/main/java/inha/gdgoc/domain/manito/entity/ManitoSession.java (1)
Getter(10-41)
src/main/java/inha/gdgoc/domain/user/service/UserAdminService.java (1)
src/main/java/inha/gdgoc/domain/user/controller/UserAdminController.java (1)
RequiredArgsConstructor(22-80)
src/main/java/inha/gdgoc/domain/auth/controller/AuthController.java (4)
src/main/java/inha/gdgoc/global/config/jwt/TokenProvider.java (1)
RequiredArgsConstructor(22-127)src/main/java/inha/gdgoc/domain/auth/service/AuthService.java (1)
Slf4j(27-138)src/main/java/inha/gdgoc/global/security/TokenAuthenticationFilter.java (1)
Slf4j(17-98)src/main/java/inha/gdgoc/domain/auth/controller/message/AuthMessage.java (1)
AuthMessage(3-11)
๐ Additional comments (41)
src/main/java/inha/gdgoc/domain/user/enums/TeamType.java (1)
8-8: LGTM!์๋ก์ด HQ ํ ํ์ ์ด ๊ธฐ์กด ํจํด๊ณผ ์ผ๊ด๋๊ฒ ์ถ๊ฐ๋์์ต๋๋ค. enum ์์์ from() ๋ฉ์๋ ๋ชจ๋ ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ฐ์ดํธ๋์์ต๋๋ค.
Also applies to: 22-22
src/main/java/inha/gdgoc/global/exception/BusinessException.java (1)
15-18: LGTM!์ปค์คํ ๋ฉ์์ง๋ฅผ ์ง์ํ๋ ์์ฑ์๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ถ๊ฐ๋์์ต๋๋ค. ๊ธฐ์กด ์์ฑ์์ ํจ๊ป ๋ ์ ์ฐํ ์์ธ ์ฒ๋ฆฌ๋ฅผ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
src/main/java/inha/gdgoc/domain/user/enums/UserRole.java (2)
18-21: LGTM!๊ถํ ๋น๊ต ๋ก์ง์ด ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์์ต๋๋ค. null ์ธ์์ ๋ํด false๋ฅผ ๋ฐํํ๋ ๊ฒ์ "๊ถํ ์์"์ ์๋ฏธํ๋ ํฉ๋ฆฌ์ ์ธ ๊ธฐ๋ณธ ๋์์ ๋๋ค.
26-35: LGTM!๊ถํ ๊ณ์ธต ๊ตฌ์กฐ๊ฐ ๋ช ํํ๊ฒ ์ ์๋์์ต๋๋ค. enum ์์์ ๋ฌด๊ดํ๊ฒ rank๋ฅผ ์ค์์์ ๊ด๋ฆฌํ๋ ์ข์ ์ค๊ณ์ ๋๋ค.
src/main/java/inha/gdgoc/global/exception/GlobalErrorCode.java (1)
17-17: LGTM! ์๋ฏธ์ ์ฌ๋ฐ๋ฅธ ์์ ์ ๋๋ค.
FORBIDDEN_USER์ HTTP ์ํ๋ฅผ 404์์ 403์ผ๋ก ๋ณ๊ฒฝํ ๊ฒ์ ๊ถํ ๋ถ์กฑ ์ค๋ฅ์ ์๋ฏธ๋ฅผ ์ ํํ ๋ฐ์ํฉ๋๋ค. ๋ค๋ง ์ด๋ API ์๋น์ ์ ์ฅ์์ breaking change์ด๋ฏ๋ก, API ๋ฌธ์๋ ๋ฆด๋ฆฌ์ค ๋ ธํธ์ ๋ช ์ํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค.src/main/java/inha/gdgoc/domain/user/dto/request/UpdateUserRoleTeamRequest.java (1)
6-9: LGTM!๋ถ๋ถ ์ ๋ฐ์ดํธ๋ฅผ ์ํ DTO ์ค๊ณ๊ฐ ๊น๋ํฉ๋๋ค. null์ "๋ณ๊ฒฝ ์์"์ผ๋ก ์ฒ๋ฆฌํ๋ ์๋ฏธ๊ฐ ์ฃผ์์ผ๋ก ๋ช ํํ ํ์๋์ด ์์ต๋๋ค. ์๋น์ค ๊ณ์ธต์์ ์ด ์๋ฏธ๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ฒ๋ฆฌํ๋์ง๋ User.java ๋ฆฌ๋ทฐ์์ ํ์ธ ์์ฒญํ์ต๋๋ค.
src/main/java/inha/gdgoc/domain/user/entity/User.java (1)
134-135: serviceRole null ๊ฐ ์ฒ๋ฆฌ๋ ์์ ํจ
updateRoleAndTeam()๋ฉ์๋์์req.role()์ด null์ผ ๋ ๊ธฐ์กด ์ญํ ์ ์ ์งํ๋ ๋ก์ง์ด ์์ด์,changeRole()์๋ ํญ์ null์ด ์๋ ๊ฐ์ด ์ ๋ฌ๋ฉ๋๋ค.updateUserRoleWithRules()๋ฉ์๋๋newRole๋งค๊ฐ๋ณ์๋ก ๋ฐ์ ์ ํจํ ์ญํ ๊ฐ์ ๊ฒ์ฆ ํ ์ ๋ฌํ๋ฏ๋ก ๋ฌธ์ ์์ต๋๋ค.src/main/java/inha/gdgoc/domain/user/dto/request/UpdateRoleRequest.java (1)
6-8: LGTM!
@NotNull๊ฒ์ฆ์ด ํฌํจ๋ ๊ฐ๊ฒฐํ record DTO์ ๋๋ค. ์ญํ ์ ๋ฐ์ดํธ ์์ฒญ์ ์ ํฉํ ๊ตฌํ์ ๋๋ค.src/main/java/inha/gdgoc/domain/manito/dto/response/ManitoSessionResponse.java (1)
7-11: LGTM!์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋ ํจํด์ ์ฌ์ฉํ ๊น๋ํ DTO ๊ตฌํ์ ๋๋ค.
Instant๋ฅผ ์ฌ์ฉํ ํ์์คํฌํ ์ฒ๋ฆฌ๋ ์ ์ ํฉ๋๋ค.src/main/java/inha/gdgoc/domain/manito/dto/response/ManitoVerifyResponse.java (1)
7-11: LGTM!๋ชฉ์ ์ ๋ช ํํ๊ฒ ์ค๋ช ํ๋ Javadoc๊ณผ ํจ๊ป ๊ฐ๊ฒฐํ๊ฒ ๊ตฌํ๋ DTO์ ๋๋ค.
src/main/java/inha/gdgoc/domain/user/dto/response/UserSummaryResponse.java (1)
6-14: LGTM!๊ด๋ฆฌ์ ์ปจํ ์คํธ์์ ์ฌ์ฉ์ ์์ฝ ์ ๋ณด๋ฅผ ์ ๊ณตํ๊ธฐ ์ํ ์ ์ ํ DTO ๊ตฌํ์ ๋๋ค. ํ์ํ ํ๋๋ค์ด ์ ์ ์๋์ด ์์ต๋๋ค.
src/main/java/inha/gdgoc/domain/manito/repository/ManitoSessionRepository.java (1)
8-18: LGTM!๋ฆฌํฌ์งํ ๋ฆฌ ์ธํฐํ์ด์ค๊ฐ Spring Data JPA ๊ท์น์ ์ ๋ฐ๋ฅด๊ณ ์์ผ๋ฉฐ, ๋ฉ์๋ ๋ค์ด๋ฐ๊ณผ ๋ฌธ์ํ๊ฐ ๋ช ํํฉ๋๋ค.
src/main/java/inha/gdgoc/domain/manito/service/ManitoUserService.java (1)
25-47: ๊ฒ์ฆ ๋ก์ง์ด ์ ๊ตฌํ๋์ด ์์ต๋๋ค.๋ฉ์๋๊ฐ ๋ค์์ ์ ์ ํ ์ฒ๋ฆฌํฉ๋๋ค:
- ์ธ์ ๋ฐ ์ฐธ๊ฐ์ ์กด์ฌ ์ฌ๋ถ ํ์ธ
- PIN ์ ๊ทํ ๋ฐ ๊ฒ์ฆ
- ์ํธํ๋ ๋ง๋๋ ์ ๋ณด ์กด์ฌ ์ฌ๋ถ ํ์ธ
- ๋ช ํํ ์๋ฌ ๋ฉ์์ง์ ์ ์ ํ ์๋ฌ ์ฝ๋ ์ฌ์ฉ
ํธ๋์ญ์ ์ค์ ๊ณผ ์๋ฌ ์ฒ๋ฆฌ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์ด ์์ต๋๋ค.
src/main/java/inha/gdgoc/global/config/jwt/TokenProvider.java (2)
29-38: ์๋ก์ด ํ ํฐ ์์ฑ ๋ฉ์๋๊ฐ ์ ์ ํฉ๋๋ค.
generateSelfSignupToken๊ณผgenerateGoogleLoginToken๋ฉ์๋๊ฐ ๊ธฐ์กดgenerateRefreshTokenํจํด์ ์ ๋ฐ๋ฅด๊ณ ์์ต๋๋ค.
63-77: ๊ถํ ๊ตฌ์ฑ ๋ก์ง์ด ์ฌ๋ฐ๋ฅด๊ฒ ๊ฐ์ ๋์์ต๋๋ค.์ญํ (ROLE_)๊ณผ ํ(TEAM_) ๊ถํ์ ๋ชจ๋ ํฌํจํ๋๋ก ๋ณ๊ฒฝ๋์ด ๋ ์ธ๋ฐํ ๊ถํ ์ ์ด๊ฐ ๊ฐ๋ฅํฉ๋๋ค. ์ ํ์ ํ ์ ๋ณด ์ฒ๋ฆฌ๋ ์ ์ ํฉ๋๋ค.
src/main/java/inha/gdgoc/domain/manito/dto/request/ManitoSessionCreateRequest.java (1)
8-15: LGTM!Record ๊ธฐ๋ฐ DTO๊ฐ ๊ฐ๊ฒฐํ๊ณ ๋ช ํํ๋ฉฐ, ๊ฒ์ฆ ์ ์ฝ์กฐ๊ฑด์ด ์ ์ ํ๊ฒ ์ค์ ๋์ด ์์ต๋๋ค.
src/main/java/inha/gdgoc/domain/manito/dto/request/ManitoVerifyRequest.java (1)
19-22: ๊ฒ์ฆ ์ ์ฝ์กฐ๊ฑด์ด ์ ์ ํฉ๋๋ค.PIN ํ๋์ ๊ฒ์ฆ์ด ๋จ๊ณ์ ์ผ๋ก ๋ช ํํ ์๋ฌ ๋ฉ์์ง๋ฅผ ์ ๊ณตํ๋๋ก ๊ตฌ์ฑ๋์ด ์์ต๋๋ค.
@Size์@Pattern์ ์กฐํฉ์ด ์ฌ์ฉ์์๊ฒ ๋ ๋์ ๊ฒ์ฆ ํผ๋๋ฐฑ์ ์ ๊ณตํฉ๋๋ค.src/main/java/inha/gdgoc/domain/user/repository/UserRepository.java (1)
48-48: Null ์์ ์ฑ ๊ฐ์ ์ด ์ ์ ํฉ๋๋ค.
@NotNull์ด๋ ธํ ์ด์ ์ถ๊ฐ๋ก ๋ฉ์๋ ๊ณ์ฝ์ด ๋ช ํํด์ก์ต๋๋ค.src/main/java/inha/gdgoc/domain/core/attendance/repository/AttendanceRecordRepository.java (1)
29-36: ๋ฉ์๋ ์๊ทธ๋์ฒ ๋ณ๊ฒฝ์ด ์ ์ ํ๊ฒ ๋ฐ์๋์์ต๋๋ค.PostgreSQL ํ์ ์์ ์ฑ์ ์ํ
CAST(:userIds AS bigint[])์ถ๊ฐ์ ํ๋ผ๋ฏธํฐ ๋ณ๊ฒฝ(List<Long>โLong[])์ด ๋ชจ๋ ์ฌ๋ฐ๋ฅด๊ฒ ์ ์ฉ๋์์ต๋๋ค. CoreAttendanceService์ ํธ์ถ ์ง์ ์์userIds.toArray(Long[]::new)์ผ๋ก ์ ํํ ๋ณํ๋์ด ๋ฉ์๋์ ์ ๋ฌ๋๊ณ ์์ต๋๋ค.src/main/java/inha/gdgoc/domain/manito/controller/ManitoVerifyController.java (1)
23-33: ์ปจํธ๋กค๋ฌ ๊ตฌํ์ด ์ ์ ํฉ๋๋ค.REST ์๋ํฌ์ธํธ ๊ตฌ์กฐ๊ฐ ๋ช ํํ๊ณ , ๊ฒ์ฆ ๋ฐ ์๋ต ์ฒ๋ฆฌ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์ด ์์ต๋๋ค.
verifyAndGetAssignment๋ฉ์๋๊ฐencryptedManitto์ ์กด์ฌ ์ฌ๋ถ๋ฅผ ๊ฒ์ฆํ๋ฏ๋ก Line 27์ ์์ ํ๊ณ ,nameํ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ค์์nullable = false์ ์ฝ์ด ์ค์ ๋์ด ์์ผ๋ฏ๋ก Line 28์getName()๋ null์ ๋ฐํํ ์ ์์ด ์์ ํฉ๋๋ค.src/main/java/inha/gdgoc/domain/manito/repository/ManitoAssignmentRepository.java (1)
10-28: LGTM!๋ค๋ฅธ ์ฟผ๋ฆฌ ๋ฉ์๋๋ค์ Spring Data JPA ๋ค์ด๋ฐ ์ปจ๋ฒค์ ์ ์ ๋ฐ๋ฅด๊ณ ์์ผ๋ฉฐ,
Optional๋ฐํ ํ์ ์ ์ ์ ํ ์ฌ์ฉํ์ฌ null ์์ ์ฑ์ ํ๋ณดํ์ต๋๋ค.findBySession_CodeAndStudentId๋ฅผ ํตํด ์ธ์ ๋ ํฌ์งํ ๋ฆฌ ์์ด ๋ฐ๋ก ์กฐํํ ์ ์๋ ์ ๋ ์ข์ ์ค๊ณ์ ๋๋ค.src/main/java/inha/gdgoc/domain/core/attendance/controller/CoreAttendanceController.java (2)
54-66: LGTM!๋ ์ง ์์ฑ/์ญ์ ์๋ํฌ์ธํธ์ ๋ํ
ORGANIZER/ADMIN์ญํ ์ ํ์ด ์ ์ ํฉ๋๋ค. ํด๋์ค ๋ ๋ฒจ์@PreAuthorize๋ฅผ ๋ฉ์๋ ๋ ๋ฒจ์์ ๋ ์ ํ์ ์ผ๋ก ์ค๋ฒ๋ผ์ด๋ํ๋ ํจํด์ Spring Security ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ฐ๋ฆ ๋๋ค.
127-141: LGTM!์๋ก์ด
summaryCsvAll์๋ํฌ์ธํธ๊ฐ ๊ธฐ์กด ํจํด์ ์ผ๊ด๋๊ฒ ๋ฐ๋ฅด๊ณ ์์ต๋๋ค. Content-Disposition ํค๋ ์ค์ ๊ณผ CSV ์๋ต ์ฒ๋ฆฌ๊ฐ ์ ์ ํฉ๋๋ค.src/main/java/inha/gdgoc/domain/recruit/controller/RecruitMemberController.java (1)
88-88: ๊ถํ ํํ์์ ๋ ผ๋ฆฌ์ ์๋๋ฅผ ํ์ธํด ์ฃผ์ธ์.ํ์ฌ
@PreAuthorizeํํ์์ ๋ค์๊ณผ ๊ฐ์ด ํด์๋ฉ๋๋ค:
LEAD,ORGANIZER,ADMIN์ญํ ์ค ํ๋๋ฅผ ๊ฐ์ง ์ฌ์ฉ์ ๋๋- ์ญํ ์ ๊ด๊ณ์์ด HR ํ์ ์ํ ๋ชจ๋ ์ฌ์ฉ์
์ด๋ก ์ธํด HR ํ์ ์ํ ์ผ๋ฐ
USER์ญํ ์ ์ฌ์ฉ์๋ ์ด ๋ฏผ๊ฐํ ์๋ํฌ์ธํธ์ ์ ๊ทผํ ์ ์์ต๋๋ค. ์๋๋ ๋์์ด๋ผ๋ฉด ๋ฌด์ํ์ ๋ ๋์ง๋ง,LEAD์ญํ ์ด๋ฉด์ HR ํ์ธ ๊ฒฝ์ฐ๋ง ํ์ฉํ๋ ค๋ฉด ํํ์์ ์์ ํด์ผ ํฉ๋๋ค.์๋๋ ๋์์ธ์ง ํ์ธํด ์ฃผ์ธ์:
- ํ์ฌ: HR ํ์์ด๋ฉด ์ญํ ๋ฌด๊ดํ๊ฒ ์ ๊ทผ ๊ฐ๋ฅ
- ๋์:
(hasRole('LEAD') and principal.team == T(...).HR) or hasAnyRole('ORGANIZER','ADMIN')src/main/java/inha/gdgoc/domain/user/controller/UserAdminController.java (1)
59-59: HR ํ ๊ถํ ํํ์ ์๋ ํ์ธ ํ์.
RecruitMemberController์ ๋์ผํ ํจํด์ ๋๋ค. HR ํ์ ์ํ ์ผ๋ฐUSER์ญํ ๋ ์ญํ ์์ ๊ถํ์ ๊ฐ์ง๊ฒ ๋ฉ๋๋ค. ์๋๋ ๋์์ธ์ง ํ์ธํด ์ฃผ์ธ์.src/main/java/inha/gdgoc/domain/manito/controller/ManitoAdminController.java (1)
39-46: ํ์ผ ์ ๋ก๋ ์๋ํฌ์ธํธ์ ๋ํ ๊ฒ์ฆ ์๋ฃ.๋ค์ ์ฌํญ๋ค์ด ์ด๋ฏธ ๊ตฌํ๋์ด ์์ต๋๋ค:
ํ์ผ ํฌ๊ธฐ ์ ํ: ๋ชจ๋ ์ค์ ํ์ผ(dev, local, prod)์์
max-file-size: 10MB,max-request-size: 12MB๋ก ์ค์ ๋์ด ์์ต๋๋ค.CSV ํ์ ๊ฒ์ฆ:
ManitoAdminService.importParticipantsCsv()์์ ๋น ํ์ผ ํ์ธ, ํค๋ ํ์ ๊ฒ์ฆ, ํ์ ์ปฌ๋ผ ๊ฒ์ฆ, CSV ์ด์ค์ผ์ดํ ์ฒ๋ฆฌ, ํ๋ ๊ฐ ๊ฒ์ฆ์ด ๋ชจ๋ ์๋น์ค ๋ ์ด์ด์์ ์ํ๋ฉ๋๋ค.๋ฉ๋ชจ๋ฆฌ ํจ์จ์ฑ: CSV ๊ฐ์ ธ์ค๊ธฐ๋
BufferedReader๋ก ์คํธ๋ฆฌ๋ฐ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌ๋๋ฉฐ, CSV ๋ด๋ณด๋ด๊ธฐ๋StringBuilder๋ก ๋น๋๋์ด ์ผ๋ฐ์ ์ธ ๋ฐ์ดํฐ ๊ท๋ชจ์์ ๋ฉ๋ชจ๋ฆฌ ๋ฌธ์ ๊ฐ ์์ต๋๋ค.src/main/java/inha/gdgoc/domain/manito/entity/ManitoSession.java (2)
10-14: ์ํฐํฐ ๊ตฌ์กฐ๊ฐ ์ ์ ํฉ๋๋ค.JPA ์ํฐํฐ๋ก์ ์ ์ ํ ์ด๋ ธํ ์ด์ ๊ตฌ์ฑ์ ๋๋ค.
@NoArgsConstructor(access = AccessLevel.PROTECTED)๋ก JPA ํ๋ก์ ์์ฑ์ ์ง์ํ๋ฉด์ ์ธ๋ถ ์ง์ ์์ฑ์ ๋ฐฉ์งํฉ๋๋ค.
32-40: Builder ํจํด๊ณผ ๋ณ๊ฒฝ ๋ฉ์๋ ๊ตฌํ์ด ์ ์ ํฉ๋๋ค.
code๋ ๋ถ๋ณ์ผ๋ก ์ ์งํ๊ณtitle๋ง ๋ณ๊ฒฝ ๊ฐ๋ฅํ๊ฒ ํ ์ค๊ณ๊ฐ ์ข์ต๋๋ค. ์ธ์ ์ฝ๋๋ ์๋ณ์ ์ญํ ์ ํ๋ฏ๋ก ์์ฑ ํ ๋ณ๊ฒฝ์ ๋ง๋ ๊ฒ์ด ์ฌ๋ฐ๋ฅธ ์ ๊ทผ์ ๋๋ค.src/main/java/inha/gdgoc/domain/manito/entity/ManitoAssignment.java (3)
10-14: ์ํฐํฐ ๊ตฌ์กฐ์ ์ ์ฝ ์กฐ๊ฑด์ด ์ ์ค๊ณ๋์์ต๋๋ค.์ธ์ -ํ๋ฒ ์กฐํฉ์ ๋ํ ์ ๋ํฌ ์ ์ฝ(
uq_manito_assignment_per_student)๊ณผ ์ ์ ํ ์ธ๋ฑ์ค ์ค์ ์ผ๋ก ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ๊ณผ ์ฟผ๋ฆฌ ์ฑ๋ฅ์ ๋ณด์ฅํฉ๋๋ค.
20-22: LAZY ํ์น ์ ๋ต์ด ์ ์ ํฉ๋๋ค.
ManyToOne๊ด๊ณ์FetchType.LAZY๋ฅผ ์ฌ์ฉํ์ฌ ๋ถํ์ํ ์ธ์ ๋ฐ์ดํฐ ๋ก๋ฉ์ ๋ฐฉ์งํฉ๋๋ค.
49-59: ๋ณ๊ฒฝ ๋ฉ์๋๋ค์ด ๋๋ฉ์ธ ์บก์ํ๋ฅผ ์ ์งํต๋๋ค.Setter ๋์ ๋ช ์์ ์ธ ๋ณ๊ฒฝ ๋ฉ์๋(
changePinHash,changeEncryptedManitto,changeName)๋ฅผ ์ ๊ณตํ์ฌ ๋๋ฉ์ธ ๋ก์ง์ ์๋๋ฅผ ๋ช ํํ ํฉ๋๋ค.src/main/java/inha/gdgoc/domain/manito/service/ManitoAdminService.java (1)
59-87: ๊ทธ๋ฃน ํฌ๊ธฐ ๊ณ์ฐ ์๊ณ ๋ฆฌ์ฆ์ด ์ ์ ํฉ๋๋ค.5~9๋ช ๊ทธ๋ฃน์ผ๋ก ๋ถํ ํ๋ ๋ก์ง์ด ๋ช ํํ๊ฒ ๊ตฌํ๋์ด ์์ผ๋ฉฐ, ์ต์ ์ธ์ ๊ฒ์ฆ๋ ํฌํจ๋์ด ์์ต๋๋ค.
src/main/java/inha/gdgoc/domain/user/service/UserAdminService.java (3)
97-102: ๊ถํ ๊ฒ์ฆ ๋ก์ง์ด ์ ์ ํฉ๋๋ค.ํธ์ง์๊ฐ ๋์์ ํ์ฌ ์ญํ ๊ณผ ์ ์ญํ ๋ชจ๋๋ณด๋ค ์์ ๊ถํ์ ๊ฐ์ ธ์ผ ํ๋ ๊ฒ์ฆ์ด ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์ด ์์ต๋๋ค.
104-143: ์ญํ ๋ณ ๊ถํ ๊ท์น์ด ๋ช ํํ๊ฒ ๊ตฌํ๋์์ต๋๋ค.ADMIN, ORGANIZER, LEAD ๊ฐ๊ฐ์ ๋ํ ๊ถํ ์ ์ฝ์ด switch ํํ์์ผ๋ก ์ ์ ๋ฆฌ๋์ด ์์ต๋๋ค. HR-LEAD์ ํ ๋ณ๊ฒฝ ์์ธ ์ผ์ด์ค๋ ์ ์ ํ ์ฒ๋ฆฌ๋ฉ๋๋ค.
163-172: HR-CORE ์์ธ ๊ฒฝ๋ก๊ฐ ์ ์ ํ ๊ตฌํ๋์์ต๋๋ค.HRํ CORE ๋ฉค๋ฒ๊ฐ GUEST๋ฅผ MEMBER๋ก ์น๊ฒฉํ ์ ์๋ ํน๋ณ ๊ถํ์ด ๋ช ํํ๊ฒ ๋ถ๋ฆฌ๋์ด ์์ต๋๋ค.
src/main/java/inha/gdgoc/domain/auth/controller/AuthController.java (2)
168-198: ์ญํ /ํ ๊ฒ์ฆ ์๋ํฌ์ธํธ๊ฐ ์ ๊ตฌํ๋์์ต๋๋ค.
UserRole.hasAtLeast๋ฅผ ์ฌ์ฉํ ์ญํ ๊ฒ์ฆ๊ณผ ORGANIZER ์ด์์ ํ ๊ฒ์ฆ์ ์ฐํํ๋ ๋ก์ง์ด ์ ์ ํฉ๋๋ค. OR ์กฐ๊ฑด์ผ๋ก ์ต์ข ํ์ ํ๋ ๊ฒ๋ ํฉ๋ฆฌ์ ์ ๋๋ค.
168-169: ์ ํจํ์ง ์์ ์ญํ ๊ฐ์ ๋ํ ์์ธ ์ฒ๋ฆฌ๋ ์ด๋ฏธ ๊ตฌํ๋์ด ์์ต๋๋ค.
@PathVariable UserRole role์ ์๋ชป๋ ๋ฌธ์์ด์ด ์ ๋ฌ๋ ๋ ๋ฐ์ํ๋MethodArgumentTypeMismatchException์GlobalExceptionHandler์์@ExceptionHandler(MethodArgumentTypeMismatchException.class)(72-84์ค)๋ก ์ด๋ฏธ ์ฒ๋ฆฌ๋๊ณ ์์ต๋๋ค.src/main/java/inha/gdgoc/domain/core/attendance/service/CoreAttendanceService.java (4)
33-39: CSV ์ด์ค์ผ์ดํ ๋ก์ง์ด ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์์ต๋๋ค.RFC 4180 CSV ํ์ค์ ๋ฐ๋ผ null ์ฒ๋ฆฌ, ํน์ ๋ฌธ์ ๊ฐ์ง, ๋ฐ์ดํ ์ด์ค์ผ์ดํ์ด ์ ํํ๊ฒ ๊ตฌํ๋์ด ์์ต๋๋ค.
306-336: ํฌํผ ๋ฉ์๋ ๋ฌธ์ํ๊ฐ ์ ๋์ด ์์ต๋๋ค.Javadoc ์ฃผ์ ์ถ๊ฐ์ ์ฝ๋ ํฌ๋งทํ ๊ฐ์ ์ด ์ ์ ํ๊ฒ ์ด๋ฃจ์ด์ก์ต๋๋ค.
88-96: ํ๋ก์ ํธ์ Java ๋ฒ์ ์ 17๋ก ์ค์ ๋์ด ์์ต๋๋ค.
.toList()๋ฉ์๋๋ Java 16๋ถํฐ ๋์ ๋์์ผ๋ฉฐ, ํ๋ก์ ํธ๊ฐ Java 17์ ์ฌ์ฉํ๊ณ ์์ผ๋ฏ๋ก ํธํ์ฑ ๋ฌธ์ ๋ ์์ต๋๋ค. ํ์ฌ ์ฝ๋๋ ์ต์ Java ๋ฌธ๋ฒ์ ์ ์ ํ๊ฒ ํ์ฉํ๊ณ ์์ต๋๋ค.
76-76: UserRole.ORGANIZER ์ถ๊ฐ๋ ์ปจํธ๋กค๋ฌ ๋ ๋ฒจ์ ๊ธฐ์กด ๊ถํ ๋ชจ๋ธ๊ณผ ์ผ์นํฉ๋๋ค.์ปจํธ๋กค๋ฌ ํด๋์ค ๋ ๋ฒจ์
@PreAuthorize("hasAnyRole('LEAD','ORGANIZER','ADMIN')")์์ ์ด๋ฏธ ORGANIZER ์ญํ ์ด ํ๊ฐ๋์ด ์์ต๋๋ค. ๋์ฑ์ด ์ปจํธ๋กค๋ฌ ๋ก์ง(line 71, 82, 113)์์ ์ด๋ค ์๋น์ค ๋ฉ์๋๋ LEAD ์ฌ์ฉ์๊ฐ ์๋ ๋(๋๋ HR ํ์ LEAD์ผ ๋) ํธ์ถ๋๋ฏ๋ก, ORGANIZER์ ADMIN์ด ์๋๋ ๋์์ ๋๋ค. ์๋น์ค ๋ฉ์๋์ UserRole.ORGANIZER๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ ๊ธฐ์กด ๊ถํ ์ ์ฑ ๊ณผ ์ผ๊ด์ฑ ์๋ ๋ณ๊ฒฝ์ ๋๋ค.
| security = { @SecurityRequirement(name = "BearerAuth") } | ||
| ) | ||
| @PreAuthorize("hasRole('ADMIN')") | ||
| @PreAuthorize("hasAnyRole('LEAD', 'ORGANIZER', 'ADMIN')") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
๐งฉ Analysis chain
๐ Script executed:
# 1. CoreRecruitController.java ํ์ผ์ ์ค์ ๋ด์ฉ ํ์ธ (lines 50-100)
cat -n src/main/java/inha/gdgoc/domain/core/recruit/controller/CoreRecruitController.java | sed -n '50,100p'Repository: GDGoCINHA/24-2_GDGoC_Server
Length of output: 2669
๐ Script executed:
# 2. CoreRecruitApplicationService ๋๋ ๊ด๋ จ ์๋น์ค์์ ํํฐ๋ง ๋ก์ง ํ์ธ
fd -e java CoreRecruitApplicationService -o CoreRecruitService --exec wc -l {} \; | head -5Repository: GDGoCINHA/24-2_GDGoC_Server
Length of output: 226
๐ Script executed:
# 3. ์ ์ฒด ์ฝ๋๋ฒ ์ด์ค์์ hasAnyRole ํจํด ๊ฒ์
rg -n "hasAnyRole.*LEAD.*ORGANIZER" --type=javaRepository: GDGoCINHA/24-2_GDGoC_Server
Length of output: 1814
๐ Script executed:
# 4. UserRole ๋๋ Role enum ์ ์ ํ์ธ
fd -e java | xargs grep -l "enum.*Role\|class.*Role" | head -5Repository: GDGoCINHA/24-2_GDGoC_Server
Length of output: 455
๐ Script executed:
# 5. CoreRecruitController ํ์ผ์ ์ ์ฒด ๋ผ์ธ ์ ํ์ธ
wc -l src/main/java/inha/gdgoc/domain/core/recruit/controller/CoreRecruitController.javaRepository: GDGoCINHA/24-2_GDGoC_Server
Length of output: 157
๐ Script executed:
# CoreRecruitApplicationService ํ์ผ ์ฐพ๊ธฐ ๋ฐ ๋ด์ฉ ํ์ธ
fd -e java -path "*/service/*" | xargs grep -l "CoreRecruitApplicationService\|findApplicantsPage\|getApplicantDetail" | head -3Repository: GDGoCINHA/24-2_GDGoC_Server
Length of output: 239
๐ Script executed:
# CoreRecruitApplicationService์ findApplicantsPage ๋ฉ์๋ ๊ตฌํ ํ์ธ
rg -n "findApplicantsPage|getApplicantDetail" -A 10 --type=java -B 2Repository: GDGoCINHA/24-2_GDGoC_Server
Length of output: 5190
๐ Script executed:
# CoreRecruitApplication ์ํฐํฐ ๊ตฌ์กฐ ํ์ธ (ํ ์ฐ๊ด์ฑ ์๋์ง)
fd -e java CoreRecruitApplication --type=java | xargs cat | head -100Repository: GDGoCINHA/24-2_GDGoC_Server
Length of output: 242
๐ Script executed:
# RecruitMemberController์ ๋น๊ตํ๊ธฐ ์ํด ์ ์ฌํ ํํฐ๋ง ํจํด ํ์ธ
rg -n "TeamType.*HR.*principal.team" --type=java -B 5 -A 5 | head -30Repository: GDGoCINHA/24-2_GDGoC_Server
Length of output: 3988
๐ Script executed:
# CoreRecruitApplication ์ํฐํฐ ๊ตฌ์กฐ ํ์ธ
find . -name "CoreRecruitApplication.java" -exec cat {} \;Repository: GDGoCINHA/24-2_GDGoC_Server
Length of output: 2021
๐ Script executed:
# CoreRecruitApplicantDetailResponse์ CoreRecruitApplicantSummaryResponse ํ์ธ (์ด๋ค ๋ฐ์ดํฐ ๋
ธ์ถ๋๋์ง)
rg -n "class CoreRecruitApplicant.*Response" -A 15Repository: GDGoCINHA/24-2_GDGoC_Server
Length of output: 53
๐ Script executed:
# CoreRecruitApplication์ repository ์ฟผ๋ฆฌ ๋ฉ์๋ ํ์ธ
rg -n "CoreRecruitApplicationRepository\|interface.*CoreRecruitApplication" -A 20Repository: GDGoCINHA/24-2_GDGoC_Server
Length of output: 53
์ง์์ ์กฐํ ์๋ํฌ์ธํธ์ ํ ์์ค ๋ณด์ ํํฐ๋ง์ด ๋๋ฝ๋์ด ์์ต๋๋ค.
์ ๊ทผ ๊ถํ์ด ADMIN ์ ์ฉ์์ LEAD, ORGANIZER, ADMIN์ผ๋ก ํ๋๋์์ผ๋, ์๋น์ค ๊ณ์ธต์์ ํ ์์ค ํํฐ๋ง์ด ์ ํ ๊ตฌํ๋์ง ์์์ต๋๋ค.
findApplicantsPage()(๋ผ์ธ 42-47): ์ด๋ฆ ๊ฒ์๋ง ์ํ, ํ ๊ธฐ๋ฐ ํํฐ๋ง ์์getApplicantDetail()(๋ผ์ธ 50-54): ์ง์ ID ์กฐํ, ๊ถํ ๊ฒ์ฆ ์์CoreRecruitApplication์ํฐํฐ๋ "team" ํ๋๋ฅผ ๋ณด์ ํ๊ณ ์์ผ๋ฏ๋ก ์ง์์๊ฐ ํ๋ณ๋ก ๋ฒ์๊ฐ ์ง์ ๋์ด์ผ ํจ์ ์์ฌํฉ๋๋ค
ํ์ฌ ์ํ์์ LEAD์ ORGANIZER ์ญํ ์ ๊ฐ์ง ์ฌ์ฉ์๋ ๋ชจ๋ ํ์ ๋ชจ๋ ์ง์์ ์ ๋ณด(ํ๋ฒ, ์ ํ๋ฒํธ, ์ด๋ฉ์ผ, ์ง์ ๋๊ธฐ, ๊ฐ์ ๋ฑ ๋ฏผ๊ฐํ ๊ฐ์ธ์ ๋ณด)์ ์ ํ ์์ด ์ ๊ทผํ ์ ์์ต๋๋ค.
ํ๋ณ ๋๋ ์ญํ ์ปจํ ์คํธ์ ๋ฐ๋ฅธ ํํฐ๋ง ๋ก์ง์ ์๋น์ค ๋๋ ์ ์ฅ์ ๊ณ์ธต์ ์ถ๊ฐํด์ผ ํฉ๋๋ค.
๐ค Prompt for AI Agents
In
src/main/java/inha/gdgoc/domain/core/recruit/controller/CoreRecruitController.java
around lines 42-55, the controller was broadened to LEAD/ORGANIZER/ADMIN but did
not enforce row-level team filtering; update the service/repository layer to
apply team-based access control and modify findApplicantsPage() (lines ~42-47)
to add a team filter when the caller is LEAD or ORGANIZER (Admins bypass), and
modify getApplicantDetail() (lines ~50-54) to verify the current user's team(s)
against the applicant's team and return 403 (or throw AccessDenied) when not
allowed; obtain the caller's roles and team membership from SecurityContext (or
a CurrentUser service), push team-limited queries down to the repository (add
team constraint to the query or repository method), and add/adjust unit tests to
cover LEAD/ORGANIZER access to own-team applicants and denial for other-team
applicants.
| security = { @SecurityRequirement(name = "BearerAuth") } | ||
| ) | ||
| @PreAuthorize("hasRole('ADMIN')") | ||
| @PreAuthorize("hasAnyRole('LEAD', 'ORGANIZER', 'ADMIN')") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
๐งฉ Analysis chain
๐ Script executed:
find src -name "*CoreRecruitController*" -type fRepository: GDGoCINHA/24-2_GDGoC_Server
Length of output: 153
๐ Script executed:
# Find the CoreRecruitController file
find . -name "CoreRecruitController.java" -type f 2>/dev/null | head -5
# Also search for any service methods related to applicant details
find . -name "*.java" -path "*/service/*" -type f 2>/dev/null | xargs grep -l "getApplicant" 2>/dev/null | head -10Repository: GDGoCINHA/24-2_GDGoC_Server
Length of output: 245
๐ Script executed:
# Search for CoreRecruitController and getApplicantDetail method
find . -name "*.java" -type f | xargs grep -l "getApplicantDetail" 2>/dev/null | head -5Repository: GDGoCINHA/24-2_GDGoC_Server
Length of output: 245
๐ Script executed:
# Check CoreRecruitController.java around line 92
cat -n ./src/main/java/inha/gdgoc/domain/core/recruit/controller/CoreRecruitController.java | sed -n '85,100p'Repository: GDGoCINHA/24-2_GDGoC_Server
Length of output: 784
๐ Script executed:
# Check CoreRecruitApplicationService.java for getApplicantDetail method
grep -n "getApplicantDetail" ./src/main/java/inha/gdgoc/domain/core/recruit/service/CoreRecruitApplicationService.java -A 20Repository: GDGoCINHA/24-2_GDGoC_Server
Length of output: 393
๐ Script executed:
# Also check if there's any filtering/authorization logic in the service
grep -n "teamId\|team\|authorization\|permission" ./src/main/java/inha/gdgoc/domain/core/recruit/service/CoreRecruitApplicationService.javaRepository: GDGoCINHA/24-2_GDGoC_Server
Length of output: 110
@PreAuthorize๋ง์ผ๋ก๋ ๋ถ์ถฉ๋ถํฉ๋๋ค. ์๋น์ค ๋ ์ด์ด์ ์ธ๊ฐ ๊ฒ์ฆ์ด ํ์ํฉ๋๋ค.
getApplicantDetail ๋ฉ์๋๊ฐ ID๋ก ์กฐํํ ์ง์์์ ๋ํ ์ ๊ทผ ๊ถํ์ ๊ฒ์ฆํ์ง ์์ต๋๋ค. ํ์ฌ ๊ตฌํ:
- repository.findById(id)๋ก ๋ชจ๋ ์ง์์ ์กฐํ ๊ฐ๋ฅ
- ์์ฒญ์๊ฐ ํด๋น ์ง์์์ ํ์ ์ํ๋์ง ํ์ธ ์ ํจ
- ํ ๊ธฐ๋ฐ ํํฐ๋ง ๋ก์ง ์์
LEAD๋ ORGANIZER๊ฐ ์์์ ID๋ก ๋ชจ๋ ์ง์์์ ์์ธ ์ ๋ณด๋ฅผ ์กฐํํ ์ ์๋ ์ฌ๊ฐํ ๋ณด์ ์ทจ์ฝ์ ์ ๋๋ค. ์๋น์ค ๋ ์ด์ด์์ ์์ฒญ์์ ํ๊ณผ ์ง์์ ์์ ํ์ ๋น๊ตํ์ฌ ์ ๊ทผ์ ์ ํํด์ผ ํฉ๋๋ค.
๐ค Prompt for AI Agents
In
src/main/java/inha/gdgoc/domain/core/recruit/controller/CoreRecruitController.java
around line 92, the controller uses @PreAuthorize but the service layer does not
verify that the requesting user belongs to the same team as the applicant;
update the service method that loads applicant details to perform an explicit
authorization check: fetch the applicant by id, fetch the requester (from
SecurityContextHolder or by passing principal/userId into the service), compare
their team ids (allow if same team or if requester has ADMIN role), and if not
authorized throw an AccessDeniedException (or your app's equivalent); ensure the
controller passes the principal or userId into the service and add unit tests
for same-team, admin, and forbidden cases.
| @RestController | ||
| @RequestMapping("/api/v1/admin/manito") | ||
| @RequiredArgsConstructor | ||
| public class ManitoAdminController { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
๋ณด์ ์ทจ์ฝ์ : ๊ด๋ฆฌ์ ์๋ํฌ์ธํธ์ ์ธ์ฆ/์ธ๊ฐ๊ฐ ์์ต๋๋ค.
์ด ์ปจํธ๋กค๋ฌ๋ /api/v1/admin/manito ๊ฒฝ๋ก์ ์์ผ๋ฉฐ ๊ด๋ฆฌ์ ๊ธฐ๋ฅ(์ธ์
์์ฑ, ์ฐธ๊ฐ์ ์
๋ก๋ ๋ฑ)์ ์ ๊ณตํ์ง๋ง, @PreAuthorize ์ด๋
ธํ
์ด์
์ด ์์ต๋๋ค. ๋๊ตฌ๋ ์ด ์๋ํฌ์ธํธ์ ์ ๊ทผํ ์ ์์ด ์ฌ๊ฐํ ๋ณด์ ์ทจ์ฝ์ ์
๋๋ค.
๋ค๋ฅธ ๊ด๋ฆฌ์ ์ปจํธ๋กค๋ฌ๋ค(UserAdminController, CoreAttendanceController)์ ์ ์ ํ ๊ถํ ๊ฒ์ฌ๋ฅผ ํ๊ณ ์์ต๋๋ค.
๐ ์์ ์ ์
+import org.springframework.security.access.prepost.PreAuthorize;
+
@RestController
@RequestMapping("/api/v1/admin/manito")
@RequiredArgsConstructor
+@PreAuthorize("hasAnyRole('ORGANIZER', 'ADMIN')")
public class ManitoAdminController {๐ Committable suggestion
โผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @RestController | |
| @RequestMapping("/api/v1/admin/manito") | |
| @RequiredArgsConstructor | |
| public class ManitoAdminController { | |
| import org.springframework.security.access.prepost.PreAuthorize; | |
| @RestController | |
| @RequestMapping("/api/v1/admin/manito") | |
| @RequiredArgsConstructor | |
| @PreAuthorize("hasAnyRole('ORGANIZER', 'ADMIN')") | |
| public class ManitoAdminController { |
๐ค Prompt for AI Agents
In src/main/java/inha/gdgoc/domain/manito/controller/ManitoAdminController.java
around lines 14 to 17, the controller exposing /api/v1/admin/manito lacks
authentication/authorization and must be restricted; add a class-level security
annotation (e.g., @PreAuthorize("hasRole('ADMIN')") or
@PreAuthorize("hasAuthority('ADMIN')") consistent with the project's convention)
or annotate each admin method similarly, ensure the necessary import and that
method security is enabled in the application (e.g., @EnableGlobalMethodSecurity
or equivalent), and mirror the same role/authority checks used in
UserAdminController/CoreAttendanceController so only authorized admin users can
access these endpoints.
| @PostMapping("/sessions") | ||
| public ResponseEntity<ApiResponse<ManitoSessionResponse, Void>> createSession( | ||
| @RequestBody ManitoSessionCreateRequest request | ||
| ) { | ||
| ManitoSessionResponse body = manitoAdminService.createSession(request); | ||
| return ResponseEntity.ok( | ||
| ApiResponse.ok("์ธ์ ์์ฑ ์ฑ๊ณต", body) | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
์์ฒญ ๋ณธ๋ฌธ์ @Valid ์ด๋
ธํ
์ด์
์ด ๋๋ฝ๋์์ต๋๋ค.
ManitoSessionCreateRequest์ @NotBlank ๋ฑ์ ์ ํจ์ฑ ๊ฒ์ฌ ์ด๋
ธํ
์ด์
์ด ์์ ๊ฒฝ์ฐ, @Valid ์์ด๋ ๊ฒ์ฆ์ด ์ํ๋์ง ์์ต๋๋ค.
๐ ์์ ์ ์
+import jakarta.validation.Valid;
+
@PostMapping("/sessions")
public ResponseEntity<ApiResponse<ManitoSessionResponse, Void>> createSession(
- @RequestBody ManitoSessionCreateRequest request
+ @RequestBody @Valid ManitoSessionCreateRequest request
) {๐ Committable suggestion
โผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @PostMapping("/sessions") | |
| public ResponseEntity<ApiResponse<ManitoSessionResponse, Void>> createSession( | |
| @RequestBody ManitoSessionCreateRequest request | |
| ) { | |
| ManitoSessionResponse body = manitoAdminService.createSession(request); | |
| return ResponseEntity.ok( | |
| ApiResponse.ok("์ธ์ ์์ฑ ์ฑ๊ณต", body) | |
| ); | |
| } | |
| import jakarta.validation.Valid; | |
| @PostMapping("/sessions") | |
| public ResponseEntity<ApiResponse<ManitoSessionResponse, Void>> createSession( | |
| @RequestBody @Valid ManitoSessionCreateRequest request | |
| ) { | |
| ManitoSessionResponse body = manitoAdminService.createSession(request); | |
| return ResponseEntity.ok( | |
| ApiResponse.ok("์ธ์ ์์ฑ ์ฑ๊ณต", body) | |
| ); | |
| } |
๐ค Prompt for AI Agents
In src/main/java/inha/gdgoc/domain/manito/controller/ManitoAdminController.java
around lines 29 to 37, the @RequestBody parameter is missing the @Valid
annotation so bean validation on ManitoSessionCreateRequest won't run; add the
@Valid annotation to the request parameter (e.g. public
ResponseEntity<ApiResponse<..., Void>> createSession(@Valid @RequestBody
ManitoSessionCreateRequest request)) and import the correct annotation
(jakarta.validation.Valid or javax.validation.Valid depending on project),
ensuring validation will be triggered.
| package inha.gdgoc.domain.manito.controller.message; | ||
|
|
||
| public class ManitoMessage { | ||
|
|
||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
๋น ํด๋์ค์ ๋ชฉ์ ์ ๋ช ํํ ํด์ฃผ์ธ์.
์ด ํด๋์ค๋ ๊ตฌํ ๋ด์ฉ์ด ์๋ ๋น ํด๋์ค์ ๋๋ค. ์๋์ ์ธ ํ๋ ์ด์คํ๋์ธ์ง, ์ถํ ๊ตฌํ ์์ ์ธ์ง, ์๋๋ฉด ์ค์๋ก ์ปค๋ฐ๋ ๊ฒ์ธ์ง ํ์ธ์ด ํ์ํฉ๋๋ค. ์ฌ์ฉ๋์ง ์๋ ์ฝ๋๋ ์ ๊ฑฐํ๊ฑฐ๋, ํฅํ ๊ตฌํ์ด ํ์ํ ๊ฒฝ์ฐ TODO ์ฃผ์์ ์ถ๊ฐํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค.
์ด ํด๋์ค๋ฅผ ์ถ์ ํ๊ธฐ ์ํ ์ด์๋ฅผ ์์ฑํ๊ฑฐ๋, ๊ตฌํ ์ฝ๋๋ฅผ ์์ฑํ๋ ๊ฒ์ ๋์๋๋ฆด๊น์?
๐ค Prompt for AI Agents
In src/main/java/inha/gdgoc/domain/manito/controller/message/ManitoMessage.java
lines 1-5 there is an empty class with no implementation or comment; determine
its intended purpose and act accordingly: if it is a deliberate placeholder, add
a TODO comment describing the intended responsibilities, expected fields/methods
and a link or issue number, and annotate as @SuppressWarnings("unused") only if
referenced later; if it was committed accidentally and unused, delete the file
and remove any imports/usages; if implementation is pending, implement the
required fields/methods (or add an interface/record) consistent with other
message classes and update related tests; ensure commit message documents the
decision.
| assignmentRepository.flush(); | ||
|
|
||
| ManitoAssignment reloaded = assignmentRepository.findBySessionAndStudentId(session, studentId) | ||
| .orElseThrow(); | ||
|
|
||
| log.info("[MANITO] after save: studentId='{}', enc='{}'", reloaded.getStudentId(), reloaded.getEncryptedManitto()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
๋ฃจํ ๋ด์์ flush() ํธ์ถ์ ์ฑ๋ฅ ์ ํ๋ฅผ ์ ๋ฐํฉ๋๋ค.
flush()์ ์ฌ์กฐํ๊ฐ ๊ฐ ๋ ์ฝ๋๋ง๋ค ์คํ๋์ด N+1 ๋ฌธ์ ์ ์ ์ฌํ ์ฑ๋ฅ ์ ํ๊ฐ ๋ฐ์ํฉ๋๋ค. ๋๋ฒ๊น
๋ชฉ์ ์ด๋ผ๋ฉด ์ ๊ฑฐํ๊ณ , ํ์์ ํธ๋์ญ์
์ข
๋ฃ ์ ํ ๋ฒ๋ง ์ฒ๋ฆฌ๋๋๋ก ํ์ธ์.
๐ ์์ ์ ์
assignment.changeEncryptedManitto(encryptedManitto);
-
- assignmentRepository.flush();
-
- ManitoAssignment reloaded = assignmentRepository.findBySessionAndStudentId(session, studentId)
- .orElseThrow();
-
- log.info("[MANITO] after save: studentId='{}', enc='{}'", reloaded.getStudentId(), reloaded.getEncryptedManitto());Committable suggestion skipped: line range outside the PR's diff.
๐ค Prompt for AI Agents
In src/main/java/inha/gdgoc/domain/manito/service/ManitoAdminService.java around
lines 264 to 269, the code calls assignmentRepository.flush() and then
re-queries each saved assignment inside a loop which causes per-record
flushing/reloads and significant performance degradation; remove the
per-iteration flush() and the immediate findBySessionAndStudentId(...) call,
instead rely on the managed entity state returned from the save operation (or
collect ids and perform a single bulk query after the loop) and perform a single
flush() (or let the transaction commit) after processing all records to avoid
N+1 behavior.
| try { | ||
| int asInt = Integer.parseInt(digits); | ||
| return String.format("%04d", asInt); | ||
| } catch (NumberFormatException e) { | ||
| throw new BusinessException(GlobalErrorCode.BAD_REQUEST, "PIN ํ์์ด ์ฌ๋ฐ๋ฅด์ง ์์ต๋๋ค."); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
4์๋ฆฌ๋ฅผ ์ด๊ณผํ๋ PIN ์ ๋ ฅ ์ ์์์น ๋ชปํ ๋์ ๋ฐ์ ๊ฐ๋ฅ
ํ์ฌ ๊ตฌํ์์ "12345"์ ๊ฐ์ด 4์๋ฆฌ๋ฅผ ์ด๊ณผํ๋ ์ซ์๊ฐ ์
๋ ฅ๋๋ฉด String.format("%04d", 12345)๋ "12345" (5์๋ฆฌ)๋ฅผ ๋ฐํํฉ๋๋ค. ์ด๋ 4์๋ฆฌ PIN ์ ์ฑ
๊ณผ ๋ง์ง ์์ ์ ์์ต๋๋ค.
์ต๋ ์๋ฆฟ์๋ฅผ ๊ฒ์ฆํ๊ฑฐ๋, ๋ง์ง๋ง 4์๋ฆฌ๋ง ์ฌ์ฉํ๋๋ก ์ฒ๋ฆฌ๊ฐ ํ์ํ ์ ์์ต๋๋ค.
๐ ์ ์๋ ์์ ์ฌํญ
try {
int asInt = Integer.parseInt(digits);
+ if (asInt > 9999) {
+ throw new BusinessException(GlobalErrorCode.BAD_REQUEST, "PIN์ 4์๋ฆฌ ์ดํ์ฌ์ผ ํฉ๋๋ค.");
+ }
return String.format("%04d", asInt);
} catch (NumberFormatException e) {
throw new BusinessException(GlobalErrorCode.BAD_REQUEST, "PIN ํ์์ด ์ฌ๋ฐ๋ฅด์ง ์์ต๋๋ค.");
}๐ค Prompt for AI Agents
In src/main/java/inha/gdgoc/domain/manito/service/ManitoPinPolicy.java around
lines 22 to 27, the method currently parses the input and formats it which
allows inputs longer than 4 digits (e.g., "12345") to pass through; update the
validation to explicitly reject inputs longer than 4 characters (after trimming
and ensuring non-null) by throwing BusinessException with the same BAD_REQUEST
code, or alternatively decide to keep only the last 4 digits (pick one approach
consistently); implement the chosen behavior before parsing (check
digits.length() > 4 and throw or trim to last 4), keep existing
NumberFormatException handling for non-numeric input, and ensure leading zeros
are preserved by continuing to use String.format("%04d", parsedInt) for valid
4-or-fewer digit inputs.
| public ResponseEntity<ApiResponse<Void, Void>> updateRoleTeam( | ||
| @AuthenticationPrincipal CustomUserDetails me, | ||
| @PathVariable Long userId, | ||
| @RequestBody UpdateUserRoleTeamRequest req | ||
| ) { | ||
| userAdminService.updateRoleAndTeam(me, userId, req); | ||
| return ResponseEntity.ok(ApiResponse.ok("USER_ROLE_TEAM_UPDATED")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Valid ์ด๋
ธํ
์ด์
์ด ๋๋ฝ๋์์ต๋๋ค.
updateUserRole ๋ฉ์๋(line 64)์๋ @Valid๊ฐ ์์ง๋ง, updateRoleTeam ๋ฉ์๋์ UpdateUserRoleTeamRequest์๋ ์์ต๋๋ค. ๋ ์๋ํฌ์ธํธ ๋ชจ๋ ์์ฒญ ๋ณธ๋ฌธ ์ ํจ์ฑ ๊ฒ์ฌ๊ฐ ํ์ํ ๊ฒ์ผ๋ก ๋ณด์
๋๋ค.
๐ ์์ ์ ์
public ResponseEntity<ApiResponse<Void, Void>> updateRoleTeam(
@AuthenticationPrincipal CustomUserDetails me,
@PathVariable Long userId,
- @RequestBody UpdateUserRoleTeamRequest req
+ @RequestBody @Valid UpdateUserRoleTeamRequest req
) {๐ค Prompt for AI Agents
In src/main/java/inha/gdgoc/domain/user/controller/UserAdminController.java
around lines 49 to 55, the request body parameter for updateRoleTeam is missing
the @Valid annotation so the UpdateUserRoleTeamRequest won't be validated; add
the @Valid annotation to the @RequestBody parameter (and ensure the
javax.validation.Valid import is present) so the request is validated the same
way as updateUserRole.
| "/api/v1/fileupload", | ||
| "/api/v1/manito/verify") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
๐งฉ Analysis chain
๐ Script executed:
#!/bin/bash
# TokenAuthenticationFilter ํ์ผ ์์น ์ฐพ๊ธฐ
find . -name "TokenAuthenticationFilter.java" -type f
# shouldNotFilter ๋ฉ์๋ ๋ด์ฉ ํ์ธ
rg -A 20 "shouldNotFilter" src/main/java/inha/gdgoc/global/security/TokenAuthenticationFilter.java
# manito์ fileupload ๊ฒฝ๋ก ํ์ธ
rg -n "manito|fileupload" src/main/java/inha/gdgoc/global/security/TokenAuthenticationFilter.javaRepository: GDGoCINHA/24-2_GDGoC_Server
Length of output: 1081
๐ Script executed:
#!/bin/bash
# TokenAuthenticationFilter ์ ์ฒด ํ์ผ ์ฝ๊ธฐ
cat -n src/main/java/inha/gdgoc/global/security/TokenAuthenticationFilter.javaRepository: GDGoCINHA/24-2_GDGoC_Server
Length of output: 4264
TokenAuthenticationFilter์ ์ ์๋ํฌ์ธํธ ์ถ๊ฐ ํ์
/api/v1/manito/verify์ /api/v1/fileupload ์๋ํฌ์ธํธ๊ฐ SecurityConfig์ permitAll()์๋ ์ถ๊ฐ๋์์ผ๋, TokenAuthenticationFilter์ shouldNotFilter() ๋ฉ์๋์๋ ์ถ๊ฐ๋์ง ์์์ต๋๋ค. ํ๋ก์ ํธ์ ๋ณด์ ์ํคํ
์ฒ ํจํด์ ๋ฐ๋ฅด๋ฉด ์์ชฝ ๋ชจ๋์์ ์ฒ๋ฆฌ๋์ด์ผ ํ๋ฏ๋ก, TokenAuthenticationFilter 46ํ ๋ค์์ ๋ค์์ ์ถ๊ฐํ์ธ์:
|| uri.startsWith("/api/v1/manito/verify")
|| uri.equals("/api/v1/fileupload");
ํ์ฌ ์ํ์์๋ ์ด ๊ฒฝ๋ก๋ค์ด SecurityConfig์์๋ ํ์ฉ๋์ง๋ง ํํฐ์์๋ ์ฌ์ ํ ์ธ์ฆ์ ์๋ํ๊ฒ ๋ฉ๋๋ค.
๐ค Prompt for AI Agents
In src/main/java/inha/gdgoc/global/security/SecurityConfig.java around lines
52-53, the two endpoints were added to permitAll() but not to
TokenAuthenticationFilter.shouldNotFilter; update TokenAuthenticationFilter
(after line 46) to include the additional exclusions by adding checks for
uri.startsWith("/api/v1/manito/verify") and uri.equals("/api/v1/fileupload") so
those paths are skipped by the filter (place them in the existing OR-chain in
shouldNotFilter()).
| org.hibernate.orm.jdbc.bind: trace | ||
| org.hibernate.type: trace |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ํ๋ก๋์ ํ๊ฒฝ์์ trace ๋ ๋ฒจ ๋ก๊น ์ ์ํํฉ๋๋ค.
ํ๋ก๋์ ํ๊ฒฝ์์ Hibernate ๋ก๊น ์ trace ๋ ๋ฒจ๋ก ์ค์ ํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ฌ๊ฐํ ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค:
- ์ฑ๋ฅ ์ ํ: trace ๋ก๊น ์ ๋ฐฉ๋ํ ์์ ๋ก๊ทธ๋ฅผ ์์ฑํ์ฌ CPU, I/O, ๋์คํฌ ๊ณต๊ฐ์ ๊ณผ๋ํ๊ฒ ์๋นํฉ๋๋ค.
- ๋ณด์/์ปดํ๋ผ์ด์ธ์ค ์ํ:
org.hibernate.orm.jdbc.bind: trace๋ SQL ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ์ ๋ก๊ทธ์ ๊ธฐ๋กํ๋ฏ๋ก, ์ฌ์ฉ์ ์ด๋ฉ์ผ, ๋น๋ฐ๋ฒํธ, ๊ฐ์ธ์ ๋ณด ๋ฑ ๋ฏผ๊ฐํ ๋ฐ์ดํฐ๊ฐ ๋ก๊ทธ์ ๋ ธ์ถ๋ ์ ์์ต๋๋ค. - ์ด์ ๋ฆฌ์คํฌ: ๋ก๊ทธ ๋ณผ๋ฅจ ๊ธ์ฆ์ผ๋ก ๋์คํฌ ๊ณต๊ฐ ๋ถ์กฑ, ๋ก๊ทธ ๋ถ์ ์ด๋ ค์ ๋ฑ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
ํ๋ก๋์ ํ๊ฒฝ์์๋ INFO ๋๋ WARN ๋ ๋ฒจ์ ๊ถ์ฅํ๋ฉฐ, ํ์์ DEBUG๊น์ง๋ง ์ฌ์ฉํ๋ ๊ฒ์ด ์์ ํฉ๋๋ค.
๐ ๊ถ์ฅ ์์ ์ฌํญ
์ต์ 1 (๊ถ์ฅ): ํ๋ก๋์ ์์๋ ๋ฎ์ ๋ก๊ทธ ๋ ๋ฒจ ์ฌ์ฉ
logging:
level:
org.hibernate.SQL: debug
- org.hibernate.orm.jdbc.bind: trace
- org.hibernate.type: trace
+ org.hibernate.orm.jdbc.bind: off
+ org.hibernate.type: off์ต์ 2: ์์ธ ๋ก๊น ์ด ํ์ํ ๊ฒฝ์ฐ ๊ฐ๋ฐ/์คํ ์ด์ง ํ๊ฒฝ์์๋ง ํ์ฑํ
ํ๋ก๋์
(application-prod.yml)์์๋ ์ ๊ฑฐํ๊ณ , ๊ฐ๋ฐ ํ๊ฒฝ(application-dev.yml)์์๋ง trace ๋ ๋ฒจ์ ์ฌ์ฉํ์ธ์.
๐ Committable suggestion
โผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| org.hibernate.orm.jdbc.bind: trace | |
| org.hibernate.type: trace | |
| org.hibernate.orm.jdbc.bind: off | |
| org.hibernate.type: off |
๐ค Prompt for AI Agents
src/main/resources/application-prod.yml around lines 53-54: the production
config currently sets org.hibernate.orm.jdbc.bind and org.hibernate.type to
trace which can leak sensitive data and degrade performance; change these two
entries to a safer level (e.g., INFO or WARN) or remove them entirely from
application-prod.yml and instead place trace-level settings only in
application-dev.yml/application-staging.yml; ensure no JDBC bind/parameter trace
logging remains enabled in production.
๐ ์ฐ๊ด๋ ์ด์
โจ ์์ ๋ด์ฉ
๐ฌ ๋ฆฌ๋ทฐ ์๊ตฌ์ฌํญ(์ ํ)
Summary by CodeRabbit
๋ฆด๋ฆฌ์ค ๋ ธํธ
์๋ก์ด ๊ธฐ๋ฅ
์ ๊ทผ ๊ถํ ํ๋
๋ฒ๊ทธ ์์
โ๏ธ Tip: You can customize this high-level summary in your review settings.