Skip to content

Conversation

@anxi01
Copy link
Member

@anxi01 anxi01 commented Dec 27, 2025

✅ PR 유형

어떤 변경 사항이 있었나요?

  • 새로운 기능 추가
  • 버그 수정
  • 코드에 영향을 주지 않는 변경사항(오타 수정, 탭 사이즈 변경, 변수명 변경)
  • 코드 리팩토링
  • 주석 추가 및 수정
  • 문서 수정
  • 빌드 부분 혹은 패키지 매니저 수정
  • 파일 혹은 폴더명 수정
  • 파일 혹은 폴더 삭제

🚀 작업 내용

이번 PR에서 작업한 내용을 구체적으로 설명해주세요. (이미지 첨부 가능)

  • 배너 API를 Admin에서 Banner 도메인으로 이동했습니다.
    • DTO, Controller/Service Code, Test Code를 옮겼습니다.
  • 로컬에서 배너 테스트 진행하였고, 정상 동작 확인했습니다.

📝️ 관련 이슈

본인이 작업한 내용이 어떤 Issue와 관련이 있는지 작성해주세요.


💬 기타 사항 or 추가 코멘트

남기고 싶은 말, 참고 블로그 등이 있다면 기록해주세요.

Summary by CodeRabbit

릴리스 노트

  • 새 기능

    • 배너 및 바 배너 관리 API 추가 (생성, 조회, 수정, 삭제)
    • 활성화된 배너 공개 조회 엔드포인트 추가
    • 배너 클릭 수 추적 기능 추가
  • 리팩토링

    • 배너 관리 기능을 전용 API로 재구성
    • 이미지 업로드 지원 포함

✏️ Tip: You can customize this high-level summary in your review settings.

@anxi01 anxi01 self-assigned this Dec 27, 2025
@anxi01 anxi01 requested a review from bbbang105 as a code owner December 27, 2025 13:42
@anxi01 anxi01 added 🚀 feat 새로운 기능 추가 / 일부 코드 추가 / 일부 코드 수정 (리팩토링과 구분) / 디자인 요소 수정 🔄 refactor 코드 리팩토링 😉 seongmin 성민 PR labels Dec 27, 2025
@coderabbitai
Copy link

coderabbitai bot commented Dec 27, 2025

Walkthrough

배너 관리 기능을 Admin 도메인에서 Banner 도메인으로 재구조화합니다. AdminController와 AdminService에서 배너 관련 엔드포인트와 메서드를 제거하고, BannerController와 신규 BannerService로 이동합니다. 배너 요청/응답 DTO의 패키지도 재배치됩니다.

Changes

응집도 / 파일(들) 변경 요약
AdminController 정리
src/main/java/side/onetime/controller/AdminController.java
배너/바 배너 관련 10개 엔드포인트 제거 (등록, 조회, 페이지네이션, 활성화 조회, 업데이트, 삭제). 와일드카드 임포트를 구체적 DTO 임포트로 변경. MultipartFile 관련 임포트 제거.
BannerController 확장
src/main/java/side/onetime/controller/BannerController.java
클래스 레벨 요청 매핑을 /api/v1/banners에서 /api/v1로 변경. 배너/바 배너 CRUD 관련 10개 엔드포인트 추가 (등록, 조회, 페이지네이션, 활성화 조회, 업데이트, 삭제). 클릭 수 증가 엔드포인트 경로 업데이트.
배너 요청 DTO 패키지 이동
src/main/java/side/onetime/dto/banner/request/RegisterBannerRequest.java, RegisterBarBannerRequest.java, UpdateBannerRequest.java, UpdateBarBannerRequest.java
패키지를 side.onetime.dto.admin.request에서 side.onetime.dto.banner.request로 변경.
배너 응답 DTO 패키지 이동
src/main/java/side/onetime/dto/banner/response/GetBannerResponse.java, GetBarBannerResponse.java, GetAllBannersResponse.java, GetAllBarBannersResponse.java, GetAllActivatedBannersResponse.java, GetAllActivatedBarBannersResponse.java
패키지를 side.onetime.dto.admin.response에서 side.onetime.dto.banner.response로 변경. GetAllBannersResponseGetAllBarBannersResponse에는 PageInfo 임포트 추가.
AdminService 정리
src/main/java/side/onetime/service/AdminService.java
배너 저장소, 바 배너 저장소, S3Util 필드 제거. 배너 관련 12개 메서드 제거 (CRUD, 활성화 조회, 이미지 처리). 배너 관련 임포트 제거.
신규 BannerService 추가
src/main/java/side/onetime/service/BannerService.java
배너 및 바 배너 CRUD, 페이지네이션, 활성화 조회, S3 이미지 업로드/삭제, 클릭 수 증가 기능을 포함하는 포괄적 서비스 추가. Admin 인증 검증 로직 포함.
보안 및 필터 설정
src/main/java/side/onetime/global/config/SecurityConfig.java, src/main/java/side/onetime/global/filter/JwtFilter.java
SecurityConfig에 /api/v1/bar-banners/** 공개 URL 추가. JwtFilter에 /api/v1/bar-banners 경로 제외 추가.
테스트 코드 업데이트
src/test/java/side/onetime/admin/AdminControllerTest.java
배너 관련 테스트 메서드 및 임포트 제거 (MockMultipartFile, 문서화 관련).
신규 배너 컨트롤러 테스트
src/test/java/side/onetime/banner/BannerControllerTest.java
BannerController의 배너/바 배너 엔드포인트에 대한 광범위한 단위 테스트 추가.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • bbbang105

Poem

🐰 배너들이 떠나 새로운 집을 찾았네,
Admin의 품을 떠나 Banner 영역으로,
패키지 정돈하고 엔드포인트 정렬하며,
서비스는 분리되고 책임은 명확해지고,
아름다운 구조의 재탄생! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 68.89% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 Admin 도메인에서 Banner 도메인으로 배너 API를 이동하는 주요 변경사항을 명확하게 설명하고 있습니다.
Description check ✅ Passed PR 설명은 제공된 템플릿의 필수 섹션(PR 유형, 작업 내용, 관련 이슈)을 모두 포함하고 있으며, 변경사항을 구체적으로 설명하고 있습니다.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/#308

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

🧹 Nitpick comments (2)
src/main/java/side/onetime/dto/banner/response/GetAllBarBannersResponse.java (1)

1-19: 패키지 이동이 적절하게 완료되었습니다.

side.onetime.dto.banner.response 패키지로의 이동이 잘 수행되었습니다.

PageInfoside.onetime.dto.admin.response 패키지에 남아있어 cross-package 의존성이 발생합니다. 향후 PageInfoside.onetime.dto.common 같은 공통 패키지로 이동하는 것을 고려해 볼 수 있습니다.

src/main/java/side/onetime/controller/BannerController.java (1)

21-24: @RequestMapping 경로 구조 확인 필요.

현재 클래스 레벨에서 /api/v1을 사용하고 개별 메서드에서 /banners/**, /bar-banners/**를 정의하고 있습니다. 이는 기능적으로는 문제없지만, 다른 컨트롤러들(AdminController/api/v1/admin, TokenController/api/v1/tokens)과 일관성이 부족합니다.

하나의 컨트롤러에서 두 가지 리소스 타입(banners, bar-banners)을 모두 관리하는 현재 구조가 의도된 설계라면 문제없습니다. 다만 향후 각각을 별도 컨트롤러로 분리하는 것도 고려해볼 수 있습니다.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 88a58a0 and e4371ef.

📒 Files selected for processing (18)
  • src/main/java/side/onetime/controller/AdminController.java
  • src/main/java/side/onetime/controller/BannerController.java
  • src/main/java/side/onetime/dto/banner/request/RegisterBannerRequest.java
  • src/main/java/side/onetime/dto/banner/request/RegisterBarBannerRequest.java
  • src/main/java/side/onetime/dto/banner/request/UpdateBannerRequest.java
  • src/main/java/side/onetime/dto/banner/request/UpdateBarBannerRequest.java
  • src/main/java/side/onetime/dto/banner/response/GetAllActivatedBannersResponse.java
  • src/main/java/side/onetime/dto/banner/response/GetAllActivatedBarBannersResponse.java
  • src/main/java/side/onetime/dto/banner/response/GetAllBannersResponse.java
  • src/main/java/side/onetime/dto/banner/response/GetAllBarBannersResponse.java
  • src/main/java/side/onetime/dto/banner/response/GetBannerResponse.java
  • src/main/java/side/onetime/dto/banner/response/GetBarBannerResponse.java
  • src/main/java/side/onetime/global/config/SecurityConfig.java
  • src/main/java/side/onetime/global/filter/JwtFilter.java
  • src/main/java/side/onetime/service/AdminService.java
  • src/main/java/side/onetime/service/BannerService.java
  • src/test/java/side/onetime/admin/AdminControllerTest.java
  • src/test/java/side/onetime/banner/BannerControllerTest.java
🧰 Additional context used
📓 Path-based instructions (7)
src/main/java/**/dto/**/*.java

📄 CodeRabbit inference engine (CLAUDE.md)

src/main/java/**/dto/**/*.java: Create DTOs organized by feature in dto directory with request and response subdirectories
Use toEntity() methods and static factory of() methods for DTO to entity conversion

Files:

  • src/main/java/side/onetime/dto/banner/response/GetAllBannersResponse.java
  • src/main/java/side/onetime/dto/banner/request/UpdateBarBannerRequest.java
  • src/main/java/side/onetime/dto/banner/response/GetBannerResponse.java
  • src/main/java/side/onetime/dto/banner/request/RegisterBarBannerRequest.java
  • src/main/java/side/onetime/dto/banner/response/GetBarBannerResponse.java
  • src/main/java/side/onetime/dto/banner/response/GetAllActivatedBarBannersResponse.java
  • src/main/java/side/onetime/dto/banner/response/GetAllBarBannersResponse.java
  • src/main/java/side/onetime/dto/banner/request/UpdateBannerRequest.java
  • src/main/java/side/onetime/dto/banner/response/GetAllActivatedBannersResponse.java
  • src/main/java/side/onetime/dto/banner/request/RegisterBannerRequest.java
src/main/java/**/dto/**/response/*Response.java

📄 CodeRabbit inference engine (CLAUDE.md)

Use *Response suffixes for DTO class naming

Files:

  • src/main/java/side/onetime/dto/banner/response/GetAllBannersResponse.java
  • src/main/java/side/onetime/dto/banner/response/GetBannerResponse.java
  • src/main/java/side/onetime/dto/banner/response/GetBarBannerResponse.java
  • src/main/java/side/onetime/dto/banner/response/GetAllActivatedBarBannersResponse.java
  • src/main/java/side/onetime/dto/banner/response/GetAllBarBannersResponse.java
  • src/main/java/side/onetime/dto/banner/response/GetAllActivatedBannersResponse.java
src/test/java/**/*Test.java

📄 CodeRabbit inference engine (CLAUDE.md)

src/test/java/**/*Test.java: Use Spring REST Docs and SpringDoc OpenAPI for API documentation generation
Use JUnit 5 with Spring Boot Test for unit and integration testing

Files:

  • src/test/java/side/onetime/banner/BannerControllerTest.java
  • src/test/java/side/onetime/admin/AdminControllerTest.java
src/main/java/**/dto/**/request/*Request.java

📄 CodeRabbit inference engine (CLAUDE.md)

Use *Request and *Response suffixes for DTO class naming

Files:

  • src/main/java/side/onetime/dto/banner/request/UpdateBarBannerRequest.java
  • src/main/java/side/onetime/dto/banner/request/RegisterBarBannerRequest.java
  • src/main/java/side/onetime/dto/banner/request/UpdateBannerRequest.java
  • src/main/java/side/onetime/dto/banner/request/RegisterBannerRequest.java
src/main/java/**/service/*Service.java

📄 CodeRabbit inference engine (CLAUDE.md)

src/main/java/**/service/*Service.java: Use @service annotation for business logic layer classes
Use @distributedlock annotation for race condition prevention in service methods
Use @transactional annotation for transaction management

Files:

  • src/main/java/side/onetime/service/BannerService.java
  • src/main/java/side/onetime/service/AdminService.java
src/main/java/**/{controller,service}/*.java

📄 CodeRabbit inference engine (CLAUDE.md)

Use constructor injection with @requiredargsconstructor for dependency injection

Files:

  • src/main/java/side/onetime/service/BannerService.java
  • src/main/java/side/onetime/service/AdminService.java
  • src/main/java/side/onetime/controller/BannerController.java
  • src/main/java/side/onetime/controller/AdminController.java
src/main/java/**/controller/*Controller.java

📄 CodeRabbit inference engine (CLAUDE.md)

src/main/java/**/controller/*Controller.java: Use @RestController annotation for REST API endpoints
Use generic response wrapper ApiResponse with onSuccess() and onFailure() methods for all API responses
Use RESTful API endpoints with /api/v1/ prefix

Files:

  • src/main/java/side/onetime/controller/BannerController.java
  • src/main/java/side/onetime/controller/AdminController.java
🧠 Learnings (12)
📓 Common learnings
Learnt from: anxi01
Repo: onetime-with-members/backend PR: 269
File: src/main/java/side/onetime/dto/admin/response/GetBannerResponse.java:12-16
Timestamp: 2025-08-30T09:03:01.457Z
Learning: BarBanner와 Banner는 완전히 별개의 엔티티입니다. Banner는 organization, title, subTitle, colorCode, imageUrl 필드를 사용하고, BarBanner는 contentKor, contentEng, backgroundColorCode, textColorCode 필드를 사용합니다. 각각 다른 목적과 스키마를 가진 독립적인 엔티티로 설계되었습니다.
Learnt from: bbbang105
Repo: onetime-with-members/backend PR: 269
File: src/main/java/side/onetime/util/S3Util.java:63-73
Timestamp: 2025-08-29T11:40:58.895Z
Learning: 배너 이미지 저장 시 /banner/{banner_id}/ 경로 구조를 사용하여 파일을 더 체계적으로 관리하는 것을 선호합니다.
📚 Learning: 2025-12-21T11:41:05.367Z
Learnt from: CR
Repo: onetime-with-members/backend PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-21T11:41:05.367Z
Learning: Applies to src/test/java/**/controller/*ControllerTest.java : Use MockMvc for controller integration tests

Applied to files:

  • src/test/java/side/onetime/banner/BannerControllerTest.java
  • src/test/java/side/onetime/admin/AdminControllerTest.java
📚 Learning: 2025-12-21T11:41:05.367Z
Learnt from: CR
Repo: onetime-with-members/backend PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-21T11:41:05.367Z
Learning: Applies to src/test/java/**/*Test.java : Use Spring REST Docs and SpringDoc OpenAPI for API documentation generation

Applied to files:

  • src/test/java/side/onetime/banner/BannerControllerTest.java
  • src/test/java/side/onetime/admin/AdminControllerTest.java
📚 Learning: 2025-08-29T11:40:00.748Z
Learnt from: bbbang105
Repo: onetime-with-members/backend PR: 269
File: src/main/java/side/onetime/domain/BarBanner.java:76-78
Timestamp: 2025-08-29T11:40:00.748Z
Learning: BarBanner와 Banner 엔티티에서 소프트 삭제(markAsDeleted) 시에는 isDeleted=true와 함께 isActivated=false도 설정해야 합니다. 이는 삭제된 레코드가 복구될 때 의도치 않게 활성 상태로 남는 것을 방지하기 위함입니다.

Applied to files:

  • src/test/java/side/onetime/banner/BannerControllerTest.java
  • src/test/java/side/onetime/admin/AdminControllerTest.java
📚 Learning: 2025-12-21T11:41:05.367Z
Learnt from: CR
Repo: onetime-with-members/backend PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-21T11:41:05.367Z
Learning: Applies to src/main/java/**/dto/**/request/*Request.java : Use *Request and *Response suffixes for DTO class naming

Applied to files:

  • src/main/java/side/onetime/dto/banner/request/UpdateBarBannerRequest.java
  • src/main/java/side/onetime/dto/banner/response/GetBannerResponse.java
  • src/main/java/side/onetime/dto/banner/request/RegisterBarBannerRequest.java
  • src/main/java/side/onetime/dto/banner/response/GetBarBannerResponse.java
  • src/main/java/side/onetime/dto/banner/response/GetAllActivatedBarBannersResponse.java
  • src/main/java/side/onetime/dto/banner/response/GetAllActivatedBannersResponse.java
  • src/main/java/side/onetime/dto/banner/request/RegisterBannerRequest.java
📚 Learning: 2025-12-21T11:41:05.367Z
Learnt from: CR
Repo: onetime-with-members/backend PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-21T11:41:05.367Z
Learning: Applies to src/main/java/**/dto/**/response/*Response.java : Use *Response suffixes for DTO class naming

Applied to files:

  • src/main/java/side/onetime/dto/banner/response/GetBannerResponse.java
  • src/main/java/side/onetime/dto/banner/response/GetBarBannerResponse.java
  • src/main/java/side/onetime/dto/banner/response/GetAllActivatedBarBannersResponse.java
  • src/main/java/side/onetime/dto/banner/response/GetAllActivatedBannersResponse.java
📚 Learning: 2025-08-29T11:40:58.895Z
Learnt from: bbbang105
Repo: onetime-with-members/backend PR: 269
File: src/main/java/side/onetime/util/S3Util.java:63-73
Timestamp: 2025-08-29T11:40:58.895Z
Learning: 배너 이미지 저장 시 /banner/{banner_id}/ 경로 구조를 사용하여 파일을 더 체계적으로 관리하는 것을 선호합니다.

Applied to files:

  • src/main/java/side/onetime/service/BannerService.java
  • src/main/java/side/onetime/controller/BannerController.java
📚 Learning: 2025-08-29T11:40:12.488Z
Learnt from: bbbang105
Repo: onetime-with-members/backend PR: 269
File: src/main/java/side/onetime/service/AdminService.java:280-288
Timestamp: 2025-08-29T11:40:12.488Z
Learning: 배너 등록/수정 시 S3 업로드와 DB 저장 순서는 DB 저장 먼저 → S3 업로드 → 실패 시 exception으로 롤백하는 방식이 더 간단하고 효과적임. TransactionSynchronization보다는 Transactional의 자동 롤백 메커니즘을 활용하는 것이 권장됨.

Applied to files:

  • src/main/java/side/onetime/service/BannerService.java
  • src/main/java/side/onetime/service/AdminService.java
📚 Learning: 2025-12-21T11:41:05.367Z
Learnt from: CR
Repo: onetime-with-members/backend PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-21T11:41:05.367Z
Learning: Applies to src/main/java/**/auth/*.java : Use Spring Security, OAuth2 (Google, Kakao, Naver), and JWT (JJWT) for authentication and authorization

Applied to files:

  • src/main/java/side/onetime/global/filter/JwtFilter.java
📚 Learning: 2025-12-21T11:41:05.367Z
Learnt from: CR
Repo: onetime-with-members/backend PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-21T11:41:05.367Z
Learning: Applies to src/main/java/**/controller/*Controller.java : Use RESTful API endpoints with /api/v1/ prefix

Applied to files:

  • src/main/java/side/onetime/controller/BannerController.java
  • src/main/java/side/onetime/controller/AdminController.java
📚 Learning: 2025-12-21T11:41:05.367Z
Learnt from: CR
Repo: onetime-with-members/backend PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-21T11:41:05.367Z
Learning: Applies to src/main/java/**/controller/*Controller.java : Use RestController annotation for REST API endpoints

Applied to files:

  • src/main/java/side/onetime/controller/BannerController.java
  • src/main/java/side/onetime/controller/AdminController.java
📚 Learning: 2025-12-21T11:41:05.367Z
Learnt from: CR
Repo: onetime-with-members/backend PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-21T11:41:05.367Z
Learning: Applies to src/test/java/**/*Test.java : Use JUnit 5 with Spring Boot Test for unit and integration testing

Applied to files:

  • src/test/java/side/onetime/admin/AdminControllerTest.java
🧬 Code graph analysis (4)
src/main/java/side/onetime/dto/banner/response/GetAllBannersResponse.java (2)
src/main/java/side/onetime/dto/admin/response/GetAllBannersResponse.java (2)
  • JsonNaming (8-19)
  • of (13-18)
src/main/java/side/onetime/dto/admin/response/GetAllBarBannersResponse.java (2)
  • JsonNaming (8-19)
  • of (13-18)
src/test/java/side/onetime/banner/BannerControllerTest.java (1)
src/test/java/side/onetime/admin/AdminControllerTest.java (1)
  • WebMvcTest (38-484)
src/main/java/side/onetime/global/config/SecurityConfig.java (1)
src/main/java/side/onetime/domain/BarBanner.java (1)
  • updateLinkUrl (72-74)
src/main/java/side/onetime/controller/BannerController.java (2)
src/main/java/side/onetime/global/config/SecurityConfig.java (1)
  • RequiredArgsConstructor (22-122)
src/main/java/side/onetime/controller/TokenController.java (1)
  • RestController (16-36)
⏰ 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). (1)
  • GitHub Check: Build and Push to ECR
🔇 Additional comments (27)
src/main/java/side/onetime/dto/banner/request/RegisterBannerRequest.java (1)

1-1: 패키지 이동이 올바르게 수행되었습니다.

Admin 도메인에서 Banner 도메인으로 DTO가 깔끔하게 이동되었습니다. 코딩 가이드라인을 준수하고 있습니다.

src/main/java/side/onetime/dto/banner/request/UpdateBannerRequest.java (1)

1-1: 패키지 이동이 올바르게 수행되었습니다.

DTO가 Banner 도메인으로 적절히 재배치되었습니다.

src/main/java/side/onetime/dto/banner/request/UpdateBarBannerRequest.java (1)

1-1: 패키지 이동이 올바르게 수행되었습니다.

BarBanner DTO가 Banner 도메인으로 적절히 이동되었습니다.

src/main/java/side/onetime/dto/banner/response/GetAllActivatedBarBannersResponse.java (1)

1-1: 패키지 이동이 올바르게 수행되었습니다.

Response DTO가 Banner 도메인으로 적절히 재배치되었으며, 코딩 가이드라인을 준수하고 있습니다.

src/main/java/side/onetime/dto/banner/response/GetBannerResponse.java (1)

1-1: 패키지 이동이 올바르게 수행되었습니다.

Response DTO가 Banner 도메인으로 적절히 이동되었으며, static factory 메서드를 포함하고 있습니다.

src/main/java/side/onetime/global/filter/JwtFilter.java (1)

104-104: BarBanner 경로의 JWT 필터 제외를 확인해주세요.

/api/v1/bar-banners 경로가 JWT 필터에서 제외되어 인증 검증을 우회하게 되었습니다. 이는 SecurityConfig의 변경사항과 일관되지만, BarBanner 엔드포인트가 실제로 인증 없이 접근 가능해야 하는지 확인이 필요합니다.

src/main/java/side/onetime/dto/banner/response/GetBarBannerResponse.java (1)

1-1: 패키지 이동이 올바르게 수행되었습니다.

GetBarBannerResponse가 Banner 도메인으로 적절히 이동되었으며, static factory 메서드를 포함하고 있습니다.

src/main/java/side/onetime/dto/banner/response/GetAllActivatedBannersResponse.java (1)

1-15: 패키지 이동이 적절하게 완료되었습니다.

side.onetime.dto.admin.response에서 side.onetime.dto.banner.response로의 패키지 이동이 PR 목표에 맞게 잘 수행되었습니다. 코딩 가이드라인에 따른 *Response 네이밍 규칙과 static factory method 패턴도 잘 유지되어 있습니다.

src/main/java/side/onetime/dto/banner/request/RegisterBarBannerRequest.java (1)

1-41: 패키지 이동 및 DTO 구현이 적절합니다.

side.onetime.dto.banner.request 패키지로의 이동이 잘 수행되었습니다. 코딩 가이드라인에 따른 *Request 네이밍 규칙, toEntity() 메서드, 그리고 적절한 validation 어노테이션이 잘 적용되어 있습니다.

src/test/java/side/onetime/banner/BannerControllerTest.java (5)

41-52: 테스트 클래스 구성이 적절합니다.

@WebMvcTest@MockBean을 사용한 컨트롤러 테스트 구성이 코딩 가이드라인에 맞게 잘 설정되어 있습니다. BannerService, JwtUtil, CustomUserDetailsService에 대한 목 의존성이 적절하게 주입되었습니다.


53-96: 배너 등록 테스트가 적절하게 구현되었습니다.

Multipart 요청을 사용한 배너 등록 테스트가 잘 작성되어 있습니다. MockMultipartFile을 통한 JSON request와 이미지 파일 처리가 적절합니다.


98-148: 띠배너 등록 테스트가 적절하게 구현되었습니다.

JSON 요청 처리, request/response 필드 문서화, 스키마 참조가 잘 작성되어 있습니다.


393-488: 활성화된 배너/띠배너 조회 테스트가 적절합니다.

공개 엔드포인트에 대한 테스트로서 Authorization 헤더 없이 요청하는 것이 적절합니다. 이는 SecurityConfig와 JwtFilter의 공개 접근 설정과 일치합니다.


666-699: 배너 클릭 수 증가 테스트가 적절합니다.

path parameter 문서화와 응답 필드 검증이 잘 작성되어 있습니다.

src/main/java/side/onetime/dto/banner/response/GetAllBannersResponse.java (1)

1-20: 패키지 이동이 적절하게 완료되었습니다.

side.onetime.dto.banner.response 패키지로의 이동이 PR 목표에 맞게 잘 수행되었습니다.

src/test/java/side/onetime/admin/AdminControllerTest.java (2)

21-24: import 정리가 적절하게 수행되었습니다.

배너 관련 기능이 BannerController로 이동함에 따라 import가 특정 admin request DTO로 정리되었습니다. 관심사 분리가 잘 이루어졌습니다.


38-483: AdminControllerTest가 적절하게 리팩토링되었습니다.

배너 관련 테스트가 BannerControllerTest로 이동되어, 이 테스트 클래스는 이제 관리자 계정 관리(회원가입, 로그인, 프로필 조회, 권한 수정, 탈퇴)와 대시보드 기능에만 집중합니다. 도메인 분리가 잘 반영되었습니다.

src/main/java/side/onetime/service/BannerService.java (5)

26-34: 서비스 클래스 구성이 코딩 가이드라인에 맞게 잘 설정되었습니다.

@Service, @RequiredArgsConstructor를 통한 생성자 주입, @Slf4j 로깅이 적절하게 적용되었습니다.


46-53: 배너 등록 로직이 적절하게 구현되었습니다.

DB 저장 후 S3 업로드 순서가 권장 패턴에 맞게 구현되었습니다. 업로드 실패 시 트랜잭션 롤백을 활용할 수 있습니다. Based on learnings, DB 저장 먼저 → S3 업로드 → 실패 시 롤백 방식이 적용되었습니다.


173-195: 활성화된 배너 조회 메서드가 공개 엔드포인트로 적절하게 구현되었습니다.

getAllActivatedBanners()getAllActivatedBarBanners()에서 인증 검증(jwtUtil.getAdminUserFromHeader)을 수행하지 않는 것이 올바릅니다. 이는 SecurityConfig의 공개 접근 설정과 일치합니다.


312-319: 배너 이미지 업로드 경로가 적절합니다.

/banner/{banner_id}/ 경로 구조를 사용하여 파일을 체계적으로 관리하고 있습니다. Based on learnings, 이 경로 구조가 권장됩니다.


263-289: 소프트 삭제 구현이 올바르게 되어 있습니다.

Banner와 BarBanner의 markAsDeleted() 메서드를 확인한 결과, 두 엔티티 모두 소프트 삭제 시 isDeleted=true와 함께 isActivated=false를 정확히 설정하고 있습니다. 따라서 삭제된 레코드가 복구될 때 의도치 않게 활성 상태로 남는 것이 방지되어 있습니다.

Likely an incorrect or invalid review comment.

src/main/java/side/onetime/service/AdminService.java (2)

11-13: import 정리가 적절하게 수행되었습니다.

배너 관련 DTO import가 제거되고 관리자 관련 request DTO만 명시적으로 import되었습니다.


28-36: AdminService의 의존성이 적절하게 정리되었습니다.

BannerRepository, BarBannerRepository, S3Util 의존성이 제거되어 AdminService가 관리자 계정 관리와 대시보드 기능에만 집중합니다. 단일 책임 원칙(SRP)에 더 부합하는 구조가 되었습니다.

src/main/java/side/onetime/controller/AdminController.java (1)

10-12: 배너 관련 임포트 제거 및 구체적 임포트 사용 확인.

배너 API가 Banner 도메인으로 이동됨에 따라 관련 임포트가 제거되었고, 와일드카드 대신 구체적인 admin request DTO들을 임포트하도록 변경되었습니다. 이는 더 명확한 의존성 관리를 위한 좋은 개선입니다.

src/main/java/side/onetime/controller/BannerController.java (2)

242-254: 배너 클릭 수 증가 API 구현 확인.

인증 없이 접근 가능한 공개 API로 올바르게 설계되었습니다. 사용자가 배너를 클릭할 때 인증 없이 클릭 수를 증가시킬 수 있어야 하므로 적절한 구현입니다.


28-240: JWT 필터 우회로 인한 관리자 API 인증 부재.

JwtFiltershouldNotFilter() 메서드에서 /api/v1/banners, /api/v1/bar-banners로 시작하는 모든 경로가 JWT 검증을 건너뜁니다(줄 95-96). 동시에 SecurityConfigPUBLIC_URLS도 이들 패턴을 포함합니다(줄 43-44). 결과적으로 배너 등록, 수정, 삭제와 같은 관리자 전용 API가 인증 없이 접근 가능합니다.

메서드의 @RequestHeader("Authorization") 파라미터는 단순 값 캡처일 뿐, Spring Security의 실제 인증 강제를 제공하지 않습니다.

필수 수정 사항:

  • JwtFilter.shouldNotFilter()에서 /api/v1/banners, /api/v1/bar-banners 제거
  • SecurityConfig.PUBLIC_URLS에서도 동일하게 제거
  • 공개 조회 엔드포인트(/api/v1/banners/activated/all, /api/v1/bar-banners/activated/all)만 명시적으로 PUBLIC_URLS에 포함
  • 나머지 배너 API(register, all, {id}, update, delete)는 JWT 인증 필수
⛔ Skipped due to learnings
Learnt from: CR
Repo: onetime-with-members/backend PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-21T11:41:05.367Z
Learning: Applies to src/main/java/**/auth/*.java : Use Spring Security, OAuth2 (Google, Kakao, Naver), and JWT (JJWT) for authentication and authorization
Learnt from: bbbang105
Repo: onetime-with-members/backend PR: 269
File: src/main/java/side/onetime/util/S3Util.java:63-73
Timestamp: 2025-08-29T11:40:58.895Z
Learning: 배너 이미지 저장 시 /banner/{banner_id}/ 경로 구조를 사용하여 파일을 더 체계적으로 관리하는 것을 선호합니다.

"/api/v1/tokens/**",
"/api/v1/admin/**",
"/api/v1/banners/**",
"/api/v1/bar-banners/**",
Copy link

@coderabbitai coderabbitai bot Dec 27, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, let's look at the SecurityConfig.java file to understand the context
cat -n src/main/java/side/onetime/global/config/SecurityConfig.java | head -60

Repository: onetime-with-members/backend

Length of output: 2571


🏁 Script executed:

# Search for BarBanner controller endpoints
rg -n "BarBanner|bar-banner" --type java -i | head -30

Repository: onetime-with-members/backend

Length of output: 4153


🏁 Script executed:

# Look for the controller class with GetMapping
rg -n "@GetMapping.*BarBanner|BarBannerController" --type java -A 3

Repository: onetime-with-members/backend

Length of output: 54


🏁 Script executed:

# Check for BannerService or similar service classes
rg -n "class.*BannerService|BarBannerService" --type java -A 10

Repository: onetime-with-members/backend

Length of output: 972


🏁 Script executed:

# Look at the entire PUBLIC_URLS section to understand the pattern
rg -n "PUBLIC_URLS|getPublicUrls" --type java -B 3 -A 15

Repository: onetime-with-members/backend

Length of output: 3283


🏁 Script executed:

# Find the controller class that handles bar-banners endpoints
rg -n "BarBanner.*Controller|bar-banner.*Controller" --type java -B 2 -A 15

Repository: onetime-with-members/backend

Length of output: 54


🏁 Script executed:

# Alternative search for the controller
rg -n "@RestController.*Banner|@RequestMapping.*banner" --type java -B 2 -A 20

Repository: onetime-with-members/backend

Length of output: 54


🏁 Script executed:

# Search for any controller that maps to /api/v1/bar-banners
rg -n "bar-banner" --type java -B 5 -A 5

Repository: onetime-with-members/backend

Length of output: 22353


🏁 Script executed:

# Let me verify the controller class declaration and mapping
head -30 src/main/java/side/onetime/controller/BannerController.java

Repository: onetime-with-members/backend

Length of output: 1140


BarBanner 엔드포인트에 대한 과도한 공개 접근 설정 - 심각한 보안 취약점

/api/v1/bar-banners/** 와일드카드는 인증이 필요한 모든 CRUD 작업을 공개적으로 노출합니다:

  • POST /bar-banners/register - 누구나 배너 생성 가능 (인증 필수 엔드포인트)
  • PATCH /bar-banners/{id} - 누구나 배너 수정 가능 (인증 필수 엔드포인트)
  • DELETE /bar-banners/{id} - 누구나 배너 삭제 가능 (인증 필수 엔드포인트)
  • GET /bar-banners/all - 누구나 페이지네이션된 전체 배너 조회 가능, 미발행 배너 포함 (인증 필수 엔드포인트)
  • GET /bar-banners/{id} - 누구나 특정 배너 조회 가능 (인증 필수 엔드포인트)

오직 GET /bar-banners/activated/all 엔드포인트만 공개하도록 제한해야 합니다. PUBLIC_URLS의 /api/v1/bar-banners/** 엔트리를 제거하고 /api/v1/bar-banners/activated/all 경로만 명시적으로 공개 접근을 허용하도록 변경하세요.

🤖 Prompt for AI Agents
In src/main/java/side/onetime/global/config/SecurityConfig.java around line 44,
the PUBLIC_URLS entry "/api/v1/bar-banners/**" overly exposes all BarBanner CRUD
endpoints; remove that wildcard from PUBLIC_URLS and instead add only
"/api/v1/bar-banners/activated/all" as an explicitly permitted (anonymous)
endpoint, ensuring all other /api/v1/bar-banners/** routes remain protected by
authentication/authorization rules (adjust any antMatchers/authorizeRequests
ordering if necessary so the specific public path is checked before secured
patterns).

Copy link
Member Author

Choose a reason for hiding this comment

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

인증 필수인 API는 어드민 토큰으로 앞단에서 검증함

Copy link

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
# Check BannerService implementation for admin authentication validation
echo "=== BannerService admin authentication checks ==="
ast-grep --pattern 'verifyAdminUser($$$)' src/main/java/side/onetime/service/BannerService.java

echo -e "\n=== BannerService registerBarBanner method ==="
ast-grep --pattern $'registerBarBanner($$$) {
  $$$
}'

echo -e "\n=== Check for admin verification in BannerService ==="
rg -n "verifyAdmin|checkAdmin|validateAdmin" src/main/java/side/onetime/service/BannerService.java -A 2 -B 2

Length of output: 152


🏁 Script executed:

#!/bin/bash
# Check JwtFilter shouldNotFilter implementation
echo "=== JwtFilter shouldNotFilter method ==="
ast-grep --pattern $'shouldNotFilter($$$) {
  $$$
}'

echo -e "\n=== JwtFilter complete implementation ==="
cat src/main/java/side/onetime/global/filter/JwtFilter.java

Length of output: 6402


🏁 Script executed:

#!/bin/bash
# Check BannerController getAllActivatedBarBanners endpoint
echo "=== BannerController getAllActivatedBarBanners ==="
ast-grep --pattern $'getAllActivatedBarBanners($$$) {
  $$$
}'

echo -e "\n=== Check which bar-banner endpoints have Authorization header ==="
rg -n "@.*Mapping.*bar-banner" src/main/java/side/onetime/controller/BannerController.java -A 5 -B 2

Length of output: 2573


🏁 Script executed:

#!/bin/bash
# Get complete BannerService implementation to check admin verification
echo "=== BannerService complete implementation ==="
cat src/main/java/side/onetime/service/BannerService.java

Length of output: 12028


🏁 Script executed:

#!/bin/bash
# Search for admin verification utility methods in JwtUtil
echo "=== JwtUtil admin verification methods ==="
rg -n "verifyAdmin|checkAdmin|AdminUser" src/main/java/side/onetime/util/JwtUtil.java -A 3 -B 1

Length of output: 479


@anxi01

프론트엔드 검증은 보안 메커니즘이 아니며, curl이나 Postman 등으로 쉽게 우회할 수 있습니다.

현재 구현을 확인한 결과:

현재 상태:

  1. JwtFiltershouldNotFilter에서 /api/v1/bar-banners 경로를 JWT 검증에서 완전히 제외
  2. SecurityConfigPUBLIC_URLS/api/v1/bar-banners/** 추가로 Spring Security 인증 완전히 우회
  3. BannerService는 admin 메서드에서 jwtUtil.getAdminUserFromHeader()를 호출하여 토큰 검증 수행

문제점:

보안 계층(JwtFilter, SecurityConfig)이 완전히 우회되고, 서비스 계층에서만 예외를 던지는 방식은 올바른 보안 아키텍처가 아닙니다:

# 인증 없이 admin API 호출 가능 (서비스에서 예외 발생)
curl -X POST https://api.example.com/api/v1/bar-banners/register \
  -H "Content-Type: application/json" \
  -d '{"title":"test"}'

올바른 보안 계층 구조:

  1. Filter Layer (JwtFilter): JWT 토큰 검증 및 인증 정보 설정
  2. Security Layer (SecurityConfig): 경로별 접근 권한 제어
  3. Service Layer (BannerService): 비즈니스 로직 및 역할 기반 인가 (defense-in-depth)

권장 수정사항:

  1. JwtFilter.shouldNotFilter()에서 /api/v1/bar-banners 제거하거나, 특정 경로만 제외:
// 활성화된 띠배너 조회만 JWT 필터 제외
(isGet && path.equals("/api/v1/bar-banners/activated/all"))
  1. SecurityConfig.PUBLIC_URLS에서 와일드카드 제거하고 공개 엔드포인트만 명시:
private static final String[] PUBLIC_URLS = {
    // ... 기존 항목들
    "/api/v1/banners/activated/all",
    "/api/v1/bar-banners/activated/all",  // 공개 엔드포인트만 허용
    // "/api/v1/bar-banners/**",  // 제거

이렇게 하면:

  • GET /bar-banners/activated/all: 공개 접근 (의도된 동작)
  • ✅ 나머지 admin 엔드포인트들: JwtFilter에서 토큰 검증 → SecurityConfig에서 인증 확인 → Service에서 admin 역할 확인 (다층 방어)

현재 방식은 보안 계층을 우회하고 서비스 레이어에서만 검증하기 때문에, 보안 아키텍처 관점에서 개선이 필요합니다.


🧠 Learnings used
Learnt from: CR
Repo: onetime-with-members/backend PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-21T11:41:05.367Z
Learning: Applies to src/main/java/**/auth/*.java : Use Spring Security, OAuth2 (Google, Kakao, Naver), and JWT (JJWT) for authentication and authorization

Learnt from: CR
Repo: onetime-with-members/backend PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-21T11:41:05.367Z
Learning: Applies to src/main/java/**/controller/*Controller.java : Use RESTful API endpoints with /api/v1/ prefix

Copy link
Member Author

Choose a reason for hiding this comment

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

JwtFilter에서는 토큰에서 userId를 읽어와서 SecurityContext에 User를 적용하고 있어
그래서 사용자가 사용하지 않거나 인증이 필요하지 않은 API (어드민, 배너)는 JwtFilter를 생략해야해

SecurityConfig에서 PUBLIC_URLS, AUTHENTICATED_URLS는 확인이 필요할 거 같네

Copy link

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
# Check which Banner and BarBanner endpoints should be public vs admin-only
echo "=== BannerController endpoints and their authorization requirements ==="
rg -n "@.*Mapping" src/main/java/side/onetime/controller/BannerController.java -A 8 -B 2 | head -120

echo -e "\n=== AdminController endpoints ==="
rg -n "@.*Mapping" src/main/java/side/onetime/controller/AdminController.java -A 5 -B 2 | head -60

Length of output: 7672


@anxi01

이해했습니다! JwtFilter가 userId를 추출해서 User를 SecurityContext에 설정하는 용도라면, 어드민/배너 API는 JwtFilter를 건너뛰는 게 맞습니다.

현재 SecurityConfig를 확인한 결과, PUBLIC_URLS의 와일드카드 설정이 과도하게 넓습니다:

🔍 현재 문제점

private static final String[] PUBLIC_URLS = {
    "/api/v1/admin/**",        // ⚠️ 모든 어드민 API가 permitAll
    "/api/v1/banners/**",      // ⚠️ 모든 배너 API가 permitAll  
    "/api/v1/bar-banners/**",  // ⚠️ 모든 띠배너 API가 permitAll
    // ...
};

이 설정은 Spring Security 관점에서 모든 하위 경로를 인증 없이 접근 가능하게 만듭니다:

  • /admin/register, /admin/login (의도: 공개)
  • /admin/profile, /admin/all (의도: 어드민 토큰 필요) → 하지만 permitAll 적용됨
  • /banners/activated/all (의도: 공개)
  • /banners/register, /banners/{id} (의도: 어드민 토큰 필요) → 하지만 permitAll 적용됨

서비스 레이어에서 어드민 토큰 검증을 하고 있어서 동작은 하지만, Spring Security 설정과 실제 보안 로직이 불일치합니다.

✅ 권장 수정안

코드 조회 결과, 실제로 공개 접근이 필요한 엔드포인트만 명시하세요:

private static final String[] PUBLIC_URLS = {
    "/login/**",
    "/api/v1/events/**",
    "/api/v1/schedules/**",
    "/api/v1/members/**",
    "/api/v1/urls/**",
    "/api/v1/tokens/**",
    // 어드민 - 공개 엔드포인트만
    "/api/v1/admin/register",
    "/api/v1/admin/login",
    // 배너 - 공개 엔드포인트만
    "/api/v1/banners/activated/all",
    "/api/v1/banners/*/clicks",
    "/api/v1/bar-banners/activated/all",
    "/api/v1/users/onboarding",
    "/api/v1/users/logout",
    "/actuator/health"
};

어드민 토큰이 필요한 엔드포인트는 PUBLIC_URLS에서 제거하고, 대신 아래 중 하나를 선택하세요:

옵션 1: 현재 구조 유지 (간단)

어드민 토큰이 필요한 API들을 별도 패턴으로 추가:

private static final String[] ADMIN_URLS = {
    "/api/v1/admin/profile",
    "/api/v1/admin/all",
    "/api/v1/admin/status",
    "/api/v1/admin/withdraw",
    "/api/v1/banners/**",  // activated/all과 clicks 제외한 나머지
    "/api/v1/bar-banners/**"  // activated/all 제외한 나머지
};

// SecurityFilterChain에서
.authorizeHttpRequests(authorize -> authorize
    .requestMatchers(SWAGGER_URLS).permitAll()
    .requestMatchers(PUBLIC_URLS).permitAll()
    .requestMatchers(ADMIN_URLS).permitAll()  // 서비스 레이어에서 어드민 검증
    .requestMatchers(AUTHENTICATED_URLS).authenticated()
    .anyRequest().authenticated()
)

옵션 2: 더 명확한 구조 (권장)

공개 API만 permitAll(), 나머지는 .anyRequest().permitAll()로 처리하되, JwtFilter에서 user 경로만 필터링:

// JwtFilter.shouldNotFilter() - user API 아닌 것들은 모두 skip
return !path.startsWith("/api/v1/users/") && 
       !path.startsWith("/api/v1/fixed-schedules/");

이렇게 하면:

  • User API → JwtFilter 통과 → AUTHENTICATED_URLS로 인증 필요
  • Admin/Banner API → JwtFilter 건너뜀 → permitAll → 서비스 레이어 검증

어떤 방식을 선호하시나요?


🧬 Code Graph Analysis Results

[src/main/java/side/onetime/global/config/SecurityConfig.java]

  • Snippet 1: PUBLIC_URLS and AUTHENTICATED_URLS definitions (relevant to which endpoints are publicly accessible vs require authentication)
    Summary:

    • Parameters: none
    • Returns: none (constants)
    • Details: Defines two arrays of URL patterns used to configure security rules:
      • PUBLIC_URLS: endpoints accessible without authentication (e.g., login, events, schedules, member-related APIs, admin, banners, onboarding, logout, health, etc.).
      • AUTHENTICATED_URLS: endpoints that require authentication (e.g., user-related APIs, fixed-schedules).
    • Related behavior: these arrays are used in the SecurityFilterChain to determine permitAll vs authenticated requirements.

    Code:
    private static final String[] PUBLIC_URLS = {
    "/login/",
    "/api/v1/events/
    ",
    "/api/v1/schedules/",
    "/api/v1/members/
    ",
    "/api/v1/urls/",
    "/api/v1/tokens/
    ",
    "/api/v1/admin/",
    "/api/v1/banners/
    ",
    "/api/v1/bar-banners/**",
    "/api/v1/users/onboarding",
    "/api/v1/users/logout",
    "/actuator/health"
    };

    private static final String[] AUTHENTICATED_URLS = {
    "/api/v1/users/",
    "/api/v1/fixed-schedules/
    ",
    };

  • Snippet 2: SecurityFilterChain integration showing how PUBLIC_URLS and AUTHENTICATED_URLS influence access control (and JwtFilter usage)
    Summary:

    • Parameters: HttpSecurity httpSecurity
    • Returns: SecurityFilterChain
    • Exceptions: Exception
    • Details: Configures HTTP security to:
      • Disable HTTP Basic and CSRF
      • Apply CORS configuration
      • Permit all for SWAGGER_URLS and PUBLIC_URLS
      • Require authentication for AUTHENTICATED_URLS and any other request
      • Configure OAuth2 login success/failure handlers
      • Add JwtFilter before the UsernamePasswordAuthenticationFilter
    • This ties the user comment about JwtFilter reading userId from token and the need to skip JwtFilter for non-authenticated/public endpoints.

    Code:
    @bean
    public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
    httpSecurity
    .httpBasic(HttpBasicConfigurer::disable)
    .cors(corsConfigurer -> corsConfigurer.configurationSource(corsConfigurationSource()))
    .csrf(AbstractHttpConfigurer::disable)
    .authorizeHttpRequests(authorize -> authorize
    .requestMatchers(SWAGGER_URLS).permitAll()
    .requestMatchers(PUBLIC_URLS).permitAll()
    .requestMatchers(AUTHENTICATED_URLS).authenticated()
    .anyRequest().authenticated()
    )
    .oauth2Login(oauth -> oauth
    .successHandler(oAuthLoginSuccessHandler)
    .failureHandler(oAuthLoginFailureHandler)
    )
    .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);

    return httpSecurity.build();
    }


🧠 Learnings used
Learnt from: CR
Repo: onetime-with-members/backend PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-21T11:41:05.367Z
Learning: Applies to src/main/java/**/auth/*.java : Use Spring Security, OAuth2 (Google, Kakao, Naver), and JWT (JJWT) for authentication and authorization

Learnt from: CR
Repo: onetime-with-members/backend PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-21T11:41:05.367Z
Learning: Applies to src/main/java/**/controller/*Controller.java : Use RESTful API endpoints with /api/v1/ prefix

Learnt from: bbbang105
Repo: onetime-with-members/backend PR: 246
File: src/main/java/side/onetime/service/TokenService.java:37-37
Timestamp: 2025-06-04T16:25:22.271Z
Learning: JwtUtil의 getClaimFromToken 메서드는 JWT 파싱 및 클레임 추출 과정에서 발생하는 JwtException과 IllegalArgumentException을 catch하여 _TOKEN_CLAIM_EXTRACTION_ERROR로 변환하여 던진다. 따라서 클레임이 누락되거나 추출에 실패하는 경우에 대한 별도의 null 체크는 불필요하다.

Copy link
Member Author

Choose a reason for hiding this comment

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

차후 PR에서 진행 예정

Copy link

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Member

@bbbang105 bbbang105 left a comment

Choose a reason for hiding this comment

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

LGTM! :)

@anxi01 anxi01 merged commit 35d4ccf into develop Jan 2, 2026
4 checks passed
@anxi01 anxi01 deleted the refactor/#308 branch January 2, 2026 15:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🚀 feat 새로운 기능 추가 / 일부 코드 추가 / 일부 코드 수정 (리팩토링과 구분) / 디자인 요소 수정 🔄 refactor 코드 리팩토링 😉 seongmin 성민 PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[refactor]: 배너 API를 Admin에서 Banner 도메인으로 이동한다

3 participants