Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
67eafa0
프로젝트_멀티모듈_구조_도입 : feat : root build.gradle.kts 설정 https://github.com/…
Chuseok22 Jan 2, 2026
0a57603
프로젝트_멀티모듈_구조_도입 : feat : [common 모듈] build.gradle.kts 설정 https://gith…
Chuseok22 Jan 2, 2026
896f8b2
프로젝트_멀티모듈_구조_도입 : feat : 의존성 버전 중앙 관리를 위한 libs.toml 파일추가 https://gith…
Chuseok22 Jan 2, 2026
414531d
프로젝트_멀티모듈_구조_도입 : feat : [auth 모듈] build.gradle.kts 설정 https://github…
Chuseok22 Jan 2, 2026
7499f89
프로젝트_멀티모듈_구조_도입 : feat : [member 모듈] build.gradle.kts 설정 https://gith…
Chuseok22 Jan 2, 2026
61da421
프로젝트_멀티모듈_구조_도입 : feat : [web 모듈] build.gradle.kts 설정 https://github.…
Chuseok22 Jan 2, 2026
b521d03
프로젝트_멀티모듈_구조_도입 : feat : settings.gradle.kts 모듈 설정 추가 https://github.…
Chuseok22 Jan 2, 2026
d1c1ba8
프로젝트_멀티모듈_구조_도입 : feat : application.yml web 모듈 이동 https://github.com…
Chuseok22 Jan 2, 2026
efdffd2
프로젝트_멀티모듈_구조_도입 : feat : gitignore 설정 https://github.com/CampusTable/…
Chuseok22 Jan 2, 2026
f4652fd
프로젝트_멀티모듈_구조_도입 : feat : cicd 시 환경변수 파일 동적 생성 https://github.com/Camp…
Chuseok22 Jan 2, 2026
d1aff91
프로젝트_멀티모듈_구조_도입 : feat : swagger-ui 의존성 추가 https://github.com/CampusT…
Chuseok22 Jan 3, 2026
f51eb04
프로젝트_멀티모듈_구조_도입 : feat : Swagger 세팅 https://github.com/CampusTable/ca…
Chuseok22 Jan 3, 2026
fa62857
프로젝트_멀티모듈_구조_도입 : feat : CommonUtil.kt 추가 https://github.com/CampusTa…
Chuseok22 Jan 5, 2026
8edefd3
프로젝트_멀티모듈_구조_도입 : feat : coderabbit 추가 https://github.com/CampusTable…
Chuseok22 Jan 5, 2026
6760122
프로젝트_멀티모듈_구조_도입 : feat : [web모듈] component, database 스캔 추가 https://gi…
Chuseok22 Jan 5, 2026
5f39fec
프로젝트_멀티모듈_구조_도입 : feat : nexus chuseok22 관련 의존성 추가 https://github.com…
Chuseok22 Jan 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .coderabbit.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
language: "ko-KR"
ignored_branch: ""
early_access: false
reviews:
profile: "chill"
request_changes_workflow: false
high_level_summary: true
poem: true
review_status: true
collapse_walkthrough: false
auto_review:
enabled: true
drafts: false
base_branches:
- test
chat:
auto_reply: true
12 changes: 6 additions & 6 deletions .github/workflows/spring-boot-cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ jobs:
- name: Gradle Wrapper 실행권한 부여
run: chmod +x gradlew

# application-prod.yml 파일을 빌드 전에 생성
- name: Create application-prod.yml from secret
- name: application-prod.yml 파일 생성
run: |
mkdir -p src/main/resources
cat << 'EOF' > ./src/main/resources/application-prod.yml
${{ secrets.APPLICATION_PROD_YML }}
EOF
echo "${{ secrets.APPLICATION_PROD_YML }}" > CT-web/src/main/resources/application-prod.yml

- name: config-imports.yml 파일 생성
run: |
echo "${{ secrets.CONFIG_IMPORTS_YML }}" > CT-web/src/main/resources/config-imports.yml

# 브랜치 별 active profile 설정
- name: Decide active profile
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,6 @@ out/
.kotlin

### ENV ###
application-*.yml
CT-web/src/main/resources/application-*.yml
CT-web/src/main/resources/config-imports.yml
CT-web/src/main/resources/springdoc.yml
20 changes: 20 additions & 0 deletions CT-auth/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
plugins {
id("java-library")
}

tasks.bootJar {
enabled = false
}

tasks.jar {
enabled = true
archiveClassifier.set("")
}

dependencies {
implementation(project(":CT-common"))

api(libs.spring.boot.starter.security)
api(libs.spring.security.test)
Comment on lines +17 to +18
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

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.

Suggested change
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.

}

31 changes: 31 additions & 0 deletions CT-common/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
plugins {
id("java-library")
}

tasks.bootJar {
enabled = false
}

tasks.jar {
enabled = true
archiveClassifier.set("")
}

// common 모듈 api 의존성은 모든 모듈에 적용
dependencies {
// Spring Starter Web
api(libs.spring.boot.starter.web)

// JPA
api(libs.spring.boot.starter.data.jpa)

// Validation
api(libs.spring.boot.starter.validation)

// Jackson
api(libs.jackson.module.kotlin)

api(libs.kotlin.reflect)
api(libs.kotlin.stdlib)
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.chuseok22.ctcommon.core.util

/**
* null 또는 빈 문자열을 기본값으로 대체
*/
fun String?.nvl(fallback: String): String {
return when {
this == null -> fallback
this == "null" -> fallback
this.isBlank() -> fallback
else -> this
}
}
19 changes: 19 additions & 0 deletions CT-member/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
plugins {
id("java-library")
}

tasks.bootJar {
enabled = false
}

tasks.jar {
enabled = true
archiveClassifier.set("")
}

dependencies {
implementation(project(":CT-common"))

// Postgres
api(libs.postgresql)
}
15 changes: 15 additions & 0 deletions CT-web/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
plugins {
id("java-library")
id("org.springframework.boot")
}

dependencies {
implementation(project(":CT-auth"))
implementation(project(":CT-common"))
implementation(project(":CT-member"))

implementation(libs.swagger.ui)
implementation(libs.http.logging)
implementation(libs.api.change.log)
}

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.chuseok22.campustableserver
package com.chuseok22.ctweb

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.chuseok22.ctweb.infrastructure.config

import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration

@Configuration
@ComponentScan(basePackages = [
"com.chuseok22.*"
])
class ComponentScanConfig {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.chuseok22.ctweb.infrastructure.config

import org.springframework.boot.autoconfigure.domain.EntityScan
import org.springframework.context.annotation.Configuration
import org.springframework.data.jpa.repository.config.EnableJpaRepositories

@Configuration
@EntityScan(basePackages = ["com.chuseok22.*"])
@EnableJpaRepositories(basePackages = ["com.chuseok22.*"])
class DatabaseScanConfig {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.chuseok22.ctweb.infrastructure.config

import com.chuseok22.ctweb.infrastructure.properties.SpringDocProperties
import io.swagger.v3.oas.annotations.OpenAPIDefinition
import io.swagger.v3.oas.annotations.info.Info
import io.swagger.v3.oas.models.Components
import io.swagger.v3.oas.models.OpenAPI
import io.swagger.v3.oas.models.security.SecurityRequirement
import io.swagger.v3.oas.models.security.SecurityScheme
import io.swagger.v3.oas.models.servers.Server
import org.springdoc.core.customizers.OpenApiCustomizer
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@OpenAPIDefinition(
info = Info(
title = "캠퍼스 테이블 CampusTable"
)
)
@Configuration
@EnableConfigurationProperties(SpringDocProperties::class)
class SwaggerConfig(
private val properties: SpringDocProperties
) {

@Bean
fun OpenAPI(): OpenAPI {
val apiKey: SecurityScheme = SecurityScheme()
.type(SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT")
.`in`(SecurityScheme.In.HEADER)
.name("Authorization")

return OpenAPI()
.components(Components().addSecuritySchemes("Bearer Token", apiKey))
.addSecurityItem(SecurityRequirement().addList("Bearer Token"))
}

@Bean
fun serverCustomizer(): OpenApiCustomizer {
return OpenApiCustomizer { openApi ->
properties.servers.forEach { server ->
openApi.addServersItem(
Server()
.url(server.url)
.description(server.description)
)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.chuseok22.ctweb.infrastructure.properties

import jakarta.validation.Valid
import jakarta.validation.constraints.NotBlank
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.validation.annotation.Validated

@Validated
@ConfigurationProperties(prefix = "springdoc")
data class SpringDocProperties(
@field:Valid
val servers: List<Servers>
) {
data class Servers(
@field:NotBlank
val url: String,
@field:NotBlank
val description: String
)
}
30 changes: 30 additions & 0 deletions CT-web/src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
spring:
profiles:
active: prod
Comment on lines +2 to +3
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

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

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

config:
import: classpath:config-imports.yml
jpa:
open-in-view: false
properties:
hibernate:
jdbc:
time_zone: UTC
dialect: org.hibernate.dialect.PostgreSQLDialect
show_sql: false
format_sql: true
use_sql_comments: true
flyway:
enabled: true
locations: classpath:db/migration
baseline-on-migrate: false
validate-on-migrate: true
out-of-order: false # 과거 버전이 뒤늦게 들어오는 경우 방지
clean-disabled: true # 실수로 clean 되는 경우 방지
jackson:
time-zone: Asia/Seoul
servlet:
multipart:
enabled: true # 파일 업로드 허용
max-file-size: 200MB # 업로드 파일 최대 크기
max-request-size: 1000MB # 요청 전체 최대 크기
file-size-threshold: 10MB
Comment on lines +25 to +30
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

git ls-files | head -30

Repository: CampusTable/campus-table-server

Length of output: 886


🏁 Script executed:

find . -maxdepth 3 -type f -name "*.md" -o -name "README*" | head -20

Repository: CampusTable/campus-table-server

Length of output: 668


🏁 Script executed:

rg -l "upload|file.*size" --type java --max-count 20

Repository: CampusTable/campus-table-server

Length of output: 57


🏁 Script executed:

find . -name "README*" -type f | grep -v node_modules

Repository: CampusTable/campus-table-server

Length of output: 102


🏁 Script executed:

rg -l "upload|multipart" --type java -g "*.java" | head -20

Repository: CampusTable/campus-table-server

Length of output: 223


🏁 Script executed:

cat CT-web/src/main/resources/application.yml | head -40

Repository: CampusTable/campus-table-server

Length of output: 837


🏁 Script executed:

find . -maxdepth 2 -name "*.md" -type f | grep -i readme

Repository: 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 -20

Repository: 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 -20

Repository: 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 -30

Repository: CampusTable/campus-table-server

Length of output: 57


🏁 Script executed:

cat ./README.md 2>/dev/null || find . -maxdepth 3 -iname "*readme*" -type f | head -5

Repository: 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 -20

Repository: 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 -20

Repository: CampusTable/campus-table-server

Length of output: 57


🏁 Script executed:

cat .cursor/scripts/README.md | head -50

Repository: CampusTable/campus-table-server

Length of output: 1481


🏁 Script executed:

find CT-web/src/main/kotlin -type f -name "*.kt" | head -30

Repository: 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 -30

Repository: CampusTable/campus-table-server

Length of output: 57


🏁 Script executed:

rg -i "file.*upload|upload.*file|200.*MB|1000.*MB" --type kotlin

Repository: CampusTable/campus-table-server

Length of output: 57


🏁 Script executed:

cat CT-web/src/main/kotlin/com/chuseok22/ctweb/CampusTableServerApplication.kt

Repository: CampusTable/campus-table-server

Length of output: 366


🏁 Script executed:

find . -type f \( -name "*.java" -o -name "*.kt" -o -name "*.groovy" \) | wc -l

Repository: 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/null

Repository: CampusTable/campus-table-server

Length of output: 464


🏁 Script executed:

rg -i "multipart\|upload\|file.*size" . --max-count 30

Repository: CampusTable/campus-table-server

Length of output: 57


🏁 Script executed:

cat CT-web/src/main/kotlin/com/chuseok22/ctweb/infrastructure/config/SwaggerConfig.kt

Repository: CampusTable/campus-table-server

Length of output: 1726


🏁 Script executed:

git log --oneline CT-web/src/main/resources/application.yml | head -10

Repository: 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 -20

Repository: 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 -30

Repository: 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.kts

Repository: 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/null

Repository: CampusTable/campus-table-server

Length of output: 59


🏁 Script executed:

find . -type f -name "*.kt" -path "*/src/main/*" | xargs wc -l | tail -1

Repository: CampusTable/campus-table-server

Length of output: 85


🏁 Script executed:

cat CT-common/build.gradle.kts

Repository: 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 -20

Repository: CampusTable/campus-table-server

Length of output: 672


🏁 Script executed:

find . -maxdepth 3 -name "*.md" -type f | xargs cat 2>/dev/null

Repository: 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.

Loading
Loading