1. module-api (애플리케이션 계층)

api 계층은 bootJar가 활성화되어 있는 독립적으로 실행 가능한 어플리케이션 모듈이다. 모든 하위 모듈들을 조립하여 서비스 비즈니스를 완성하게 된다.
의존성(모든 하위 모듈에 의존)
- module-infrastructure
- module-domain
- module-global-utils
주요 구성(기능별 패키지 분리)
- 메인 애플리케이션 실행부
- Controller 레이어: 요청/응답 처리
- Application Service 레이어: 여러 도메인 기능 조합 및 유스케이스 구현
빌드 설정
- bootJar 활성화 (실행 가능한 JAR 생성)
기능 단위나 기능 수가 확장된다면, module-api 하위에 module-api-place, module-api-meeting과 같이 확장이 가능하다.
2. module-infrastructure

: 데이터 접근 및 외부 시스템과 연동, DB 영속성 처리, domain 모듈에 선언된 인터페이스를 구현하는 구현체들로 구성하였다.
의존성(하위 모듈에 의존)
- module-domain
- module-global-utils
주요 구성(기능별 패키지 분리)
- JPA 기반 영속성 구현체
- Repository 구현 및 쿼리 작성 (QueryDSL/Kotlin-JDSL)
- 외부 API 클라이언트 구성
- 도메인 ↔ 인프라 객체 변환 매퍼
빌드 설정
- bootJar 비활성화, Jar 생성 활성화
3. module-domain

: 비즈니스 규칙을 담고 있는 가장 핵심적인 모듈로, 기술 의존 없이 시스템의 개념과 규칙만 표현하도록 구성하였다.
의존성(하위 모듈에 의존)
- module-global-utils
주요 구성(기능별 패키지 분리)
- 도메인 모델(엔티티 역할을 하는 순수 Kotlin 클래스)
- Repository 인터페이스
- 도메인 예외 및 에러 정의
- Command/Query 객체 등 유스케이스 입력 모델
빌드 설정
- bootJar 비활성화, Jar 생성 활성화
4. module-global-utils

: 모든 모듈에서 공통적으로 활용할 수 있는 유틸리티 및 기본 구성 요소를 담는 최하위 계층, 필요한 경우 어디에서든 가져다 사용 가능하도록 구성하였다.
주의할 점은, 시스템 내 모든 모듈들이 의존할 수 있을만큼 얇은 의존성을 제공해야 하기에, 프로젝트 내 어떠한 모듈도 의존하지 않아야 한다. 외부의 의존 또한 가지면 안되고, 최대한 안정적이게 잘 변하지 않는 코드만 있어야 한다.
주요 구성(기능별 패키지 분리)
- 공통 예외 정의 및 에러 코드 구조
- 응답 포맷
- 공통 유틸리티 클래스(DataEncoder 등)
- 최소한의 범용 컴포넌트만 위치
빌드 설정
- bootJar 비활성화, Jar 생성 활성화
🔥 왜 global-utils를 과하게 쓰는 것이 위험한가?
1) 모든 모듈이 의존하기 때문에 변경 비용이 크다
: 최하위 모듈에서 계속해서 코드 변화가 있거나 오류가 있다면, 전체 시스템의 재빌드 및 재배포로 이어질 수 있다.
2) 결합도가 증가할 수 있다
: global-utils가 너무 비대해지면 상위 레이어들이 해당 모듈을 사용하며, 서로 비슷한 util을 공유하게 되고
결국 모듈 간 경계가 흐려질 수 있다.
