Skip to content
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

refactor/#137 Admin 백오피스 모듈 분리 및 Facade CQRS 패턴 도입 #155

Merged
merged 19 commits into from
Jan 3, 2025

Conversation

LeeHanEum
Copy link
Member

@LeeHanEum LeeHanEum commented Jan 1, 2025

Summary

Admin 모듈을 생성하여 별도의 백오피스 애플리케이션 서버로 분리했어요.
또한 분리 과정에서 공통 로직을 domain 모듈에 담기 위해 Facade 레이어를 도입 했고, 원활한 의존성 관리를 위해 CQRS 패턴을 준수하여 구현했어요.

Tasks

  • Admin 모듈 생성
  • 백오피스 분산 애플리케이션 서버 구축
  • Facade 레이어 도입
  • CQRS 패턴 구현

To Reviewer

백오피스 분산 애플리케이션 서버 구축
기존 단일 API 서버를 유저용(aics-api)과 관리자용(aics-admin)으로 분리하여 멀티모듈 기반 아키텍처의 이점을 활용한 백오피스 분산 애플리케이션 서버를 구축했어요. 이러한 변경은 유저와 관리자 각각의 사용 목적에 따라 서버를 분리하여 각 서비스의 관심사를 명확히 분리하기 때문에 보다 객체 지향적인 설계가 가능해집니다. 한 쪽 서버에서 예상치 못한 장애가 발생하더라도 다른 서버에서 영향을 받지 않으며, 각 서버의 독립적인 배포가 가능해 서비스 전체가 중단되는 일이 발생하지 않아요. (단, 현재 배포 파이프라인은 유저/관리자 모두 한번에 배포하기 때문에 추후 변경이 필요합니다.)

Facade 레이어 도입
클라이언트가 복잡한 하위 시스템에 직접 접근하지 않고, Facade를 통해 간접적으로 접근하여 각 서비스 의존성을 간소화 하기 위해 도입되었어요. aics-apiaics-admin 같은 최상위 모듈에서는 Service 계층의 의존성을 필요에 따라 직접 또는 간접적으로 Facade를 통해 조율 받습니다.

서비스 레이어에 CQRS 패턴 적용
먼저 CQRS 패턴이란 읽기와 쓰기 작업을 분리하여 시스템의 성능과 확장성을 최적화하는 패턴입니다. CommandService는 주로 도메인의 상태를 변경하고, QueryService는 도메인을 읽기 조회하는 작업을 담당합니다. 이러한 변경 역시 각 서비스의 의존성을 간소화 하기 위함이에요.

Screenshot

예시 의존성 그래프
스크린샷 2025-01-03 오전 4 02 26

@LeeHanEum LeeHanEum added the 🔨refactor refactoring code label Jan 1, 2025
@LeeHanEum LeeHanEum requested a review from a team January 1, 2025 14:35
@LeeHanEum LeeHanEum self-assigned this Jan 1, 2025
@Copilot Copilot bot review requested due to automatic review settings January 1, 2025 14:35
@LeeHanEum LeeHanEum linked an issue Jan 1, 2025 that may be closed by this pull request
2 tasks
@LeeHanEum LeeHanEum marked this pull request as draft January 1, 2025 14:35
Copy link
Contributor

coderabbitai bot commented Jan 1, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

이 풀 리퀘스트는 aics-admin 모듈을 새로 생성하고, 기존 aics-api 모듈에서 관리자용 API를 분리하는 작업을 수행합니다. Facade 패턴을 도입하여 서비스 레이어의 로직을 중앙화하고, 컨트롤러와 서비스의 역할을 명확히 구분하였습니다. 주요 변경 사항은 모듈 구조 재구성, 패키지 이동, Facade 클래스 생성, 그리고 관련 설정 파일 업데이트를 포함합니다.

Changes

파일 경로 변경 요약
settings.gradle aics-admin 서브 프로젝트 추가
aics-admin/build.gradle Gradle 빌드 설정 및 의존성 구성
aics-admin/src/main/java/kgu/developers/admin/* 관리자용 API 컨트롤러, 서비스, 설정 클래스 추가
aics-admin/src/main/resources/application*.yml 환경별 애플리케이션 설정 파일 추가
aics-domain/* 도메인 서비스 및 예외 클래스 리팩토링
aics-api/* 기존 API 관련 클래스 제거 및 리팩토링

Assessment against linked issues

목표 달성 여부 설명
aics-admin 모듈 생성 새로운 aics-admin 모듈이 성공적으로 생성됨
Facade 계층 도입 PostFacade, UserFacade, LabFacade 등 Facade 클래스가 추가됨
관리자 API와 사용자 API 분리 관리자용 API 로직이 별도의 모듈로 분리됨
서비스 레이어 로직 중앙화 Facade 클래스를 통해 공통 로직 중앙화

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Choose a reason for hiding this comment

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

Copilot reviewed 64 out of 79 changed files in this pull request and generated no comments.

Files not reviewed (15)
  • aics-admin/build.gradle: Language not supported
  • aics-admin/src/main/java/kgu/developers/admin/lab/presentation/response/LabPersistResponse.java: Evaluated as low risk
  • aics-admin/src/main/java/kgu/developers/admin/lab/presentation/request/LabRequest.java: Evaluated as low risk
  • aics-admin/src/main/java/kgu/developers/admin/file/presentation/response/FilePersistResponse.java: Evaluated as low risk
  • aics-admin/src/main/java/kgu/developers/admin/lab/presentation/LabAdminController.java: Evaluated as low risk
  • aics-admin/src/main/java/kgu/developers/admin/lab/application/LabAdminFacade.java: Evaluated as low risk
  • aics-admin/src/main/java/kgu/developers/admin/file/presentation/exception/FileExceptionCode.java: Evaluated as low risk
  • aics-admin/src/main/java/kgu/developers/admin/file/presentation/exception/FileSavingException.java: Evaluated as low risk
  • aics-admin/src/main/java/kgu/developers/admin/file/presentation/response/FilePathResponse.java: Evaluated as low risk
  • aics-admin/src/main/java/kgu/developers/admin/file/presentation/FileAdminController.java: Evaluated as low risk
  • aics-admin/src/main/java/kgu/developers/admin/file/application/FileAdminFacade.java: Evaluated as low risk
  • aics-admin/src/main/java/kgu/developers/admin/post/presentation/response/PostPersistResponse.java: Evaluated as low risk
  • aics-admin/src/main/java/kgu/developers/admin/post/presentation/request/PostRequest.java: Evaluated as low risk
  • aics-admin/src/main/java/kgu/developers/admin/post/presentation/PostAdminController.java: Evaluated as low risk
  • aics-admin/src/main/java/kgu/developers/admin/config/SwaggerConfig.java: Evaluated as low risk
Copy link
Contributor

@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: 11

🧹 Nitpick comments (60)
aics-domain/src/main/java/kgu/developers/domain/post/exception/PostDomainExceptionCode.java (1)

3-3: static import 사용 시 충돌이나 가독성 저하에 유의하세요.
import static org.springframework.http.HttpStatus.*로 모든 상수를 임포트하면, HttpStatus와의 충돌 가능성이나 IDE 검색 시 혼동이 생길 수 있습니다. 명확성을 위해 필요한 상수만 임포트하거나, 정적 임포트를 피하는 방법을 고려해 보세요.

aics-domain/src/main/java/kgu/developers/domain/lab/infrastructure/LabRepositoryImpl.java (1)

33-34: Lab 엔티티 삭제 시 예외 상황 처리를 고려해주세요
이 로직은 지정된 ID의 Lab 엔티티가 존재하지 않을 경우 EmptyResultDataAccessException이 발생할 수 있습니다. 예외 상황을 제어하거나, DB에 실제 엔티티가 존재하는지 확인하는 선행 로직을 두어 예상치 못한 장애를 방지하는 방안을 검토해 주세요.

aics-admin/src/main/java/kgu/developers/admin/user/presentation/response/UserDetailPageResponse.java (1)

3-3: Enum 상수 임포트 범위 재검토
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.*; 문은 전체 상수를 임포트하므로, 실제 사용되는 상수만 임포트하도록 제한하면 전체 코드 가독성이 더 좋아질 수 있습니다.

aics-domain/src/main/java/kgu/developers/domain/user/application/query/UserQueryService.java (2)

23-25: 페이지네이션 반환 타입에 대한 검증 제안
userRepository.findAllOrderByIdDesc(pageable) 호출 시, 커스텀 리턴 타입인 PaginatedListResponse를 바로 반환하고 있습니다. 내부적으로 정상 동작이 보장되는지 확인하거나, 필요하다면 추가적인 검증 로직(예: 결과가 null인 경우)을 고려해 볼 수 있습니다.


37-45: SecurityContext에서 사용자 식별자를 파싱할 때의 오류 처리
(UserDetails) principal로 캐스팅 후, 예외 발생 시 UserNotAuthenticatedException을 던지는 구조는 명확합니다. 다만, principalUserDetails 형태가 아닐 수 있는 상황(토큰 만료, 인증 정보 없음 등)에서 어떤 추가 로깅이 필요한지 고민해 보시는 것도 좋겠습니다.

aics-admin/src/main/resources/application-local.yml (1)

4-4: 파일 끝에 개행 문자 추가 필요

YAML 파일 형식 표준에 따라 파일 끝에 개행 문자를 추가해 주세요.

 spring:
   jpa:
     hibernate:
-      ddl-auto: update
+      ddl-auto: update
+
🧰 Tools
🪛 yamllint (1.35.1)

[error] 4-4: no new line character at the end of file

(new-line-at-end-of-file)

aics-domain/src/main/java/kgu/developers/domain/user/domain/User.java (2)

77-77: 비밀번호 인코딩 로직 적용

.password(passwordEncoder.encode(password)) 구문을 통해 비밀번호를 즉시 인코딩하는 것은 보안상 적절합니다. passwordEncoder.encode(...) 호출 전후에 추가 검증 로직이나 정책(예: 비밀번호 복잡도 검사)이 필요하다면, 별도의 메서드로 분리하는 것도 고려해볼 수 있습니다.


Line range hint 126-130: 신규 메서드 isPasswordMatching 도입 검토

새로 추가된 isPasswordMatching(String rawPassword, PasswordEncoder passwordEncoder)는 비밀번호 일치 여부를 확인할 수 있어 보안 및 사용성에 이점을 줍니다. 다만, 메서드명에 is 접두사가 붙었으므로 boolean을 반환하는 편이 더 명확해 보일 수 있습니다. 현재는 일치하지 않을 경우 예외를 던지므로, 메서드명을 validatePassword 등으로 변경하는 것도 고려해보세요.

aics-domain/src/main/java/kgu/developers/domain/post/application/command/PostSchedulingService.java (2)

18-18: 유지 기간 상수 정의의 가독성 확인 권장
해당 상수(POST_RETENTION_DAYS)는 30일을 초 단위로 계산한 값을 직접 표현하고 있습니다. 향후 유지 기간을 변경해야 할 경우 예측이 어려우므로, Duration 객체나 별도의 상수(예: DAYS_30_IN_SECONDS)를 통해 가독성을 향상시키는 방안을 고려해 보시면 좋겠습니다.


28-34: 마지막 정리 시간 정보 표시의 다국어 처리 고려
현재 정리 시간을 한국어로 반환하고 있으나, 해외 사용자 지원 또는 다국어 확장 가능성이 있는 프로젝트라면 국제화(i18n)나 메시지 번들을 활용해 문자열을 관리할 여지를 고려해 보시는 것이 좋겠습니다.

aics-domain/src/main/java/kgu/developers/domain/lab/exception/LabNotFoundException.java (1)

3-3: 정적 임포트 와일드카드 사용에 대한 제안
import static kgu.developers.domain.lab.exception.LabDomainExceptionCode.*; 구문은 정의된 모든 항목이 임포트되어 클래스 내부에서 참조되는 상수를 파악하기 어려울 수 있습니다. 필요한 상수만 명시적으로 임포트하면 가독성이 높아집니다.

예시 수정안:

-import static kgu.developers.domain.lab.exception.LabDomainExceptionCode.*;
+import static kgu.developers.domain.lab.exception.LabDomainExceptionCode.LAB_NOT_FOUND;
aics-domain/src/main/java/kgu/developers/domain/user/exception/UserDomainExceptionCode.java (1)

3-3: 정적 임포트 사용에 대한 주의가 필요합니다.
HttpStatus의 모든 상수를 정적 임포트하면 코드 가독성은 높아질 수 있으나, 다른 팀원이 즉시 소스 위치를 파악하기 어려울 수 있습니다. 협업 시 명시적 사용을 고려해보는 것도 좋겠습니다.

aics-domain/src/main/java/kgu/developers/domain/lab/exception/LabDomainExceptionCode.java (1)

3-3: 정적 임포트 사용 시 명시성 고려

import static org.springframework.http.HttpStatus.*;로 변경하면서 여러 HttpStatus 상수를 간단히 사용할 수 있지만, 코드 읽기 시 명시성이 떨어질 수 있습니다. 필요 범위에 맞춰 명확하게 사용하는 방안도 검토해보세요.

aics-domain/src/main/java/kgu/developers/domain/comment/application/command/CommentSchedulingService.java (2)

17-17: 상수 선언 위치 및 의미 명확화 제안
COMMENT_RETENTION_DAYS는 30일(초 단위)이라는 중요한 정책을 담고 있습니다. 해당 상수를 외부 설정 파일이나 오버라이딩 가능한 프로퍼티로 분리하여 운영 환경 혹은 요구사항 변경에 유연하게 대응할 수 있게 하는 방안을 고려해 보시면 어떨까요?


26-32: 로케일 및 다국어 지원 고려
getFormattedLastCleanupRunTime() 메서드에서 날짜/시간 문자열을 "yyyy년 MM월 dd일 HH시 mm분 ss초" 형태로 포매팅하고 있습니다. 추후 다국어 지원이 필요할 경우, 로케일별로 포매팅이 가능하도록 확장성 있는 설계를 검토해 보시는 것을 권장드립니다.

aics-domain/src/main/java/kgu/developers/domain/user/application/command/UserCommandService.java (2)

24-27: 필드 업데이트 시 값 검증 과정 추가 검토

updateUserDetails가 이메일, 전화번호를 수정하지만, 유효성 검증 로직이 없습니다. 입력값이 Null 혹은 빈 문자열인지에 대한 검증이 필요할 수 있습니다.


29-31: 예외 발생 시점에 대한 로깅 및 상세 메시지 보강 권장

validateDuplicateId는 단순히 예외만 던지지만, 운영 환경에서 중복 아이디 발생 원인 파악을 위해 상세 메시지 로깅이 도움이 됩니다.

if (userRepository.existsById(id)) {
-    throw new UserIdDuplicateException();
+    log.error("User ID 중복: " + id);
+    throw new UserIdDuplicateException("중복된 회원 아이디(" + id + ")가 이미 존재합니다.");
}
aics-admin/src/main/resources/application.yml (1)

4-7: 애플리케이션 이름을 더 명확하게 지정해주세요

현재 aics-server로 되어있는 애플리케이션 이름을 aics-admin-server로 변경하는 것이 좋겠습니다. 이는 관리자 백오피스 서버임을 명확히 나타내며, 다른 서비스와의 구분을 용이하게 합니다.

spring:
  application:
-    name: aics-server
+    name: aics-admin-server
aics-domain/src/main/java/kgu/developers/domain/lab/application/query/LabQueryService.java (1)

17-19: 메서드 명과 반환 형태가 혼동을 유발할 수 있습니다.

getLabsByName() 메서드는 “이름으로 특정 Lab을 검색”하는 것으로 오인할 수 있으니 “정렬된 Lab 목록을 조회”한다는 의미가 드러나는 이름(getAllLabsOrderedByName 등)으로 변경을 고려해 보세요.

aics-domain/src/main/java/kgu/developers/domain/comment/application/command/CommentCommandService.java (1)

20-25: createComment 메서드에서 도메인 객체 생성 흐름이 명확합니다.

PostQueryServiceUserQueryService를 통해 필요한 엔티티를 얻고, Comment.create(..., user, post)로 도메인 객체를 생성하는 흐름이 의도에 부합합니다. 추가로, 생성 시점에서 작성자나 게시글의 권한 체크 로직이 필요한 경우, 도메인 객체 또는 서비스 레이어에서 검증을 강화할 수도 있습니다.

aics-api/src/main/java/kgu/developers/api/comment/presentation/CommentController.java (2)

74-74: getComments에서 페이징 처리를 고려할 필요가 있습니다.

현재는 단순히 댓글 목록 전체를 조회 후 반환합니다. 향후 댓글이 대량으로 쌓이면 페이징 쿼리로 확장이 필요할 수 있습니다.


94-94: getLastCleanupRunTime 엔드포인트는 운영 모니터링용으로 보입니다.

외부에 노출할 필요가 없는 경우, 보안 또는 접근 제어를 고려해야 합니다.

현재 접근 제어가 없다면, IP 제한 또는 관리자 권한 검증 등을 적용할 필요가 있을까요?

aics-api/src/main/java/kgu/developers/api/lab/presentation/LabController.java (1)

Line range hint 23-32: [LabFacade 주입 및 사용 방식 점검]
private final LabFacade labFacade; 필드 정의와 labFacade.getLabs() 호출로 라우팅이 간소화되었으며, 컨트롤러-파사드 구조가 명확해졌습니다. 다만, 트랜잭션 범위가 Facade 계층에 적절히 적용되는지와, 현재 API 역할이 ‘조회’만 담당하는지 확인 부탁드립니다.

aics-admin/src/main/java/kgu/developers/admin/config/SwaggerConfig.java (2)

32-39: [OpenAPI Bean 생성 로직 점검]
openAPI() 메서드에서 Info, Security, Servers 등을 일괄 설정하고 있어 설정이 명확하게 분리·관리됩니다. 유지보수성 측면에서 적절해 보이며, 추가로 운영 환경별(host, basePath 등) 설정 확장을 고려할 수 있습니다.


74-80: [API Description 다국어 확장 가능성]
API 설명을 한국어로 서술하면서, format("""...""") 구문을 사용하는 점이 보기 좋습니다. 이후 다국어 지원이 필요하다면, Locale·MessageSource 혹은 별도 리소스 번들을 고려해보는 것도 좋겠습니다.

aics-api/src/main/java/kgu/developers/api/post/presentation/PostController.java (1)

30-30: [파사드 필드 선언]
private final PostFacade postFacade; 필드로 인한 의존성 강도는 적절합니다. 단, 향후 CQRS 적용 시 쿼리에 특화된 역할과 커맨드에 특화된 역할을 구분하는 구조가 계속 유지되는지 점검 부탁드립니다.

aics-admin/src/main/java/kgu/developers/admin/lab/presentation/LabAdminController.java (2)

47-59: [연구실 수정 로직]
updateComment 메서드를 통해 요구사항에 맞춰 수정 처리 로직이 잘 연결되어 있습니다. 다만, 우선 명명 규칙(Comment 대신 Lab)을 통일하면 가독성이 향상될 것으로 보입니다.


61-73: [연구실 삭제 로직]
deleteComment 메서드에서 @DeleteMapping으로 HTTP DELETE 메서드를 정상 사용 중입니다. 관리자 API와 일반 사용자 API 간 권한 구분(예: SecurityContext)도 추가로 검토하면 안정적인 접근 제어가 가능할 것입니다.

aics-admin/src/main/java/kgu/developers/admin/user/application/UserAdminFacade.java (2)

11-12: 컴포넌트 어노테이션 사용에 대한 일관성 고려
현재 @Component를 사용하고 있으나, 스프링 서비스 레이어라는 의도를 명확히 하고 싶다면 @Service를 사용하는 것도 좋습니다.


16-19: Facade 레벨에서의 추가 로직 고려
getUsers(Pageable pageable) 메서드는 내부적으로 단순 조회 후 Response로 변환하는 역할을 하고 있습니다. 관리자 전용 요구사항(권한 검증, 필터링 등)이 있다면 현재 Facade 레벨에서 추가 로직을 처리하는 방안을 검토해 보세요.

aics-admin/src/main/java/kgu/developers/admin/post/presentation/request/PostRequest.java (1)

30-31: 새로운 필드 category의 기본값 고려
카테고리가 선택되지 않을 경우를 어떻게 처리할지 미리 정의해 두는 것을 권장합니다. 필요한 경우 enum의 기본값 설정 또는 별도의 UNKNOWN 카테고리 처리 등이 유용할 수 있습니다.

aics-admin/src/main/java/kgu/developers/admin/lab/application/LabAdminFacade.java (1)

25-28: updateLab 메서드 동작 확인
labQueryService.getById(id)로 Lab를 조회 후 labCommandService.updateLab을 호출하는 흐름이 명확합니다. 다만 조회된 Lab이 없는 경우 예외 처리도 고려 부탁드립니다.

aics-domain/src/main/java/kgu/developers/domain/post/application/command/PostCommandService.java (3)

18-22: createPost 메서드의 유효성 검증
userQueryService.me()로 작성자를 가져온 후 Post.create로 객체를 생성하는 흐름이 좋습니다. title, content, category가 null이 아닌지 등 추가 유효성 검사를 고려해 보세요.


24-28: updatePost 메서드에서의 중복 로직
제목, 내용, 카테고리를 각각 다른 메서드로 업데이트하고 있습니다. 각 update 메서드마다 비즈니스 로직이 들어가 있으면 좋지만, 단순 속성 변경만 수행한다면 하나의 메서드로 묶는 방안도 고려 가능합니다.


38-40: 논리 삭제 로직
post.delete()를 통해 삭제 상태로 전환합니다. 복원 가능 여부를 고려해야 하는지, 물리 삭제가 필요한지 요구 사항에 맞게 재검토해 주세요.

aics-api/src/main/java/kgu/developers/api/user/application/UserFacade.java (1)

16-19: Builder 어노테이션 사용 점검
@Builder와 함께 @Component, @Transactional, @RequiredArgsConstructor를 동시에 적용하셨습니다. 빌더 패턴이 필요한 시나리오인지 확인 부탁드립니다. 보통 Facade 클래스에는 빌더를 잘 사용하지 않습니다.

aics-admin/src/main/java/kgu/developers/admin/post/application/PostAdminFacade.java (2)

21-24: [예외 처리 제안]
createPost 메서드에서 요청 데이터 검증이 충분히 이루어지는지 확인이 필요합니다. title, content, category가 빈 값이거나 유효하지 않을 때 사전에 방어 로직을 추가하는 방안을 고려해 보세요.


44-46: [스케줄링 결과 확인 권장]
getLastCleanupRunTime()은 반환값으로 마지막 정리 시각을 표시하지만, 스케줄링이 정상적으로 수행되고 있는지 주기적으로 점검이 필요합니다. 모니터링 지표나 로그를 통해 검증해 보세요.

aics-api/src/testFixtures/java/mock/TestContainer.java (3)

17-20: [주석 정리 권장]
테스트 컨테이너 내에서 이전에 사용하던 UserService, PostService 코드가 모두 주석으로만 남아 있습니다. 필요가 없어진 코드라면 삭제하는 방안도 고려해 보세요.


28-31: [주석 처리된 Facade 빌더]
메서드 체이닝 형태로 Facade 객체를 빌드하려 했으나, 아직 주석 처리된 상태입니다. 추후 Facade를 사용한다면, 관련 파라미터나 설정 값을 점검하고 활성화하세요.


46-46: [추가 테스트 제안]
this.postFacade = new PostFacade(...) 부분도 주석 처리가 되어 있습니다. 추후 게시물 관련 테스트 진행 시 Facade 사용으로 일관성 있게 작성할 수 있도록 준비해 두시는 것을 권장드립니다.

aics-domain/src/main/java/kgu/developers/domain/post/application/query/PostQueryService.java (1)

27-37: [이전/다음 게시물 동시 조회]
이전 글과 다음 글을 같이 조회하는 로직이 postRepository.findByPrevPost, postRepository.findByNextPost로 구현되어 있습니다. 성능 상의 문제가 없는지 살펴보고, 인덱스나 쿼리 튜닝이 필요한 경우도 검토하시기 바랍니다.

aics-admin/src/main/java/kgu/developers/admin/user/presentation/UserAdminController.java (2)

29-34: [Swagger 문서 개선 제안]
@Operation@ApiResponse 설명이 비교적 간결합니다. API 사용 의도를 명확히 하려면 요청 파라미터, 예시 응답, 에러 케이스 등을 조금 더 자세히 기술하시면 좋겠습니다.


35-41: [유저 조회 API 파라미터 검증]
페이지 인덱스와 개수에 대해 양수 검증을 추가하신 점이 좋습니다. 다만, 요청 파라미터가 유효 범위를 넘어서거나 너무 커질 때 서버 부담이 커질 수 있으니, 이를 처리하는 로직(예: 최대 페이징 사이즈 제한)도 고려해 보세요.

aics-api/src/main/java/kgu/developers/api/config/SwaggerConfig.java (1)

3-4: [ko-KR] 정적 임포트 사용 방식 점검
java.lang.String.*org.springframework.security.config.Elements.*를 정적 임포트하는 것은, 메서드나 상수를 명확하게 식별하기 어려울 수 있습니다. 가독성을 위해 필요한 메서드 또는 상수만 임포트하는 방식도 고려해 보세요.

aics-api/src/main/java/kgu/developers/api/auth/application/AuthService.java (1)

25-25: [ko-KR] private final UserQueryService userQueryService; 변경 검토
UserService에서 UserQueryService로 변경됨에 따라, 쓰기 작업(회원 생성, 업데이트 등)은 수행하지 않는 서비스로 보입니다. AuthService 로직에서 쓰기 작업이 필요 없다면 적절한 분리가 이루어졌는지 재확인해 주세요.

aics-api/src/main/java/kgu/developers/api/user/presentation/UserController.java (4)

3-4: [ko-KR] HTTP Status 정적 임포트 검토
static org.springframework.http.HttpStatus.*를 임포트하는 경우 상태 코드를 명확성이 떨어지는 형태로 사용할 수 있습니다. 필요에 따라 HttpStatus.CREATED, HttpStatus.OK와 같이 명시적으로 사용하는 것도 고려해 보세요.


19-19: [ko-KR] UserFacade 주입 변경
UserService 대신 UserFacade를 주입받는 구조는 CQRS나 Facade 패턴에 맞추어 설계된 것으로 보입니다. 다만, Facade 내에서 너무 많은 역할을 하게 되지 않도록 주의해 주세요.


29-29: [ko-KR] Swagger 태그 주석
@Tag(name = "User", description = "회원 API")를 통해 Swagger에 문서화가 잘 진행되고 있습니다. 추가 파라미터나 응답 DTO가 있는 경우, 별도 스키마 정의를 고려해 보세요.


31-31: [ko-KR] private final UserFacade userFacade; 필드 확인
이미 AuthService에서도 일부 사용자 정보를 조회하고 있습니다. UserFacadeUserQueryService의 책임을 구분하여, 중복 로직이 발생하지 않도록 주의해야 합니다.

aics-admin/src/main/java/kgu/developers/admin/post/presentation/PostAdminController.java (4)

33-33: 주입된 Facade 인스턴스에 대한 주석 추가 제안
PostAdminFacade의 역할 및 주 책임을 간단히 주석으로 남기면 코드 가독성 향상에 도움이 될 것 같습니다.


41-46: 성공적으로 게시글 생성 시, 응답 로그 추가 고려
게시글 생성 성공 후 서버 로그 등을 통해 관련 이벤트를 남기면 운영 시 참고에 도움이 될 것 같습니다.


68-73: 핀 기능 토글 시, 현재 상태를 반환하는 방안 고려
핀 활성/비활성을 토글할 때, 최종 상태를 API 응답 등으로 반환해주면 클라이언트 측에서 현재 상태를 재확인하기에 편리할 수 있습니다.


88-97: 용도별 Endpoint 분리 검토
GetMapping("/cleanup-last-run") 엔드포인트가 삭제된 게시글을 영구 삭제하는 로직과 더불어 최근 정리 시간을 확인하는 용도로 사용되고 있습니다. 다양한 관리 기능이 추가될 경우, 해당 API를 별도 Controller나 Endpoint로 분리하여 유지보수를 용이하게 할 수 있습니다.

aics-admin/src/main/resources/application-dev.yml (1)

1-9: 파일의 마지막 줄에 개행 문자 추가 권장
yamllint에서 no new line character at the end of file 오류가 감지되었습니다. 아래와 같이 마지막 줄 이후 개행 문자를 추가해주시면 좋습니다.

  password: ${REDIS_PASSWORD}
+ 
🧰 Tools
🪛 yamllint (1.35.1)

[error] 9-9: no new line character at the end of file

(new-line-at-end-of-file)

aics-admin/build.gradle (1)

9-14: 모듈 간 의존성 최적화 검토
aics-domain, aics-common, aics-infra, aics-global-utils 모두 implementation으로 추가되었습니다. 혹시 api를 사용해야 하는 부분은 없는지, 일부 의존성이 필요 이상으로 노출되지 않는지 검토 부탁드립니다.

aics-admin/src/main/resources/application-prod.yml (1)

4-10: JPA 설정 검토 의견

프로덕션 환경의 JPA 설정이 적절하게 구성되어 있습니다. 특히:

  • validate 모드는 프로덕션에 적합합니다
  • default_batch_fetch_size가 최적화되어 있습니다
  • open-in-view 비활성화는 좋은 선택입니다

하지만 성능 모니터링을 위해 다음 설정의 추가를 고려해보세요:

spring:
  jpa:
    properties:
      hibernate:
        generate_statistics: true
aics-admin/src/main/resources/db/schema.sql (3)

73-89: 사용자 테이블 최적화 제안

user 테이블에 대한 개선 사항:

  1. 이메일과 전화번호 컬럼에 인덱스 추가 필요
  2. role 컬럼의 기본값 설정 고려
  3. major 확장성을 위해 별도 테이블로 분리 고려
CREATE INDEX idx_user_email ON "user" (email) WHERE deleted_at IS NULL;
CREATE INDEX idx_user_phone ON "user" (phone) WHERE deleted_at IS NULL;
ALTER TABLE "user" ALTER COLUMN role SET DEFAULT 'USER';

91-112: 게시글 테이블 성능 최적화

post 테이블의 성능 개선을 위한 제안:

  1. 카테고리와 생성일자에 대한 복합 인덱스 추가
  2. 조회수 업데이트를 위한 최적화된 쿼리 사용
  3. 첨부파일 관계에 대한 캐싱 전략 수립
CREATE INDEX idx_post_category_created_at ON post (category, created_at) WHERE deleted_at IS NULL;

114-128: 댓글 테이블 구조 개선

comment 테이블에 대한 제안:

  1. 계층형 댓글 지원을 위한 parent_id 컬럼 추가 고려
  2. 게시글별 댓글 조회 성능을 위한 인덱스 추가
  3. 삭제된 사용자의 댓글 처리 정책 수립
ALTER TABLE comment ADD COLUMN parent_id BIGINT REFERENCES comment(id);
CREATE INDEX idx_comment_post_id ON comment (post_id, created_at) WHERE deleted_at IS NULL;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a7de92 and ef1f967.

📒 Files selected for processing (79)
  • aics-admin/build.gradle (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/AicsAdminApplication.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/config/InfraConfig.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/config/SwaggerConfig.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/file/application/FileAdminFacade.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/file/presentation/FileAdminController.java (5 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/file/presentation/exception/FileExceptionCode.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/file/presentation/exception/FileSavingException.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/file/presentation/response/FilePathResponse.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/file/presentation/response/FilePersistResponse.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/lab/application/LabAdminFacade.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/lab/presentation/LabAdminController.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/lab/presentation/request/LabRequest.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/lab/presentation/response/LabPersistResponse.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/post/application/PostAdminFacade.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/post/presentation/PostAdminController.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/post/presentation/request/PostRequest.java (2 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/post/presentation/response/PostPersistResponse.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/user/application/UserAdminFacade.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/user/presentation/UserAdminController.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/user/presentation/response/UserDetailPageResponse.java (1 hunks)
  • aics-admin/src/main/resources/application-dev.yml (1 hunks)
  • aics-admin/src/main/resources/application-local.yml (1 hunks)
  • aics-admin/src/main/resources/application-prod.yml (1 hunks)
  • aics-admin/src/main/resources/application.yml (1 hunks)
  • aics-admin/src/main/resources/db/data.sql (1 hunks)
  • aics-admin/src/main/resources/db/schema.sql (1 hunks)
  • aics-api/src/main/java/kgu/developers/api/auth/application/AuthService.java (3 hunks)
  • aics-api/src/main/java/kgu/developers/api/comment/application/CommentFacade.java (1 hunks)
  • aics-api/src/main/java/kgu/developers/api/comment/application/CommentService.java (0 hunks)
  • aics-api/src/main/java/kgu/developers/api/comment/presentation/CommentController.java (6 hunks)
  • aics-api/src/main/java/kgu/developers/api/config/SwaggerConfig.java (2 hunks)
  • aics-api/src/main/java/kgu/developers/api/lab/application/LabFacade.java (1 hunks)
  • aics-api/src/main/java/kgu/developers/api/lab/application/LabService.java (0 hunks)
  • aics-api/src/main/java/kgu/developers/api/lab/presentation/LabController.java (2 hunks)
  • aics-api/src/main/java/kgu/developers/api/post/application/PostFacade.java (1 hunks)
  • aics-api/src/main/java/kgu/developers/api/post/application/PostService.java (0 hunks)
  • aics-api/src/main/java/kgu/developers/api/post/presentation/PostController.java (4 hunks)
  • aics-api/src/main/java/kgu/developers/api/user/application/UserFacade.java (1 hunks)
  • aics-api/src/main/java/kgu/developers/api/user/application/UserService.java (0 hunks)
  • aics-api/src/main/java/kgu/developers/api/user/presentation/UserController.java (3 hunks)
  • aics-api/src/main/java/kgu/developers/api/user/presentation/exception/UserExceptionCode.java (0 hunks)
  • aics-api/src/testFixtures/java/auth/application/AuthServiceTest.java (2 hunks)
  • aics-api/src/testFixtures/java/auth/presentation/AuthControllerTest.java (1 hunks)
  • aics-api/src/testFixtures/java/comment/application/CommentServiceTest.java (4 hunks)
  • aics-api/src/testFixtures/java/lab/application/LabServiceTest.java (7 hunks)
  • aics-api/src/testFixtures/java/mock/TestContainer.java (2 hunks)
  • aics-api/src/testFixtures/java/post/application/PostServiceTest.java (4 hunks)
  • aics-api/src/testFixtures/java/user/application/UserServiceTest.java (5 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/comment/application/command/CommentCommandService.java (1 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/comment/application/command/CommentSchedulingService.java (1 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/comment/application/query/CommentQueryService.java (1 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/comment/exception/CommentDomainExceptionCode.java (2 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/comment/exception/CommentNotFoundException.java (1 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/file/FileSaveService.java (1 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/lab/application/command/LabCommandService.java (1 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/lab/application/query/LabQueryService.java (1 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/lab/domain/LabRepository.java (1 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/lab/exception/LabDomainExceptionCode.java (2 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/lab/exception/LabNotFoundException.java (1 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/lab/infrastructure/LabRepositoryImpl.java (1 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/post/application/command/PostCommandService.java (1 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/post/application/command/PostSchedulingService.java (1 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/post/application/query/PostQueryService.java (1 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/post/application/response/PostDetailResponse.java (1 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/post/application/response/PostTitleResponse.java (1 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/post/domain/Post.java (1 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/post/exception/PostDomainExceptionCode.java (2 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/post/exception/PostNotFoundException.java (1 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/user/application/command/UserCommandService.java (1 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/user/application/query/UserQueryService.java (1 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/user/application/response/UserDetailResponse.java (1 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/user/domain/User.java (2 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/user/exception/UserDomainExceptionCode.java (2 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/user/exception/UserIdDuplicateException.java (1 hunks)
  • aics-domain/src/main/java/kgu/developers/domain/user/exception/UserNotAuthenticatedException.java (1 hunks)
  • aics-domain/src/testFixtures/java/mock/FakeLabRepository.java (2 hunks)
  • aics-infra/src/main/java/kgu/developers/infra/AicsConfigGroup.java (0 hunks)
  • settings.gradle (1 hunks)
💤 Files with no reviewable changes (6)
  • aics-api/src/main/java/kgu/developers/api/user/presentation/exception/UserExceptionCode.java
  • aics-api/src/main/java/kgu/developers/api/post/application/PostService.java
  • aics-infra/src/main/java/kgu/developers/infra/AicsConfigGroup.java
  • aics-api/src/main/java/kgu/developers/api/user/application/UserService.java
  • aics-api/src/main/java/kgu/developers/api/lab/application/LabService.java
  • aics-api/src/main/java/kgu/developers/api/comment/application/CommentService.java
✅ Files skipped from review due to trivial changes (15)
  • aics-admin/src/main/java/kgu/developers/admin/post/presentation/response/PostPersistResponse.java
  • aics-admin/src/main/java/kgu/developers/admin/AicsAdminApplication.java
  • aics-admin/src/main/java/kgu/developers/admin/lab/presentation/response/LabPersistResponse.java
  • aics-admin/src/main/java/kgu/developers/admin/file/presentation/response/FilePersistResponse.java
  • aics-admin/src/main/java/kgu/developers/admin/lab/presentation/request/LabRequest.java
  • aics-admin/src/main/java/kgu/developers/admin/file/presentation/response/FilePathResponse.java
  • aics-admin/src/main/java/kgu/developers/admin/file/presentation/exception/FileExceptionCode.java
  • aics-api/src/testFixtures/java/comment/application/CommentServiceTest.java
  • aics-domain/src/testFixtures/java/mock/FakeLabRepository.java
  • aics-api/src/testFixtures/java/post/application/PostServiceTest.java
  • aics-domain/src/main/java/kgu/developers/domain/post/application/response/PostDetailResponse.java
  • aics-domain/src/main/java/kgu/developers/domain/post/application/response/PostTitleResponse.java
  • aics-domain/src/main/java/kgu/developers/domain/user/application/response/UserDetailResponse.java
  • aics-domain/src/main/java/kgu/developers/domain/comment/exception/CommentNotFoundException.java
  • aics-admin/src/main/java/kgu/developers/admin/file/presentation/exception/FileSavingException.java
🧰 Additional context used
📓 Learnings (1)
aics-api/src/testFixtures/java/lab/application/LabServiceTest.java (1)
Learnt from: LeeShinHaeng
PR: kgu-developers/aics-server#124
File: aics-api/src/testFixtures/java/lab/application/LabServiceTest.java:76-87
Timestamp: 2024-12-03T04:40:00.172Z
Learning: LabServiceTest.java에서 `getById()`와 같은 private 메소드를 테스트할 때, 이를 내부적으로 사용하는 `deleteLab()`과 같은 public 메소드를 통해 간접적으로 접근하고, 이 접근 방법을 설명하는 주석을 포함하는 것이 허용됩니다.
🪛 yamllint (1.35.1)
aics-admin/src/main/resources/application-local.yml

[error] 4-4: no new line character at the end of file

(new-line-at-end-of-file)

aics-admin/src/main/resources/application-dev.yml

[error] 9-9: no new line character at the end of file

(new-line-at-end-of-file)

aics-admin/src/main/resources/application-prod.yml

[error] 15-15: no new line character at the end of file

(new-line-at-end-of-file)

🔇 Additional comments (123)
aics-api/src/testFixtures/java/auth/presentation/AuthControllerTest.java (1)

28-28: Facade 레이어 테스트 및 의존성 정확성 확인

userFacade.createUser()를 통해 새롭게 Facade 레이어를 활용하고 있습니다. 이렇게 변경된 구조가 의도대로 동작하는지 중점적으로 확인해보세요. 특히 기존 UserService를 대체하는 로직이 중복되거나 누락되지 않았는지 검증이 필요합니다.

aics-domain/src/main/java/kgu/developers/domain/post/exception/PostDomainExceptionCode.java (2)

1-1: 패키지 구조의 재정비가 도메인 로직을 명확하게 분리합니다.
패키지를 kgu.developers.domain.post.exception로 이동함으로써 도메인 계층에서 발생하는 예외 처리를 한 곳에서 관리할 수 있어 가독성과 유지보수성이 높아졌습니다.


13-14: 열거형 이름 변경이 전체 코드베이스 구조에 부합합니다.
PostDomainExceptionCode로 명명하여 예외 코드가 도메인 단에서 관리됨을 명확히 표현하고 있습니다. 예외 메시지도 업무 맥락을 잘 반영하므로 유지보수 시 혼동이 줄어들 것으로 보입니다.

aics-admin/src/main/java/kgu/developers/admin/user/presentation/response/UserDetailPageResponse.java (2)

1-1: 패키지 명칭 변경 확인 필요
이전 api 패키지에서 admin 패키지로 이동되어, 관리 영역으로의 책임 분리가 명확해졌습니다.
추가적으로 해당 패키지 이동 후 레거시 코드에서 UserDetailPageResponse를 사용하는 부분이 깨지지 않았는지 확인이 필요합니다.


9-9: UserDetailResponse 임포트 확인
UserDetailResponse가 새로 임포트되어, users.stream().map(UserDetailResponse::from)를 사용하는 로직과 정상적으로 연동됩니다. 다만, 해당 클래스의 내부 구현(필드, 생성자 등) 변경 시 from 메서드 호출부에 영향이 없는지 주의 깊게 살펴보시기 바랍니다.

aics-api/src/main/java/kgu/developers/api/post/application/PostFacade.java (3)

16-18: 클래스 설계가 적절합니다.

클래스에 Service 및 RequiredArgsConstructor 애너테이션을 사용하여 의존성 주입을 명확히 처리하고 있습니다. Facade 계층에서 핵심 도메인 로직을 적절히 캡슐화하여 유지보수성을 높이는 방식이 바람직해 보입니다.


22-27: 메서드 네이밍과 구현이 일관적입니다.

getPostsByKeywordAndCategory 메서드는 파라미터로 받은 키워드와 카테고리에 따라 게시글 목록을 조회하고, 반환 객체로 PostSummaryPageResponse를 사용하는 부분이 직관적입니다. 향후 필터 조건이나 정렬 옵션이 확장될 수 있으므로, 메서드 시그니처가 유연성을 가질 수 있도록 주의 깊게 관리해 주세요.


29-34: 조회 시 뷰 카운트 증가 로직 검토 필요

조회 직후 뷰 카운트를 증가시키는 로직은 일반적으로 문제없지만, 다중 트래픽 환경에서 동시 업데이트가 발생할 수 있으므로 동시성 처리에 유의해주세요. 이후 요구사항에 따라 락 사용 또는 버전 관리를 고려할 수 있습니다.

aics-domain/src/main/java/kgu/developers/domain/user/application/query/UserQueryService.java (3)

1-2: 도메인 계층과 기능 분리가 명확합니다.
query 패키지로 분리하여 Read 전용 로직을 모으는 구조는 향후 CQRS 적용 시 매우 유용해 보입니다.


17-20: 읽기 전용 트랜잭션 선언이 적절해 보입니다.
데이터를 조회하는 서비스이므로 @Transactional(readOnly = true)는 쿼리 성능 측면에서 적절한 설정입니다.


27-30: 예외 처리가 잘 이루어져 있습니다.
UserNotFoundException을 즉시 발생시킴으로써, 조회 대상 사용자가 없을 때 명확한 에러가 반환될 수 있습니다. 추후 예외 메시지나 상세 정보가 필요하다면, 커스텀 메시지를 추가하는 방안도 고려해 보세요.

aics-domain/src/main/java/kgu/developers/domain/user/domain/User.java (2)

17-17: 비밀번호 인코딩을 위한 적절한 의존성 주입 확인

BCryptPasswordEncoderPasswordEncoder를 동시에 import하여, 향후 유연한 비밀번호 인코딩 전략 교체가 가능해졌습니다. 현재 구현처럼 PasswordEncoder 인터페이스를 사용하면 추후 필요한 인코딩 알고리즘으로 쉽게 전환할 수 있으므로 좋은 접근입니다.


72-73: User.create 메서드의 시그니처 변경에 따른 주의

create 메서드에 PasswordEncoder가 추가되어, 사용자 생성 시점에 비밀번호가 즉시 인코딩되도록 구현되었습니다. 호출부에서 PasswordEncoder를 지속적으로 주입해야 하므로, 객체 생성 위치나 의존성 주입 방식을 점검해 보시기 바랍니다.

aics-domain/src/main/java/kgu/developers/domain/post/application/command/PostSchedulingService.java (2)

21-23: 스케줄링 시점과 트랜잭션 경계 설정에 대한 점검 필요
@Scheduled@Transactional을 함께 사용하면, 스케줄링된 작업 도중 예외가 발생했을 때 트랜잭션이 롤백될 수 있습니다. 이는 일부 상황에서 의도치 않은 동작을 초래할 수 있으므로, 트랜잭션 경계 설정을 별도로 분리하거나 필요한 시점에만 트랜잭션을 열도록 재검토해 보시는 것이 좋습니다.


24-24: ⚠️ Potential issue

파라미터 타입/의미 재검토 필요
deleteAllByDeletedAtBefore(POST_RETENTION_DAYS) 메서드는 흔히 시간 기준(LocalDateTime)을 인자로 받을 것으로 예상됩니다. 그러나 현재는 초 단위의 정수 상수가 직접 전달되고 있어, 저장소 메서드와의 파라미터 타입 불일치 가능성이 우려됩니다. 실제로 의도한 기능을 수행하는지 재차 확인하시길 권장드립니다.

aics-domain/src/main/java/kgu/developers/domain/lab/exception/LabNotFoundException.java (1)

1-1: 패키지 이동 확인 완료
도메인 계층에서 예외를 정의하는 것은 유지보수에 적합해 보입니다. 별도 문제 없이 적절하게 이동되었습니다.

aics-domain/src/main/java/kgu/developers/domain/user/exception/UserDomainExceptionCode.java (3)

17-17: 사용자 인증 예외 코드가 필요충분하게 정의되었습니다.
인증 실패 상황을 명확히 의미하는 메시지와 코드가 매핑되어 있어 적절합니다.


18-18: 예외 코드 재배치에 따른 영향 범위를 확인하세요.
USER_NOT_FOUND 상수의 위치가 변경되었으므로, 해당 상수를 사용하는 코드에서 의도치 않은 에러나 순서 의존성이 없는지 점검해보세요.


19-19: 아이디 중복 예외 코드 추가를 테스트로 검증하세요.
새로운 예외가 등록된 만큼, 회원가입 로직에서 중복 상황이 올바르게 처리되는지 단위 테스트와 통합 테스트를 통해 검증하는 것을 권장합니다.

aics-domain/src/main/java/kgu/developers/domain/lab/exception/LabDomainExceptionCode.java (2)

13-15: 코드 일관성 및 유지보수성 확보

LAB_NOT_FOUND 에러 코드가 NOT_FOUND 상태를 누적적으로 드러내고 있어, 코드 가독성이 향상되었습니다. 마침표(;) 뒤에 더 많은 예외 타입이 추가될 가능성이 있다면, 주석을 명시하거나 다른 에러 코드와 함께 정렬해서 관리하는 것이 좋습니다.


1-1: 패키지 이동에 따른 호환성 확인 필요

패키지 경로가 kgu.developers.api.lab.presentation.exception에서 kgu.developers.domain.lab.exception로 변경되었습니다. 기존에 해당 클래스 혹은 에러 코드를 참조하는 부분이 있다면 모두 정상적으로 수정되었는지 점검이 필요합니다.

아래 스크립트를 사용하여 기존 LabExceptionCode를 호출하던 흔적이 있는지 확인해보세요.

✅ Verification successful

패키지 이동이 정상적으로 처리되었습니다

검증 결과, 다음과 같은 사항들이 확인되었습니다:

  • 기존 kgu.developers.api.lab.presentation.exception.LabExceptionCode 패키지 경로를 참조하는 코드가 없습니다.
  • 새로운 LabDomainExceptionCode는 도메인 계층에서 적절히 사용되고 있습니다.
  • LabNotFoundException과 같은 관련 예외들이 새로운 패키지 구조를 올바르게 참조하고 있습니다.
  • 테스트 코드를 포함한 모든 사용처에서 새로운 패키지 경로를 사용하고 있습니다.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 이전 패키지 경로에서 작성된 import/참조가 남아 있는지 검색
rg "kgu\.developers\.api\.lab\.presentation\.exception\.LabExceptionCode" -A 5

Length of output: 80


Script:

#!/bin/bash
# 기존 LabExceptionCode 클래스의 사용처를 검색
rg "LabExceptionCode" -l

# 도메인 예외 관련 파일들의 변경 이력 확인
fd "Lab.*Exception.*" --type f

Length of output: 235


Script:

#!/bin/bash
# LabNotFoundException의 내용을 확인하여 예외 코드 사용 방식 파악
cat aics-domain/src/main/java/kgu/developers/domain/lab/exception/LabNotFoundException.java

# 전체 코드베이스에서 Lab 관련 예외 사용 패턴 검색
rg "Lab.*Exception" -A 3

Length of output: 4134

aics-domain/src/main/java/kgu/developers/domain/comment/application/command/CommentSchedulingService.java (2)

20-24: cron 표현식의 정확성 및 TimeZone 고려
@Scheduled(cron = "0 0 0 * * *")는 자정마다 스케줄링이 실행됨을 의미하지만, 서버 TimeZone에 따라 실제 실행 시각이 달라질 수 있습니다. 운영 환경의 TimeZone이 명시적으로 설정되어 있는지 확인하시고, 필요하다면 zone 속성을 지정하거나 설정 파일에서 TimeZone을 관리하는 방안을 고려해 보세요.


22-22: deleteAllByDeletedAtBefore 매개변수 타입 확인
deleteAllByDeletedAtBefore(COMMENT_RETENTION_DAYS)라고 정수 타입을 직접 전달하고 있지만, 일반적으로 before가 날짜 기준으로 동작한다면 LocalDateTime이나 Instant 같은 시간 객체를 사용하는 구현일 가능성이 큽니다. 이 메서드가 int 파라미터로 정상적으로 동작하는지, 혹은 메서드 내부에서 날짜 변환 로직을 수행하는지 한번 더 확인해 주세요.

aics-domain/src/main/java/kgu/developers/domain/user/application/command/UserCommandService.java (2)

12-14: 클래스 선언과 애너테이션 사용이 적절합니다.

@Service@RequiredArgsConstructor 애너테이션 사용으로 해당 클래스의 의도가 명확해 보입니다. 생성자 주입 방식 또한 이상적으로 적용되어 있어 유지보수성과 확장성이 좋습니다.


15-16: 필드 선언 시점에 대한 트랜잭션 관리 고려 제안

bCryptPasswordEncoderuserRepository 모두 사용자 생성/업데이트 시점에서 사용되며, 두 의존성 모두 트랜잭션 범위 내에서 동작 가능성을 고려해야 합니다. 추가적인 메서드 단위의 트랜잭션 관리가 필요하다면, 별도로 확인 부탁드립니다.

aics-admin/src/main/resources/application.yml (3)

24-29: 파일 업로드 설정이 적절합니다

환경 변수를 통해 파일 크기 제한을 구성할 수 있도록 설정되어 있으며, 기본값 10MB는 적절한 수준입니다.


42-48: API 문서화 설정이 적절합니다

JSON API에 적합한 미디어 타입이 설정되어 있으며, 알파벳순 정렬 설정으로 문서의 가독성이 향상됩니다.


8-23: 데이터베이스 설정이 적절히 구성되었습니다

환경 변수를 통한 설정과 개발용 기본값이 잘 구성되어 있습니다. open-in-view: false 설정으로 성능 이슈를 방지하고 있습니다.

프로덕션 환경에서 필요한 환경 변수들이 모두 설정되어 있는지 확인하기 위해 다음 스크립트를 실행해주세요:

aics-domain/src/main/java/kgu/developers/domain/lab/application/query/LabQueryService.java (2)

12-14: 클래스 및 생성자 주입 방식이 적절합니다.

@RequiredArgsConstructor를 통해 필수 의존성을 안전하게 주입하고, @Service로 선언하여 비즈니스 로직 계층의 명확한 분리를 보장하고 있습니다.


21-23: 예외 처리 로직이 명확하여 가독성이 좋습니다.

LabNotFoundException으로 검색 실패 시점을 명시적으로 드러내어, 책임을 효과적으로 분리하고 있습니다. 현재 로직은 유지 보수와 테스트에 유리해 보입니다.

aics-domain/src/main/java/kgu/developers/domain/post/exception/PostNotFoundException.java (3)

1-1: 패키지 경로 변경이 적절합니다.
기존 API 레이어에서 도메인 레이어로 예외가 이동되어 계층 분리가 명확해졌습니다. 특별한 문제는 없어 보입니다.


3-3: 정적 임포트를 통한 상수 사용이 명료합니다.
PostDomainExceptionCode 전체를 가져오지만, 필요에 따라 구체적인 상수만 사용하는 형태라면 가독성과 유지보수에 유리합니다.


5-5: CustomException 임포트가 올바르게 이루어졌습니다.
프로젝트 내 공통 예외 규칙을 따르고 있어, 일관된 예외 처리에 도움이 됩니다.

aics-domain/src/main/java/kgu/developers/domain/comment/exception/CommentDomainExceptionCode.java (2)

1-1: 패키지 리팩토링이 적절합니다.
domain 계층으로 이전함으로써 책임이 명확해지고, 구조적인 명확성을 높이는 데 도움이 됩니다.


13-13: 이름 변경 및 리팩토링이 적절합니다.
CommentDomainExceptionCode로 명명하여 도메인 관점의 예외라는 점이 더욱 분명해졌습니다.

aics-domain/src/main/java/kgu/developers/domain/comment/application/query/CommentQueryService.java (3)

12-15: 구현 방식 및 클래스 구조가 적절합니다.

클래스 레벨에서 @Service, @RequiredArgsConstructor를 사용하여 빈 등록과 생성자 주입을 적용한 점이 표준적이고 유지보수에 용이해 보입니다. 추후 도메인 로직이 확장되거나 종속이 늘어날 경우에도 쉽게 확장 가능할 것으로 판단됩니다.


17-19: getComments(Long postId) 메서드의 커맨드/쿼리 분리 의도를 잘 반영합니다.

특정 게시글에 대한 댓글 목록을 얻는 쿼리 메서드로서, 삭제되지 않은 댓글만 조회하도록 한 점이 역할상 명확합니다.


21-25: getById(Long commentId) 메서드의 예외 처리 방식이 명확합니다.

존재하지 않거나 이미 삭제된 댓글은 CommentNotFoundException을 던져서 에러 처리를 일관되게 수행하는 방식이 적절합니다. 다만, 추가적인 로그 기록이나 필요한 경우性能 모니터링을 고려할 수도 있습니다.

aics-domain/src/main/java/kgu/developers/domain/comment/application/command/CommentCommandService.java (3)

13-14: @Service@RequiredArgsConstructor 사용이 적절합니다.

명령(쓰기) 로직을 전담하는 서비스로 구분되어, 다른 레이어에서도 의존성을 명확히 추적할 수 있습니다.


27-29: updateComment 메서드의 인자 전달 방식이 직관적입니다.

댓글과 수정할 내용을 분리하여 전달하고, 도메인 객체에 위임하는 구조가 명확합니다.


31-33: deleteComment의 논리 삭제 처리가 명확합니다.

comment.delete() 메서드를 통해 삭제 로직을 캡슐화한 점이 적절합니다. 이후 배치나 스케줄링을 통한 데이터 정리가 가능해 보입니다.

aics-api/src/main/java/kgu/developers/api/comment/application/CommentFacade.java (6)

18-20: Facade 계층을 통한 트랜잭션 범위 설정이 유용해 보입니다.

@Transactional을 Facade 계층에 적용하여 비즈니스 흐름을 한 번에 관리하면서, Command/Query 서비스를 깔끔하게 호출하는 구조가 유지보수에 도움이 됩니다.


26-29: createComment에서 DTO 변환과 Command 호출 간 구분이 명확합니다.

CommentRequest에서 필요한 정보를 추출해 CommentCommandService를 바로 호출하는 점이 좋습니다. 반환된 ID를 다시 DTO로 감싸 응답하는 구조가 일관성이 있습니다.


31-34: getComments 메서드에서 Query 서비스를 적절히 호출합니다.

조회 로직을 Facade에서 단순하게 유지하고, 목록을 응답 DTO로 변환하는 구성이 좋습니다.


36-40: 댓글 수정 시 예외 처리가 필요할 수 있습니다.

이미 삭제된 댓글을 수정하려 할 때 등 예외 상황에 대한 논의가 필요합니다. CommentQueryService.getById에서 예외가 발생하더라도, 필요에 따라 로그나 사용자 메시지 처리가 있으면 좋습니다.


41-44: 댓글 삭제 로직이 Facade와 Command 간 역할 구분이 선명합니다.

이전 단계에서 조회하고, 이후 Command를 호출하는 방식이 유지보수 측면에서 명확합니다.


46-48: getLastCleanupRunTime 메서드는 임의의 외부 상태 조회 구현으로 보입니다.

스케줄링 서비스의 동작 시점을 조회하여 응답하는 방식으로, Comment 관리 기능과는 별도 모듈로 적절하게 분리된 것으로 판단됩니다.

aics-api/src/main/java/kgu/developers/api/comment/presentation/CommentController.java (4)

36-36: CommentFacade 의존성 주입으로 컨트롤러가 간결해졌습니다.

CommentService 대신 CommentFacade를 사용하여 종합적인 로직을 위임하는 구조로 변경된 점이 모듈 분리에 부합합니다.


47-47: createComment 응답 처리 로직이 명확합니다.

Facade에서 CommentPersistResponse를 반환받아 201 상태 코드로 응답을 보내는 형태가 REST API 규약에 적합합니다.


61-61: 댓글 수정 시 예외 상황에 대한 처리 방안 점검이 필요합니다.

Facade에서 예외를 던지게 되면 컨트롤러 레벨에서 어떤 메시지를 반환할지 협의가 필요할 수 있습니다.


87-87: 댓글 삭제 API가 PATCH 메서드를 사용하는 점에 대한 의견이 필요합니다.

일반적으로 HTTP DELETE 메서드를 쓰는 경우도 많습니다. API 스펙 협의에 따라 변경 가능성을 검토해 보길 권장합니다.

aics-api/src/main/java/kgu/developers/api/lab/presentation/LabController.java (2)

3-6: [임포트 문 관련 안내]
해당 임포트들은 컨트롤러 계층에서 사용되는 Spring Web 및 HTTP 응답 처리를 위한 표준 라이브러리를 잘 포함하고 있습니다. 별다른 문제는 없어 보입니다.


13-13: [LabFacade 임포트 확인]
LabService 대신 LabFacade를 임포트하여 기존 서비스 로직을 파사드 레이어로 추상화하는 구조 변경이 반영되었습니다. 다른 클래스 혹은 계층에서 LabFacade를 호출할 때 이름 충돌이나 의존성 문제는 없는지 검토 부탁드립니다.

aics-admin/src/main/java/kgu/developers/admin/config/SwaggerConfig.java (2)

22-24: [SwaggerConfig 클래스 생성]
해당 설정 클래스를 통해 Admin 모듈의 Swagger 문서화를 진행하는 점이 명확합니다. @Configuration@RequiredArgsConstructor 설정이 적절히 배치되어 있고, 내부 bean 주입 방식을 통해 환경설정(Environment)을 받아오는 구조가 유지되고 있습니다.


66-72: [SecurityScheme 설정]
JWT 스키마 설정이 잘 정의되어 있습니다. Bearer 타입과 포맷을 명시하여 API 보안 인증 과정을 자동문서화할 수 있습니다. 다른 보안 방식이 함께 필요하다면, addSecuritySchemes에 추가 등록을 고려해주세요.

aics-api/src/main/java/kgu/developers/api/post/presentation/PostController.java (3)

19-19: [PostFacade 의존성 주입 확인]
기존 PostServicePostFacade로 교체되었습니다. 도메인 로직이 파사드로 이관된 만큼, 해당 클래스 내부에서 여러 도메인 서비스를 연계하여 호출하는지 확인해 주세요.


44-44: [게시글 조회 로직 변경]
postFacade.getPostsByKeywordAndCategory를 통해 게시글 목록을 페이징으로 가져오는 로직이 명확합니다. 기존 코드 대비 커맨드 로직이 제거된 것으로 보이는데, 관리자 API로 기능이 이전되었는지 확인해 주세요.


58-58: [게시글 상세 조회 부분]
postFacade.getPostByIdWithPrevAndNext(postId) 메서드 호출을 통해 이전·다음 게시글을 함께 조회하는 로직이 간결합니다. 필요할 경우, 조회 전후 데이터 검증(예: 게시글 상태/삭제 여부)을 관리자 쪽 로직과 일관성 있게 유지하는지 확인 바랍니다.

aics-admin/src/main/java/kgu/developers/admin/lab/presentation/LabAdminController.java (1)

27-31: [LabAdminController 구조 점검]
@RestController, @RequiredArgsConstructor, @RequestMapping("/api/v1/labs") 등의 설정이 잘 어우러져 있습니다. Admin 전용 API라는 점이 명확히 분리되어, 기존 API와 충돌 문제도 방지됩니다.

aics-domain/src/main/java/kgu/developers/domain/lab/domain/LabRepository.java (1)

13-13: [deleteById로의 변경 확인]
void deleteById(Long id)로 변경되어 ID 기반 삭제가 명확히 드러납니다. 엔티티 객체를 직접 전달받던 방식에서 ID만 사용하는 방식이므로, 트랜잭션 범위나 엔티티 영속성 처리 흐름도 함께 검토해 주세요.

aics-domain/src/main/java/kgu/developers/domain/user/exception/UserIdDuplicateException.java (1)

1-3: 패키지 구조와 예외 코드 변경이 유효해 보입니다.
예외 코드 전용 클래스(UserDomainExceptionCode)로 이동하여 도메인 레이어에 맞는 구조로 재정비한 점이 합리적입니다.

aics-domain/src/main/java/kgu/developers/domain/user/exception/UserNotAuthenticatedException.java (2)

1-3: API 계층에서 도메인 계층으로 이동 및 예외 코드 분리
UserNotAuthenticatedException을 도메인 전용 예외로 재배치하여, 도메인 논리에 집중된 책임이 더 명확해졌습니다.


10-10: 예외 코드 상수 사용
USER_NOT_AUTHENTICATED 상수를 통해 예외를 더욱 직관적으로 표현하고 있습니다.

aics-admin/src/main/java/kgu/developers/admin/config/InfraConfig.java (1)

9-16: JPA 및 프로퍼티 설정을 위한 새 구성 클래스
새로운 InfraConfig 파일을 통해 JPA, JPA Auditing, Properties 설정이 모듈화되어 있습니다.

  • @Configuration(proxyBeanMethods = false)로 성능을 최적화하고,
  • @ComponentScan 범위를 명시적으로 설정하여 필요 컴포넌트만 스캔하도록 구성한 점이 합리적입니다.
aics-domain/src/main/java/kgu/developers/domain/file/FileSaveService.java (2)

10-13: 파일 저장 서비스 클래스의 추가
FileSaveService가 파일 저장 로직을 캡슐화해, Controller 혹은 Facade 레벨에서 활용하기에 적합합니다.


15-19: 파일 엔티티 생성 및 저장 로직
MultipartFile 메서드를 활용해 엔티티를 생성하고, FileRepository로 저장하는 흐름이 직관적이며 확장 가능성이 높습니다.

aics-api/src/main/java/kgu/developers/api/lab/application/LabFacade.java (2)

13-15: 주의: @transactional(readOnly = true) 사용 시 데이터 변경 불가
트랜잭션 옵션을 읽기 전용으로 설정하면 추가적인 데이터 변경(쓰기) 작업이 발생할 경우 예외가 발생할 수 있습니다. Facade 레벨에서 쓰기 작업이 필요하다면 별도의 메서드를 분리하거나 readOnly 옵션을 해제하는 별도 트랜잭션 설정이 필요합니다.


19-22: 적절한 메서드 명과 반환 타입
getLabs() 메서드는 직관적인 이름으로, Lab 목록을 조회하여 DTO 형태로 변환하는 로직이 깔끔하게 분리되었습니다. 필요한 필터 조건이나 추가 파라미터가 있다면 추후 확장성에 유의해 주세요.

aics-domain/src/main/java/kgu/developers/domain/lab/application/command/LabCommandService.java (2)

14-17: 생성 전 중복 체크 필요성 검토
createLab() 호출 시 name, loc, site가 동일한 Lab이 이미 존재하는지 확인하는 로직이 없다면, 중복 레코드가 저장될 우려가 있습니다. 도메인 요구사항에 따라 중복 방지 처리를 고려해 주세요.


25-27: 엔티티 삭제 시 예외 처리 확인
deleteLabById()에서 해당 ID가 존재하지 않을 경우 발생할 수 있는 예외 상황 또는 삭제 이력을 누락해도 되는지 검토가 필요합니다. 도메인 규칙 또는 감사 로그 목적이라면 이에 맞게 보완이 필요할 수 있습니다.

aics-admin/src/main/java/kgu/developers/admin/post/presentation/request/PostRequest.java (1)

1-1: 패키지 변경 확인
package kgu.developers.admin.post.presentation.request;로 변경되어, 관리자 기능에 적합한 패키지 구조로 보입니다. 특이점이나 충돌되는 클래스가 없는지 검토해 주세요.

aics-admin/src/main/java/kgu/developers/admin/file/application/FileAdminFacade.java (5)

1-1: 패키지 구조 리팩터링 확인
프로젝트 구조 상 admin.file.application 패키지로 이동하신 것은 모듈별 책임 분리에 적절해 보입니다.


6-7: 필요한 의존성만 명확히 import
FilePathResponse, FileSaveService 등 필요한 클래스만 깔끔히 import하셨습니다. 추가 import가 누락되거나 불필요하게 포함되지 않은지 확인 부탁드립니다.


16-16: 클래스 이름 및 접근 제어
public class FileAdminFacade로 네이밍을 변경하면서 관리자 전용 파일 로직을 잘 분리하셨습니다. 접근 제어 및 책임이 명확해 보입니다.


18-18: fileSaveService 의존성 주입 확인
fileSaveServicefinal로 선언하여 생성자 주입 방식을 사용하신 점이 좋습니다. 필수 의존성임을 명확히 표현합니다.


22-22: 🛠️ Refactor suggestion

파일 저장 로직의 예외 처리 필요성
fileSaveService.saveFile(file, storedPath) 호출 시 예외가 발생할 경우를 대비한 예외 처리나 에러 핸들링이 필요해 보입니다. 파일 저장 실패 시 반환 로직도 함께 고려해 주세요.

aics-admin/src/main/java/kgu/developers/admin/lab/application/LabAdminFacade.java (5)

3-11: import 및 의존성 구조
LabRequest, LabPersistResponse, LabCommandService, LabQueryService 등을 적절히 import하여 가독성이 높습니다. 다만 현재 import 목록에서는 필요하지 않은 클래스가 추가로 포함되었는지 혹은 누락되었는지 확인 부탁드립니다.


13-15: 클래스 레벨 어노테이션
@Component, @Transactional, @RequiredArgsConstructor를 함께 사용해 트랜잭션 범위를 Facade 단에서 관리하신 점이 좋습니다. 모듈 내 서비스 간 트랜잭션 전파가 적절히 이뤄지는지 확인 필요합니다.


16-18: LabAdminFacade 필드 주입
private final LabCommandService labCommandService; / private final LabQueryService labQueryService;로 명확하게 책임을 분리하셨습니다. 향후 단위 테스트 시 Mock 주입 등에도 유리합니다.


20-23: createLab 메서드의 반환 타입
LabPersistResponse를 즉시 반환하여 생성된 Lab의 식별자를 전달하는 방식이 간결합니다. 필요 시, 추가 정보를 함께 반환해야 하는지 고려해볼 수 있습니다.


30-33: deleteLab 메서드 호출 방식
labCommandService.deleteLabById(id)를 통해 라ボ 삭제를 단순화하셨습니다. 해당 메서드 내부에서 존재하지 않는 ID에 대한 예외 처리가 되는지 다시 한번 확인 부탁드립니다.

aics-domain/src/main/java/kgu/developers/domain/post/application/command/PostCommandService.java (3)

12-16: 클래스 선언 및 어노테이션 구성
@Service, @RequiredArgsConstructor로 서비스 레이어를 깔끔히 구성하셨습니다. User, Post 리소스를 함께 다루므로 트랜잭션 범위를 명확히 관리해 주세요.


30-32: 고정(Post Pin) 상태 토글
togglePinned() 메서드를 통해 상태를 뒤집는 방식이 깔끔합니다. UI와의 동기화가 필요한지 여부(프론트와 실시간 반영 등)는 별도 검토 부탁드립니다.


34-36: 조회수 증가 로직
increaseViews로 단순 증가 처리만 수행하셨습니다. 여러 쓰레드에서 동시에 이 메서드가 호출될 때 동시성 문제가 없는지 확인 부탁드립니다.

aics-api/src/main/java/kgu/developers/api/user/application/UserFacade.java (2)

21-22: UserQueryService와 UserCommandService 분리
조회와 명령 기능을 분리해 각각 주입받으신 점이 CQRS 구조에 부합합니다. 가독성과 책임 분리가 좋아 보입니다.


35-37: getUserDetail 메서드의 보안 고려
userQueryService.getUserDetail() 호출 시 민감 정보가 노출되지 않는지 확인 부탁드립니다. 응답 객체의 범위를 다시 한번 점검해 주세요.

aics-admin/src/main/java/kgu/developers/admin/post/application/PostAdminFacade.java (4)

14-19: [필드 주입 방식 확인]
클래스의 의존성 주입 방식을 생성자를 통한 private final 필드로 사용하셨네요. Spring에서 권장하는 방식이며, 유지보수와 테스트 작성에도 용이합니다.


26-30: [트랜잭션 범위 주의]
@Transactional을 사용하여 updatePost 메서드를 묶으셨습니다. postQueryService.getById(postId)에서 예외가 발생하거나, 도중에 다른 예외가 발생할 경우 롤백이 잘 동작하는지 확인해주세요.


32-36: [게시물 고정 해제 패턴 확인]
togglePostPinStatus 메서드 사용 시, 현재 게시물의 핀 상태를 토글하는 로직을 postCommandService가 정상 처리하는지 테스트 케이스에서 점검해 보시길 권장드립니다.


38-42: [삭제 로직 점검]
deletePost 구현 시, 데이터가 완전히 삭제되는지 혹은 소프트 삭제를 적용하는지 확인하세요. 동일 도메인 내에 삭제 로직이 일관성 있게 적용되어야 합니다.

aics-api/src/testFixtures/java/mock/TestContainer.java (2)

8-9: [파사드 주석 처리 주의]
PostFacadeUserFacade가 주석 처리되어 있어 현재는 실제 객체를 사용하지 못하는 상태입니다. 추후 테스트에서 Facade를 활용하려면 주석을 해제하고 의존관계를 보완해주세요.


33-33: [주석 참고]
@Builder를 통해 AuthService 인스턴스를 생성할 때, 실제 userFacade를 주입하도록 수정할 계획인지 확인 부탁드립니다. 그렇지 않다면 주석을 제거하거나 다른 명시적인 방식으로 구현해주세요.

aics-domain/src/main/java/kgu/developers/domain/post/application/query/PostQueryService.java (2)

22-25: [페이징 조회 로직 검증]
keywordcategory가 null이 들어올 가능성은 없는지 확인이 필요합니다. 검색 필터 로직에서 null-safe 처리를 고려해 주세요.


39-43: [게시물 조회 예외 처리]
getById에서 삭제된 게시물을 제외하고 불러오도록 필터링하고 있습니다. 이 예외 처리 로직이 다른 서비스 계층과도 일관되게 동작하는지 확인해 보세요.

aics-api/src/main/java/kgu/developers/api/config/SwaggerConfig.java (2)

1-1: [ko-KR] 패키지 구조 변경 확인
패키지를 kgu.developers.infra.config에서 kgu.developers.api.config로 변경하여, SwaggerConfig가 API 영역에 더욱 명확히 속하게 되었습니다. 변경된 패키지 구조가 다른 클래스 및 설정 파일과 충돌하지 않는지 확인이 필요합니다.


25-25: [ko-KR] AicsConfig 제거에 따른 영향도 점검
이전에는 AicsConfig를 구현했으나, 현재는 제거되었습니다. 혹시 AicsConfig 인터페이스에서 제공하던 공통 설정이나 계약이 있었다면, 해당 로직이 누락되지 않았는지 점검이 필요합니다.

aics-api/src/main/java/kgu/developers/api/auth/application/AuthService.java (3)

7-7: [ko-KR] UserFacade 임포트 변경 주의
UserService 대신 UserFacade를 사용하던 기존 로직이 있었나요? 현재 AuthService에서는 UserFacade가 아닌 UserQueryService를 사용하고 있으므로, facade와 queryService의 사용처를 명확히 구분해 주세요.


11-11: [ko-KR] UserQueryService 추가 확인
UserQueryService를 새로 임포트하셨는데, 읽기 전용(쿼리) 역할을 담당하는 클래스가 맞다면 적절한 CQRS 분리가 이루어진 것으로 보입니다.


35-35: [ko-KR] userQueryService.getUserById(userId) 호출 검증
로그인 시 사용자 조회 로직이 userQueryService를 통해 이루어집니다. 만약, 로그인 로직 내에서 비즈니스 검증 로직(예: 사용자 상태, 탈퇴 여부 등)이 필요하다면, QueryService만으로 충분한지 확인해 보세요.

aics-domain/src/main/java/kgu/developers/domain/post/domain/Post.java (1)

87-90: [ko-KR] updateCategory 메서드 추가
카테고리를 동적으로 변경할 수 있도록 메서드가 추가되었습니다. 이 로직이 게시글의 다른 속성(예: 조회수, 작성자 등)에 영향을 주지 않는지, 비즈니스 로직과의 정합성을 재검토하시기 바랍니다.

aics-api/src/main/java/kgu/developers/api/user/presentation/UserController.java (6)

5-11: [ko-KR] API 매핑 경로 및 메서드 명확화
@GetMapping, @PatchMapping, @PostMapping 등을 각각 사용하는 것은 RESTful 관점에서 적절해 보입니다. 다만, 경로 설계(/api/v1/users, /my, /signup)가 다른 컨트롤러와 일관성을 유지하는지 확인하세요.


22-22: [ko-KR] UserDetailResponse 임포트 경로 변경 반영
새로운 패키지 경로(kgu.developers.domain.user.application.response)로 변경된 것으로 보입니다. 해당 DTO가 적절히 분리되어 있는지, 도메인 엔티티와의 결합도가 높지 않은지 확인이 필요합니다.


42-42: [ko-KR] 회원 가입 로직 검증
userFacade.createUser(request)가 반려 로직이나 에러 처리를 충분히 수행하는지 확인이 필요합니다. 예: 중복 사용자, 유효하지 않은 파라미터 등


46-50: [ko-KR] 마이페이지 조회 API
이 메서드는 본인의 정보를 조회하는 기능을 제공합니다. 인증/인가 절차(예: SecurityContext 기반)와 연결되어 있는지, 필요한 권한 체크가 누락되지 않았는지 확인하세요.


53-53: [ko-KR] userFacade.getUserDetail() 호출 로직
이 로직은 현재 로그인한 사용자 정보만 반환하는지, 아니면 임의의 사용자 정보를 가져오는지 확인하십시오.


66-66: [ko-KR] 회원 정보 수정 API - Validation 점검
userFacade.updateUser(request)가 실제로 유효성 검증(전화번호 형식, 이메일 형식 등)을 수행하는지 확인하세요. 수정 로직이 도메인 객체에 올바르게 반영되는지도 중요합니다.

aics-api/src/testFixtures/java/user/application/UserServiceTest.java (2)

11-11: [임포트 변경]
UserFacade를 새로 임포트함으로써 UserService 대신 UserFacade를 사용하도록 리팩터링된 점을 확인했습니다. 다른 테스트나 클래스에서 연관된 임포트 충돌은 없는지 확인 부탁드립니다.
[approve]


Line range hint 19-119: [테스트 전체 주석 처리]
UserServiceTest 클래스 전체가 주석(/* ... */)으로 감싸져 있어 테스트가 전혀 동작하지 않습니다. 그대로 유지할 필요가 없으면 주석을 제거하여 실제 테스트를 수행하거나, 불필요하다면 파일에서 제거하는 방안을 고려해주세요.

aics-api/src/testFixtures/java/lab/application/LabServiceTest.java (2)

7-8: [임포트 변경]
LabFacadeLabNotFoundException 관련 임포트가 추가되었습니다. 외부에서 사용하는 위치와 충돌 가능성이 없는지 확인 부탁드립니다.
[approve]


Line range hint 20-129: [테스트 전체 주석 처리]
클래스 전체가 주석 처리되어 있어 테스트가 실행되지 않습니다. 이미 다른 방식으로 테스트 중이라면 정리하거나, 필요한 경우 주석을 해제하여 테스트 코드를 정상 수행할 수 있도록 논의해 보세요.

aics-admin/src/main/java/kgu/developers/admin/file/presentation/FileAdminController.java (6)

1-1: [패키지 변경]
kgu.developers.admin.file.presentation 패키지로 이동하여 관리자 전용 파일 업로드 컨트롤러임을 명확히 표시하고 있습니다. 모듈 분리에 따른 구조상의 이점이 잘 드러나므로 유지하셔도 좋겠습니다.


22-23: [임포트 추가]
FileAdminFacadeFilePathResponse 관련 임포트가 새로 추가되었습니다. 의존 관계가 깨지지 않고 정상적으로 주입되는지 확인 부탁드립니다.
[approve]


30-31: [클래스명 & DI 변경]
FileAdminController로 클래스명이 수정되면서 fileAdminFacade를 사용하는 구조가 명확해졌습니다. 관리 기능을 전담하는 컨트롤러로 목적이 분명해져 유지보수 측면에서 긍정적인 변화로 보입니다.


44-44: [파일 업로드 로직 적용]
fileAdminFacade.saveFile(...)를 통해 게시글 첨부 파일을 저장하도록 변경되었습니다. 파사드 계층에서 예외 처리나 파일 유효성 검사를 충분히 수행하는지 확인 부탁드립니다.


59-59: [소개글 파일 업로드 로직 적용]
소개글 이미지 저장이 fileAdminFacade.saveFile(...)를 통해 일관되게 적용되었습니다. 동일 로직을 사용하는 부분이 많아, 재사용이 용이해 보입니다.


74-74: [캐러셀 파일 업로드 로직 적용]
캐러셀 이미지 또한 동일한 방식으로 파일을 저장하도록 변경하셨습니다. 이 로직에 대해 오류 처리는 어떻게 진행되는지 확인 부탁드립니다.

aics-api/src/testFixtures/java/auth/application/AuthServiceTest.java (2)

11-11: [임포트 변경]
UserService 임포트가 사라지고 UserFacade 임포트가 추가되었습니다. 전반적으로 AuthService 내에서 UserFacade가 올바르게 주입되는지 한번 더 점검해 주세요.


35-36: [AuthService 빌더 변경]
AuthService에서 userFacade를 주입받도록 변경되었습니다. 새로운 파사드 구조에 맞춰 의존성을 적절히 변환한 점이 좋습니다. 다만, 로그인 흐름이나 예외 처리 로직이 제대로 이어지는지는 추가 테스트가 필요할 수 있습니다.
[approve]

aics-admin/src/main/java/kgu/developers/admin/post/presentation/PostAdminController.java (1)

54-60: 요청 Param Validation 로직 확인
@PathVariable @Positive Long postId@RequestBody PostRequest request에 대한 유효성 검증이 적절히 이뤄지고 있습니다. 다만, Controller 테스트 코드에서 예외 케이스 테스트가 별도로 있는지 확인 부탁드립니다.

settings.gradle (1)

2-2: 하위 모듈 추가 확인
'aics-admin' 모듈이 성공적으로 추가되었습니다. 빌드나 배포 시 의존성 문제가 없는지 다른 모듈들과의 연결 상태를 최종 확인 부탁드립니다.

aics-admin/build.gradle (1)

1-3: Spring Boot JAR 생성 설정 확인
bootJarjar 활성화 설정으로 인해 배포 시 별도의 JAR 파일이 생성됩니다. 서버 실행환경에서 충돌 없이 잘 동작하는지 확인 필요합니다.

aics-admin/src/main/resources/application-prod.yml (1)

12-15: Redis 환경 변수 검증 필요

Redis 설정이 환경 변수를 사용하고 있습니다. 프로덕션 배포 전에 다음 사항을 확인해주세요:

  • REDIS_PASSWORD 환경 변수가 설정되어 있는지 검증
  • Redis 연결 보안을 위한 SSL/TLS 설정 고려

또한 파일 끝에 개행이 누락되어 있습니다. 추가해주세요.

🧰 Tools
🪛 yamllint (1.35.1)

[error] 15-15: no new line character at the end of file

(new-line-at-end-of-file)

aics-admin/src/main/resources/db/data.sql (1)

28-36: 파일 경로 검증 필요

file_entity 테이블의 물리적 경로에 대해 다음 사항을 확인해주세요:

  1. 파일 시스템 접근 권한
  2. 경로 트래버설 취약점 방지
  3. 스토리지 용량 계획
✅ Verification successful

Let me gather more information about the file handling implementation.


Let me check one more aspect of the implementation to verify security measures.


파일 시스템 보안 검증 완료

파일 처리 시스템이 다음과 같은 보안 조치들을 적절히 구현하고 있습니다:

  1. 경로 정규화 및 검증

    • StringUtils.cleanPath를 통한 파일명 정리
    • normalize()를 사용한 경로 정규화
    • 절대 경로 변환 및 검증
  2. 파일 확장자 보안

    • disallowedExtensions 설정을 통한 위험 확장자 차단
    • 확장자 검증 로직 구현
  3. 스토리지 구성

    • 설정 기반의 업로드 경로 관리 (${user.dir}/cloud)
    • 디렉토리 자동 생성 및 권한 관리

data.sql의 파일 경로들은 애플리케이션의 파일 처리 시스템과 호환되며, 적절한 보안 조치가 되어 있습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 파일 경로 패턴 검사
echo "Checking file paths..."
rg -g '*.java' 'new File\(.*\)' 
rg -g '*.java' 'Paths\.get\(.*\)'

Length of output: 294


Script:

#!/bin/bash
# Check file storage related implementations
echo "Checking file storage implementation..."
rg -g '*.java' -A 10 'class FileStorageServiceImpl'

# Check file path properties configuration
echo -e "\nChecking file path properties..."
fd -e java -e yml -e properties | xargs rg 'upload.*path'

# Check file entity related code
echo -e "\nChecking file entity implementation..."
rg -g '*.java' -A 5 'class FileEntity'

Length of output: 2855


Script:

#!/bin/bash
# Check file storage service implementation details
echo "Checking file storage security measures..."
rg -g '*.java' -A 20 'store\(.*MultipartFile'

# Check for path normalization and validation
echo -e "\nChecking path validation..."
rg -g '*.java' 'normalize|getCanonicalPath|isAbsolute|startsWith'

# Check file extension validation
echo -e "\nChecking extension validation..."
rg -g '*.java' -B 2 -A 5 'disallowedExtensions'

Length of output: 9238

Comment on lines +1 to +4
spring:
jpa:
hibernate:
ddl-auto: update
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

필수 데이터베이스 설정이 누락됨

로컬 환경 설정에 다음과 같은 필수 속성들이 누락되어 있습니다:

  • 데이터베이스 연결 정보 (URL, 사용자명, 비밀번호)
  • JPA 추가 설정 (show-sql, database-platform 등)
  • 커넥션 풀 설정

다음과 같은 설정을 추가하는 것을 제안드립니다:

 spring:
   jpa:
     hibernate:
       ddl-auto: update
+    show-sql: true
+    properties:
+      hibernate:
+        format_sql: true
+  datasource:
+    url: jdbc:mysql://localhost:3306/aics
+    username: root
+    password: root
+    hikari:
+      maximum-pool-size: 10
+      minimum-idle: 5
📝 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.

Suggested change
spring:
jpa:
hibernate:
ddl-auto: update
spring:
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
format_sql: true
datasource:
url: jdbc:mysql://localhost:3306/aics
username: root
password: root
hikari:
maximum-pool-size: 10
minimum-idle: 5
🧰 Tools
🪛 yamllint (1.35.1)

[error] 4-4: no new line character at the end of file

(new-line-at-end-of-file)


💡 Codebase verification

데이터베이스 스키마 설정의 환경별 일관성 검토 필요

현재 환경별 ddl-auto 설정이 다음과 같이 구성되어 있습니다:

  • 운영/기본 환경: validate (적절함)
  • 개발/로컬 환경: update (위험 요소)

update 설정이 개발 및 로컬 환경에서 일관되게 사용되고 있어 의도적인 설정으로 보이나, 다음 사항을 고려해주시기 바랍니다:

  • 개발 환경(application-dev.yml)에서도 update를 사용하는 것은 위험할 수 있습니다. 여러 개발자가 동시에 접근할 경우 예기치 않은 스키마 변경이 발생할 수 있습니다.
  • aics-adminaics-api 모듈 모두 동일한 패턴을 보이고 있어, 이는 시스템 전반의 설정으로 보입니다.

권장사항:

  • 개발 환경은 validate로 변경하고, 스키마 변경이 필요한 경우 명시적인 마이그레이션 스크립트를 사용하는 것이 안전합니다.
  • 로컬 환경에서만 update를 제한적으로 사용하시기 바랍니다.
🔗 Analysis chain

데이터베이스 스키마 자동 업데이트 설정에 대한 보안 고려사항

ddl-auto: update 설정은 개발 환경에서는 편리하지만, 다음과 같은 위험이 있습니다:

  • 의도하지 않은 스키마 변경으로 인한 데이터 손실 가능성
  • 성능 저하 (애플리케이션 시작 시 스키마 검사)
  • 동시 실행되는 여러 인스턴스 간의 충돌 가능성

로컬 환경에서만 사용하고, 다른 환경(개발, 스테이징, 운영)에서는 validate 모드를 사용하는 것을 권장드립니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: 다른 환경의 설정 파일에서 ddl-auto 설정 확인

echo "다른 환경의 ddl-auto 설정 확인:"
rg -A 1 "ddl-auto:" "aics-admin/src/main/resources/application-*.yml"

Length of output: 212


Script:

#!/bin/bash
# Check all yml files in the project
echo "모든 YML 파일 검색:"
fd -e yml -e yaml

echo -e "\nddl-auto 설정이 있는 파일 검색:"
rg -l "ddl-auto"

echo -e "\n각 파일의 ddl-auto 설정 확인:"
rg -A 1 "ddl-auto" 

Length of output: 2059

🧰 Tools
🪛 yamllint (1.35.1)

[error] 4-4: no new line character at the end of file

(new-line-at-end-of-file)

Comment on lines +18 to +22
public String createUser(String userId, String password, String name, String email, String phone, Major major) {
validateDuplicateId(userId);
User user = User.create(userId, password, name, email, phone, major, bCryptPasswordEncoder);
return userRepository.save(user).getId();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

사용자 생성 시 트랜잭션 범위를 명확히 지정하는 것 권장

createUser 메서드는 DB에 사용자 정보를 저장하기 때문에, 메서드 단위의 트랜잭션이 반드시 보장되어야 합니다. @Transactional 적용 여부를 검토하시길 권장드립니다.

+import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
public class UserCommandService {
+   @Transactional
    public String createUser(...) {
        // ...
    }
}

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +30 to +35
data:
redis:
host: ${REDIS_HOST:localhost}
port: ${REDIS_PORT:6379}
password: ${REDIS_PASSWORD}

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Redis 비밀번호에 개발 환경용 기본값이 필요합니다

현재 REDIS_PASSWORD 환경 변수에 기본값이 설정되어 있지 않아 개발 환경에서 문제가 발생할 수 있습니다.

  redis:
    host: ${REDIS_HOST:localhost}
    port: ${REDIS_PORT:6379}
-    password: ${REDIS_PASSWORD}
+    password: ${REDIS_PASSWORD:}
📝 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.

Suggested change
data:
redis:
host: ${REDIS_HOST:localhost}
port: ${REDIS_PORT:6379}
password: ${REDIS_PASSWORD}
data:
redis:
host: ${REDIS_HOST:localhost}
port: ${REDIS_PORT:6379}
password: ${REDIS_PASSWORD:}

Comment on lines +49 to +51
jwt:
issuer: ${JWT_ISSUER}
secret_key: ${JWT_SECRET_KEY}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

JWT 설정에 개발 환경용 기본값 추가가 필요합니다

JWT 설정에 기본값이 없어 개발 환경 설정이 번거로울 수 있습니다.

jwt:
-  issuer: ${JWT_ISSUER}
-  secret_key: ${JWT_SECRET_KEY}
+  issuer: ${JWT_ISSUER:aics-admin-dev}
+  secret_key: ${JWT_SECRET_KEY:your-dev-secret-key-min-32-chars}
📝 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.

Suggested change
jwt:
issuer: ${JWT_ISSUER}
secret_key: ${JWT_SECRET_KEY}
jwt:
issuer: ${JWT_ISSUER:aics-admin-dev}
secret_key: ${JWT_SECRET_KEY:your-dev-secret-key-min-32-chars}

Comment on lines +36 to +41
file:
url: /cloud
upload-path: ${user.dir}/cloud
secret-key: ${FILE_SECRET_KEY}
disallowed-extensions: exe, bat, sh, cmd, js, html, jsp, php, asp, aspx, dll, so, ps1, vbs, msi, htaccess, phtml, jar, war

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

파일 업로드 경로 및 보안 설정 개선이 필요합니다

  1. ${user.dir}을 사용한 업로드 경로는 서버 실행 위치에 따라 달라질 수 있어 안정성이 떨어집니다.
  2. 파일 시크릿 키에 기본값이 없어 개발 환경 설정이 어려울 수 있습니다.
file:
   url: /cloud
-   upload-path: ${user.dir}/cloud
+   upload-path: ${FILE_UPLOAD_PATH:/tmp/aics-admin/cloud}
-   secret-key: ${FILE_SECRET_KEY}
+   secret-key: ${FILE_SECRET_KEY:your-dev-secret-key}
   disallowed-extensions: exe, bat, sh, cmd, js, html, jsp, php, asp, aspx, dll, so, ps1, vbs, msi, htaccess, phtml, jar, war
📝 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.

Suggested change
file:
url: /cloud
upload-path: ${user.dir}/cloud
secret-key: ${FILE_SECRET_KEY}
disallowed-extensions: exe, bat, sh, cmd, js, html, jsp, php, asp, aspx, dll, so, ps1, vbs, msi, htaccess, phtml, jar, war
file:
url: /cloud
upload-path: ${FILE_UPLOAD_PATH:/tmp/aics-admin/cloud}
secret-key: ${FILE_SECRET_KEY:your-dev-secret-key}
disallowed-extensions: exe, bat, sh, cmd, js, html, jsp, php, asp, aspx, dll, so, ps1, vbs, msi, htaccess, phtml, jar, war

Comment on lines +32 to +45
private final LabAdminFacade labAdminFacade;

@Operation(summary = "연구실 생성 API", description = """
- Description : 이 API는 연구실을 생성합니다.
- Assignee : 박민준
""")
@ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = LabPersistResponse.class)))
@PostMapping
public ResponseEntity<LabPersistResponse> createComment(
@Valid @RequestBody LabRequest request
) {
LabPersistResponse response = labAdminFacade.createLab(request);
return ResponseEntity.status(CREATED).body(response);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

[연구실 생성 로직]
createComment 메서드로 연구실 등록을 처리하고 있지만 메서드 명이 createComment로 되어 있습니다. 도메인 개념상 ‘연구실 생성’이므로, 메서드 명 및 주석이 일관되도록 createLab 등으로 변경하는 방안을 고려해 주세요.

- public ResponseEntity<LabPersistResponse> createComment(
+ public ResponseEntity<LabPersistResponse> createLab(
📝 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.

Suggested change
private final LabAdminFacade labAdminFacade;
@Operation(summary = "연구실 생성 API", description = """
- Description : API는 연구실을 생성합니다.
- Assignee : 박민준
""")
@ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = LabPersistResponse.class)))
@PostMapping
public ResponseEntity<LabPersistResponse> createComment(
@Valid @RequestBody LabRequest request
) {
LabPersistResponse response = labAdminFacade.createLab(request);
return ResponseEntity.status(CREATED).body(response);
}
private final LabAdminFacade labAdminFacade;
@Operation(summary = "연구실 생성 API", description = """
- Description : API는 연구실을 생성합니다.
- Assignee : 박민준
""")
@ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = LabPersistResponse.class)))
@PostMapping
public ResponseEntity<LabPersistResponse> createLab(
@Valid @RequestBody LabRequest request
) {
LabPersistResponse response = labAdminFacade.createLab(request);
return ResponseEntity.status(CREATED).body(response);
}

Comment on lines +19 to +23
public void updateLab(Lab lab, String name, String loc, String site) {
lab.updateName(name);
lab.updateLoc(loc);
lab.updateSite(site);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

업데이트 시 유효성 검증 필요
updateLab() 메서드는 단순히 엔티티 필드를 변경하고 있지만, name, loc, site 파라미터가 유효한지 사전에 검증하는 로직은 보이지 않습니다. 사용자의 입력 범위나 필수 조건 등을 확인해 보시기 바랍니다.

Comment on lines +24 to +28
public UserPersistResponse createUser(UserCreateRequest request) {
String id = userCommandService.createUser(request.userId(), request.password(), request.name(), request.email(),
request.phone(), request.major());
return UserPersistResponse.of(id);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

createUser 메서드 파라미터 및 예외 처리
request의 userId, password, name 등 필수값들이 null이 아닌지 검사 부탁드립니다. 또한 중복 userId 등록 시 별도 예외가 필요한지 검토해 주세요.

Comment on lines +30 to +33
public void updateUser(UserUpdateRequest request) {
User user = userQueryService.me();
userCommandService.updateUserDetails(user, request.email(), request.phone());
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

updateUser 메서드에서의 사용자 조회
User user = userQueryService.me();로 본인 정보를 가져온 뒤 업데이트하는 로직이 적절합니다. 다만 유효하지 않은 사용자일 경우 예외 처리도 필요할 수 있습니다.

Comment on lines +11 to +21
-- password: password1234!
INSERT INTO "user" (id, password, name, email, phone, major, role, created_at, updated_at)
VALUES ('202412346', '$2a$10$NkQj6yk0Xh4QhKevjrOkouQBymXUgpKqmHQFnTUKRaVhDrRZf5OTG', '이한음', '[email protected]',
'010-2345-6789', 'AIT', 'SUPER', CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP),
('202412347', '$2a$10$NkQj6yk0Xh4QhKevjrOkouQBymXUgpKqmHQFnTUKRaVhDrRZf5OTG', '박민준', '[email protected]',
'010-1234-8765', 'CSE', 'USER', CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP),
('202412348', '$2a$10$NkQj6yk0Xh4QhKevjrOkouQBymXUgpKqmHQFnTUKRaVhDrRZf5OTG', '이신행', '[email protected]',
'010-3456-7890', 'SSS', 'ADMIN', CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

보안: 패스워드 노출 문제

초기 데이터에 하드코딩된 패스워드와 관련하여 다음 사항을 개선해주세요:

  1. 주석에 패스워드를 노출하지 마세요
  2. 테스트용 계정이라도 복잡한 패스워드를 사용하세요
  3. 프로덕션 배포 전에 반드시 이 패스워드를 변경하세요

Copy link
Contributor

@LeeShinHaeng LeeShinHaeng left a comment

Choose a reason for hiding this comment

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

방대한 양의 작업을 진행하시느라 많이 수고스러우셨을 것으로 생각됩니다! 정말 고생하셨어요 👍
사소한 사항 코멘트로 남겨 놓았으니 확인 부탁드려요~

@@ -0,0 +1,73 @@
package kgu.developers.admin.lab.presentation;

import static org.springframework.http.HttpStatus.*;
Copy link
Contributor

Choose a reason for hiding this comment

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

프로젝트 초반에 코드 컨벤션을 정할 때, * 사용을 지양하도록 정했던 것으로 기억합니다!
혹시 *로 수정한 이유가 있으실까요?

Copy link
Member Author

Choose a reason for hiding this comment

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

헉 제가 최근에 개발 환경이 바뀌면서 인텔리제이 설정을 빼먹은거 같아요! 수정하겠습니다 👍

String name, String email,
String phone, Major major) {
public static User create(String id, String password, String name, String email, String phone, Major major,
PasswordEncoder passwordEncoder) {
Copy link
Contributor

Choose a reason for hiding this comment

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

테스트 코드 중 User의 create 메소드를 사용하는 부분에서 에러가 발생하는 것으로 보입니다.
테스트 코드 부분에 수정이 필요할 것 같습니다!

Copy link
Contributor

@minjo-on minjo-on left a comment

Choose a reason for hiding this comment

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

대공사 하시느라 고생하셨습니다 !! 신행님이 말씀해주신 부분 작업하기 쉽도록 댓글 남겼습니다😁

@@ -23,6 +25,9 @@ public record PostRequest(
""",
requiredMode = Schema.RequiredMode.REQUIRED)
Copy link
Contributor

Choose a reason for hiding this comment

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

이 부분도 static으로 선언하여 통일성을 유지하는 것은 어떨까요? 코드 스타일의 일관성을 유지하면 유지보수성과 가독성이 향상될 것 같습니다!


import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.*;

Copy link
Contributor

Choose a reason for hiding this comment

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

이 부분도 *로 선언되어 있습니다 !

import static java.lang.String.format;
import static org.springframework.security.config.Elements.JWT;
import static java.lang.String.*;
import static org.springframework.security.config.Elements.*;

Copy link
Contributor

Choose a reason for hiding this comment

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

이 부분도 그렇습니다 !

@@ -1,39 +1,34 @@
package kgu.developers.api.user.presentation;

import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.*;

Copy link
Contributor

Choose a reason for hiding this comment

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

이부분도 그렇습니다!

package kgu.developers.domain.about.application.command;

import static kgu.developers.domain.about.domain.About.*;

Copy link
Contributor

Choose a reason for hiding this comment

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

이 부분도 그렇습니다 !


import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.HttpStatus.*;

Copy link
Contributor

Choose a reason for hiding this comment

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

here !


import kgu.developers.common.exception.CustomException;
import static kgu.developers.domain.post.exception.PostDomainExceptionCode.*;

Copy link
Contributor

Choose a reason for hiding this comment

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

here !

@@ -1,7 +1,6 @@
package kgu.developers.domain.user.exception;

import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.HttpStatus.*;

Copy link
Contributor

Choose a reason for hiding this comment

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

here !


import static kgu.developers.api.user.presentation.exception.UserExceptionCode.USER_ID_DUPLICATED;
import static kgu.developers.domain.user.exception.UserDomainExceptionCode.*;
Copy link
Contributor

Choose a reason for hiding this comment

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

here !

package kgu.developers.api.user.presentation.exception;
package kgu.developers.domain.user.exception;

import static kgu.developers.domain.user.exception.UserDomainExceptionCode.*;

Copy link
Contributor

Choose a reason for hiding this comment

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

here !

@LeeHanEum LeeHanEum merged commit 237d8b9 into develop Jan 3, 2025
2 of 3 checks passed
@LeeHanEum LeeHanEum deleted the refactor/#137-setup-admin-module branch January 3, 2025 10:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🔨refactor refactoring code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

어드민 API 모듈 분리 및 Facade 도입
3 participants