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
|
||||
|
||||
### 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.runApplication
|
||||
|
||||
@SpringBootApplication
|
||||
@SpringBootApplication(scanBasePackages = ["com.quantbench.balance"])
|
||||
class BalanceApplication
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
@@ -5,9 +5,7 @@ import org.springframework.boot.test.context.SpringBootTest
|
||||
|
||||
@SpringBootTest
|
||||
class BalanceApplicationTests {
|
||||
|
||||
@Test
|
||||
fun contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
97
build.gradle
97
build.gradle
@@ -1,40 +1,35 @@
|
||||
plugins {
|
||||
id 'org.jetbrains.kotlin.jvm' version '2.2.21'
|
||||
id 'org.jetbrains.kotlin.plugin.spring' version '2.2.21'
|
||||
id 'org.springframework.boot' version '4.0.1'
|
||||
id 'io.spring.dependency-management' version '1.1.7'
|
||||
id 'org.hibernate.orm' version '7.2.0.Final'
|
||||
id 'org.graalvm.buildtools.native' version '0.11.3'
|
||||
id 'org.jetbrains.kotlin.plugin.jpa' 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' 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.graalvm.buildtools.native' version '0.11.3' apply false
|
||||
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'
|
||||
version = '0.0.1-SNAPSHOT'
|
||||
description = 'balance'
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(24)
|
||||
}
|
||||
}
|
||||
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()
|
||||
}
|
||||
|
||||
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'
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(24)
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
@@ -43,18 +38,48 @@ kotlin {
|
||||
}
|
||||
}
|
||||
|
||||
hibernate {
|
||||
enhancement {
|
||||
enableAssociationManagement = true
|
||||
}
|
||||
dependencies {
|
||||
implementation 'org.jetbrains.kotlin:kotlin-reflect'
|
||||
// detektPlugins 'io.gitlab.arturbosch.detekt:detekt-formatting:1.23.7'
|
||||
}
|
||||
|
||||
allOpen {
|
||||
annotation 'jakarta.persistence.Entity'
|
||||
annotation 'jakarta.persistence.MappedSuperclass'
|
||||
annotation 'jakarta.persistence.Embeddable'
|
||||
}
|
||||
|
||||
tasks.named('test') {
|
||||
tasks.withType(Test) {
|
||||
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'
|
||||
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