-
Notifications
You must be signed in to change notification settings - Fork 0
20260102 #1 프로젝트 멀티모듈 구조 도입 #2
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
The head ref may contain hidden characters: "20260102_#1_\uD504\uB85C\uC81D\uD2B8_\uBA40\uD2F0\uBAA8\uB4C8_\uAD6C\uC870_\uB3C4\uC785"
Conversation
|
Warning Rate limit exceeded@Chuseok22 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 19 minutes and 45 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (19)
Note
|
| Cohort / File(s) | Summary |
|---|---|
루트/빌드 구성 & 버전 카탈로그 build.gradle.kts, gradle/libs.versions.toml, settings.gradle.kts |
멀티모듈 전환: allprojects/subprojects로 공통 설정 이동, Java 21 툴체인·Kotlin 컴파일 옵션 설정, 버전 카탈로그 추가, 서브프로젝트 포함 선언 추가. |
모듈별 Gradle 스크립트 CT-auth/build.gradle.kts, CT-common/build.gradle.kts, CT-member/build.gradle.kts, CT-web/build.gradle.kts |
각 모듈에 java-library 적용, bootJar 비활성화·표준 jar 활성화, 모듈별 의존성(프로젝트 간 의존성 및 라이브러리) 선언 추가. |
웹 모듈 애플리케이션 및 스캔/DB 설정 CT-web/src/main/kotlin/com/chuseok22/ctweb/CampusTableServerApplication.kt, .../ComponentScanConfig.kt, .../DatabaseScanConfig.kt |
패키지명 변경 및 컴포넌트/엔티티/레포지토리 자동 스캔을 위한 설정 클래스 추가. |
OpenAPI / SpringDoc 설정 CT-web/src/main/kotlin/.../SwaggerConfig.kt, CT-web/src/main/kotlin/.../SpringDocProperties.kt |
OpenAPI 빈과 JWT Bearer 보안 스킴 추가, SpringDoc 서버 목록 바인딩용 @ConfigurationProperties 타입 및 OpenApiCustomizer 빈 도입. |
애플리케이션 구성 CT-web/src/main/resources/application.yml |
프로파일/설정 임포트(config-imports.yml) 참조 추가 및 JPA/Hibernate, Flyway, Jackson 타임존, multipart 등 설정 변경. |
공통 유틸리티 CT-common/src/main/kotlin/.../CommonUtil.kt |
String?.nvl(fallback: String): String 확장 함수 추가(널/"null"/공백 체크 후 대체). |
CI/CD 및 리포스 관리 .github/workflows/spring-boot-cicd.yml, .gitignore |
CI에서 CT-web/src/main/resources/application-prod.yml 직접 생성하도록 변경, config-imports.yml 생성 스텝 추가(스텝명 한글화). .gitignore에서 ENV 패턴을 특정 리소스 경로로 좁힘. |
테스트 제거 src/test/kotlin/com/chuseok22/campustableserver/CampusTableServerApplicationTests.kt |
기본 컨텍스트 로드 통합 테스트 파일 삭제. |
도구·메타 설정 .coderabbit.yaml |
코드리뷰/챗봇 설정 파일 추가(한국어, 자동리뷰 등). |
Estimated code review effort
🎯 4 (Complex) | ⏱️ ~60 minutes
Poem
🐰 새 모듈로 껑충, 빌드가 춤추네,
설정은 정리되어 경로가 반짝,
스웨거는 길을 밝혀 주고, 시크릿은 조심히 숨겨,
토끼가 당근 들고 CI를 응원하네,
깡충깡충 배포의 날을 기다립니다.
Pre-merge checks and finishing touches
❌ Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. | You can run @coderabbitai generate docstrings to improve docstring coverage. |
✅ Passed checks (2 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | PR 제목 '20260102 #1 프로젝트 멀티모듈 구조 도입'은 실제 변경 사항의 핵심을 정확하게 반영하고 있습니다. 멀티모듈 구조 도입이라는 주요 변경 사항을 명확하게 설명합니다. |
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
Fix all issues with AI Agents 🤖
In @build.gradle.kts:
- Around line 53-58: Replace the deprecated kotlinOptions DSL used inside
tasks.withType<KotlinCompile>().configureEach with the new compilerOptions API:
locate the tasks.withType<KotlinCompile>() block and remove kotlinOptions { ...
} and instead call compilerOptions { set jvmTarget via the property provider
(e.g., jvmTarget.set("21")) and set freeCompilerArgs through its typed property
(e.g., freeCompilerArgs.set(listOf("-Xjsr305=strict"))); ensure you import or
reference the KotlinCompile type and use the compilerOptions closures/property
setters so the configuration uses property providers and typed options.
- Around line 26-32: The subprojects block applies several plugins but misses
applying the kotlin.allopen plugin and configuring it for JPA; update the
subprojects block to apply the "org.jetbrains.kotlin.plugin.allopen"
(kotlin.allopen) plugin and add an allOpen configuration that lists the JPA
annotations ("jakarta.persistence.Entity",
"jakarta.persistence.MappedSuperclass", "jakarta.persistence.Embeddable") so
Kotlin classes used as JPA entities are compiled open for proxying; locate the
subprojects block and add the apply(plugin =
"org.jetbrains.kotlin.plugin.allopen") line and an allOpen { annotation("...")
... } block (placed after the plugins/dependencies configuration) to enable this
behavior.
In @CT-auth/build.gradle.kts:
- Around line 17-18: Replace the incorrect api(...) declaration for the test
library with a test-only scope: change api(libs.spring.security.test) to
testImplementation(libs.spring.security.test) so spring-security-test is only on
the test classpath; leave api(libs.spring.boot.starter.security) as-is and
ensure any other modules that need spring-security-test add their own
testImplementation entry.
In @CT-web/build.gradle.kts:
- Around line 5-12: The build currently disables tasks.bootJar and re-enables
tasks.jar, which prevents producing a runnable Spring Boot JAR; if this module
is the main application, revert that by removing or changing the tasks.bootJar
block so bootJar is enabled (delete the tasks.bootJar { enabled = false } line
or set enabled = true) and ensure tasks.jar is not forcing a plain library JAR
(either remove the tasks.jar override or set tasks.jar.enabled = false and/or
remove archiveClassifier.set("")), leaving bootJar as the primary artifact.
In @CT-web/src/main/resources/application.yml:
- Around line 2-3: The file currently hardcodes the production profile via the
YAML key "profiles.active: prod", which forces prod settings everywhere; remove
that hardcoded "profiles.active" entry from application.yml, create
environment-specific override files (e.g., application-local.yml,
application-prod.yml) for profile-specific settings, and rely on the
SPRING_PROFILES_ACTIVE environment variable (or CI/deploy config) to activate
the correct profile at runtime rather than embedding "prod" in application.yml.
- Around line 25-30: The servlet.multipart settings in application.yml are
overly permissive and unused; either remove the entire servlet.multipart block
to disable multipart support or, if uploads will be supported, lower limits and
harden controls: change max-file-size to 10-50MB and max-request-size to
50-100MB, and ensure upload endpoints are protected via
authentication/authorization, rate limiting, and antivirus scanning before
enabling the servlet.multipart configuration.
🧹 Nitpick comments (8)
.gitignore (1)
43-45: Well-scoped .gitignore patterns for multi-module structure.The transition from a broad
application-*.ymlpattern to targeted, module-specific paths is appropriate for the multi-module architecture. This approach:
- Prevents accidental commits of environment-specific configuration files in the web module
- Avoids overly broad ignore patterns that could mask legitimate configuration elsewhere
- Aligns with the Swagger configuration additions (
springdoc.yml)Ensure that your CI/CD pipeline correctly generates these configuration files at runtime before the application starts.
If you'd like, I can help document the configuration file generation process in your CI/CD workflow or create a template for these files in the repository to clarify their expected structure.
CT-common/src/main/kotlin/com/chuseok22/ctcommon/core/util/CommonUtil.kt (1)
6-13: Document the string "null" handling behavior.The check
this == "null"on line 9 treats the string literal "null" as equivalent to an actual null value. While this might be intentional for handling serialized/external data sources, it could be surprising to developers and may lead to unintended behavior if "null" is a valid value in your domain.Consider:
- Adding a KDoc comment explaining this behavior and the use case
- Evaluating whether this check is necessary for your use cases
- If needed, consider providing separate functions: one that handles string "null" and one that doesn't
📝 Example documentation
/** - * null 또는 빈 문자열을 기본값으로 대체 + * null, 문자열 "null", 또는 빈 문자열을 기본값으로 대체 + * + * @param fallback null/blank일 경우 반환할 기본값 + * @return 원본 문자열이 null, "null" 문자열, 또는 blank인 경우 fallback을 반환하고, 그렇지 않으면 원본 문자열 반환 + * + * 참고: 이 함수는 외부 데이터 소스에서 문자열 "null"이 실제 null 값을 나타낼 수 있는 경우를 처리합니다. */ fun String?.nvl(fallback: String): String {.github/workflows/spring-boot-cicd.yml (2)
46-48: Ensure the target directory exists before writing files.The workflow writes directly to
CT-web/src/main/resources/without verifying the directory exists. While this directory should exist in the repository structure, adding an explicit check improves robustness.🔎 Suggested improvement
- name: application-prod.yml 파일 생성 run: | + mkdir -p CT-web/src/main/resources echo "${{ secrets.APPLICATION_PROD_YML }}" > CT-web/src/main/resources/application-prod.yml
50-52: Ensure the target directory exists before writing files.Same as the previous step, consider adding
mkdir -pto ensure the directory exists.🔎 Suggested improvement
- name: config-imports.yml 파일 생성 run: | + mkdir -p CT-web/src/main/resources echo "${{ secrets.CONFIG_IMPORTS_YML }}" > CT-web/src/main/resources/config-imports.ymlCT-web/src/main/kotlin/com/chuseok22/ctweb/infrastructure/properties/SpringDocProperties.kt (1)
8-20: Consider adding size validation for the servers list.The
serverslist currently has no size constraint, allowing an empty list. If at least one server entry is required for your OpenAPI documentation, consider adding@field:NotEmpty.🔎 Optional improvement
+import jakarta.validation.constraints.NotEmpty + @Validated @ConfigurationProperties(prefix = "springdoc") data class SpringDocProperties( @field:Valid + @field:NotEmpty val servers: List<Servers> ) {CT-web/src/main/kotlin/com/chuseok22/ctweb/infrastructure/config/SwaggerConfig.kt (1)
27-39: Follow Kotlin naming conventions for bean methods.The bean method name
OpenAPI()starts with an uppercase letter, which doesn't follow Kotlin/Java naming conventions for methods. Consider renaming toopenAPI().🔎 Suggested fix
@Bean - fun OpenAPI(): OpenAPI { + fun openAPI(): OpenAPI { val apiKey: SecurityScheme = SecurityScheme() .type(SecurityScheme.Type.HTTP) .scheme("bearer")CT-member/build.gradle.kts (1)
17-18: Consider usingimplementationinstead ofapifor PostgreSQL driver.The PostgreSQL driver is declared with
api, which exposes it to all modules that depend on CT-member (such as CT-web). Database drivers are typically internal implementation details and should useimplementationscope unless consuming modules require direct access to PostgreSQL classes.🔎 Recommended change
// Postgres - api(libs.postgresql) + implementation(libs.postgresql)Use
apionly if other modules need to directly use PostgreSQL JDBC classes. For most multi-module setups,implementationprovides better encapsulation.CT-web/build.gradle.kts (1)
1-3: Redundant plugin application.The
java-libraryplugin is already applied to all subprojects in the rootbuild.gradle.kts(line 27). This declaration is unnecessary.🔎 Proposed fix
-plugins { - id("java-library") -} - tasks.bootJar {
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
.github/workflows/spring-boot-cicd.yml.gitignoreCT-auth/build.gradle.ktsCT-common/build.gradle.ktsCT-common/src/main/kotlin/com/chuseok22/ctcommon/core/util/CommonUtil.ktCT-member/build.gradle.ktsCT-web/build.gradle.ktsCT-web/src/main/kotlin/com/chuseok22/ctweb/CampusTableServerApplication.ktCT-web/src/main/kotlin/com/chuseok22/ctweb/infrastructure/config/SwaggerConfig.ktCT-web/src/main/kotlin/com/chuseok22/ctweb/infrastructure/properties/SpringDocProperties.ktCT-web/src/main/resources/application.ymlbuild.gradle.ktsgradle/libs.versions.tomlsettings.gradle.ktssrc/main/resources/application.ymlsrc/test/kotlin/com/chuseok22/campustableserver/CampusTableServerApplicationTests.kt
💤 Files with no reviewable changes (1)
- src/test/kotlin/com/chuseok22/campustableserver/CampusTableServerApplicationTests.kt
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (11)
CT-web/src/main/kotlin/com/chuseok22/ctweb/CampusTableServerApplication.kt (2)
1-1: LGTM! Package rename aligns with the CT-web module structure.The package name change from
com.chuseok22.campustableservertocom.chuseok22.ctwebis appropriate for the new multi-module structure.
6-7: No component scanning issue found in current code.The codebase has no Spring components in CT-auth, CT-common, or CT-member modules. CT-auth and CT-member are empty, and CT-common contains only a utility class. All Spring components (
@Configuration,@Bean,@ConfigurationProperties) are in CT-web under the correct package (com.chuseok22.ctweb), so the default component scanning works as expected. The concern about multi-module component discovery is not applicable to the current state of the code.Likely an incorrect or invalid review comment.
CT-web/src/main/kotlin/com/chuseok22/ctweb/infrastructure/config/SwaggerConfig.kt (1)
41-52: LGTM!The
serverCustomizerbean correctly uses the validated properties to dynamically add servers to the OpenAPI document. The implementation properly leverages the SpringDoc customization mechanism.gradle/libs.versions.toml (1)
1-6: No issues found. All specified versions are valid and available on Maven Central:
- Spring Boot 3.5.9 (released December 18, 2025)
- springdoc-openapi-starter-webmvc-ui 3.0.1 (released January 1, 2026)
- Kotlin 1.9.25 (released July 19, 2024)
CT-web/src/main/resources/application.yml (2)
16-22: Verify Flyway baseline configuration for existing databases.
baseline-on-migrate: false(line 19) will cause Flyway to fail if the target database already exists without a Flyway schema history table. This is appropriate for greenfield projects but problematic if migrating an existing database.If this application will connect to existing databases (e.g., staging/prod environments set up before Flyway), consider:
- Setting
baseline-on-migrate: truetemporarily during initial migration- Or manually creating the Flyway baseline before deployment
Otherwise, the current configuration is appropriate for new databases.
6-15: Timezone configuration mismatch between JPA and Jackson.JPA is configured with
time_zone: UTC(line 11) while Jackson usestime-zone: Asia/Seoul(line 24). This creates an inconsistency where:
- Database stores timestamps in UTC
- API responses serialize timestamps in Asia/Seoul timezone
- Developers must account for the conversion between layers
If this split is intentional for your use case, document it clearly. Otherwise, standardize on a single timezone throughout the application stack (UTC recommended for consistency with database and backend logic).
settings.gradle.kts (1)
3-6: Multi-module structure correctly configured.The four modules (CT-auth, CT-common, CT-member, CT-web) are properly registered in the Gradle multi-project build. This aligns with the module-specific build.gradle.kts files provided.
CT-member/build.gradle.kts (1)
1-12: Library module configuration is correct.The java-library plugin with disabled
bootJarand enabledjaris the proper setup for a non-executable library module in a Spring Boot multi-module project.CT-common/build.gradle.kts (1)
1-30: Common module configuration follows best practices.The CT-common module correctly:
- Uses
java-libraryplugin with disabledbootJarfor library-only usage- Declares all dependencies as
api(lines 17, 20, 23, 26, 28-29) to transitively expose them to dependent modules- Includes essential shared dependencies (Spring Web, JPA, Validation, Jackson, Kotlin stdlib)
The comment on line 14 clearly documents the intent: "common 모듈 api 의존성은 모든 모듈에 적용" (common module api dependencies apply to all modules).
CT-auth/build.gradle.kts (1)
1-12: Library module configuration is correct.Consistent with other library modules (CT-common, CT-member), the java-library plugin with disabled
bootJarand enabledjaris appropriate for CT-auth.build.gradle.kts (1)
13-24: Overall structure looks good.The multi-module setup with centralized configuration in
allprojectsandsubprojectsblocks follows Gradle best practices. The version catalog approach for dependency management is a good choice.Ensure the custom Nexus repository at
https://nexus.chuseok22.com/repository/maven-releases/is accessible from your CI/CD environment.
| subprojects { | ||
| apply(plugin = "java-library") | ||
| apply(plugin = "org.jetbrains.kotlin.jvm") | ||
| apply(plugin = "org.jetbrains.kotlin.plugin.spring") | ||
| apply(plugin = "org.jetbrains.kotlin.plugin.jpa") | ||
| apply(plugin = "org.springframework.boot") | ||
| apply(plugin = "io.spring.dependency-management") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
find . -name "build.gradle.kts" -type f | head -20Repository: CampusTable/campus-table-server
Length of output: 204
🏁 Script executed:
cat -n ./build.gradle.ktsRepository: CampusTable/campus-table-server
Length of output: 1988
🌐 Web query:
kotlin.plugin.jpa allOpen automatic
💡 Result:
Short answer: kotlin.plugin.jpa (kotlin-jpa) does NOT automatically make JPA entity classes open. It is a wrapper for the no-arg plugin (generates synthetic no-arg ctors). To make entities "open" you must enable the all-open plugin (or explicitly configure all-open annotations), or use the kotlin-spring preset when appropriate.
What to do (Gradle Kotlin DSL):
- Add kotlin-jpa for no-arg (optional, for JPA constructors).
- Add kotlin-allopen and configure it to target JPA annotations (or jakarta versions).
Example build.gradle.kts:
plugins {
kotlin("jvm") version "1.9.x"
kotlin("plugin.jpa") version "1.9.x" // no-arg / jpa
id("org.jetbrains.kotlin.plugin.allopen") version "1.9.x" // all-open
}
allOpen {
annotation("javax.persistence.Entity")
annotation("javax.persistence.MappedSuperclass")
annotation("javax.persistence.Embeddable")
// or use the Jakarta variants:
// annotation("jakarta.persistence.Entity")
// annotation("jakarta.persistence.MappedSuperclass")
// annotation("jakarta.persistence.Embeddable")
}
Notes:
- kotlin-jpa only wires no-arg behavior; it does not imply all-open. [1][2]
- The all-open plugin supports presets (spring/micronaut/quarkus) but there is no built‑in "jpa" all-open preset — you must list the JPA annotations yourself (or use a Spring preset if your entities are annotated with Spring meta-annotations). [1][5]
Sources:
[1] Kotlin docs — All-open compiler plugin.
[2] Kotlin compiler plugins / kotlin-jpa (no-arg wrapper).
[3] Spring Initializr issue discussing that kotlin-spring/kotlin-jpa don’t auto-configure all-open for JPA entities.
🏁 Script executed:
rg "allOpen" ./build.gradle.kts ./CT-*/build.gradle.ktsRepository: CampusTable/campus-table-server
Length of output: 57
Apply kotlin.allopen plugin and configure it for JPA annotations.
The kotlin.allopen plugin is declared in the plugins block (line 7) but never applied in the subprojects block. For JPA entities to work correctly with Kotlin, they must be open for proxying. Without this, you'll encounter runtime issues with lazy loading and transaction boundaries.
Required changes
Add the plugin application:
subprojects {
apply(plugin = "java-library")
apply(plugin = "org.jetbrains.kotlin.jvm")
apply(plugin = "org.jetbrains.kotlin.plugin.spring")
apply(plugin = "org.jetbrains.kotlin.plugin.jpa")
+ apply(plugin = "org.jetbrains.kotlin.plugin.allopen")
apply(plugin = "org.springframework.boot")
apply(plugin = "io.spring.dependency-management")And add the allOpen configuration (e.g., after the dependencies block):
allOpen {
annotation("jakarta.persistence.Entity")
annotation("jakarta.persistence.MappedSuperclass")
annotation("jakarta.persistence.Embeddable")
}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In @build.gradle.kts around lines 26-32, The subprojects block applies several
plugins but misses applying the kotlin.allopen plugin and configuring it for
JPA; update the subprojects block to apply the
"org.jetbrains.kotlin.plugin.allopen" (kotlin.allopen) plugin and add an allOpen
configuration that lists the JPA annotations ("jakarta.persistence.Entity",
"jakarta.persistence.MappedSuperclass", "jakarta.persistence.Embeddable") so
Kotlin classes used as JPA entities are compiled open for proxying; locate the
subprojects block and add the apply(plugin =
"org.jetbrains.kotlin.plugin.allopen") line and an allOpen { annotation("...")
... } block (placed after the plugins/dependencies configuration) to enable this
behavior.
| api(libs.spring.boot.starter.security) | ||
| api(libs.spring.security.test) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test dependency incorrectly declared as api scope.
spring-security-test is a testing library but is declared with api scope (line 18). This:
- Adds test dependencies to the runtime classpath of all dependent modules (like CT-web)
- Can cause classpath pollution and unexpected behavior in production
- Violates dependency scope best practices
Test dependencies should use testImplementation scope.
🔎 Required fix
api(libs.spring.boot.starter.security)
- api(libs.spring.security.test)
+ testImplementation(libs.spring.security.test)If CT-web or other modules also need Spring Security Test, they should declare it explicitly in their own dependencies block rather than inheriting it from CT-auth.
📝 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.
| api(libs.spring.boot.starter.security) | |
| api(libs.spring.security.test) | |
| api(libs.spring.boot.starter.security) | |
| testImplementation(libs.spring.security.test) |
🤖 Prompt for AI Agents
In @CT-auth/build.gradle.kts around lines 17-18, Replace the incorrect api(...)
declaration for the test library with a test-only scope: change
api(libs.spring.security.test) to testImplementation(libs.spring.security.test)
so spring-security-test is only on the test classpath; leave
api(libs.spring.boot.starter.security) as-is and ensure any other modules that
need spring-security-test add their own testImplementation entry.
| profiles: | ||
| active: prod |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hardcoded production profile breaks local development.
Setting spring.profiles.active: prod directly in application.yml forces all environments (local, dev, CI) to run with the production profile, which can lead to incorrect database connections, missing test data, or disabled debug features.
Instead, use environment-specific configuration files (application-local.yml, application-prod.yml) or override via environment variable (SPRING_PROFILES_ACTIVE).
🔎 Recommended approach
Remove the hardcoded profile and rely on environment-based activation:
spring:
- profiles:
- active: prod
config:
import: classpath:config-imports.ymlThen set the profile via environment variable in your deployment:
- Local:
SPRING_PROFILES_ACTIVE=local - Production:
SPRING_PROFILES_ACTIVE=prod
🤖 Prompt for AI Agents
In @CT-web/src/main/resources/application.yml around lines 2-3, The file
currently hardcodes the production profile via the YAML key "profiles.active:
prod", which forces prod settings everywhere; remove that hardcoded
"profiles.active" entry from application.yml, create environment-specific
override files (e.g., application-local.yml, application-prod.yml) for
profile-specific settings, and rely on the SPRING_PROFILES_ACTIVE environment
variable (or CI/deploy config) to activate the correct profile at runtime rather
than embedding "prod" in application.yml.
| servlet: | ||
| multipart: | ||
| enabled: true # 파일 업로드 허용 | ||
| max-file-size: 200MB # 업로드 파일 최대 크기 | ||
| max-request-size: 1000MB # 요청 전체 최대 크기 | ||
| file-size-threshold: 10MB |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
git ls-files | head -30Repository: CampusTable/campus-table-server
Length of output: 886
🏁 Script executed:
find . -maxdepth 3 -type f -name "*.md" -o -name "README*" | head -20Repository: CampusTable/campus-table-server
Length of output: 668
🏁 Script executed:
rg -l "upload|file.*size" --type java --max-count 20Repository: CampusTable/campus-table-server
Length of output: 57
🏁 Script executed:
find . -name "README*" -type f | grep -v node_modulesRepository: CampusTable/campus-table-server
Length of output: 102
🏁 Script executed:
rg -l "upload|multipart" --type java -g "*.java" | head -20Repository: CampusTable/campus-table-server
Length of output: 223
🏁 Script executed:
cat CT-web/src/main/resources/application.yml | head -40Repository: CampusTable/campus-table-server
Length of output: 837
🏁 Script executed:
find . -maxdepth 2 -name "*.md" -type f | grep -i readmeRepository: CampusTable/campus-table-server
Length of output: 57
🏁 Script executed:
find CT-web/src/main/java -type f -name "*.java" | xargs rg -l "upload|multipart" 2>/dev/null | head -20Repository: CampusTable/campus-table-server
Length of output: 189
🏁 Script executed:
find . -type f -name "*.java" | xargs rg -l "MultipartFile|@PostMapping.*upload" 2>/dev/null | head -20Repository: CampusTable/campus-table-server
Length of output: 57
🏁 Script executed:
ls -la CT-web/src/main/Repository: CampusTable/campus-table-server
Length of output: 292
🏁 Script executed:
find . -type f -name "*.java" | head -30Repository: CampusTable/campus-table-server
Length of output: 57
🏁 Script executed:
cat ./README.md 2>/dev/null || find . -maxdepth 3 -iname "*readme*" -type f | head -5Repository: CampusTable/campus-table-server
Length of output: 102
🏁 Script executed:
find CT-web/src/main/kotlin -type f -name "*.kt" | xargs rg -l "upload|multipart|MultipartFile" 2>/dev/null | head -20Repository: CampusTable/campus-table-server
Length of output: 57
🏁 Script executed:
find CT-web/src/main/kotlin -type f -name "*.kt" | xargs rg -l "PostMapping|RequestBody" 2>/dev/null | head -20Repository: CampusTable/campus-table-server
Length of output: 57
🏁 Script executed:
cat .cursor/scripts/README.md | head -50Repository: CampusTable/campus-table-server
Length of output: 1481
🏁 Script executed:
find CT-web/src/main/kotlin -type f -name "*.kt" | head -30Repository: CampusTable/campus-table-server
Length of output: 323
🏁 Script executed:
find CT-web/src/main/kotlin -type f -name "*.kt" | xargs rg "@RestController|@Controller|class.*Controller" | head -30Repository: CampusTable/campus-table-server
Length of output: 57
🏁 Script executed:
rg -i "file.*upload|upload.*file|200.*MB|1000.*MB" --type kotlinRepository: CampusTable/campus-table-server
Length of output: 57
🏁 Script executed:
cat CT-web/src/main/kotlin/com/chuseok22/ctweb/CampusTableServerApplication.ktRepository: CampusTable/campus-table-server
Length of output: 366
🏁 Script executed:
find . -type f \( -name "*.java" -o -name "*.kt" -o -name "*.groovy" \) | wc -lRepository: CampusTable/campus-table-server
Length of output: 76
🏁 Script executed:
rg -i "multipart|upload.*file|file.*upload" --type-list | head -5 && rg -i "multipart\|upload" . --max-count 20 2>/dev/nullRepository: CampusTable/campus-table-server
Length of output: 464
🏁 Script executed:
rg -i "multipart\|upload\|file.*size" . --max-count 30Repository: CampusTable/campus-table-server
Length of output: 57
🏁 Script executed:
cat CT-web/src/main/kotlin/com/chuseok22/ctweb/infrastructure/config/SwaggerConfig.ktRepository: CampusTable/campus-table-server
Length of output: 1726
🏁 Script executed:
git log --oneline CT-web/src/main/resources/application.yml | head -10Repository: CampusTable/campus-table-server
Length of output: 184
🏁 Script executed:
find . -maxdepth 3 -name "pom.xml" -o -name "build.gradle.kts"Repository: CampusTable/campus-table-server
Length of output: 204
🏁 Script executed:
ls -la CT-web/Repository: CampusTable/campus-table-server
Length of output: 304
🏁 Script executed:
git log --all --oneline | head -20Repository: CampusTable/campus-table-server
Length of output: 279
🏁 Script executed:
find . -type f -name "*.kt" | xargs rg "@RestController|@PostMapping|@RequestMapping|fun.*upload" 2>/dev/null | head -30Repository: CampusTable/campus-table-server
Length of output: 57
🏁 Script executed:
git log --all --pretty=format:"%h %s" | grep -i "upload\|file"Repository: CampusTable/campus-table-server
Length of output: 57
🏁 Script executed:
cat CT-web/build.gradle.ktsRepository: CampusTable/campus-table-server
Length of output: 376
🏁 Script executed:
find . -type f -name "*.kt" -path "*/src/main/*" | xargs grep -l "upload\|MultipartFile\|file.*size" 2>/dev/nullRepository: CampusTable/campus-table-server
Length of output: 59
🏁 Script executed:
find . -type f -name "*.kt" -path "*/src/main/*" | xargs wc -l | tail -1Repository: CampusTable/campus-table-server
Length of output: 85
🏁 Script executed:
cat CT-common/build.gradle.ktsRepository: CampusTable/campus-table-server
Length of output: 528
🏁 Script executed:
find . -type f -name "*.kt" -o -name "*.md" -o -name "*.txt" | xargs grep -l "upload\|파일" 2>/dev/null | head -20Repository: CampusTable/campus-table-server
Length of output: 672
🏁 Script executed:
find . -maxdepth 3 -name "*.md" -type f | xargs cat 2>/dev/nullRepository: CampusTable/campus-table-server
Length of output: 50390
🏁 Script executed:
rg "max.*file\|max.*request" -A 2 -B 2 CT-web/src/main/resources/Repository: CampusTable/campus-table-server
Length of output: 57
Remove or reduce multipart configuration — currently unused and poses unnecessary security risk if ever activated.
The multipart configuration in application.yml (lines 25-30) is configured with very permissive limits (max-file-size: 200MB, max-request-size: 1000MB), but no corresponding upload handling code exists in the codebase.
Recommendation:
- If file upload is not planned, remove or disable the multipart configuration entirely
- If file upload is planned for future development, reduce these limits to practical defaults and implement security controls:
max-file-size: 10-50MB(appropriate for most use cases)max-request-size: 50-100MB- Add rate limiting on upload endpoints
- Add authentication/authorization checks
- Implement virus scanning where appropriate
🤖 Prompt for AI Agents
In @CT-web/src/main/resources/application.yml around lines 25-30, The
servlet.multipart settings in application.yml are overly permissive and unused;
either remove the entire servlet.multipart block to disable multipart support
or, if uploads will be supported, lower limits and harden controls: change
max-file-size to 10-50MB and max-request-size to 50-100MB, and ensure upload
endpoints are protected via authentication/authorization, rate limiting, and
antivirus scanning before enabling the servlet.multipart configuration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Fix all issues with AI Agents 🤖
In @build.gradle.kts:
- Around line 18-23: Remove the unused custom Maven repository declaration
inside the repositories block (the maven { url =
uri("https://nexus.chuseok22.com/repository/maven-releases/") } entry) in
build.gradle.kts so only standard repositories (e.g., mavenCentral()) remain;
this simplifies the build configuration and avoids referencing an unused Nexus
host.
In
@CT-web/src/main/kotlin/com/chuseok22/ctweb/infrastructure/config/ComponentScanConfig.kt:
- Around line 6-11: The ComponentScanConfig class is redundant because
@SpringBootApplication already scans the main package, so remove the entire
ComponentScanConfig class (the class named ComponentScanConfig annotated with
@Configuration and @ComponentScan(basePackages = ["com.chuseok22.*"]) ); if you
truly need cross-module scanning in future, replace the wildcard with explicit
package names or use @Import in the application class instead; if you decide to
keep the empty class for now, annotate or configure to suppress detekt’s
EmptyClassBlock warning (e.g., add a suppression) and add a comment explaining
why it must remain.
In
@CT-web/src/main/kotlin/com/chuseok22/ctweb/infrastructure/config/DatabaseScanConfig.kt:
- Around line 7-11: DatabaseScanConfig is unnecessary because there are
currently no entities or repositories to scan; remove the DatabaseScanConfig
class (and its @EntityScan/@EnableJpaRepositories annotations) to rely on Spring
Boot’s default scanning from the @SpringBootApplication in package
com.chuseok22.ctweb, or if you intend to add entities from other modules later,
replace the broad wildcard with explicit target packages in DatabaseScanConfig
(or recreate it then) so only real entity/repository packages are scanned.
♻️ Duplicate comments (2)
build.gradle.kts (1)
26-32: JPA 엔티티를 위한kotlin.allopen플러그인을 적용하고 구성하세요.
kotlin.allopen플러그인이 선언되어 있지만(라인 7) subprojects 블록에서 적용되지 않았습니다. JPA 엔티티가 Kotlin에서 올바르게 작동하려면 프록시 생성을 위해open이어야 합니다. 이것이 없으면 지연 로딩 및 트랜잭션 경계에서 런타임 문제가 발생합니다.🔎 필요한 변경사항
플러그인 적용을 추가하세요:
subprojects { apply(plugin = "java-library") apply(plugin = "org.jetbrains.kotlin.jvm") apply(plugin = "org.jetbrains.kotlin.plugin.spring") apply(plugin = "org.jetbrains.kotlin.plugin.jpa") + apply(plugin = "org.jetbrains.kotlin.plugin.allopen") apply(plugin = "org.springframework.boot") apply(plugin = "io.spring.dependency-management")그리고 allOpen 구성을 추가하세요 (예: dependencies 블록 이후):
allOpen { annotation("jakarta.persistence.Entity") annotation("jakarta.persistence.MappedSuperclass") annotation("jakarta.persistence.Embeddable") }Based on past review comments.
CT-web/build.gradle.kts (1)
1-4: 메인 애플리케이션 모듈에bootJar설정을 명시적으로 추가하세요.CT-web은
@SpringBootApplication어노테이션이 적용된 메인 애플리케이션 모듈입니다. 현재 코드에는bootJar와jar작업의 설정이 명시되어 있지 않습니다. 다른 모든 라이브러리 모듈(CT-auth, CT-common, CT-member)에서는bootJar를 비활성화하고jar를 활성화하는 설정을 명시적으로 정의하고 있으므로, 메인 애플리케이션 모듈도 일관성 있게bootJar를 활성화하는 설정을 추가해야 합니다.권장 설정
plugins { id("java-library") id("org.springframework.boot") } + +tasks.bootJar { + enabled = true + archiveClassifier.set("") +} + +tasks.jar { + enabled = false +} dependencies { implementation(project(":CT-auth"))
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
CT-web/build.gradle.ktsCT-web/src/main/kotlin/com/chuseok22/ctweb/infrastructure/config/ComponentScanConfig.ktCT-web/src/main/kotlin/com/chuseok22/ctweb/infrastructure/config/DatabaseScanConfig.ktbuild.gradle.kts
🧰 Additional context used
🪛 detekt (1.23.8)
CT-web/src/main/kotlin/com/chuseok22/ctweb/infrastructure/config/ComponentScanConfig.kt
[warning] 10-11: The class or object ComponentScanConfig is empty.
(detekt.empty-blocks.EmptyClassBlock)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (4)
CT-web/build.gradle.kts (1)
6-12: 의존성 구조가 적절합니다.멀티모듈 구조에서 web 모듈이 다른 모듈들(auth, common, member)을 의존하고 Swagger UI를 포함하는 것은 올바른 설계입니다.
build.gradle.kts (3)
34-38: Java 21 툴체인 구성이 적절합니다.모든 서브프로젝트에 대해 Java 21을 통일되게 사용하는 것은 멀티모듈 프로젝트에서 일관성을 보장하는 좋은 방법입니다.
40-47: 의존성 및 구성 설정이 올바릅니다.
compileOnly가annotationProcessor를 확장하는 것은 어노테이션 처리기를 컴파일 클래스패스에서 사용할 수 있도록 하는 표준 패턴입니다.- 테스트 의존성(JUnit5, Platform Launcher)이 적절하게 구성되었습니다.
53-58:compilerOptions마이그레이션을 완료했습니다.더 이상 사용되지 않는
kotlinOptions대신 새로운compilerOptionsAPI를 사용하여 Kotlin 2.0+와의 호환성을 보장합니다. JVM 타겟 21 설정 및 strict JSR-305 null 검사 활성화가 올바르게 구성되었습니다.
CT-web/src/main/kotlin/com/chuseok22/ctweb/infrastructure/config/ComponentScanConfig.kt
Show resolved
Hide resolved
CT-web/src/main/kotlin/com/chuseok22/ctweb/infrastructure/config/DatabaseScanConfig.kt
Show resolved
Hide resolved
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Fix all issues with AI Agents 🤖
In @gradle/libs.versions.toml:
- Line 6: The declared swaggerUI version in libs.versions.toml (swaggerUI =
"3.0.1") targets Spring Boot 4 and is incompatible with Spring Boot 3.5.9;
update the swaggerUI entry to a Spring Boot 3 compatible 2.8.x release (e.g.,
change the swaggerUI version to the latest 2.8.*) so that
springdoc-openapi-starter-webmvc-ui matches Spring Boot 3.5.9.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
CT-web/build.gradle.ktsgradle/libs.versions.toml
🚧 Files skipped from review as they are similar to previous changes (1)
- CT-web/build.gradle.kts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (2)
gradle/libs.versions.toml (2)
3-4: Spring Boot 3.5.9와 Kotlin 1.9.25는 호환 가능합니다.Spring Boot 3.5.9는 2025년 12월 18일에 출시된 3.5.x 라인의 최신 버전이며, Spring Boot의 관리되는 의존성에 Kotlin 1.9.25가 포함되어 있습니다. 두 버전의 조합은 유효하고 정상적으로 작동합니다.
7-9: Chuseok22 저장소가 이미 구성되어 있으므로, 의존성 접근 가능성을 확인하세요.Nexus 저장소(
https://nexus.chuseok22.com/repository/maven-releases/)가 build.gradle.kts에 이미 설정되어 있습니다. 다만 세 개의 커스텀 의존성(com.chuseok22:ApiChangeLog:1.0.1,com.chuseok22:sejong-portal-login:1.0.0,com.chuseok22:logging:0.0.9)이 실제로 해당 저장소에 존재하고 다운로드 가능한지 확인이 필요합니다.
| kotlin = "1.9.25" | ||
| springBoot = "3.5.9" | ||
| springDependencyManagement = "1.1.7" | ||
| swaggerUI = "3.0.1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
cat gradle/libs.versions.tomlRepository: CampusTable/campus-table-server
Length of output: 2518
🌐 Web query:
SpringDoc OpenAPI 3.0.1 Spring Boot 3.5.9 compatibility
💡 Result:
Short answer: springdoc-openapi 3.0.1 targets Spring Boot 4, so it is not compatible with Spring Boot 3.5.9. For Spring Boot 3.5.x use springdoc-openapi 2.8.x (e.g. latest 2.8.*). [1][2]
Recommendation: replace org.springdoc:springdoc-openapi-starter-* version 3.0.1 with a 2.8.x release (or the latest 2.8.*) when running Spring Boot 3.5.9. [1] [2]
Sources:
- springdoc compatibility matrix (Spring Boot 3.5.x → springdoc 2.8.x). [1]
- springdoc v3 (3.x) notes showing 3.x is for Spring Boot 4. [2]
SpringDoc OpenAPI 버전을 Spring Boot 3.5.9와 호환되는 버전으로 업그레이드하세요.
현재 설정된 springdoc-openapi-starter-webmvc-ui 버전 3.0.1은 Spring Boot 4을 대상으로 하며 Spring Boot 3.5.9와 호환되지 않습니다. Spring Boot 3.5.9를 사용할 경우 swaggerUI = "2.8.x"(최신 2.8.* 버전)으로 변경해야 합니다.
🤖 Prompt for AI Agents
In @gradle/libs.versions.toml around line 6, The declared swaggerUI version in
libs.versions.toml (swaggerUI = "3.0.1") targets Spring Boot 4 and is
incompatible with Spring Boot 3.5.9; update the swaggerUI entry to a Spring Boot
3 compatible 2.8.x release (e.g., change the swaggerUI version to the latest
2.8.*) so that springdoc-openapi-starter-webmvc-ui matches Spring Boot 3.5.9.
✨ 변경 사항
✅ 테스트
Summary by CodeRabbit
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.