본문 바로가기
개발

Spring Boot(Kotlin) 서버 기본 셋팅 — 1편. 왜 멀티 모듈 구조인가?

by 새싹 아빠 2025. 11. 21.

이 시리즈는 Spring Boot(Kotlin) 기반 서버를 처음 구성할 때
“실무에서 바로 쓰는 구조”를 그대로 따라 만들 수 있도록 정리한 개발 기록입니다.

기본적인 API 서버 셋팅을 잘 해놓으면,
이후 어떤 프로젝트든 같은 구조로 빠르게 개발할 수 있습니다.

📚 Spring Boot(Kotlin) 서버 기본 셋팅 — 시리즈 안내

(1편부터 12편까지 시리즈로 구성될 예정입니다)

  1. 왜 멀티 모듈 구조인가? (아키텍처 철학 & 전체 설계 편) ← 현재 글
  2. API Response 포맷 설계
  3. 글로벌 예외 처리(GlobalExceptionHandler)
  4. Swagger(OpenAPI) 설정
  5. Security(JWT) 기본 골격
  6. JWT TokenProvider
  7. Redis 설정
  8. Validation 설정
  9. Logging + MDC(traceId)
  10. application.yml 프로필 분리 (local/dev/prod)
  11. 멀티모듈 + JPA 기본 구조 정리
  12. 완성된 프로젝트 템플릿 git 공유

 

1편. 멀티 모듈 구조를 왜 사용하는가?

Spring Boot 프로젝트를 처음 만들면 대부분 이렇게 시작합니다:

src/main/kotlin
 ├─ controller
 ├─ service
 ├─ repository
 ├─ domain

즉, 단일 모듈 구조로 시작합니다. 초기에 서비스가 작을 땐 전혀 문제가 없습니다.
하지만 시간이 지나면서 문제가 하나씩 터지기 시작합니다.

 

⚠️ 1. 단일 모듈 구조의 문제점

1) 기능이 늘어날수록 Controller/Service가  늘어남

기능이 조금만 추가돼도 이렇게 늘어납니다:

  • 로그인 / 소셜 로그인
  • 푸시 알림
  • 일정 관리
  • 이미지 업로드
  • 검색
  • 관리자 페이지
  • 외부 API 연동
  • 배치 작업

2) 레이어드 아키텍처 규칙이 점점 무너짐

처음에는 이렇게 깨끗하게 시작합니다

  • Controller → Service → Repository

하지만 시간이 지나면 이런 일들이 벌어지기 쉽습니다

  • Controller에서 Service를 건너뛰고 Repository를 직접 호출
  • Service에서 외부 API 호출
  • 비즈니스 로직이 Controller/Service/Repository에 분산
  • DTO 대신 Entity를 그대로 외부로 반환

이런 일이 생기는 이유는 파일이 많아지고 복잡해져도, 구조적으로 막아주는 장치가 없기 때문입니다.

3) 외부에서 들어오는 값을 그대로 내부로 넘기는 위험

클라이언트의 요청은 신뢰할 수 없는 외부 데이터입니다. 그런데 많은 단일 모듈 프로젝트가 이렇게 작성합니다:

@PostMapping("/signup")
fun signup(@RequestBody request: SignupRequest) =
    userService.signup(request)

문제는 SignupRequest가 Service → Repository → Domain 계층까지

그대로 흘러가는 경우가 많다는 점입니다.

왜 위험할까요?

  • 외부 API 스펙이 바뀌면 내부 코드가 연쇄적으로 깨짐
  • 보안적으로 취약 (의도치 않은 필드가 그대로 전달될 수 있음)
  • Domain 레벨의 무결성이 무너짐 (도메인 규칙이 DTO에 의존)
  • 유지보수 난이도 증가 (어디까지가 외부 모델인지 경계가 모호)

그래서 필요한 것이 바로 “계층 간 매핑(DTO → Service Model → Entity)” 입니다.

즉,

  • Request DTO (api 계층) : 클라이언트가 보내는 값을 받는 전용 모델
  • Service 내부 모델(application 계층) : 비즈니스 로직이 다루기 편한 형태로 변환
  • Entity (domain 계층) : DB와 매핑되는 순수 도메인 객체

이 구조를 자연스럽게 강제하려면, 멀티 모듈 구조가 훨씬 유리합니다.
모듈이 나뉘어 있으면 “외부 값 그대로 깊은 계층으로 흘러 들어가는 것”을 설계 차원에서 막기 쉬워집니다.

4) 배치(Batch)와 API가 섞이기 시작함

API 서버는 24시간 빠르게 응답해야 하고,
Batch는 대량 처리나 스케줄링을 담당합니다.

둘이 같은 모듈/같은 서버에 있으면:

  • 배치 실행 중 장애 → API도 같이 다운
  • 배치 로직이 무거워지면 API 응답 지연
  • Batch만 수정해도 API 서버를 재시작해야 함
  • 서로 다른 책임이 섞임 (SRP 위반)

어느 순간부터는 “API와 배치를 분리하고 싶다”는 생각이 들 수밖에 없습니다.

 

⚡ 그래서 등장한 구조: 멀티 모듈 아키텍처

위 문제들을 해결하기 위해, 이 시리즈에서는 프로젝트를 다음과 같이 나누어 사용합니다.

/api          → Controller, Security, Filter, API 응답/요청 DTO
/application  → Service, TokenProvider, Domain 규칙, Repository 인터페이스
/batch        → Scheduler, Cron 작업

 

 

 

🟦 2. 멀티 모듈 구조의 장점

🟢 장점 1) 책임 분리가 명확하다 (SRP 준수)

모듈 역할
api 클라이언트 요청을 받고 응답을 만드는 영역 (Web Layer, Controller, Filter, Security)
application 비즈니스 로직(Service), Domain 규칙, TokenProvider, Repository 인터페이스
batch 주기 작업, 대량 처리용 모듈 (스케줄러, Cron 기반 작업)

덕분에 기능이 커져도 “어떤 코드가 어디 있어야 하는지”가 명확해집니다.
각 모듈은 자신의 책임에만 집중하게 되고, 구조가 무너지지 않습니다.

🟢 장점 2) 외부 입력값을 그대로 넘기지 않고 “계층 별 DTO”가 자연스럽게 분리

흐름을 정리하면 이렇게 됩니다.

  • 클라이언트 요청 → Request DTO (api 계층)
  • Request DTO → Service 내부 모델 (application 계층)
  • Service 내부 모델 → Entity (domain 계층)

즉, 계층 간 매핑이 강제됩니다. 이 방식의 장점:

  • 외부 스펙 변화가 내부 도메인을 직접 깨뜨리지 않음
  • 보안적으로 안전 (불필요한 필드가 내부로 끼어들기 어려움)
  • 도메인 모델(Entity)이 깔끔하게 유지됨
  • 서비스 코드에서 “입력 모델”과 “도메인 모델”을 구분해서 다룰 수 있음

특히 Request/Response DTO는 api 모듈에,
실제 도메인/서비스 모델은 application 모듈에 둠으로써
“외부 값이 깊은 레이어까지 스며드는 것”을 구조적으로 막을 수 있습니다.

🟢 장점 3) API / Batch를 독립적으로 실행 가능

IntelliJ 기준으로,

  • ApiApplicationKt 실행 → API 서버
  • BatchApplicationKt 실행 → 배치 서버

이렇게 서로 다른 Run Configuration으로 동시에 실행할 수 있습니다.
운영 환경에서도 각각 독립 배포가 가능해집니다.

🟢 장점 4) 테스트하기 쉽다

  • api 모듈: Controller / Filter / Security 테스트
  • application 모듈: Service 비즈니스 로직 테스트
  • batch 모듈: 스케줄러 및 배치 로직 테스트

모듈이 분리되어 있기 때문에, 필요 없는 다른 계층을 끌어들이지 않고도 테스트를 작성할 수 있습니다.

🟢 장점 5) 대규모 서비스로 확장하기 좋은 구조

나중에 서비스가 커지면 이렇게 확장할 수도 있습니다:

/api
/application
/batch
/notification
/file
/auth

새로운 기능을 새 모듈로 분리해 나가는 것이 가능해집니다.
전체 프로젝트가 커져도, 모듈 단위로 관리하면서 복잡도를 통제할 수 있습니다.

 

🟦 3. 이 시리즈에서 다룰 모듈별 작업 맵

각 편이 어떤 모듈과 관련 있는지 한 번에 볼 수 있도록 정리해보면 아래와 같습니다.

Step 작업 내용 관련 모듈
1 왜 멀티 모듈 구조인가? (아키텍처 철학 & 전체 설계) 전체 개요
2 API Response 포맷 설계 api / application
3 글로벌 예외 처리(GlobalExceptionHandler) api / application
4 Swagger(OpenAPI) 설정 api
5 Security(JWT) 기본 골격 api
6 JWT TokenProvider application
7 Redis 설정 application
8 Validation 설정 api / application
9 Logging + MDC(traceId) api
10 application.yml 프로필 분리 전체
11 멀티모듈 + JPA 기본 구조 정리 api / application
12 완성된 프로젝트 템플릿 zip 공유 전체 (GitHub / zip)

 

🟩 다음 글 예고

다음 글에서는 실제 코드 작업을 시작합니다.

👉 2편. API Response 포맷 설계 — 왜 가장 먼저 해야 하는가?
공통 응답 포맷을 먼저 잡아두면, 이후 예외 처리, Security, Logging까지 모두 일관된 구조로 이어갈 수 있습니다.

 

다음 글:

https://jaemoi8.tistory.com/30

 

Spring Boot(Kotlin) — 2편. API Response 포맷 설계

📚 Spring Boot(Kotlin) 서버 기본 셋팅 — 시리즈 안내왜 멀티 모듈 구조인가? (아키텍처 철학 & 전체 설계 편) API Response 포맷 설계 ← 현재 글글로벌 예외 처리(GlobalExceptionHandler)Swagger(OpenAPI) 설정Secur

jaemoi8.tistory.com