Skip to content

Feature/11 layered to hexagonal#16

Merged
coehgns merged 71 commits intomainfrom
feature/11-layered-to-hexagonal
Aug 15, 2025
Merged

Feature/11 layered to hexagonal#16
coehgns merged 71 commits intomainfrom
feature/11-layered-to-hexagonal

Conversation

@coehgns
Copy link
Copy Markdown
Contributor

@coehgns coehgns commented Jul 28, 2025

Summary by CodeRabbit

  • 신규 기능

    • 일정 관리 도메인 및 REST API, gRPC 서비스 추가: 일정 조회, 유형별 조회, 일괄 수정 기능 제공
    • JWT 기반 인증 및 Spring Security 적용, 예외 처리 및 에러 응답 구조화
    • 일정 엔티티, DTO, 예외, 매퍼 등 도메인 구조 도입 및 데이터베이스 연동
    • 일정 관련 gRPC 프로토콜 정의 및 코드 생성 지원
  • 버그 수정

    • 없음
  • 문서화

    • 각 클래스 및 주요 메서드에 KDoc 기반 설명 추가
  • 테스트

    • 기본 애플리케이션 구동 테스트 케이스 추가
  • 환경설정/빌드

    • 의존성 및 플러그인 버전 관리 구조 개선, Gradle 스크립트 및 설정 파일 정비
    • Detekt 설정 일부 변경, 불필요한 빌드 스크립트 및 테스트 파일 제거
  • 기타

    • 예외 및 에러 코드 통합 관리, 전역 예외 필터 및 핸들러 추가
    • 코드 구조화 및 모듈화, 불필요 파일 정리

@coehgns coehgns self-assigned this Jul 28, 2025
@coehgns coehgns added the Setup label Jul 28, 2025
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jul 28, 2025

Important

Review skipped

Auto 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

이 변경 사항은 기존의 단일 모듈 구조를 제거하고, casper-schedule라는 새로운 멀티 모듈 구조로 프로젝트를 재구성합니다. 빌드 스크립트와 설정 파일이 대폭 수정 및 추가되었으며, 도메인, 애플리케이션, 어댑터, 예외 처리, 보안, gRPC 및 테스트 등 전체적인 백엔드 구조가 새롭게 도입되었습니다. 기존의 엔트리포인트 및 테스트 파일 등은 삭제되었습니다.

Changes

Cohort / File(s) Change Summary
기존 빌드 및 설정 파일 삭제
build-logic/build.gradle.kts, build-logic/settings.gradle.kts, build-logic/src/main/kotlin/io/casper/build/TestClass.kt, src/main/kotlin/hs/kr/entrydsm/schedule/CasperScheduleApplication.kt, src/test/kotlin/hs/kr/entrydsm/schedule/CasperScheduleApplicationTests.kt, src/main/resources/application.properties
기존 빌드 로직, 엔트리포인트, 테스트, 프로퍼티 파일 등 단일 모듈 관련 파일 삭제
빌드 및 설정 파일 추가/수정
build.gradle.kts, settings.gradle.kts, detekt.yml
플러그인 버전 다운그레이드, Spring Boot mainClass 명시, 멀티 모듈 구조로 전환, MagicNumber 룰 비활성화 등 빌드/정적분석 설정 변경
buildSrc 기반 빌드 관리 도입
buildSrc/build.gradle.kts, buildSrc/src/main/kotlin/Dependencies.kt, buildSrc/src/main/kotlin/DependencyVersion.kt, buildSrc/src/main/kotlin/Plugin.kt, buildSrc/src/main/kotlin/PluginVersion.kt
의존성 및 플러그인 버전/ID를 중앙 집중적으로 관리하는 Kotlin 객체 추가
casper-schedule 모듈 신규 도입
casper-schedule/build.gradle.kts, casper-schedule/src/main/proto/schedule.proto
Spring Boot, gRPC, MapStruct, Protobuf 등 다양한 플러그인 및 의존성 선언, gRPC용 프로토콜 버퍼 파일 추가
애플리케이션 엔트리포인트 및 테스트 추가
casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/CasperScheduleApplication.kt, casper-schedule/src/test/kotlin/hs/kr/entrydsm/schedule/CasperScheduleApplicationTests.kt
Spring Boot 애플리케이션 진입점 및 기본 컨텍스트 로드 테스트 클래스 추가
도메인/애플리케이션/어댑터 계층 신규 구현
casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/...
Schedule 관련 DTO, 엔티티, Mapper, Repository, UseCase, Service, Facade, 예외 등 전체 계층 구조 구현
글로벌 예외 처리 및 보안 구성
casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/error/..., casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/security/...
글로벌 예외 필터/핸들러, 커스텀 예외, 에러코드, JWT 필터 및 보안 설정 등 추가
기타 설정/유틸성 클래스
casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/error/config/ConfigurationPropertiesConfig.kt
ConfigurationProperties 스캔용 설정 등 기타 보조 클래스 추가

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant ScheduleWebAdapter
    participant QueryScheduleByTypeUseCase
    participant ScheduleFacade
    participant FindSchedulePort
    participant DB

    Client->>ScheduleWebAdapter: GET /schedule?type=...
    ScheduleWebAdapter->>QueryScheduleByTypeUseCase: execute(type)
    QueryScheduleByTypeUseCase->>ScheduleFacade: getScheduleByType(type)
    ScheduleFacade->>FindSchedulePort: findByType(type)
    FindSchedulePort->>DB: DB 조회
    DB-->>FindSchedulePort: Schedule
    FindSchedulePort-->>ScheduleFacade: Schedule
    ScheduleFacade-->>QueryScheduleByTypeUseCase: Schedule
    QueryScheduleByTypeUseCase-->>ScheduleWebAdapter: ScheduleDto
    ScheduleWebAdapter-->>Client: ScheduleDto (JSON)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Poem

🐰
새로운 모듈이 퐁당,
스케줄 토끼가 뛰노네!
예외도 척척, 보안도 빵빵,
gRPC도 척척, 빌드도 깔끔!
새 출발의 발자국,
코드밭에 남기며
오늘도 당근 한입, 행복한 개발! 🥕

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/11-layered-to-hexagonal

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

‼️ IMPORTANT
Auto-reply has been disabled for this repository in the CodeRabbit settings. The CodeRabbit bot will not respond to your replies unless it is explicitly tagged.

  • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @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.

@coehgns coehgns requested a review from devizi0 July 30, 2025 06:28
@coehgns
Copy link
Copy Markdown
Contributor Author

coehgns commented Aug 2, 2025

Important

Review skipped

Auto 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.

✨ Finishing Touches
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
🪧 Tips

@coehgns coehgns closed this Aug 2, 2025
@coehgns coehgns reopened this Aug 2, 2025
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Aug 2, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

@coehgns I can help you resolve the CodeRabbit configuration issue. Let me gather information about your current configuration settings to provide specific guidance on enabling auto reviews.


🛠️ Debug Information Gathered


@coehgns 이제 문제를 정확히 파악했습니다. 현재 CodeRabbit 구성에서 자동 리뷰가 비활성화되어 있습니다.

문제 원인

현재 설정에서 다음과 같이 자동 리뷰가 비활성화되어 있습니다:

auto_review:
  enabled: false
  auto_incremental_review: false

해결 방법

옵션 1: CodeRabbit UI에서 설정 변경

  1. CodeRabbit 대시보드에 로그인
  2. 해당 리포지토리로 이동
  3. Settings > Reviews > Auto Review 섹션에서
  4. "Automatic Review" 옵션을 활성화
  5. "Automatic Incremental Review" 옵션도 활성화 (권장)

옵션 2: .coderabbit.yaml 파일 생성/수정

리포지토리 루트에 .coderabbit.yaml 파일을 생성하거나 수정하여 다음 내용을 추가:

reviews:
  auto_review:
    enabled: true
    auto_incremental_review: true

현재 PR에 대한 즉시 해결책

지금 이 PR을 리뷰받으려면 다음 명령어를 사용하세요:

@coderabbitai review

설정 변경 후 향후 PR들은 자동으로 리뷰됩니다. 추가 질문이 있으시면 언제든 말씀해 주세요!

@coehgns
Copy link
Copy Markdown
Contributor Author

coehgns commented Aug 2, 2025

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Aug 2, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

1 similar comment
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Aug 2, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coehgns
Copy link
Copy Markdown
Contributor Author

coehgns commented Aug 2, 2025

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Aug 2, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

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

♻️ Duplicate comments (1)
casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/service/QueryScheduleByTypeService.kt (1)

24-27: 잘못된 타입 입력에 대한 예외 처리가 필요합니다.

Type.valueOf(type)는 유효하지 않은 타입 문자열이 전달될 경우 IllegalArgumentException을 발생시킵니다. 이에 대한 적절한 예외 처리가 없어 클라이언트에게 명확한 오류 메시지를 제공할 수 없습니다.

다음과 같이 예외 처리를 추가하세요:

 override fun execute(type: String): ScheduleDto {
-    val schedule = scheduleFacade.getScheduleByType(Type.valueOf(type))
+    val scheduleType = try {
+        Type.valueOf(type.uppercase())
+    } catch (e: IllegalArgumentException) {
+        throw InvalidScheduleTypeException("유효하지 않은 스케줄 타입입니다: $type")
+    }
+    val schedule = scheduleFacade.getScheduleByType(scheduleType)
     return ScheduleDto(schedule.type, schedule.date)
 }
🧹 Nitpick comments (22)
detekt.yml (1)

13-15: MagicNumber 규칙 전체 비활성화는 과도합니다—선택적 억제 또는 ignoreNumbers 확장이 더 적절합니다.

MagicNumber를 전부 끄면 의도치 않은 매직 넘버가 코드베이스 곳곳에 퍼질 수 있어 가독성과 유지보수성이 떨어집니다.
권장 사항:

  1. active: true로 유지하고, 실제 필요에 따라 @Suppress("MagicNumber")를 해당 함수/파일 단위로 지정합니다.
  2. 혹은 ignoreNumbers 목록에 자주 쓰이는 값(예: 포트, 기본 페이지 크기 등)을 추가하여 규칙을 완화합니다.

이전 커밋에서 해당 규칙이 불편을 초래한 구체적 사례가 없다면, 전역 비활성화 대신 위 두 방법을 우선 고려해 주세요.

buildSrc/build.gradle.kts (1)

1-7: 레포지토리 선언에 플러그인 저장소 추가 검토

kotlin-dsl 플러그인 자체는 Gradle 배포본에 포함돼 있지만, 향후 buildSrc 에서 외부 플러그인을 사용할 경우를 대비해 gradlePluginPortal() 을 함께 선언해 두면 재사용성이 좋아집니다.

 repositories {
+    gradlePluginPortal()
     mavenCentral()
 }
casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/error/exception/CasperException.kt (1)

9-11: 예외 메시지 노출 여부 고려

현재 RuntimeException 의 기본 message 가 null 이라 스택트레이스만으로 원인을 파악하기 어렵습니다. errorCode.messagesuper(message) 로 전달하거나 override val message 를 구현해두면 로깅·모니터링 시 가독성이 향상됩니다.

-abstract class CasperException(
-    val errorCode: ErrorCode
-) : RuntimeException()
+abstract class CasperException(
+    val errorCode: ErrorCode
+) : RuntimeException(errorCode.message)
build.gradle.kts (1)

80-82: BootJar 설정을 루트에 두는 경우의 부작용

tasks.withType<BootJar> 설정이 루트에서 전체 서브모듈에 적용됩니다. 현 시점엔 casper-schedule 하나뿐이라 문제없지만, 다른 Spring Boot 모듈이 추가되면 mainClass 충돌 위험이 있습니다. 해당 설정을 casper-schedule/build.gradle.kts 로 이동하거나, 대상 프로젝트를 한정해주세요.

-tasks.withType<org.springframework.boot.gradle.tasks.bundling.BootJar> {
-    mainClass.set("hs.kr.entrydsm.schedule.CasperScheduleApplication")
-}
+project(":casper-schedule") {
+    tasks.withType<org.springframework.boot.gradle.tasks.bundling.BootJar> {
+        mainClass.set("hs.kr.entrydsm.schedule.CasperScheduleApplication")
+    }
+}
casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/adapter/in/dto/request/UpdateSchedulesRequest.kt (1)

11-14: 검증 어노테이션 개선을 고려해보세요.

현재 구현은 기본적으로 올바르지만 다음 개선사항을 고려해보세요:

 data class UpdateSchedulesRequest(
-    @field:NotNull
+    @field:NotEmpty
+    @field:Valid
     val schedules: List<ScheduleDto>
 )

개선 이유:

  • @NotEmpty: 빈 리스트 방지 (비즈니스 로직상 의미가 더 적절)
  • @Valid: ScheduleDto 내부 필드들의 검증을 위한 중첩 검증 활성화
casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/error/config/ConfigurationPropertiesConfig.kt (1)

1-12: 패키지 위치가 의도를 혼동시킬 수 있습니다.

global.error.config 아래에 두면 “에러 처리 전용 설정”으로 오해하기 쉽습니다.
전역 @ConfigurationPropertiesScan 용도라면 global.config 또는 루트 configuration 등의 보다 일반적인 패키지로 이동하는 편이 명확합니다.

buildSrc/src/main/kotlin/PluginVersion.kt (1)

1-8: 버전 업스트림 동향 주기적 점검 권장

하드코딩된 버전이 장기간 고정되면 보안 패치 반영이 늦어질 수 있습니다.
dependabot 등으로 주기적 업데이트를 자동화하는 방안을 고려해 주세요.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/security/jwt/JwtProperties.kt (1)

15-15: JWT 비밀 키 보안 관리 고려 필요

JWT 서명에 사용되는 비밀 키를 properties 파일에 직접 저장하는 것은 보안상 위험할 수 있습니다. 환경 변수나 외부 키 관리 시스템 사용을 고려해보세요.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/error/exception/ErrorCode.kt (1)

10-27: 잘 구조화된 에러 코드 정의

에러 코드가 논리적으로 분류되어 있고, 적절한 HTTP 상태 코드를 사용하고 있습니다. 중앙집중식 에러 처리에 적합한 구조입니다.

일관성을 위해 다음 개선사항을 고려해보세요:

 enum class ErrorCode(
     val status: Int,
     val message: String
 ) {
-    // Internal Server Error
+    // 5xx - Server Errors
     INTERNAL_SERVER_ERROR(500, "Internal Server Error"),
 
-    // UnAuthorization
+    // 4xx - Client Errors
+    // Authorization
     INVALID_TOKEN(401, "Invalid Token"),
     EXPIRED_TOKEN(401, "Expired Token"),
 
     // Schedule
     DATE_SEQUENCE_NOT_VALID(400, "Schedule sequence is not valid"),
     INVALID_SCHEDULE(400, "Schedule list is Empty."),
     SCHEDULE_NOT_FOUND(404, "Schedule Not Found"),
-
     TYPE_MAPPING_ERROR(400, "Schedule Type Mapping Error")
 }
casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/port/in/QueryScheduleByTypeUseCase.kt (1)

17-17: 타입 안전성 개선 고려

현재 String 타입을 사용하고 있지만, 도메인의 Type enum을 직접 사용하면 더 타입 안전한 API를 제공할 수 있습니다.

- fun execute(type: String): ScheduleDto
+ fun execute(type: Type): ScheduleDto

단, 이 경우 웹 어댑터에서 문자열을 enum으로 변환하는 로직이 필요합니다.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/adapter/out/persistence/repository/ScheduleRepository.kt (1)

25-25: 반환 타입 일관성을 고려해보세요.

findByType() 메서드가 nullable을 반환하는 것은 적절하지만, 타입별로 하나의 스케줄만 존재한다는 비즈니스 규칙이 확실하다면 Optional<ScheduleJpaEntity>를 사용하는 것을 고려해보세요.

Spring Data JPA의 관례를 따라 다음과 같이 수정할 수 있습니다:

+import java.util.Optional
+
-    fun findByType(type: Type): ScheduleJpaEntity?
+    fun findByType(type: Type): Optional<ScheduleJpaEntity>
casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/service/UpdateSchedulesService.kt (2)

13-13: 불필요한 import 제거 필요

kotlin.collections.ifEmpty는 코틀린 표준 라이브러리에 내장된 함수이므로 명시적으로 import할 필요가 없습니다.

-import kotlin.collections.ifEmpty

40-47: 배치 처리 성능 최적화 고려 필요

현재 구현은 각 스케줄을 개별적으로 조회하고 저장하므로 N+1 문제가 발생할 수 있습니다. 대량의 스케줄 업데이트 시 성능 이슈가 예상됩니다.

배치 처리를 위한 성능 최적화를 고려해보세요:

  • 모든 스케줄을 한 번에 조회 후 Map으로 변환
  • 배치 저장 기능 활용
casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/facade/ScheduleFacade.kt (1)

18-21: @component vs @service 어노테이션 선택 검토

현재 @Component를 사용하고 있지만, 이 클래스가 비즈니스 로직을 캡슐화하는 파사드 역할을 한다면 @Service가 더 적절할 수 있습니다.

-@Component
+@Service
casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/error/GlobalExceptionFilter.kt (1)

55-64: 메서드명 오타 수정

메서드명이 writerErrorCode로 되어 있는데, writeErrorCode가 더 적절합니다.

-    private fun writerErrorCode(
+    private fun writeErrorCode(

그리고 호출하는 곳도 수정:

-            writerErrorCode(response, e.errorCode)
+            writeErrorCode(response, e.errorCode)
-            writerErrorCode(response, ErrorCode.INTERNAL_SERVER_ERROR)
+            writeErrorCode(response, ErrorCode.INTERNAL_SERVER_ERROR)
casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/service/QuerySchedulesService.kt (1)

47-55: 성능 최적화 고려 필요

getCurrentStatus() 메서드에서 각 타입별로 개별 조회를 수행하고 있어 N+1 문제가 발생할 수 있습니다.

-        val firstAnnounce: Schedule = scheduleFacade.getScheduleByType(Type.FIRST_ANNOUNCEMENT)
-        val interview: Schedule = scheduleFacade.getScheduleByType(Type.INTERVIEW)
-        val secondAnnounce: Schedule = scheduleFacade.getScheduleByType(Type.SECOND_ANNOUNCEMENT)
-
-        val startDate = scheduleFacade.getScheduleByType(Type.START_DATE).date
-        val endDate = scheduleFacade.getScheduleByType(Type.END_DATE).date
+        // 모든 스케줄을 한 번에 조회 후 Map으로 변환하여 사용
+        val scheduleMap = findSchedulePort.findAllBy().associateBy { it.type }
+        
+        val firstAnnounce = scheduleMap[Type.FIRST_ANNOUNCEMENT] ?: throw ScheduleNotFoundException
+        val interview = scheduleMap[Type.INTERVIEW] ?: throw ScheduleNotFoundException
+        val secondAnnounce = scheduleMap[Type.SECOND_ANNOUNCEMENT] ?: throw ScheduleNotFoundException
+        val startDate = scheduleMap[Type.START_DATE]?.date ?: throw ScheduleNotFoundException
+        val endDate = scheduleMap[Type.END_DATE]?.date ?: throw ScheduleNotFoundException
casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/adapter/in/dto/ScheduleDto.kt (1)

17-17: 타임존 하드코딩 개선 고려사항

Asia/Seoul 타임존이 하드코딩되어 있습니다. 향후 국제화나 다른 타임존 지원이 필요할 경우를 대비해 설정 파일이나 상수로 관리하는 것을 검토해보세요.

+companion object {
+    const val DEFAULT_TIMEZONE = "Asia/Seoul"
+    const val DEFAULT_DATE_PATTERN = "yyyy-MM-dd'T'HH:mm:ss"
+}
+
-@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss", timezone = "Asia/Seoul")
+@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DEFAULT_DATE_PATTERN, timezone = DEFAULT_TIMEZONE)
casper-schedule/src/main/proto/schedule.proto (1)

16-18: 날짜 필드 타입 개선 고려사항

GetScheduleResponsedate 필드가 string 타입으로 정의되어 있습니다. 타입 안전성과 표준화를 위해 Google의 Well-Known Types인 google.protobuf.Timestamp를 사용하는 것을 고려해보세요.

+import "google/protobuf/timestamp.proto";
+
 message GetScheduleResponse {
   Type type = 1;
-  string date = 2;
+  google.protobuf.Timestamp date = 2;
 }
casper-schedule/build.gradle.kts (1)

60-68: gRPC 의존성 정리 제안

gRPC 관련 의존성들이 잘 구성되어 있지만, 가독성을 위해 그룹화와 주석을 개선할 수 있습니다.

-	//grpc
+	// gRPC 서버 및 클라이언트
 	implementation(Dependencies.GRPC_NETTY_SHADED)
 	implementation(Dependencies.GRPC_PROTOBUF)
 	implementation(Dependencies.GRPC_STUB)
+	
+	// Kotlin gRPC 지원
 	implementation(Dependencies.GRPC_KOTLIN_STUB)
 	implementation(Dependencies.PROTOBUF_KOTLIN)
-	testImplementation(Dependencies.GRPC_TESTING)
 	implementation(Dependencies.GRPC_SERVER_SPRING)
 	implementation(Dependencies.GOOGLE_PROTOBUF)
+	
+	// gRPC 테스트
+	testImplementation(Dependencies.GRPC_TESTING)
casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/error/GlobalExceptionHandler.kt (1)

28-31: 중복된 HttpStatus 설정

ErrorResponse에 이미 status 코드를 전달하고 있는데, ResponseEntity에서 다시 HttpStatus를 설정하고 있습니다. 이는 중복이며 불일치 가능성이 있습니다.

다음 중 하나의 방식을 선택하여 일관성을 유지하세요:

 return ResponseEntity(
     ErrorResponse(code.status, code.message),
-    org.springframework.http.HttpStatus.valueOf(code.status)
+    HttpStatus.valueOf(code.status)
 )

또는 ResponseEntity.status()를 사용하여 더 명확하게 작성할 수 있습니다:

-        return ResponseEntity(
-            ErrorResponse(code.status, code.message),
-            org.springframework.http.HttpStatus.valueOf(code.status)
-        )
+        return ResponseEntity.status(code.status)
+            .body(ErrorResponse(code.status, code.message))
casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/adapter/in/ScheduleWebAdapter.kt (2)

51-55: 반환 타입 명시 누락

updateSchedules 메서드에서 반환 타입이 명시되지 않았습니다. 코드 가독성과 유지보수성을 위해 반환 타입을 명시해야 합니다.

반환 타입을 명시하세요:

     @PatchMapping
     fun updateSchedules(
         @RequestBody @Valid
         request: UpdateSchedulesRequest
-    ) = updateSchedulesUseCase.execute(request)
+    ): UpdateSchedulesResponse = updateSchedulesUseCase.execute(request)

또는 use case의 반환 타입이 Unit이라면:

-    ) = updateSchedulesUseCase.execute(request)
+    ) {
+        updateSchedulesUseCase.execute(request)
+    }

1-1: 패키지명의 백틱 사용

Kotlin에서 in은 예약어이므로 백틱으로 감싸는 것이 필요하지만, 가독성을 위해 다른 패키지명 사용을 고려해볼 수 있습니다.

in 대신 다음과 같은 대안을 고려해보세요:

  • inbound
  • web
  • controller

예시:

-package hs.kr.entrydsm.schedule.domain.schedule.adapter.`in`
+package hs.kr.entrydsm.schedule.domain.schedule.adapter.inbound
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 28262a1 and 56eedcf.

📒 Files selected for processing (54)
  • build-logic/build.gradle.kts (0 hunks)
  • build-logic/settings.gradle.kts (0 hunks)
  • build-logic/src/main/kotlin/io/casper/build/TestClass.kt (0 hunks)
  • build.gradle.kts (2 hunks)
  • buildSrc/build.gradle.kts (1 hunks)
  • buildSrc/src/main/kotlin/Dependencies.kt (1 hunks)
  • buildSrc/src/main/kotlin/DependencyVersion.kt (1 hunks)
  • buildSrc/src/main/kotlin/Plugin.kt (1 hunks)
  • buildSrc/src/main/kotlin/PluginVersion.kt (1 hunks)
  • casper-schedule/build.gradle.kts (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/CasperScheduleApplication.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/adapter/in/ScheduleWebAdapter.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/adapter/in/dto/ScheduleDto.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/adapter/in/dto/request/UpdateSchedulesRequest.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/adapter/in/dto/response/SchedulesResponse.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/adapter/out/entity/ScheduleJpaEntity.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/adapter/out/mapper/ScheduleMapper.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/adapter/out/persistence/SchedulePersistenceAdapter.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/adapter/out/persistence/repository/ScheduleRepository.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/exception/InvalidScheduleRequestException.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/exception/InvalidScheduleSequenceException.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/exception/ScheduleNotFoundException.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/port/in/QueryScheduleByTypeUseCase.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/port/in/QuerySchedulesUseCase.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/port/in/ScheduleFacadeUseCase.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/port/in/UpdateSchedulesUseCase.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/port/out/FindSchedulePort.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/port/out/SaveSchedulePort.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/service/QueryScheduleByTypeService.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/service/QuerySchedulesService.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/service/UpdateSchedulesService.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/facade/ScheduleFacade.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/model/Schedule.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/model/type/Type.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/error/ErrorResponse.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/error/GlobalExceptionFilter.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/error/GlobalExceptionHandler.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/error/config/ConfigurationPropertiesConfig.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/error/exception/CasperException.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/error/exception/ErrorCode.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/exception/ExpiredTokenException.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/exception/InternalServerErrorException.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/exception/InvalidTokenException.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/security/FilterConfig.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/security/SecurityConfig.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/security/jwt/JwtFilter.kt (1 hunks)
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/security/jwt/JwtProperties.kt (1 hunks)
  • casper-schedule/src/main/proto/schedule.proto (1 hunks)
  • casper-schedule/src/test/kotlin/hs/kr/entrydsm/schedule/CasperScheduleApplicationTests.kt (1 hunks)
  • detekt.yml (1 hunks)
  • settings.gradle.kts (1 hunks)
  • src/main/kotlin/hs/kr/entrydsm/schedule/CasperScheduleApplication.kt (0 hunks)
  • src/main/resources/application.properties (0 hunks)
  • src/test/kotlin/hs/kr/entrydsm/schedule/CasperScheduleApplicationTests.kt (0 hunks)
💤 Files with no reviewable changes (6)
  • src/main/resources/application.properties
  • build-logic/settings.gradle.kts
  • build-logic/build.gradle.kts
  • build-logic/src/main/kotlin/io/casper/build/TestClass.kt
  • src/main/kotlin/hs/kr/entrydsm/schedule/CasperScheduleApplication.kt
  • src/test/kotlin/hs/kr/entrydsm/schedule/CasperScheduleApplicationTests.kt
🧰 Additional context used
🪛 detekt (1.23.8)
casper-schedule/src/test/kotlin/hs/kr/entrydsm/schedule/CasperScheduleApplicationTests.kt

[warning] 18-19: This empty block of code can be removed.

(detekt.empty-blocks.EmptyFunctionBlock)

🪛 Buf (1.55.1)
casper-schedule/src/main/proto/schedule.proto

3-3: Files with package "schedule.proto" must be within a directory "schedule/proto" relative to root but were in directory "casper-schedule/src/main/proto".

(PACKAGE_DIRECTORY_MATCH)

🔇 Additional comments (43)
settings.gradle.kts (1)

17-17: casper-schedule 모듈 디렉터리 및 빌드 스크립트 확인 완료

  • casper-schedule/ 디렉터리 존재
  • casper-schedule/build.gradle.kts 파일 존재

위 사항을 검증했으며, Gradle 구성에 문제 없습니다. 추가 작업은 필요하지 않습니다.

build.gradle.kts (1)

10-10: ktlint 버전 다운그레이드 사유 확인

12.x → 11.5.1 로 버전이 하향되었습니다. 최신 버전에서 해결된 버그나 CVE 가 다시 발생할 수 있으니, 호환성 문제 때문인지 명시적인 코멘트를 남겨 두면 추후 유지보수 시 혼란을 줄일 수 있습니다.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/exception/ScheduleNotFoundException.kt (1)

1-12: LGTM! 잘 구현된 도메인 예외 클래스입니다.

헥사고날 아키텍처에서 도메인 예외의 올바른 구현을 보여줍니다:

  • object 선언으로 상태가 없는 예외를 적절히 구현
  • 기본 CasperException을 확장하여 일관된 예외 계층 구조 유지
  • ErrorCode 열거형을 사용하여 에러 코드 중앙 집중화
  • 명확한 한국어 문서화로 사용 시점 설명
casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/port/out/SaveSchedulePort.kt (1)

1-16: LGTM! 헥사고날 아키텍처의 아웃바운드 포트가 잘 설계되었습니다.

포트 인터페이스의 우수한 구현:

  • 단일 책임 원칙을 따라 일정 저장만 담당
  • 도메인 모델(Schedule)을 사용하여 영속성 기술과 분리
  • 명확한 메서드 시그니처와 한국어 문서화
  • 인터페이스 분리 원칙을 준수하여 응집도 높음
casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/adapter/in/dto/request/UpdateSchedulesRequest.kt (1)

1-1: 패키지명의 백틱 사용이 적절합니다.

Kotlin에서 in이 예약어이므로 백틱을 사용한 것이 올바른 접근입니다.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/exception/InvalidScheduleSequenceException.kt (1)

1-12: LGTM! 일관성 있는 예외 설계입니다.

다른 도메인 예외들과 일관된 패턴을 따라 잘 구현되었습니다:

  • 특정 비즈니스 규칙(일정 순서) 위반에 대한 명확한 예외
  • object 선언으로 상태 없는 예외를 적절히 모델링
  • 상세한 문서화로 사용 시나리오를 명확히 설명
casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/exception/InvalidTokenException.kt (1)

1-12: LGTM! 글로벌 예외의 적절한 배치입니다.

보안 관련 예외의 올바른 구현:

  • 도메인별 예외와 글로벌 예외를 패키지로 적절히 분리
  • JWT 토큰 검증이라는 횡단 관심사에 대한 전용 예외
  • 다른 예외들과 일관된 구현 패턴 유지
casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/port/in/UpdateSchedulesUseCase.kt (2)

1-18: 헥사고날 아키텍처 패턴이 잘 적용된 유스케이스 인터페이스입니다.

인바운드 포트 패턴을 올바르게 구현했으며, 단일 책임 원칙을 잘 따르고 있습니다. 한국어 문서화도 명확하고 이해하기 쉽습니다.


14-15: UpdateSchedulesUseCase 구현체 및 예외 처리 검증 요청

UpdateSchedulesUseCase 인터페이스는 존재하나, 이를 구현한 클래스가 레포지토리 내에서 확인되지 않습니다.
문서에 명시된 예외가 실제 코드에서 던져지는지 아래 사항을 직접 검증해주세요:

  • 인터페이스 UpdateSchedulesUseCase를 구현한 클래스 파일 경로 및 패키지 확인
  • 해당 구현체의 메서드 내에서
    • InvalidScheduleRequestException
    • InvalidScheduleSequenceException
      예외가 실제로 발생(throw)되는지

문서의 @throws 주석과 구현체 간 일치 여부를 재검토 부탁드립니다.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/exception/InvalidScheduleRequestException.kt (2)

1-12: 잘 구현된 도메인 예외 클래스입니다.

Kotlin의 object 패턴을 사용한 싱글톤 예외 구현이 적절하며, CasperException 계층구조를 올바르게 따르고 있습니다. 한국어 문서화도 명확합니다.


11-11: INVALID_SCHEDULE 에러 코드가 정의되어 있습니다
ErrorCode enum(casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/error/exception/ErrorCode.kt)에서
INVALID_SCHEDULE(400, "Schedule list is Empty.")가 이미 선언되어 있으므로, 참조에 문제가 없습니다.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/model/type/Type.kt (2)

1-13: 명확하고 잘 정의된 도메인 열거형입니다.

입학 일정의 단계를 명확하게 표현하고 있으며, 비즈니스 도메인을 잘 반영한 명명이 되어 있습니다. 문서화도 적절합니다.


8-12: Type enum 순서 및 순서 의존성 검증 완료

  • casper-schedule/src/main/kotlin/…/Type.ktcasper-schedule/src/main/proto/schedule.proto 의 enum 정의 순서가 완전히 일치합니다.
  • 비즈니스 로직(QuerySchedulesService, QueryScheduleByTypeService 등)에서 Type 을 조회할 때 ordinal 에 의존하지 않고, 명시적으로 Type.START_DATE, Type.FIRST_ANNOUNCEMENT 등으로만 사용하고 있어 순서 변경 리스크가 없습니다.

따라서 현재 정의를 유지해도 무방합니다.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/exception/InternalServerErrorException.kt (1)

1-12: 일관성 있게 구현된 글로벌 예외 클래스입니다.

다른 예외 클래스들과 동일한 패턴을 따르고 있으며, 서버 내부 오류를 위한 적절한 위치에 배치되어 있습니다. 문서화도 명확합니다.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/port/in/QuerySchedulesUseCase.kt (1)

1-16: CQRS 패턴을 잘 구현한 조회 유스케이스입니다.

단일 책임을 가진 명확한 조회 인터페이스이며, 문서화도 적절합니다. 헥사고날 아키텍처의 인바운드 포트 패턴을 올바르게 따르고 있습니다.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/error/ErrorResponse.kt (1)

10-13: ✅ 문제없이 잘 설계된 공통 응답 DTO입니다.

필드 정의·가시성 모두 적절하며, 직렬화 라이브러리(Jackson/Kotlin-module)와도 호환됩니다.
추가 의견 없습니다.

buildSrc/src/main/kotlin/Plugin.kt (1)

1-11: 플러그인 ID 상수화👍

공통 플러그인 ID를 중앙 집중화해 오타·중복을 방지했습니다.
차후 멀티모듈에도 재사용 가능해 유지보수성이 크게 향상됩니다.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/port/in/QueryScheduleByTypeUseCase.kt (1)

1-1: 백틱 사용으로 Kotlin 예약어 처리

in 키워드가 Kotlin 예약어이므로 백틱으로 올바르게 처리했습니다.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/port/in/ScheduleFacadeUseCase.kt (1)

9-18: Facade 패턴의 올바른 구현

외부 시스템과의 인터페이스 역할을 하는 Facade 유스케이스가 잘 정의되어 있습니다. Type enum을 직접 사용하여 타입 안전성을 보장하고 있으며, 예외 처리 명세도 명확합니다.

casper-schedule/src/test/kotlin/hs/kr/entrydsm/schedule/CasperScheduleApplicationTests.kt (2)

17-19: 컨텍스트 로딩 테스트의 올바른 구현

빈 테스트 메서드는 Spring Boot 통합 테스트에서 일반적인 패턴입니다. 애플리케이션 컨텍스트가 성공적으로 로드되는지 확인하는 스모크 테스트 역할을 합니다. 정적 분석 도구의 제거 제안은 무시해도 됩니다.


10-21: Spring Boot 테스트 구조 양호

@SpringBootTest 어노테이션을 사용한 통합 테스트 클래스가 적절히 구성되어 있습니다. 새로운 모듈 구조에서 애플리케이션이 정상적으로 시작되는지 확인하는 기본적인 검증을 제공합니다.

buildSrc/src/main/kotlin/Dependencies.kt (1)

1-43: 의존성 중앙 관리 구조가 잘 설계되었습니다.

카테고리별로 의존성을 체계적으로 그룹화하고 DependencyVersion을 통한 버전 관리가 잘 구현되어 있습니다. 프로젝트의 유지보수성이 크게 향상될 것입니다.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/port/out/FindSchedulePort.kt (1)

6-24: 헥사고날 아키텍처 아웃바운드 포트가 잘 구현되었습니다.

인터페이스 설계가 깔끔하고 메서드 시그니처가 명확합니다. 한국어 문서화도 잘 되어 있으며, nullable 반환 타입 사용이 적절합니다. 클린 아키텍처 원칙을 잘 따르고 있습니다.

buildSrc/src/main/kotlin/DependencyVersion.kt (1)

1-17: 버전 중앙 관리 구조가 우수합니다.

의존성 버전을 한 곳에서 관리하는 접근 방식이 훌륭합니다. 버전 업데이트 시 일관성 유지와 유지보수성이 크게 향상될 것입니다.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/CasperScheduleApplication.kt (1)

6-21: Spring Boot 애플리케이션 진입점이 올바르게 구현되었습니다.

표준 Spring Boot 컨벤션을 잘 따르고 있으며, 한국어 문서화도 충실합니다. 코드가 깔끔하고 최소한의 필요한 요소만 포함되어 있어 좋습니다.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/model/Schedule.kt (1)

6-28: 도메인 모델이 우수하게 설계되었습니다.

불변성을 유지하는 데이터 클래스 설계가 훌륭하고, updateDate 메서드가 새 인스턴스를 반환하여 불변성 원칙을 잘 따르고 있습니다. 한국어 문서화가 매우 상세하며 도메인 주도 설계 원칙에 부합합니다.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/adapter/out/mapper/ScheduleMapper.kt (1)

11-28: LGTM!

MapStruct 매퍼 구현이 올바르게 되어 있습니다. Spring 컴포넌트 모델 설정과 메서드 시그니처가 적절하며, 도메인 모델과 JPA 엔티티 간의 변환을 깔끔하게 처리합니다.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/security/SecurityConfig.kt (1)

50-50: FilterConfig 의존성 확인 완료

  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/security/FilterConfig.kt 에서 class FilterConfig 구현 확인
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/security/jwt/JwtFilter.kt 에서 class JwtFilter 구현 확인
  • casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/error/GlobalExceptionFilter.kt 에서 class GlobalExceptionFilter 구현 확인

위 클래스들이 모두 정상적으로 구현되어 있으므로 추가 검토나 수정은 필요하지 않습니다.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/service/UpdateSchedulesService.kt (1)

43-45: 날짜 비교 경계 조건 명확화 필요
UpdateSchedulesService.kt(43–45)에서는 오직 이전 일정의 날짜가 새 날짜보다 뒤인 경우에만 InvalidScheduleSequenceException을 던지고, 동일한 날짜는 허용하고 있습니다. 반면 QuerySchedulesService.kt에서는 isEqual을 적극 활용해 “동일 날짜”를 별도로 처리하고 있으므로, 비즈니스 요구사항에 따라 UpdateSchedulesService에서도 동일한 날짜 허용 여부를 명확히 정의해야 합니다.

예시) 동일 날짜도 금지하려면:

if (index != 0 &&
    (scheduleDtoList[index - 1].date.isAfter(scheduleDto.date) ||
     scheduleDtoList[index - 1].date.isEqual(scheduleDto.date))
) {
    throw InvalidScheduleSequenceException
}

검토 항목:

  • UpdateSchedulesService.kt (43–45): 동일 날짜 허용 여부 검토 및 경계 조건(isEqual) 추가 여부 결정
  • QuerySchedulesService.kt: 날짜 비교 로직 경계 처리와 일치하는지 확인

비즈니스 룰에 맞춰 경계 조건을 확실히 정의해주세요.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/facade/ScheduleFacade.kt (1)

29-32: LGTM! 깔끔한 파사드 패턴 구현

파사드 패턴이 올바르게 구현되어 있으며, 의존성 주입과 예외 처리도 적절합니다. Elvis 연산자를 사용한 null 처리가 코틀린답고 간결합니다.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/adapter/out/persistence/SchedulePersistenceAdapter.kt (3)

18-22: LGTM! 헥사고날 아키텍처 원칙 준수

Persistence Adapter가 올바르게 구현되어 있습니다. 도메인과 영속성 계층 간의 분리가 잘 되어 있고, 의존성 주입도 적절합니다.


29-31: Null 처리 로직 확인

let 블록을 사용한 null 처리가 적절합니다. Repository에서 null을 반환할 때 적절히 처리되고 있습니다.


48-50: 저장 로직 및 반환 처리 적합 확인

  • ScheduleRepositoryJpaRepository<…, Int>를 상속해 save() 호출 시 영속화된 엔티티를 반환
  • 반환된 엔티티를 scheduleMapper.toModel()로 도메인 모델로 변환하는 패턴이 다른 조회 메서드(findByType, findAllBy)와 일관되게 사용됨
  • 별도의 문제나 추가 검증 요청 사항 없습니다.
casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/application/service/QuerySchedulesService.kt (2)

31-39: LGTM! 깔끔한 서비스 구현

모든 스케줄을 조회하고 DTO로 변환하는 로직이 잘 구현되어 있습니다. 함수형 프로그래밍 스타일의 map 사용도 적절합니다.


66-66: InvalidScheduleSequenceException 처리 로직이 적절함 확인됨
QuerySchedulesService 와 UpdateSchedulesService 에서 모두 스케줄 순서가 유효하지 않은 상황에 대해 일관되게 InvalidScheduleSequenceException 을 던지고 있으며, 예외 클래스의 설명(일정의 시작일이 종료일보다 늦거나, 이전 일정과의 순서가 맞지 않는 경우 발생)도 적용 대상과 일치합니다.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/adapter/in/dto/ScheduleDto.kt (1)

14-20: 헥사고날 아키텍처 패턴 잘 적용됨

DTO 설계가 우수합니다. 불변 데이터 클래스, 적절한 검증 어노테이션, 명확한 JSON 포맷팅이 잘 구현되어 있으며 헥사고날 아키텍처의 어댑터 계층에 적합한 구조입니다.

casper-schedule/src/main/proto/schedule.proto (1)

8-10: gRPC 서비스 정의 구조 우수함

서비스 인터페이스가 명확하고 RESTful한 스타일로 잘 설계되었습니다. 타입별 스케줄 조회 기능이 단순하고 효과적으로 정의되어 있습니다.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/security/jwt/JwtFilter.kt (1)

65-70: UserRole 열거형 구조 적절함

역할 정의가 명확하고 권한 수준이 잘 구분되어 있습니다. 각 역할의 용도가 주석으로 잘 설명되어 있어 유지보수성이 좋습니다.

casper-schedule/build.gradle.kts (2)

72-94: Protobuf 설정 구성 우수함

gRPC 코드 생성을 위한 Protobuf 플러그인 설정이 잘 구성되어 있습니다. Java와 Kotlin gRPC stub 생성을 모두 지원하며, 버전 관리도 중앙화되어 있어 유지보수성이 좋습니다.


4-12: 플러그인 구성 및 중앙화된 버전 관리 우수함

플러그인 ID와 버전이 중앙화되어 관리되고 있어 일관성과 유지보수성이 뛰어납니다. 헥사고날 아키텍처 구현에 필요한 모든 플러그인이 적절히 포함되어 있습니다.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/global/security/FilterConfig.kt (2)

34-38: 필터 체인 순서 확인

addFilterBefore의 호출 순서로 인해 최종 필터 실행 순서가 GlobalExceptionFilter -> JwtFilter -> UsernamePasswordAuthenticationFilter가 됩니다. 예외 처리가 가장 먼저 실행되는 것이 올바른 설계입니다.


18-21: Spring Security 설정 패턴 우수함

SecurityConfigurerAdapter를 적절히 확장하여 필터 체인을 구성하고 있으며, 의존성 주입도 올바르게 구현되어 있습니다. 컴포넌트 스캔을 통한 빈 등록도 적절합니다.

casper-schedule/src/main/kotlin/hs/kr/entrydsm/schedule/domain/schedule/adapter/in/ScheduleWebAdapter.kt (1)

25-31: 헥사고날 아키텍처 패턴 준수 확인

이 adapter는 헥사고날 아키텍처의 input adapter로서 올바른 구조를 가지고 있습니다. use case 인터페이스에만 의존하고 있어 의존성 역전 원칙을 잘 따르고 있습니다.

@coehgns coehgns merged commit 591c6a7 into main Aug 15, 2025
1 check passed
@coehgns coehgns deleted the feature/11-layered-to-hexagonal branch August 15, 2025 09:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants