From 015913c6215e7f28e6e7c4d4de9fc2f19e787d78 Mon Sep 17 00:00:00 2001 From: Sumin Hwang <163857590+tnals0924@users.noreply.github.com> Date: Tue, 13 Oct 2026 19:12:23 +0900 Subject: [PATCH 1/4] =?UTF-8?q?chore:=20JVM=20=EA=B8=B0=EB=B3=B8=20?= =?UTF-8?q?=EC=8B=9C=EA=B0=84=EB=8C=80=EB=A5=BC=20=EC=84=9C=EC=9A=B8?= =?UTF-8?q?=EB=A1=9C=20=EA=B3=A0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kookmin/stream/config/TimezoneConfig.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 bootstrap/src/main/java/kr/ac/kookmin/stream/config/TimezoneConfig.java diff --git a/bootstrap/src/main/java/kr/ac/kookmin/stream/config/TimezoneConfig.java b/bootstrap/src/main/java/kr/ac/kookmin/stream/config/TimezoneConfig.java new file mode 100644 index 00000000..27778108 --- /dev/null +++ b/bootstrap/src/main/java/kr/ac/kookmin/stream/config/TimezoneConfig.java @@ -0,0 +1,18 @@ +package kr.ac.kookmin.stream.config; + +import jakarta.annotation.PostConstruct; +import java.util.TimeZone; +import kr.ac.kookmin.stream.common.DateUtil; +import org.springframework.context.annotation.Configuration; + +/** + * JVM 기본 시간대를 서울로 고정한다. 컨테이너 시간대(UTC)와 관계없이 {@code LocalDateTime.now()} 등이 한국 시간을 쓰게 한다. + */ +@Configuration +public class TimezoneConfig { + + @PostConstruct + void setDefaultTimeZone() { + TimeZone.setDefault(TimeZone.getTimeZone(DateUtil.KST)); + } +} From 6c0fd408fe85ba813cc582ec09d529bdb6040acb Mon Sep 17 00:00:00 2001 From: Sumin Hwang <163857590+tnals0924@users.noreply.github.com> Date: Tue, 13 Oct 2026 19:16:28 +0900 Subject: [PATCH 2/4] =?UTF-8?q?refactor:=20=EC=8B=9C=EA=B0=84=EB=8C=80=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=EC=9D=84=20bootstrap.config=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kookmin/stream/{ => bootstrap}/config/TimezoneConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename bootstrap/src/main/java/kr/ac/kookmin/stream/{ => bootstrap}/config/TimezoneConfig.java (91%) diff --git a/bootstrap/src/main/java/kr/ac/kookmin/stream/config/TimezoneConfig.java b/bootstrap/src/main/java/kr/ac/kookmin/stream/bootstrap/config/TimezoneConfig.java similarity index 91% rename from bootstrap/src/main/java/kr/ac/kookmin/stream/config/TimezoneConfig.java rename to bootstrap/src/main/java/kr/ac/kookmin/stream/bootstrap/config/TimezoneConfig.java index 27778108..43234362 100644 --- a/bootstrap/src/main/java/kr/ac/kookmin/stream/config/TimezoneConfig.java +++ b/bootstrap/src/main/java/kr/ac/kookmin/stream/bootstrap/config/TimezoneConfig.java @@ -1,4 +1,4 @@ -package kr.ac.kookmin.stream.config; +package kr.ac.kookmin.stream.bootstrap.config; import jakarta.annotation.PostConstruct; import java.util.TimeZone; From 83ede8e14b9a3d69105b62637658528edecfa082 Mon Sep 17 00:00:00 2001 From: Sumin Hwang <163857590+tnals0924@users.noreply.github.com> Date: Tue, 13 Oct 2026 19:16:28 +0900 Subject: [PATCH 3/4] =?UTF-8?q?refactor:=20=EB=A9=94=EC=9D=B8=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=EB=A5=BC=20bootstrap=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../stream/StreamServerApplication.java | 15 -------------- .../bootstrap/StreamServerApplication.java | 20 +++++++++++++++++++ .../DomainImplAccessTests.java | 2 +- .../{ => bootstrap}/ModularityTests.java | 5 +++-- .../{ => bootstrap}/MySqlIntegrationTest.java | 2 +- .../RentalApplyConcurrencyTest.java | 2 +- 6 files changed, 26 insertions(+), 20 deletions(-) delete mode 100644 bootstrap/src/main/java/kr/ac/kookmin/stream/StreamServerApplication.java create mode 100644 bootstrap/src/main/java/kr/ac/kookmin/stream/bootstrap/StreamServerApplication.java rename bootstrap/src/test/java/kr/ac/kookmin/stream/{ => bootstrap}/DomainImplAccessTests.java (97%) rename bootstrap/src/test/java/kr/ac/kookmin/stream/{ => bootstrap}/ModularityTests.java (67%) rename bootstrap/src/test/java/kr/ac/kookmin/stream/{ => bootstrap}/MySqlIntegrationTest.java (98%) rename bootstrap/src/test/java/kr/ac/kookmin/stream/{ => bootstrap}/RentalApplyConcurrencyTest.java (99%) diff --git a/bootstrap/src/main/java/kr/ac/kookmin/stream/StreamServerApplication.java b/bootstrap/src/main/java/kr/ac/kookmin/stream/StreamServerApplication.java deleted file mode 100644 index 7e19e23d..00000000 --- a/bootstrap/src/main/java/kr/ac/kookmin/stream/StreamServerApplication.java +++ /dev/null @@ -1,15 +0,0 @@ -package kr.ac.kookmin.stream; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.ConfigurationPropertiesScan; - -@SpringBootApplication -@ConfigurationPropertiesScan -public class StreamServerApplication { - - public static void main(String[] args) { - SpringApplication.run(StreamServerApplication.class, args); - } - -} diff --git a/bootstrap/src/main/java/kr/ac/kookmin/stream/bootstrap/StreamServerApplication.java b/bootstrap/src/main/java/kr/ac/kookmin/stream/bootstrap/StreamServerApplication.java new file mode 100644 index 00000000..cf1e4c9c --- /dev/null +++ b/bootstrap/src/main/java/kr/ac/kookmin/stream/bootstrap/StreamServerApplication.java @@ -0,0 +1,20 @@ +package kr.ac.kookmin.stream.bootstrap; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.AutoConfigurationPackage; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; + +// 메인 클래스는 bootstrap 패키지에 두지만, 빈·JPA 엔티티와 레포지토리·설정 바인딩은 모든 모듈이 있는 루트 패키지에서 찾는다 +@SpringBootApplication(scanBasePackages = StreamServerApplication.BASE_PACKAGE) +@AutoConfigurationPackage(basePackages = StreamServerApplication.BASE_PACKAGE) +@ConfigurationPropertiesScan(StreamServerApplication.BASE_PACKAGE) +public class StreamServerApplication { + + static final String BASE_PACKAGE = "kr.ac.kookmin.stream"; + + public static void main(String[] args) { + SpringApplication.run(StreamServerApplication.class, args); + } + +} diff --git a/bootstrap/src/test/java/kr/ac/kookmin/stream/DomainImplAccessTests.java b/bootstrap/src/test/java/kr/ac/kookmin/stream/bootstrap/DomainImplAccessTests.java similarity index 97% rename from bootstrap/src/test/java/kr/ac/kookmin/stream/DomainImplAccessTests.java rename to bootstrap/src/test/java/kr/ac/kookmin/stream/bootstrap/DomainImplAccessTests.java index f0cca2fe..5deb4b75 100644 --- a/bootstrap/src/test/java/kr/ac/kookmin/stream/DomainImplAccessTests.java +++ b/bootstrap/src/test/java/kr/ac/kookmin/stream/bootstrap/DomainImplAccessTests.java @@ -1,4 +1,4 @@ -package kr.ac.kookmin.stream; +package kr.ac.kookmin.stream.bootstrap; import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses; diff --git a/bootstrap/src/test/java/kr/ac/kookmin/stream/ModularityTests.java b/bootstrap/src/test/java/kr/ac/kookmin/stream/bootstrap/ModularityTests.java similarity index 67% rename from bootstrap/src/test/java/kr/ac/kookmin/stream/ModularityTests.java rename to bootstrap/src/test/java/kr/ac/kookmin/stream/bootstrap/ModularityTests.java index 4e08dea7..5ff71dec 100644 --- a/bootstrap/src/test/java/kr/ac/kookmin/stream/ModularityTests.java +++ b/bootstrap/src/test/java/kr/ac/kookmin/stream/bootstrap/ModularityTests.java @@ -1,4 +1,4 @@ -package kr.ac.kookmin.stream; +package kr.ac.kookmin.stream.bootstrap; import org.junit.jupiter.api.Test; import org.springframework.modulith.core.ApplicationModules; @@ -6,7 +6,8 @@ class ModularityTests { - private final ApplicationModules modules = ApplicationModules.of(StreamServerApplication.class); + // 메인 클래스 패키지(bootstrap)가 아니라 루트 패키지를 기준으로 모듈을 나눈다 + private final ApplicationModules modules = ApplicationModules.of(StreamServerApplication.BASE_PACKAGE); @Test void verify() { diff --git a/bootstrap/src/test/java/kr/ac/kookmin/stream/MySqlIntegrationTest.java b/bootstrap/src/test/java/kr/ac/kookmin/stream/bootstrap/MySqlIntegrationTest.java similarity index 98% rename from bootstrap/src/test/java/kr/ac/kookmin/stream/MySqlIntegrationTest.java rename to bootstrap/src/test/java/kr/ac/kookmin/stream/bootstrap/MySqlIntegrationTest.java index 9ad15035..36ae1e06 100644 --- a/bootstrap/src/test/java/kr/ac/kookmin/stream/MySqlIntegrationTest.java +++ b/bootstrap/src/test/java/kr/ac/kookmin/stream/bootstrap/MySqlIntegrationTest.java @@ -1,4 +1,4 @@ -package kr.ac.kookmin.stream; +package kr.ac.kookmin.stream.bootstrap; import java.util.Map; import org.springframework.boot.test.context.SpringBootTest; diff --git a/bootstrap/src/test/java/kr/ac/kookmin/stream/RentalApplyConcurrencyTest.java b/bootstrap/src/test/java/kr/ac/kookmin/stream/bootstrap/RentalApplyConcurrencyTest.java similarity index 99% rename from bootstrap/src/test/java/kr/ac/kookmin/stream/RentalApplyConcurrencyTest.java rename to bootstrap/src/test/java/kr/ac/kookmin/stream/bootstrap/RentalApplyConcurrencyTest.java index 1fb15c15..b837187a 100644 --- a/bootstrap/src/test/java/kr/ac/kookmin/stream/RentalApplyConcurrencyTest.java +++ b/bootstrap/src/test/java/kr/ac/kookmin/stream/bootstrap/RentalApplyConcurrencyTest.java @@ -1,4 +1,4 @@ -package kr.ac.kookmin.stream; +package kr.ac.kookmin.stream.bootstrap; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; From b76f1c55c29d917ba2c7896fde107f2f773106dd Mon Sep 17 00:00:00 2001 From: Sumin Hwang <163857590+tnals0924@users.noreply.github.com> Date: Tue, 13 Oct 2026 19:16:28 +0900 Subject: [PATCH 4/4] =?UTF-8?q?docs:=20=EB=A9=94=EC=9D=B8=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=9C=84=EC=B9=98=EC=99=80=20=ED=83=90?= =?UTF-8?q?=EC=83=89=20=EB=B2=94=EC=9C=84=20=EC=BB=A8=EB=B2=A4=EC=85=98=20?= =?UTF-8?q?=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/conventions/architecture.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/conventions/architecture.md b/docs/conventions/architecture.md index fcd48b89..0bc04259 100644 --- a/docs/conventions/architecture.md +++ b/docs/conventions/architecture.md @@ -201,7 +201,11 @@ Gradle 모듈 분리가 도메인 간 경계를 컴파일 타임에 막고, Spri ### 4-2. 패키지 컨벤션 (탐지 규칙) -- `@Modulithic` 메인 클래스는 `bootstrap`의 `{basePackage}`에 둔다. +- 메인 클래스는 `{basePackage}.bootstrap`에 두고, 탐색 범위는 `{basePackage}`로 넓힌다. 기본값(메인 클래스 패키지)으로 두면 다른 모듈의 빈·JPA 엔티티·레포지토리·`@ConfigurationProperties`를 찾지 못한다. + - 빈: `@SpringBootApplication(scanBasePackages = ...)` + - JPA 엔티티·레포지토리: `@AutoConfigurationPackage(basePackages = ...)` + - 설정 바인딩: `@ConfigurationPropertiesScan(...)` + - Modulith 모듈 탐지: `ApplicationModules.of("{basePackage}")` (클래스를 넘기면 그 패키지가 루트가 된다) - **Gradle 경로와 Java 패키지는 별개다.** 도메인은 Gradle 상 `:core:domain:{도메인}`이지만 패키지는 루트 직속 형제로 둔다. ``` @@ -262,7 +266,7 @@ import org.springframework.modulith.ApplicationModule; // bootstrap/src/test/.../ModularityTests.java class ModularityTests { - private final ApplicationModules modules = ApplicationModules.of(Application.class); + private final ApplicationModules modules = ApplicationModules.of("{basePackage}"); // 메인 클래스 패키지(bootstrap)가 아닌 루트 기준 @Test void verify() {