api와 storage에 대해 멀티모듈 구조로 분리
This commit is contained in:
8
.claude/settings.local.json
Normal file
8
.claude/settings.local.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(./gradlew balance-core-api:dependencies:*)",
|
||||||
|
"Bash(./gradlew detekt:*)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
27
.editorconfig
Normal file
27
.editorconfig
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
insert_final_newline = true
|
||||||
|
max_line_length = 120
|
||||||
|
tab_width = 4
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.{kt,kts}]
|
||||||
|
indent_size = 4
|
||||||
|
continuation_indent_size = 4
|
||||||
|
ij_kotlin_align_multiline_parameters = true
|
||||||
|
ij_kotlin_allow_trailing_comma = true
|
||||||
|
ij_kotlin_allow_trailing_comma_on_call_site = true
|
||||||
|
|
||||||
|
[*.gradle]
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.{yml,yaml}]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -38,3 +38,6 @@ out/
|
|||||||
|
|
||||||
### Kotlin ###
|
### Kotlin ###
|
||||||
.kotlin
|
.kotlin
|
||||||
|
|
||||||
|
### Lint ###
|
||||||
|
detekt-baseline.xml
|
||||||
|
|||||||
726
CLAUDE.md
Normal file
726
CLAUDE.md
Normal file
@@ -0,0 +1,726 @@
|
|||||||
|
# Spring Boot 멀티모듈 프로젝트 설계 가이드라인
|
||||||
|
|
||||||
|
## 개요
|
||||||
|
|
||||||
|
이 문서는 Spring Boot 프로젝트를 멀티모듈 구조로 설계하고 구현하기 위한 가이드라인입니다.
|
||||||
|
본 프로젝트(balance)의 실제 구조 변경 경험을 바탕으로 작성되었습니다.
|
||||||
|
|
||||||
|
## 목차
|
||||||
|
|
||||||
|
1. [멀티모듈 구조의 이점](#멀티모듈-구조의-이점)
|
||||||
|
2. [모듈 분리 원칙](#모듈-분리-원칙)
|
||||||
|
3. [표준 모듈 구조](#표준-모듈-구조)
|
||||||
|
4. [Gradle 설정](#gradle-설정)
|
||||||
|
5. [의존성 관리 전략](#의존성-관리-전략)
|
||||||
|
6. [패키지 구조 및 네이밍](#패키지-구조-및-네이밍)
|
||||||
|
7. [주의사항 및 베스트 프랙티스](#주의사항-및-베스트-프랙티스)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 멀티모듈 구조의 이점
|
||||||
|
|
||||||
|
### 1. 관심사의 분리 (Separation of Concerns)
|
||||||
|
- 각 모듈이 명확한 책임을 가짐
|
||||||
|
- 도메인, 데이터 접근, API 레이어를 물리적으로 분리
|
||||||
|
|
||||||
|
### 2. 재사용성 (Reusability)
|
||||||
|
- Storage 모듈처럼 독립적인 모듈은 다른 프로젝트에서 재사용 가능
|
||||||
|
- 공통 기능을 별도 모듈로 추출하여 여러 프로젝트에서 활용
|
||||||
|
|
||||||
|
### 3. 빌드 최적화
|
||||||
|
- 변경된 모듈만 재빌드
|
||||||
|
- 병렬 빌드 가능
|
||||||
|
|
||||||
|
### 4. 팀 협업
|
||||||
|
- 모듈별로 소유권 분리 가능
|
||||||
|
- 충돌 최소화
|
||||||
|
|
||||||
|
### 5. 의존성 제어
|
||||||
|
- 모듈 간 의존성을 명시적으로 관리
|
||||||
|
- 순환 참조 방지
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 모듈 분리 원칙
|
||||||
|
|
||||||
|
### 레이어드 아키텍처 기반 분리
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────┐
|
||||||
|
│ API/Presentation │ ← balance-core-api
|
||||||
|
│ (Controller) │
|
||||||
|
├─────────────────────┤
|
||||||
|
│ Business Logic │ ← balance-core-api
|
||||||
|
│ (Service) │
|
||||||
|
├─────────────────────┤
|
||||||
|
│ Data Access │ ← storage
|
||||||
|
│ (Entity, Repo) │
|
||||||
|
└─────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 권장 모듈 분리 전략
|
||||||
|
|
||||||
|
#### 1. Storage/Domain 모듈
|
||||||
|
**목적:** 데이터 엔티티 및 레포지토리
|
||||||
|
|
||||||
|
**포함 요소:**
|
||||||
|
- JPA 엔티티 (`@Entity`)
|
||||||
|
- Repository 인터페이스 (`JpaRepository`)
|
||||||
|
- 도메인 모델
|
||||||
|
- 데이터 접근 로직
|
||||||
|
|
||||||
|
**특징:**
|
||||||
|
- 다른 모듈에 의존하지 않음 (독립적)
|
||||||
|
- Spring Boot 실행 불가 (라이브러리 모듈)
|
||||||
|
- 다른 프로젝트에서 재사용 가능
|
||||||
|
|
||||||
|
#### 2. Core API 모듈
|
||||||
|
**목적:** REST API 및 비즈니스 로직
|
||||||
|
|
||||||
|
**포함 요소:**
|
||||||
|
- REST 컨트롤러 (`@RestController`)
|
||||||
|
- 서비스 계층 (`@Service`)
|
||||||
|
- DTO (Data Transfer Objects)
|
||||||
|
- 애플리케이션 진입점 (`@SpringBootApplication`)
|
||||||
|
|
||||||
|
**특징:**
|
||||||
|
- Storage 모듈에 의존
|
||||||
|
- 실행 가능한 Spring Boot 애플리케이션
|
||||||
|
- HTTP 엔드포인트 제공
|
||||||
|
|
||||||
|
#### 3. (선택) Common 모듈
|
||||||
|
**목적:** 공통 유틸리티 및 설정
|
||||||
|
|
||||||
|
**포함 요소:**
|
||||||
|
- 공통 유틸리티 클래스
|
||||||
|
- 공통 예외 클래스
|
||||||
|
- 공통 설정
|
||||||
|
- 공통 DTO
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 표준 모듈 구조
|
||||||
|
|
||||||
|
### 디렉토리 구조 예시
|
||||||
|
|
||||||
|
```
|
||||||
|
project-root/
|
||||||
|
├── settings.gradle
|
||||||
|
├── build.gradle
|
||||||
|
├── storage/
|
||||||
|
│ ├── build.gradle
|
||||||
|
│ └── src/
|
||||||
|
│ ├── main/
|
||||||
|
│ │ └── kotlin/
|
||||||
|
│ │ └── com/company/project/storage/
|
||||||
|
│ │ ├── entity/
|
||||||
|
│ │ │ ├── User.kt
|
||||||
|
│ │ │ └── Order.kt
|
||||||
|
│ │ └── repository/
|
||||||
|
│ │ ├── UserRepository.kt
|
||||||
|
│ │ └── OrderRepository.kt
|
||||||
|
│ └── test/
|
||||||
|
│ └── kotlin/
|
||||||
|
│ └── com/company/project/storage/
|
||||||
|
│
|
||||||
|
├── core-api/
|
||||||
|
│ ├── build.gradle
|
||||||
|
│ └── src/
|
||||||
|
│ ├── main/
|
||||||
|
│ │ ├── kotlin/
|
||||||
|
│ │ │ └── com/company/project/
|
||||||
|
│ │ │ ├── Application.kt
|
||||||
|
│ │ │ ├── controller/
|
||||||
|
│ │ │ │ ├── UserController.kt
|
||||||
|
│ │ │ │ └── OrderController.kt
|
||||||
|
│ │ │ └── service/
|
||||||
|
│ │ │ ├── UserService.kt
|
||||||
|
│ │ │ └── OrderService.kt
|
||||||
|
│ │ └── resources/
|
||||||
|
│ │ └── application.properties
|
||||||
|
│ └── test/
|
||||||
|
│ └── kotlin/
|
||||||
|
│ └── com/company/project/
|
||||||
|
│
|
||||||
|
└── common/ (선택사항)
|
||||||
|
├── build.gradle
|
||||||
|
└── src/
|
||||||
|
└── main/
|
||||||
|
└── kotlin/
|
||||||
|
└── com/company/project/common/
|
||||||
|
├── util/
|
||||||
|
├── exception/
|
||||||
|
└── config/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Gradle 설정
|
||||||
|
|
||||||
|
### 1. 루트 프로젝트 `settings.gradle`
|
||||||
|
|
||||||
|
```gradle
|
||||||
|
rootProject.name = 'project-name'
|
||||||
|
include 'storage'
|
||||||
|
include 'core-api'
|
||||||
|
// include 'common' // 필요시
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 루트 프로젝트 `build.gradle`
|
||||||
|
|
||||||
|
```gradle
|
||||||
|
plugins {
|
||||||
|
id 'org.jetbrains.kotlin.jvm' version '2.2.21' apply false
|
||||||
|
id 'org.jetbrains.kotlin.plugin.spring' version '2.2.21' apply false
|
||||||
|
id 'org.springframework.boot' version '4.0.1' apply false
|
||||||
|
id 'io.spring.dependency-management' version '1.1.7' apply false
|
||||||
|
id 'org.hibernate.orm' version '7.2.0.Final' apply false
|
||||||
|
id 'org.jetbrains.kotlin.plugin.jpa' version '2.2.21' apply false
|
||||||
|
}
|
||||||
|
|
||||||
|
group = 'com.company'
|
||||||
|
version = '0.0.1-SNAPSHOT'
|
||||||
|
|
||||||
|
subprojects {
|
||||||
|
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||||
|
apply plugin: 'io.spring.dependency-management'
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
toolchain {
|
||||||
|
languageVersion = JavaLanguageVersion.of(21) // 또는 17, 24
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
compilerOptions {
|
||||||
|
freeCompilerArgs.addAll '-Xjsr305=strict', '-Xannotation-default-target=param-property'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation 'org.jetbrains.kotlin:kotlin-reflect'
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(Test) {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Storage 모듈 `storage/build.gradle`
|
||||||
|
|
||||||
|
```gradle
|
||||||
|
plugins {
|
||||||
|
id 'org.jetbrains.kotlin.plugin.spring'
|
||||||
|
id 'org.springframework.boot'
|
||||||
|
id 'org.hibernate.orm'
|
||||||
|
id 'org.jetbrains.kotlin.plugin.jpa'
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||||
|
|
||||||
|
// 데이터베이스 드라이버
|
||||||
|
runtimeOnly 'com.h2database:h2'
|
||||||
|
runtimeOnly 'org.postgresql:postgresql'
|
||||||
|
// runtimeOnly 'com.mysql:mysql-connector-j'
|
||||||
|
}
|
||||||
|
|
||||||
|
hibernate {
|
||||||
|
enhancement {
|
||||||
|
enableAssociationManagement = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allOpen {
|
||||||
|
annotation 'jakarta.persistence.Entity'
|
||||||
|
annotation 'jakarta.persistence.MappedSuperclass'
|
||||||
|
annotation 'jakarta.persistence.Embeddable'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 라이브러리 모듈이므로 bootJar 비활성화
|
||||||
|
bootJar {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Core API 모듈 `core-api/build.gradle`
|
||||||
|
|
||||||
|
```gradle
|
||||||
|
plugins {
|
||||||
|
id 'org.jetbrains.kotlin.plugin.spring'
|
||||||
|
id 'org.jetbrains.kotlin.plugin.jpa'
|
||||||
|
id 'org.springframework.boot'
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
// 내부 모듈 의존성
|
||||||
|
implementation project(':storage')
|
||||||
|
|
||||||
|
// Spring Boot Starters
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-webmvc'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-h2console'
|
||||||
|
implementation 'tools.jackson.module:jackson-module-kotlin'
|
||||||
|
|
||||||
|
// 개발 도구
|
||||||
|
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
||||||
|
|
||||||
|
// 테스트
|
||||||
|
testImplementation 'org.springframework.boot:spring-boot-starter-data-jpa-test'
|
||||||
|
testImplementation 'org.springframework.boot:spring-boot-starter-webmvc-test'
|
||||||
|
testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5'
|
||||||
|
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 실행 가능한 jar 생성 (기본값이므로 생략 가능)
|
||||||
|
// bootJar {
|
||||||
|
// enabled = true
|
||||||
|
// }
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 의존성 관리 전략
|
||||||
|
|
||||||
|
### 의존성 방향 규칙
|
||||||
|
|
||||||
|
```
|
||||||
|
core-api ──→ storage
|
||||||
|
↓
|
||||||
|
common (선택)
|
||||||
|
```
|
||||||
|
|
||||||
|
**규칙:**
|
||||||
|
1. 상위 레이어는 하위 레이어에 의존 가능
|
||||||
|
2. 하위 레이어는 상위 레이어에 의존하면 안 됨
|
||||||
|
3. 순환 의존성 절대 금지
|
||||||
|
|
||||||
|
### 모듈 간 의존성 선언
|
||||||
|
|
||||||
|
```gradle
|
||||||
|
dependencies {
|
||||||
|
// 올바른 예
|
||||||
|
implementation project(':storage')
|
||||||
|
implementation project(':common')
|
||||||
|
|
||||||
|
// 잘못된 예 (storage 모듈에서)
|
||||||
|
// implementation project(':core-api') // ❌ 순환 의존성
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 외부 의존성 관리
|
||||||
|
|
||||||
|
**루트 프로젝트에서 버전 관리:**
|
||||||
|
|
||||||
|
```gradle
|
||||||
|
// build.gradle (root)
|
||||||
|
ext {
|
||||||
|
springCloudVersion = '2024.0.0'
|
||||||
|
}
|
||||||
|
|
||||||
|
subprojects {
|
||||||
|
apply plugin: 'io.spring.dependency-management'
|
||||||
|
|
||||||
|
dependencyManagement {
|
||||||
|
imports {
|
||||||
|
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 패키지 구조 및 네이밍
|
||||||
|
|
||||||
|
### 패키지 네이밍 컨벤션
|
||||||
|
|
||||||
|
```
|
||||||
|
com.company.project.{module}.{layer}
|
||||||
|
```
|
||||||
|
|
||||||
|
**예시:**
|
||||||
|
```
|
||||||
|
com.quantbench.balance.storage.entity
|
||||||
|
com.quantbench.balance.storage.repository
|
||||||
|
com.quantbench.balance.controller
|
||||||
|
com.quantbench.balance.service
|
||||||
|
```
|
||||||
|
|
||||||
|
### 모듈별 패키지 구조
|
||||||
|
|
||||||
|
#### Storage 모듈
|
||||||
|
```
|
||||||
|
com.quantbench.balance.storage/
|
||||||
|
├── entity/
|
||||||
|
│ ├── User.kt
|
||||||
|
│ ├── Order.kt
|
||||||
|
│ └── Product.kt
|
||||||
|
└── repository/
|
||||||
|
├── UserRepository.kt
|
||||||
|
├── OrderRepository.kt
|
||||||
|
└── ProductRepository.kt
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Core API 모듈
|
||||||
|
```
|
||||||
|
com.quantbench.balance/
|
||||||
|
├── Application.kt
|
||||||
|
├── controller/
|
||||||
|
│ ├── UserController.kt
|
||||||
|
│ ├── OrderController.kt
|
||||||
|
│ └── ProductController.kt
|
||||||
|
├── service/
|
||||||
|
│ ├── UserService.kt
|
||||||
|
│ ├── OrderService.kt
|
||||||
|
│ └── ProductService.kt
|
||||||
|
└── dto/
|
||||||
|
├── UserDto.kt
|
||||||
|
├── OrderDto.kt
|
||||||
|
└── ProductDto.kt
|
||||||
|
```
|
||||||
|
|
||||||
|
### Spring Boot 애플리케이션 클래스 설정
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
package com.quantbench.balance
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||||
|
import org.springframework.boot.runApplication
|
||||||
|
|
||||||
|
@SpringBootApplication(scanBasePackages = ["com.quantbench.balance"])
|
||||||
|
class BalanceApplication
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
runApplication<BalanceApplication>(*args)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**중요:**
|
||||||
|
- `scanBasePackages`를 명시하여 모든 모듈의 컴포넌트를 스캔
|
||||||
|
- 패키지 구조는 일관성 있게 유지 (`com.quantbench.balance.*`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 주의사항 및 베스트 프랙티스
|
||||||
|
|
||||||
|
### 1. 모듈 설계 원칙
|
||||||
|
|
||||||
|
#### ✅ DO (권장)
|
||||||
|
- 각 모듈은 단일 책임을 가져야 함
|
||||||
|
- 모듈 간 인터페이스는 명확하게 정의
|
||||||
|
- Storage 모듈은 가능한 한 독립적으로 유지
|
||||||
|
- 공통 기능은 별도 모듈로 분리
|
||||||
|
|
||||||
|
#### ❌ DON'T (비권장)
|
||||||
|
- 순환 의존성 생성
|
||||||
|
- 너무 많은 모듈로 과도하게 분리 (3-5개 권장)
|
||||||
|
- 하위 레이어가 상위 레이어에 의존
|
||||||
|
- 모듈 간 패키지 직접 접근
|
||||||
|
|
||||||
|
### 2. Gradle 설정 주의사항
|
||||||
|
|
||||||
|
#### bootJar 설정
|
||||||
|
```gradle
|
||||||
|
// Storage 모듈 (라이브러리)
|
||||||
|
bootJar {
|
||||||
|
enabled = false // 실행 불가능
|
||||||
|
}
|
||||||
|
jar {
|
||||||
|
enabled = true // 일반 jar 생성
|
||||||
|
}
|
||||||
|
|
||||||
|
// API 모듈 (실행 가능)
|
||||||
|
bootJar {
|
||||||
|
enabled = true // 기본값이므로 생략 가능
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 플러그인 적용
|
||||||
|
- 루트 프로젝트: `apply false` 사용
|
||||||
|
- 서브 프로젝트: 필요한 플러그인만 적용
|
||||||
|
|
||||||
|
### 3. Spring Boot 4.0+ 사용 시 주의사항
|
||||||
|
|
||||||
|
Spring Boot 4.0에서는 일부 어노테이션이 변경되거나 제거되었습니다.
|
||||||
|
|
||||||
|
**컴포넌트 스캔 설정:**
|
||||||
|
```kotlin
|
||||||
|
// ✅ 권장 (Spring Boot 4.0+)
|
||||||
|
@SpringBootApplication(scanBasePackages = ["com.quantbench.balance"])
|
||||||
|
class BalanceApplication
|
||||||
|
|
||||||
|
// ❌ 비권장 (구버전 방식, Spring Boot 4.0에서 문제 발생 가능)
|
||||||
|
@SpringBootApplication
|
||||||
|
@EntityScan("com.quantbench.balance.storage.entity")
|
||||||
|
@EnableJpaRepositories("com.quantbench.balance.storage.repository")
|
||||||
|
class BalanceApplication
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 빌드 및 실행
|
||||||
|
|
||||||
|
#### 전체 빌드
|
||||||
|
```bash
|
||||||
|
./gradlew clean build
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 특정 모듈 빌드
|
||||||
|
```bash
|
||||||
|
./gradlew :storage:build
|
||||||
|
./gradlew :core-api:build
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 애플리케이션 실행
|
||||||
|
```bash
|
||||||
|
./gradlew :core-api:bootRun
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 의존성 확인
|
||||||
|
```bash
|
||||||
|
./gradlew :core-api:dependencies --configuration runtimeClasspath
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 테스트 전략
|
||||||
|
|
||||||
|
#### Storage 모듈 테스트
|
||||||
|
```kotlin
|
||||||
|
@DataJpaTest
|
||||||
|
class UserRepositoryTest {
|
||||||
|
@Autowired
|
||||||
|
lateinit var userRepository: UserRepository
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `should save and find user`() {
|
||||||
|
// 테스트 코드
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### API 모듈 통합 테스트
|
||||||
|
```kotlin
|
||||||
|
@SpringBootTest
|
||||||
|
@AutoConfigureMockMvc
|
||||||
|
class UserControllerIntegrationTest {
|
||||||
|
@Autowired
|
||||||
|
lateinit var mockMvc: MockMvc
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `should return user by id`() {
|
||||||
|
mockMvc.perform(get("/api/users/1"))
|
||||||
|
.andExpect(status().isOk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. 성능 최적화
|
||||||
|
|
||||||
|
#### Gradle 빌드 최적화
|
||||||
|
```properties
|
||||||
|
# gradle.properties
|
||||||
|
org.gradle.parallel=true
|
||||||
|
org.gradle.caching=true
|
||||||
|
org.gradle.configureondemand=true
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 모듈별 병렬 빌드
|
||||||
|
```bash
|
||||||
|
./gradlew build --parallel
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 실제 적용 예시 (balance 프로젝트)
|
||||||
|
|
||||||
|
### 적용 전 (단일 모듈)
|
||||||
|
```
|
||||||
|
balance/
|
||||||
|
├── build.gradle
|
||||||
|
├── settings.gradle
|
||||||
|
└── src/
|
||||||
|
├── main/
|
||||||
|
│ └── kotlin/com/quantbench/balance/
|
||||||
|
│ └── BalanceApplication.kt
|
||||||
|
└── test/
|
||||||
|
```
|
||||||
|
|
||||||
|
### 적용 후 (멀티 모듈)
|
||||||
|
```
|
||||||
|
balance/
|
||||||
|
├── build.gradle # 공통 설정
|
||||||
|
├── settings.gradle # 모듈 정의
|
||||||
|
├── storage/ # 데이터 접근 레이어
|
||||||
|
│ ├── build.gradle
|
||||||
|
│ └── src/main/kotlin/com/quantbench/balance/storage/
|
||||||
|
│ ├── entity/
|
||||||
|
│ └── repository/
|
||||||
|
└── balance-core-api/ # API 레이어
|
||||||
|
├── build.gradle
|
||||||
|
└── src/
|
||||||
|
├── main/
|
||||||
|
│ ├── kotlin/com/quantbench/balance/
|
||||||
|
│ │ ├── BalanceApplication.kt
|
||||||
|
│ │ ├── controller/
|
||||||
|
│ │ └── service/
|
||||||
|
│ └── resources/application.properties
|
||||||
|
└── test/
|
||||||
|
```
|
||||||
|
|
||||||
|
### 핵심 변경 사항
|
||||||
|
|
||||||
|
1. **모듈 분리:** storage와 balance-core-api로 분리
|
||||||
|
2. **의존성 방향:** balance-core-api → storage
|
||||||
|
3. **실행 가능성:** balance-core-api만 실행 가능, storage는 라이브러리
|
||||||
|
4. **재사용성:** storage 모듈은 다른 프로젝트에서 재사용 가능
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 추가 확장 시나리오
|
||||||
|
|
||||||
|
### 1. Admin API 추가
|
||||||
|
```
|
||||||
|
balance/
|
||||||
|
├── storage/
|
||||||
|
├── balance-core-api/
|
||||||
|
└── balance-admin-api/ # 관리자 API
|
||||||
|
├── build.gradle
|
||||||
|
└── src/
|
||||||
|
```
|
||||||
|
|
||||||
|
**의존성 구조:**
|
||||||
|
```
|
||||||
|
balance-core-api ──→ storage
|
||||||
|
balance-admin-api ──→ storage
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Batch 모듈 추가
|
||||||
|
```
|
||||||
|
balance/
|
||||||
|
├── storage/
|
||||||
|
├── balance-core-api/
|
||||||
|
└── balance-batch/ # 배치 작업
|
||||||
|
├── build.gradle
|
||||||
|
└── src/
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Common 모듈 추가
|
||||||
|
```
|
||||||
|
balance/
|
||||||
|
├── common/ # 공통 유틸리티
|
||||||
|
├── storage/
|
||||||
|
├── balance-core-api/
|
||||||
|
└── balance-admin-api/
|
||||||
|
```
|
||||||
|
|
||||||
|
**의존성 구조:**
|
||||||
|
```
|
||||||
|
balance-core-api ──→ storage ──→ common
|
||||||
|
balance-admin-api ──→ storage ──→ common
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 문제 해결 (Troubleshooting)
|
||||||
|
|
||||||
|
### 1. 컴파일 에러: Unresolved reference
|
||||||
|
|
||||||
|
**문제:**
|
||||||
|
```
|
||||||
|
e: Unresolved reference 'EntityScan'
|
||||||
|
e: Unresolved reference 'EnableJpaRepositories'
|
||||||
|
```
|
||||||
|
|
||||||
|
**해결:**
|
||||||
|
- Spring Boot 4.0+에서는 `@EntityScan`, `@EnableJpaRepositories` 대신
|
||||||
|
- `@SpringBootApplication(scanBasePackages = [...])`를 사용
|
||||||
|
|
||||||
|
### 2. bootJar 에러
|
||||||
|
|
||||||
|
**문제:**
|
||||||
|
```
|
||||||
|
Main class name has not been configured and it could not be resolved
|
||||||
|
```
|
||||||
|
|
||||||
|
**해결:**
|
||||||
|
```gradle
|
||||||
|
// Storage 모듈에서
|
||||||
|
bootJar {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
jar {
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 컴포넌트 스캔 실패
|
||||||
|
|
||||||
|
**문제:** Repository나 Service가 스캔되지 않음
|
||||||
|
|
||||||
|
**해결:**
|
||||||
|
```kotlin
|
||||||
|
@SpringBootApplication(scanBasePackages = ["com.company.project"])
|
||||||
|
```
|
||||||
|
패키지 구조가 일관성 있게 유지되는지 확인
|
||||||
|
|
||||||
|
### 4. 순환 의존성
|
||||||
|
|
||||||
|
**문제:**
|
||||||
|
```
|
||||||
|
Circular dependency between the following tasks:
|
||||||
|
:module-a:jar
|
||||||
|
:module-b:jar
|
||||||
|
```
|
||||||
|
|
||||||
|
**해결:**
|
||||||
|
- 모듈 간 의존성 구조 재검토
|
||||||
|
- 공통 기능은 별도 모듈로 분리
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 마이그레이션 체크리스트
|
||||||
|
|
||||||
|
기존 프로젝트를 멀티모듈로 마이그레이션할 때:
|
||||||
|
|
||||||
|
- [ ] 1. 모듈 구조 설계 (어떤 모듈로 분리할지 결정)
|
||||||
|
- [ ] 2. `settings.gradle`에 모듈 추가
|
||||||
|
- [ ] 3. 루트 `build.gradle` 수정 (공통 설정 분리)
|
||||||
|
- [ ] 4. 각 모듈별 `build.gradle` 생성
|
||||||
|
- [ ] 5. 디렉토리 구조 생성
|
||||||
|
- [ ] 6. 기존 소스 코드를 적절한 모듈로 이동
|
||||||
|
- [ ] 7. 패키지 구조 정리
|
||||||
|
- [ ] 8. Application 클래스 수정 (컴포넌트 스캔 설정)
|
||||||
|
- [ ] 9. 빌드 테스트 (`./gradlew clean build`)
|
||||||
|
- [ ] 10. 애플리케이션 실행 테스트
|
||||||
|
- [ ] 11. 단위 테스트 및 통합 테스트 검증
|
||||||
|
- [ ] 12. CI/CD 파이프라인 업데이트 (필요시)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 참고 자료
|
||||||
|
|
||||||
|
- [Spring Boot Reference Documentation](https://docs.spring.io/spring-boot/index.html)
|
||||||
|
- [Gradle Multi-Project Builds](https://docs.gradle.org/current/userguide/multi_project_builds.html)
|
||||||
|
- [Kotlin and Spring Boot](https://spring.io/guides/tutorials/spring-boot-kotlin)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 버전 정보
|
||||||
|
|
||||||
|
- Spring Boot: 4.0.1
|
||||||
|
- Kotlin: 2.2.21
|
||||||
|
- Gradle: 9.2.1
|
||||||
|
- Java: 24 (또는 21, 17)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**작성일:** 2026-01-11
|
||||||
|
**프로젝트:** balance
|
||||||
|
**작성자:** Claude Code
|
||||||
344
LINT.md
Normal file
344
LINT.md
Normal file
@@ -0,0 +1,344 @@
|
|||||||
|
# Kotlin Lint 설정 가이드
|
||||||
|
|
||||||
|
## 개요
|
||||||
|
|
||||||
|
이 프로젝트는 Kotlin 코드 품질을 유지하기 위해 **ktlint**를 사용합니다.
|
||||||
|
|
||||||
|
## 사용 가능한 Lint 도구
|
||||||
|
|
||||||
|
### 1. ktlint (활성화됨 ✅)
|
||||||
|
|
||||||
|
Kotlin 공식 코드 스타일 가이드를 따르는 린터 및 포맷터입니다.
|
||||||
|
|
||||||
|
**특징:**
|
||||||
|
- 코드 스타일 체크
|
||||||
|
- 자동 포맷팅 기능
|
||||||
|
- Kotlin 2.2.21과 완벽 호환
|
||||||
|
|
||||||
|
### 2. detekt (현재 비활성화됨 ⚠️)
|
||||||
|
|
||||||
|
정적 코드 분석 도구로 코드 냄새, 복잡도, 잠재적 버그를 탐지합니다.
|
||||||
|
|
||||||
|
**비활성화 이유:**
|
||||||
|
- Kotlin 2.2.21과 호환성 문제
|
||||||
|
- detekt 1.23.7은 Kotlin 2.0.10까지만 지원
|
||||||
|
- 향후 detekt가 Kotlin 2.2.x를 지원하면 재활성화 예정
|
||||||
|
|
||||||
|
**활성화 방법:**
|
||||||
|
1. `build.gradle`에서 detekt 관련 주석 제거
|
||||||
|
2. Kotlin 버전을 2.0.x로 다운그레이드하거나
|
||||||
|
3. detekt 최신 버전(Kotlin 2.2.x 지원) 출시 대기
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 사용 가능한 Gradle Tasks
|
||||||
|
|
||||||
|
### 코드 스타일 체크
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 모든 모듈의 Kotlin 코드 스타일 체크
|
||||||
|
./gradlew ktlintCheck
|
||||||
|
|
||||||
|
# 특정 모듈만 체크
|
||||||
|
./gradlew :balance-core-api:ktlintCheck
|
||||||
|
./gradlew :storage:ktlintCheck
|
||||||
|
```
|
||||||
|
|
||||||
|
### 자동 포맷팅
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 모든 모듈의 Kotlin 코드 자동 포맷팅
|
||||||
|
./gradlew ktlintFormat
|
||||||
|
|
||||||
|
# 특정 모듈만 포맷팅
|
||||||
|
./gradlew :balance-core-api:ktlintFormat
|
||||||
|
./gradlew :storage:ktlintFormat
|
||||||
|
```
|
||||||
|
|
||||||
|
### 빌드와 함께 실행
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 빌드 전에 자동으로 ktlint 체크 실행
|
||||||
|
./gradlew clean build
|
||||||
|
|
||||||
|
# 또는
|
||||||
|
./gradlew check # 모든 검증 태스크 실행 (ktlint 포함)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ktlint 설정
|
||||||
|
|
||||||
|
### 1. 기본 설정 (build.gradle)
|
||||||
|
|
||||||
|
```gradle
|
||||||
|
ktlint {
|
||||||
|
version = '1.4.1'
|
||||||
|
android = false
|
||||||
|
outputToConsole = true
|
||||||
|
coloredOutput = true
|
||||||
|
ignoreFailures = false
|
||||||
|
filter {
|
||||||
|
exclude('**/generated/**')
|
||||||
|
exclude('**/build/**')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. .editorconfig 설정
|
||||||
|
|
||||||
|
프로젝트 루트의 `.editorconfig` 파일에서 코드 스타일을 세부 설정할 수 있습니다.
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[*.{kt,kts}]
|
||||||
|
indent_size = 4
|
||||||
|
continuation_indent_size = 4
|
||||||
|
max_line_length = 120
|
||||||
|
ij_kotlin_allow_trailing_comma = true
|
||||||
|
ij_kotlin_allow_trailing_comma_on_call_site = true
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## IDE 통합
|
||||||
|
|
||||||
|
### IntelliJ IDEA / Android Studio
|
||||||
|
|
||||||
|
#### 1. ktlint 플러그인 설치
|
||||||
|
|
||||||
|
1. `Preferences` → `Plugins`
|
||||||
|
2. "ktlint" 검색
|
||||||
|
3. 설치 및 재시작
|
||||||
|
|
||||||
|
#### 2. EditorConfig 활성화
|
||||||
|
|
||||||
|
1. `Preferences` → `Editor` → `Code Style`
|
||||||
|
2. "Enable EditorConfig support" 체크
|
||||||
|
|
||||||
|
#### 3. 저장 시 자동 포맷팅 (선택사항)
|
||||||
|
|
||||||
|
1. `Preferences` → `Tools` → `Actions on Save`
|
||||||
|
2. "Reformat code" 체크
|
||||||
|
3. "Optimize imports" 체크
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CI/CD 통합
|
||||||
|
|
||||||
|
### GitHub Actions 예시
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: Lint Check
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up JDK 24
|
||||||
|
uses: actions/setup-java@v3
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: '24'
|
||||||
|
|
||||||
|
- name: Grant execute permission for gradlew
|
||||||
|
run: chmod +x gradlew
|
||||||
|
|
||||||
|
- name: Run ktlint
|
||||||
|
run: ./gradlew ktlintCheck
|
||||||
|
|
||||||
|
- name: Upload ktlint reports
|
||||||
|
if: failure()
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: ktlint-reports
|
||||||
|
path: '**/build/reports/ktlint/'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 일반적인 린트 규칙
|
||||||
|
|
||||||
|
### 1. 들여쓰기
|
||||||
|
- 4 스페이스 사용 (탭 사용 금지)
|
||||||
|
|
||||||
|
### 2. 최대 줄 길이
|
||||||
|
- 120자 제한
|
||||||
|
|
||||||
|
### 3. 임포트
|
||||||
|
- 와일드카드 임포트 금지 (java.util.* 제외)
|
||||||
|
- 사용하지 않는 임포트 제거
|
||||||
|
|
||||||
|
### 4. 네이밍
|
||||||
|
- 클래스: PascalCase
|
||||||
|
- 함수/변수: camelCase
|
||||||
|
- 상수: UPPER_SNAKE_CASE
|
||||||
|
|
||||||
|
### 5. 공백
|
||||||
|
- 파일 끝에 빈 줄 추가
|
||||||
|
- 클래스 본문 시작/끝에 불필요한 빈 줄 제거
|
||||||
|
- 불필요한 공백 제거
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 린트 위반 사항 수정
|
||||||
|
|
||||||
|
### 자동 수정 (권장)
|
||||||
|
|
||||||
|
대부분의 스타일 위반은 자동으로 수정할 수 있습니다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew ktlintFormat
|
||||||
|
```
|
||||||
|
|
||||||
|
### 수동 수정
|
||||||
|
|
||||||
|
자동 수정이 불가능한 경우, 린트 리포트를 확인하고 수동으로 수정합니다.
|
||||||
|
|
||||||
|
**리포트 위치:**
|
||||||
|
```
|
||||||
|
build/reports/ktlint/
|
||||||
|
├── ktlintMainSourceSetCheck.txt
|
||||||
|
└── ktlintTestSourceSetCheck.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### 특정 규칙 비활성화 (비권장)
|
||||||
|
|
||||||
|
정말 필요한 경우에만 사용합니다.
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
// 한 줄 비활성화
|
||||||
|
@Suppress("ktlint:standard:max-line-length")
|
||||||
|
val veryLongVariableName = "..."
|
||||||
|
|
||||||
|
// 파일 전체 비활성화
|
||||||
|
@file:Suppress("ktlint:standard:filename")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 커밋 전 체크리스트
|
||||||
|
|
||||||
|
코드를 커밋하기 전에 다음을 실행하세요:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. 코드 포맷팅
|
||||||
|
./gradlew ktlintFormat
|
||||||
|
|
||||||
|
# 2. 린트 체크
|
||||||
|
./gradlew ktlintCheck
|
||||||
|
|
||||||
|
# 3. 빌드 및 테스트
|
||||||
|
./gradlew clean build
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Git Hook 설정 (선택사항)
|
||||||
|
|
||||||
|
커밋 전에 자동으로 ktlint를 실행하도록 설정할 수 있습니다.
|
||||||
|
|
||||||
|
### pre-commit hook 생성
|
||||||
|
|
||||||
|
`.git/hooks/pre-commit` 파일 생성:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/sh
|
||||||
|
echo "Running ktlint check..."
|
||||||
|
./gradlew ktlintCheck
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "❌ ktlint check failed. Please run './gradlew ktlintFormat' to fix."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ ktlint check passed!"
|
||||||
|
```
|
||||||
|
|
||||||
|
실행 권한 부여:
|
||||||
|
```bash
|
||||||
|
chmod +x .git/hooks/pre-commit
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 문제 해결
|
||||||
|
|
||||||
|
### 1. ktlint 버전 호환성 문제
|
||||||
|
|
||||||
|
**증상:**
|
||||||
|
```
|
||||||
|
Class org.jetbrains.kotlin.lexer.KtTokens does not have member field...
|
||||||
|
```
|
||||||
|
|
||||||
|
**해결:**
|
||||||
|
- `build.gradle`에서 ktlint 버전을 1.4.1 이상으로 업데이트
|
||||||
|
- Kotlin 버전과 호환되는 ktlint 버전 확인
|
||||||
|
|
||||||
|
### 2. 포맷팅 후에도 체크 실패
|
||||||
|
|
||||||
|
**원인:**
|
||||||
|
- IDE와 ktlint의 포맷팅 규칙 불일치
|
||||||
|
|
||||||
|
**해결:**
|
||||||
|
```bash
|
||||||
|
# ktlint 포맷팅 사용
|
||||||
|
./gradlew ktlintFormat
|
||||||
|
|
||||||
|
# IDE 포맷팅 사용 금지 또는 .editorconfig 확인
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 특정 파일 제외하기
|
||||||
|
|
||||||
|
`build.gradle`의 ktlint 설정 수정:
|
||||||
|
|
||||||
|
```gradle
|
||||||
|
ktlint {
|
||||||
|
filter {
|
||||||
|
exclude('**/generated/**')
|
||||||
|
exclude('**/build/**')
|
||||||
|
exclude('**/MySpecialFile.kt') // 특정 파일 제외
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 참고 자료
|
||||||
|
|
||||||
|
- [ktlint 공식 문서](https://pinterest.github.io/ktlint/)
|
||||||
|
- [Kotlin 코드 스타일 가이드](https://kotlinlang.org/docs/coding-conventions.html)
|
||||||
|
- [EditorConfig](https://editorconfig.org/)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 향후 계획
|
||||||
|
|
||||||
|
### detekt 재활성화
|
||||||
|
|
||||||
|
Kotlin 2.2.x를 지원하는 detekt 버전이 출시되면:
|
||||||
|
|
||||||
|
1. `build.gradle`에서 주석 해제:
|
||||||
|
```gradle
|
||||||
|
apply plugin: 'io.gitlab.arturbosch.detekt'
|
||||||
|
```
|
||||||
|
|
||||||
|
2. detekt 설정 활성화
|
||||||
|
|
||||||
|
3. 정적 분석 실행:
|
||||||
|
```bash
|
||||||
|
./gradlew detekt
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**최종 업데이트:** 2026-01-11
|
||||||
|
**ktlint 버전:** 1.4.1
|
||||||
|
**Kotlin 버전:** 2.2.21
|
||||||
19
balance-core-api/build.gradle
Normal file
19
balance-core-api/build.gradle
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
plugins {
|
||||||
|
id 'org.jetbrains.kotlin.plugin.spring'
|
||||||
|
id 'org.jetbrains.kotlin.plugin.jpa'
|
||||||
|
id 'org.springframework.boot'
|
||||||
|
id 'org.graalvm.buildtools.native'
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation project(':storage')
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-webmvc'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-h2console'
|
||||||
|
implementation 'tools.jackson.module:jackson-module-kotlin'
|
||||||
|
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
||||||
|
testImplementation 'org.springframework.boot:spring-boot-starter-data-jpa-test'
|
||||||
|
testImplementation 'org.springframework.boot:spring-boot-starter-webmvc-test'
|
||||||
|
testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5'
|
||||||
|
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ package com.quantbench.balance
|
|||||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||||
import org.springframework.boot.runApplication
|
import org.springframework.boot.runApplication
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication(scanBasePackages = ["com.quantbench.balance"])
|
||||||
class BalanceApplication
|
class BalanceApplication
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
@@ -5,9 +5,7 @@ import org.springframework.boot.test.context.SpringBootTest
|
|||||||
|
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
class BalanceApplicationTests {
|
class BalanceApplicationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun contextLoads() {
|
fun contextLoads() {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
107
build.gradle
107
build.gradle
@@ -1,60 +1,85 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'org.jetbrains.kotlin.jvm' version '2.2.21'
|
id 'org.jetbrains.kotlin.jvm' version '2.2.21' apply false
|
||||||
id 'org.jetbrains.kotlin.plugin.spring' version '2.2.21'
|
id 'org.jetbrains.kotlin.plugin.spring' version '2.2.21' apply false
|
||||||
id 'org.springframework.boot' version '4.0.1'
|
id 'org.springframework.boot' version '4.0.1' apply false
|
||||||
id 'io.spring.dependency-management' version '1.1.7'
|
id 'io.spring.dependency-management' version '1.1.7' apply false
|
||||||
id 'org.hibernate.orm' version '7.2.0.Final'
|
id 'org.hibernate.orm' version '7.2.0.Final' apply false
|
||||||
id 'org.graalvm.buildtools.native' version '0.11.3'
|
id 'org.graalvm.buildtools.native' version '0.11.3' apply false
|
||||||
id 'org.jetbrains.kotlin.plugin.jpa' version '2.2.21'
|
id 'org.jetbrains.kotlin.plugin.jpa' version '2.2.21' apply false
|
||||||
|
id 'org.jlleitschuh.gradle.ktlint' version '12.1.1' apply false
|
||||||
|
id 'io.gitlab.arturbosch.detekt' version '1.23.7' apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
group = 'com.quantbench'
|
group = 'com.quantbench'
|
||||||
version = '0.0.1-SNAPSHOT'
|
version = '0.0.1-SNAPSHOT'
|
||||||
description = 'balance'
|
description = 'balance'
|
||||||
|
|
||||||
java {
|
subprojects {
|
||||||
|
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||||
|
apply plugin: 'io.spring.dependency-management'
|
||||||
|
apply plugin: 'org.jlleitschuh.gradle.ktlint'
|
||||||
|
// detekt는 Kotlin 2.2.21과 호환성 문제가 있어 주석 처리
|
||||||
|
// Kotlin 2.0.x로 다운그레이드하거나 detekt 최신 버전 출시 시 활성화
|
||||||
|
// apply plugin: 'io.gitlab.arturbosch.detekt'
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
toolchain {
|
toolchain {
|
||||||
languageVersion = JavaLanguageVersion.of(24)
|
languageVersion = JavaLanguageVersion.of(24)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
kotlin {
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation 'org.springframework.boot:spring-boot-h2console'
|
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-webmvc'
|
|
||||||
implementation 'org.jetbrains.kotlin:kotlin-reflect'
|
|
||||||
implementation 'tools.jackson.module:jackson-module-kotlin'
|
|
||||||
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
|
||||||
runtimeOnly 'com.h2database:h2'
|
|
||||||
runtimeOnly 'org.postgresql:postgresql'
|
|
||||||
testImplementation 'org.springframework.boot:spring-boot-starter-data-jpa-test'
|
|
||||||
testImplementation 'org.springframework.boot:spring-boot-starter-webmvc-test'
|
|
||||||
testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5'
|
|
||||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
|
||||||
}
|
|
||||||
|
|
||||||
kotlin {
|
|
||||||
compilerOptions {
|
compilerOptions {
|
||||||
freeCompilerArgs.addAll '-Xjsr305=strict', '-Xannotation-default-target=param-property'
|
freeCompilerArgs.addAll '-Xjsr305=strict', '-Xannotation-default-target=param-property'
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
hibernate {
|
|
||||||
enhancement {
|
|
||||||
enableAssociationManagement = true
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
allOpen {
|
dependencies {
|
||||||
annotation 'jakarta.persistence.Entity'
|
implementation 'org.jetbrains.kotlin:kotlin-reflect'
|
||||||
annotation 'jakarta.persistence.MappedSuperclass'
|
// detektPlugins 'io.gitlab.arturbosch.detekt:detekt-formatting:1.23.7'
|
||||||
annotation 'jakarta.persistence.Embeddable'
|
}
|
||||||
}
|
|
||||||
|
|
||||||
tasks.named('test') {
|
tasks.withType(Test) {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ktlint 설정
|
||||||
|
ktlint {
|
||||||
|
version = '1.4.1'
|
||||||
|
android = false
|
||||||
|
outputToConsole = true
|
||||||
|
coloredOutput = true
|
||||||
|
ignoreFailures = false
|
||||||
|
filter {
|
||||||
|
exclude('**/generated/**')
|
||||||
|
exclude('**/build/**')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// detekt 설정 (현재 비활성화 - Kotlin 2.2.21과 호환성 문제)
|
||||||
|
// detekt {
|
||||||
|
// buildUponDefaultConfig = true
|
||||||
|
// allRules = false
|
||||||
|
// config.setFrom(files("$rootDir/detekt.yml"))
|
||||||
|
// // baseline은 존재할 때만 사용
|
||||||
|
// def baselineFile = file("$rootDir/detekt-baseline.xml")
|
||||||
|
// if (baselineFile.exists()) {
|
||||||
|
// baseline = baselineFile
|
||||||
|
// }
|
||||||
|
// ignoreFailures = false
|
||||||
|
// }
|
||||||
|
|
||||||
|
// tasks.withType(io.gitlab.arturbosch.detekt.Detekt).configureEach {
|
||||||
|
// reports {
|
||||||
|
// html.required = true
|
||||||
|
// xml.required = false
|
||||||
|
// txt.required = false
|
||||||
|
// sarif.required = false
|
||||||
|
// md.required = false
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
595
detekt.yml
Normal file
595
detekt.yml
Normal file
@@ -0,0 +1,595 @@
|
|||||||
|
build:
|
||||||
|
maxIssues: 0
|
||||||
|
excludeCorrectable: false
|
||||||
|
weights:
|
||||||
|
complexity: 2
|
||||||
|
LongParameterList: 1
|
||||||
|
style: 1
|
||||||
|
comments: 1
|
||||||
|
|
||||||
|
config:
|
||||||
|
validation: true
|
||||||
|
warningsAsErrors: false
|
||||||
|
checkExhaustiveness: false
|
||||||
|
|
||||||
|
processors:
|
||||||
|
active: true
|
||||||
|
|
||||||
|
console-reports:
|
||||||
|
active: true
|
||||||
|
|
||||||
|
output-reports:
|
||||||
|
active: true
|
||||||
|
|
||||||
|
comments:
|
||||||
|
active: true
|
||||||
|
AbsentOrWrongFileLicense:
|
||||||
|
active: false
|
||||||
|
CommentOverPrivateFunction:
|
||||||
|
active: false
|
||||||
|
CommentOverPrivateProperty:
|
||||||
|
active: false
|
||||||
|
DeprecatedBlockTag:
|
||||||
|
active: false
|
||||||
|
EndOfSentenceFormat:
|
||||||
|
active: false
|
||||||
|
OutdatedDocumentation:
|
||||||
|
active: false
|
||||||
|
UndocumentedPublicClass:
|
||||||
|
active: false
|
||||||
|
UndocumentedPublicFunction:
|
||||||
|
active: false
|
||||||
|
UndocumentedPublicProperty:
|
||||||
|
active: false
|
||||||
|
|
||||||
|
complexity:
|
||||||
|
active: true
|
||||||
|
ComplexCondition:
|
||||||
|
active: true
|
||||||
|
threshold: 4
|
||||||
|
ComplexInterface:
|
||||||
|
active: false
|
||||||
|
CyclomaticComplexMethod:
|
||||||
|
active: true
|
||||||
|
threshold: 15
|
||||||
|
ignoreSingleWhenExpression: false
|
||||||
|
ignoreSimpleWhenEntries: false
|
||||||
|
ignoreNestingFunctions: false
|
||||||
|
LabeledExpression:
|
||||||
|
active: false
|
||||||
|
LargeClass:
|
||||||
|
active: true
|
||||||
|
threshold: 600
|
||||||
|
LongMethod:
|
||||||
|
active: true
|
||||||
|
threshold: 60
|
||||||
|
LongParameterList:
|
||||||
|
active: true
|
||||||
|
functionThreshold: 6
|
||||||
|
constructorThreshold: 7
|
||||||
|
ignoreDefaultParameters: false
|
||||||
|
ignoreDataClasses: true
|
||||||
|
ignoreAnnotatedParameter: []
|
||||||
|
MethodOverloading:
|
||||||
|
active: false
|
||||||
|
NamedArguments:
|
||||||
|
active: false
|
||||||
|
NestedBlockDepth:
|
||||||
|
active: true
|
||||||
|
threshold: 4
|
||||||
|
ReplaceSafeCallChainWithRun:
|
||||||
|
active: false
|
||||||
|
StringLiteralDuplication:
|
||||||
|
active: false
|
||||||
|
TooManyFunctions:
|
||||||
|
active: true
|
||||||
|
thresholdInFiles: 20
|
||||||
|
thresholdInClasses: 20
|
||||||
|
thresholdInInterfaces: 20
|
||||||
|
thresholdInObjects: 20
|
||||||
|
thresholdInEnums: 20
|
||||||
|
ignoreDeprecated: false
|
||||||
|
ignorePrivate: false
|
||||||
|
ignoreOverridden: false
|
||||||
|
|
||||||
|
coroutines:
|
||||||
|
active: true
|
||||||
|
GlobalCoroutineUsage:
|
||||||
|
active: false
|
||||||
|
InjectDispatcher:
|
||||||
|
active: false
|
||||||
|
RedundantSuspendModifier:
|
||||||
|
active: true
|
||||||
|
SleepInsteadOfDelay:
|
||||||
|
active: true
|
||||||
|
SuspendFunSwallowedCancellation:
|
||||||
|
active: false
|
||||||
|
SuspendFunWithCoroutineScopeReceiver:
|
||||||
|
active: false
|
||||||
|
SuspendFunWithFlowReturnType:
|
||||||
|
active: true
|
||||||
|
|
||||||
|
empty-blocks:
|
||||||
|
active: true
|
||||||
|
EmptyCatchBlock:
|
||||||
|
active: true
|
||||||
|
allowedExceptionNameRegex: '_|(ignore|expected).*'
|
||||||
|
EmptyClassBlock:
|
||||||
|
active: true
|
||||||
|
EmptyDefaultConstructor:
|
||||||
|
active: true
|
||||||
|
EmptyDoWhileBlock:
|
||||||
|
active: true
|
||||||
|
EmptyElseBlock:
|
||||||
|
active: true
|
||||||
|
EmptyFinallyBlock:
|
||||||
|
active: true
|
||||||
|
EmptyForBlock:
|
||||||
|
active: true
|
||||||
|
EmptyFunctionBlock:
|
||||||
|
active: true
|
||||||
|
ignoreOverridden: false
|
||||||
|
EmptyIfBlock:
|
||||||
|
active: true
|
||||||
|
EmptyInitBlock:
|
||||||
|
active: true
|
||||||
|
EmptyKtFile:
|
||||||
|
active: true
|
||||||
|
EmptySecondaryConstructor:
|
||||||
|
active: true
|
||||||
|
EmptyTryBlock:
|
||||||
|
active: true
|
||||||
|
EmptyWhenBlock:
|
||||||
|
active: true
|
||||||
|
EmptyWhileBlock:
|
||||||
|
active: true
|
||||||
|
|
||||||
|
exceptions:
|
||||||
|
active: true
|
||||||
|
ExceptionRaisedInUnexpectedLocation:
|
||||||
|
active: true
|
||||||
|
methodNames:
|
||||||
|
- 'equals'
|
||||||
|
- 'finalize'
|
||||||
|
- 'hashCode'
|
||||||
|
- 'toString'
|
||||||
|
InstanceOfCheckForException:
|
||||||
|
active: true
|
||||||
|
NotImplementedDeclaration:
|
||||||
|
active: false
|
||||||
|
ObjectExtendsThrowable:
|
||||||
|
active: false
|
||||||
|
PrintStackTrace:
|
||||||
|
active: true
|
||||||
|
RethrowCaughtException:
|
||||||
|
active: true
|
||||||
|
ReturnFromFinally:
|
||||||
|
active: true
|
||||||
|
ignoreLabeled: false
|
||||||
|
SwallowedException:
|
||||||
|
active: true
|
||||||
|
ignoredExceptionTypes:
|
||||||
|
- 'InterruptedException'
|
||||||
|
- 'MalformedURLException'
|
||||||
|
- 'NumberFormatException'
|
||||||
|
- 'ParseException'
|
||||||
|
allowedExceptionNameRegex: '_|(ignore|expected).*'
|
||||||
|
ThrowingExceptionFromFinally:
|
||||||
|
active: true
|
||||||
|
ThrowingExceptionInMain:
|
||||||
|
active: false
|
||||||
|
ThrowingExceptionsWithoutMessageOrCause:
|
||||||
|
active: true
|
||||||
|
exceptions:
|
||||||
|
- 'ArrayIndexOutOfBoundsException'
|
||||||
|
- 'Exception'
|
||||||
|
- 'IllegalArgumentException'
|
||||||
|
- 'IllegalMonitorStateException'
|
||||||
|
- 'IllegalStateException'
|
||||||
|
- 'IndexOutOfBoundsException'
|
||||||
|
- 'NullPointerException'
|
||||||
|
- 'RuntimeException'
|
||||||
|
- 'Throwable'
|
||||||
|
ThrowingNewInstanceOfSameException:
|
||||||
|
active: true
|
||||||
|
TooGenericExceptionCaught:
|
||||||
|
active: true
|
||||||
|
exceptionNames:
|
||||||
|
- 'ArrayIndexOutOfBoundsException'
|
||||||
|
- 'Error'
|
||||||
|
- 'Exception'
|
||||||
|
- 'IllegalMonitorStateException'
|
||||||
|
- 'IndexOutOfBoundsException'
|
||||||
|
- 'NullPointerException'
|
||||||
|
- 'RuntimeException'
|
||||||
|
- 'Throwable'
|
||||||
|
allowedExceptionNameRegex: '_|(ignore|expected).*'
|
||||||
|
TooGenericExceptionThrown:
|
||||||
|
active: true
|
||||||
|
exceptionNames:
|
||||||
|
- 'Error'
|
||||||
|
- 'Exception'
|
||||||
|
- 'RuntimeException'
|
||||||
|
- 'Throwable'
|
||||||
|
|
||||||
|
naming:
|
||||||
|
active: true
|
||||||
|
BooleanPropertyNaming:
|
||||||
|
active: false
|
||||||
|
ClassNaming:
|
||||||
|
active: true
|
||||||
|
classPattern: '[A-Z][a-zA-Z0-9]*'
|
||||||
|
ConstructorParameterNaming:
|
||||||
|
active: true
|
||||||
|
parameterPattern: '[a-z][A-Za-z0-9]*'
|
||||||
|
privateParameterPattern: '[a-z][A-Za-z0-9]*'
|
||||||
|
excludeClassPattern: '$^'
|
||||||
|
EnumNaming:
|
||||||
|
active: true
|
||||||
|
enumEntryPattern: '[A-Z][_a-zA-Z0-9]*'
|
||||||
|
ForbiddenClassName:
|
||||||
|
active: false
|
||||||
|
FunctionMaxLength:
|
||||||
|
active: false
|
||||||
|
FunctionMinLength:
|
||||||
|
active: false
|
||||||
|
FunctionNaming:
|
||||||
|
active: true
|
||||||
|
excludeClassPattern: '$^'
|
||||||
|
functionPattern: '[a-z][a-zA-Z0-9]*'
|
||||||
|
excludeAnnotatedFunction: ['Composable']
|
||||||
|
ignoreAnnotated: ['Test']
|
||||||
|
FunctionParameterNaming:
|
||||||
|
active: true
|
||||||
|
parameterPattern: '[a-z][A-Za-z0-9]*'
|
||||||
|
InvalidPackageDeclaration:
|
||||||
|
active: true
|
||||||
|
rootPackage: ''
|
||||||
|
LambdaParameterNaming:
|
||||||
|
active: false
|
||||||
|
MatchingDeclarationName:
|
||||||
|
active: true
|
||||||
|
mustBeFirst: true
|
||||||
|
MemberNameEqualsClassName:
|
||||||
|
active: true
|
||||||
|
ignoreOverridden: true
|
||||||
|
NoNameShadowing:
|
||||||
|
active: true
|
||||||
|
NonBooleanPropertyPrefixedWithIs:
|
||||||
|
active: false
|
||||||
|
ObjectPropertyNaming:
|
||||||
|
active: true
|
||||||
|
constantPattern: '[A-Za-z][_A-Za-z0-9]*'
|
||||||
|
propertyPattern: '[A-Za-z][_A-Za-z0-9]*'
|
||||||
|
privatePropertyPattern: '(_)?[A-Za-z][_A-Za-z0-9]*'
|
||||||
|
PackageNaming:
|
||||||
|
active: true
|
||||||
|
packagePattern: '[a-z]+(\.[a-z][A-Za-z0-9]*)*'
|
||||||
|
TopLevelPropertyNaming:
|
||||||
|
active: true
|
||||||
|
constantPattern: '[A-Z][_A-Z0-9]*'
|
||||||
|
propertyPattern: '[A-Za-z][_A-Za-z0-9]*'
|
||||||
|
privatePropertyPattern: '_?[A-Za-z][_A-Za-z0-9]*'
|
||||||
|
VariableMaxLength:
|
||||||
|
active: false
|
||||||
|
VariableMinLength:
|
||||||
|
active: false
|
||||||
|
VariableNaming:
|
||||||
|
active: true
|
||||||
|
variablePattern: '[a-z][A-Za-z0-9]*'
|
||||||
|
privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*'
|
||||||
|
excludeClassPattern: '$^'
|
||||||
|
|
||||||
|
performance:
|
||||||
|
active: true
|
||||||
|
ArrayPrimitive:
|
||||||
|
active: true
|
||||||
|
CouldBeSequence:
|
||||||
|
active: false
|
||||||
|
ForEachOnRange:
|
||||||
|
active: true
|
||||||
|
SpreadOperator:
|
||||||
|
active: false
|
||||||
|
UnnecessaryPartOfBinaryExpression:
|
||||||
|
active: false
|
||||||
|
UnnecessaryTemporaryInstantiation:
|
||||||
|
active: true
|
||||||
|
|
||||||
|
potential-bugs:
|
||||||
|
active: true
|
||||||
|
AvoidReferentialEquality:
|
||||||
|
active: true
|
||||||
|
forbiddenTypePatterns:
|
||||||
|
- 'kotlin.String'
|
||||||
|
CastNullableToNonNullableType:
|
||||||
|
active: false
|
||||||
|
CastToNullableType:
|
||||||
|
active: false
|
||||||
|
Deprecation:
|
||||||
|
active: false
|
||||||
|
DontDowncastCollectionTypes:
|
||||||
|
active: false
|
||||||
|
DoubleMutabilityForCollection:
|
||||||
|
active: true
|
||||||
|
ElseCaseInsteadOfExhaustiveWhen:
|
||||||
|
active: false
|
||||||
|
EqualsAlwaysReturnsTrueOrFalse:
|
||||||
|
active: true
|
||||||
|
EqualsWithHashCodeExist:
|
||||||
|
active: true
|
||||||
|
ExitOutsideMain:
|
||||||
|
active: false
|
||||||
|
ExplicitGarbageCollectionCall:
|
||||||
|
active: true
|
||||||
|
HasPlatformType:
|
||||||
|
active: true
|
||||||
|
IgnoredReturnValue:
|
||||||
|
active: true
|
||||||
|
ImplicitDefaultLocale:
|
||||||
|
active: true
|
||||||
|
ImplicitUnitReturnType:
|
||||||
|
active: false
|
||||||
|
InvalidRange:
|
||||||
|
active: true
|
||||||
|
IteratorHasNextCallsNextMethod:
|
||||||
|
active: true
|
||||||
|
IteratorNotThrowingNoSuchElementException:
|
||||||
|
active: true
|
||||||
|
LateinitUsage:
|
||||||
|
active: false
|
||||||
|
MapGetWithNotNullAssertionOperator:
|
||||||
|
active: true
|
||||||
|
MissingPackageDeclaration:
|
||||||
|
active: false
|
||||||
|
NullCheckOnMutableProperty:
|
||||||
|
active: false
|
||||||
|
NullableToStringCall:
|
||||||
|
active: false
|
||||||
|
UnconditionalJumpStatementInLoop:
|
||||||
|
active: false
|
||||||
|
UnnecessaryNotNullCheck:
|
||||||
|
active: false
|
||||||
|
UnnecessaryNotNullOperator:
|
||||||
|
active: true
|
||||||
|
UnnecessarySafeCall:
|
||||||
|
active: true
|
||||||
|
UnreachableCatchBlock:
|
||||||
|
active: true
|
||||||
|
UnreachableCode:
|
||||||
|
active: true
|
||||||
|
UnsafeCallOnNullableType:
|
||||||
|
active: true
|
||||||
|
UnsafeCast:
|
||||||
|
active: true
|
||||||
|
UnusedUnaryOperator:
|
||||||
|
active: true
|
||||||
|
UselessPostfixExpression:
|
||||||
|
active: true
|
||||||
|
WrongEqualsTypeParameter:
|
||||||
|
active: true
|
||||||
|
|
||||||
|
style:
|
||||||
|
active: true
|
||||||
|
AlsoCouldBeApply:
|
||||||
|
active: false
|
||||||
|
BracesOnIfStatements:
|
||||||
|
active: false
|
||||||
|
BracesOnWhenStatements:
|
||||||
|
active: false
|
||||||
|
CanBeNonNullable:
|
||||||
|
active: false
|
||||||
|
CascadingCallWrapping:
|
||||||
|
active: false
|
||||||
|
ClassOrdering:
|
||||||
|
active: false
|
||||||
|
CollapsibleIfStatements:
|
||||||
|
active: false
|
||||||
|
DataClassContainsFunctions:
|
||||||
|
active: false
|
||||||
|
DataClassShouldBeImmutable:
|
||||||
|
active: false
|
||||||
|
DestructuringDeclarationWithTooManyEntries:
|
||||||
|
active: true
|
||||||
|
maxDestructuringEntries: 3
|
||||||
|
DoubleNegativeLambda:
|
||||||
|
active: false
|
||||||
|
EqualsNullCall:
|
||||||
|
active: true
|
||||||
|
EqualsOnSignatureLine:
|
||||||
|
active: false
|
||||||
|
ExplicitCollectionElementAccessMethod:
|
||||||
|
active: false
|
||||||
|
ExplicitItLambdaParameter:
|
||||||
|
active: false
|
||||||
|
ExpressionBodySyntax:
|
||||||
|
active: false
|
||||||
|
ForbiddenAnnotation:
|
||||||
|
active: false
|
||||||
|
ForbiddenComment:
|
||||||
|
active: true
|
||||||
|
values:
|
||||||
|
- 'FIXME:'
|
||||||
|
- 'STOPSHIP:'
|
||||||
|
- 'TODO:'
|
||||||
|
allowedPatterns: ''
|
||||||
|
ForbiddenImport:
|
||||||
|
active: false
|
||||||
|
ForbiddenMethodCall:
|
||||||
|
active: false
|
||||||
|
ForbiddenSuppress:
|
||||||
|
active: false
|
||||||
|
ForbiddenVoid:
|
||||||
|
active: true
|
||||||
|
ignoreOverridden: false
|
||||||
|
ignoreUsageInGenerics: false
|
||||||
|
FunctionOnlyReturningConstant:
|
||||||
|
active: true
|
||||||
|
ignoreOverridableFunction: true
|
||||||
|
ignoreActualFunction: true
|
||||||
|
excludedFunctions: []
|
||||||
|
LoopWithTooManyJumpStatements:
|
||||||
|
active: true
|
||||||
|
maxJumpCount: 1
|
||||||
|
MagicNumber:
|
||||||
|
active: true
|
||||||
|
excludes:
|
||||||
|
- '**/test/**'
|
||||||
|
- '**/androidTest/**'
|
||||||
|
- '**/commonTest/**'
|
||||||
|
- '**/jvmTest/**'
|
||||||
|
- '**/jsTest/**'
|
||||||
|
- '**/iosTest/**'
|
||||||
|
ignoreNumbers:
|
||||||
|
- '-1'
|
||||||
|
- '0'
|
||||||
|
- '1'
|
||||||
|
- '2'
|
||||||
|
ignoreHashCodeFunction: true
|
||||||
|
ignorePropertyDeclaration: false
|
||||||
|
ignoreLocalVariableDeclaration: false
|
||||||
|
ignoreConstantDeclaration: true
|
||||||
|
ignoreCompanionObjectPropertyDeclaration: true
|
||||||
|
ignoreAnnotation: false
|
||||||
|
ignoreNamedArgument: true
|
||||||
|
ignoreEnums: false
|
||||||
|
ignoreRanges: false
|
||||||
|
ignoreExtensionFunctions: true
|
||||||
|
MandatoryBracesLoops:
|
||||||
|
active: false
|
||||||
|
MaxChainedCallsOnSameLine:
|
||||||
|
active: false
|
||||||
|
MaxLineLength:
|
||||||
|
active: true
|
||||||
|
maxLineLength: 120
|
||||||
|
excludePackageStatements: true
|
||||||
|
excludeImportStatements: true
|
||||||
|
excludeCommentStatements: false
|
||||||
|
MayBeConst:
|
||||||
|
active: true
|
||||||
|
ModifierOrder:
|
||||||
|
active: true
|
||||||
|
MultilineLambdaItParameter:
|
||||||
|
active: false
|
||||||
|
MultilineRawStringIndentation:
|
||||||
|
active: false
|
||||||
|
NestedClassesVisibility:
|
||||||
|
active: true
|
||||||
|
NewLineAtEndOfFile:
|
||||||
|
active: true
|
||||||
|
NoTabs:
|
||||||
|
active: false
|
||||||
|
NullableBooleanCheck:
|
||||||
|
active: false
|
||||||
|
ObjectLiteralToLambda:
|
||||||
|
active: true
|
||||||
|
OptionalAbstractKeyword:
|
||||||
|
active: true
|
||||||
|
OptionalUnit:
|
||||||
|
active: false
|
||||||
|
PreferToOverPairSyntax:
|
||||||
|
active: false
|
||||||
|
ProtectedMemberInFinalClass:
|
||||||
|
active: true
|
||||||
|
RedundantExplicitType:
|
||||||
|
active: false
|
||||||
|
RedundantHigherOrderMapUsage:
|
||||||
|
active: true
|
||||||
|
RedundantVisibilityModifierRule:
|
||||||
|
active: false
|
||||||
|
ReturnCount:
|
||||||
|
active: true
|
||||||
|
max: 2
|
||||||
|
excludedFunctions:
|
||||||
|
- 'equals'
|
||||||
|
excludeLabeled: false
|
||||||
|
excludeReturnFromLambda: true
|
||||||
|
excludeGuardClauses: false
|
||||||
|
SafeCast:
|
||||||
|
active: true
|
||||||
|
SerialVersionUIDInSerializableClass:
|
||||||
|
active: true
|
||||||
|
SpacingBetweenPackageAndImports:
|
||||||
|
active: false
|
||||||
|
StringShouldBeRawString:
|
||||||
|
active: false
|
||||||
|
ThrowsCount:
|
||||||
|
active: true
|
||||||
|
max: 2
|
||||||
|
excludeGuardClauses: false
|
||||||
|
TrailingWhitespace:
|
||||||
|
active: false
|
||||||
|
TrimMultilineRawString:
|
||||||
|
active: false
|
||||||
|
UnderscoresInNumericLiterals:
|
||||||
|
active: false
|
||||||
|
UnnecessaryAbstractClass:
|
||||||
|
active: true
|
||||||
|
UnnecessaryAnnotationUseSiteTarget:
|
||||||
|
active: false
|
||||||
|
UnnecessaryApply:
|
||||||
|
active: true
|
||||||
|
UnnecessaryBackticks:
|
||||||
|
active: false
|
||||||
|
UnnecessaryBracesAroundTrailingLambda:
|
||||||
|
active: false
|
||||||
|
UnnecessaryFilter:
|
||||||
|
active: true
|
||||||
|
UnnecessaryInheritance:
|
||||||
|
active: true
|
||||||
|
UnnecessaryInnerClass:
|
||||||
|
active: false
|
||||||
|
UnnecessaryLet:
|
||||||
|
active: false
|
||||||
|
UnnecessaryParentheses:
|
||||||
|
active: false
|
||||||
|
UntilInsteadOfRangeTo:
|
||||||
|
active: false
|
||||||
|
UnusedImports:
|
||||||
|
active: false
|
||||||
|
UnusedParameter:
|
||||||
|
active: true
|
||||||
|
allowedNames: 'ignored|expected'
|
||||||
|
UnusedPrivateClass:
|
||||||
|
active: true
|
||||||
|
UnusedPrivateMember:
|
||||||
|
active: true
|
||||||
|
allowedNames: ''
|
||||||
|
UnusedPrivateProperty:
|
||||||
|
active: true
|
||||||
|
allowedNames: '_|ignored|expected|serialVersionUID'
|
||||||
|
UseAnyOrNoneInsteadOfFind:
|
||||||
|
active: true
|
||||||
|
UseArrayLiteralsInAnnotations:
|
||||||
|
active: true
|
||||||
|
UseCheckNotNull:
|
||||||
|
active: true
|
||||||
|
UseCheckOrError:
|
||||||
|
active: true
|
||||||
|
UseDataClass:
|
||||||
|
active: false
|
||||||
|
UseEmptyCounterpart:
|
||||||
|
active: false
|
||||||
|
UseIfEmptyOrIfBlank:
|
||||||
|
active: false
|
||||||
|
UseIfInsteadOfWhen:
|
||||||
|
active: false
|
||||||
|
UseIsNullOrEmpty:
|
||||||
|
active: true
|
||||||
|
UseOrEmpty:
|
||||||
|
active: true
|
||||||
|
UseRequire:
|
||||||
|
active: true
|
||||||
|
UseRequireNotNull:
|
||||||
|
active: true
|
||||||
|
UseSumOfInsteadOfFlatMapSize:
|
||||||
|
active: false
|
||||||
|
UselessCallOnNotNull:
|
||||||
|
active: true
|
||||||
|
UtilityClassWithPublicConstructor:
|
||||||
|
active: true
|
||||||
|
VarCouldBeVal:
|
||||||
|
active: true
|
||||||
|
WildcardImport:
|
||||||
|
active: true
|
||||||
|
excludeImports:
|
||||||
|
- 'java.util.*'
|
||||||
@@ -1 +1,3 @@
|
|||||||
rootProject.name = 'balance'
|
rootProject.name = 'balance'
|
||||||
|
include 'storage'
|
||||||
|
include 'balance-core-api'
|
||||||
|
|||||||
33
storage/build.gradle
Normal file
33
storage/build.gradle
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
plugins {
|
||||||
|
id 'org.jetbrains.kotlin.plugin.spring'
|
||||||
|
id 'org.springframework.boot'
|
||||||
|
id 'org.hibernate.orm'
|
||||||
|
id 'org.jetbrains.kotlin.plugin.jpa'
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||||
|
runtimeOnly 'com.h2database:h2'
|
||||||
|
runtimeOnly 'org.postgresql:postgresql'
|
||||||
|
}
|
||||||
|
|
||||||
|
hibernate {
|
||||||
|
enhancement {
|
||||||
|
enableAssociationManagement = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allOpen {
|
||||||
|
annotation 'jakarta.persistence.Entity'
|
||||||
|
annotation 'jakarta.persistence.MappedSuperclass'
|
||||||
|
annotation 'jakarta.persistence.Embeddable'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 라이브러리 모듈이므로 bootJar 비활성화
|
||||||
|
bootJar {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user