From 003b54351c073361cfd9272616e050f3737dc80c Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Tue, 28 Oct 2025 02:30:05 +0900
Subject: [PATCH 01/40] =?UTF-8?q?docs:=201round.md=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 docs/1round.md | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)
 create mode 100644 docs/1round.md

diff --git a/docs/1round.md b/docs/1round.md
new file mode 100644
index 000000000..922b0bcea
--- /dev/null
+++ b/docs/1round.md
@@ -0,0 +1,67 @@
+## 🧪 Implementation Quest
+
+> 지정된 **단위 테스트 / 통합 테스트 / E2E 테스트 케이스**를 필수로 구현하고, 모든 테스트를 통과시키는 것을 목표로 합니다.
+>
+
+### 회원 가입
+
+**🧱 단위 테스트**
+
+- [ ]  ID 가 `영문 및 숫자 10자 이내` 형식에 맞지 않으면, User 객체 생성에 실패한다.
+- [ ]  이메일이 `xx@yy.zz` 형식에 맞지 않으면, User 객체 생성에 실패한다.
+- [ ]  생년월일이 `yyyy-MM-dd` 형식에 맞지 않으면, User 객체 생성에 실패한다.
+
+**🔗 통합 테스트**
+
+- [ ]  회원 가입시 User 저장이 수행된다. ( spy 검증 )
+- [ ]  이미 가입된 ID 로 회원가입 시도 시, 실패한다.
+
+**🌐 E2E 테스트**
+
+- [ ]  회원 가입이 성공할 경우, 생성된 유저 정보를 응답으로 반환한다.
+- [ ]  회원 가입 시에 성별이 없을 경우, `400 Bad Request` 응답을 반환한다.
+
+### 내 정보 조회
+
+**🔗 통합 테스트**
+
+- [ ]  해당 ID 의 회원이 존재할 경우, 회원 정보가 반환된다.
+- [ ]  해당 ID 의 회원이 존재하지 않을 경우, null 이 반환된다.
+
+**🌐 E2E 테스트**
+
+- [ ]  내 정보 조회에 성공할 경우, 해당하는 유저 정보를 응답으로 반환한다.
+- [ ]  존재하지 않는 ID 로 조회할 경우, `404 Not Found` 응답을 반환한다.
+
+### 포인트 조회
+
+**🔗 통합 테스트**
+
+- [ ]  해당 ID 의 회원이 존재할 경우, 보유 포인트가 반환된다.
+- [ ]  해당 ID 의 회원이 존재하지 않을 경우, null 이 반환된다.
+
+**🌐 E2E 테스트**
+
+- [ ]  포인트 조회에 성공할 경우, 보유 포인트를 응답으로 반환한다.
+- [ ]  `X-USER-ID` 헤더가 없을 경우, `400 Bad Request` 응답을 반환한다.
+
+### 포인트 충전
+
+**🧱 단위 테스트**
+
+- [ ]  0 이하의 정수로 포인트를 충전 시 실패한다.
+
+**🔗 통합 테스트**
+
+- [ ]  존재하지 않는 유저 ID 로 충전을 시도한 경우, 실패한다.
+
+**🌐 E2E 테스트**
+
+- [ ]  존재하는 유저가 1000원을 충전할 경우, 충전된 보유 총량을 응답으로 반환한다.
+- [ ]  존재하지 않는 유저로 요청할 경우, `404 Not Found` 응답을 반환한다.
+
+## ✅ Checklist
+
+- [ ]  테스트는 모두 통과해야 하며, `@Test` 기반으로 명시적으로 작성
+- [ ]  각 테스트는 테스트 명/설명/입력/예상 결과가 분명해야 함
+- [ ]  E2E 테스트는 실제 HTTP 요청을 통해 흐름을 검증할 것
\ No newline at end of file

From 00498cd9969b6df9d026a270376da4d27c2f85a5 Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Tue, 28 Oct 2025 03:22:55 +0900
Subject: [PATCH 02/40] =?UTF-8?q?feat:=20User=20=EB=8F=84=EB=A9=94?=
 =?UTF-8?q?=EC=9D=B8=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../java/com/loopers/domain/user/User.java    | 13 +++++++++
 .../com/loopers/domain/user/UserBirth.java    | 26 ++++++++++++++++++
 .../com/loopers/domain/user/UserEmail.java    | 27 +++++++++++++++++++
 .../java/com/loopers/domain/user/UserId.java  | 24 +++++++++++++++++
 4 files changed, 90 insertions(+)
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/user/User.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/user/UserBirth.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/user/UserEmail.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/user/UserId.java

diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/user/User.java b/apps/commerce-api/src/main/java/com/loopers/domain/user/User.java
new file mode 100644
index 000000000..9e782a7e5
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/user/User.java
@@ -0,0 +1,13 @@
+package com.loopers.domain.user;
+
+public class User {
+    private final UserId userId;
+    private final UserEmail email;
+    private final UserBirth birth;
+
+    public User(UserId userId, UserEmail email, UserBirth birth) {
+        this.userId = userId;
+        this.email = email;
+        this.birth = birth;
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserBirth.java b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserBirth.java
new file mode 100644
index 000000000..0bdc950e3
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserBirth.java
@@ -0,0 +1,26 @@
+package com.loopers.domain.user;
+
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
+
+import java.util.regex.Pattern;
+
+public class UserBirth {
+
+    private static final Pattern PATTERN = Pattern.compile("^\\d{4}-\\d{2}-\\d{2}$");
+
+
+    private final String birth;
+
+    public UserBirth(String birth) {
+        if (birth == null || birth.isBlank()) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "생년월일이 비어 있을 수 없습니다.");
+        }
+
+        if(!PATTERN.matcher(birth).matches()) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "생년월일 형식이 맞지 않습니다.");
+        }
+
+        this.birth = birth;
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserEmail.java b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserEmail.java
new file mode 100644
index 000000000..a3005c312
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserEmail.java
@@ -0,0 +1,27 @@
+package com.loopers.domain.user;
+
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
+
+import java.util.regex.Pattern;
+
+public class UserEmail {
+
+    private final static Pattern PATTERN = Pattern.compile("^[\\w.+-]+@[\\w.-]+\\.[a-zA-Z]{2,}$");
+
+    private String email;
+
+    public UserEmail(String email) {
+        if(email == null || email.isBlank()) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "이메일이 비어 있을 수 없습니다.");
+        }
+
+        if(!PATTERN.matcher(email).matches()) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "이메일 형식에 맞지 않습니다. ex)xx@yy.zz");
+        }
+
+        this.email = email;
+    }
+
+
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserId.java b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserId.java
new file mode 100644
index 000000000..9adb13bbd
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserId.java
@@ -0,0 +1,24 @@
+package com.loopers.domain.user;
+
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
+
+import java.util.regex.Pattern;
+
+public class UserId {
+
+    private static final Pattern PATTERN = Pattern.compile("^[a-zA-Z0-9]{1,10}$");
+
+    private final String id;
+
+    public UserId(String id) {
+        if(id == null || id.isEmpty()) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "사용자 ID가 비어있을 수 없습니다.");
+        }
+
+        if (!PATTERN.matcher(id).matches()) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "사용자 ID가 영문 및 숫자 10자 이내여야 합니다.");
+        }
+        this.id = id;
+    }
+}

From 1ad67daafe6c9ae1398249e339b0c9bb20632869 Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Tue, 28 Oct 2025 03:23:37 +0900
Subject: [PATCH 03/40] =?UTF-8?q?test:=20=ED=9A=8C=EC=9B=90=EA=B0=80?=
 =?UTF-8?q?=EC=9E=85=20=EB=8B=A8=EC=9C=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../loopers/domain/user/UserBirthTest.java    | 25 +++++++++++++++
 .../loopers/domain/user/UserEmailTest.java    | 31 +++++++++++++++++++
 .../com/loopers/domain/user/UserIdTest.java   | 31 +++++++++++++++++++
 3 files changed, 87 insertions(+)
 create mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/user/UserBirthTest.java
 create mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/user/UserEmailTest.java
 create mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/user/UserIdTest.java

diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserBirthTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserBirthTest.java
new file mode 100644
index 000000000..7d603fa04
--- /dev/null
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserBirthTest.java
@@ -0,0 +1,25 @@
+package com.loopers.domain.user;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.*;
+
+@DisplayName("UserBirth Test")
+class UserBirthTest {
+    @DisplayName("UserBirth 모델을 생성할 때")
+    @Nested
+    class Create {
+        @DisplayName("UserBirth이 형식에 맞으면, 정상적으로 생성된다.")
+        @Test
+        void createUserBirth_whenValid() {
+            String birth = "1994-12-01";
+
+            UserBirth userBirth = new UserBirth(birth);
+
+            assertThat(userBirth).extracting("birth").isEqualTo(birth);
+        }
+    }
+}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserEmailTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserEmailTest.java
new file mode 100644
index 000000000..10a527b42
--- /dev/null
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserEmailTest.java
@@ -0,0 +1,31 @@
+package com.loopers.domain.user;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@DisplayName("UserEmail Test")
+class UserEmailTest {
+
+    @DisplayName("UserEmail 모델을 생성할 때")
+    @Nested
+    class Create {
+        @DisplayName("UserEmail이 형식에 맞으면, 정상적으로 생성된다.")
+        @Test
+        void createUserEmail_whenValid() {
+
+            // given
+            String email = "yh45g@gmail.com";
+
+            // when
+            UserEmail userEmail = new UserEmail(email);
+
+            // then
+            Assertions.assertThat(userEmail).extracting("email").isEqualTo(email);
+
+        }
+    }
+}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserIdTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserIdTest.java
new file mode 100644
index 000000000..67e23e206
--- /dev/null
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserIdTest.java
@@ -0,0 +1,31 @@
+package com.loopers.domain.user;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@DisplayName("UserId Test")
+class UserIdTest {
+
+    @DisplayName("UserId 모델을 생성할 때")
+    @Nested
+    class Create {
+        @DisplayName("userId가 형식에 맞으면, 정상적으로 생성된다.")
+        @Test
+        void createUserId_whenValid() {
+
+            // given
+            String id = "yh45g";
+
+            // when
+            UserId userId = new UserId(id);
+
+            // then
+            Assertions.assertThat(userId).extracting("id").isEqualTo(id);
+
+        }
+    }
+}

From 4a1336604a8f08fcc0ada12fe21244770040feb3 Mon Sep 17 00:00:00 2001
From: bookers-web <net75jin@bookers.life>
Date: Tue, 28 Oct 2025 18:57:19 +0900
Subject: [PATCH 04/40] =?UTF-8?q?feat=20:=20User=20=EA=B0=92=EA=B0=9D?=
 =?UTF-8?q?=EC=B2=B4=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=99=84=EB=A3=8C=20?=
 =?UTF-8?q?=ED=9B=84=20=EC=82=AD=EC=A0=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../com/loopers/domain/user/UserBirth.java    | 26 ----------------
 .../com/loopers/domain/user/UserEmail.java    | 27 ----------------
 .../java/com/loopers/domain/user/UserId.java  | 24 --------------
 .../loopers/domain/user/UserBirthTest.java    | 25 ---------------
 .../loopers/domain/user/UserEmailTest.java    | 31 -------------------
 .../com/loopers/domain/user/UserIdTest.java   | 31 -------------------
 6 files changed, 164 deletions(-)
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/user/UserBirth.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/user/UserEmail.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/user/UserId.java
 delete mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/user/UserBirthTest.java
 delete mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/user/UserEmailTest.java
 delete mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/user/UserIdTest.java

diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserBirth.java b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserBirth.java
deleted file mode 100644
index 0bdc950e3..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserBirth.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.loopers.domain.user;
-
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-
-import java.util.regex.Pattern;
-
-public class UserBirth {
-
-    private static final Pattern PATTERN = Pattern.compile("^\\d{4}-\\d{2}-\\d{2}$");
-
-
-    private final String birth;
-
-    public UserBirth(String birth) {
-        if (birth == null || birth.isBlank()) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "생년월일이 비어 있을 수 없습니다.");
-        }
-
-        if(!PATTERN.matcher(birth).matches()) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "생년월일 형식이 맞지 않습니다.");
-        }
-
-        this.birth = birth;
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserEmail.java b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserEmail.java
deleted file mode 100644
index a3005c312..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserEmail.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.loopers.domain.user;
-
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-
-import java.util.regex.Pattern;
-
-public class UserEmail {
-
-    private final static Pattern PATTERN = Pattern.compile("^[\\w.+-]+@[\\w.-]+\\.[a-zA-Z]{2,}$");
-
-    private String email;
-
-    public UserEmail(String email) {
-        if(email == null || email.isBlank()) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "이메일이 비어 있을 수 없습니다.");
-        }
-
-        if(!PATTERN.matcher(email).matches()) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "이메일 형식에 맞지 않습니다. ex)xx@yy.zz");
-        }
-
-        this.email = email;
-    }
-
-
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserId.java b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserId.java
deleted file mode 100644
index 9adb13bbd..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserId.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.loopers.domain.user;
-
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-
-import java.util.regex.Pattern;
-
-public class UserId {
-
-    private static final Pattern PATTERN = Pattern.compile("^[a-zA-Z0-9]{1,10}$");
-
-    private final String id;
-
-    public UserId(String id) {
-        if(id == null || id.isEmpty()) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "사용자 ID가 비어있을 수 없습니다.");
-        }
-
-        if (!PATTERN.matcher(id).matches()) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "사용자 ID가 영문 및 숫자 10자 이내여야 합니다.");
-        }
-        this.id = id;
-    }
-}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserBirthTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserBirthTest.java
deleted file mode 100644
index 7d603fa04..000000000
--- a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserBirthTest.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.loopers.domain.user;
-
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.*;
-
-@DisplayName("UserBirth Test")
-class UserBirthTest {
-    @DisplayName("UserBirth 모델을 생성할 때")
-    @Nested
-    class Create {
-        @DisplayName("UserBirth이 형식에 맞으면, 정상적으로 생성된다.")
-        @Test
-        void createUserBirth_whenValid() {
-            String birth = "1994-12-01";
-
-            UserBirth userBirth = new UserBirth(birth);
-
-            assertThat(userBirth).extracting("birth").isEqualTo(birth);
-        }
-    }
-}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserEmailTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserEmailTest.java
deleted file mode 100644
index 10a527b42..000000000
--- a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserEmailTest.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.loopers.domain.user;
-
-import org.assertj.core.api.Assertions;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-@DisplayName("UserEmail Test")
-class UserEmailTest {
-
-    @DisplayName("UserEmail 모델을 생성할 때")
-    @Nested
-    class Create {
-        @DisplayName("UserEmail이 형식에 맞으면, 정상적으로 생성된다.")
-        @Test
-        void createUserEmail_whenValid() {
-
-            // given
-            String email = "yh45g@gmail.com";
-
-            // when
-            UserEmail userEmail = new UserEmail(email);
-
-            // then
-            Assertions.assertThat(userEmail).extracting("email").isEqualTo(email);
-
-        }
-    }
-}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserIdTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserIdTest.java
deleted file mode 100644
index 67e23e206..000000000
--- a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserIdTest.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.loopers.domain.user;
-
-import org.assertj.core.api.Assertions;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-@DisplayName("UserId Test")
-class UserIdTest {
-
-    @DisplayName("UserId 모델을 생성할 때")
-    @Nested
-    class Create {
-        @DisplayName("userId가 형식에 맞으면, 정상적으로 생성된다.")
-        @Test
-        void createUserId_whenValid() {
-
-            // given
-            String id = "yh45g";
-
-            // when
-            UserId userId = new UserId(id);
-
-            // then
-            Assertions.assertThat(userId).extracting("id").isEqualTo(id);
-
-        }
-    }
-}

From bc962b2dae67d277e3e5a57fd2589fe898961576 Mon Sep 17 00:00:00 2001
From: bookers-web <net75jin@bookers.life>
Date: Tue, 28 Oct 2025 18:57:33 +0900
Subject: [PATCH 05/40] =?UTF-8?q?feat=20:=20User=20=EA=B0=9D=EC=B2=B4=20?=
 =?UTF-8?q?=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../java/com/loopers/domain/user/User.java    | 68 ++++++++++++++++---
 .../com/loopers/domain/user/UserTest.java     | 18 +++++
 2 files changed, 77 insertions(+), 9 deletions(-)
 create mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/user/UserTest.java

diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/user/User.java b/apps/commerce-api/src/main/java/com/loopers/domain/user/User.java
index 9e782a7e5..fec224c80 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/user/User.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/user/User.java
@@ -1,13 +1,63 @@
 package com.loopers.domain.user;
 
-public class User {
-    private final UserId userId;
-    private final UserEmail email;
-    private final UserBirth birth;
-
-    public User(UserId userId, UserEmail email, UserBirth birth) {
-        this.userId = userId;
-        this.email = email;
-        this.birth = birth;
+import com.loopers.domain.BaseEntity;
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Table;
+
+import java.util.regex.Pattern;
+
+@Entity
+@Table(name = "user")
+public class User extends BaseEntity {
+
+    private static final Pattern USERID_PATTERN = Pattern.compile("^[a-zA-Z0-9]{1,10}$");
+    private static final Pattern BIRTH_PATTERN = Pattern.compile("^\\d{4}-\\d{2}-\\d{2}$");
+    private static final Pattern EMAIL_PATTERN = Pattern.compile("^[\\w.+-]+@[\\w.-]+\\.[a-zA-Z]{2,}$");
+
+    private String userId;
+    private String email;
+    private String birth;
+
+    protected User() {}
+
+    public User(String userId, String email, String birth) {
+        this.userId = requireValidUserId(userId);
+        this.email = requireValidEmail(email);
+        this.birth = requireValidBirthDate(birth);
+    }
+
+    String requireValidUserId(String userId) {
+        if(userId == null || userId.isEmpty()) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "사용자 ID가 비어있을 수 없습니다.");
+        }
+
+        if (!USERID_PATTERN.matcher(userId).matches()) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "사용자 ID가 영문 및 숫자 10자 이내여야 합니다.");
+        }
+        return userId;
+    }
+
+    String requireValidEmail(String email) {
+        if(email == null || email.isBlank()) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "이메일이 비어 있을 수 없습니다.");
+        }
+
+        if(!EMAIL_PATTERN.matcher(email).matches()) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "이메일 형식에 맞지 않습니다. ex)xx@yy.zz");
+        }
+        return email;
+    }
+
+    String requireValidBirthDate(String birth) {
+        if (birth == null || birth.isBlank()) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "생년월일이 비어 있을 수 없습니다.");
+        }
+
+        if(!BIRTH_PATTERN.matcher(birth).matches()) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "생년월일 형식이 맞지 않습니다.");
+        }
+        return birth;
     }
 }
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserTest.java
new file mode 100644
index 000000000..1d938accc
--- /dev/null
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserTest.java
@@ -0,0 +1,18 @@
+package com.loopers.domain.user;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * packageName : com.loopers.domain.user
+ * fileName     : UserTest
+ * author      : byeonsungmun
+ * date        : 25. 10. 28.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 25. 10. 28.     byeonsungmun       최초 생성
+ */
+class UserTest {
+
+}

From 0605dc42e8612898d0ad5ca4d094d09e0b158283 Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Wed, 29 Oct 2025 03:25:07 +0900
Subject: [PATCH 06/40] =?UTF-8?q?docs:=201round.md=20=EB=AC=B8=EC=84=9C?=
 =?UTF-8?q?=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 docs/1round.md | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/docs/1round.md b/docs/1round.md
index 922b0bcea..28d422eb9 100644
--- a/docs/1round.md
+++ b/docs/1round.md
@@ -7,9 +7,9 @@
 
 **🧱 단위 테스트**
 
-- [ ]  ID 가 `영문 및 숫자 10자 이내` 형식에 맞지 않으면, User 객체 생성에 실패한다.
-- [ ]  이메일이 `xx@yy.zz` 형식에 맞지 않으면, User 객체 생성에 실패한다.
-- [ ]  생년월일이 `yyyy-MM-dd` 형식에 맞지 않으면, User 객체 생성에 실패한다.
+- [x]  ID 가 `영문 및 숫자 10자 이내` 형식에 맞지 않으면, User 객체 생성에 실패한다.
+- [x]  이메일이 `xx@yy.zz` 형식에 맞지 않으면, User 객체 생성에 실패한다.
+- [x]  생년월일이 `yyyy-MM-dd` 형식에 맞지 않으면, User 객체 생성에 실패한다.
 
 **🔗 통합 테스트**
 

From f1d94ed833be33a3c1125a406946a878084c67cf Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Wed, 29 Oct 2025 03:25:35 +0900
Subject: [PATCH 07/40] =?UTF-8?q?feat:=20UserRepository,=20UserService=20?=
 =?UTF-8?q?=EC=83=9D=EC=84=B1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../loopers/domain/user/UserRepository.java   | 10 ++++++++
 .../com/loopers/domain/user/UserService.java  | 25 +++++++++++++++++++
 2 files changed, 35 insertions(+)
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/user/UserRepository.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java

diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserRepository.java b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserRepository.java
new file mode 100644
index 000000000..6ac3b7b98
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserRepository.java
@@ -0,0 +1,10 @@
+package com.loopers.domain.user;
+
+import java.util.Optional;
+
+public interface UserRepository {
+
+    Optional<User> findByUserId(String id);
+
+    User save(User user);
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java
new file mode 100644
index 000000000..b5dad2ef6
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java
@@ -0,0 +1,25 @@
+package com.loopers.domain.user;
+
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+@RequiredArgsConstructor
+public class UserService {
+
+    private final UserRepository userRepository;
+
+    @Transactional
+    User register(String userId, String email, String birth) {
+        userRepository.findByUserId(userId).ifPresent(user -> {
+            throw new CoreException(ErrorType.CONFLICT);
+        });
+
+        User user = new User(userId, email, birth);
+        return userRepository.save(user);
+    }
+
+}

From a51021cf7e2c345d1e13aee7fc29402d9b885a32 Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Wed, 29 Oct 2025 03:26:47 +0900
Subject: [PATCH 08/40] =?UTF-8?q?test:=20=ED=9A=8C=EC=9B=90=20=EA=B0=80?=
 =?UTF-8?q?=EC=9E=85=20=ED=86=B5=ED=95=A9=ED=85=8C=EC=8A=A4=ED=8A=B8=20?=
 =?UTF-8?q?=EC=9E=91=EC=84=B1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../user/UserServiceIntegrationTest.java      | 52 +++++++++++++++++++
 1 file changed, 52 insertions(+)
 create mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java

diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java
new file mode 100644
index 000000000..f226daf6c
--- /dev/null
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java
@@ -0,0 +1,52 @@
+package com.loopers.domain.user;
+
+import com.loopers.support.error.CoreException;
+import com.loopers.utils.DatabaseCleanUp;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+@SpringBootTest
+class UserServiceIntegrationTest {
+
+    @Autowired
+    private UserRepository userRepository;
+
+    @Autowired
+    private UserService userService;
+
+    @Autowired
+    private DatabaseCleanUp databaseCleanUp;
+
+    @AfterEach
+    void tearDown() {
+        databaseCleanUp.truncateAllTables();
+    }
+
+    @DisplayName("통합 테스트 ")
+    @Nested
+    class UserRegister {
+
+        @DisplayName("회원 가입시 User 저장이 수행된다.")
+        @Test
+        void save_whenUserRegister() {
+            String userId = "yh45g";
+            String email = "yh45g@loopers.com";
+            String brith = "1994-12-05";
+
+            User user = new User(userId, email, brith);
+            UserRepository userRepositorySpy = spy(userRepository);
+            UserService userServiceSpy = new UserService(userRepositorySpy);
+            userServiceSpy.register(userId, email, brith);
+
+            verify(userRepositorySpy).save(user);
+        }
+    }
+}

From a946ac0a78d4bd7cbe562f61fc3f81baf7dc1673 Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Wed, 29 Oct 2025 03:32:17 +0900
Subject: [PATCH 09/40] =?UTF-8?q?fix:=20=EB=B6=88=ED=95=84=EC=9A=94?=
 =?UTF-8?q?=ED=95=9C=20import=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../main/java/com/loopers/domain/user/UserRepository.java    | 5 ++++-
 .../src/main/java/com/loopers/domain/user/UserService.java   | 4 ++--
 .../com/loopers/domain/user/UserServiceIntegrationTest.java  | 2 --
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserRepository.java b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserRepository.java
index 6ac3b7b98..06234b87f 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserRepository.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserRepository.java
@@ -1,10 +1,13 @@
 package com.loopers.domain.user;
 
+import org.springframework.stereotype.Component;
+
 import java.util.Optional;
 
+@Component
 public interface UserRepository {
 
     Optional<User> findByUserId(String id);
 
-    User save(User user);
+    void save(User user);
 }
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java
index b5dad2ef6..8603ad673 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java
@@ -13,13 +13,13 @@ public class UserService {
     private final UserRepository userRepository;
 
     @Transactional
-    User register(String userId, String email, String birth) {
+    public void register(String userId, String email, String birth) {
         userRepository.findByUserId(userId).ifPresent(user -> {
             throw new CoreException(ErrorType.CONFLICT);
         });
 
         User user = new User(userId, email, birth);
-        return userRepository.save(user);
+        userRepository.save(user);
     }
 
 }
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java
index f226daf6c..a8b887ef2 100644
--- a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java
@@ -1,6 +1,5 @@
 package com.loopers.domain.user;
 
-import com.loopers.support.error.CoreException;
 import com.loopers.utils.DatabaseCleanUp;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.DisplayName;
@@ -9,7 +8,6 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 
-import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 

From 33c0ab862b18e90eabdbf0384325884d0b727b93 Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Thu, 30 Oct 2025 04:43:19 +0900
Subject: [PATCH 10/40] =?UTF-8?q?test:=20=EB=82=B4=EC=A0=95=EB=B3=B4=20?=
 =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EB=B0=8F=20E2E=20=ED=85=8C=EC=8A=A4?=
 =?UTF-8?q?=ED=8A=B8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../loopers/application/user/UserFacade.java  |  25 ++++
 .../loopers/application/user/UserInfo.java    |  14 ++
 .../java/com/loopers/domain/user/User.java    |  22 ++-
 .../loopers/domain/user/UserRepository.java   |   7 +-
 .../com/loopers/domain/user/UserService.java  |  13 +-
 .../user/UserJpaRepository.java               |  10 ++
 .../user/UserRepositoryImpl.java              |  27 ++++
 .../interfaces/api/user/UserV1ApiSpec.java    |  28 ++++
 .../interfaces/api/user/UserV1Controller.java |  31 ++++
 .../interfaces/api/user/UserV1Dto.java        |  24 ++++
 .../user/UserServiceIntegrationTest.java      |  29 ++--
 .../api/user/UserV1ControllerTest.java        | 135 ++++++++++++++++++
 12 files changed, 348 insertions(+), 17 deletions(-)
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/application/user/UserFacade.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/application/user/UserInfo.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserJpaRepository.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserRepositoryImpl.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1ApiSpec.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Controller.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Dto.java
 create mode 100644 apps/commerce-api/src/test/java/com/loopers/interfaces/api/user/UserV1ControllerTest.java

diff --git a/apps/commerce-api/src/main/java/com/loopers/application/user/UserFacade.java b/apps/commerce-api/src/main/java/com/loopers/application/user/UserFacade.java
new file mode 100644
index 000000000..4df3eff79
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/application/user/UserFacade.java
@@ -0,0 +1,25 @@
+package com.loopers.application.user;
+
+import com.loopers.domain.user.User;
+import com.loopers.domain.user.UserService;
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+@RequiredArgsConstructor
+@Component
+public class UserFacade {
+    private final UserService userService;
+
+    public UserInfo register(String userId, String email, String birth, String gender) {
+        User user = userService.register(userId, email, birth, gender);
+        return UserInfo.from(user);
+    }
+
+    public UserInfo getUser(String userId) {
+        return userService.findUserByUserId(userId)
+                .map(UserInfo::from)
+                .orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "회원 정보를 찾을 수 없습니다."));
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/user/UserInfo.java b/apps/commerce-api/src/main/java/com/loopers/application/user/UserInfo.java
new file mode 100644
index 000000000..08f5cea43
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/application/user/UserInfo.java
@@ -0,0 +1,14 @@
+package com.loopers.application.user;
+
+import com.loopers.domain.user.User;
+
+public record UserInfo(String userId, String email, String birth, String gender) {
+    public static UserInfo from(User user) {
+        return new UserInfo(
+                user.getUserId(),
+                user.getEmail(),
+                user.getBirth(),
+                user.getGender()
+        );
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/user/User.java b/apps/commerce-api/src/main/java/com/loopers/domain/user/User.java
index fec224c80..67ce14001 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/user/User.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/user/User.java
@@ -1,31 +1,44 @@
 package com.loopers.domain.user;
 
 import com.loopers.domain.BaseEntity;
+import com.loopers.domain.point.Point;
 import com.loopers.support.error.CoreException;
 import com.loopers.support.error.ErrorType;
+import jakarta.persistence.Column;
 import jakarta.persistence.Entity;
 import jakarta.persistence.Table;
+import lombok.Getter;
 
 import java.util.regex.Pattern;
 
 @Entity
 @Table(name = "user")
+@Getter
 public class User extends BaseEntity {
 
     private static final Pattern USERID_PATTERN = Pattern.compile("^[a-zA-Z0-9]{1,10}$");
     private static final Pattern BIRTH_PATTERN = Pattern.compile("^\\d{4}-\\d{2}-\\d{2}$");
     private static final Pattern EMAIL_PATTERN = Pattern.compile("^[\\w.+-]+@[\\w.-]+\\.[a-zA-Z]{2,}$");
 
+    @Column(unique = true, nullable = false)
     private String userId;
+
+    @Column(nullable = false)
     private String email;
+
+    @Column(nullable = false)
     private String birth;
 
+    @Column(nullable = false)
+    private String gender;
+
     protected User() {}
 
-    public User(String userId, String email, String birth) {
+    public User(String userId, String email, String birth, String gender) {
         this.userId = requireValidUserId(userId);
         this.email = requireValidEmail(email);
         this.birth = requireValidBirthDate(birth);
+        this.gender = requireValidGender(gender);
     }
 
     String requireValidUserId(String userId) {
@@ -60,4 +73,11 @@ String requireValidBirthDate(String birth) {
         }
         return birth;
     }
+
+    String requireValidGender(String gender) {
+        if(gender == null || gender.isBlank()) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "성별이 비어있습니다.");
+        }
+        return gender;
+    }
 }
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserRepository.java b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserRepository.java
index 06234b87f..f4b26266e 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserRepository.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserRepository.java
@@ -1,13 +1,10 @@
 package com.loopers.domain.user;
 
-import org.springframework.stereotype.Component;
-
 import java.util.Optional;
 
-@Component
 public interface UserRepository {
 
-    Optional<User> findByUserId(String id);
+    Optional<User> findByUserId(String userId);
 
-    void save(User user);
+    User save(User user);
 }
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java
index 8603ad673..8dcf999e8 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java
@@ -6,6 +6,8 @@
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.util.Optional;
+
 @Component
 @RequiredArgsConstructor
 public class UserService {
@@ -13,13 +15,18 @@ public class UserService {
     private final UserRepository userRepository;
 
     @Transactional
-    public void register(String userId, String email, String birth) {
+    public User register(String userId, String email, String birth, String gender) {
         userRepository.findByUserId(userId).ifPresent(user -> {
             throw new CoreException(ErrorType.CONFLICT);
         });
 
-        User user = new User(userId, email, birth);
-        userRepository.save(user);
+        User user = new User(userId, email, birth, gender);
+        return userRepository.save(user);
+    }
+
+    @Transactional(readOnly = true)
+    public Optional<User> findUserByUserId(String userId){
+        return userRepository.findByUserId(userId);
     }
 
 }
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserJpaRepository.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserJpaRepository.java
new file mode 100644
index 000000000..1a78b9a69
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserJpaRepository.java
@@ -0,0 +1,10 @@
+package com.loopers.infrastructure.user;
+
+import com.loopers.domain.user.User;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.Optional;
+
+public interface UserJpaRepository extends JpaRepository<User, Long> {
+    Optional<User> findByUserId(String userId);
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserRepositoryImpl.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserRepositoryImpl.java
new file mode 100644
index 000000000..25f05bc6e
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserRepositoryImpl.java
@@ -0,0 +1,27 @@
+package com.loopers.infrastructure.user;
+
+import com.loopers.domain.user.User;
+import com.loopers.domain.user.UserRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+import java.util.Optional;
+
+@RequiredArgsConstructor
+@Component
+public class UserRepositoryImpl implements UserRepository {
+
+    private final UserJpaRepository userJpaRepository;
+
+    @Override
+    public Optional<User> findByUserId(String userId) {
+        return userJpaRepository.findByUserId(userId);
+    }
+
+    @Override
+    public User save(User user) {
+        userJpaRepository.save(user);
+        return user;
+    }
+}
+
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1ApiSpec.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1ApiSpec.java
new file mode 100644
index 000000000..f11f386e2
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1ApiSpec.java
@@ -0,0 +1,28 @@
+package com.loopers.interfaces.api.user;
+
+import com.loopers.interfaces.api.ApiResponse;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+@Tag(name = "Users V1 API", description = "Users API입니다.")
+public interface UserV1ApiSpec {
+
+    @Operation(
+            summary = "회원 가입",
+            description = "회원 가입을 합니다."
+    )
+    ApiResponse<UserV1Dto.UserResponse> register(
+        @Schema(description = "회원가입")
+        UserV1Dto.RegisterRequest request
+    );
+
+    @Operation(
+            summary = "회원 조회",
+            description = "해당 회원을 조회합니다."
+    )
+    ApiResponse<UserV1Dto.UserResponse> getUser(
+        @Schema(name = "회원 ID", description = "조회할 회원 ID")
+        String userId
+    );
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Controller.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Controller.java
new file mode 100644
index 000000000..aed39ae1f
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Controller.java
@@ -0,0 +1,31 @@
+package com.loopers.interfaces.api.user;
+
+import com.loopers.application.user.UserFacade;
+import com.loopers.application.user.UserInfo;
+import com.loopers.interfaces.api.ApiResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/api/v1/users")
+public class UserV1Controller implements UserV1ApiSpec {
+
+    private final UserFacade userFacade;
+
+    @Override
+    @PostMapping("/register")
+    public ApiResponse<UserV1Dto.UserResponse> register(@RequestBody UserV1Dto.RegisterRequest request) {
+        UserInfo userInfo = userFacade.register(request.userId(), request.mail(), request.birth(), request.gender());
+        UserV1Dto.UserResponse response = UserV1Dto.UserResponse.from(userInfo);
+        return ApiResponse.success(response);
+    }
+
+    @Override
+    @GetMapping("/{userId}")
+    public ApiResponse<UserV1Dto.UserResponse> getUser(@PathVariable String userId) {
+        UserInfo userInfo = userFacade.getUser(userId);
+        UserV1Dto.UserResponse response = UserV1Dto.UserResponse.from(userInfo);
+        return ApiResponse.success(response);
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Dto.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Dto.java
new file mode 100644
index 000000000..cc634be67
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Dto.java
@@ -0,0 +1,24 @@
+package com.loopers.interfaces.api.user;
+
+import com.loopers.application.user.UserInfo;
+import jakarta.validation.Valid;
+
+public class UserV1Dto {
+    public record RegisterRequest(
+            String userId,
+            String mail,
+            String birth,
+            String gender
+    ){}
+
+    public record UserResponse(String userId, String email, String birth, String gender) {
+        public static UserResponse from(UserInfo info) {
+            return new UserResponse(
+                    info.userId(),
+                    info.email(),
+                    info.birth(),
+                    info.gender()
+            );
+        }
+    }
+}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java
index a8b887ef2..edcfca9a9 100644
--- a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java
@@ -1,13 +1,12 @@
 package com.loopers.domain.user;
 
+import com.loopers.support.error.CoreException;
 import com.loopers.utils.DatabaseCleanUp;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.*;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
@@ -28,7 +27,7 @@ void tearDown() {
         databaseCleanUp.truncateAllTables();
     }
 
-    @DisplayName("통합 테스트 ")
+    @DisplayName("통합 테스트")
     @Nested
     class UserRegister {
 
@@ -38,13 +37,27 @@ void save_whenUserRegister() {
             String userId = "yh45g";
             String email = "yh45g@loopers.com";
             String brith = "1994-12-05";
+            String gender = "Male";
 
-            User user = new User(userId, email, brith);
             UserRepository userRepositorySpy = spy(userRepository);
             UserService userServiceSpy = new UserService(userRepositorySpy);
-            userServiceSpy.register(userId, email, brith);
+            userServiceSpy.register(userId, email, brith, gender);
 
-            verify(userRepositorySpy).save(user);
+            verify(userRepositorySpy).save(any(User.class));
+        }
+
+        @DisplayName("이미 가입된 ID 로 회원가입 시도 시, 실패한다.")
+        @Test
+        void register_whenUserIdAlreadyExists_thenFail() {
+            String userId = "yh45g";
+            String email = "yh45g@loopers.com";
+            String brith = "1994-12-05";
+            String gender = "Male";
+
+            userService.register(userId, email, brith, gender);
+
+            Assertions.assertThrows(CoreException.class, ()
+                    -> userService.register(userId, email, brith, gender));
         }
     }
 }
diff --git a/apps/commerce-api/src/test/java/com/loopers/interfaces/api/user/UserV1ControllerTest.java b/apps/commerce-api/src/test/java/com/loopers/interfaces/api/user/UserV1ControllerTest.java
new file mode 100644
index 000000000..c0648f86c
--- /dev/null
+++ b/apps/commerce-api/src/test/java/com/loopers/interfaces/api/user/UserV1ControllerTest.java
@@ -0,0 +1,135 @@
+package com.loopers.interfaces.api.user;
+
+import com.loopers.domain.user.User;
+import com.loopers.infrastructure.user.UserJpaRepository;
+import com.loopers.interfaces.api.ApiResponse;
+import com.loopers.utils.DatabaseCleanUp;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.*;
+
+import java.util.function.Function;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+class UserV1ControllerTest {
+
+    private static final String REGISTER_ENDPOINT = "/api/v1/users/register";
+    private static final Function<String, String> GETUSER_ENDPOINT = id -> "/api/v1/users/" + id;
+    private final TestRestTemplate testRestTemplate;
+    private final UserJpaRepository userJpaRepository;
+    private final DatabaseCleanUp databaseCleanUp;
+
+    @Autowired
+    public UserV1ControllerTest(TestRestTemplate testRestTemplate, UserJpaRepository userJpaRepository, DatabaseCleanUp databaseCleanUp) {
+        this.testRestTemplate = testRestTemplate;
+        this.userJpaRepository = userJpaRepository;
+        this.databaseCleanUp = databaseCleanUp;
+    }
+
+    @AfterEach
+    void tearDown() {
+        databaseCleanUp.truncateAllTables();
+    }
+
+    @DisplayName("POST /api/v1/users")
+    @Nested
+    class RegisterUser {
+        @DisplayName("회원 가입이 성공할 경우, 생성된 유저 정보를 응답으로 반환한다.")
+        @Test
+        void registerUser_whenSuccessResponseUser() {
+            String userId = "yh45g";
+            String email = "yh45g@loopers.com";
+            String birth = "1994-12-05";
+            String gender = "MALE";
+
+            UserV1Dto.RegisterRequest request = new UserV1Dto.RegisterRequest(userId, email, birth, gender);
+
+            ParameterizedTypeReference<ApiResponse<UserV1Dto.UserResponse>> responseType = new ParameterizedTypeReference<>() {};
+
+            ResponseEntity<ApiResponse<UserV1Dto.UserResponse>> response =
+                    testRestTemplate.exchange(REGISTER_ENDPOINT, HttpMethod.POST, new HttpEntity<>(request), responseType);
+
+            assertAll(
+                    () -> assertTrue(response.getStatusCode().is2xxSuccessful()),
+                    () -> assertThat(response.getBody().data().userId()).isEqualTo(userId),
+                    () -> assertThat(response.getBody().data().email()).isEqualTo(email),
+                    () -> assertThat(response.getBody().data().birth()).isEqualTo(birth),
+                    () -> assertThat(response.getBody().data().gender()).isEqualTo(gender)
+            );
+        }
+        @DisplayName("회원 가입 시에 성별이 없을 경우, 400 BAD_REQUEST 응답을 받는다.")
+        @Test
+        void throwsBadRequest_whenGenderIsNotProvided() {
+            String userId = "yh45g";
+            String email = "yh45g@loopers.com";
+            String birth = "1994-12-05";
+            String gender =  null;
+
+            UserV1Dto.RegisterRequest request = new UserV1Dto.RegisterRequest(userId, email, birth, gender);
+
+            ParameterizedTypeReference<ApiResponse<UserV1Dto.UserResponse>> responseType = new ParameterizedTypeReference<>() {};
+            ResponseEntity<ApiResponse<UserV1Dto.UserResponse>> response =
+                    testRestTemplate.exchange(REGISTER_ENDPOINT, HttpMethod.POST, new HttpEntity<>(request), responseType);
+
+            assertAll(
+                    () -> assertTrue(response.getStatusCode().is4xxClientError()),
+                    () -> assertThat(response.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST)
+            );
+        }
+    }
+
+    @DisplayName("GET /api/v1/users/{userId}")
+    @Nested
+    class GetUserById {
+        @DisplayName("해당 ID의 회원이 존재할 경우, 회원 정보가 반환된다.")
+        @Test
+        void getUserById_whenSuccessResponseUser() {
+            String userId = "yh45g";
+            String email = "yh45g@loopers.com";
+            String birth = "1994-12-05";
+            String gender = "MALE";
+
+            userJpaRepository.save(new User(userId, email, birth, gender));
+
+            String requestUrl = GETUSER_ENDPOINT.apply(userId);
+            ParameterizedTypeReference<ApiResponse<UserV1Dto.UserResponse>> responseType = new ParameterizedTypeReference<>() {};
+            ResponseEntity<ApiResponse<UserV1Dto.UserResponse>> response =
+                    testRestTemplate.exchange(requestUrl, HttpMethod.GET, new HttpEntity<>(null), responseType);
+
+            assertAll(
+                    () -> assertTrue(response.getStatusCode().is2xxSuccessful()),
+                    () -> assertThat(response.getBody().data().userId()).isEqualTo(userId),
+                    () -> assertThat(response.getBody().data().email()).isEqualTo(email),
+                    () -> assertThat(response.getBody().data().birth()).isEqualTo(birth),
+                    () -> assertThat(response.getBody().data().gender()).isEqualTo(gender)
+            );
+        }
+
+        @DisplayName("해당 ID의 회원이 존재하지 않을 경우, null 이 반환된다.")
+        @Test
+        void throwsException_whenInvalidUserIdIsProvided() {
+            String userId = "notUserId";
+            String requestUrl = GETUSER_ENDPOINT.apply(userId);
+            ParameterizedTypeReference<ApiResponse<UserV1Dto.UserResponse>> responseType = new ParameterizedTypeReference<>() {};
+            ResponseEntity<ApiResponse<UserV1Dto.UserResponse>> response =
+                    testRestTemplate.exchange(requestUrl, HttpMethod.GET, new HttpEntity<>(null), responseType);
+
+            HttpHeaders headers = new HttpHeaders();
+            assertAll(
+                    () -> assertTrue(response.getStatusCode().is4xxClientError()),
+                    () -> assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND)
+            );
+        }
+    }
+
+}

From b73c2c6d549816528d3c5165e7e200ef34a4d95f Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Thu, 30 Oct 2025 04:43:49 +0900
Subject: [PATCH 11/40] docs: 1round.md check list update

---
 docs/1round.md | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/docs/1round.md b/docs/1round.md
index 28d422eb9..b8931c23b 100644
--- a/docs/1round.md
+++ b/docs/1round.md
@@ -13,25 +13,25 @@
 
 **🔗 통합 테스트**
 
-- [ ]  회원 가입시 User 저장이 수행된다. ( spy 검증 )
-- [ ]  이미 가입된 ID 로 회원가입 시도 시, 실패한다.
+- [x]  회원 가입시 User 저장이 수행된다. ( spy 검증 )
+- [x]  이미 가입된 ID 로 회원가입 시도 시, 실패한다.
 
 **🌐 E2E 테스트**
 
-- [ ]  회원 가입이 성공할 경우, 생성된 유저 정보를 응답으로 반환한다.
-- [ ]  회원 가입 시에 성별이 없을 경우, `400 Bad Request` 응답을 반환한다.
+- [x]  회원 가입이 성공할 경우, 생성된 유저 정보를 응답으로 반환한다.
+- [x]  회원 가입 시에 성별이 없을 경우, `400 Bad Request` 응답을 반환한다.
 
 ### 내 정보 조회
 
 **🔗 통합 테스트**
 
-- [ ]  해당 ID 의 회원이 존재할 경우, 회원 정보가 반환된다.
-- [ ]  해당 ID 의 회원이 존재하지 않을 경우, null 이 반환된다.
+- [x]  해당 ID 의 회원이 존재할 경우, 회원 정보가 반환된다.
+- [x]  해당 ID 의 회원이 존재하지 않을 경우, null 이 반환된다.
 
 **🌐 E2E 테스트**
 
-- [ ]  내 정보 조회에 성공할 경우, 해당하는 유저 정보를 응답으로 반환한다.
-- [ ]  존재하지 않는 ID 로 조회할 경우, `404 Not Found` 응답을 반환한다.
+- [x]  내 정보 조회에 성공할 경우, 해당하는 유저 정보를 응답으로 반환한다.
+- [x]  존재하지 않는 ID 로 조회할 경우, `404 Not Found` 응답을 반환한다.
 
 ### 포인트 조회
 

From 8d5e90a8a0129ead9315ac4bbb80b1560fc68d45 Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Thu, 30 Oct 2025 04:44:08 +0900
Subject: [PATCH 12/40] =?UTF-8?q?feat:=20=ED=8F=AC=EC=9D=B8=ED=8A=B8=20?=
 =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=EC=B6=94?=
 =?UTF-8?q?=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../java/com/loopers/domain/point/Point.java  | 20 +++++++++++++++++++
 .../loopers/domain/point/PointRepository.java |  4 ++++
 .../loopers/domain/point/PointService.java    |  6 ++++++
 .../point/PointJpaRepository.java             |  7 +++++++
 4 files changed, 37 insertions(+)
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/point/PointRepository.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointJpaRepository.java

diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java b/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java
new file mode 100644
index 000000000..26266d141
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java
@@ -0,0 +1,20 @@
+package com.loopers.domain.point;
+
+
+import com.loopers.domain.BaseEntity;
+import com.loopers.domain.user.User;
+import jakarta.persistence.*;
+
+@Entity
+@Table(name = "point")
+public class Point extends BaseEntity {
+
+    @OneToOne(fetch = FetchType.LAZY, optional = false)
+    @JoinColumn(name = "user_id", unique = true, nullable = false)
+    private User user;
+
+    @Column(nullable = false)
+    private Long Amount;
+
+
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/point/PointRepository.java b/apps/commerce-api/src/main/java/com/loopers/domain/point/PointRepository.java
new file mode 100644
index 000000000..0a50068ca
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/point/PointRepository.java
@@ -0,0 +1,4 @@
+package com.loopers.domain.point;
+
+public interface PointRepository {
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java b/apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java
new file mode 100644
index 000000000..03807f888
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java
@@ -0,0 +1,6 @@
+package com.loopers.domain.point;
+
+public class PointService {
+
+
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointJpaRepository.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointJpaRepository.java
new file mode 100644
index 000000000..aa1089a9e
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointJpaRepository.java
@@ -0,0 +1,7 @@
+package com.loopers.infrastructure.point;
+
+import com.loopers.domain.point.Point;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface PointJpaRepository extends JpaRepository<Point, Long> {
+}

From d6711cfa75f8019e9555edb24d390d1af0f34d4b Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Thu, 30 Oct 2025 04:46:37 +0900
Subject: [PATCH 13/40] =?UTF-8?q?feat:=20=EB=82=B4=EC=A0=95=EB=B3=B4=20?=
 =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EB=B0=8F=20E2E=20=ED=85=8C=EC=8A=A4?=
 =?UTF-8?q?=ED=8A=B8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/java/com/loopers/domain/user/User.java             | 1 -
 .../java/com/loopers/interfaces/api/user/UserV1ApiSpec.java     | 2 +-
 .../main/java/com/loopers/interfaces/api/user/UserV1Dto.java    | 1 -
 .../com/loopers/interfaces/api/user/UserV1ControllerTest.java   | 1 -
 4 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/user/User.java b/apps/commerce-api/src/main/java/com/loopers/domain/user/User.java
index 67ce14001..287b84cf8 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/user/User.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/user/User.java
@@ -1,7 +1,6 @@
 package com.loopers.domain.user;
 
 import com.loopers.domain.BaseEntity;
-import com.loopers.domain.point.Point;
 import com.loopers.support.error.CoreException;
 import com.loopers.support.error.ErrorType;
 import jakarta.persistence.Column;
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1ApiSpec.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1ApiSpec.java
index f11f386e2..dec948cdf 100644
--- a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1ApiSpec.java
+++ b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1ApiSpec.java
@@ -5,7 +5,7 @@
 import io.swagger.v3.oas.annotations.media.Schema;
 import io.swagger.v3.oas.annotations.tags.Tag;
 
-@Tag(name = "Users V1 API", description = "Users API입니다.")
+@Tag(name = "Users V1 API", description = "Users API 입니다.")
 public interface UserV1ApiSpec {
 
     @Operation(
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Dto.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Dto.java
index cc634be67..16aab05e2 100644
--- a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Dto.java
+++ b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Dto.java
@@ -1,7 +1,6 @@
 package com.loopers.interfaces.api.user;
 
 import com.loopers.application.user.UserInfo;
-import jakarta.validation.Valid;
 
 public class UserV1Dto {
     public record RegisterRequest(
diff --git a/apps/commerce-api/src/test/java/com/loopers/interfaces/api/user/UserV1ControllerTest.java b/apps/commerce-api/src/test/java/com/loopers/interfaces/api/user/UserV1ControllerTest.java
index c0648f86c..5a297152b 100644
--- a/apps/commerce-api/src/test/java/com/loopers/interfaces/api/user/UserV1ControllerTest.java
+++ b/apps/commerce-api/src/test/java/com/loopers/interfaces/api/user/UserV1ControllerTest.java
@@ -124,7 +124,6 @@ void throwsException_whenInvalidUserIdIsProvided() {
             ResponseEntity<ApiResponse<UserV1Dto.UserResponse>> response =
                     testRestTemplate.exchange(requestUrl, HttpMethod.GET, new HttpEntity<>(null), responseType);
 
-            HttpHeaders headers = new HttpHeaders();
             assertAll(
                     () -> assertTrue(response.getStatusCode().is4xxClientError()),
                     () -> assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND)

From 7a566848790f056205df2f593f7d90324e48cb79 Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Fri, 31 Oct 2025 05:02:34 +0900
Subject: [PATCH 14/40] =?UTF-8?q?docs:=201round.md=20=EC=9A=94=EA=B5=AC?=
 =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EC=99=84=EB=A3=8C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 docs/1round.md | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/docs/1round.md b/docs/1round.md
index b8931c23b..106d6c809 100644
--- a/docs/1round.md
+++ b/docs/1round.md
@@ -37,31 +37,31 @@
 
 **🔗 통합 테스트**
 
-- [ ]  해당 ID 의 회원이 존재할 경우, 보유 포인트가 반환된다.
-- [ ]  해당 ID 의 회원이 존재하지 않을 경우, null 이 반환된다.
+- [x]  해당 ID 의 회원이 존재할 경우, 보유 포인트가 반환된다.
+- [x]  해당 ID 의 회원이 존재하지 않을 경우, null 이 반환된다.
 
 **🌐 E2E 테스트**
 
-- [ ]  포인트 조회에 성공할 경우, 보유 포인트를 응답으로 반환한다.
-- [ ]  `X-USER-ID` 헤더가 없을 경우, `400 Bad Request` 응답을 반환한다.
+- [x]  포인트 조회에 성공할 경우, 보유 포인트를 응답으로 반환한다.
+- [x]  `X-USER-ID` 헤더가 없을 경우, `400 Bad Request` 응답을 반환한다.
 
 ### 포인트 충전
 
 **🧱 단위 테스트**
 
-- [ ]  0 이하의 정수로 포인트를 충전 시 실패한다.
+- [X]  0 이하의 정수로 포인트를 충전 시 실패한다.
 
 **🔗 통합 테스트**
 
-- [ ]  존재하지 않는 유저 ID 로 충전을 시도한 경우, 실패한다.
+- [X]  존재하지 않는 유저 ID 로 충전을 시도한 경우, 실패한다.
 
 **🌐 E2E 테스트**
 
-- [ ]  존재하는 유저가 1000원을 충전할 경우, 충전된 보유 총량을 응답으로 반환한다.
-- [ ]  존재하지 않는 유저로 요청할 경우, `404 Not Found` 응답을 반환한다.
+- [X]  존재하는 유저가 1000원을 충전할 경우, 충전된 보유 총량을 응답으로 반환한다.
+- [X]  존재하지 않는 유저로 요청할 경우, `404 Not Found` 응답을 반환한다.
 
 ## ✅ Checklist
 
-- [ ]  테스트는 모두 통과해야 하며, `@Test` 기반으로 명시적으로 작성
-- [ ]  각 테스트는 테스트 명/설명/입력/예상 결과가 분명해야 함
-- [ ]  E2E 테스트는 실제 HTTP 요청을 통해 흐름을 검증할 것
\ No newline at end of file
+- [X]  테스트는 모두 통과해야 하며, `@Test` 기반으로 명시적으로 작성
+- [X]  각 테스트는 테스트 명/설명/입력/예상 결과가 분명해야 함
+- [X]  E2E 테스트는 실제 HTTP 요청을 통해 흐름을 검증할 것
\ No newline at end of file

From ded9e381c05c545f59c24e8e9f0f4d90f7f4d980 Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Fri, 31 Oct 2025 05:06:36 +0900
Subject: [PATCH 15/40] =?UTF-8?q?chore:=20=ED=8C=8C=EC=9D=BC=20=EC=9C=84?=
 =?UTF-8?q?=EC=B9=98=20=EC=9D=B4=EB=8F=99?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../interfaces/api/{ => example}/ExampleV1ApiE2ETest.java     | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
 rename apps/commerce-api/src/test/java/com/loopers/interfaces/api/{ => example}/ExampleV1ApiE2ETest.java (98%)

diff --git a/apps/commerce-api/src/test/java/com/loopers/interfaces/api/ExampleV1ApiE2ETest.java b/apps/commerce-api/src/test/java/com/loopers/interfaces/api/example/ExampleV1ApiE2ETest.java
similarity index 98%
rename from apps/commerce-api/src/test/java/com/loopers/interfaces/api/ExampleV1ApiE2ETest.java
rename to apps/commerce-api/src/test/java/com/loopers/interfaces/api/example/ExampleV1ApiE2ETest.java
index 1bb3dba65..70f256149 100644
--- a/apps/commerce-api/src/test/java/com/loopers/interfaces/api/ExampleV1ApiE2ETest.java
+++ b/apps/commerce-api/src/test/java/com/loopers/interfaces/api/example/ExampleV1ApiE2ETest.java
@@ -1,8 +1,8 @@
-package com.loopers.interfaces.api;
+package com.loopers.interfaces.api.example;
 
 import com.loopers.domain.example.ExampleModel;
 import com.loopers.infrastructure.example.ExampleJpaRepository;
-import com.loopers.interfaces.api.example.ExampleV1Dto;
+import com.loopers.interfaces.api.ApiResponse;
 import com.loopers.utils.DatabaseCleanUp;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.DisplayName;

From 5b83c0381587841ba3e14015d9233013c6d37122 Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Fri, 31 Oct 2025 05:07:19 +0900
Subject: [PATCH 16/40] =?UTF-8?q?feat:=20=ED=8F=AC=EC=9D=B8=ED=8A=B8=20?=
 =?UTF-8?q?=EB=8F=84=EB=A9=94=EC=9D=B8=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../application/point/PointFacade.java        | 28 ++++++++++++++
 .../loopers/application/point/PointInfo.java  | 13 +++++++
 .../java/com/loopers/domain/point/Point.java  | 37 +++++++++++++++----
 .../loopers/domain/point/PointRepository.java |  6 +++
 .../loopers/domain/point/PointService.java    | 24 ++++++++++++
 .../point/PointJpaRepository.java             |  4 ++
 .../point/PointRepositoryImpl.java            | 26 +++++++++++++
 .../interfaces/api/point/PointV1ApiSpec.java  | 27 ++++++++++++++
 .../api/point/PointV1Controller.java          | 31 ++++++++++++++++
 .../interfaces/api/point/PointV1Dto.java      | 17 +++++++++
 10 files changed, 205 insertions(+), 8 deletions(-)
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/application/point/PointFacade.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/application/point/PointInfo.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointRepositoryImpl.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1ApiSpec.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1Controller.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1Dto.java

diff --git a/apps/commerce-api/src/main/java/com/loopers/application/point/PointFacade.java b/apps/commerce-api/src/main/java/com/loopers/application/point/PointFacade.java
new file mode 100644
index 000000000..009be1cec
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/application/point/PointFacade.java
@@ -0,0 +1,28 @@
+package com.loopers.application.point;
+
+import com.loopers.domain.point.Point;
+import com.loopers.domain.point.PointService;
+import com.loopers.interfaces.api.point.PointV1Dto;
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+@RequiredArgsConstructor
+@Component
+public class PointFacade {
+    private final PointService pointService;
+
+    public PointInfo getPoint(String userId) {
+        Point point = pointService.findPointByUserId(userId);
+
+        if (point == null) {
+            throw new CoreException(ErrorType.NOT_FOUND, "사용자 존재하지 않습니다.");
+        }
+        return PointInfo.from(point);
+    }
+
+    public PointInfo chargePoint(PointV1Dto.ChargePointRequest request) {
+        return PointInfo.from(pointService.chargePoint(request.userId(), request.chargeAmount()));
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/point/PointInfo.java b/apps/commerce-api/src/main/java/com/loopers/application/point/PointInfo.java
new file mode 100644
index 000000000..2c357dc7e
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/application/point/PointInfo.java
@@ -0,0 +1,13 @@
+package com.loopers.application.point;
+
+import com.loopers.domain.point.Point;
+
+public record PointInfo(String userId, Long amount) {
+    public static PointInfo from(Point info) {
+        return new PointInfo(
+                info.getUserId(),
+                info.getAmount()
+        );
+    }
+
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java b/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java
index 26266d141..bef72fb00 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java
@@ -1,20 +1,41 @@
 package com.loopers.domain.point;
 
-
 import com.loopers.domain.BaseEntity;
-import com.loopers.domain.user.User;
-import jakarta.persistence.*;
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Table;
+import lombok.Getter;
 
 @Entity
 @Table(name = "point")
+@Getter
 public class Point extends BaseEntity {
 
-    @OneToOne(fetch = FetchType.LAZY, optional = false)
-    @JoinColumn(name = "user_id", unique = true, nullable = false)
-    private User user;
+    private String userId;
+
+    private Long amount;
+
+    protected Point() {}
+
+    public Point(String userId, Long amount) {
+        this.userId = requireValidUserId(userId);
+        this.amount = amount;
+    }
 
-    @Column(nullable = false)
-    private Long Amount;
+    String requireValidUserId(String userId) {
+        if(userId == null || userId.isEmpty()) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "사용자 ID가 비어있을 수 없습니다.");
+        }
+        return userId;
+    }
 
+    public Point charge(Long chargeAmount) {
+        if (chargeAmount == null || chargeAmount <= 0) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "0원 이하로 포인트를 충전 할수 없습니다.");
+        }
+        this.amount += chargeAmount;
+        return new Point(this.userId, this.amount);
+    }
 
 }
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/point/PointRepository.java b/apps/commerce-api/src/main/java/com/loopers/domain/point/PointRepository.java
index 0a50068ca..314022491 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/point/PointRepository.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/point/PointRepository.java
@@ -1,4 +1,10 @@
 package com.loopers.domain.point;
 
+import java.util.Optional;
+
 public interface PointRepository {
+
+    Optional<Point> findByUserId(String userId);
+
+    Point save(Point point);
 }
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java b/apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java
index 03807f888..2ecc7b456 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java
@@ -1,6 +1,30 @@
 package com.loopers.domain.point;
 
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@RequiredArgsConstructor
+@Component
 public class PointService {
 
+    private final PointRepository pointRepository;
+
+
+    @Transactional(readOnly = true)
+    public Point findPointByUserId(String userId) {
+        return pointRepository.findByUserId(userId).orElse(null);
+    }
+
+    @Transactional
+    public Point chargePoint(String userId, Long chargeAmount) {
+        Point point = pointRepository.findByUserId(userId)
+                .orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "포인트를 충전할수 없는 사용자입니다."));
+        point.charge(chargeAmount);
+        return pointRepository.save(point);
+    }
+
 
 }
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointJpaRepository.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointJpaRepository.java
index aa1089a9e..a35a56151 100644
--- a/apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointJpaRepository.java
+++ b/apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointJpaRepository.java
@@ -3,5 +3,9 @@
 import com.loopers.domain.point.Point;
 import org.springframework.data.jpa.repository.JpaRepository;
 
+import java.util.Optional;
+
 public interface PointJpaRepository extends JpaRepository<Point, Long> {
+
+    Optional<Point> findByUserId(String userId);
 }
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointRepositoryImpl.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointRepositoryImpl.java
new file mode 100644
index 000000000..1663b1d4f
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointRepositoryImpl.java
@@ -0,0 +1,26 @@
+package com.loopers.infrastructure.point;
+
+import com.loopers.domain.point.Point;
+import com.loopers.domain.point.PointRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+import java.util.Optional;
+
+@RequiredArgsConstructor
+@Component
+public class PointRepositoryImpl implements PointRepository {
+
+    private final PointJpaRepository pointJpaRepository;
+
+    @Override
+    public Optional<Point> findByUserId(String userId) {
+        return pointJpaRepository.findByUserId(userId);
+    }
+
+    @Override
+    public Point save(Point point) {
+        pointJpaRepository.save(point);
+        return point;
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1ApiSpec.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1ApiSpec.java
new file mode 100644
index 000000000..b954c1a4e
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1ApiSpec.java
@@ -0,0 +1,27 @@
+package com.loopers.interfaces.api.point;
+
+import com.loopers.interfaces.api.ApiResponse;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.tags.Tag;
+@Tag(name = "Point V1 API", description = "Point API 입니다.")
+public interface PointV1ApiSpec {
+
+    @Operation(
+            summary = "포인트 회원 조회",
+            description = "회원의 포인트를 조회한다."
+    )
+    ApiResponse<PointV1Dto.PointResponse> getPoint(
+            @Schema(name = "회원 Id", description = "조회할 회원 ID")
+            String userId
+    );
+
+    @Operation(
+            summary = "포인트 충전",
+            description = "회원의 포인트를 충전한다."
+    )
+    ApiResponse<PointV1Dto.PointResponse> chargePoint(
+            @Schema(name = "포인트 충전 요청", description = "조회할 회원 ID")
+            PointV1Dto.ChargePointRequest request
+    );
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1Controller.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1Controller.java
new file mode 100644
index 000000000..866fce9b3
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1Controller.java
@@ -0,0 +1,31 @@
+package com.loopers.interfaces.api.point;
+
+import com.loopers.application.point.PointFacade;
+import com.loopers.application.point.PointInfo;
+import com.loopers.interfaces.api.ApiResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/api/v1/points")
+public class PointV1Controller implements PointV1ApiSpec {
+
+    private final PointFacade pointFacade;
+
+    @Override
+    @GetMapping
+    public ApiResponse<PointV1Dto.PointResponse> getPoint(@RequestHeader("X-USER-ID") String userId) {
+        PointInfo pointInfo = pointFacade.getPoint(userId);
+        PointV1Dto.PointResponse response = PointV1Dto.PointResponse.from(pointInfo);
+        return ApiResponse.success(response);
+    }
+
+    @Override
+    @PatchMapping("/charge")
+    public ApiResponse<PointV1Dto.PointResponse> chargePoint(@RequestBody PointV1Dto.ChargePointRequest request) {
+        PointInfo pointInfo = pointFacade.chargePoint(request);
+        PointV1Dto.PointResponse response = PointV1Dto.PointResponse.from(pointInfo);
+        return ApiResponse.success(response);
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1Dto.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1Dto.java
new file mode 100644
index 000000000..406e84cc5
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1Dto.java
@@ -0,0 +1,17 @@
+package com.loopers.interfaces.api.point;
+
+import com.loopers.application.point.PointInfo;
+
+public class PointV1Dto {
+
+    public record ChargePointRequest(String userId, Long chargeAmount) {}
+
+    public record PointResponse(String userId, Long amount){
+        public static PointResponse from(PointInfo info) {
+            return new PointResponse(
+                    info.userId(),
+                    info.amount()
+            );
+        }
+    }
+}

From 3158c2bce49c3e9a6cea90cc499c54688ecb169a Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Fri, 31 Oct 2025 05:07:37 +0900
Subject: [PATCH 17/40] =?UTF-8?q?test:=20=ED=8F=AC=EC=9D=B8=ED=8A=B8=20?=
 =?UTF-8?q?=EB=8F=84=EB=A9=94=EC=9D=B8=20=EB=8B=A8=EC=9C=84=ED=85=8C?=
 =?UTF-8?q?=EC=8A=A4=ED=8A=B8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../com/loopers/domain/point/PointTest.java   | 23 +++++++++++++++++++
 1 file changed, 23 insertions(+)
 create mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/point/PointTest.java

diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/point/PointTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/point/PointTest.java
new file mode 100644
index 000000000..bcc911321
--- /dev/null
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/point/PointTest.java
@@ -0,0 +1,23 @@
+package com.loopers.domain.point;
+
+import com.loopers.support.error.CoreException;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class PointTest {
+    @DisplayName("Point 단위 테스트")
+    @Nested
+    class Charge {
+        @DisplayName("0 이하의 정수로 포인트를 충전 시 실패한다.")
+        @Test
+        void throwsChargeAmountFailException_whenZeroAmountOrNegative() {
+            Point point = new Point("yh45g", 0L);
+            assertThrows(CoreException.class, () ->
+                    point.charge(0L));
+        }
+    }
+
+}

From e287600296c6797ca187820d7036f229713cc969 Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Fri, 31 Oct 2025 05:07:42 +0900
Subject: [PATCH 18/40] =?UTF-8?q?test:=20=ED=8F=AC=EC=9D=B8=ED=8A=B8=20?=
 =?UTF-8?q?=EB=8F=84=EB=A9=94=EC=9D=B8=20=ED=86=B5=ED=95=A9=ED=85=8C?=
 =?UTF-8?q?=EC=8A=A4=ED=8A=B8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../point/PointServiceIntegrationTest.java    | 86 +++++++++++++++++++
 1 file changed, 86 insertions(+)
 create mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/point/PointServiceIntegrationTest.java

diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/point/PointServiceIntegrationTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/point/PointServiceIntegrationTest.java
new file mode 100644
index 000000000..544db751b
--- /dev/null
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/point/PointServiceIntegrationTest.java
@@ -0,0 +1,86 @@
+package com.loopers.domain.point;
+
+import com.loopers.domain.user.User;
+import com.loopers.domain.user.UserRepository;
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
+import com.loopers.utils.DatabaseCleanUp;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@SpringBootTest
+class PointServiceIntegrationTest {
+
+    @Autowired
+    private PointRepository pointRepository;
+
+    @Autowired
+    private UserRepository userRepository;
+
+    @Autowired
+    private PointService pointService;
+
+    @Autowired
+    private DatabaseCleanUp databaseCleanUp;
+
+    @AfterEach
+    void tearDown() {
+        databaseCleanUp.truncateAllTables();
+    }
+
+    @DisplayName("포인트 조회 통합 테스트")
+    @Nested
+    class PointUser {
+
+        @DisplayName("해당 ID의 회원이 존재할 경우, 보유 포인트가 반환된다.")
+        @Test
+        void returnPointInfo_whenValidIdIsProvided() {
+            String id = "yh45g";
+            String email = "yh45g@loopers.com";
+            String birth = "1994-12-05";
+            String gender = "MALE";
+
+            userRepository.save(new User(id, email, birth, gender));
+            pointRepository.save(new Point(id, 0L));
+
+            Point result = pointService.findPointByUserId(id);
+
+            assertThat(result.getUserId()).isEqualTo(id);
+            assertThat(result.getAmount()).isEqualTo(0L);
+        }
+
+        @DisplayName("회원이 존재 하지 않을 경우, null 이 반환된다.")
+        @Test
+        void returnNull_whenInvalidUserIdIsProvided() {
+            String id = "yh45g";
+
+            Point point = pointService.findPointByUserId(id);
+
+            assertThat(point).isNull();
+        }
+    }
+
+    @DisplayName("포인트 충전 통합 테스트")
+    @Nested
+    class Charge {
+
+        @DisplayName("존재하지 않는 유저 ID 로 충전을 시도한 경우, 실패한다.")
+        @Test
+        void throwsChargeAmountFailException_whenUserIDIsNotProvided() {
+            String id = "yh45g";
+
+            CoreException exception = assertThrows(CoreException.class, () -> {
+                pointService.chargePoint(id, 1000L);
+            });
+
+            assertThat(exception.getErrorType()).isEqualTo(ErrorType.NOT_FOUND);
+        }
+    }
+}

From 9c5e6ea939ed49903969a5743b4c79cfe55e5df8 Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Fri, 31 Oct 2025 05:07:49 +0900
Subject: [PATCH 19/40] =?UTF-8?q?test:=20=ED=8F=AC=EC=9D=B8=ED=8A=B8=20?=
 =?UTF-8?q?=EB=8F=84=EB=A9=94=EC=9D=B8=20E2E=ED=85=8C=EC=8A=A4=ED=8A=B8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../api/point/PointV1ControllerTest.java      | 140 ++++++++++++++++++
 1 file changed, 140 insertions(+)
 create mode 100644 apps/commerce-api/src/test/java/com/loopers/interfaces/api/point/PointV1ControllerTest.java

diff --git a/apps/commerce-api/src/test/java/com/loopers/interfaces/api/point/PointV1ControllerTest.java b/apps/commerce-api/src/test/java/com/loopers/interfaces/api/point/PointV1ControllerTest.java
new file mode 100644
index 000000000..8e8507f72
--- /dev/null
+++ b/apps/commerce-api/src/test/java/com/loopers/interfaces/api/point/PointV1ControllerTest.java
@@ -0,0 +1,140 @@
+package com.loopers.interfaces.api.point;
+
+import com.loopers.domain.point.Point;
+import com.loopers.domain.point.PointRepository;
+import com.loopers.domain.user.User;
+import com.loopers.domain.user.UserRepository;
+import com.loopers.interfaces.api.ApiResponse;
+import com.loopers.utils.DatabaseCleanUp;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.*;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+class PointV1ControllerTest {
+
+    private static final String GET_USER_POINT_ENDPOINT = "/api/v1/points";
+    private static final String POST_USER_POINT_ENDPOINT = "/api/v1/points/charge";
+
+    @Autowired
+    private PointRepository pointRepository;
+
+    @Autowired
+    private UserRepository userRepository;
+
+    @Autowired
+    private DatabaseCleanUp databaseCleanUp;
+
+    @Autowired
+    private TestRestTemplate testRestTemplate;
+
+    @AfterEach
+    void tearDown() {
+        databaseCleanUp.truncateAllTables();
+    }
+
+    @DisplayName("GET /api/v1/points")
+    @Nested
+    class UserPoint {
+
+        @DisplayName("포인트 조회에 성공할 경우, 보유 포인트를 응답으로 반환한다.")
+        @Test
+        void returnPoint_whenValidUserIdIsProvided() {
+            String id = "yh45g";
+            String email = "yh45g@loopers.com";
+            String birth = "1994-12-05";
+            String gender = "MALE";
+            Long amount = 1000L;
+
+            userRepository.save(new User(id, email, birth, gender));
+            pointRepository.save(new Point(id, amount));
+
+            HttpHeaders headers = new HttpHeaders();
+            headers.add("X-USER-ID", id);
+            ParameterizedTypeReference<ApiResponse<PointV1Dto.PointResponse>> responseType = new ParameterizedTypeReference<>() {};
+            ResponseEntity<ApiResponse<PointV1Dto.PointResponse>> response =
+                    testRestTemplate.exchange(GET_USER_POINT_ENDPOINT, HttpMethod.GET, new HttpEntity<>(null, headers), responseType);
+
+            assertAll(
+                    () -> assertTrue(response.getStatusCode().is2xxSuccessful()),
+                    () -> assertThat(response.getBody().data().userId()).isEqualTo(id),
+                    () -> assertThat(response.getBody().data().amount()).isEqualTo(1000L)
+            );
+        }
+
+        @DisplayName("해당 ID의 회원이 존재하지 않을 경우, null을 반환한다.")
+        @Test
+        void returnNull_whenUserIdExists() {
+            String id = "yh45g";
+
+            HttpHeaders headers = new HttpHeaders();
+            headers.add("X-USER-ID", id);
+            ParameterizedTypeReference<ApiResponse<PointV1Dto.PointResponse>> responseType = new ParameterizedTypeReference<>() {};
+            ResponseEntity<ApiResponse<PointV1Dto.PointResponse>> response =
+                    testRestTemplate.exchange(GET_USER_POINT_ENDPOINT, HttpMethod.GET, new HttpEntity<>(null, headers), responseType);
+
+            assertAll(
+                    () -> assertTrue(response.getStatusCode().is4xxClientError()),
+                    () -> assertThat(response.getBody().data()).isNull()
+            );
+        }
+    }
+
+    @DisplayName("POST /api/v1/points/charge")
+    @Nested
+    class Charge {
+
+        @DisplayName("존재하는 유저가 1000원을 충전할 경우, 충전된 보유 총량을 응답으로 반환한다.")
+        @Test
+        void returnsTotalPoint_whenChargeUserPoint() {
+            String id = "yh45g";
+            String email = "yh45g@loopers.com";
+            String birth = "1994-12-05";
+            String gender = "MALE";
+
+            userRepository.save(new User(id, email, birth, gender));
+            pointRepository.save(new Point(id, 0L));
+
+            PointV1Dto.ChargePointRequest request = new PointV1Dto.ChargePointRequest(id, 1000L);
+
+            HttpHeaders headers = new HttpHeaders();
+            headers.add("X-USER-ID", id);
+            ParameterizedTypeReference<ApiResponse<PointV1Dto.PointResponse>> responseType = new ParameterizedTypeReference<>() {};
+            ResponseEntity<ApiResponse<PointV1Dto.PointResponse>> response =
+                    testRestTemplate.exchange(POST_USER_POINT_ENDPOINT, HttpMethod.PATCH, new HttpEntity<>(request, headers), responseType);
+
+            assertAll(
+                    () -> assertTrue(response.getStatusCode().is2xxSuccessful()),
+                    () -> assertThat(response.getBody().data().userId()).isEqualTo(id),
+                    () -> assertThat(response.getBody().data().amount()).isEqualTo(1000L)
+            );
+        }
+
+        @DisplayName("존재하지 않는 유저로 요청할 경우, 404 Not Found 응답을 반환한다.")
+        @Test
+        void throwsException_whenInvalidUserIdIsProvided() {
+            String id = "yh45g";
+
+            HttpHeaders headers = new HttpHeaders();
+            headers.add("X-USER-ID", id);
+            ParameterizedTypeReference<ApiResponse<PointV1Dto.PointResponse>> responseType = new ParameterizedTypeReference<>() {};
+            ResponseEntity<ApiResponse<PointV1Dto.PointResponse>> response =
+                    testRestTemplate.exchange(POST_USER_POINT_ENDPOINT, HttpMethod.PATCH, new HttpEntity<>(null, headers), responseType);
+
+            assertAll(
+                    () -> assertTrue(response.getStatusCode().is4xxClientError()),
+                    () -> assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND)
+            );
+        }
+    }
+}

From 3774002312fc9fddcc417b938e19c46731f1591a Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Fri, 31 Oct 2025 05:08:22 +0900
Subject: [PATCH 20/40] =?UTF-8?q?refactor:=20=ED=9A=8C=EC=9B=90=20?=
 =?UTF-8?q?=EB=8F=84=EB=A9=94=EC=9D=B8=20=EB=A6=AC=ED=8C=A9=ED=86=A0?=
 =?UTF-8?q?=EB=A7=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../loopers/application/user/UserFacade.java  |  8 ++-
 .../com/loopers/domain/user/UserService.java  |  6 +-
 .../user/UserJpaRepository.java               |  1 +
 .../interfaces/api/user/UserV1ApiSpec.java    |  2 +-
 .../user/UserServiceIntegrationTest.java      | 40 +++++++++++-
 .../com/loopers/domain/user/UserTest.java     | 61 +++++++++++++++----
 .../api/user/UserV1ControllerTest.java        | 37 +++++------
 7 files changed, 114 insertions(+), 41 deletions(-)

diff --git a/apps/commerce-api/src/main/java/com/loopers/application/user/UserFacade.java b/apps/commerce-api/src/main/java/com/loopers/application/user/UserFacade.java
index 4df3eff79..f42bd5206 100644
--- a/apps/commerce-api/src/main/java/com/loopers/application/user/UserFacade.java
+++ b/apps/commerce-api/src/main/java/com/loopers/application/user/UserFacade.java
@@ -18,8 +18,10 @@ public UserInfo register(String userId, String email, String birth, String gende
     }
 
     public UserInfo getUser(String userId) {
-        return userService.findUserByUserId(userId)
-                .map(UserInfo::from)
-                .orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "회원 정보를 찾을 수 없습니다."));
+        User user = userService.findUserByUserId(userId);
+        if (user == null) {
+            throw new CoreException(ErrorType.NOT_FOUND, "사용자 존재하지 않습니다.");
+        }
+        return UserInfo.from(user);
     }
 }
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java
index 8dcf999e8..db386e1e8 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java
@@ -6,8 +6,6 @@
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.util.Optional;
-
 @Component
 @RequiredArgsConstructor
 public class UserService {
@@ -25,8 +23,8 @@ public User register(String userId, String email, String birth, String gender) {
     }
 
     @Transactional(readOnly = true)
-    public Optional<User> findUserByUserId(String userId){
-        return userRepository.findByUserId(userId);
+    public User findUserByUserId(String userId){
+        return userRepository.findByUserId(userId).orElse(null);
     }
 
 }
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserJpaRepository.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserJpaRepository.java
index 1a78b9a69..f80a5bc52 100644
--- a/apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserJpaRepository.java
+++ b/apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserJpaRepository.java
@@ -6,5 +6,6 @@
 import java.util.Optional;
 
 public interface UserJpaRepository extends JpaRepository<User, Long> {
+
     Optional<User> findByUserId(String userId);
 }
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1ApiSpec.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1ApiSpec.java
index dec948cdf..235e8e9fa 100644
--- a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1ApiSpec.java
+++ b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1ApiSpec.java
@@ -13,7 +13,7 @@ public interface UserV1ApiSpec {
             description = "회원 가입을 합니다."
     )
     ApiResponse<UserV1Dto.UserResponse> register(
-        @Schema(description = "회원가입")
+        @Schema(name = "회원 가입 요청", description = "회원가입")
         UserV1Dto.RegisterRequest request
     );
 
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java
index edcfca9a9..c342c8aa7 100644
--- a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java
@@ -6,6 +6,8 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertAll;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -27,7 +29,7 @@ void tearDown() {
         databaseCleanUp.truncateAllTables();
     }
 
-    @DisplayName("통합 테스트")
+    @DisplayName("회원 가입 통합 테스트")
     @Nested
     class UserRegister {
 
@@ -48,7 +50,7 @@ void save_whenUserRegister() {
 
         @DisplayName("이미 가입된 ID 로 회원가입 시도 시, 실패한다.")
         @Test
-        void register_whenUserIdAlreadyExists_thenFail() {
+        void throwsException_whenDuplicateUserId() {
             String userId = "yh45g";
             String email = "yh45g@loopers.com";
             String brith = "1994-12-05";
@@ -60,4 +62,38 @@ void register_whenUserIdAlreadyExists_thenFail() {
                     -> userService.register(userId, email, brith, gender));
         }
     }
+
+    @DisplayName("내 정보 조회 통합 테스트")
+    @Nested
+    class Get {
+
+        @DisplayName("해당 ID 의 회원이 존재할 경우, 회원 정보가 반환된다.")
+        @Test
+        void returnsUser_whenValidIdIsProvided() {
+            String userId = "yh45g";
+            String email = "yh45g@loopers.com";
+            String brith = "1994-12-05";
+            String gender = "Male";
+
+            userService.register(userId, email, brith, gender);
+
+            User user = userService.findUserByUserId(userId);
+
+            assertAll(
+                    () -> assertThat(user.getUserId()).isEqualTo(userId),
+                    () -> assertThat(user.getEmail()).isEqualTo(email),
+                    () -> assertThat(user.getBirth()).isEqualTo(brith),
+                    () -> assertThat(user.getGender()).isEqualTo(gender)
+            );
+        }
+
+        @DisplayName("해당 ID 의 회원이 존재하지 않을 경우, null 이 반환된다.")
+        @Test
+        void returnNull_whenInvalidUserIdIsProvided() {
+            String userId = "yh45g";
+            User user = userService.findUserByUserId(userId);
+
+            assertThat(user).isNull();
+        }
+    }
 }
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserTest.java
index 1d938accc..a8f8948ca 100644
--- a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserTest.java
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserTest.java
@@ -1,18 +1,53 @@
 package com.loopers.domain.user;
 
-import static org.junit.jupiter.api.Assertions.*;
-
-/**
- * packageName : com.loopers.domain.user
- * fileName     : UserTest
- * author      : byeonsungmun
- * date        : 25. 10. 28.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 25. 10. 28.     byeonsungmun       최초 생성
- */
+import com.loopers.support.error.CoreException;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
 class UserTest {
+    @DisplayName("User 단위 테스트")
+    @Nested
+    class Create {
+        @DisplayName("ID 가 영문 및 숫자 10자 이내 형식에 맞지 않으면, User 객체 생성에 실패한다.")
+        @Test
+        void throwsException_whenInvalidUserIdFormat() {
+            // given
+            String invalidUserId = "invalid_id_123"; // 10자 초과 + 특수문자 포함
+            String email = "valid@loopers.com";
+            String birth = "1994-12-05";
+            String gender = "MALE";
+
+            // when & then
+            assertThrows(CoreException.class, () -> new User(invalidUserId, email, birth, gender));
+        }
+
+        @DisplayName("이메일이 `xx@yy.zz` 형식에 맞지 않으면, User 객체 생성에 실패한다.")
+        @Test
+        void throwsException_whenInvalidEmailFormat() {
+            // given
+            String userId = "yh45g";
+            String invalidEmail = "invalid-email-format"; // '@' 없음
+            String birth = "1994-12-05";
+            String gender = "MALE";
+
+            // when & then
+            assertThrows(CoreException.class, () -> new User(userId, invalidEmail, birth, gender));
+        }
+
+        @DisplayName("생년월일이 `yyyy-MM-dd` 형식에 맞지 않으면, User 객체 생성에 실패한다.")
+        @Test
+        void throwsException_whenInvalidBirthFormat() {
+            // given
+            String userId = "yh45g";
+            String invalidEmail = "invalid-email-format"; // '@' 없음
+            String birth = "1994-12-05";
+            String gender = "MALE";
 
+            // when & then
+            assertThrows(CoreException.class, () -> new User(userId, invalidEmail, birth, gender));
+        }
+    }
 }
diff --git a/apps/commerce-api/src/test/java/com/loopers/interfaces/api/user/UserV1ControllerTest.java b/apps/commerce-api/src/test/java/com/loopers/interfaces/api/user/UserV1ControllerTest.java
index 5a297152b..b99da8b4e 100644
--- a/apps/commerce-api/src/test/java/com/loopers/interfaces/api/user/UserV1ControllerTest.java
+++ b/apps/commerce-api/src/test/java/com/loopers/interfaces/api/user/UserV1ControllerTest.java
@@ -12,7 +12,10 @@
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.test.web.client.TestRestTemplate;
 import org.springframework.core.ParameterizedTypeReference;
-import org.springframework.http.*;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
 
 import java.util.function.Function;
 
@@ -23,18 +26,17 @@
 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
 class UserV1ControllerTest {
 
-    private static final String REGISTER_ENDPOINT = "/api/v1/users/register";
-    private static final Function<String, String> GETUSER_ENDPOINT = id -> "/api/v1/users/" + id;
-    private final TestRestTemplate testRestTemplate;
-    private final UserJpaRepository userJpaRepository;
-    private final DatabaseCleanUp databaseCleanUp;
+    private static final String USER_REGISTER_ENDPOINT = "/api/v1/users/register";
+    private static final Function<String, String> GET_USER_ENDPOINT = id -> "/api/v1/users/" + id;
 
     @Autowired
-    public UserV1ControllerTest(TestRestTemplate testRestTemplate, UserJpaRepository userJpaRepository, DatabaseCleanUp databaseCleanUp) {
-        this.testRestTemplate = testRestTemplate;
-        this.userJpaRepository = userJpaRepository;
-        this.databaseCleanUp = databaseCleanUp;
-    }
+    private TestRestTemplate testRestTemplate;
+
+    @Autowired
+    private UserJpaRepository userJpaRepository;
+
+    @Autowired
+    private DatabaseCleanUp databaseCleanUp;
 
     @AfterEach
     void tearDown() {
@@ -57,7 +59,7 @@ void registerUser_whenSuccessResponseUser() {
             ParameterizedTypeReference<ApiResponse<UserV1Dto.UserResponse>> responseType = new ParameterizedTypeReference<>() {};
 
             ResponseEntity<ApiResponse<UserV1Dto.UserResponse>> response =
-                    testRestTemplate.exchange(REGISTER_ENDPOINT, HttpMethod.POST, new HttpEntity<>(request), responseType);
+                    testRestTemplate.exchange(USER_REGISTER_ENDPOINT, HttpMethod.POST, new HttpEntity<>(request), responseType);
 
             assertAll(
                     () -> assertTrue(response.getStatusCode().is2xxSuccessful()),
@@ -79,7 +81,7 @@ void throwsBadRequest_whenGenderIsNotProvided() {
 
             ParameterizedTypeReference<ApiResponse<UserV1Dto.UserResponse>> responseType = new ParameterizedTypeReference<>() {};
             ResponseEntity<ApiResponse<UserV1Dto.UserResponse>> response =
-                    testRestTemplate.exchange(REGISTER_ENDPOINT, HttpMethod.POST, new HttpEntity<>(request), responseType);
+                    testRestTemplate.exchange(USER_REGISTER_ENDPOINT, HttpMethod.POST, new HttpEntity<>(request), responseType);
 
             assertAll(
                     () -> assertTrue(response.getStatusCode().is4xxClientError()),
@@ -91,7 +93,7 @@ void throwsBadRequest_whenGenderIsNotProvided() {
     @DisplayName("GET /api/v1/users/{userId}")
     @Nested
     class GetUserById {
-        @DisplayName("해당 ID의 회원이 존재할 경우, 회원 정보가 반환된다.")
+        @DisplayName("내 정보 조회에 성공할 경우, 해당하는 유저 정보를 반환한다.")
         @Test
         void getUserById_whenSuccessResponseUser() {
             String userId = "yh45g";
@@ -101,7 +103,7 @@ void getUserById_whenSuccessResponseUser() {
 
             userJpaRepository.save(new User(userId, email, birth, gender));
 
-            String requestUrl = GETUSER_ENDPOINT.apply(userId);
+            String requestUrl = GET_USER_ENDPOINT.apply(userId);
             ParameterizedTypeReference<ApiResponse<UserV1Dto.UserResponse>> responseType = new ParameterizedTypeReference<>() {};
             ResponseEntity<ApiResponse<UserV1Dto.UserResponse>> response =
                     testRestTemplate.exchange(requestUrl, HttpMethod.GET, new HttpEntity<>(null), responseType);
@@ -115,11 +117,11 @@ void getUserById_whenSuccessResponseUser() {
             );
         }
 
-        @DisplayName("해당 ID의 회원이 존재하지 않을 경우, null 이 반환된다.")
+        @DisplayName("존재하지 않는 ID 로 조회할 경우, 404 Not Found 응답을 반환한다.")
         @Test
         void throwsException_whenInvalidUserIdIsProvided() {
             String userId = "notUserId";
-            String requestUrl = GETUSER_ENDPOINT.apply(userId);
+            String requestUrl = GET_USER_ENDPOINT.apply(userId);
             ParameterizedTypeReference<ApiResponse<UserV1Dto.UserResponse>> responseType = new ParameterizedTypeReference<>() {};
             ResponseEntity<ApiResponse<UserV1Dto.UserResponse>> response =
                     testRestTemplate.exchange(requestUrl, HttpMethod.GET, new HttpEntity<>(null), responseType);
@@ -130,5 +132,4 @@ void throwsException_whenInvalidUserIdIsProvided() {
             );
         }
     }
-
 }

From 8e5643aa0e3276c4028fb05abe30fa9108966f84 Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Fri, 31 Oct 2025 05:10:30 +0900
Subject: [PATCH 21/40] =?UTF-8?q?chore:=20=ED=9A=8C=EC=9B=90=20=EB=8F=84?=
 =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/java/com/loopers/domain/point/Point.java         | 4 ++--
 .../com/loopers/domain/point/PointServiceIntegrationTest.java | 4 +---
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java b/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java
index bef72fb00..02e1f9f7f 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java
@@ -30,12 +30,12 @@ String requireValidUserId(String userId) {
         return userId;
     }
 
-    public Point charge(Long chargeAmount) {
+    public void charge(Long chargeAmount) {
         if (chargeAmount == null || chargeAmount <= 0) {
             throw new CoreException(ErrorType.BAD_REQUEST, "0원 이하로 포인트를 충전 할수 없습니다.");
         }
         this.amount += chargeAmount;
-        return new Point(this.userId, this.amount);
+        new Point(this.userId, this.amount);
     }
 
 }
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/point/PointServiceIntegrationTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/point/PointServiceIntegrationTest.java
index 544db751b..2ba880463 100644
--- a/apps/commerce-api/src/test/java/com/loopers/domain/point/PointServiceIntegrationTest.java
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/point/PointServiceIntegrationTest.java
@@ -76,9 +76,7 @@ class Charge {
         void throwsChargeAmountFailException_whenUserIDIsNotProvided() {
             String id = "yh45g";
 
-            CoreException exception = assertThrows(CoreException.class, () -> {
-                pointService.chargePoint(id, 1000L);
-            });
+            CoreException exception = assertThrows(CoreException.class, () -> pointService.chargePoint(id, 1000L));
 
             assertThat(exception.getErrorType()).isEqualTo(ErrorType.NOT_FOUND);
         }

From ef3eebdce67a2a6566c5636de732acb9778095fd Mon Sep 17 00:00:00 2001
From: bookers-web <net75jin@bookers.life>
Date: Fri, 31 Oct 2025 15:26:04 +0900
Subject: [PATCH 22/40] =?UTF-8?q?style:=20=EC=BD=94=EB=93=9C=20=EC=9E=90?=
 =?UTF-8?q?=EB=8F=99=EC=A0=95=EB=A0=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/java/com/loopers/domain/point/Point.java     | 1 -
 .../main/java/com/loopers/domain/point/PointService.java  | 6 +-----
 .../main/java/com/loopers/domain/user/UserService.java    | 2 +-
 .../com/loopers/interfaces/api/point/PointV1ApiSpec.java  | 1 +
 .../java/com/loopers/interfaces/api/point/PointV1Dto.java | 5 +++--
 .../com/loopers/interfaces/api/user/UserV1ApiSpec.java    | 8 ++++----
 .../java/com/loopers/interfaces/api/user/UserV1Dto.java   | 3 ++-
 7 files changed, 12 insertions(+), 14 deletions(-)

diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java b/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java
index 02e1f9f7f..b8f453f14 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java
@@ -37,5 +37,4 @@ public void charge(Long chargeAmount) {
         this.amount += chargeAmount;
         new Point(this.userId, this.amount);
     }
-
 }
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java b/apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java
index 2ecc7b456..dfc0788c6 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java
@@ -12,7 +12,6 @@ public class PointService {
 
     private final PointRepository pointRepository;
 
-
     @Transactional(readOnly = true)
     public Point findPointByUserId(String userId) {
         return pointRepository.findByUserId(userId).orElse(null);
@@ -20,11 +19,8 @@ public Point findPointByUserId(String userId) {
 
     @Transactional
     public Point chargePoint(String userId, Long chargeAmount) {
-        Point point = pointRepository.findByUserId(userId)
-                .orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "포인트를 충전할수 없는 사용자입니다."));
+        Point point = pointRepository.findByUserId(userId).orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "포인트를 충전할수 없는 사용자입니다."));
         point.charge(chargeAmount);
         return pointRepository.save(point);
     }
-
-
 }
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java
index db386e1e8..da2878300 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java
@@ -23,7 +23,7 @@ public User register(String userId, String email, String birth, String gender) {
     }
 
     @Transactional(readOnly = true)
-    public User findUserByUserId(String userId){
+    public User findUserByUserId(String userId) {
         return userRepository.findByUserId(userId).orElse(null);
     }
 
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1ApiSpec.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1ApiSpec.java
index b954c1a4e..faa21f303 100644
--- a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1ApiSpec.java
+++ b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1ApiSpec.java
@@ -4,6 +4,7 @@
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.media.Schema;
 import io.swagger.v3.oas.annotations.tags.Tag;
+
 @Tag(name = "Point V1 API", description = "Point API 입니다.")
 public interface PointV1ApiSpec {
 
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1Dto.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1Dto.java
index 406e84cc5..b0b3d050e 100644
--- a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1Dto.java
+++ b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1Dto.java
@@ -4,9 +4,10 @@
 
 public class PointV1Dto {
 
-    public record ChargePointRequest(String userId, Long chargeAmount) {}
+    public record ChargePointRequest(String userId, Long chargeAmount) {
+    }
 
-    public record PointResponse(String userId, Long amount){
+    public record PointResponse(String userId, Long amount) {
         public static PointResponse from(PointInfo info) {
             return new PointResponse(
                     info.userId(),
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1ApiSpec.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1ApiSpec.java
index 235e8e9fa..1bed68e62 100644
--- a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1ApiSpec.java
+++ b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1ApiSpec.java
@@ -13,8 +13,8 @@ public interface UserV1ApiSpec {
             description = "회원 가입을 합니다."
     )
     ApiResponse<UserV1Dto.UserResponse> register(
-        @Schema(name = "회원 가입 요청", description = "회원가입")
-        UserV1Dto.RegisterRequest request
+            @Schema(name = "회원 가입 요청", description = "회원가입")
+            UserV1Dto.RegisterRequest request
     );
 
     @Operation(
@@ -22,7 +22,7 @@ ApiResponse<UserV1Dto.UserResponse> register(
             description = "해당 회원을 조회합니다."
     )
     ApiResponse<UserV1Dto.UserResponse> getUser(
-        @Schema(name = "회원 ID", description = "조회할 회원 ID")
-        String userId
+            @Schema(name = "회원 ID", description = "조회할 회원 ID")
+            String userId
     );
 }
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Dto.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Dto.java
index 16aab05e2..263214848 100644
--- a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Dto.java
+++ b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Dto.java
@@ -8,7 +8,8 @@ public record RegisterRequest(
             String mail,
             String birth,
             String gender
-    ){}
+    ) {
+    }
 
     public record UserResponse(String userId, String email, String birth, String gender) {
         public static UserResponse from(UserInfo info) {

From d7386544e6f8468272cd5be72e14007ee2eaa32e Mon Sep 17 00:00:00 2001
From: bookers-web <net75jin@bookers.life>
Date: Fri, 31 Oct 2025 15:46:55 +0900
Subject: [PATCH 23/40] =?UTF-8?q?remove:=20sample=20code=20=EC=82=AD?=
 =?UTF-8?q?=EC=A0=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../application/example/ExampleFacade.java    |  17 ---
 .../application/example/ExampleInfo.java      |  13 --
 .../loopers/domain/example/ExampleModel.java  |  44 -------
 .../domain/example/ExampleRepository.java     |   7 --
 .../domain/example/ExampleService.java        |  20 ---
 .../example/ExampleJpaRepository.java         |   6 -
 .../example/ExampleRepositoryImpl.java        |  19 ---
 .../api/example/ExampleV1ApiSpec.java         |  19 ---
 .../api/example/ExampleV1Controller.java      |  28 -----
 .../interfaces/api/example/ExampleV1Dto.java  |  15 ---
 .../domain/example/ExampleModelTest.java      |  65 ----------
 .../ExampleServiceIntegrationTest.java        |  72 -----------
 .../api/example/ExampleV1ApiE2ETest.java      | 114 ------------------
 13 files changed, 439 deletions(-)
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/application/example/ExampleFacade.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/application/example/ExampleInfo.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleModel.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleRepository.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleService.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/example/ExampleJpaRepository.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/example/ExampleRepositoryImpl.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1ApiSpec.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1Controller.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1Dto.java
 delete mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/example/ExampleModelTest.java
 delete mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/example/ExampleServiceIntegrationTest.java
 delete mode 100644 apps/commerce-api/src/test/java/com/loopers/interfaces/api/example/ExampleV1ApiE2ETest.java

diff --git a/apps/commerce-api/src/main/java/com/loopers/application/example/ExampleFacade.java b/apps/commerce-api/src/main/java/com/loopers/application/example/ExampleFacade.java
deleted file mode 100644
index 552a9ad62..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/application/example/ExampleFacade.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.loopers.application.example;
-
-import com.loopers.domain.example.ExampleModel;
-import com.loopers.domain.example.ExampleService;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Component;
-
-@RequiredArgsConstructor
-@Component
-public class ExampleFacade {
-    private final ExampleService exampleService;
-
-    public ExampleInfo getExample(Long id) {
-        ExampleModel example = exampleService.getExample(id);
-        return ExampleInfo.from(example);
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/example/ExampleInfo.java b/apps/commerce-api/src/main/java/com/loopers/application/example/ExampleInfo.java
deleted file mode 100644
index 877aba96c..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/application/example/ExampleInfo.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.loopers.application.example;
-
-import com.loopers.domain.example.ExampleModel;
-
-public record ExampleInfo(Long id, String name, String description) {
-    public static ExampleInfo from(ExampleModel model) {
-        return new ExampleInfo(
-            model.getId(),
-            model.getName(),
-            model.getDescription()
-        );
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleModel.java b/apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleModel.java
deleted file mode 100644
index c588c4a8a..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleModel.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.loopers.domain.example;
-
-import com.loopers.domain.BaseEntity;
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-import jakarta.persistence.Entity;
-import jakarta.persistence.Table;
-
-@Entity
-@Table(name = "example")
-public class ExampleModel extends BaseEntity {
-
-    private String name;
-    private String description;
-
-    protected ExampleModel() {}
-
-    public ExampleModel(String name, String description) {
-        if (name == null || name.isBlank()) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "이름은 비어있을 수 없습니다.");
-        }
-        if (description == null || description.isBlank()) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "설명은 비어있을 수 없습니다.");
-        }
-
-        this.name = name;
-        this.description = description;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public String getDescription() {
-        return description;
-    }
-
-    public void update(String newDescription) {
-        if (newDescription == null || newDescription.isBlank()) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "설명은 비어있을 수 없습니다.");
-        }
-        this.description = newDescription;
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleRepository.java b/apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleRepository.java
deleted file mode 100644
index 3625e5662..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleRepository.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.loopers.domain.example;
-
-import java.util.Optional;
-
-public interface ExampleRepository {
-    Optional<ExampleModel> find(Long id);
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleService.java b/apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleService.java
deleted file mode 100644
index c0e8431e8..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleService.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.loopers.domain.example;
-
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Component;
-import org.springframework.transaction.annotation.Transactional;
-
-@RequiredArgsConstructor
-@Component
-public class ExampleService {
-
-    private final ExampleRepository exampleRepository;
-
-    @Transactional(readOnly = true)
-    public ExampleModel getExample(Long id) {
-        return exampleRepository.find(id)
-            .orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "[id = " + id + "] 예시를 찾을 수 없습니다."));
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/example/ExampleJpaRepository.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/example/ExampleJpaRepository.java
deleted file mode 100644
index ce6d3ead0..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/infrastructure/example/ExampleJpaRepository.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package com.loopers.infrastructure.example;
-
-import com.loopers.domain.example.ExampleModel;
-import org.springframework.data.jpa.repository.JpaRepository;
-
-public interface ExampleJpaRepository extends JpaRepository<ExampleModel, Long> {}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/example/ExampleRepositoryImpl.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/example/ExampleRepositoryImpl.java
deleted file mode 100644
index 37f2272f0..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/infrastructure/example/ExampleRepositoryImpl.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.loopers.infrastructure.example;
-
-import com.loopers.domain.example.ExampleModel;
-import com.loopers.domain.example.ExampleRepository;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Component;
-
-import java.util.Optional;
-
-@RequiredArgsConstructor
-@Component
-public class ExampleRepositoryImpl implements ExampleRepository {
-    private final ExampleJpaRepository exampleJpaRepository;
-
-    @Override
-    public Optional<ExampleModel> find(Long id) {
-        return exampleJpaRepository.findById(id);
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1ApiSpec.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1ApiSpec.java
deleted file mode 100644
index 219e3101e..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1ApiSpec.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.loopers.interfaces.api.example;
-
-import com.loopers.interfaces.api.ApiResponse;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.media.Schema;
-import io.swagger.v3.oas.annotations.tags.Tag;
-
-@Tag(name = "Example V1 API", description = "Loopers 예시 API 입니다.")
-public interface ExampleV1ApiSpec {
-
-    @Operation(
-        summary = "예시 조회",
-        description = "ID로 예시를 조회합니다."
-    )
-    ApiResponse<ExampleV1Dto.ExampleResponse> getExample(
-        @Schema(name = "예시 ID", description = "조회할 예시의 ID")
-        Long exampleId
-    );
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1Controller.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1Controller.java
deleted file mode 100644
index 917376016..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1Controller.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.loopers.interfaces.api.example;
-
-import com.loopers.application.example.ExampleFacade;
-import com.loopers.application.example.ExampleInfo;
-import com.loopers.interfaces.api.ApiResponse;
-import lombok.RequiredArgsConstructor;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-@RequiredArgsConstructor
-@RestController
-@RequestMapping("/api/v1/examples")
-public class ExampleV1Controller implements ExampleV1ApiSpec {
-
-    private final ExampleFacade exampleFacade;
-
-    @GetMapping("/{exampleId}")
-    @Override
-    public ApiResponse<ExampleV1Dto.ExampleResponse> getExample(
-        @PathVariable(value = "exampleId") Long exampleId
-    ) {
-        ExampleInfo info = exampleFacade.getExample(exampleId);
-        ExampleV1Dto.ExampleResponse response = ExampleV1Dto.ExampleResponse.from(info);
-        return ApiResponse.success(response);
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1Dto.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1Dto.java
deleted file mode 100644
index 4ecf0eea5..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1Dto.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.loopers.interfaces.api.example;
-
-import com.loopers.application.example.ExampleInfo;
-
-public class ExampleV1Dto {
-    public record ExampleResponse(Long id, String name, String description) {
-        public static ExampleResponse from(ExampleInfo info) {
-            return new ExampleResponse(
-                info.id(),
-                info.name(),
-                info.description()
-            );
-        }
-    }
-}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/example/ExampleModelTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/example/ExampleModelTest.java
deleted file mode 100644
index 44ca7576e..000000000
--- a/apps/commerce-api/src/test/java/com/loopers/domain/example/ExampleModelTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.loopers.domain.example;
-
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertAll;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-class ExampleModelTest {
-    @DisplayName("예시 모델을 생성할 때, ")
-    @Nested
-    class Create {
-        @DisplayName("제목과 설명이 모두 주어지면, 정상적으로 생성된다.")
-        @Test
-        void createsExampleModel_whenNameAndDescriptionAreProvided() {
-            // arrange
-            String name = "제목";
-            String description = "설명";
-
-            // act
-            ExampleModel exampleModel = new ExampleModel(name, description);
-
-            // assert
-            assertAll(
-                () -> assertThat(exampleModel.getId()).isNotNull(),
-                () -> assertThat(exampleModel.getName()).isEqualTo(name),
-                () -> assertThat(exampleModel.getDescription()).isEqualTo(description)
-            );
-        }
-
-        @DisplayName("제목이 빈칸으로만 이루어져 있으면, BAD_REQUEST 예외가 발생한다.")
-        @Test
-        void throwsBadRequestException_whenTitleIsBlank() {
-            // arrange
-            String name = "   ";
-
-            // act
-            CoreException result = assertThrows(CoreException.class, () -> {
-                new ExampleModel(name, "설명");
-            });
-
-            // assert
-            assertThat(result.getErrorType()).isEqualTo(ErrorType.BAD_REQUEST);
-        }
-
-        @DisplayName("설명이 비어있으면, BAD_REQUEST 예외가 발생한다.")
-        @Test
-        void throwsBadRequestException_whenDescriptionIsEmpty() {
-            // arrange
-            String description = "";
-
-            // act
-            CoreException result = assertThrows(CoreException.class, () -> {
-                new ExampleModel("제목", description);
-            });
-
-            // assert
-            assertThat(result.getErrorType()).isEqualTo(ErrorType.BAD_REQUEST);
-        }
-    }
-}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/example/ExampleServiceIntegrationTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/example/ExampleServiceIntegrationTest.java
deleted file mode 100644
index bbd5fdbe1..000000000
--- a/apps/commerce-api/src/test/java/com/loopers/domain/example/ExampleServiceIntegrationTest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package com.loopers.domain.example;
-
-import com.loopers.infrastructure.example.ExampleJpaRepository;
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-import com.loopers.utils.DatabaseCleanUp;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertAll;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-@SpringBootTest
-class ExampleServiceIntegrationTest {
-    @Autowired
-    private ExampleService exampleService;
-
-    @Autowired
-    private ExampleJpaRepository exampleJpaRepository;
-
-    @Autowired
-    private DatabaseCleanUp databaseCleanUp;
-
-    @AfterEach
-    void tearDown() {
-        databaseCleanUp.truncateAllTables();
-    }
-
-    @DisplayName("예시를 조회할 때,")
-    @Nested
-    class Get {
-        @DisplayName("존재하는 예시 ID를 주면, 해당 예시 정보를 반환한다.")
-        @Test
-        void returnsExampleInfo_whenValidIdIsProvided() {
-            // arrange
-            ExampleModel exampleModel = exampleJpaRepository.save(
-                new ExampleModel("예시 제목", "예시 설명")
-            );
-
-            // act
-            ExampleModel result = exampleService.getExample(exampleModel.getId());
-
-            // assert
-            assertAll(
-                () -> assertThat(result).isNotNull(),
-                () -> assertThat(result.getId()).isEqualTo(exampleModel.getId()),
-                () -> assertThat(result.getName()).isEqualTo(exampleModel.getName()),
-                () -> assertThat(result.getDescription()).isEqualTo(exampleModel.getDescription())
-            );
-        }
-
-        @DisplayName("존재하지 않는 예시 ID를 주면, NOT_FOUND 예외가 발생한다.")
-        @Test
-        void throwsException_whenInvalidIdIsProvided() {
-            // arrange
-            Long invalidId = 999L; // Assuming this ID does not exist
-
-            // act
-            CoreException exception = assertThrows(CoreException.class, () -> {
-                exampleService.getExample(invalidId);
-            });
-
-            // assert
-            assertThat(exception.getErrorType()).isEqualTo(ErrorType.NOT_FOUND);
-        }
-    }
-}
diff --git a/apps/commerce-api/src/test/java/com/loopers/interfaces/api/example/ExampleV1ApiE2ETest.java b/apps/commerce-api/src/test/java/com/loopers/interfaces/api/example/ExampleV1ApiE2ETest.java
deleted file mode 100644
index 70f256149..000000000
--- a/apps/commerce-api/src/test/java/com/loopers/interfaces/api/example/ExampleV1ApiE2ETest.java
+++ /dev/null
@@ -1,114 +0,0 @@
-package com.loopers.interfaces.api.example;
-
-import com.loopers.domain.example.ExampleModel;
-import com.loopers.infrastructure.example.ExampleJpaRepository;
-import com.loopers.interfaces.api.ApiResponse;
-import com.loopers.utils.DatabaseCleanUp;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.web.client.TestRestTemplate;
-import org.springframework.core.ParameterizedTypeReference;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-
-import java.util.function.Function;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertAll;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
-class ExampleV1ApiE2ETest {
-
-    private static final Function<Long, String> ENDPOINT_GET = id -> "/api/v1/examples/" + id;
-
-    private final TestRestTemplate testRestTemplate;
-    private final ExampleJpaRepository exampleJpaRepository;
-    private final DatabaseCleanUp databaseCleanUp;
-
-    @Autowired
-    public ExampleV1ApiE2ETest(
-        TestRestTemplate testRestTemplate,
-        ExampleJpaRepository exampleJpaRepository,
-        DatabaseCleanUp databaseCleanUp
-    ) {
-        this.testRestTemplate = testRestTemplate;
-        this.exampleJpaRepository = exampleJpaRepository;
-        this.databaseCleanUp = databaseCleanUp;
-    }
-
-    @AfterEach
-    void tearDown() {
-        databaseCleanUp.truncateAllTables();
-    }
-
-    @DisplayName("GET /api/v1/examples/{id}")
-    @Nested
-    class Get {
-        @DisplayName("존재하는 예시 ID를 주면, 해당 예시 정보를 반환한다.")
-        @Test
-        void returnsExampleInfo_whenValidIdIsProvided() {
-            // arrange
-            ExampleModel exampleModel = exampleJpaRepository.save(
-                new ExampleModel("예시 제목", "예시 설명")
-            );
-            String requestUrl = ENDPOINT_GET.apply(exampleModel.getId());
-
-            // act
-            ParameterizedTypeReference<ApiResponse<ExampleV1Dto.ExampleResponse>> responseType = new ParameterizedTypeReference<>() {};
-            ResponseEntity<ApiResponse<ExampleV1Dto.ExampleResponse>> response =
-                testRestTemplate.exchange(requestUrl, HttpMethod.GET, new HttpEntity<>(null), responseType);
-
-            // assert
-            assertAll(
-                () -> assertTrue(response.getStatusCode().is2xxSuccessful()),
-                () -> assertThat(response.getBody().data().id()).isEqualTo(exampleModel.getId()),
-                () -> assertThat(response.getBody().data().name()).isEqualTo(exampleModel.getName()),
-                () -> assertThat(response.getBody().data().description()).isEqualTo(exampleModel.getDescription())
-            );
-        }
-
-        @DisplayName("숫자가 아닌 ID 로 요청하면, 400 BAD_REQUEST 응답을 받는다.")
-        @Test
-        void throwsBadRequest_whenIdIsNotProvided() {
-            // arrange
-            String requestUrl = "/api/v1/examples/나나";
-
-            // act
-            ParameterizedTypeReference<ApiResponse<ExampleV1Dto.ExampleResponse>> responseType = new ParameterizedTypeReference<>() {};
-            ResponseEntity<ApiResponse<ExampleV1Dto.ExampleResponse>> response =
-                testRestTemplate.exchange(requestUrl, HttpMethod.GET, new HttpEntity<>(null), responseType);
-
-            // assert
-            assertAll(
-                () -> assertTrue(response.getStatusCode().is4xxClientError()),
-                () -> assertThat(response.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST)
-            );
-        }
-
-        @DisplayName("존재하지 않는 예시 ID를 주면, 404 NOT_FOUND 응답을 받는다.")
-        @Test
-        void throwsException_whenInvalidIdIsProvided() {
-            // arrange
-            Long invalidId = -1L;
-            String requestUrl = ENDPOINT_GET.apply(invalidId);
-
-            // act
-            ParameterizedTypeReference<ApiResponse<ExampleV1Dto.ExampleResponse>> responseType = new ParameterizedTypeReference<>() {};
-            ResponseEntity<ApiResponse<ExampleV1Dto.ExampleResponse>> response =
-                testRestTemplate.exchange(requestUrl, HttpMethod.GET, new HttpEntity<>(null), responseType);
-
-            // assert
-            assertAll(
-                () -> assertTrue(response.getStatusCode().is4xxClientError()),
-                () -> assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND)
-            );
-        }
-    }
-}

From b06e034f2c369f6c3c5c7010e18449a2b59cc950 Mon Sep 17 00:00:00 2001
From: bookers-web <net75jin@bookers.life>
Date: Fri, 31 Oct 2025 15:47:43 +0900
Subject: [PATCH 24/40] =?UTF-8?q?chore:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?=
 =?UTF-8?q?=EC=BD=94=EB=93=9C=20given=20when=20then=20=EC=9E=91=EC=84=B1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../point/PointServiceIntegrationTest.java       |  9 +++++++++
 .../java/com/loopers/domain/point/PointTest.java |  3 +++
 .../domain/user/UserServiceIntegrationTest.java  | 15 ++++++++++++++-
 .../api/point/PointV1ControllerTest.java         | 16 ++++++++++++++++
 .../api/user/UserV1ControllerTest.java           | 15 ++++++++++++++-
 5 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/point/PointServiceIntegrationTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/point/PointServiceIntegrationTest.java
index 2ba880463..882bca673 100644
--- a/apps/commerce-api/src/test/java/com/loopers/domain/point/PointServiceIntegrationTest.java
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/point/PointServiceIntegrationTest.java
@@ -42,6 +42,7 @@ class PointUser {
         @DisplayName("해당 ID의 회원이 존재할 경우, 보유 포인트가 반환된다.")
         @Test
         void returnPointInfo_whenValidIdIsProvided() {
+            //given
             String id = "yh45g";
             String email = "yh45g@loopers.com";
             String birth = "1994-12-05";
@@ -50,8 +51,10 @@ void returnPointInfo_whenValidIdIsProvided() {
             userRepository.save(new User(id, email, birth, gender));
             pointRepository.save(new Point(id, 0L));
 
+            //when
             Point result = pointService.findPointByUserId(id);
 
+            //then
             assertThat(result.getUserId()).isEqualTo(id);
             assertThat(result.getAmount()).isEqualTo(0L);
         }
@@ -59,10 +62,13 @@ void returnPointInfo_whenValidIdIsProvided() {
         @DisplayName("회원이 존재 하지 않을 경우, null 이 반환된다.")
         @Test
         void returnNull_whenInvalidUserIdIsProvided() {
+            //given
             String id = "yh45g";
 
+            //when
             Point point = pointService.findPointByUserId(id);
 
+            //then
             assertThat(point).isNull();
         }
     }
@@ -74,10 +80,13 @@ class Charge {
         @DisplayName("존재하지 않는 유저 ID 로 충전을 시도한 경우, 실패한다.")
         @Test
         void throwsChargeAmountFailException_whenUserIDIsNotProvided() {
+            //given
             String id = "yh45g";
 
+            //when
             CoreException exception = assertThrows(CoreException.class, () -> pointService.chargePoint(id, 1000L));
 
+            //then
             assertThat(exception.getErrorType()).isEqualTo(ErrorType.NOT_FOUND);
         }
     }
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/point/PointTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/point/PointTest.java
index bcc911321..81bedab7d 100644
--- a/apps/commerce-api/src/test/java/com/loopers/domain/point/PointTest.java
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/point/PointTest.java
@@ -14,7 +14,10 @@ class Charge {
         @DisplayName("0 이하의 정수로 포인트를 충전 시 실패한다.")
         @Test
         void throwsChargeAmountFailException_whenZeroAmountOrNegative() {
+            //given
             Point point = new Point("yh45g", 0L);
+
+            //when&then
             assertThrows(CoreException.class, () ->
                     point.charge(0L));
         }
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java
index c342c8aa7..71091883f 100644
--- a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java
@@ -36,6 +36,7 @@ class UserRegister {
         @DisplayName("회원 가입시 User 저장이 수행된다.")
         @Test
         void save_whenUserRegister() {
+            //given
             String userId = "yh45g";
             String email = "yh45g@loopers.com";
             String brith = "1994-12-05";
@@ -43,21 +44,27 @@ void save_whenUserRegister() {
 
             UserRepository userRepositorySpy = spy(userRepository);
             UserService userServiceSpy = new UserService(userRepositorySpy);
+
+            //when
             userServiceSpy.register(userId, email, brith, gender);
 
+            //then
             verify(userRepositorySpy).save(any(User.class));
         }
 
         @DisplayName("이미 가입된 ID 로 회원가입 시도 시, 실패한다.")
         @Test
         void throwsException_whenDuplicateUserId() {
+            //given
             String userId = "yh45g";
             String email = "yh45g@loopers.com";
             String brith = "1994-12-05";
             String gender = "Male";
 
+            //when
             userService.register(userId, email, brith, gender);
 
+            //then
             Assertions.assertThrows(CoreException.class, ()
                     -> userService.register(userId, email, brith, gender));
         }
@@ -70,15 +77,17 @@ class Get {
         @DisplayName("해당 ID 의 회원이 존재할 경우, 회원 정보가 반환된다.")
         @Test
         void returnsUser_whenValidIdIsProvided() {
+            //given
             String userId = "yh45g";
             String email = "yh45g@loopers.com";
             String brith = "1994-12-05";
             String gender = "Male";
 
+            //when
             userService.register(userId, email, brith, gender);
-
             User user = userService.findUserByUserId(userId);
 
+            //then
             assertAll(
                     () -> assertThat(user.getUserId()).isEqualTo(userId),
                     () -> assertThat(user.getEmail()).isEqualTo(email),
@@ -90,9 +99,13 @@ void returnsUser_whenValidIdIsProvided() {
         @DisplayName("해당 ID 의 회원이 존재하지 않을 경우, null 이 반환된다.")
         @Test
         void returnNull_whenInvalidUserIdIsProvided() {
+            //given
             String userId = "yh45g";
+
+            //when
             User user = userService.findUserByUserId(userId);
 
+            //then
             assertThat(user).isNull();
         }
     }
diff --git a/apps/commerce-api/src/test/java/com/loopers/interfaces/api/point/PointV1ControllerTest.java b/apps/commerce-api/src/test/java/com/loopers/interfaces/api/point/PointV1ControllerTest.java
index 8e8507f72..b725fd807 100644
--- a/apps/commerce-api/src/test/java/com/loopers/interfaces/api/point/PointV1ControllerTest.java
+++ b/apps/commerce-api/src/test/java/com/loopers/interfaces/api/point/PointV1ControllerTest.java
@@ -50,6 +50,7 @@ class UserPoint {
         @DisplayName("포인트 조회에 성공할 경우, 보유 포인트를 응답으로 반환한다.")
         @Test
         void returnPoint_whenValidUserIdIsProvided() {
+            //given
             String id = "yh45g";
             String email = "yh45g@loopers.com";
             String birth = "1994-12-05";
@@ -61,10 +62,13 @@ void returnPoint_whenValidUserIdIsProvided() {
 
             HttpHeaders headers = new HttpHeaders();
             headers.add("X-USER-ID", id);
+
+            //when
             ParameterizedTypeReference<ApiResponse<PointV1Dto.PointResponse>> responseType = new ParameterizedTypeReference<>() {};
             ResponseEntity<ApiResponse<PointV1Dto.PointResponse>> response =
                     testRestTemplate.exchange(GET_USER_POINT_ENDPOINT, HttpMethod.GET, new HttpEntity<>(null, headers), responseType);
 
+            //then
             assertAll(
                     () -> assertTrue(response.getStatusCode().is2xxSuccessful()),
                     () -> assertThat(response.getBody().data().userId()).isEqualTo(id),
@@ -75,14 +79,18 @@ void returnPoint_whenValidUserIdIsProvided() {
         @DisplayName("해당 ID의 회원이 존재하지 않을 경우, null을 반환한다.")
         @Test
         void returnNull_whenUserIdExists() {
+            //given
             String id = "yh45g";
 
             HttpHeaders headers = new HttpHeaders();
             headers.add("X-USER-ID", id);
+
+            //when
             ParameterizedTypeReference<ApiResponse<PointV1Dto.PointResponse>> responseType = new ParameterizedTypeReference<>() {};
             ResponseEntity<ApiResponse<PointV1Dto.PointResponse>> response =
                     testRestTemplate.exchange(GET_USER_POINT_ENDPOINT, HttpMethod.GET, new HttpEntity<>(null, headers), responseType);
 
+            //then
             assertAll(
                     () -> assertTrue(response.getStatusCode().is4xxClientError()),
                     () -> assertThat(response.getBody().data()).isNull()
@@ -97,6 +105,7 @@ class Charge {
         @DisplayName("존재하는 유저가 1000원을 충전할 경우, 충전된 보유 총량을 응답으로 반환한다.")
         @Test
         void returnsTotalPoint_whenChargeUserPoint() {
+            //given
             String id = "yh45g";
             String email = "yh45g@loopers.com";
             String birth = "1994-12-05";
@@ -109,10 +118,13 @@ void returnsTotalPoint_whenChargeUserPoint() {
 
             HttpHeaders headers = new HttpHeaders();
             headers.add("X-USER-ID", id);
+
+            //when
             ParameterizedTypeReference<ApiResponse<PointV1Dto.PointResponse>> responseType = new ParameterizedTypeReference<>() {};
             ResponseEntity<ApiResponse<PointV1Dto.PointResponse>> response =
                     testRestTemplate.exchange(POST_USER_POINT_ENDPOINT, HttpMethod.PATCH, new HttpEntity<>(request, headers), responseType);
 
+            //then
             assertAll(
                     () -> assertTrue(response.getStatusCode().is2xxSuccessful()),
                     () -> assertThat(response.getBody().data().userId()).isEqualTo(id),
@@ -123,14 +135,18 @@ void returnsTotalPoint_whenChargeUserPoint() {
         @DisplayName("존재하지 않는 유저로 요청할 경우, 404 Not Found 응답을 반환한다.")
         @Test
         void throwsException_whenInvalidUserIdIsProvided() {
+            //given
             String id = "yh45g";
 
             HttpHeaders headers = new HttpHeaders();
             headers.add("X-USER-ID", id);
+
+            //when
             ParameterizedTypeReference<ApiResponse<PointV1Dto.PointResponse>> responseType = new ParameterizedTypeReference<>() {};
             ResponseEntity<ApiResponse<PointV1Dto.PointResponse>> response =
                     testRestTemplate.exchange(POST_USER_POINT_ENDPOINT, HttpMethod.PATCH, new HttpEntity<>(null, headers), responseType);
 
+            //then
             assertAll(
                     () -> assertTrue(response.getStatusCode().is4xxClientError()),
                     () -> assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND)
diff --git a/apps/commerce-api/src/test/java/com/loopers/interfaces/api/user/UserV1ControllerTest.java b/apps/commerce-api/src/test/java/com/loopers/interfaces/api/user/UserV1ControllerTest.java
index b99da8b4e..defe2fcd5 100644
--- a/apps/commerce-api/src/test/java/com/loopers/interfaces/api/user/UserV1ControllerTest.java
+++ b/apps/commerce-api/src/test/java/com/loopers/interfaces/api/user/UserV1ControllerTest.java
@@ -49,6 +49,7 @@ class RegisterUser {
         @DisplayName("회원 가입이 성공할 경우, 생성된 유저 정보를 응답으로 반환한다.")
         @Test
         void registerUser_whenSuccessResponseUser() {
+            //given
             String userId = "yh45g";
             String email = "yh45g@loopers.com";
             String birth = "1994-12-05";
@@ -56,11 +57,12 @@ void registerUser_whenSuccessResponseUser() {
 
             UserV1Dto.RegisterRequest request = new UserV1Dto.RegisterRequest(userId, email, birth, gender);
 
+            //when
             ParameterizedTypeReference<ApiResponse<UserV1Dto.UserResponse>> responseType = new ParameterizedTypeReference<>() {};
-
             ResponseEntity<ApiResponse<UserV1Dto.UserResponse>> response =
                     testRestTemplate.exchange(USER_REGISTER_ENDPOINT, HttpMethod.POST, new HttpEntity<>(request), responseType);
 
+            //then
             assertAll(
                     () -> assertTrue(response.getStatusCode().is2xxSuccessful()),
                     () -> assertThat(response.getBody().data().userId()).isEqualTo(userId),
@@ -72,6 +74,7 @@ void registerUser_whenSuccessResponseUser() {
         @DisplayName("회원 가입 시에 성별이 없을 경우, 400 BAD_REQUEST 응답을 받는다.")
         @Test
         void throwsBadRequest_whenGenderIsNotProvided() {
+            //given
             String userId = "yh45g";
             String email = "yh45g@loopers.com";
             String birth = "1994-12-05";
@@ -79,10 +82,12 @@ void throwsBadRequest_whenGenderIsNotProvided() {
 
             UserV1Dto.RegisterRequest request = new UserV1Dto.RegisterRequest(userId, email, birth, gender);
 
+            //when
             ParameterizedTypeReference<ApiResponse<UserV1Dto.UserResponse>> responseType = new ParameterizedTypeReference<>() {};
             ResponseEntity<ApiResponse<UserV1Dto.UserResponse>> response =
                     testRestTemplate.exchange(USER_REGISTER_ENDPOINT, HttpMethod.POST, new HttpEntity<>(request), responseType);
 
+            //then
             assertAll(
                     () -> assertTrue(response.getStatusCode().is4xxClientError()),
                     () -> assertThat(response.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST)
@@ -96,6 +101,7 @@ class GetUserById {
         @DisplayName("내 정보 조회에 성공할 경우, 해당하는 유저 정보를 반환한다.")
         @Test
         void getUserById_whenSuccessResponseUser() {
+            //given
             String userId = "yh45g";
             String email = "yh45g@loopers.com";
             String birth = "1994-12-05";
@@ -104,10 +110,13 @@ void getUserById_whenSuccessResponseUser() {
             userJpaRepository.save(new User(userId, email, birth, gender));
 
             String requestUrl = GET_USER_ENDPOINT.apply(userId);
+
+            //when
             ParameterizedTypeReference<ApiResponse<UserV1Dto.UserResponse>> responseType = new ParameterizedTypeReference<>() {};
             ResponseEntity<ApiResponse<UserV1Dto.UserResponse>> response =
                     testRestTemplate.exchange(requestUrl, HttpMethod.GET, new HttpEntity<>(null), responseType);
 
+            //then
             assertAll(
                     () -> assertTrue(response.getStatusCode().is2xxSuccessful()),
                     () -> assertThat(response.getBody().data().userId()).isEqualTo(userId),
@@ -120,12 +129,16 @@ void getUserById_whenSuccessResponseUser() {
         @DisplayName("존재하지 않는 ID 로 조회할 경우, 404 Not Found 응답을 반환한다.")
         @Test
         void throwsException_whenInvalidUserIdIsProvided() {
+            //given
             String userId = "notUserId";
             String requestUrl = GET_USER_ENDPOINT.apply(userId);
+
+            //when
             ParameterizedTypeReference<ApiResponse<UserV1Dto.UserResponse>> responseType = new ParameterizedTypeReference<>() {};
             ResponseEntity<ApiResponse<UserV1Dto.UserResponse>> response =
                     testRestTemplate.exchange(requestUrl, HttpMethod.GET, new HttpEntity<>(null), responseType);
 
+            //then
             assertAll(
                     () -> assertTrue(response.getStatusCode().is4xxClientError()),
                     () -> assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND)

From 6c487552bdc209e74b762ab8600898c3df61cc78 Mon Sep 17 00:00:00 2001
From: bookers-web <net75jin@bookers.life>
Date: Fri, 31 Oct 2025 16:46:40 +0900
Subject: [PATCH 25/40] =?UTF-8?q?fix:=20Exception=20=EB=A9=94=EC=8B=9C?=
 =?UTF-8?q?=EC=A7=80=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/java/com/loopers/domain/user/UserService.java      | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java
index da2878300..57353968a 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java
@@ -15,7 +15,7 @@ public class UserService {
     @Transactional
     public User register(String userId, String email, String birth, String gender) {
         userRepository.findByUserId(userId).ifPresent(user -> {
-            throw new CoreException(ErrorType.CONFLICT);
+            throw new CoreException(ErrorType.CONFLICT, "이미 가입된 사용자ID 입니다.");
         });
 
         User user = new User(userId, email, birth, gender);

From d9ae7adc3cfd0fb44a493c8638e258ce188e8750 Mon Sep 17 00:00:00 2001
From: simplify-len <joenggyu0@gmail.com>
Date: Mon, 3 Nov 2025 22:08:41 +0900
Subject: [PATCH 26/40] Add GitHub Actions workflow for PR Agent

---
 .github/workflows/main.yml | 13 +++++++++++++
 1 file changed, 13 insertions(+)
 create mode 100644 .github/workflows/main.yml

diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 000000000..1f80db6bf
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,13 @@
+name: PR Agent
+on:
+  pull_request:
+    types: [opened, synchronize]
+jobs:
+  pr_agent_job:
+    runs-on: ubuntu-latest
+    steps:
+      - name: PR Agent action step
+        uses: Codium-ai/pr-agent@main
+        env:
+          OPENAI_KEY: ${{ secrets.OPENAI_KEY }}
+          GITHUB_TOKEN: ${{ secrets.G_TOKEN }}

From 5bb8d33f7ffcc3e4d48c6b744ca8e4716629c9e7 Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Fri, 7 Nov 2025 16:58:30 +0900
Subject: [PATCH 27/40] =?UTF-8?q?docs=20:=20=EC=9C=A0=EC=A0=80=20=EC=8B=9C?=
 =?UTF-8?q?=EB=82=98=EB=A6=AC=EC=98=A4=20=EA=B8=B0=EB=B0=98=20=EA=B8=B0?=
 =?UTF-8?q?=EB=8A=A5=20=EC=A0=95=EC=9D=98,=20=EC=9A=94=EA=B5=AC=EC=82=AC?=
 =?UTF-8?q?=ED=95=AD=20=EB=AA=85=EC=84=B8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 docs/2round/01-requirements.md | 104 +++++++++++++++++++++++++++++++++
 1 file changed, 104 insertions(+)
 create mode 100644 docs/2round/01-requirements.md

diff --git a/docs/2round/01-requirements.md b/docs/2round/01-requirements.md
new file mode 100644
index 000000000..3296c21c6
--- /dev/null
+++ b/docs/2round/01-requirements.md
@@ -0,0 +1,104 @@
+# 유저-시나리오
+
+## 상품 목록
+1. 사용자가 모든 상품에 대해서 볼수 있다.
+2. 판매중인 상품에 대한 판매명, 판매금액, 판매브랜드, 이미지, 좋아요한 상품을 볼수있다.
+3. 사용자는 원하는 브랜드별로 상품을 볼수 있다.
+4. 사용자는 원하는 상품에대해서 좋아요를 누를수있다.
+5. 사용자는 원하는 조건에 따라 상품을 볼수있다.
+6. 사용자는 원하는 페이지로 이동할수있다.
+
+-[기능]
+1. 전체 상품 목록 조회
+2. 브랜드 상품 목록 조회
+3. 상품 좋아요 등록
+4. 필터링 (최신순, 판매순, 좋아요 순, 남자/여자)
+5. 페이징
+
+-[제약]
+1. 로그인은 X-USER-ID로 판단, 비회원일경우 "로그인 후 좋아요 가능합니다" 메시지 전달한다
+2. 상품이 없을경우 404_NOTFOUND 제공한다.
+
+---
+## 상품 상세
+1. 사용자는 원하는 판매중 상품(판매명,판매금액,판매브랜드,이미지,좋아요한 상품을 볼수있다.
+   -[기능]
+1. 사용자가 원하는 상품번호로 조회
+2. 상품 좋아요 등록 / 취소
+   -[제약]
+1. 로그인은 X-USER-ID로 판단, 비회원일경우 "로그인 후 좋아요 가능합니다" 메시지 전달한다
+2. 상품이 존재하지 않을 경우 404_NOTFOUND 제공한다.
+
+---
+## 좋아요
+1. 사용자가 원하는 상품에 대해서 좋아요를 누를 수 있다.
+2. 사용자가 원하는 상품에 대해서 좋아요를 취소 할 수 있다.
+2. 사용자가 좋아하는 상품에 대해 목록을 볼수있다.
+   -[기능]
+1. 좋아요 누른 상품에대해 목록 조회
+2. 사용가 원하는 상품에 대한 등록/취소, 단 등록/해제 (멱등성)
+   -[제약]
+1. 로그인은 X-USER-ID로 판단, 비회원일경우 "로그인 후 좋아요 가능합니다" 메시지 전달한다
+2. 해당 상품에 좋아요를 처음 등록 할때는 201_Created 제공한다
+3. 해당 상품에 좋아요를 한번더 등록 할때는 200_OK 제공한다
+4. 해당 상품에 좋아요가 등록 된 상태에서 취소 할때는 204 No Content 제공한다
+5. 해당 상품에 좋아요가 취소가 된 상태에서 한번더 취소 할때는 204 No Content 제공한다
+---
+## 브랜드
+1. 사용자는 모든 브랜드의 상품을 볼수있다.
+2. 사용자는 특정 브랜드에 대한 상품만 볼수있다.
+3. 사용자는 특정 기준으로 상품을 볼수있다. (최신순, 판매순, 좋아요 순)
+4. 사용자는 원하는 페이지로 이동할수있다.
+   [기능]
+1. 모든 브랜드 상품 조회
+2. 특정 브랜드 상품 조회
+3. 필터링 (최신순, 판매순, 좋아요 순, 남자/여자)
+4. 페이징
+   [제약]
+1. 브랜드가 없을시 404_NOTFOUND를 제공한다
+---
+## 주문
+1. 사용자가 상품 목록에서 원하는 상품을 선택하여 주문할 수 있다.
+2. 한개의 주문은 여러 상품을 포함할 수 있다.
+3. 사용자가 주문 내역을 조회해 어떤 상품을 주문했는지 확인할 수 있다.
+4. 사용자는 결제 전이라면 주문을 취소할 수 있다.
+5. 사용자는 주문 상세 화면에서 상품 정보, 수량, 결제 금액, 상태 등을 볼 수 있다.
+   [기능]
+1. 주문 생성
+2. 주문 목록 조회
+3. 주문 상세 조회
+4. 주문 취소
+5. 주문에 대한 상태관리
+   [제약]
+1. 주문 시 상품 재고 확인 및 부족 시 예외 발생
+2. 포인트 잔액 부족 시 주문 불가
+3. 동일한 주문 요청이 중복으로 들어와도 한 번만 처리
+---
+## 결제
+1. 사용자는 주문한 상품에 대해 포인트로 결제할 수 있다.
+2. 결제가 완료되면 주문 상태가 결제 완료로 변경된다.
+3. 결제 중 문제가 발생하면 결제 실패로 처리되며 포인트와 재고는 복구된다.
+4. 결제 완료 후에는 주문 취소가 불가능하다.
+   [기능]
+1. 결제요청
+2. 결제 결과 반영
+3. 결제 실패 처리
+4. 결제 내역 조회
+   [제약]
+1. 동일 주문에 대해 중복 결제 요청 시 한 번만 처리
+2. 포인트 차감실패 시 복구
+3. 외부결제 시스템 결제 시스템 처리 실패시 예외처리
+
+----
+## Ubiquitous
+| 한국어 | 영어 |
+|--------|------|
+| 사용자 | User |
+| 포인트 | Point |
+| 상품 | Product |
+| 브랜드 | Brand |
+| 좋아요 | Like |
+| 주문 | Order |
+| 재고 | Stock |
+| 가격 | Price |
+| 결제 | Payment |
\ No newline at end of file

From d50511593302038e3d4e01b13790016c1654507a Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Fri, 7 Nov 2025 16:58:45 +0900
Subject: [PATCH 28/40] =?UTF-8?q?docs=20:=20=EC=8B=9C=ED=80=80=EC=8A=A4=20?=
 =?UTF-8?q?=EB=8B=A4=EC=9D=B4=EC=96=B4=EA=B7=B8=EB=9E=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 docs/2round/02-sequence-diagrams.md | 164 ++++++++++++++++++++++++++++
 1 file changed, 164 insertions(+)
 create mode 100644 docs/2round/02-sequence-diagrams.md

diff --git a/docs/2round/02-sequence-diagrams.md b/docs/2round/02-sequence-diagrams.md
new file mode 100644
index 000000000..5264a4dc0
--- /dev/null
+++ b/docs/2round/02-sequence-diagrams.md
@@ -0,0 +1,164 @@
+# 시퀀스 다이어그램
+
+### 1. 상품 목록 조회
+```mermaid
+sequenceDiagram
+    participant User
+    participant ProductController
+    participant ProductService
+    participant ProductRepository
+    participant BrandRepository
+    participant LikeRepository
+
+    User->>ProductController: GET /api/v1/products
+    ProductController->>ProductService: getProductList
+    ProductService->>ProductRepository: findAllWithPaging
+    ProductService->>BrandRepository: findBrandInfoForProducts()
+    ProductService->>LikeRepository: countLikesForProducts()
+    ProductRepository-->>ProductService: productList
+    ProductService-->>ProductController: productListResponse
+    ProductController-->>User: 200 OK (상품 목록 + 브랜드 + 좋아요 수)
+```
+---
+### 2. 상품 상세 조회
+```mermaid
+sequenceDiagram
+    participant User
+    participant ProductController
+    participant ProductService
+    participant ProductRepository
+    participant BrandRepository
+    participant LikeRepository
+
+    User->>ProductController: GET /api/v1/products/{productId}
+    ProductController->>ProductService: getProductDetail(productId, userId)
+    ProductService->>ProductRepository: findById(productId)
+    ProductService->>BrandRepository: findBrandInfo(brandId)
+    ProductService->>LikeRepository: existsByUserIdAndProductId(userId, productId)
+    ProductRepository-->>ProductService: productDetail
+    ProductService-->>ProductController: productDetailResponse
+    ProductController-->>User: 200 OK (상품 상세 정보)
+```
+---
+### 3. 상품 좋아요 등록/취소
+```mermaid
+sequenceDiagram
+    participant User
+    participant LikeController
+    participant LikeService
+    participant LikeRepository
+
+    User->>LikeController: POST /api/v1/like/products/{productId}
+    LikeController->>LikeService: toggleLike(userId, productId)
+    LikeService->>LikeRepository: existsByUserIdAndProductId(userId, productId)
+    alt 좋아요가 존재하지 않음
+        LikeService->>LikeRepository: save(userId, productId)
+        LikeService-->>LikeController: 201 Created
+    else 이미 좋아요 되어있음
+        LikeService->>LikeRepository: delete(userId, productId)
+        LikeService-->>LikeController: 204 No Content
+    end
+    LikeController-->>User: 응답 (상태코드에 따라 다름)
+```
+---
+
+### 4. 브랜드별 상품 조회
+```mermaid
+sequenceDiagram
+    participant User
+    participant BrandController
+    participant BrandService
+    participant ProductRepository
+    participant BrandRepository
+
+    User->>BrandController: GET /api/v1/brands/{brandId}/products
+    BrandController->>BrandService: getProductsByBrand(brandId, sort, page)
+    BrandService->>BrandRepository: findById(brandId)
+    BrandService->>ProductRepository: findByBrandId(brandId, sort, page)
+    BrandRepository-->>BrandService: brandInfo
+    ProductRepository-->>BrandService: productList
+    BrandService-->>BrandController: productListResponse
+    BrandController-->>User: 200 OK (브랜드 상품 목록)
+```
+---
+### 5. 주문 생성
+```mermaid
+sequenceDiagram
+    participant User
+    participant OrderController
+    participant OrderService
+    participant ProductReader
+    participant StockService
+    participant PointService
+    participant OrderRepository
+
+    User->>OrderController: POST /api/v1/orders (items[])
+    OrderController->>OrderService: createOrder(userId, items)
+    OrderService->>ProductReader: getProductsByIds(productIds)
+    loop 각 상품에 대해
+        OrderService->>StockService: checkAndDecreaseStock(productId, quantity)
+    end
+    OrderService->>PointService: deductPoint(userId, totalPrice)
+    alt 재고 또는 포인트 부족
+        OrderService-->>OrderController: throw Exception
+        OrderController-->>User: 400 Bad Request
+    else 정상
+        OrderService->>OrderRepository: save(order, orderItems)
+        OrderService-->>OrderController: OrderResponse
+        OrderController-->>User: 201 Created (주문 완료)
+    end
+```
+---
+### 6. 주문 목록 및 상세 조회
+```mermaid
+sequenceDiagram
+    participant User
+    participant OrderController
+    participant OrderService
+    participant OrderRepository
+    participant ProductRepository
+
+    User->>OrderController: GET /api/v1/orders
+    OrderController->>OrderService: getOrderList(userId)
+    OrderService->>OrderRepository: findByUserId(userId)
+    OrderRepository-->>OrderService: orderList
+    OrderService-->>OrderController: orderListResponse
+    OrderController-->>User: 200 OK (주문 목록)
+
+    User->>OrderController: GET /api/v1/orders/{orderId}
+    OrderController->>OrderService: getOrderDetail(orderId, userId)
+    OrderService->>OrderRepository: findById(orderId)
+    OrderService->>ProductRepository: findProductsInOrder(orderId)
+    OrderRepository-->>OrderService: orderDetail
+    OrderService-->>OrderController: orderDetailResponse
+    OrderController-->>User: 200 OK (주문 상세)
+```
+---
+### 7. 결제 처리
+```mermaid
+sequenceDiagram
+    participant User
+    participant PaymentController
+    participant PaymentService
+    participant PaymentGateway
+    participant OrderRepository
+    participant PointService
+    participant StockService
+
+    User->>PaymentController: POST /api/v1/payments (orderId)
+    PaymentController->>PaymentService: processPayment(orderId, userId)
+    PaymentService->>OrderRepository: findById(orderId)
+    PaymentService->>PaymentGateway: requestPayment(orderId, amount)
+    alt 결제 성공
+        PaymentGateway-->>PaymentService: SUCCESS
+        PaymentService->>OrderRepository: updateStatus(orderId, PAID)
+        PaymentService-->>PaymentController: successResponse
+        PaymentController-->>User: 200 OK (결제 완료)
+    else 결제 실패
+        PaymentGateway-->>PaymentService: FAILED
+        PaymentService->>PointService: rollbackPoint(userId, amount)
+        PaymentService->>StockService: restoreStock(orderId)
+        PaymentService->>OrderRepository: updateStatus(orderId, FAILED)
+        PaymentController-->>User: 500 Internal Server Error (결제 실패)
+    end
+```

From 624b780acec71c75f283a61398e661f7faa545ee Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Fri, 7 Nov 2025 16:58:59 +0900
Subject: [PATCH 29/40] =?UTF-8?q?docs=20:=20=EB=8F=84=EB=A9=94=EC=9D=B8=20?=
 =?UTF-8?q?=EA=B0=9D=EC=B2=B4=20=EC=84=A4=EA=B3=84=20(=ED=81=B4=EB=9E=98?=
 =?UTF-8?q?=EC=8A=A4=20=EB=8B=A4=EC=9D=B4=EC=96=B4=EA=B7=B8=EB=9E=A8)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 docs/2round/03-class-diagram.md | 83 +++++++++++++++++++++++++++++++++
 1 file changed, 83 insertions(+)
 create mode 100644 docs/2round/03-class-diagram.md

diff --git a/docs/2round/03-class-diagram.md b/docs/2round/03-class-diagram.md
new file mode 100644
index 000000000..19a4758e6
--- /dev/null
+++ b/docs/2round/03-class-diagram.md
@@ -0,0 +1,83 @@
+# 클래스 다이어그램
+
+```mermaid
+classDiagram
+direction TB
+
+class User {
+  Long id
+  String userId
+  String name
+  String email
+  String gender
+}
+
+class Point {
+  Long id
+  Long userId
+  Long amount
+}
+
+class Brand {
+  Long id
+  String name
+  String description
+}
+
+class Product {
+  Long id
+  Long brandId
+  String name
+  Long price
+  String status
+}
+
+class Stock {
+  Long productId
+  int quantity
+}
+
+class Like {
+  Long id
+  String userId
+  Long productId
+  LocalDateTime createdAt
+}
+
+class Order {
+  Long id
+  String userId
+  String status
+  Long totalPrice
+  LocalDateTime createdAt
+  List<OrderItem> orderItems
+}
+
+class OrderItem {
+  Long id
+  Long orderId
+  Long productId
+  int quantity
+  Long priceSnapshot
+}
+
+class Payment {
+  Long id
+  Long orderId
+  String status
+  String paymentRequestId
+  LocalDateTime createdAt
+}
+
+%% 관계 설정
+User --> Point
+Brand --> Product 
+Product --> Stock
+Product --> Like
+User --> Like 
+User --> Order 
+Order --> OrderItem 
+Order --> Payment 
+OrderItem --> Product
+
+```
\ No newline at end of file

From a97d77bd5a4c4ee7a1b58dd2b973b34484622828 Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Fri, 7 Nov 2025 16:59:06 +0900
Subject: [PATCH 30/40] =?UTF-8?q?docs=20:=20=EC=A0=84=EC=B2=B4=20=ED=85=8C?=
 =?UTF-8?q?=EC=9D=B4=EB=B8=94=20=EA=B5=AC=EC=A1=B0=20=EB=B0=8F=20=EA=B4=80?=
 =?UTF-8?q?=EA=B3=84=20=EC=A0=95=EB=A6=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 docs/2round/04-erd.md | 79 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)
 create mode 100644 docs/2round/04-erd.md

diff --git a/docs/2round/04-erd.md b/docs/2round/04-erd.md
new file mode 100644
index 000000000..afc7cb8be
--- /dev/null
+++ b/docs/2round/04-erd.md
@@ -0,0 +1,79 @@
+# 엔티티 다이어그램
+```mermaid
+erDiagram
+    USER {
+        bigint id PK
+        varchar user_id
+        varchar name
+        varchar email
+        varchar gender
+    }
+
+    POINT {
+        bigint id PK
+        varchar user_id FK
+        bigint amount
+    }
+
+    BRAND {
+        bigint id PK
+        varchar name
+        varchar description
+    }
+
+    PRODUCT {
+        bigint id PK
+        bigint brand_id FK
+        varchar name
+        bigint price
+        varchar status
+    }
+
+    STOCK {
+        bigint product_id PK, FK
+        int quantity
+    }
+
+    LIKE {
+        bigint id PK
+        varchar user_id FK
+        bigint product_id FK
+        datetime created_at
+    }
+
+    ORDERS {
+        bigint id PK
+        varchar user_id FK
+        varchar status
+        bigint total_price
+        datetime created_at
+    }
+
+    ORDER_ITEM {
+        bigint id PK
+        bigint order_id FK
+        bigint product_id FK
+        int quantity
+        bigint price_snapshot
+    }
+
+    PAYMENT {
+        bigint id PK
+        bigint order_id FK
+        varchar status
+        varchar payment_request_id
+        datetime created_at
+    }
+
+    %% 관계 설정 (한글 버전)
+    USER ||--|| POINT : ""
+    BRAND ||--o{ PRODUCT : ""
+    PRODUCT ||--|| STOCK : ""
+    PRODUCT ||--o{ LIKE : ""
+    USER ||--o{ LIKE : ""
+    USER ||--o{ ORDERS : ""
+    ORDERS ||--o{ ORDER_ITEM : ""
+    ORDERS ||--|| PAYMENT : ""
+    ORDER_ITEM }o--|| PRODUCT : ""
+
+```
\ No newline at end of file

From 55f8c8b453da282f4adc3361abb8552e8880bb33 Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Fri, 7 Nov 2025 16:59:16 +0900
Subject: [PATCH 31/40] =?UTF-8?q?docs=20:=202round=20=EB=AC=B8=EC=84=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 docs/2round/2round.md | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)
 create mode 100644 docs/2round/2round.md

diff --git a/docs/2round/2round.md b/docs/2round/2round.md
new file mode 100644
index 000000000..84fdc982c
--- /dev/null
+++ b/docs/2round/2round.md
@@ -0,0 +1,37 @@
+## ✍️ Design Quest
+
+> **이커머스 도메인(상품, 브랜드, 좋아요, 주문 등)에 대한 설계**를 완료하고, 다음 주부터 개발 가능한 수준의 설계 문서를 정리하여 PR로 제출합니다.
+>
+
+### 📋 과제 정보
+
+- **설계 범위**
+    - 상품 목록 / 상품 상세 / 브랜드 조회
+    - 상품 좋아요 등록/취소 (멱등 동작)
+    - 주문 생성 및 결제 흐름 (재고 차감, 포인트 차감, 외부 시스템 연동)
+- **제외 도메인**
+    - 회원가입, 포인트 충전 (1주차 구현 완료 기준)
+- **요구사항 기반**
+    - 루프팩 이커머스 시나리오 문서를 기준으로 기능/제약사항을 설계에 반영합니다.
+- **제출 방식**
+    1. 아래 파일들을 프로젝트 내 `docs/week2/` 폴더에 `.md`로 저장
+    2. Github PR로 제출
+        - PR 제목: `[2주차] 설계 문서 제출 - 홍길동`
+        - PR 본문에 리뷰 포인트 포함 (예: 고민한 지점 등)
+
+### ✅ 제출 파일 목록 (.docs/design 디렉토리 내)
+
+| 파일명 | 내용 |
+| --- | --- |
+| `01-requirements.md` | 유저 시나리오 기반 기능 정의, 요구사항 명세 |
+| `02-sequence-diagrams.md` | 시퀀스 다이어그램 최소 2개 이상 (Mermaid 기반 작성 권장) |
+| `03-class-diagram.md` | 도메인 객체 설계 (클래스 다이어그램 or 설명 중심) |
+| `04-erd.md` | 전체 테이블 구조 및 관계 정리 (ERD Mermaid 작성 가능) |
+
+## ✅ Checklist
+
+- [ ]  상품/브랜드/좋아요/주문 도메인이 모두 포함되어 있는가?
+- [ ]  기능 요구사항이 유저 중심으로 정리되어 있는가?
+- [ ]  시퀀스 다이어그램에서 책임 객체가 드러나는가?
+- [ ]  클래스 구조가 도메인 설계를 잘 표현하고 있는가?
+- [ ]  ERD 설계 시 데이터 정합성을 고려하여 구성하였는가?
\ No newline at end of file

From 592a4e5e829a8c234dbd356abb76b5d81edcb709 Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Fri, 7 Nov 2025 16:59:24 +0900
Subject: [PATCH 32/40] =?UTF-8?q?docs=20:=201round=20=EB=AC=B8=EC=84=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 docs/{ => 1round}/1round.md | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename docs/{ => 1round}/1round.md (100%)

diff --git a/docs/1round.md b/docs/1round/1round.md
similarity index 100%
rename from docs/1round.md
rename to docs/1round/1round.md

From 5042c22dc6520c7bbb96a2c626346c6f16751e0a Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Fri, 14 Nov 2025 16:45:18 +0900
Subject: [PATCH 33/40] =?UTF-8?q?docs=20:=202round=20=EB=AC=B8=EC=84=9C=20?=
 =?UTF-8?q?=EC=88=98=EC=A0=95=2003-class-diagram.md=2004-erd.md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 docs/2round/03-class-diagram.md | 19 +++++++--------
 docs/2round/04-erd.md           | 41 +++++++++++++++------------------
 2 files changed, 28 insertions(+), 32 deletions(-)

diff --git a/docs/2round/03-class-diagram.md b/docs/2round/03-class-diagram.md
index 19a4758e6..45421dc8b 100644
--- a/docs/2round/03-class-diagram.md
+++ b/docs/2round/03-class-diagram.md
@@ -14,14 +14,13 @@ class User {
 
 class Point {
   Long id
-  Long userId
-  Long amount
+  String userId
+  Long balance
 }
 
 class Brand {
   Long id
   String name
-  String description
 }
 
 class Product {
@@ -29,7 +28,8 @@ class Product {
   Long brandId
   String name
   Long price
-  String status
+  Long likeCount;
+  Long stock
 }
 
 class Stock {
@@ -47,18 +47,19 @@ class Like {
 class Order {
   Long id
   String userId
-  String status
   Long totalPrice
+  OrderStatus status
   LocalDateTime createdAt
   List<OrderItem> orderItems
 }
 
 class OrderItem {
   Long id
-  Long orderId
+  Order order
   Long productId
-  int quantity
-  Long priceSnapshot
+  String productName
+  Long quantity
+  Long price
 }
 
 class Payment {
@@ -71,7 +72,7 @@ class Payment {
 
 %% 관계 설정
 User --> Point
-Brand --> Product 
+Brand --> Product
 Product --> Stock
 Product --> Like
 User --> Like 
diff --git a/docs/2round/04-erd.md b/docs/2round/04-erd.md
index afc7cb8be..6389b2202 100644
--- a/docs/2round/04-erd.md
+++ b/docs/2round/04-erd.md
@@ -1,4 +1,5 @@
-# 엔티티 다이어그램
+# erd
+
 ```mermaid
 erDiagram
     USER {
@@ -12,13 +13,12 @@ erDiagram
     POINT {
         bigint id PK
         varchar user_id FK
-        bigint amount
+        bigint balance
     }
 
     BRAND {
         bigint id PK
         varchar name
-        varchar description
     }
 
     PRODUCT {
@@ -26,12 +26,8 @@ erDiagram
         bigint brand_id FK
         varchar name
         bigint price
-        varchar status
-    }
-
-    STOCK {
-        bigint product_id PK, FK
-        int quantity
+        bigint like_count
+        bigint stock
     }
 
     LIKE {
@@ -44,8 +40,8 @@ erDiagram
     ORDERS {
         bigint id PK
         varchar user_id FK
+        bigint total_amount
         varchar status
-        bigint total_price
         datetime created_at
     }
 
@@ -53,8 +49,9 @@ erDiagram
         bigint id PK
         bigint order_id FK
         bigint product_id FK
-        int quantity
-        bigint price_snapshot
+        varchar product_name
+        bigint quantity
+        bigint price
     }
 
     PAYMENT {
@@ -65,15 +62,13 @@ erDiagram
         datetime created_at
     }
 
-    %% 관계 설정 (한글 버전)
-    USER ||--|| POINT : ""
-    BRAND ||--o{ PRODUCT : ""
-    PRODUCT ||--|| STOCK : ""
-    PRODUCT ||--o{ LIKE : ""
-    USER ||--o{ LIKE : ""
-    USER ||--o{ ORDERS : ""
-    ORDERS ||--o{ ORDER_ITEM : ""
-    ORDERS ||--|| PAYMENT : ""
-    ORDER_ITEM }o--|| PRODUCT : ""
-
+    %% 관계 (cardinality)
+    USER ||--|| POINT : "1:1"
+    BRAND ||--o{ PRODUCT : "1:N"
+    PRODUCT ||--o{ LIKE : "1:N"
+    USER ||--o{ LIKE : "1:N"
+    USER ||--o{ ORDERS : "1:N"
+    ORDERS ||--o{ ORDER_ITEM : "1:N"
+    ORDER_ITEM }o--|| PRODUCT : "N:1"
+    ORDERS ||--|| PAYMENT : "1:1"
 ```
\ No newline at end of file

From 4fda674eb233af0586f8757a8fc2d68d46e2cb42 Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Fri, 14 Nov 2025 16:45:30 +0900
Subject: [PATCH 34/40] =?UTF-8?q?docs=20:=203round=20=EB=AC=B8=EC=84=9C?=
 =?UTF-8?q?=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 docs/3round/3round.md | 60 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)
 create mode 100644 docs/3round/3round.md

diff --git a/docs/3round/3round.md b/docs/3round/3round.md
new file mode 100644
index 000000000..61df49f68
--- /dev/null
+++ b/docs/3round/3round.md
@@ -0,0 +1,60 @@
+# 📝 Round 3 Quests
+
+---
+
+## 💻 Implementation Quest
+
+> *** 도메인 모델링**을 통해 Product, Brand, Like, Order 기능의 핵심 개념을 **Entity, Value Object, Domain Service 등 적합한** **코드**로 작성합니다.
+* 레이어드 아키텍처 + DIP 를 적용해 유연하고 테스트 가능한 구조로 구성합니다.
+* **Application Layer를 경량 수준**으로 구성하여, 도메인 객체를 조합하는 흐름을 실제 구현해봅니다.
+* **단위 테스트를 작성**하여 도메인 로직의 정합성과 규칙을 검증합니다.
+>
+
+### 📋 과제 정보
+
+- 상품, 브랜드, 좋아요, 주문 기능의 **도메인 모델 및 도메인 서비스**를 구현합니다.
+- 도메인 간 협력 흐름을 설계하고, 필요한 로직을 **도메인 서비스**로 분리합니다.
+- Application Layer에서 도메인 객체를 조합하는 흐름을 구현합니다.
+  (예: `ProductFacade.getProductDetail(productId)` → `Product + Brand + Like 조합`)
+- Repository Interface 와 구현체는 분리하고, 테스트 가능성을 고려한 구조를 설계합니다.
+- 모든 핵심 도메인 로직에 대해 단위 테스트를 작성하고, 예외/경계 케이스도 포함합니다.
+
+### 🏷 Product / Brand 도메인
+
+## ✅ Checklist
+
+- [x]  상품 정보 객체는 브랜드 정보, 좋아요 수를 포함한다.
+- [ ]  상품의 정렬 조건(`latest`, `price_asc`, `likes_desc`) 을 고려한 조회 기능을 설계했다
+- [x]  상품은 재고를 가지고 있고, 주문 시 차감할 수 있어야 한다
+- [x]  재고는 감소만 가능하며 음수 방지는 도메인 레벨에서 처리된다
+
+### 👍 Like 도메인
+
+- [x]  좋아요는 유저와 상품 간의 관계로 별도 도메인으로 분리했다
+- [x]  중복 좋아요 방지를 위한 멱등성 처리가 구현되었다
+- [x]  상품의 좋아요 수는 상품 상세/목록 조회에서 함께 제공된다
+- [ ]  단위 테스트에서 좋아요 등록/취소/중복 방지 흐름을 검증했다
+
+### 🛒 Order 도메인
+
+- [ ]  주문은 여러 상품을 포함할 수 있으며, 각 상품의 수량을 명시한다
+- [ ]  주문 시 상품의 재고 차감, 유저 포인트 차감 등을 수행한다
+- [ ]  재고 부족, 포인트 부족 등 예외 흐름을 고려해 설계되었다
+- [ ]  단위 테스트에서 정상 주문 / 예외 주문 흐름을 모두 검증했다
+
+### 🧩 도메인 서비스
+
+- [ ]  도메인 간 협력 로직은 Domain Service에 위치시켰다
+- [ ]  상품 상세 조회 시 Product + Brand 정보 조합은 도메인 서비스에서 처리했다
+- [ ]  복합 유스케이스는 Application Layer에 존재하고, 도메인 로직은 위임되었다
+- [ ]  도메인 서비스는 상태 없이, 도메인 객체의 협력 중심으로 설계되었다
+
+### **🧱 소프트웨어 아키텍처 & 설계**
+
+- [ ]  전체 프로젝트의 구성은 아래 아키텍처를 기반으로 구성되었다
+    - Application → **Domain** ← Infrastructure
+- [ ]  Application Layer는 도메인 객체를 조합해 흐름을 orchestration 했다
+- [ ]  핵심 비즈니스 로직은 Entity, VO, Domain Service 에 위치한다
+- [ ]  Repository Interface는 Domain Layer 에 정의되고, 구현체는 Infra에 위치한다
+- [ ]  패키지는 계층 + 도메인 기준으로 구성되었다 (`/domain/order`, `/application/like` 등)
+- [ ]  테스트는 외부 의존성을 분리하고, Fake/Stub 등을 사용해 단위 테스트가 가능하게 구성되었다
\ No newline at end of file

From 25b423ec65fcf24fed8e99f405e2091fcf603e77 Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Fri, 14 Nov 2025 16:49:20 +0900
Subject: [PATCH 35/40] =?UTF-8?q?feat(brand):=20=EB=B8=8C=EB=9E=9C?=
 =?UTF-8?q?=EB=93=9C=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=EB=AA=A8=EB=8D=B8=20?=
 =?UTF-8?q?=EB=B0=8F=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=EC=84=9C=EB=B9=84?=
 =?UTF-8?q?=EC=8A=A4=20=EA=B5=AC=ED=98=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

- Brand 엔티티 생성 및 도메인 검증 로직 추가
- BrandRepository 인터페이스 정의
- Brand 도메인 서비스 설계
- Brand 단위/통합 테스트 작성 (생성/검증)
---
 .../java/com/loopers/domain/brand/Brand.java  | 47 +++++++++++++++++++
 .../loopers/domain/brand/BrandRepository.java | 20 ++++++++
 .../loopers/domain/brand/BrandService.java    | 36 ++++++++++++++
 .../brand/BrandJpaRepository.java             | 21 +++++++++
 .../brand/BrandRepositoryImpl.java            | 36 ++++++++++++++
 .../com/loopers/domain/brand/BrandTest.java   | 42 +++++++++++++++++
 6 files changed, 202 insertions(+)
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/brand/Brand.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/brand/BrandRepository.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/brand/BrandService.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/brand/BrandJpaRepository.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/brand/BrandRepositoryImpl.java
 create mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/brand/BrandTest.java

diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/brand/Brand.java b/apps/commerce-api/src/main/java/com/loopers/domain/brand/Brand.java
new file mode 100644
index 000000000..bacd46b25
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/brand/Brand.java
@@ -0,0 +1,47 @@
+package com.loopers.domain.brand;
+
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
+import jakarta.persistence.*;
+import lombok.Getter;
+
+/**
+ * packageName : com.loopers.domain.brand
+ * fileName     : Brand
+ * author      : byeonsungmun
+ * date        : 2025. 11. 11.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 11.     byeonsungmun       최초 생성
+ */
+@Entity
+@Table(name = "brand")
+@Getter
+public class Brand {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    @Column(nullable = false)
+    private String name;
+
+    protected  Brand() {}
+
+    private Brand(String name) {
+        this.name = requireValidName(name);
+    }
+
+    public static Brand create(String name) {
+        return new Brand(name);
+    }
+
+
+    private String requireValidName(String name) {
+        if (name == null || name.isEmpty()) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "상품명 비어 있을수 없습니다.");
+        }
+        return name.trim();
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/brand/BrandRepository.java b/apps/commerce-api/src/main/java/com/loopers/domain/brand/BrandRepository.java
new file mode 100644
index 000000000..c558b23fc
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/brand/BrandRepository.java
@@ -0,0 +1,20 @@
+package com.loopers.domain.brand;
+
+import java.util.Optional;
+
+/**
+ * packageName : com.loopers.domain.brand
+ * fileName     : BrandRepository
+ * author      : byeonsungmun
+ * date        : 2025. 11. 12.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 12.     byeonsungmun       최초 생성
+ */
+public interface BrandRepository {
+    Optional<Brand> findById(Long id);
+
+    void save(Brand brand);
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/brand/BrandService.java b/apps/commerce-api/src/main/java/com/loopers/domain/brand/BrandService.java
new file mode 100644
index 000000000..6aa724710
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/brand/BrandService.java
@@ -0,0 +1,36 @@
+package com.loopers.domain.brand;
+
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * packageName : com.loopers.domain.brand
+ * fileName     : BrandService
+ * author      : byeonsungmun
+ * date        : 2025. 11. 12.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 12.     byeonsungmun       최초 생성
+ */
+@Component
+@RequiredArgsConstructor
+public class BrandService {
+
+    private final BrandRepository brandRepository;
+
+    @Transactional
+    public void save(Brand brand) {
+        brandRepository.save(brand);
+    }
+
+    @Transactional(readOnly = true)
+    public Brand getBrand(Long id) {
+        return brandRepository.findById(id)
+                .orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "브랜드를 찾을 수 없습니다."));
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/brand/BrandJpaRepository.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/brand/BrandJpaRepository.java
new file mode 100644
index 000000000..111990a22
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/infrastructure/brand/BrandJpaRepository.java
@@ -0,0 +1,21 @@
+package com.loopers.infrastructure.brand;
+
+import com.loopers.domain.brand.Brand;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.Optional;
+
+/**
+ * packageName : com.loopers.infrastructure.brand
+ * fileName     : BrandJpaRepository
+ * author      : byeonsungmun
+ * date        : 2025. 11. 12.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 12.     byeonsungmun       최초 생성
+ */
+public interface BrandJpaRepository extends JpaRepository<Brand, Long> {
+    Optional<Brand> findById(Long id);
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/brand/BrandRepositoryImpl.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/brand/BrandRepositoryImpl.java
new file mode 100644
index 000000000..f23e6e5d9
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/infrastructure/brand/BrandRepositoryImpl.java
@@ -0,0 +1,36 @@
+package com.loopers.infrastructure.brand;
+
+import com.loopers.domain.brand.Brand;
+import com.loopers.domain.brand.BrandRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+import java.util.Optional;
+
+/**
+ * packageName : com.loopers.infrastructure.brand
+ * fileName     : BrandRepositroyImpl
+ * author      : byeonsungmun
+ * date        : 2025. 11. 12.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 12.     byeonsungmun       최초 생성
+ */
+@RequiredArgsConstructor
+@Component
+public class BrandRepositoryImpl implements BrandRepository {
+
+    private final BrandJpaRepository jpaRepository;
+
+    @Override
+    public Optional<Brand> findById(Long id) {
+        return jpaRepository.findById(id);
+    }
+
+    @Override
+    public void save(Brand brand) {
+        jpaRepository.save(brand);
+    }
+}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/brand/BrandTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/brand/BrandTest.java
new file mode 100644
index 000000000..9541c11f4
--- /dev/null
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/brand/BrandTest.java
@@ -0,0 +1,42 @@
+package com.loopers.domain.brand;
+
+import com.loopers.support.error.CoreException;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+/**
+ * packageName : com.loopers.domain.brand
+ * fileName     : BrandTest
+ * author      : byeonsungmun
+ * date        : 2025. 11. 14.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 14.     byeonsungmun       최초 생성
+ */
+class BrandTest {
+
+    @DisplayName("Brand 단위 테스트")
+    @Nested
+    class CreateBrandTest {
+
+        @Test
+        @DisplayName("브랜드 생성 성공")
+        void createBrandSuccess() {
+            Brand brand = Brand.create("Nike");
+            assertThat(brand.getName()).isEqualTo("Nike");
+        }
+
+        @Test
+        @DisplayName("브랜드 이름이 없으면 예외")
+        void createBrandFail() {
+            assertThatThrownBy(() -> Brand.create(""))
+                    .isInstanceOf(CoreException.class);
+        }
+    }
+}

From 04ff3450f9994f9f4fd0906a9922d0e7136e867a Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Fri, 14 Nov 2025 16:51:05 +0900
Subject: [PATCH 36/40] =?UTF-8?q?feat(product):=20=EC=83=81=ED=92=88=20?=
 =?UTF-8?q?=EB=8F=84=EB=A9=94=EC=9D=B8=20=EB=AA=A8=EB=8D=B8=20=EA=B5=AC?=
 =?UTF-8?q?=ED=98=84=20=EB=B0=8F=20=EC=9E=AC=EA=B3=A0/=EC=A0=95=EB=A0=AC?=
 =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

- Product 엔티티 구현 (재고, 좋아요 수 포함)
- decreaseStock, increaseLikeCount 등 도메인 로직 추가
- ProductRepository 인터페이스 정의
- Product 단위/통합 테스트 작성
---
 .../product/ProductDetailInfo.java            |  32 +++++
 .../application/product/ProductFacade.java    |  47 +++++++
 .../application/product/ProductInfo.java      |  33 +++++
 .../com/loopers/domain/product/Product.java   | 117 ++++++++++++++++++
 .../loopers/domain/product/ProductDetail.java |  45 +++++++
 .../domain/product/ProductDomainService.java  |  39 ++++++
 .../domain/product/ProductRepository.java     |  29 +++++
 .../domain/product/ProductService.java        |  39 ++++++
 .../product/ProductJpaRepository.java         |  19 +++
 .../product/ProductRepositoryImpl.java        |  55 ++++++++
 .../ProductServiceIntegrationTest.java        |  43 +++++++
 .../loopers/domain/product/ProductTest.java   |  95 ++++++++++++++
 12 files changed, 593 insertions(+)
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/application/product/ProductDetailInfo.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/application/product/ProductFacade.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/application/product/ProductInfo.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/product/Product.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/product/ProductDetail.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/product/ProductDomainService.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/product/ProductRepository.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/product/ProductService.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/product/ProductJpaRepository.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/product/ProductRepositoryImpl.java
 create mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/product/ProductServiceIntegrationTest.java
 create mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/product/ProductTest.java

diff --git a/apps/commerce-api/src/main/java/com/loopers/application/product/ProductDetailInfo.java b/apps/commerce-api/src/main/java/com/loopers/application/product/ProductDetailInfo.java
new file mode 100644
index 000000000..2a9ecee27
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/application/product/ProductDetailInfo.java
@@ -0,0 +1,32 @@
+package com.loopers.application.product;
+
+import com.loopers.domain.product.ProductDetail;
+
+/**
+ * packageName : com.loopers.application.product
+ * fileName     : ProductDetail
+ * author      : byeonsungmun
+ * date        : 2025. 11. 13.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 13.     byeonsungmun       최초 생성
+ */
+public record ProductDetailInfo(
+        Long id,
+        String name,
+        String brandName,
+        Long price,
+        Long likeCount
+) {
+    public static ProductDetailInfo from(ProductDetail productDetail) {
+        return new ProductDetailInfo(
+                productDetail.getId(),
+                productDetail.getName(),
+                productDetail.getBrandName(),
+                productDetail.getPrice(),
+                productDetail.getLikeCount()
+        );
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/product/ProductFacade.java b/apps/commerce-api/src/main/java/com/loopers/application/product/ProductFacade.java
new file mode 100644
index 000000000..7b83360e7
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/application/product/ProductFacade.java
@@ -0,0 +1,47 @@
+package com.loopers.application.product;
+
+import com.loopers.domain.brand.Brand;
+import com.loopers.domain.brand.BrandService;
+import com.loopers.domain.like.LikeService;
+import com.loopers.domain.product.ProductDetail;
+import com.loopers.domain.product.ProductDomainService;
+import com.loopers.domain.product.ProductService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Component;
+
+/**
+ * packageName : com.loopers.application.product
+ * fileName     : ProdcutFacade
+ * author      : byeonsungmun
+ * date        : 2025. 11. 10.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 10.     byeonsungmun       최초 생성
+ */
+@Component
+@RequiredArgsConstructor
+public class ProductFacade {
+
+    private final ProductService productService;
+    private final BrandService brandService;
+    private final LikeService likeService;
+    private final ProductDomainService productDomainService;
+
+    public Page<ProductInfo> getProducts(Pageable pageable) {
+        return productService.getProducts(pageable)
+                .map(product ->  {
+                    Brand brand = brandService.getBrand(product.getId());
+                    long likeCount = likeService.countByProductId(product.getId());
+                    return ProductInfo.of(product, brand, likeCount);
+                });
+    }
+
+    public ProductDetailInfo getProduct(Long id) {
+        ProductDetail productDetail = productDomainService.getProductDetail(id);
+        return ProductDetailInfo.from(productDetail);
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/product/ProductInfo.java b/apps/commerce-api/src/main/java/com/loopers/application/product/ProductInfo.java
new file mode 100644
index 000000000..8bcd93dd8
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/application/product/ProductInfo.java
@@ -0,0 +1,33 @@
+package com.loopers.application.product;
+
+import com.loopers.domain.brand.Brand;
+import com.loopers.domain.product.Product;
+
+/**
+ * packageName : com.loopers.application.product
+ * fileName     : ProductInfo
+ * author      : byeonsungmun
+ * date        : 2025. 11. 10.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 10.     byeonsungmun       최초 생성
+ */
+public record ProductInfo(
+        Long id,
+        String name,
+        String brandName,
+        Long price,
+        Long likeCount
+) {
+    public static ProductInfo of(Product product, Brand brand, Long likeCount) {
+        return new ProductInfo(
+                product.getId(),
+                product.getName(),
+                brand.getName(),
+                product.getPrice(),
+                likeCount
+        );
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/product/Product.java b/apps/commerce-api/src/main/java/com/loopers/domain/product/Product.java
new file mode 100644
index 000000000..cade20580
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/product/Product.java
@@ -0,0 +1,117 @@
+package com.loopers.domain.product;
+
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
+import jakarta.persistence.*;
+import lombok.Getter;
+
+/**
+ * packageName : com.loopers.domain.product
+ * fileName     : Product
+ * author      : byeonsungmun
+ * date        : 2025. 11. 10.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 10.     byeonsungmun       최초 생성
+ */
+
+@Entity
+@Table(name = "product")
+@Getter
+public class Product {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    @Column(name = "ref_brand_id", nullable = false)
+    private Long brandId;
+
+    @Column(nullable = false)
+    private String name;
+
+    @Column(nullable = false)
+    private Long price;
+
+    @Column
+    private Long likeCount;
+
+    @Column(nullable = false)
+    private Long stock;
+
+    protected Product() {}
+
+    private Product(Long brandId, String name, Long price, Long likeCount, Long stock) {
+        this.brandId = requireValidBrandId(brandId);
+        this.name = requireValidName(name);
+        this.price = requireValidPrice(price);
+        this.likeCount = requireValidLikeCount(likeCount);
+        this.stock = requireValidStock(stock);
+    }
+
+    public static Product create(Long brandId, String name, Long price, Long stock) {
+        return new Product(
+                brandId,
+                name,
+                price,
+                0L,
+                stock
+        );
+    }
+
+    private Long requireValidBrandId(Long brandId) {
+        if (brandId == null || brandId <= 0) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "브랜드 ID는 필수입니다.");
+        }
+
+        return brandId;
+    }
+
+    private String requireValidName(String name) {
+        if (name == null || name.isEmpty()) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "상품명은 필수입니다.");
+        }
+        return name;
+    }
+
+    private Long requireValidPrice(Long price) {
+        if (price == null || price < 0) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "상품 가격은 0원 이상이어야 합니다.");
+        }
+        return price;
+    }
+
+    public Long requireValidLikeCount(Long likeCount) {
+        if (likeCount == null || likeCount < 0) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "좋아요 개수는 0개 미만으로 설정할 수 없습니다.");
+        }
+        return likeCount;
+    }
+
+    private Long requireValidStock(Long stock) {
+        if (stock < 0) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "상품 재고는 0 미만으로 설정할 수 없습니다.");
+        }
+        return stock;
+    }
+
+    public void increaseLikeCount() {
+        this.likeCount++;
+    }
+
+    public void decreaseLikeCount() {
+        if (this.likeCount > 0) this.likeCount--;
+    }
+
+    public void decreaseStock(Long quantity) {
+        if (quantity <= 0) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "차감 수량은 0보다 커야 합니다.");
+        }
+        if (this.stock - quantity < 0) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "재고가 부족합니다.");
+        }
+        this.stock -= quantity;
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductDetail.java b/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductDetail.java
new file mode 100644
index 000000000..808bff196
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductDetail.java
@@ -0,0 +1,45 @@
+package com.loopers.domain.product;
+
+import com.loopers.domain.brand.Brand;
+import lombok.Getter;
+
+/**
+ * packageName : com.loopers.domain.product
+ * fileName     : ProductDetail
+ * author      : byeonsungmun
+ * date        : 2025. 11. 13.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 13.     byeonsungmun       최초 생성
+ */
+@Getter
+public class ProductDetail {
+
+    private Long id;
+    private String name;
+    private String brandName;
+    private Long price;
+    private Long likeCount;
+
+    protected ProductDetail() {}
+
+    private ProductDetail(Long id, String name, String brandName, Long price, Long likeCount) {
+        this.id = id;
+        this.name = name;
+        this.brandName = brandName;
+        this.price = price;
+        this.likeCount = likeCount;
+    }
+
+    public static ProductDetail of(Product product, Brand brand, Long likeCount) {
+        return new ProductDetail(
+                product.getId(),
+                product.getName(),
+                brand.getName(),
+                product.getPrice(),
+                likeCount
+        );
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductDomainService.java b/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductDomainService.java
new file mode 100644
index 000000000..f86edfddd
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductDomainService.java
@@ -0,0 +1,39 @@
+package com.loopers.domain.product;
+
+import com.loopers.domain.brand.Brand;
+import com.loopers.domain.brand.BrandRepository;
+import com.loopers.domain.like.LikeRepository;
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+/**
+ * packageName : com.loopers.domain.product
+ * fileName     : ProductDetailService
+ * author      : byeonsungmun
+ * date        : 2025. 11. 13.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 13.     byeonsungmun       최초 생성
+ */
+@Component
+@RequiredArgsConstructor
+public class ProductDomainService {
+
+    private final ProductRepository productRepository;
+    private final BrandRepository brandRepository;
+    private final LikeRepository likeRepository;
+
+    public ProductDetail getProductDetail(Long id) {
+        Product product = productRepository.findById(id)
+                .orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "상품을 찾을 수 없습니다."));
+        Brand brand = brandRepository.findById(product.getBrandId())
+                .orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "브랜드를 찾을 수 없습니다"));
+        long likeCount = likeRepository.countByProductId(id);
+
+        return ProductDetail.of(product, brand, likeCount);
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductRepository.java b/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductRepository.java
new file mode 100644
index 000000000..dadda62a0
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductRepository.java
@@ -0,0 +1,29 @@
+package com.loopers.domain.product;
+
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+
+import java.util.Optional;
+
+/**
+ * packageName : com.loopers.domain.product
+ * fileName     : ProductRepositroy
+ * author      : byeonsungmun
+ * date        : 2025. 11. 12.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 12.     byeonsungmun       최초 생성
+ */
+public interface ProductRepository {
+    Page<Product> findAll(Pageable pageable);
+
+    Optional<Product> findById(Long id);
+
+    void incrementLikeCount(Long productId);
+
+    void decrementLikeCount(Long productId);
+
+    Product save(Product product);
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductService.java b/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductService.java
new file mode 100644
index 000000000..a9c03fc80
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductService.java
@@ -0,0 +1,39 @@
+package com.loopers.domain.product;
+
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * packageName : com.loopers.domain.product
+ * fileName     : ProductService
+ * author      : byeonsungmun
+ * date        : 2025. 11. 12.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 12.     byeonsungmun       최초 생성
+ */
+
+@Component
+@RequiredArgsConstructor
+public class ProductService {
+
+    private final ProductRepository productRepository;
+
+    @Transactional(readOnly = true)
+    public Page<Product> getProducts(Pageable pageable) {
+        return productRepository.findAll(pageable);
+    }
+
+    public Product getProduct(Long productId) {
+        return productRepository.findById(productId)
+                .orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "해당 상품이 없습니다"));
+    }
+}
+
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/product/ProductJpaRepository.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/product/ProductJpaRepository.java
new file mode 100644
index 000000000..5ceaae067
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/infrastructure/product/ProductJpaRepository.java
@@ -0,0 +1,19 @@
+package com.loopers.infrastructure.product;
+
+import com.loopers.domain.product.Product;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+/**
+ * packageName : com.loopers.infrastructure.product
+ * fileName     : ProductJpaRepository
+ * author      : byeonsungmun
+ * date        : 2025. 11. 13.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 13.     byeonsungmun       최초 생성
+ */
+public interface ProductJpaRepository extends JpaRepository<Product, Long> {
+
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/product/ProductRepositoryImpl.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/product/ProductRepositoryImpl.java
new file mode 100644
index 000000000..ba0feb19c
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/infrastructure/product/ProductRepositoryImpl.java
@@ -0,0 +1,55 @@
+package com.loopers.infrastructure.product;
+
+import com.loopers.domain.product.Product;
+import com.loopers.domain.product.ProductRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Component;
+
+import java.util.Optional;
+
+/**
+ * packageName : com.loopers.infrastructure.product
+ * fileName     : ProductRepositoryImpl
+ * author      : byeonsungmun
+ * date        : 2025. 11. 13.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 13.     byeonsungmun       최초 생성
+ */
+@Component
+@RequiredArgsConstructor
+public class ProductRepositoryImpl implements ProductRepository {
+
+    private final ProductJpaRepository productJpaRepository;
+
+    @Override
+    public Page<Product> findAll(Pageable pageable) {
+        return productJpaRepository.findAll(pageable);
+    }
+
+    @Override
+    public Optional<Product> findById(Long id) {
+        return productJpaRepository.findById(id);
+    }
+
+    @Override
+    public void incrementLikeCount(Long productId) {
+        Product product = productJpaRepository.findById(productId).get();
+        product.increaseLikeCount();
+    }
+
+    @Override
+    public void decrementLikeCount(Long productId) {
+        Product product = productJpaRepository.findById(productId).get();
+        product.decreaseLikeCount();
+    }
+
+    @Override
+    public Product save(Product product) {
+        return productJpaRepository.save(product);
+    }
+}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/product/ProductServiceIntegrationTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/product/ProductServiceIntegrationTest.java
new file mode 100644
index 000000000..8ad61a194
--- /dev/null
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/product/ProductServiceIntegrationTest.java
@@ -0,0 +1,43 @@
+package com.loopers.domain.product;
+
+import com.loopers.utils.DatabaseCleanUp;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+/**
+ * packageName : com.loopers.domain.product
+ * fileName     : ProductServiceIntegrationTest
+ * author      : byeonsungmun
+ * date        : 2025. 11. 13.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 13.     byeonsungmun       최초 생성
+ */
+
+@SpringBootTest
+public class ProductServiceIntegrationTest {
+
+    @Autowired
+    private ProductService productService;
+
+    @Autowired
+    private DatabaseCleanUp databaseCleanUp;
+
+    @AfterEach
+    void tearDown() {
+        databaseCleanUp.truncateAllTables();
+    }
+
+    @Nested
+    @DisplayName("상품 목록 조회 테스트")
+    class ProductListTests {
+
+        Product product;
+
+    }
+}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/product/ProductTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/product/ProductTest.java
new file mode 100644
index 000000000..c2c6fdd9b
--- /dev/null
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/product/ProductTest.java
@@ -0,0 +1,95 @@
+package com.loopers.domain.product;
+
+import com.loopers.support.error.CoreException;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * packageName : com.loopers.domain.product
+ * fileName     : ProductTest
+ * author      : byeonsungmun
+ * date        : 2025. 11. 10.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 10.     byeonsungmun       최초 생성
+ */
+class ProductTest {
+    @DisplayName("Product 좋아요 수 증감 테스트")
+    @Nested
+    class LikeCountChange {
+
+        @DisplayName("좋아요 수를 증가시킨다.")
+        @Test
+        void increaseLikeCount_incrementsLikeCount() {
+            // given
+            Product product = Product.create(11L, "나이키 에어2", 30000L, 10L);
+
+            // when
+            product.increaseLikeCount();
+
+            // then
+            assertEquals(1L, product.getLikeCount());
+        }
+
+        @DisplayName("좋아요 수를 감소시킨다. 0 미만으로는 감소하지 않는다.")
+        @Test
+        void decreaseLikeCount_decrementsLikeCountButNotBelowZero() {
+            // given
+            Product product = Product.create(11L, "나이키 에어2", 30000L, 1L);
+
+            // when
+            product.decreaseLikeCount();
+
+            // then
+            assertEquals(0L, product.getLikeCount());
+
+            // when decrease again
+            product.decreaseLikeCount();
+
+            // then likeCount should not go below 0
+            assertEquals(0L, product.getLikeCount());
+        }
+    }
+
+    @DisplayName("Product 재고 차감 테스트")
+    @Nested
+    class Stock {
+
+        @DisplayName("재고를 정상 차감한다.")
+        @Test
+        void decreaseStock_successfullyDecreasesStock() {
+            // given
+            Product product = Product.create(1L, "나이키 에어2", 30000L, 10L);
+
+            // when
+            product.decreaseStock(3L);
+
+            // then
+            assertEquals(7, product.getStock());
+        }
+
+        @DisplayName("차감 수량이 0 이하이면 예외 발생")
+        @Test
+        void decreaseStock_withInvalidQuantity_throwsException() {
+            Product product = Product.create(1L, "나이키 에어2", 30000L, 10L);
+
+            assertThrows(CoreException.class, () -> product.decreaseStock(0L));
+            assertThrows(CoreException.class, () -> product.decreaseStock(-1L));
+        }
+
+        @DisplayName("재고보다 큰 수량 차감 시 예외 발생")
+        @Test
+        void decreaseStock_withInsufficientStock_throwsException() {
+            Product product = Product.create(1L, "나이키 에어2", 30000L, 10L);
+
+            assertThrows(CoreException.class, () -> product.decreaseStock(11L));
+        }
+    }
+}
+

From 7e0ac82a96f46a3b49837b5133167fae240e4e94 Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Fri, 14 Nov 2025 16:51:42 +0900
Subject: [PATCH 37/40] =?UTF-8?q?feat(like):=20=EC=A2=8B=EC=95=84=EC=9A=94?=
 =?UTF-8?q?=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=EA=B5=AC=ED=98=84=20=EB=B0=8F?=
 =?UTF-8?q?=20=EB=A9=B1=EB=93=B1=EC=84=B1=20=EC=B2=98=EB=A6=AC=20=EC=B6=94?=
 =?UTF-8?q?=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

- Like 엔티티 구현
- 좋아요 등록/취소 로직 및 중복 방지 (멱등성) 구현
- Product.likeCount 증가/감소 연동
- LikeRepository 인터페이스 정의
- Like 단위 /통 합 테스트 작성
---
 .../loopers/application/like/LikeFacade.java  |  34 ++++
 .../java/com/loopers/domain/like/Like.java    |  63 +++++++
 .../loopers/domain/like/LikeRepository.java   |  25 +++
 .../com/loopers/domain/like/LikeService.java  |  49 ++++++
 .../like/LikeJpaRepository.java               |  23 +++
 .../like/LikeRepositoryImpl.java              |  46 ++++++
 .../like/LikeServiceIntegrationTest.java      | 155 ++++++++++++++++++
 .../com/loopers/domain/like/LikeTest.java     |  91 ++++++++++
 8 files changed, 486 insertions(+)
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/application/like/LikeFacade.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/like/Like.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/like/LikeRepository.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/like/LikeService.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/like/LikeJpaRepository.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/like/LikeRepositoryImpl.java
 create mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/like/LikeServiceIntegrationTest.java
 create mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/like/LikeTest.java

diff --git a/apps/commerce-api/src/main/java/com/loopers/application/like/LikeFacade.java b/apps/commerce-api/src/main/java/com/loopers/application/like/LikeFacade.java
new file mode 100644
index 000000000..5d885672e
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/application/like/LikeFacade.java
@@ -0,0 +1,34 @@
+package com.loopers.application.like;
+
+import com.loopers.domain.like.LikeService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * packageName : com.loopers.application.like
+ * fileName     : LikeFacade
+ * author      : byeonsungmun
+ * date        : 2025. 11. 14.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 14.     byeonsungmun       최초 생성
+ */
+@Component
+@RequiredArgsConstructor
+@Transactional
+public class LikeFacade {
+
+    private final LikeService likeService;
+
+    public void createLike(String userId, Long productId) {
+        likeService.like(userId, productId);
+    }
+
+    public void deleteLike(String userId, Long productId) {
+        likeService.unlike(userId, productId);
+    }
+}
+
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/like/Like.java b/apps/commerce-api/src/main/java/com/loopers/domain/like/Like.java
new file mode 100644
index 000000000..4430b496a
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/like/Like.java
@@ -0,0 +1,63 @@
+package com.loopers.domain.like;
+
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
+import jakarta.persistence.*;
+import lombok.Getter;
+
+import java.time.LocalDateTime;
+
+/**
+ * packageName : com.loopers.domain.like
+ * fileName     : Like
+ * author      : byeonsungmun
+ * date        : 2025. 11. 11.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 11.     byeonsungmun       최초 생성
+ */
+@Entity
+@Table(name = "product_like")
+@Getter
+public class Like {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    @Column(name = "ref_user_id", nullable = false)
+    private String userId;
+
+    @Column(name = "ref_product_id", nullable = false)
+    private Long productId;
+
+    @Column(nullable = false)
+    private LocalDateTime createdAt;
+
+    protected Like() {}
+
+    private Like(String userId, Long productId) {
+        this.userId = requireValidUserId(userId);
+        this.productId = requireValidProductId(productId);
+        this.createdAt = LocalDateTime.now();
+    }
+
+    public static Like create(String userId, Long productId) {
+        return new Like(userId, productId);
+    }
+
+    private String requireValidUserId(String userId) {
+        if (userId == null || userId.isEmpty()) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "사용자 ID는 필수입니다.");
+        }
+        return userId;
+    }
+
+    private Long requireValidProductId(Long productId) {
+        if (productId == null || productId <= 0) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "상품 ID는 필수입니다.");
+        }
+        return productId;
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/like/LikeRepository.java b/apps/commerce-api/src/main/java/com/loopers/domain/like/LikeRepository.java
new file mode 100644
index 000000000..945b10235
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/like/LikeRepository.java
@@ -0,0 +1,25 @@
+package com.loopers.domain.like;
+
+import java.util.Optional;
+
+/**
+ * packageName : com.loopers.domain.like
+ * fileName     : LikeRepository
+ * author      : byeonsungmun
+ * date        : 2025. 11. 12.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 12.     byeonsungmun       최초 생성
+ */
+public interface LikeRepository {
+
+    Optional<Like> findByUserIdAndProductId(String userId, Long productId);
+
+    void save(Like like);
+
+    void delete(Like like);
+
+    long countByProductId(Long productId);
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/like/LikeService.java b/apps/commerce-api/src/main/java/com/loopers/domain/like/LikeService.java
new file mode 100644
index 000000000..41ae90b6a
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/like/LikeService.java
@@ -0,0 +1,49 @@
+package com.loopers.domain.like;
+
+import com.loopers.domain.product.ProductRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * packageName : com.loopers.application.like
+ * fileName     : LikeService
+ * author      : byeonsungmun
+ * date        : 2025. 11. 12.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 12.     byeonsungmun       최초 생성
+ */
+@Component
+@RequiredArgsConstructor
+public class LikeService {
+
+    private final LikeRepository likeRepository;
+    private final ProductRepository productRepository;
+
+    @Transactional
+    public void like(String userId, Long productId) {
+        if (likeRepository.findByUserIdAndProductId(userId, productId).isPresent()) return;
+
+        Like like = Like.create(userId, productId);
+        likeRepository.save(like);
+        productRepository.incrementLikeCount(productId);
+    }
+
+    @Transactional
+    public void unlike(String userId, Long productId) {
+        likeRepository.findByUserIdAndProductId(userId, productId)
+                .ifPresent(like -> {
+                    likeRepository.delete(like);
+                    productRepository.decrementLikeCount(productId);
+                });
+    }
+
+    @Transactional(readOnly = true)
+    public long countByProductId(Long productId) {
+        return likeRepository.countByProductId(productId);
+    }
+
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/like/LikeJpaRepository.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/like/LikeJpaRepository.java
new file mode 100644
index 000000000..865a30db7
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/infrastructure/like/LikeJpaRepository.java
@@ -0,0 +1,23 @@
+package com.loopers.infrastructure.like;
+
+import com.loopers.domain.like.Like;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.Optional;
+
+/**
+ * packageName : com.loopers.infrastructure.like
+ * fileName     : LikeJpaRepository
+ * author      : byeonsungmun
+ * date        : 2025. 11. 12.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 12.     byeonsungmun       최초 생성
+ */
+public interface LikeJpaRepository extends JpaRepository<Like, Long> {
+    Optional<Like> findByUserIdAndProductId(String userId, Long productId);
+
+    long countByProductId(Long productId);
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/like/LikeRepositoryImpl.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/like/LikeRepositoryImpl.java
new file mode 100644
index 000000000..e037b6efb
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/infrastructure/like/LikeRepositoryImpl.java
@@ -0,0 +1,46 @@
+package com.loopers.infrastructure.like;
+
+import com.loopers.domain.like.Like;
+import com.loopers.domain.like.LikeRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+import java.util.Optional;
+
+/**
+ * packageName : com.loopers.infrastructure.like
+ * fileName     : LikeRepositoryImpl
+ * author      : byeonsungmun
+ * date        : 2025. 11. 12.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 12.     byeonsungmun       최초 생성
+ */
+@Component
+@RequiredArgsConstructor
+public class LikeRepositoryImpl implements LikeRepository {
+
+    private final LikeJpaRepository likeJpaRepository;
+
+    @Override
+    public Optional<Like> findByUserIdAndProductId(String userId, Long productId) {
+        return likeJpaRepository.findByUserIdAndProductId(userId, productId);
+    }
+
+    @Override
+    public void save(Like like) {
+        likeJpaRepository.save(like);
+    }
+
+    @Override
+    public void delete(Like like) {
+        likeJpaRepository.delete(like);
+    }
+
+    @Override
+    public long countByProductId(Long productId) {
+        return likeJpaRepository.countByProductId(productId);
+    }
+}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/like/LikeServiceIntegrationTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/like/LikeServiceIntegrationTest.java
new file mode 100644
index 000000000..0be07a6fb
--- /dev/null
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/like/LikeServiceIntegrationTest.java
@@ -0,0 +1,155 @@
+package com.loopers.domain.like;
+
+import com.loopers.domain.product.Product;
+import com.loopers.domain.product.ProductRepository;
+import com.loopers.domain.user.User;
+import com.loopers.domain.user.UserRepository;
+import com.loopers.utils.DatabaseCleanUp;
+import org.junit.jupiter.api.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.transaction.annotation.Transactional;
+
+import static org.assertj.core.api.Assertions.*;
+
+/**
+ * packageName : com.loopers.domain.like
+ * fileName     : LikeServiceIntegrationTest
+ * author      : byeonsungmun
+ * date        : 2025. 11. 14.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 14.     byeonsungmun       최초 생성
+ */
+@SpringBootTest
+class LikeServiceIntegrationTest {
+
+    @Autowired
+    private LikeService likeService;
+
+    @Autowired
+    private LikeRepository likeRepository;
+
+    @Autowired
+    private ProductRepository productRepository;
+
+    @Autowired
+    private UserRepository userRepository;
+
+    @Autowired
+    private DatabaseCleanUp cleanUp;
+
+    @AfterEach
+    void tearDown() {
+        cleanUp.truncateAllTables();
+    }
+
+    @Nested
+    @DisplayName("좋아요 기능 통합 테스트")
+    class LikeTests {
+
+        @Test
+        @DisplayName("좋아요 생성 성공 → 좋아요 저장 + 상품의 likeCount 증가")
+        @Transactional
+        void likeSuccess() {
+            // given
+            User user = userRepository.save(new User("user1", "u1@mail.com", "1990-01-01", "MALE"));
+            Product product = productRepository.save(Product.create(1L, "상품A", 1000L, 10L));
+
+            // when
+            likeService.like(user.getUserId(), product.getId());
+
+            // then
+            Like saved = likeRepository.findByUserIdAndProductId("user1", 1L).orElse(null);
+            assertThat(saved).isNotNull();
+
+            Product updated = productRepository.findById(1L).get();
+            assertThat(updated.getLikeCount()).isEqualTo(1L);
+        }
+
+        @Test
+        @DisplayName("중복 좋아요 시 likeCount 증가 안 하고 저장도 안 됨")
+        @Transactional
+        void duplicateLike() {
+            // given
+            userRepository.save(new User("user1", "u1@mail.com", "1990-01-01", "MALE"));
+            productRepository.save(Product.create(1L, "상품A", 1000L, 10L));
+
+            likeService.like("user1", 1L);
+
+            // when
+            likeService.like("user1", 1L); // 중복 호출
+
+            // then
+            long likeCount = likeRepository.countByProductId(1L);
+            assertThat(likeCount).isEqualTo(1L);
+
+            Product updated = productRepository.findById(1L).get();
+            assertThat(updated.getLikeCount()).isEqualTo(1L); // 증가 X
+        }
+
+        @Test
+        @DisplayName("좋아요 취소 성공 → like 삭제 + 상품의 likeCount 감소")
+        @Transactional
+        void unlikeSuccess() {
+            // given
+            userRepository.save(new User("user1", "u1@mail.com", "1990-01-01", "MALE"));
+            productRepository.save(Product.create(1L, "상품A", 1000L, 10L));
+
+            likeService.like("user1", 1L);
+
+            // when
+            likeService.unlike("user1", 1L);
+
+            // then
+            Like like = likeRepository.findByUserIdAndProductId("user1", 1L).orElse(null);
+            assertThat(like).isNull();
+
+            Product updated = productRepository.findById(1L).get();
+            assertThat(updated.getLikeCount()).isEqualTo(0L);
+        }
+
+        @Test
+        @DisplayName("없는 좋아요 취소 시 likeCount 감소 안 함")
+        @Transactional
+        void unlikeNonExisting() {
+            // given
+            userRepository.save(new User("user1", "u1@mail.com", "1990-01-01", "MALE"));
+            Product product = Product.create(1L, "상품A", 1000L, 10L);
+            product.increaseLikeCount();
+            product.increaseLikeCount();
+            product.increaseLikeCount();
+            product.increaseLikeCount();
+            product.increaseLikeCount();
+
+            productRepository.save(product);
+            // when — 호출은 해도
+            likeService.unlike("user1", 1L);
+
+            // then — 변화 없음
+            Product updated = productRepository.findById(1L).get();
+            assertThat(updated.getLikeCount()).isEqualTo(5L);
+        }
+
+        @Test
+        @DisplayName("countByProductId 정상 조회")
+        @Transactional
+        void countTest() {
+            // given
+            userRepository.save(new User("user1", "u1@mail.com", "1990-01-01", "MALE"));
+            userRepository.save(new User("user2", "u2@mail.com", "1991-01-01", "MALE"));
+            productRepository.save(Product.create(1L, "상품A", 1000L, 10L));
+
+            likeService.like("user1", 1L);
+            likeService.like("user2", 1L);
+
+            // when
+            long count = likeService.countByProductId(1L);
+
+            // then
+            assertThat(count).isEqualTo(2L);
+        }
+    }
+}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/like/LikeTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/like/LikeTest.java
new file mode 100644
index 000000000..d5b8bd851
--- /dev/null
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/like/LikeTest.java
@@ -0,0 +1,91 @@
+package com.loopers.domain.like;
+
+import com.loopers.support.error.CoreException;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDateTime;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * packageName : com.loopers.domain.like
+ * fileName     : LikeTest
+ * author      : byeonsungmun
+ * date        : 2025. 11. 13.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 13.     byeonsungmun       최초 생성
+ */
+class LikeTest {
+
+
+    @DisplayName("정상적으로 Like 엔티티를 생성수 할 있다")
+    @Nested
+    class LikeCreate {
+
+        @DisplayName("Like생성자를 생성한다")
+        @Test
+        void createLike_success() {
+            // given
+            String userId = "user-001";
+            Long productId = 100L;
+
+            // when
+            Like like = Like.create(userId, productId);
+
+            // then
+            assertThat(like.getUserId()).isEqualTo(userId);
+            assertThat(like.getProductId()).isEqualTo(productId);
+            assertThat(like.getCreatedAt()).isBeforeOrEqualTo(LocalDateTime.now());
+        }
+
+        @Test
+        @DisplayName("userId가 null이면 예외가 발생한다")
+        void createLike_invalidUserId_null() {
+            // given
+            String userId = null;
+            Long productId = 100L;
+
+            // when & then
+            assertThrows(CoreException.class, () -> Like.create(userId, productId));
+        }
+
+        @Test
+        @DisplayName("userId가 빈 문자열이면 예외가 발생한다")
+        void createLike_invalidUserId_empty() {
+            // given
+            String userId = "";
+            Long productId = 100L;
+
+            // when & then
+            assertThrows(CoreException.class, () -> Like.create(userId, productId));
+        }
+
+        @Test
+        @DisplayName("productId가 null이면 예외가 발생한다")
+        void createLike_invalidProductId_null() {
+            // given
+            String userId = "user-001";
+            Long productId = null;
+
+            // when & then
+            assertThrows(CoreException.class, () -> Like.create(userId, productId));
+        }
+
+        @Test
+        @DisplayName("productId가 0 이하이면 예외가 발생한다")
+        void createLike_invalidProductId_zeroOrNegative() {
+            // given
+            String userId = "user-001";
+            Long productId = -1L;
+
+            // when & then
+            assertThrows(CoreException.class, () -> Like.create(userId, productId));
+        }
+    }
+}

From 1087ea25cc8da37b4a565b7131ab9418aabd157f Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Fri, 14 Nov 2025 16:59:26 +0900
Subject: [PATCH 38/40] =?UTF-8?q?feat(order,=20point):=20=EC=A3=BC?=
 =?UTF-8?q?=EB=AC=B8=20=EC=83=9D=EC=84=B1=20=EC=9C=A0=EC=8A=A4=EC=BC=80?=
 =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EB=B0=8F=20=ED=8F=AC=EC=9D=B8=ED=8A=B8=20?=
 =?UTF-8?q?=EC=B0=A8=EA=B0=90=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=EA=B5=AC?=
 =?UTF-8?q?=ED=98=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

- Order / OrderItem 엔티티 구현
- 상품 재고 차감, 포인트 차감 도메인 로직 추가
- Order 도메인 서비스 + Facade 조합 구현
- OrderRepository, PointRepository 인터페이스 정의
- 정상 주문/재고부족 포인트/부족 단위 / 통합 테스트 작성
---
 .../application/order/CreateOrderCommand.java |  19 ++
 .../application/order/OrderFacade.java        |  83 +++++++++
 .../loopers/application/order/OrderInfo.java  |  42 +++++
 .../application/order/OrderItemCommand.java   |  17 ++
 .../application/order/OrderItemInfo.java      |  32 ++++
 .../loopers/application/point/PointInfo.java  |   2 +-
 .../java/com/loopers/domain/order/Order.java  |  85 +++++++++
 .../com/loopers/domain/order/OrderItem.java   |  91 ++++++++++
 .../loopers/domain/order/OrderRepository.java |  21 +++
 .../loopers/domain/order/OrderService.java    |  28 +++
 .../com/loopers/domain/order/OrderStatus.java |  42 +++++
 .../java/com/loopers/domain/point/Point.java  |  31 +++-
 .../loopers/domain/point/PointService.java    |  17 ++
 .../order/OrderJpaRepository.java             |  18 ++
 .../order/OrderRepositoryImpl.java            |  36 ++++
 .../point/PointRepositoryImpl.java            |   3 +-
 .../order/OrderServiceIntegrationTest.java    | 170 ++++++++++++++++++
 .../com/loopers/domain/order/OrderTest.java   | 122 +++++++++++++
 .../point/PointServiceIntegrationTest.java    |  19 +-
 .../com/loopers/domain/point/PointTest.java   | 111 ++++++++++--
 .../api/point/PointV1ControllerTest.java      |   4 +-
 21 files changed, 969 insertions(+), 24 deletions(-)
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/application/order/CreateOrderCommand.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/application/order/OrderFacade.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/application/order/OrderInfo.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/application/order/OrderItemCommand.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/application/order/OrderItemInfo.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/order/Order.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/order/OrderItem.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/order/OrderRepository.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/order/OrderService.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/order/OrderStatus.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/order/OrderJpaRepository.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/order/OrderRepositoryImpl.java
 create mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/order/OrderServiceIntegrationTest.java
 create mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/order/OrderTest.java

diff --git a/apps/commerce-api/src/main/java/com/loopers/application/order/CreateOrderCommand.java b/apps/commerce-api/src/main/java/com/loopers/application/order/CreateOrderCommand.java
new file mode 100644
index 000000000..683e39cdd
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/application/order/CreateOrderCommand.java
@@ -0,0 +1,19 @@
+package com.loopers.application.order;
+
+import java.util.List;
+
+/**
+ * packageName : com.loopers.application.order
+ * fileName     : CreateOrderCommand
+ * author      : byeonsungmun
+ * date        : 2025. 11. 14.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 14.     byeonsungmun       최초 생성
+ */
+public record CreateOrderCommand(
+        String userId,
+        List<OrderItemCommand> items
+) {}
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/order/OrderFacade.java b/apps/commerce-api/src/main/java/com/loopers/application/order/OrderFacade.java
new file mode 100644
index 000000000..9e06282b4
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/application/order/OrderFacade.java
@@ -0,0 +1,83 @@
+package com.loopers.application.order;
+
+import com.loopers.domain.order.Order;
+import com.loopers.domain.order.OrderItem;
+import com.loopers.domain.order.OrderService;
+import com.loopers.domain.order.OrderStatus;
+import com.loopers.domain.point.Point;
+import com.loopers.domain.point.PointService;
+import com.loopers.domain.product.Product;
+import com.loopers.domain.product.ProductService;
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * packageName : com.loopers.application.order
+ * fileName     : OrderFacade
+ * author      : byeonsungmun
+ * date        : 2025. 11. 13.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 13.     byeonsungmun       최초 생성
+ */
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class OrderFacade {
+
+    private final OrderService orderService;
+    private final ProductService productService;
+    private final PointService pointService;
+
+    @Transactional
+    public OrderInfo createOrder(CreateOrderCommand command) {
+
+        if (command == null || command.items() == null || command.items().isEmpty()) {
+            throw new CoreException(ErrorType.NOT_FOUND, "상품 정보가 비어있습니다");
+        }
+
+        Order order = Order.create(command.userId());
+
+        for (OrderItemCommand itemCommand : command.items()) {
+
+            //상품가져오고
+            Product product = productService.getProduct(itemCommand.productId());
+
+            // 재고감소
+            product.decreaseStock(itemCommand.quantity());
+
+            // OrderItem생성
+            OrderItem orderItem = OrderItem.create(
+                    product.getId(),
+                    product.getName(),
+                    itemCommand.quantity(),
+                    product.getPrice());
+
+            order.addOrderItem(orderItem);
+            orderItem.setOrder(order);
+        }
+
+        //총 가격구하고
+        long totalAmount = order.getOrderItems().stream()
+                .mapToLong(OrderItem::getAmount)
+                .sum();
+
+        order.updateTotalAmount(totalAmount);
+
+        Point point = pointService.findPointByUserId(command.userId());
+        point.use(totalAmount);
+
+        //저장
+        Order saved = orderService.createOrder(order);
+        saved.updateStatus(OrderStatus.COMPLETE);
+
+        return OrderInfo.from(saved);
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/order/OrderInfo.java b/apps/commerce-api/src/main/java/com/loopers/application/order/OrderInfo.java
new file mode 100644
index 000000000..70028c27c
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/application/order/OrderInfo.java
@@ -0,0 +1,42 @@
+package com.loopers.application.order;
+
+import com.loopers.domain.order.Order;
+import com.loopers.domain.order.OrderStatus;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * packageName : com.loopers.application.order
+ * fileName     : OrderInfo
+ * author      : byeonsungmun
+ * date        : 2025. 11. 14.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 14.     byeonsungmun       최초 생성
+ */
+public record OrderInfo(
+        Long orderId,
+        String userId,
+        Long totalAmount,
+        OrderStatus status,
+        LocalDateTime createdAt,
+        List<OrderItemInfo> items
+) {
+    public static OrderInfo from(Order order) {
+        List<OrderItemInfo> itemInfos = order.getOrderItems().stream()
+                .map(OrderItemInfo::from)
+                .toList();
+
+        return new OrderInfo(
+                order.getId(),
+                order.getUserId(),
+                order.getTotalAmount(),
+                order.getStatus(),
+                order.getCreatedAt(),
+                itemInfos
+        );
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/order/OrderItemCommand.java b/apps/commerce-api/src/main/java/com/loopers/application/order/OrderItemCommand.java
new file mode 100644
index 000000000..1ac46862f
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/application/order/OrderItemCommand.java
@@ -0,0 +1,17 @@
+package com.loopers.application.order;
+
+/**
+ * packageName : com.loopers.application.order
+ * fileName     : OrderItemCommand
+ * author      : byeonsungmun
+ * date        : 2025. 11. 14.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 14.     byeonsungmun       최초 생성
+ */
+public record OrderItemCommand(
+        Long productId,
+        Long quantity
+) {}
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/order/OrderItemInfo.java b/apps/commerce-api/src/main/java/com/loopers/application/order/OrderItemInfo.java
new file mode 100644
index 000000000..b3f2359c6
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/application/order/OrderItemInfo.java
@@ -0,0 +1,32 @@
+package com.loopers.application.order;
+
+import com.loopers.domain.order.OrderItem;
+
+/**
+ * packageName : com.loopers.application.order
+ * fileName     : OrderInfo
+ * author      : byeonsungmun
+ * date        : 2025. 11. 13.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 13.     byeonsungmun       최초 생성
+ */
+public record OrderItemInfo(
+        Long productId,
+        String productName,
+        Long quantity,
+        Long price,
+        Long amount
+) {
+    public static OrderItemInfo from(OrderItem item) {
+        return new OrderItemInfo(
+                item.getProductId(),
+                item.getProductName(),
+                item.getQuantity(),
+                item.getPrice(),
+                item.getAmount()
+        );
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/point/PointInfo.java b/apps/commerce-api/src/main/java/com/loopers/application/point/PointInfo.java
index 2c357dc7e..65497297b 100644
--- a/apps/commerce-api/src/main/java/com/loopers/application/point/PointInfo.java
+++ b/apps/commerce-api/src/main/java/com/loopers/application/point/PointInfo.java
@@ -6,7 +6,7 @@ public record PointInfo(String userId, Long amount) {
     public static PointInfo from(Point info) {
         return new PointInfo(
                 info.getUserId(),
-                info.getAmount()
+                info.getBalance()
         );
     }
 
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/order/Order.java b/apps/commerce-api/src/main/java/com/loopers/domain/order/Order.java
new file mode 100644
index 000000000..9d7b9d3f2
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/order/Order.java
@@ -0,0 +1,85 @@
+package com.loopers.domain.order;
+
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
+import jakarta.persistence.*;
+import lombok.Getter;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * packageName : com.loopers.domain.order
+ * fileName     : Order
+ * author      : byeonsungmun
+ * date        : 2025. 11. 11.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 11.     byeonsungmun       최초 생성
+ */
+@Entity
+@Table(name = "orders")
+@Getter
+public class Order {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    @Column(name = "ref_user_id", nullable = false)
+    private String userId;
+
+    @Column(nullable = false)
+    private Long totalAmount;
+
+    @Enumerated(EnumType.STRING)
+    private OrderStatus status;
+
+    @Column(nullable = false)
+    private LocalDateTime createdAt;
+
+    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
+    private List<OrderItem> orderItems = new ArrayList<>();
+
+    protected Order() {}
+
+    private Order(String userId, OrderStatus status) {
+        this.userId = requiredValidUserId(userId);
+        this.totalAmount = 0L;
+        this.status = requiredValidStatus(status);
+        this.createdAt = LocalDateTime.now();
+    }
+
+    public static Order create(String userId) {
+        return new Order(userId, OrderStatus.PENDING);
+    }
+
+    public void addOrderItem(OrderItem orderItem) {
+        this.orderItems.add(orderItem);
+    }
+
+    private OrderStatus requiredValidStatus(OrderStatus status) {
+        if (status == null) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "주문 상태는 필수 입니다.");
+        }
+        return status;
+    }
+
+    private String requiredValidUserId(String userId) {
+        if (userId == null || userId.isEmpty()) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "사용자 ID는 필수 입니다.");
+        }
+        return userId;
+    }
+
+    public void updateTotalAmount(long totalAmount) {
+        this.totalAmount = totalAmount;
+    }
+
+    public void updateStatus(OrderStatus status) {
+        this.status = status;
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderItem.java b/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderItem.java
new file mode 100644
index 000000000..dce97a44a
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderItem.java
@@ -0,0 +1,91 @@
+package com.loopers.domain.order;
+
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
+import jakarta.persistence.*;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * packageName : com.loopers.domain.order
+ * fileName     : OrderItem
+ * author      : byeonsungmun
+ * date        : 2025. 11. 11.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 11.     byeonsungmun       최초 생성
+ */
+
+@Entity
+@Table(name = "order_item")
+@Getter
+public class OrderItem {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    @Setter
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "order_id", nullable = false)
+    private Order order;
+
+    @Column(name = "ref_product_id", nullable = false)
+    private Long productId;
+
+    @Column(name = "ref_product_name", nullable = false)
+    private String productName;
+
+    @Column(nullable = false)
+    private Long quantity;
+
+    @Column(nullable = false)
+    private Long price;
+
+    protected OrderItem() {}
+
+    private OrderItem(Long productId, String productName, Long quantity, Long price) {
+        this.productId = requiredValidProductId(productId);
+        this.productName = requiredValidProductName(productName);
+        this.quantity = requiredQuantity(quantity);
+        this.price = requiredPrice(price);
+    }
+
+    public static OrderItem create(Long productId, String productName, Long quantity, Long price) {
+        return new OrderItem(productId, productName, quantity, price);
+    }
+
+    public Long getAmount() {
+        return quantity * price;
+    }
+
+    private Long requiredValidProductId(Long productId) {
+        if (productId == null || productId <= 0)  {
+            throw new CoreException(ErrorType.BAD_REQUEST, "상품 ID는 필수입니다.");
+        }
+        return productId;
+    }
+
+    private String requiredValidProductName(String productName) {
+        if (productName == null || productName.isEmpty())  {
+            throw new CoreException(ErrorType.BAD_REQUEST, "상품명은 필수입니다.");
+        }
+        return productName;
+    }
+
+    private Long requiredQuantity(Long quantity) {
+        if (quantity == null || quantity <= 0)  {
+            throw new CoreException(ErrorType.BAD_REQUEST, "수량은 1개 이상이어야 합니다.");
+        }
+        return quantity;
+    }
+
+    private Long requiredPrice(Long price) {
+        if (price == null || price < 0)  {
+            throw new CoreException(ErrorType.BAD_REQUEST, "가격은 0원 이상이어야 합니다.");
+        }
+        return price;
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderRepository.java b/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderRepository.java
new file mode 100644
index 000000000..c80262041
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderRepository.java
@@ -0,0 +1,21 @@
+package com.loopers.domain.order;
+
+import java.util.Optional;
+
+/**
+ * packageName : com.loopers.domain.order
+ * fileName     : OrderRepository
+ * author      : byeonsungmun
+ * date        : 2025. 11. 13.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 13.     byeonsungmun       최초 생성
+ */
+public interface OrderRepository {
+
+    Order save(Order order);
+
+    Optional<Order> findById(Long orderId);
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderService.java b/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderService.java
new file mode 100644
index 000000000..a66be03d3
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderService.java
@@ -0,0 +1,28 @@
+package com.loopers.domain.order;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * packageName : com.loopers.domain.order
+ * fileName     : OrderService
+ * author      : byeonsungmun
+ * date        : 2025. 11. 13.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 13.     byeonsungmun       최초 생성
+ */
+@Component
+@RequiredArgsConstructor
+public class OrderService {
+
+    private final OrderRepository orderRepository;
+
+    @Transactional
+    public Order createOrder(Order order) {
+        return orderRepository.save(order);
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderStatus.java b/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderStatus.java
new file mode 100644
index 000000000..14ea592ef
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderStatus.java
@@ -0,0 +1,42 @@
+package com.loopers.domain.order;
+
+/**
+ * packageName : com.loopers.domain.order
+ * fileName     : OrderStatus
+ * author      : byeonsungmun
+ * date        : 2025. 11. 11.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 11.     byeonsungmun       최초 생성
+ */
+public enum OrderStatus {
+
+    COMPLETE("결제성공"),
+    CANCEL("결제취소"),
+    FAIL("결제실패"),
+    PENDING("결제중");
+
+    private final String description;
+
+    OrderStatus(String description) {
+        this.description = description;
+    }
+
+    public boolean isCompleted() {
+        return this == COMPLETE;
+    }
+
+    public boolean isPending() {
+        return this == PENDING;
+    }
+
+    public boolean isCanceled() {
+        return this == CANCEL;
+    }
+
+    public String description() {
+        return description;
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java b/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java
index b8f453f14..ea0c18c9d 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java
@@ -3,8 +3,7 @@
 import com.loopers.domain.BaseEntity;
 import com.loopers.support.error.CoreException;
 import com.loopers.support.error.ErrorType;
-import jakarta.persistence.Entity;
-import jakarta.persistence.Table;
+import jakarta.persistence.*;
 import lombok.Getter;
 
 @Entity
@@ -12,15 +11,23 @@
 @Getter
 public class Point extends BaseEntity {
 
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Id
+    private Long id;
+
     private String userId;
 
-    private Long amount;
+    private Long balance;
 
     protected Point() {}
 
-    public Point(String userId, Long amount) {
+    private Point(String userId, Long balance) {
         this.userId = requireValidUserId(userId);
-        this.amount = amount;
+        this.balance = balance;
+    }
+
+    public static Point create(String userId, Long balance) {
+        return new Point(userId, balance);
     }
 
     String requireValidUserId(String userId) {
@@ -34,7 +41,17 @@ public void charge(Long chargeAmount) {
         if (chargeAmount == null || chargeAmount <= 0) {
             throw new CoreException(ErrorType.BAD_REQUEST, "0원 이하로 포인트를 충전 할수 없습니다.");
         }
-        this.amount += chargeAmount;
-        new Point(this.userId, this.amount);
+        this.balance += chargeAmount;
+        new Point(this.userId, this.balance);
+    }
+
+    public void use(Long useAmount) {
+        if (useAmount == null || useAmount <= 0) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "0원 이하로 사용할 수 없습니다.");
+        }
+        if (this.balance < useAmount) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "포인트가 부족합니다.");
+        }
+        this.balance -= useAmount;
     }
 }
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java b/apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java
index dfc0788c6..1a6293f91 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java
@@ -23,4 +23,21 @@ public Point chargePoint(String userId, Long chargeAmount) {
         point.charge(chargeAmount);
         return pointRepository.save(point);
     }
+
+    @Transactional
+    public Point usePoint(String userId, Long useAmount) {
+        Point point = pointRepository.findByUserId(userId)
+                .orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "포인트 정보를 찾을 수 없습니다."));
+
+        if (useAmount == null || useAmount <= 0) {
+            throw new CoreException(ErrorType.NOT_FOUND, "차감할 포인트는 1 이상이어야 합니다.");
+        }
+
+        if (point.getBalance() < useAmount) {
+            throw new CoreException(ErrorType.NOT_FOUND, "포인트가 부족합니다.");
+        }
+
+        point.use(useAmount);
+        return pointRepository.save(point);
+    }
 }
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/order/OrderJpaRepository.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/order/OrderJpaRepository.java
new file mode 100644
index 000000000..39cfb136d
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/infrastructure/order/OrderJpaRepository.java
@@ -0,0 +1,18 @@
+package com.loopers.infrastructure.order;
+
+import com.loopers.domain.order.Order;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+/**
+ * packageName : com.loopers.infrastructure.order
+ * fileName     : OrderJpaRepository
+ * author      : byeonsungmun
+ * date        : 2025. 11. 14.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 14.     byeonsungmun       최초 생성
+ */
+public interface OrderJpaRepository extends JpaRepository<Order, Long> {
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/order/OrderRepositoryImpl.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/order/OrderRepositoryImpl.java
new file mode 100644
index 000000000..f8c7b5b68
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/infrastructure/order/OrderRepositoryImpl.java
@@ -0,0 +1,36 @@
+package com.loopers.infrastructure.order;
+
+import com.loopers.domain.order.Order;
+import com.loopers.domain.order.OrderRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+import java.util.Optional;
+
+/**
+ * packageName : com.loopers.infrastructure.order
+ * fileName     : OrderRepositroyImpl
+ * author      : byeonsungmun
+ * date        : 2025. 11. 14.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 14.     byeonsungmun       최초 생성
+ */
+@Component
+@RequiredArgsConstructor
+public class OrderRepositoryImpl implements OrderRepository {
+
+    private final OrderJpaRepository orderJpaRepository;
+
+    @Override
+    public Order save(Order order) {
+        return orderJpaRepository.save(order);
+    }
+
+    @Override
+    public Optional<Order> findById(Long orderId) {
+        return  orderJpaRepository.findById(orderId);
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointRepositoryImpl.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointRepositoryImpl.java
index 1663b1d4f..530191b66 100644
--- a/apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointRepositoryImpl.java
+++ b/apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointRepositoryImpl.java
@@ -20,7 +20,6 @@ public Optional<Point> findByUserId(String userId) {
 
     @Override
     public Point save(Point point) {
-        pointJpaRepository.save(point);
-        return point;
+        return pointJpaRepository.save(point);
     }
 }
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/order/OrderServiceIntegrationTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/order/OrderServiceIntegrationTest.java
new file mode 100644
index 000000000..149e71540
--- /dev/null
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/order/OrderServiceIntegrationTest.java
@@ -0,0 +1,170 @@
+package com.loopers.domain.order;
+
+import com.loopers.application.order.CreateOrderCommand;
+import com.loopers.application.order.OrderFacade;
+import com.loopers.application.order.OrderInfo;
+import com.loopers.application.order.OrderItemCommand;
+import com.loopers.domain.point.Point;
+import com.loopers.domain.point.PointRepository;
+import com.loopers.domain.product.Product;
+import com.loopers.domain.product.ProductRepository;
+import com.loopers.utils.DatabaseCleanUp;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+/**
+ * packageName : com.loopers.domain.order
+ * fileName     : OrderServiceIntegrationTest
+ * author      : byeonsungmun
+ * date        : 2025. 11. 14.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 14.     byeonsungmun       최초 생성
+ */
+@SpringBootTest
+public class OrderServiceIntegrationTest {
+
+    @Autowired
+    private OrderFacade orderFacade;
+
+    @Autowired
+    private ProductRepository productRepository;
+
+    @Autowired
+    private PointRepository pointRepository;
+
+    @Autowired
+    private OrderRepository orderRepository;
+
+    @Autowired
+    private DatabaseCleanUp databaseCleanUp;
+
+    @AfterEach
+    void tearDown() {
+        databaseCleanUp.truncateAllTables();
+    }
+
+    @Nested
+    @DisplayName("주문 생성 성공")
+    class OrderCreateSuccess {
+
+        @Test
+        @Transactional
+        void createOrder_success() {
+
+            // given
+            Product p1 = productRepository.save(Product.create(1L, "아메리카노", 3000L, 100L));
+            Product p2 = productRepository.save(Product.create(1L, "라떼", 4000L, 200L));
+
+            pointRepository.save(Point.create("user1", 20000L));
+
+            CreateOrderCommand command = new CreateOrderCommand(
+                    "user1",
+                    List.of(
+                            new OrderItemCommand(p1.getId(), 2L),  // 6000원
+                            new OrderItemCommand(p2.getId(), 1L)   // 4000원
+                    )
+            );
+
+            // when
+            OrderInfo info = orderFacade.createOrder(command);
+
+            // then
+            Order saved = orderRepository.findById(info.orderId()).orElseThrow();
+
+            assertThat(saved.getStatus()).isEqualTo(OrderStatus.COMPLETE);
+            assertThat(saved.getTotalAmount()).isEqualTo(10000L);
+            assertThat(saved.getOrderItems()).hasSize(2);
+
+            // 재고 감소 확인
+            Product updated1 = productRepository.findById(p1.getId()).get();
+            Product updated2 = productRepository.findById(p2.getId()).get();
+            assertThat(updated1.getStock()).isEqualTo(98);
+            assertThat(updated2.getStock()).isEqualTo(199);
+
+            // 포인트 감소 확인
+            Point point = pointRepository.findByUserId("user1").get();
+            assertThat(point.getBalance()).isEqualTo(10000L);  // 20000 - 10000
+
+        }
+    }
+
+    @Nested
+    @DisplayName("주문 실패 케이스")
+    class OrderCreateFail {
+
+        @Test
+        @Transactional
+        @DisplayName("재고 부족으로 실패")
+        void insufficientStock_fail() {
+            Product item = productRepository.save(Product.create(1L, "상품", 1000L, 1L));
+            pointRepository.save(Point.create("user1", 5000L));
+
+            CreateOrderCommand command = new CreateOrderCommand(
+                    "user1",
+                    List.of(new OrderItemCommand(item.getId(), 5L))
+            );
+
+            assertThatThrownBy(() -> orderFacade.createOrder(command))
+                    .isInstanceOf(RuntimeException.class); // 너의 도메인 예외 타입 맞춰도 됨
+        }
+
+        @Test
+        @Transactional
+        @DisplayName("포인트 부족으로 실패")
+        void insufficientPoint_fail() {
+            Product item = productRepository.save(Product.create(1L, "상품", 1000L, 10L));
+            pointRepository.save(Point.create("user1", 2000L)); // 부족
+
+            CreateOrderCommand command = new CreateOrderCommand(
+                    "user1",
+                    List.of(new OrderItemCommand(item.getId(), 5L)) // 총 5000원
+            );
+
+            assertThatThrownBy(() -> orderFacade.createOrder(command))
+                    .hasMessageContaining("포인트"); // 메시지 맞추면 더 정확하게 가능
+        }
+
+        @Test
+        @Transactional
+        @DisplayName("없는 상품 주문 시 실패")
+        void noProduct_fail() {
+            pointRepository.save(Point.create("user1", 10000L));
+
+            CreateOrderCommand command = new CreateOrderCommand(
+                    "user1",
+                    List.of(new OrderItemCommand(999L, 1L))
+            );
+
+            assertThatThrownBy(() -> orderFacade.createOrder(command))
+                    .isInstanceOf(RuntimeException.class);
+        }
+
+        @Test
+        @Transactional
+        @DisplayName("유저 포인트 정보 없으면 실패")
+        void noUserPoint_fail() {
+            Product item = productRepository.save(Product.create(1L, "상품", 1000L, 10L));
+
+            CreateOrderCommand command = new CreateOrderCommand(
+                    "user1",
+                    List.of(new OrderItemCommand(item.getId(), 1L))
+            );
+
+            assertThatThrownBy(() -> orderFacade.createOrder(command))
+                    .isInstanceOf(RuntimeException.class);
+        }
+    }
+}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/order/OrderTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/order/OrderTest.java
new file mode 100644
index 000000000..60ed16ecc
--- /dev/null
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/order/OrderTest.java
@@ -0,0 +1,122 @@
+package com.loopers.domain.order;
+
+import com.loopers.support.error.CoreException;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+/**
+ * packageName : com.loopers.domain.order
+ * fileName     : OrderTest
+ * author      : byeonsungmun
+ * date        : 2025. 11. 14.
+ * description :
+ * ===========================================
+ * DATE         AUTHOR       NOTE
+ * -------------------------------------------
+ * 2025. 11. 14.     byeonsungmun       최초 생성
+ */
+class OrderTest {
+
+    @Nested
+    @DisplayName("Order 생성 테스트")
+    class CreateOrderTest {
+
+        @Test
+        @DisplayName("주문 생성 성공")
+        void createOrderSuccess() {
+            // when
+            Order order = Order.create("user123");
+
+            // then
+            assertThat(order.getUserId()).isEqualTo("user123");
+            assertThat(order.getStatus()).isEqualTo(OrderStatus.PENDING);
+            assertThat(order.getTotalAmount()).isEqualTo(0L);
+            assertThat(order.getCreatedAt()).isNotNull();
+            assertThat(order.getOrderItems()).isEmpty();
+        }
+
+        @Test
+        @DisplayName("userId가 null이면 생성 실패")
+        void createOrderFailUserIdNull() {
+            assertThatThrownBy(() -> Order.create(null))
+                    .isInstanceOf(CoreException.class)
+                    .hasMessageContaining("사용자 ID는 필수");
+        }
+
+        @Test
+        @DisplayName("userId가 공백이면 생성 실패")
+        void createOrderFailUserIdBlank() {
+            assertThatThrownBy(() -> Order.create(""))
+                    .isInstanceOf(CoreException.class)
+                    .hasMessageContaining("사용자 ID는 필수");
+        }
+    }
+
+    @Nested
+    @DisplayName("Order 상태 업데이트 테스트")
+    class UpdateStatusTest {
+
+        @Test
+        @DisplayName("주문 상태 업데이트 성공")
+        void updateStatusSuccess() {
+            // given
+            Order order = Order.create("user123");
+
+            // when
+            order.updateStatus(OrderStatus.COMPLETE);
+
+            // then
+            assertThat(order.getStatus()).isEqualTo(OrderStatus.COMPLETE);
+        }
+    }
+
+    @Nested
+    @DisplayName("총액 업데이트 테스트")
+    class UpdateAmountTest {
+
+        @Test
+        @DisplayName("총액 업데이트 성공")
+        void updateTotalAmountSuccess() {
+            // given
+            Order order = Order.create("user123");
+
+            // when
+            order.updateTotalAmount(5000L);
+
+            // then
+            assertThat(order.getTotalAmount()).isEqualTo(5000L);
+        }
+    }
+
+    @Nested
+    @DisplayName("OrderItem 추가 테스트")
+    class AddOrderItemTest {
+
+        @Test
+        @DisplayName("OrderItem 추가 성공")
+        void addOrderItemSuccess() {
+            // given
+            Order order = Order.create("user123");
+
+            OrderItem item = OrderItem.create(
+                    1L,
+                    "상품명",
+                    2L,
+                    1000L
+            );
+
+            // when
+            order.addOrderItem(item);
+            item.setOrder(order);
+
+            // then
+            assertThat(order.getOrderItems()).hasSize(1);
+            assertThat(order.getOrderItems().getFirst().getProductName()).isEqualTo("상품명");
+            assertThat(item.getOrder()).isEqualTo(order);
+        }
+    }
+}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/point/PointServiceIntegrationTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/point/PointServiceIntegrationTest.java
index 882bca673..b623bc9c7 100644
--- a/apps/commerce-api/src/test/java/com/loopers/domain/point/PointServiceIntegrationTest.java
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/point/PointServiceIntegrationTest.java
@@ -49,14 +49,14 @@ void returnPointInfo_whenValidIdIsProvided() {
             String gender = "MALE";
 
             userRepository.save(new User(id, email, birth, gender));
-            pointRepository.save(new Point(id, 0L));
+            pointRepository.save(Point.create(id, 0L));
 
             //when
             Point result = pointService.findPointByUserId(id);
 
             //then
             assertThat(result.getUserId()).isEqualTo(id);
-            assertThat(result.getAmount()).isEqualTo(0L);
+            assertThat(result.getBalance()).isEqualTo(0L);
         }
 
         @DisplayName("회원이 존재 하지 않을 경우, null 이 반환된다.")
@@ -89,5 +89,20 @@ void throwsChargeAmountFailException_whenUserIDIsNotProvided() {
             //then
             assertThat(exception.getErrorType()).isEqualTo(ErrorType.NOT_FOUND);
         }
+
+        @Test
+        @DisplayName("회원이 존재하면 포인트 충전 성공")
+        void chargeSuccess() {
+            // given
+            String userId = "user2";
+            userRepository.save(new User(userId, "yh45g@loopers.com", "1994-12-05", "MALE"));
+            pointRepository.save(Point.create(userId, 1000L));
+
+            // when
+            Point updated = pointService.chargePoint(userId, 500L);
+
+            // then
+            assertThat(updated.getBalance()).isEqualTo(1500L);
+        }
     }
 }
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/point/PointTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/point/PointTest.java
index 81bedab7d..f33fb2821 100644
--- a/apps/commerce-api/src/test/java/com/loopers/domain/point/PointTest.java
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/point/PointTest.java
@@ -5,21 +5,112 @@
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
 
 class PointTest {
-    @DisplayName("Point 단위 테스트")
+
+    @Nested
+    @DisplayName("포인트 생성 테스트")
+    class CreatePointTest {
+
+        @Test
+        @DisplayName("포인트 생성 성공")
+        void createPointSuccess() {
+            // when
+            Point point = Point.create("user123", 100L);
+
+            // then
+            assertThat(point.getUserId()).isEqualTo("user123");
+            assertThat(point.getBalance()).isEqualTo(100L);
+        }
+
+        @Test
+        @DisplayName("userId가 null이면 생성 실패")
+        void createPointFailUserIdNull() {
+            assertThatThrownBy(() -> Point.create(null, 100L))
+                    .isInstanceOf(CoreException.class)
+                    .hasMessageContaining("사용자 ID가 비어있을 수 없습니다.");
+        }
+
+        @Test
+        @DisplayName("userId가 공백이면 생성 실패")
+        void createPointFailUserIdBlank() {
+            assertThatThrownBy(() -> Point.create("", 100L))
+                    .isInstanceOf(CoreException.class)
+                    .hasMessageContaining("사용자 ID가 비어있을 수 없습니다.");
+        }
+    }
+
+    @Nested
+    @DisplayName("포인트 충전 테스트")
+    class ChargePointTest {
+
+        @Test
+        @DisplayName("포인트 충전 성공")
+        void chargeSuccess() {
+            // given
+            Point point = Point.create("user123", 100L);
+
+            // when
+            point.charge(50L);
+
+            // then
+            assertThat(point.getBalance()).isEqualTo(150L);
+        }
+
+        @Test
+        @DisplayName("포인트 충전 실패 - 0 이하 입력")
+        void chargeFailZeroOrNegative() {
+            Point point = Point.create("user123", 100L);
+
+            assertThatThrownBy(() -> point.charge(0L))
+                    .isInstanceOf(CoreException.class)
+                    .hasMessageContaining("충전");
+
+            assertThatThrownBy(() -> point.charge(-10L))
+                    .isInstanceOf(CoreException.class);
+        }
+    }
+
     @Nested
-    class Charge {
-        @DisplayName("0 이하의 정수로 포인트를 충전 시 실패한다.")
+    @DisplayName("포인트 사용 테스트")
+    class UsePointTest {
+
+        @Test
+        @DisplayName("포인트 사용 성공")
+        void useSuccess() {
+            // given
+            Point point = Point.create("user123", 100L);
+
+            // when
+            point.use(40L);
+
+            // then
+            assertThat(point.getBalance()).isEqualTo(60L);
+        }
+
+        @Test
+        @DisplayName("포인트 사용 실패 - 0 이하 입력")
+        void useFailZeroOrNegative() {
+            Point point = Point.create("user123", 100L);
+
+            assertThatThrownBy(() -> point.use(0L))
+                    .isInstanceOf(CoreException.class)
+                    .hasMessageContaining("사용할 수 없습니다.");
+
+            assertThatThrownBy(() -> point.use(-10L))
+                    .isInstanceOf(CoreException.class);
+        }
+
         @Test
-        void throwsChargeAmountFailException_whenZeroAmountOrNegative() {
-            //given
-            Point point = new Point("yh45g", 0L);
+        @DisplayName("포인트 사용 실패 - 잔액 부족")
+        void useFailNotEnough() {
+            Point point = Point.create("user123", 50L);
 
-            //when&then
-            assertThrows(CoreException.class, () ->
-                    point.charge(0L));
+            assertThatThrownBy(() -> point.use(100L))
+                    .isInstanceOf(CoreException.class)
+                    .hasMessageContaining("포인트가 부족");
         }
     }
 
diff --git a/apps/commerce-api/src/test/java/com/loopers/interfaces/api/point/PointV1ControllerTest.java b/apps/commerce-api/src/test/java/com/loopers/interfaces/api/point/PointV1ControllerTest.java
index b725fd807..7d7a2c18c 100644
--- a/apps/commerce-api/src/test/java/com/loopers/interfaces/api/point/PointV1ControllerTest.java
+++ b/apps/commerce-api/src/test/java/com/loopers/interfaces/api/point/PointV1ControllerTest.java
@@ -58,7 +58,7 @@ void returnPoint_whenValidUserIdIsProvided() {
             Long amount = 1000L;
 
             userRepository.save(new User(id, email, birth, gender));
-            pointRepository.save(new Point(id, amount));
+            pointRepository.save(Point.create(id, amount));
 
             HttpHeaders headers = new HttpHeaders();
             headers.add("X-USER-ID", id);
@@ -112,7 +112,7 @@ void returnsTotalPoint_whenChargeUserPoint() {
             String gender = "MALE";
 
             userRepository.save(new User(id, email, birth, gender));
-            pointRepository.save(new Point(id, 0L));
+            pointRepository.save(Point.create(id, 0L));
 
             PointV1Dto.ChargePointRequest request = new PointV1Dto.ChargePointRequest(id, 1000L);
 

From c5754ffe7e7c4d2aeff7ad026181f823d5f55896 Mon Sep 17 00:00:00 2001
From: adminhelper <201401339hs@gmail.com>
Date: Tue, 18 Nov 2025 01:02:46 +0900
Subject: [PATCH 39/40] =?UTF-8?q?fix=20:=20PR=EC=BD=94=EB=93=9C=20?=
 =?UTF-8?q?=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../loopers/application/like/LikeFacade.java  |  2 --
 .../application/order/OrderFacade.java        |  6 ++--
 .../application/product/ProductFacade.java    |  6 ++--
 .../java/com/loopers/domain/brand/Brand.java  |  2 +-
 .../loopers/domain/brand/BrandService.java    |  1 -
 .../java/com/loopers/domain/order/Order.java  |  1 +
 .../java/com/loopers/domain/point/Point.java  |  1 -
 .../loopers/domain/point/PointService.java    |  4 +--
 .../com/loopers/domain/product/Product.java   |  5 ++-
 .../domain/product/ProductDomainService.java  |  2 ++
 .../domain/product/ProductService.java        | 18 +++++++++--
 .../com/loopers/domain/user/UserService.java  |  2 +-
 .../brand/BrandJpaRepository.java             |  3 --
 .../product/ProductRepositoryImpl.java        |  8 +++--
 .../user/UserRepositoryImpl.java              |  3 +-
 .../interfaces/api/point/PointV1ApiSpec.java  |  2 +-
 .../com/loopers/domain/user/UserTest.java     |  6 ++--
 docs/2round/03-class-diagram.md               |  6 ----
 docs/3round/3round.md                         | 32 +++++++++----------
 19 files changed, 59 insertions(+), 51 deletions(-)

diff --git a/apps/commerce-api/src/main/java/com/loopers/application/like/LikeFacade.java b/apps/commerce-api/src/main/java/com/loopers/application/like/LikeFacade.java
index 5d885672e..d9dd33205 100644
--- a/apps/commerce-api/src/main/java/com/loopers/application/like/LikeFacade.java
+++ b/apps/commerce-api/src/main/java/com/loopers/application/like/LikeFacade.java
@@ -3,7 +3,6 @@
 import com.loopers.domain.like.LikeService;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Component;
-import org.springframework.transaction.annotation.Transactional;
 
 /**
  * packageName : com.loopers.application.like
@@ -18,7 +17,6 @@
  */
 @Component
 @RequiredArgsConstructor
-@Transactional
 public class LikeFacade {
 
     private final LikeService likeService;
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/order/OrderFacade.java b/apps/commerce-api/src/main/java/com/loopers/application/order/OrderFacade.java
index 9e06282b4..2fba4b4aa 100644
--- a/apps/commerce-api/src/main/java/com/loopers/application/order/OrderFacade.java
+++ b/apps/commerce-api/src/main/java/com/loopers/application/order/OrderFacade.java
@@ -4,7 +4,6 @@
 import com.loopers.domain.order.OrderItem;
 import com.loopers.domain.order.OrderService;
 import com.loopers.domain.order.OrderStatus;
-import com.loopers.domain.point.Point;
 import com.loopers.domain.point.PointService;
 import com.loopers.domain.product.Product;
 import com.loopers.domain.product.ProductService;
@@ -40,7 +39,7 @@ public class OrderFacade {
     public OrderInfo createOrder(CreateOrderCommand command) {
 
         if (command == null || command.items() == null || command.items().isEmpty()) {
-            throw new CoreException(ErrorType.NOT_FOUND, "상품 정보가 비어있습니다");
+            throw new CoreException(ErrorType.BAD_REQUEST, "상품 정보가 비어있습니다");
         }
 
         Order order = Order.create(command.userId());
@@ -71,8 +70,7 @@ public OrderInfo createOrder(CreateOrderCommand command) {
 
         order.updateTotalAmount(totalAmount);
 
-        Point point = pointService.findPointByUserId(command.userId());
-        point.use(totalAmount);
+        pointService.usePoint(command.userId(), totalAmount);
 
         //저장
         Order saved = orderService.createOrder(order);
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/product/ProductFacade.java b/apps/commerce-api/src/main/java/com/loopers/application/product/ProductFacade.java
index 7b83360e7..e6a25de23 100644
--- a/apps/commerce-api/src/main/java/com/loopers/application/product/ProductFacade.java
+++ b/apps/commerce-api/src/main/java/com/loopers/application/product/ProductFacade.java
@@ -31,10 +31,10 @@ public class ProductFacade {
     private final LikeService likeService;
     private final ProductDomainService productDomainService;
 
-    public Page<ProductInfo> getProducts(Pageable pageable) {
-        return productService.getProducts(pageable)
+    public Page<ProductInfo> getProducts(String sort, Pageable pageable) {
+        return productService.getProducts(sort ,pageable)
                 .map(product ->  {
-                    Brand brand = brandService.getBrand(product.getId());
+                    Brand brand = brandService.getBrand(product.getBrandId());
                     long likeCount = likeService.countByProductId(product.getId());
                     return ProductInfo.of(product, brand, likeCount);
                 });
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/brand/Brand.java b/apps/commerce-api/src/main/java/com/loopers/domain/brand/Brand.java
index bacd46b25..d334ccebf 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/brand/Brand.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/brand/Brand.java
@@ -40,7 +40,7 @@ public static Brand create(String name) {
 
     private String requireValidName(String name) {
         if (name == null || name.isEmpty()) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "상품명 비어 있을수 없습니다.");
+            throw new CoreException(ErrorType.BAD_REQUEST, "브랜드명은 비어 있을 수 없습니다.");
         }
         return name.trim();
     }
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/brand/BrandService.java b/apps/commerce-api/src/main/java/com/loopers/domain/brand/BrandService.java
index 6aa724710..e0f58c77b 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/brand/BrandService.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/brand/BrandService.java
@@ -23,7 +23,6 @@ public class BrandService {
 
     private final BrandRepository brandRepository;
 
-    @Transactional
     public void save(Brand brand) {
         brandRepository.save(brand);
     }
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/order/Order.java b/apps/commerce-api/src/main/java/com/loopers/domain/order/Order.java
index 9d7b9d3f2..84f299c6b 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/order/Order.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/order/Order.java
@@ -58,6 +58,7 @@ public static Order create(String userId) {
     }
 
     public void addOrderItem(OrderItem orderItem) {
+        orderItem.setOrder(this);
         this.orderItems.add(orderItem);
     }
 
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java b/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java
index ea0c18c9d..bc28a902a 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java
@@ -42,7 +42,6 @@ public void charge(Long chargeAmount) {
             throw new CoreException(ErrorType.BAD_REQUEST, "0원 이하로 포인트를 충전 할수 없습니다.");
         }
         this.balance += chargeAmount;
-        new Point(this.userId, this.balance);
     }
 
     public void use(Long useAmount) {
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java b/apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java
index 1a6293f91..9c9570615 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java
@@ -30,11 +30,11 @@ public Point usePoint(String userId, Long useAmount) {
                 .orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "포인트 정보를 찾을 수 없습니다."));
 
         if (useAmount == null || useAmount <= 0) {
-            throw new CoreException(ErrorType.NOT_FOUND, "차감할 포인트는 1 이상이어야 합니다.");
+            throw new CoreException(ErrorType.BAD_REQUEST, "차감할 포인트는 1 이상이어야 합니다.");
         }
 
         if (point.getBalance() < useAmount) {
-            throw new CoreException(ErrorType.NOT_FOUND, "포인트가 부족합니다.");
+            throw new CoreException(ErrorType.BAD_REQUEST, "포인트가 부족합니다.");
         }
 
         point.use(useAmount);
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/product/Product.java b/apps/commerce-api/src/main/java/com/loopers/domain/product/Product.java
index cade20580..29968402f 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/product/Product.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/product/Product.java
@@ -83,7 +83,7 @@ private Long requireValidPrice(Long price) {
         return price;
     }
 
-    public Long requireValidLikeCount(Long likeCount) {
+    private Long requireValidLikeCount(Long likeCount) {
         if (likeCount == null || likeCount < 0) {
             throw new CoreException(ErrorType.BAD_REQUEST, "좋아요 개수는 0개 미만으로 설정할 수 없습니다.");
         }
@@ -91,6 +91,9 @@ public Long requireValidLikeCount(Long likeCount) {
     }
 
     private Long requireValidStock(Long stock) {
+        if (stock == null) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "상품 재고는 필수입니다.");
+        }
         if (stock < 0) {
             throw new CoreException(ErrorType.BAD_REQUEST, "상품 재고는 0 미만으로 설정할 수 없습니다.");
         }
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductDomainService.java b/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductDomainService.java
index f86edfddd..166aff66b 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductDomainService.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductDomainService.java
@@ -7,6 +7,7 @@
 import com.loopers.support.error.ErrorType;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
 
 /**
  * packageName : com.loopers.domain.product
@@ -27,6 +28,7 @@ public class ProductDomainService {
     private final BrandRepository brandRepository;
     private final LikeRepository likeRepository;
 
+    @Transactional(readOnly = true)
     public ProductDetail getProductDetail(Long id) {
         Product product = productRepository.findById(id)
                 .orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "상품을 찾을 수 없습니다."));
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductService.java b/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductService.java
index a9c03fc80..067f194ae 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductService.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductService.java
@@ -4,7 +4,9 @@
 import com.loopers.support.error.ErrorType;
 import lombok.RequiredArgsConstructor;
 import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
 import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -27,8 +29,20 @@ public class ProductService {
     private final ProductRepository productRepository;
 
     @Transactional(readOnly = true)
-    public Page<Product> getProducts(Pageable pageable) {
-        return productRepository.findAll(pageable);
+    public Page<Product> getProducts(String sort, Pageable pageable) {
+        Sort sortOption = switch (sort) {
+            case "price_asc" -> Sort.by("price").ascending();
+            case "likes_desc" -> Sort.by("likeCount").descending();
+            default -> Sort.by("createdAt").descending(); // latest
+        };
+
+        Pageable sortedPageable = PageRequest.of(
+                pageable.getPageNumber(),
+                pageable.getPageSize(),
+                sortOption
+        );
+
+        return productRepository.findAll(sortedPageable);
     }
 
     public Product getProduct(Long productId) {
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java
index 57353968a..3cc033076 100644
--- a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java
@@ -15,7 +15,7 @@ public class UserService {
     @Transactional
     public User register(String userId, String email, String birth, String gender) {
         userRepository.findByUserId(userId).ifPresent(user -> {
-            throw new CoreException(ErrorType.CONFLICT, "이미 가입된 사용자ID 입니다.");
+            throw new CoreException(ErrorType.CONFLICT, "이미 가입된 사용자 ID 입니다.");
         });
 
         User user = new User(userId, email, birth, gender);
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/brand/BrandJpaRepository.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/brand/BrandJpaRepository.java
index 111990a22..759f3caf1 100644
--- a/apps/commerce-api/src/main/java/com/loopers/infrastructure/brand/BrandJpaRepository.java
+++ b/apps/commerce-api/src/main/java/com/loopers/infrastructure/brand/BrandJpaRepository.java
@@ -3,8 +3,6 @@
 import com.loopers.domain.brand.Brand;
 import org.springframework.data.jpa.repository.JpaRepository;
 
-import java.util.Optional;
-
 /**
  * packageName : com.loopers.infrastructure.brand
  * fileName     : BrandJpaRepository
@@ -17,5 +15,4 @@
  * 2025. 11. 12.     byeonsungmun       최초 생성
  */
 public interface BrandJpaRepository extends JpaRepository<Brand, Long> {
-    Optional<Brand> findById(Long id);
 }
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/product/ProductRepositoryImpl.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/product/ProductRepositoryImpl.java
index ba0feb19c..dbad0d9d5 100644
--- a/apps/commerce-api/src/main/java/com/loopers/infrastructure/product/ProductRepositoryImpl.java
+++ b/apps/commerce-api/src/main/java/com/loopers/infrastructure/product/ProductRepositoryImpl.java
@@ -2,6 +2,8 @@
 
 import com.loopers.domain.product.Product;
 import com.loopers.domain.product.ProductRepository;
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
 import lombok.RequiredArgsConstructor;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
@@ -38,13 +40,15 @@ public Optional<Product> findById(Long id) {
 
     @Override
     public void incrementLikeCount(Long productId) {
-        Product product = productJpaRepository.findById(productId).get();
+        Product product = productJpaRepository.findById(productId)
+                .orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "상품을 찾을수 없습니다."));
         product.increaseLikeCount();
     }
 
     @Override
     public void decrementLikeCount(Long productId) {
-        Product product = productJpaRepository.findById(productId).get();
+        Product product = productJpaRepository.findById(productId)
+                .orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "상품을 찾을수 없습니다."));
         product.decreaseLikeCount();
     }
 
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserRepositoryImpl.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserRepositoryImpl.java
index 25f05bc6e..8fb6f7bdf 100644
--- a/apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserRepositoryImpl.java
+++ b/apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserRepositoryImpl.java
@@ -20,8 +20,7 @@ public Optional<User> findByUserId(String userId) {
 
     @Override
     public User save(User user) {
-        userJpaRepository.save(user);
-        return user;
+        return userJpaRepository.save(user);
     }
 }
 
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1ApiSpec.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1ApiSpec.java
index faa21f303..6f0458399 100644
--- a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1ApiSpec.java
+++ b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1ApiSpec.java
@@ -22,7 +22,7 @@ ApiResponse<PointV1Dto.PointResponse> getPoint(
             description = "회원의 포인트를 충전한다."
     )
     ApiResponse<PointV1Dto.PointResponse> chargePoint(
-            @Schema(name = "포인트 충전 요청", description = "조회할 회원 ID")
+            @Schema(name = "포인트 충전 요청", description = "충전할 포인트 정보를 포함한 요청")
             PointV1Dto.ChargePointRequest request
     );
 }
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserTest.java
index a8f8948ca..7d74fdfe2 100644
--- a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserTest.java
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserTest.java
@@ -42,12 +42,12 @@ void throwsException_whenInvalidEmailFormat() {
         void throwsException_whenInvalidBirthFormat() {
             // given
             String userId = "yh45g";
-            String invalidEmail = "invalid-email-format"; // '@' 없음
-            String birth = "1994-12-05";
+            String email = "valid@loopers.com";
+            String invalidBirth = "19941205"; // 형식 오류: 하이픈 없음
             String gender = "MALE";
 
             // when & then
-            assertThrows(CoreException.class, () -> new User(userId, invalidEmail, birth, gender));
+            assertThrows(CoreException.class, () -> new User(userId, email, invalidBirth, gender));
         }
     }
 }
diff --git a/docs/2round/03-class-diagram.md b/docs/2round/03-class-diagram.md
index 45421dc8b..8d39cfd0a 100644
--- a/docs/2round/03-class-diagram.md
+++ b/docs/2round/03-class-diagram.md
@@ -32,11 +32,6 @@ class Product {
   Long stock
 }
 
-class Stock {
-  Long productId
-  int quantity
-}
-
 class Like {
   Long id
   String userId
@@ -73,7 +68,6 @@ class Payment {
 %% 관계 설정
 User --> Point
 Brand --> Product
-Product --> Stock
 Product --> Like
 User --> Like 
 User --> Order 
diff --git a/docs/3round/3round.md b/docs/3round/3round.md
index 61df49f68..b9f333cca 100644
--- a/docs/3round/3round.md
+++ b/docs/3round/3round.md
@@ -24,7 +24,7 @@
 ## ✅ Checklist
 
 - [x]  상품 정보 객체는 브랜드 정보, 좋아요 수를 포함한다.
-- [ ]  상품의 정렬 조건(`latest`, `price_asc`, `likes_desc`) 을 고려한 조회 기능을 설계했다
+- [x]  상품의 정렬 조건(`latest`, `price_asc`, `likes_desc`) 을 고려한 조회 기능을 설계했다
 - [x]  상품은 재고를 가지고 있고, 주문 시 차감할 수 있어야 한다
 - [x]  재고는 감소만 가능하며 음수 방지는 도메인 레벨에서 처리된다
 
@@ -33,28 +33,28 @@
 - [x]  좋아요는 유저와 상품 간의 관계로 별도 도메인으로 분리했다
 - [x]  중복 좋아요 방지를 위한 멱등성 처리가 구현되었다
 - [x]  상품의 좋아요 수는 상품 상세/목록 조회에서 함께 제공된다
-- [ ]  단위 테스트에서 좋아요 등록/취소/중복 방지 흐름을 검증했다
+- [x]  단위 테스트에서 좋아요 등록/취소/중복 방지 흐름을 검증했다
 
 ### 🛒 Order 도메인
 
-- [ ]  주문은 여러 상품을 포함할 수 있으며, 각 상품의 수량을 명시한다
-- [ ]  주문 시 상품의 재고 차감, 유저 포인트 차감 등을 수행한다
-- [ ]  재고 부족, 포인트 부족 등 예외 흐름을 고려해 설계되었다
-- [ ]  단위 테스트에서 정상 주문 / 예외 주문 흐름을 모두 검증했다
+- [x]  주문은 여러 상품을 포함할 수 있으며, 각 상품의 수량을 명시한다
+- [x]  주문 시 상품의 재고 차감, 유저 포인트 차감 등을 수행한다
+- [x]  재고 부족, 포인트 부족 등 예외 흐름을 고려해 설계되었다
+- [x]  단위 테스트에서 정상 주문 / 예외 주문 흐름을 모두 검증했다
 
 ### 🧩 도메인 서비스
 
-- [ ]  도메인 간 협력 로직은 Domain Service에 위치시켰다
-- [ ]  상품 상세 조회 시 Product + Brand 정보 조합은 도메인 서비스에서 처리했다
-- [ ]  복합 유스케이스는 Application Layer에 존재하고, 도메인 로직은 위임되었다
-- [ ]  도메인 서비스는 상태 없이, 도메인 객체의 협력 중심으로 설계되었다
+- [x]  도메인 간 협력 로직은 Domain Service에 위치시켰다
+- [x]  상품 상세 조회 시 Product + Brand 정보 조합은 도메인 서비스에서 처리했다
+- [x]  복합 유스케이스는 Application Layer에 존재하고, 도메인 로직은 위임되었다
+- [x]  도메인 서비스는 상태 없이, 도메인 객체의 협력 중심으로 설계되었다
 
 ### **🧱 소프트웨어 아키텍처 & 설계**
 
-- [ ]  전체 프로젝트의 구성은 아래 아키텍처를 기반으로 구성되었다
+- [x]  전체 프로젝트의 구성은 아래 아키텍처를 기반으로 구성되었다
     - Application → **Domain** ← Infrastructure
-- [ ]  Application Layer는 도메인 객체를 조합해 흐름을 orchestration 했다
-- [ ]  핵심 비즈니스 로직은 Entity, VO, Domain Service 에 위치한다
-- [ ]  Repository Interface는 Domain Layer 에 정의되고, 구현체는 Infra에 위치한다
-- [ ]  패키지는 계층 + 도메인 기준으로 구성되었다 (`/domain/order`, `/application/like` 등)
-- [ ]  테스트는 외부 의존성을 분리하고, Fake/Stub 등을 사용해 단위 테스트가 가능하게 구성되었다
\ No newline at end of file
+- [x]  Application Layer는 도메인 객체를 조합해 흐름을 orchestration 했다
+- [x]  핵심 비즈니스 로직은 Entity, VO, Domain Service 에 위치한다
+- [x]  Repository Interface는 Domain Layer 에 정의되고, 구현체는 Infra에 위치한다
+- [x]  패키지는 계층 + 도메인 기준으로 구성되었다 (`/domain/order`, `/application/like` 등)
+- [x]  테스트는 외부 의존성을 분리하고, Fake/Stub 등을 사용해 단위 테스트가 가능하게 구성되었다
\ No newline at end of file

From be18c88a093c7086d9683b346c48376d5b6f687f Mon Sep 17 00:00:00 2001
From: BOB <56067193+adminhelper@users.noreply.github.com>
Date: Fri, 21 Nov 2025 16:55:58 +0900
Subject: [PATCH 40/40] =?UTF-8?q?Revert=20"[volume-3]=20=EB=8F=84=EB=A9=94?=
 =?UTF-8?q?=EC=9D=B8=20=EB=AA=A8=EB=8D=B8=EB=A7=81=20=EB=B0=8F=20=EA=B5=AC?=
 =?UTF-8?q?=ED=98=84"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../application/example/ExampleFacade.java    |  17 ++
 .../application/example/ExampleInfo.java      |  13 ++
 .../loopers/application/like/LikeFacade.java  |  32 ----
 .../application/order/CreateOrderCommand.java |  19 --
 .../application/order/OrderFacade.java        |  81 ---------
 .../loopers/application/order/OrderInfo.java  |  42 -----
 .../application/order/OrderItemCommand.java   |  17 --
 .../application/order/OrderItemInfo.java      |  32 ----
 .../application/point/PointFacade.java        |  28 ---
 .../loopers/application/point/PointInfo.java  |  13 --
 .../product/ProductDetailInfo.java            |  32 ----
 .../application/product/ProductFacade.java    |  47 -----
 .../application/product/ProductInfo.java      |  33 ----
 .../loopers/application/user/UserFacade.java  |  27 ---
 .../loopers/application/user/UserInfo.java    |  14 --
 .../java/com/loopers/domain/brand/Brand.java  |  47 -----
 .../loopers/domain/brand/BrandRepository.java |  20 ---
 .../loopers/domain/brand/BrandService.java    |  35 ----
 .../loopers/domain/example/ExampleModel.java  |  44 +++++
 .../domain/example/ExampleRepository.java     |   7 +
 .../domain/example/ExampleService.java        |  20 +++
 .../java/com/loopers/domain/like/Like.java    |  63 -------
 .../loopers/domain/like/LikeRepository.java   |  25 ---
 .../com/loopers/domain/like/LikeService.java  |  49 -----
 .../java/com/loopers/domain/order/Order.java  |  86 ---------
 .../com/loopers/domain/order/OrderItem.java   |  91 ----------
 .../loopers/domain/order/OrderRepository.java |  21 ---
 .../loopers/domain/order/OrderService.java    |  28 ---
 .../com/loopers/domain/order/OrderStatus.java |  42 -----
 .../java/com/loopers/domain/point/Point.java  |  56 ------
 .../loopers/domain/point/PointRepository.java |  10 --
 .../loopers/domain/point/PointService.java    |  43 -----
 .../com/loopers/domain/product/Product.java   | 120 -------------
 .../loopers/domain/product/ProductDetail.java |  45 -----
 .../domain/product/ProductDomainService.java  |  41 -----
 .../domain/product/ProductRepository.java     |  29 ---
 .../domain/product/ProductService.java        |  53 ------
 .../java/com/loopers/domain/user/User.java    |  82 ---------
 .../loopers/domain/user/UserRepository.java   |  10 --
 .../com/loopers/domain/user/UserService.java  |  30 ----
 .../brand/BrandJpaRepository.java             |  18 --
 .../brand/BrandRepositoryImpl.java            |  36 ----
 .../example/ExampleJpaRepository.java         |   6 +
 .../example/ExampleRepositoryImpl.java        |  19 ++
 .../like/LikeJpaRepository.java               |  23 ---
 .../like/LikeRepositoryImpl.java              |  46 -----
 .../order/OrderJpaRepository.java             |  18 --
 .../order/OrderRepositoryImpl.java            |  36 ----
 .../point/PointJpaRepository.java             |  11 --
 .../point/PointRepositoryImpl.java            |  25 ---
 .../product/ProductJpaRepository.java         |  19 --
 .../product/ProductRepositoryImpl.java        |  59 ------
 .../user/UserJpaRepository.java               |  11 --
 .../user/UserRepositoryImpl.java              |  26 ---
 .../api/example/ExampleV1ApiSpec.java         |  19 ++
 .../api/example/ExampleV1Controller.java      |  28 +++
 .../interfaces/api/example/ExampleV1Dto.java  |  15 ++
 .../interfaces/api/point/PointV1ApiSpec.java  |  28 ---
 .../api/point/PointV1Controller.java          |  31 ----
 .../interfaces/api/point/PointV1Dto.java      |  18 --
 .../interfaces/api/user/UserV1ApiSpec.java    |  28 ---
 .../interfaces/api/user/UserV1Controller.java |  31 ----
 .../interfaces/api/user/UserV1Dto.java        |  24 ---
 .../com/loopers/domain/brand/BrandTest.java   |  42 -----
 .../domain/example/ExampleModelTest.java      |  65 +++++++
 .../ExampleServiceIntegrationTest.java        |  72 ++++++++
 .../like/LikeServiceIntegrationTest.java      | 155 ----------------
 .../com/loopers/domain/like/LikeTest.java     |  91 ----------
 .../order/OrderServiceIntegrationTest.java    | 170 ------------------
 .../com/loopers/domain/order/OrderTest.java   | 122 -------------
 .../point/PointServiceIntegrationTest.java    | 108 -----------
 .../com/loopers/domain/point/PointTest.java   | 117 ------------
 .../ProductServiceIntegrationTest.java        |  43 -----
 .../loopers/domain/product/ProductTest.java   |  95 ----------
 .../user/UserServiceIntegrationTest.java      | 112 ------------
 .../com/loopers/domain/user/UserTest.java     |  53 ------
 .../interfaces/api/ExampleV1ApiE2ETest.java   | 114 ++++++++++++
 .../api/point/PointV1ControllerTest.java      | 156 ----------------
 .../api/user/UserV1ControllerTest.java        | 148 ---------------
 docs/1round/1round.md                         |  67 -------
 docs/2round/01-requirements.md                | 104 -----------
 docs/2round/02-sequence-diagrams.md           | 164 -----------------
 docs/2round/03-class-diagram.md               |  78 --------
 docs/2round/04-erd.md                         |  74 --------
 docs/2round/2round.md                         |  37 ----
 docs/3round/3round.md                         |  60 -------
 86 files changed, 439 insertions(+), 3927 deletions(-)
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/application/example/ExampleFacade.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/application/example/ExampleInfo.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/application/like/LikeFacade.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/application/order/CreateOrderCommand.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/application/order/OrderFacade.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/application/order/OrderInfo.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/application/order/OrderItemCommand.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/application/order/OrderItemInfo.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/application/point/PointFacade.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/application/point/PointInfo.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/application/product/ProductDetailInfo.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/application/product/ProductFacade.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/application/product/ProductInfo.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/application/user/UserFacade.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/application/user/UserInfo.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/brand/Brand.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/brand/BrandRepository.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/brand/BrandService.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleModel.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleRepository.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleService.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/like/Like.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/like/LikeRepository.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/like/LikeService.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/order/Order.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/order/OrderItem.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/order/OrderRepository.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/order/OrderService.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/order/OrderStatus.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/point/PointRepository.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/product/Product.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/product/ProductDetail.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/product/ProductDomainService.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/product/ProductRepository.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/product/ProductService.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/user/User.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/user/UserRepository.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/brand/BrandJpaRepository.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/brand/BrandRepositoryImpl.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/example/ExampleJpaRepository.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/example/ExampleRepositoryImpl.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/like/LikeJpaRepository.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/like/LikeRepositoryImpl.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/order/OrderJpaRepository.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/order/OrderRepositoryImpl.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointJpaRepository.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointRepositoryImpl.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/product/ProductJpaRepository.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/product/ProductRepositoryImpl.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserJpaRepository.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserRepositoryImpl.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1ApiSpec.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1Controller.java
 create mode 100644 apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1Dto.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1ApiSpec.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1Controller.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1Dto.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1ApiSpec.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Controller.java
 delete mode 100644 apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Dto.java
 delete mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/brand/BrandTest.java
 create mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/example/ExampleModelTest.java
 create mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/example/ExampleServiceIntegrationTest.java
 delete mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/like/LikeServiceIntegrationTest.java
 delete mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/like/LikeTest.java
 delete mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/order/OrderServiceIntegrationTest.java
 delete mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/order/OrderTest.java
 delete mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/point/PointServiceIntegrationTest.java
 delete mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/point/PointTest.java
 delete mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/product/ProductServiceIntegrationTest.java
 delete mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/product/ProductTest.java
 delete mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java
 delete mode 100644 apps/commerce-api/src/test/java/com/loopers/domain/user/UserTest.java
 create mode 100644 apps/commerce-api/src/test/java/com/loopers/interfaces/api/ExampleV1ApiE2ETest.java
 delete mode 100644 apps/commerce-api/src/test/java/com/loopers/interfaces/api/point/PointV1ControllerTest.java
 delete mode 100644 apps/commerce-api/src/test/java/com/loopers/interfaces/api/user/UserV1ControllerTest.java
 delete mode 100644 docs/1round/1round.md
 delete mode 100644 docs/2round/01-requirements.md
 delete mode 100644 docs/2round/02-sequence-diagrams.md
 delete mode 100644 docs/2round/03-class-diagram.md
 delete mode 100644 docs/2round/04-erd.md
 delete mode 100644 docs/2round/2round.md
 delete mode 100644 docs/3round/3round.md

diff --git a/apps/commerce-api/src/main/java/com/loopers/application/example/ExampleFacade.java b/apps/commerce-api/src/main/java/com/loopers/application/example/ExampleFacade.java
new file mode 100644
index 000000000..552a9ad62
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/application/example/ExampleFacade.java
@@ -0,0 +1,17 @@
+package com.loopers.application.example;
+
+import com.loopers.domain.example.ExampleModel;
+import com.loopers.domain.example.ExampleService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+@RequiredArgsConstructor
+@Component
+public class ExampleFacade {
+    private final ExampleService exampleService;
+
+    public ExampleInfo getExample(Long id) {
+        ExampleModel example = exampleService.getExample(id);
+        return ExampleInfo.from(example);
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/example/ExampleInfo.java b/apps/commerce-api/src/main/java/com/loopers/application/example/ExampleInfo.java
new file mode 100644
index 000000000..877aba96c
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/application/example/ExampleInfo.java
@@ -0,0 +1,13 @@
+package com.loopers.application.example;
+
+import com.loopers.domain.example.ExampleModel;
+
+public record ExampleInfo(Long id, String name, String description) {
+    public static ExampleInfo from(ExampleModel model) {
+        return new ExampleInfo(
+            model.getId(),
+            model.getName(),
+            model.getDescription()
+        );
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/like/LikeFacade.java b/apps/commerce-api/src/main/java/com/loopers/application/like/LikeFacade.java
deleted file mode 100644
index d9dd33205..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/application/like/LikeFacade.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.loopers.application.like;
-
-import com.loopers.domain.like.LikeService;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Component;
-
-/**
- * packageName : com.loopers.application.like
- * fileName     : LikeFacade
- * author      : byeonsungmun
- * date        : 2025. 11. 14.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 14.     byeonsungmun       최초 생성
- */
-@Component
-@RequiredArgsConstructor
-public class LikeFacade {
-
-    private final LikeService likeService;
-
-    public void createLike(String userId, Long productId) {
-        likeService.like(userId, productId);
-    }
-
-    public void deleteLike(String userId, Long productId) {
-        likeService.unlike(userId, productId);
-    }
-}
-
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/order/CreateOrderCommand.java b/apps/commerce-api/src/main/java/com/loopers/application/order/CreateOrderCommand.java
deleted file mode 100644
index 683e39cdd..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/application/order/CreateOrderCommand.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.loopers.application.order;
-
-import java.util.List;
-
-/**
- * packageName : com.loopers.application.order
- * fileName     : CreateOrderCommand
- * author      : byeonsungmun
- * date        : 2025. 11. 14.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 14.     byeonsungmun       최초 생성
- */
-public record CreateOrderCommand(
-        String userId,
-        List<OrderItemCommand> items
-) {}
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/order/OrderFacade.java b/apps/commerce-api/src/main/java/com/loopers/application/order/OrderFacade.java
deleted file mode 100644
index 2fba4b4aa..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/application/order/OrderFacade.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.loopers.application.order;
-
-import com.loopers.domain.order.Order;
-import com.loopers.domain.order.OrderItem;
-import com.loopers.domain.order.OrderService;
-import com.loopers.domain.order.OrderStatus;
-import com.loopers.domain.point.PointService;
-import com.loopers.domain.product.Product;
-import com.loopers.domain.product.ProductService;
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-import org.springframework.transaction.annotation.Transactional;
-
-/**
- * packageName : com.loopers.application.order
- * fileName     : OrderFacade
- * author      : byeonsungmun
- * date        : 2025. 11. 13.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 13.     byeonsungmun       최초 생성
- */
-
-@Slf4j
-@Component
-@RequiredArgsConstructor
-public class OrderFacade {
-
-    private final OrderService orderService;
-    private final ProductService productService;
-    private final PointService pointService;
-
-    @Transactional
-    public OrderInfo createOrder(CreateOrderCommand command) {
-
-        if (command == null || command.items() == null || command.items().isEmpty()) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "상품 정보가 비어있습니다");
-        }
-
-        Order order = Order.create(command.userId());
-
-        for (OrderItemCommand itemCommand : command.items()) {
-
-            //상품가져오고
-            Product product = productService.getProduct(itemCommand.productId());
-
-            // 재고감소
-            product.decreaseStock(itemCommand.quantity());
-
-            // OrderItem생성
-            OrderItem orderItem = OrderItem.create(
-                    product.getId(),
-                    product.getName(),
-                    itemCommand.quantity(),
-                    product.getPrice());
-
-            order.addOrderItem(orderItem);
-            orderItem.setOrder(order);
-        }
-
-        //총 가격구하고
-        long totalAmount = order.getOrderItems().stream()
-                .mapToLong(OrderItem::getAmount)
-                .sum();
-
-        order.updateTotalAmount(totalAmount);
-
-        pointService.usePoint(command.userId(), totalAmount);
-
-        //저장
-        Order saved = orderService.createOrder(order);
-        saved.updateStatus(OrderStatus.COMPLETE);
-
-        return OrderInfo.from(saved);
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/order/OrderInfo.java b/apps/commerce-api/src/main/java/com/loopers/application/order/OrderInfo.java
deleted file mode 100644
index 70028c27c..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/application/order/OrderInfo.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.loopers.application.order;
-
-import com.loopers.domain.order.Order;
-import com.loopers.domain.order.OrderStatus;
-
-import java.time.LocalDateTime;
-import java.util.List;
-
-/**
- * packageName : com.loopers.application.order
- * fileName     : OrderInfo
- * author      : byeonsungmun
- * date        : 2025. 11. 14.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 14.     byeonsungmun       최초 생성
- */
-public record OrderInfo(
-        Long orderId,
-        String userId,
-        Long totalAmount,
-        OrderStatus status,
-        LocalDateTime createdAt,
-        List<OrderItemInfo> items
-) {
-    public static OrderInfo from(Order order) {
-        List<OrderItemInfo> itemInfos = order.getOrderItems().stream()
-                .map(OrderItemInfo::from)
-                .toList();
-
-        return new OrderInfo(
-                order.getId(),
-                order.getUserId(),
-                order.getTotalAmount(),
-                order.getStatus(),
-                order.getCreatedAt(),
-                itemInfos
-        );
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/order/OrderItemCommand.java b/apps/commerce-api/src/main/java/com/loopers/application/order/OrderItemCommand.java
deleted file mode 100644
index 1ac46862f..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/application/order/OrderItemCommand.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.loopers.application.order;
-
-/**
- * packageName : com.loopers.application.order
- * fileName     : OrderItemCommand
- * author      : byeonsungmun
- * date        : 2025. 11. 14.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 14.     byeonsungmun       최초 생성
- */
-public record OrderItemCommand(
-        Long productId,
-        Long quantity
-) {}
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/order/OrderItemInfo.java b/apps/commerce-api/src/main/java/com/loopers/application/order/OrderItemInfo.java
deleted file mode 100644
index b3f2359c6..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/application/order/OrderItemInfo.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.loopers.application.order;
-
-import com.loopers.domain.order.OrderItem;
-
-/**
- * packageName : com.loopers.application.order
- * fileName     : OrderInfo
- * author      : byeonsungmun
- * date        : 2025. 11. 13.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 13.     byeonsungmun       최초 생성
- */
-public record OrderItemInfo(
-        Long productId,
-        String productName,
-        Long quantity,
-        Long price,
-        Long amount
-) {
-    public static OrderItemInfo from(OrderItem item) {
-        return new OrderItemInfo(
-                item.getProductId(),
-                item.getProductName(),
-                item.getQuantity(),
-                item.getPrice(),
-                item.getAmount()
-        );
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/point/PointFacade.java b/apps/commerce-api/src/main/java/com/loopers/application/point/PointFacade.java
deleted file mode 100644
index 009be1cec..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/application/point/PointFacade.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.loopers.application.point;
-
-import com.loopers.domain.point.Point;
-import com.loopers.domain.point.PointService;
-import com.loopers.interfaces.api.point.PointV1Dto;
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Component;
-
-@RequiredArgsConstructor
-@Component
-public class PointFacade {
-    private final PointService pointService;
-
-    public PointInfo getPoint(String userId) {
-        Point point = pointService.findPointByUserId(userId);
-
-        if (point == null) {
-            throw new CoreException(ErrorType.NOT_FOUND, "사용자 존재하지 않습니다.");
-        }
-        return PointInfo.from(point);
-    }
-
-    public PointInfo chargePoint(PointV1Dto.ChargePointRequest request) {
-        return PointInfo.from(pointService.chargePoint(request.userId(), request.chargeAmount()));
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/point/PointInfo.java b/apps/commerce-api/src/main/java/com/loopers/application/point/PointInfo.java
deleted file mode 100644
index 65497297b..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/application/point/PointInfo.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.loopers.application.point;
-
-import com.loopers.domain.point.Point;
-
-public record PointInfo(String userId, Long amount) {
-    public static PointInfo from(Point info) {
-        return new PointInfo(
-                info.getUserId(),
-                info.getBalance()
-        );
-    }
-
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/product/ProductDetailInfo.java b/apps/commerce-api/src/main/java/com/loopers/application/product/ProductDetailInfo.java
deleted file mode 100644
index 2a9ecee27..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/application/product/ProductDetailInfo.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.loopers.application.product;
-
-import com.loopers.domain.product.ProductDetail;
-
-/**
- * packageName : com.loopers.application.product
- * fileName     : ProductDetail
- * author      : byeonsungmun
- * date        : 2025. 11. 13.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 13.     byeonsungmun       최초 생성
- */
-public record ProductDetailInfo(
-        Long id,
-        String name,
-        String brandName,
-        Long price,
-        Long likeCount
-) {
-    public static ProductDetailInfo from(ProductDetail productDetail) {
-        return new ProductDetailInfo(
-                productDetail.getId(),
-                productDetail.getName(),
-                productDetail.getBrandName(),
-                productDetail.getPrice(),
-                productDetail.getLikeCount()
-        );
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/product/ProductFacade.java b/apps/commerce-api/src/main/java/com/loopers/application/product/ProductFacade.java
deleted file mode 100644
index e6a25de23..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/application/product/ProductFacade.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.loopers.application.product;
-
-import com.loopers.domain.brand.Brand;
-import com.loopers.domain.brand.BrandService;
-import com.loopers.domain.like.LikeService;
-import com.loopers.domain.product.ProductDetail;
-import com.loopers.domain.product.ProductDomainService;
-import com.loopers.domain.product.ProductService;
-import lombok.RequiredArgsConstructor;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.Pageable;
-import org.springframework.stereotype.Component;
-
-/**
- * packageName : com.loopers.application.product
- * fileName     : ProdcutFacade
- * author      : byeonsungmun
- * date        : 2025. 11. 10.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 10.     byeonsungmun       최초 생성
- */
-@Component
-@RequiredArgsConstructor
-public class ProductFacade {
-
-    private final ProductService productService;
-    private final BrandService brandService;
-    private final LikeService likeService;
-    private final ProductDomainService productDomainService;
-
-    public Page<ProductInfo> getProducts(String sort, Pageable pageable) {
-        return productService.getProducts(sort ,pageable)
-                .map(product ->  {
-                    Brand brand = brandService.getBrand(product.getBrandId());
-                    long likeCount = likeService.countByProductId(product.getId());
-                    return ProductInfo.of(product, brand, likeCount);
-                });
-    }
-
-    public ProductDetailInfo getProduct(Long id) {
-        ProductDetail productDetail = productDomainService.getProductDetail(id);
-        return ProductDetailInfo.from(productDetail);
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/product/ProductInfo.java b/apps/commerce-api/src/main/java/com/loopers/application/product/ProductInfo.java
deleted file mode 100644
index 8bcd93dd8..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/application/product/ProductInfo.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.loopers.application.product;
-
-import com.loopers.domain.brand.Brand;
-import com.loopers.domain.product.Product;
-
-/**
- * packageName : com.loopers.application.product
- * fileName     : ProductInfo
- * author      : byeonsungmun
- * date        : 2025. 11. 10.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 10.     byeonsungmun       최초 생성
- */
-public record ProductInfo(
-        Long id,
-        String name,
-        String brandName,
-        Long price,
-        Long likeCount
-) {
-    public static ProductInfo of(Product product, Brand brand, Long likeCount) {
-        return new ProductInfo(
-                product.getId(),
-                product.getName(),
-                brand.getName(),
-                product.getPrice(),
-                likeCount
-        );
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/user/UserFacade.java b/apps/commerce-api/src/main/java/com/loopers/application/user/UserFacade.java
deleted file mode 100644
index f42bd5206..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/application/user/UserFacade.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.loopers.application.user;
-
-import com.loopers.domain.user.User;
-import com.loopers.domain.user.UserService;
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Component;
-
-@RequiredArgsConstructor
-@Component
-public class UserFacade {
-    private final UserService userService;
-
-    public UserInfo register(String userId, String email, String birth, String gender) {
-        User user = userService.register(userId, email, birth, gender);
-        return UserInfo.from(user);
-    }
-
-    public UserInfo getUser(String userId) {
-        User user = userService.findUserByUserId(userId);
-        if (user == null) {
-            throw new CoreException(ErrorType.NOT_FOUND, "사용자 존재하지 않습니다.");
-        }
-        return UserInfo.from(user);
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/user/UserInfo.java b/apps/commerce-api/src/main/java/com/loopers/application/user/UserInfo.java
deleted file mode 100644
index 08f5cea43..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/application/user/UserInfo.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.loopers.application.user;
-
-import com.loopers.domain.user.User;
-
-public record UserInfo(String userId, String email, String birth, String gender) {
-    public static UserInfo from(User user) {
-        return new UserInfo(
-                user.getUserId(),
-                user.getEmail(),
-                user.getBirth(),
-                user.getGender()
-        );
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/brand/Brand.java b/apps/commerce-api/src/main/java/com/loopers/domain/brand/Brand.java
deleted file mode 100644
index d334ccebf..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/brand/Brand.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.loopers.domain.brand;
-
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-import jakarta.persistence.*;
-import lombok.Getter;
-
-/**
- * packageName : com.loopers.domain.brand
- * fileName     : Brand
- * author      : byeonsungmun
- * date        : 2025. 11. 11.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 11.     byeonsungmun       최초 생성
- */
-@Entity
-@Table(name = "brand")
-@Getter
-public class Brand {
-    @Id
-    @GeneratedValue(strategy = GenerationType.IDENTITY)
-    private Long id;
-
-    @Column(nullable = false)
-    private String name;
-
-    protected  Brand() {}
-
-    private Brand(String name) {
-        this.name = requireValidName(name);
-    }
-
-    public static Brand create(String name) {
-        return new Brand(name);
-    }
-
-
-    private String requireValidName(String name) {
-        if (name == null || name.isEmpty()) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "브랜드명은 비어 있을 수 없습니다.");
-        }
-        return name.trim();
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/brand/BrandRepository.java b/apps/commerce-api/src/main/java/com/loopers/domain/brand/BrandRepository.java
deleted file mode 100644
index c558b23fc..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/brand/BrandRepository.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.loopers.domain.brand;
-
-import java.util.Optional;
-
-/**
- * packageName : com.loopers.domain.brand
- * fileName     : BrandRepository
- * author      : byeonsungmun
- * date        : 2025. 11. 12.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 12.     byeonsungmun       최초 생성
- */
-public interface BrandRepository {
-    Optional<Brand> findById(Long id);
-
-    void save(Brand brand);
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/brand/BrandService.java b/apps/commerce-api/src/main/java/com/loopers/domain/brand/BrandService.java
deleted file mode 100644
index e0f58c77b..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/brand/BrandService.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.loopers.domain.brand;
-
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Component;
-import org.springframework.transaction.annotation.Transactional;
-
-/**
- * packageName : com.loopers.domain.brand
- * fileName     : BrandService
- * author      : byeonsungmun
- * date        : 2025. 11. 12.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 12.     byeonsungmun       최초 생성
- */
-@Component
-@RequiredArgsConstructor
-public class BrandService {
-
-    private final BrandRepository brandRepository;
-
-    public void save(Brand brand) {
-        brandRepository.save(brand);
-    }
-
-    @Transactional(readOnly = true)
-    public Brand getBrand(Long id) {
-        return brandRepository.findById(id)
-                .orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "브랜드를 찾을 수 없습니다."));
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleModel.java b/apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleModel.java
new file mode 100644
index 000000000..c588c4a8a
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleModel.java
@@ -0,0 +1,44 @@
+package com.loopers.domain.example;
+
+import com.loopers.domain.BaseEntity;
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Table;
+
+@Entity
+@Table(name = "example")
+public class ExampleModel extends BaseEntity {
+
+    private String name;
+    private String description;
+
+    protected ExampleModel() {}
+
+    public ExampleModel(String name, String description) {
+        if (name == null || name.isBlank()) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "이름은 비어있을 수 없습니다.");
+        }
+        if (description == null || description.isBlank()) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "설명은 비어있을 수 없습니다.");
+        }
+
+        this.name = name;
+        this.description = description;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void update(String newDescription) {
+        if (newDescription == null || newDescription.isBlank()) {
+            throw new CoreException(ErrorType.BAD_REQUEST, "설명은 비어있을 수 없습니다.");
+        }
+        this.description = newDescription;
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleRepository.java b/apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleRepository.java
new file mode 100644
index 000000000..3625e5662
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleRepository.java
@@ -0,0 +1,7 @@
+package com.loopers.domain.example;
+
+import java.util.Optional;
+
+public interface ExampleRepository {
+    Optional<ExampleModel> find(Long id);
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleService.java b/apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleService.java
new file mode 100644
index 000000000..c0e8431e8
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/domain/example/ExampleService.java
@@ -0,0 +1,20 @@
+package com.loopers.domain.example;
+
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@RequiredArgsConstructor
+@Component
+public class ExampleService {
+
+    private final ExampleRepository exampleRepository;
+
+    @Transactional(readOnly = true)
+    public ExampleModel getExample(Long id) {
+        return exampleRepository.find(id)
+            .orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "[id = " + id + "] 예시를 찾을 수 없습니다."));
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/like/Like.java b/apps/commerce-api/src/main/java/com/loopers/domain/like/Like.java
deleted file mode 100644
index 4430b496a..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/like/Like.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package com.loopers.domain.like;
-
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-import jakarta.persistence.*;
-import lombok.Getter;
-
-import java.time.LocalDateTime;
-
-/**
- * packageName : com.loopers.domain.like
- * fileName     : Like
- * author      : byeonsungmun
- * date        : 2025. 11. 11.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 11.     byeonsungmun       최초 생성
- */
-@Entity
-@Table(name = "product_like")
-@Getter
-public class Like {
-    @Id
-    @GeneratedValue(strategy = GenerationType.IDENTITY)
-    private Long id;
-
-    @Column(name = "ref_user_id", nullable = false)
-    private String userId;
-
-    @Column(name = "ref_product_id", nullable = false)
-    private Long productId;
-
-    @Column(nullable = false)
-    private LocalDateTime createdAt;
-
-    protected Like() {}
-
-    private Like(String userId, Long productId) {
-        this.userId = requireValidUserId(userId);
-        this.productId = requireValidProductId(productId);
-        this.createdAt = LocalDateTime.now();
-    }
-
-    public static Like create(String userId, Long productId) {
-        return new Like(userId, productId);
-    }
-
-    private String requireValidUserId(String userId) {
-        if (userId == null || userId.isEmpty()) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "사용자 ID는 필수입니다.");
-        }
-        return userId;
-    }
-
-    private Long requireValidProductId(Long productId) {
-        if (productId == null || productId <= 0) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "상품 ID는 필수입니다.");
-        }
-        return productId;
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/like/LikeRepository.java b/apps/commerce-api/src/main/java/com/loopers/domain/like/LikeRepository.java
deleted file mode 100644
index 945b10235..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/like/LikeRepository.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.loopers.domain.like;
-
-import java.util.Optional;
-
-/**
- * packageName : com.loopers.domain.like
- * fileName     : LikeRepository
- * author      : byeonsungmun
- * date        : 2025. 11. 12.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 12.     byeonsungmun       최초 생성
- */
-public interface LikeRepository {
-
-    Optional<Like> findByUserIdAndProductId(String userId, Long productId);
-
-    void save(Like like);
-
-    void delete(Like like);
-
-    long countByProductId(Long productId);
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/like/LikeService.java b/apps/commerce-api/src/main/java/com/loopers/domain/like/LikeService.java
deleted file mode 100644
index 41ae90b6a..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/like/LikeService.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.loopers.domain.like;
-
-import com.loopers.domain.product.ProductRepository;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Component;
-import org.springframework.transaction.annotation.Transactional;
-
-/**
- * packageName : com.loopers.application.like
- * fileName     : LikeService
- * author      : byeonsungmun
- * date        : 2025. 11. 12.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 12.     byeonsungmun       최초 생성
- */
-@Component
-@RequiredArgsConstructor
-public class LikeService {
-
-    private final LikeRepository likeRepository;
-    private final ProductRepository productRepository;
-
-    @Transactional
-    public void like(String userId, Long productId) {
-        if (likeRepository.findByUserIdAndProductId(userId, productId).isPresent()) return;
-
-        Like like = Like.create(userId, productId);
-        likeRepository.save(like);
-        productRepository.incrementLikeCount(productId);
-    }
-
-    @Transactional
-    public void unlike(String userId, Long productId) {
-        likeRepository.findByUserIdAndProductId(userId, productId)
-                .ifPresent(like -> {
-                    likeRepository.delete(like);
-                    productRepository.decrementLikeCount(productId);
-                });
-    }
-
-    @Transactional(readOnly = true)
-    public long countByProductId(Long productId) {
-        return likeRepository.countByProductId(productId);
-    }
-
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/order/Order.java b/apps/commerce-api/src/main/java/com/loopers/domain/order/Order.java
deleted file mode 100644
index 84f299c6b..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/order/Order.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package com.loopers.domain.order;
-
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-import jakarta.persistence.*;
-import lombok.Getter;
-
-import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * packageName : com.loopers.domain.order
- * fileName     : Order
- * author      : byeonsungmun
- * date        : 2025. 11. 11.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 11.     byeonsungmun       최초 생성
- */
-@Entity
-@Table(name = "orders")
-@Getter
-public class Order {
-
-    @Id
-    @GeneratedValue(strategy = GenerationType.IDENTITY)
-    private Long id;
-
-    @Column(name = "ref_user_id", nullable = false)
-    private String userId;
-
-    @Column(nullable = false)
-    private Long totalAmount;
-
-    @Enumerated(EnumType.STRING)
-    private OrderStatus status;
-
-    @Column(nullable = false)
-    private LocalDateTime createdAt;
-
-    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
-    private List<OrderItem> orderItems = new ArrayList<>();
-
-    protected Order() {}
-
-    private Order(String userId, OrderStatus status) {
-        this.userId = requiredValidUserId(userId);
-        this.totalAmount = 0L;
-        this.status = requiredValidStatus(status);
-        this.createdAt = LocalDateTime.now();
-    }
-
-    public static Order create(String userId) {
-        return new Order(userId, OrderStatus.PENDING);
-    }
-
-    public void addOrderItem(OrderItem orderItem) {
-        orderItem.setOrder(this);
-        this.orderItems.add(orderItem);
-    }
-
-    private OrderStatus requiredValidStatus(OrderStatus status) {
-        if (status == null) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "주문 상태는 필수 입니다.");
-        }
-        return status;
-    }
-
-    private String requiredValidUserId(String userId) {
-        if (userId == null || userId.isEmpty()) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "사용자 ID는 필수 입니다.");
-        }
-        return userId;
-    }
-
-    public void updateTotalAmount(long totalAmount) {
-        this.totalAmount = totalAmount;
-    }
-
-    public void updateStatus(OrderStatus status) {
-        this.status = status;
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderItem.java b/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderItem.java
deleted file mode 100644
index dce97a44a..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderItem.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package com.loopers.domain.order;
-
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-import jakarta.persistence.*;
-import lombok.Getter;
-import lombok.Setter;
-
-/**
- * packageName : com.loopers.domain.order
- * fileName     : OrderItem
- * author      : byeonsungmun
- * date        : 2025. 11. 11.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 11.     byeonsungmun       최초 생성
- */
-
-@Entity
-@Table(name = "order_item")
-@Getter
-public class OrderItem {
-
-    @Id
-    @GeneratedValue(strategy = GenerationType.IDENTITY)
-    private Long id;
-
-    @Setter
-    @ManyToOne(fetch = FetchType.LAZY)
-    @JoinColumn(name = "order_id", nullable = false)
-    private Order order;
-
-    @Column(name = "ref_product_id", nullable = false)
-    private Long productId;
-
-    @Column(name = "ref_product_name", nullable = false)
-    private String productName;
-
-    @Column(nullable = false)
-    private Long quantity;
-
-    @Column(nullable = false)
-    private Long price;
-
-    protected OrderItem() {}
-
-    private OrderItem(Long productId, String productName, Long quantity, Long price) {
-        this.productId = requiredValidProductId(productId);
-        this.productName = requiredValidProductName(productName);
-        this.quantity = requiredQuantity(quantity);
-        this.price = requiredPrice(price);
-    }
-
-    public static OrderItem create(Long productId, String productName, Long quantity, Long price) {
-        return new OrderItem(productId, productName, quantity, price);
-    }
-
-    public Long getAmount() {
-        return quantity * price;
-    }
-
-    private Long requiredValidProductId(Long productId) {
-        if (productId == null || productId <= 0)  {
-            throw new CoreException(ErrorType.BAD_REQUEST, "상품 ID는 필수입니다.");
-        }
-        return productId;
-    }
-
-    private String requiredValidProductName(String productName) {
-        if (productName == null || productName.isEmpty())  {
-            throw new CoreException(ErrorType.BAD_REQUEST, "상품명은 필수입니다.");
-        }
-        return productName;
-    }
-
-    private Long requiredQuantity(Long quantity) {
-        if (quantity == null || quantity <= 0)  {
-            throw new CoreException(ErrorType.BAD_REQUEST, "수량은 1개 이상이어야 합니다.");
-        }
-        return quantity;
-    }
-
-    private Long requiredPrice(Long price) {
-        if (price == null || price < 0)  {
-            throw new CoreException(ErrorType.BAD_REQUEST, "가격은 0원 이상이어야 합니다.");
-        }
-        return price;
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderRepository.java b/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderRepository.java
deleted file mode 100644
index c80262041..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderRepository.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.loopers.domain.order;
-
-import java.util.Optional;
-
-/**
- * packageName : com.loopers.domain.order
- * fileName     : OrderRepository
- * author      : byeonsungmun
- * date        : 2025. 11. 13.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 13.     byeonsungmun       최초 생성
- */
-public interface OrderRepository {
-
-    Order save(Order order);
-
-    Optional<Order> findById(Long orderId);
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderService.java b/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderService.java
deleted file mode 100644
index a66be03d3..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderService.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.loopers.domain.order;
-
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Component;
-import org.springframework.transaction.annotation.Transactional;
-
-/**
- * packageName : com.loopers.domain.order
- * fileName     : OrderService
- * author      : byeonsungmun
- * date        : 2025. 11. 13.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 13.     byeonsungmun       최초 생성
- */
-@Component
-@RequiredArgsConstructor
-public class OrderService {
-
-    private final OrderRepository orderRepository;
-
-    @Transactional
-    public Order createOrder(Order order) {
-        return orderRepository.save(order);
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderStatus.java b/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderStatus.java
deleted file mode 100644
index 14ea592ef..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/order/OrderStatus.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.loopers.domain.order;
-
-/**
- * packageName : com.loopers.domain.order
- * fileName     : OrderStatus
- * author      : byeonsungmun
- * date        : 2025. 11. 11.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 11.     byeonsungmun       최초 생성
- */
-public enum OrderStatus {
-
-    COMPLETE("결제성공"),
-    CANCEL("결제취소"),
-    FAIL("결제실패"),
-    PENDING("결제중");
-
-    private final String description;
-
-    OrderStatus(String description) {
-        this.description = description;
-    }
-
-    public boolean isCompleted() {
-        return this == COMPLETE;
-    }
-
-    public boolean isPending() {
-        return this == PENDING;
-    }
-
-    public boolean isCanceled() {
-        return this == CANCEL;
-    }
-
-    public String description() {
-        return description;
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java b/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java
deleted file mode 100644
index bc28a902a..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/point/Point.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.loopers.domain.point;
-
-import com.loopers.domain.BaseEntity;
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-import jakarta.persistence.*;
-import lombok.Getter;
-
-@Entity
-@Table(name = "point")
-@Getter
-public class Point extends BaseEntity {
-
-    @GeneratedValue(strategy = GenerationType.IDENTITY)
-    @Id
-    private Long id;
-
-    private String userId;
-
-    private Long balance;
-
-    protected Point() {}
-
-    private Point(String userId, Long balance) {
-        this.userId = requireValidUserId(userId);
-        this.balance = balance;
-    }
-
-    public static Point create(String userId, Long balance) {
-        return new Point(userId, balance);
-    }
-
-    String requireValidUserId(String userId) {
-        if(userId == null || userId.isEmpty()) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "사용자 ID가 비어있을 수 없습니다.");
-        }
-        return userId;
-    }
-
-    public void charge(Long chargeAmount) {
-        if (chargeAmount == null || chargeAmount <= 0) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "0원 이하로 포인트를 충전 할수 없습니다.");
-        }
-        this.balance += chargeAmount;
-    }
-
-    public void use(Long useAmount) {
-        if (useAmount == null || useAmount <= 0) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "0원 이하로 사용할 수 없습니다.");
-        }
-        if (this.balance < useAmount) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "포인트가 부족합니다.");
-        }
-        this.balance -= useAmount;
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/point/PointRepository.java b/apps/commerce-api/src/main/java/com/loopers/domain/point/PointRepository.java
deleted file mode 100644
index 314022491..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/point/PointRepository.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.loopers.domain.point;
-
-import java.util.Optional;
-
-public interface PointRepository {
-
-    Optional<Point> findByUserId(String userId);
-
-    Point save(Point point);
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java b/apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java
deleted file mode 100644
index 9c9570615..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/point/PointService.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.loopers.domain.point;
-
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Component;
-import org.springframework.transaction.annotation.Transactional;
-
-@RequiredArgsConstructor
-@Component
-public class PointService {
-
-    private final PointRepository pointRepository;
-
-    @Transactional(readOnly = true)
-    public Point findPointByUserId(String userId) {
-        return pointRepository.findByUserId(userId).orElse(null);
-    }
-
-    @Transactional
-    public Point chargePoint(String userId, Long chargeAmount) {
-        Point point = pointRepository.findByUserId(userId).orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "포인트를 충전할수 없는 사용자입니다."));
-        point.charge(chargeAmount);
-        return pointRepository.save(point);
-    }
-
-    @Transactional
-    public Point usePoint(String userId, Long useAmount) {
-        Point point = pointRepository.findByUserId(userId)
-                .orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "포인트 정보를 찾을 수 없습니다."));
-
-        if (useAmount == null || useAmount <= 0) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "차감할 포인트는 1 이상이어야 합니다.");
-        }
-
-        if (point.getBalance() < useAmount) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "포인트가 부족합니다.");
-        }
-
-        point.use(useAmount);
-        return pointRepository.save(point);
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/product/Product.java b/apps/commerce-api/src/main/java/com/loopers/domain/product/Product.java
deleted file mode 100644
index 29968402f..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/product/Product.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package com.loopers.domain.product;
-
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-import jakarta.persistence.*;
-import lombok.Getter;
-
-/**
- * packageName : com.loopers.domain.product
- * fileName     : Product
- * author      : byeonsungmun
- * date        : 2025. 11. 10.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 10.     byeonsungmun       최초 생성
- */
-
-@Entity
-@Table(name = "product")
-@Getter
-public class Product {
-
-    @Id
-    @GeneratedValue(strategy = GenerationType.IDENTITY)
-    private Long id;
-
-    @Column(name = "ref_brand_id", nullable = false)
-    private Long brandId;
-
-    @Column(nullable = false)
-    private String name;
-
-    @Column(nullable = false)
-    private Long price;
-
-    @Column
-    private Long likeCount;
-
-    @Column(nullable = false)
-    private Long stock;
-
-    protected Product() {}
-
-    private Product(Long brandId, String name, Long price, Long likeCount, Long stock) {
-        this.brandId = requireValidBrandId(brandId);
-        this.name = requireValidName(name);
-        this.price = requireValidPrice(price);
-        this.likeCount = requireValidLikeCount(likeCount);
-        this.stock = requireValidStock(stock);
-    }
-
-    public static Product create(Long brandId, String name, Long price, Long stock) {
-        return new Product(
-                brandId,
-                name,
-                price,
-                0L,
-                stock
-        );
-    }
-
-    private Long requireValidBrandId(Long brandId) {
-        if (brandId == null || brandId <= 0) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "브랜드 ID는 필수입니다.");
-        }
-
-        return brandId;
-    }
-
-    private String requireValidName(String name) {
-        if (name == null || name.isEmpty()) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "상품명은 필수입니다.");
-        }
-        return name;
-    }
-
-    private Long requireValidPrice(Long price) {
-        if (price == null || price < 0) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "상품 가격은 0원 이상이어야 합니다.");
-        }
-        return price;
-    }
-
-    private Long requireValidLikeCount(Long likeCount) {
-        if (likeCount == null || likeCount < 0) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "좋아요 개수는 0개 미만으로 설정할 수 없습니다.");
-        }
-        return likeCount;
-    }
-
-    private Long requireValidStock(Long stock) {
-        if (stock == null) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "상품 재고는 필수입니다.");
-        }
-        if (stock < 0) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "상품 재고는 0 미만으로 설정할 수 없습니다.");
-        }
-        return stock;
-    }
-
-    public void increaseLikeCount() {
-        this.likeCount++;
-    }
-
-    public void decreaseLikeCount() {
-        if (this.likeCount > 0) this.likeCount--;
-    }
-
-    public void decreaseStock(Long quantity) {
-        if (quantity <= 0) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "차감 수량은 0보다 커야 합니다.");
-        }
-        if (this.stock - quantity < 0) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "재고가 부족합니다.");
-        }
-        this.stock -= quantity;
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductDetail.java b/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductDetail.java
deleted file mode 100644
index 808bff196..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductDetail.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.loopers.domain.product;
-
-import com.loopers.domain.brand.Brand;
-import lombok.Getter;
-
-/**
- * packageName : com.loopers.domain.product
- * fileName     : ProductDetail
- * author      : byeonsungmun
- * date        : 2025. 11. 13.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 13.     byeonsungmun       최초 생성
- */
-@Getter
-public class ProductDetail {
-
-    private Long id;
-    private String name;
-    private String brandName;
-    private Long price;
-    private Long likeCount;
-
-    protected ProductDetail() {}
-
-    private ProductDetail(Long id, String name, String brandName, Long price, Long likeCount) {
-        this.id = id;
-        this.name = name;
-        this.brandName = brandName;
-        this.price = price;
-        this.likeCount = likeCount;
-    }
-
-    public static ProductDetail of(Product product, Brand brand, Long likeCount) {
-        return new ProductDetail(
-                product.getId(),
-                product.getName(),
-                brand.getName(),
-                product.getPrice(),
-                likeCount
-        );
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductDomainService.java b/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductDomainService.java
deleted file mode 100644
index 166aff66b..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductDomainService.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.loopers.domain.product;
-
-import com.loopers.domain.brand.Brand;
-import com.loopers.domain.brand.BrandRepository;
-import com.loopers.domain.like.LikeRepository;
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Component;
-import org.springframework.transaction.annotation.Transactional;
-
-/**
- * packageName : com.loopers.domain.product
- * fileName     : ProductDetailService
- * author      : byeonsungmun
- * date        : 2025. 11. 13.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 13.     byeonsungmun       최초 생성
- */
-@Component
-@RequiredArgsConstructor
-public class ProductDomainService {
-
-    private final ProductRepository productRepository;
-    private final BrandRepository brandRepository;
-    private final LikeRepository likeRepository;
-
-    @Transactional(readOnly = true)
-    public ProductDetail getProductDetail(Long id) {
-        Product product = productRepository.findById(id)
-                .orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "상품을 찾을 수 없습니다."));
-        Brand brand = brandRepository.findById(product.getBrandId())
-                .orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "브랜드를 찾을 수 없습니다"));
-        long likeCount = likeRepository.countByProductId(id);
-
-        return ProductDetail.of(product, brand, likeCount);
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductRepository.java b/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductRepository.java
deleted file mode 100644
index dadda62a0..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductRepository.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.loopers.domain.product;
-
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.Pageable;
-
-import java.util.Optional;
-
-/**
- * packageName : com.loopers.domain.product
- * fileName     : ProductRepositroy
- * author      : byeonsungmun
- * date        : 2025. 11. 12.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 12.     byeonsungmun       최초 생성
- */
-public interface ProductRepository {
-    Page<Product> findAll(Pageable pageable);
-
-    Optional<Product> findById(Long id);
-
-    void incrementLikeCount(Long productId);
-
-    void decrementLikeCount(Long productId);
-
-    Product save(Product product);
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductService.java b/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductService.java
deleted file mode 100644
index 067f194ae..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/product/ProductService.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.loopers.domain.product;
-
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-import lombok.RequiredArgsConstructor;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.domain.Sort;
-import org.springframework.stereotype.Component;
-import org.springframework.transaction.annotation.Transactional;
-
-/**
- * packageName : com.loopers.domain.product
- * fileName     : ProductService
- * author      : byeonsungmun
- * date        : 2025. 11. 12.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 12.     byeonsungmun       최초 생성
- */
-
-@Component
-@RequiredArgsConstructor
-public class ProductService {
-
-    private final ProductRepository productRepository;
-
-    @Transactional(readOnly = true)
-    public Page<Product> getProducts(String sort, Pageable pageable) {
-        Sort sortOption = switch (sort) {
-            case "price_asc" -> Sort.by("price").ascending();
-            case "likes_desc" -> Sort.by("likeCount").descending();
-            default -> Sort.by("createdAt").descending(); // latest
-        };
-
-        Pageable sortedPageable = PageRequest.of(
-                pageable.getPageNumber(),
-                pageable.getPageSize(),
-                sortOption
-        );
-
-        return productRepository.findAll(sortedPageable);
-    }
-
-    public Product getProduct(Long productId) {
-        return productRepository.findById(productId)
-                .orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "해당 상품이 없습니다"));
-    }
-}
-
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/user/User.java b/apps/commerce-api/src/main/java/com/loopers/domain/user/User.java
deleted file mode 100644
index 287b84cf8..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/user/User.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package com.loopers.domain.user;
-
-import com.loopers.domain.BaseEntity;
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-import jakarta.persistence.Column;
-import jakarta.persistence.Entity;
-import jakarta.persistence.Table;
-import lombok.Getter;
-
-import java.util.regex.Pattern;
-
-@Entity
-@Table(name = "user")
-@Getter
-public class User extends BaseEntity {
-
-    private static final Pattern USERID_PATTERN = Pattern.compile("^[a-zA-Z0-9]{1,10}$");
-    private static final Pattern BIRTH_PATTERN = Pattern.compile("^\\d{4}-\\d{2}-\\d{2}$");
-    private static final Pattern EMAIL_PATTERN = Pattern.compile("^[\\w.+-]+@[\\w.-]+\\.[a-zA-Z]{2,}$");
-
-    @Column(unique = true, nullable = false)
-    private String userId;
-
-    @Column(nullable = false)
-    private String email;
-
-    @Column(nullable = false)
-    private String birth;
-
-    @Column(nullable = false)
-    private String gender;
-
-    protected User() {}
-
-    public User(String userId, String email, String birth, String gender) {
-        this.userId = requireValidUserId(userId);
-        this.email = requireValidEmail(email);
-        this.birth = requireValidBirthDate(birth);
-        this.gender = requireValidGender(gender);
-    }
-
-    String requireValidUserId(String userId) {
-        if(userId == null || userId.isEmpty()) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "사용자 ID가 비어있을 수 없습니다.");
-        }
-
-        if (!USERID_PATTERN.matcher(userId).matches()) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "사용자 ID가 영문 및 숫자 10자 이내여야 합니다.");
-        }
-        return userId;
-    }
-
-    String requireValidEmail(String email) {
-        if(email == null || email.isBlank()) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "이메일이 비어 있을 수 없습니다.");
-        }
-
-        if(!EMAIL_PATTERN.matcher(email).matches()) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "이메일 형식에 맞지 않습니다. ex)xx@yy.zz");
-        }
-        return email;
-    }
-
-    String requireValidBirthDate(String birth) {
-        if (birth == null || birth.isBlank()) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "생년월일이 비어 있을 수 없습니다.");
-        }
-
-        if(!BIRTH_PATTERN.matcher(birth).matches()) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "생년월일 형식이 맞지 않습니다.");
-        }
-        return birth;
-    }
-
-    String requireValidGender(String gender) {
-        if(gender == null || gender.isBlank()) {
-            throw new CoreException(ErrorType.BAD_REQUEST, "성별이 비어있습니다.");
-        }
-        return gender;
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserRepository.java b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserRepository.java
deleted file mode 100644
index f4b26266e..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserRepository.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.loopers.domain.user;
-
-import java.util.Optional;
-
-public interface UserRepository {
-
-    Optional<User> findByUserId(String userId);
-
-    User save(User user);
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java b/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java
deleted file mode 100644
index 3cc033076..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/domain/user/UserService.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.loopers.domain.user;
-
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Component;
-import org.springframework.transaction.annotation.Transactional;
-
-@Component
-@RequiredArgsConstructor
-public class UserService {
-
-    private final UserRepository userRepository;
-
-    @Transactional
-    public User register(String userId, String email, String birth, String gender) {
-        userRepository.findByUserId(userId).ifPresent(user -> {
-            throw new CoreException(ErrorType.CONFLICT, "이미 가입된 사용자 ID 입니다.");
-        });
-
-        User user = new User(userId, email, birth, gender);
-        return userRepository.save(user);
-    }
-
-    @Transactional(readOnly = true)
-    public User findUserByUserId(String userId) {
-        return userRepository.findByUserId(userId).orElse(null);
-    }
-
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/brand/BrandJpaRepository.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/brand/BrandJpaRepository.java
deleted file mode 100644
index 759f3caf1..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/infrastructure/brand/BrandJpaRepository.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.loopers.infrastructure.brand;
-
-import com.loopers.domain.brand.Brand;
-import org.springframework.data.jpa.repository.JpaRepository;
-
-/**
- * packageName : com.loopers.infrastructure.brand
- * fileName     : BrandJpaRepository
- * author      : byeonsungmun
- * date        : 2025. 11. 12.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 12.     byeonsungmun       최초 생성
- */
-public interface BrandJpaRepository extends JpaRepository<Brand, Long> {
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/brand/BrandRepositoryImpl.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/brand/BrandRepositoryImpl.java
deleted file mode 100644
index f23e6e5d9..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/infrastructure/brand/BrandRepositoryImpl.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.loopers.infrastructure.brand;
-
-import com.loopers.domain.brand.Brand;
-import com.loopers.domain.brand.BrandRepository;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Component;
-
-import java.util.Optional;
-
-/**
- * packageName : com.loopers.infrastructure.brand
- * fileName     : BrandRepositroyImpl
- * author      : byeonsungmun
- * date        : 2025. 11. 12.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 12.     byeonsungmun       최초 생성
- */
-@RequiredArgsConstructor
-@Component
-public class BrandRepositoryImpl implements BrandRepository {
-
-    private final BrandJpaRepository jpaRepository;
-
-    @Override
-    public Optional<Brand> findById(Long id) {
-        return jpaRepository.findById(id);
-    }
-
-    @Override
-    public void save(Brand brand) {
-        jpaRepository.save(brand);
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/example/ExampleJpaRepository.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/example/ExampleJpaRepository.java
new file mode 100644
index 000000000..ce6d3ead0
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/infrastructure/example/ExampleJpaRepository.java
@@ -0,0 +1,6 @@
+package com.loopers.infrastructure.example;
+
+import com.loopers.domain.example.ExampleModel;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface ExampleJpaRepository extends JpaRepository<ExampleModel, Long> {}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/example/ExampleRepositoryImpl.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/example/ExampleRepositoryImpl.java
new file mode 100644
index 000000000..37f2272f0
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/infrastructure/example/ExampleRepositoryImpl.java
@@ -0,0 +1,19 @@
+package com.loopers.infrastructure.example;
+
+import com.loopers.domain.example.ExampleModel;
+import com.loopers.domain.example.ExampleRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+import java.util.Optional;
+
+@RequiredArgsConstructor
+@Component
+public class ExampleRepositoryImpl implements ExampleRepository {
+    private final ExampleJpaRepository exampleJpaRepository;
+
+    @Override
+    public Optional<ExampleModel> find(Long id) {
+        return exampleJpaRepository.findById(id);
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/like/LikeJpaRepository.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/like/LikeJpaRepository.java
deleted file mode 100644
index 865a30db7..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/infrastructure/like/LikeJpaRepository.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.loopers.infrastructure.like;
-
-import com.loopers.domain.like.Like;
-import org.springframework.data.jpa.repository.JpaRepository;
-
-import java.util.Optional;
-
-/**
- * packageName : com.loopers.infrastructure.like
- * fileName     : LikeJpaRepository
- * author      : byeonsungmun
- * date        : 2025. 11. 12.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 12.     byeonsungmun       최초 생성
- */
-public interface LikeJpaRepository extends JpaRepository<Like, Long> {
-    Optional<Like> findByUserIdAndProductId(String userId, Long productId);
-
-    long countByProductId(Long productId);
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/like/LikeRepositoryImpl.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/like/LikeRepositoryImpl.java
deleted file mode 100644
index e037b6efb..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/infrastructure/like/LikeRepositoryImpl.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.loopers.infrastructure.like;
-
-import com.loopers.domain.like.Like;
-import com.loopers.domain.like.LikeRepository;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Component;
-
-import java.util.Optional;
-
-/**
- * packageName : com.loopers.infrastructure.like
- * fileName     : LikeRepositoryImpl
- * author      : byeonsungmun
- * date        : 2025. 11. 12.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 12.     byeonsungmun       최초 생성
- */
-@Component
-@RequiredArgsConstructor
-public class LikeRepositoryImpl implements LikeRepository {
-
-    private final LikeJpaRepository likeJpaRepository;
-
-    @Override
-    public Optional<Like> findByUserIdAndProductId(String userId, Long productId) {
-        return likeJpaRepository.findByUserIdAndProductId(userId, productId);
-    }
-
-    @Override
-    public void save(Like like) {
-        likeJpaRepository.save(like);
-    }
-
-    @Override
-    public void delete(Like like) {
-        likeJpaRepository.delete(like);
-    }
-
-    @Override
-    public long countByProductId(Long productId) {
-        return likeJpaRepository.countByProductId(productId);
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/order/OrderJpaRepository.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/order/OrderJpaRepository.java
deleted file mode 100644
index 39cfb136d..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/infrastructure/order/OrderJpaRepository.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.loopers.infrastructure.order;
-
-import com.loopers.domain.order.Order;
-import org.springframework.data.jpa.repository.JpaRepository;
-
-/**
- * packageName : com.loopers.infrastructure.order
- * fileName     : OrderJpaRepository
- * author      : byeonsungmun
- * date        : 2025. 11. 14.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 14.     byeonsungmun       최초 생성
- */
-public interface OrderJpaRepository extends JpaRepository<Order, Long> {
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/order/OrderRepositoryImpl.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/order/OrderRepositoryImpl.java
deleted file mode 100644
index f8c7b5b68..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/infrastructure/order/OrderRepositoryImpl.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.loopers.infrastructure.order;
-
-import com.loopers.domain.order.Order;
-import com.loopers.domain.order.OrderRepository;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Component;
-
-import java.util.Optional;
-
-/**
- * packageName : com.loopers.infrastructure.order
- * fileName     : OrderRepositroyImpl
- * author      : byeonsungmun
- * date        : 2025. 11. 14.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 14.     byeonsungmun       최초 생성
- */
-@Component
-@RequiredArgsConstructor
-public class OrderRepositoryImpl implements OrderRepository {
-
-    private final OrderJpaRepository orderJpaRepository;
-
-    @Override
-    public Order save(Order order) {
-        return orderJpaRepository.save(order);
-    }
-
-    @Override
-    public Optional<Order> findById(Long orderId) {
-        return  orderJpaRepository.findById(orderId);
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointJpaRepository.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointJpaRepository.java
deleted file mode 100644
index a35a56151..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointJpaRepository.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.loopers.infrastructure.point;
-
-import com.loopers.domain.point.Point;
-import org.springframework.data.jpa.repository.JpaRepository;
-
-import java.util.Optional;
-
-public interface PointJpaRepository extends JpaRepository<Point, Long> {
-
-    Optional<Point> findByUserId(String userId);
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointRepositoryImpl.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointRepositoryImpl.java
deleted file mode 100644
index 530191b66..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/infrastructure/point/PointRepositoryImpl.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.loopers.infrastructure.point;
-
-import com.loopers.domain.point.Point;
-import com.loopers.domain.point.PointRepository;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Component;
-
-import java.util.Optional;
-
-@RequiredArgsConstructor
-@Component
-public class PointRepositoryImpl implements PointRepository {
-
-    private final PointJpaRepository pointJpaRepository;
-
-    @Override
-    public Optional<Point> findByUserId(String userId) {
-        return pointJpaRepository.findByUserId(userId);
-    }
-
-    @Override
-    public Point save(Point point) {
-        return pointJpaRepository.save(point);
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/product/ProductJpaRepository.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/product/ProductJpaRepository.java
deleted file mode 100644
index 5ceaae067..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/infrastructure/product/ProductJpaRepository.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.loopers.infrastructure.product;
-
-import com.loopers.domain.product.Product;
-import org.springframework.data.jpa.repository.JpaRepository;
-
-/**
- * packageName : com.loopers.infrastructure.product
- * fileName     : ProductJpaRepository
- * author      : byeonsungmun
- * date        : 2025. 11. 13.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 13.     byeonsungmun       최초 생성
- */
-public interface ProductJpaRepository extends JpaRepository<Product, Long> {
-
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/product/ProductRepositoryImpl.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/product/ProductRepositoryImpl.java
deleted file mode 100644
index dbad0d9d5..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/infrastructure/product/ProductRepositoryImpl.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.loopers.infrastructure.product;
-
-import com.loopers.domain.product.Product;
-import com.loopers.domain.product.ProductRepository;
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-import lombok.RequiredArgsConstructor;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.Pageable;
-import org.springframework.stereotype.Component;
-
-import java.util.Optional;
-
-/**
- * packageName : com.loopers.infrastructure.product
- * fileName     : ProductRepositoryImpl
- * author      : byeonsungmun
- * date        : 2025. 11. 13.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 13.     byeonsungmun       최초 생성
- */
-@Component
-@RequiredArgsConstructor
-public class ProductRepositoryImpl implements ProductRepository {
-
-    private final ProductJpaRepository productJpaRepository;
-
-    @Override
-    public Page<Product> findAll(Pageable pageable) {
-        return productJpaRepository.findAll(pageable);
-    }
-
-    @Override
-    public Optional<Product> findById(Long id) {
-        return productJpaRepository.findById(id);
-    }
-
-    @Override
-    public void incrementLikeCount(Long productId) {
-        Product product = productJpaRepository.findById(productId)
-                .orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "상품을 찾을수 없습니다."));
-        product.increaseLikeCount();
-    }
-
-    @Override
-    public void decrementLikeCount(Long productId) {
-        Product product = productJpaRepository.findById(productId)
-                .orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "상품을 찾을수 없습니다."));
-        product.decreaseLikeCount();
-    }
-
-    @Override
-    public Product save(Product product) {
-        return productJpaRepository.save(product);
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserJpaRepository.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserJpaRepository.java
deleted file mode 100644
index f80a5bc52..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserJpaRepository.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.loopers.infrastructure.user;
-
-import com.loopers.domain.user.User;
-import org.springframework.data.jpa.repository.JpaRepository;
-
-import java.util.Optional;
-
-public interface UserJpaRepository extends JpaRepository<User, Long> {
-
-    Optional<User> findByUserId(String userId);
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserRepositoryImpl.java b/apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserRepositoryImpl.java
deleted file mode 100644
index 8fb6f7bdf..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/infrastructure/user/UserRepositoryImpl.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.loopers.infrastructure.user;
-
-import com.loopers.domain.user.User;
-import com.loopers.domain.user.UserRepository;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Component;
-
-import java.util.Optional;
-
-@RequiredArgsConstructor
-@Component
-public class UserRepositoryImpl implements UserRepository {
-
-    private final UserJpaRepository userJpaRepository;
-
-    @Override
-    public Optional<User> findByUserId(String userId) {
-        return userJpaRepository.findByUserId(userId);
-    }
-
-    @Override
-    public User save(User user) {
-        return userJpaRepository.save(user);
-    }
-}
-
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1ApiSpec.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1ApiSpec.java
new file mode 100644
index 000000000..219e3101e
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1ApiSpec.java
@@ -0,0 +1,19 @@
+package com.loopers.interfaces.api.example;
+
+import com.loopers.interfaces.api.ApiResponse;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+@Tag(name = "Example V1 API", description = "Loopers 예시 API 입니다.")
+public interface ExampleV1ApiSpec {
+
+    @Operation(
+        summary = "예시 조회",
+        description = "ID로 예시를 조회합니다."
+    )
+    ApiResponse<ExampleV1Dto.ExampleResponse> getExample(
+        @Schema(name = "예시 ID", description = "조회할 예시의 ID")
+        Long exampleId
+    );
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1Controller.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1Controller.java
new file mode 100644
index 000000000..917376016
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1Controller.java
@@ -0,0 +1,28 @@
+package com.loopers.interfaces.api.example;
+
+import com.loopers.application.example.ExampleFacade;
+import com.loopers.application.example.ExampleInfo;
+import com.loopers.interfaces.api.ApiResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/api/v1/examples")
+public class ExampleV1Controller implements ExampleV1ApiSpec {
+
+    private final ExampleFacade exampleFacade;
+
+    @GetMapping("/{exampleId}")
+    @Override
+    public ApiResponse<ExampleV1Dto.ExampleResponse> getExample(
+        @PathVariable(value = "exampleId") Long exampleId
+    ) {
+        ExampleInfo info = exampleFacade.getExample(exampleId);
+        ExampleV1Dto.ExampleResponse response = ExampleV1Dto.ExampleResponse.from(info);
+        return ApiResponse.success(response);
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1Dto.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1Dto.java
new file mode 100644
index 000000000..4ecf0eea5
--- /dev/null
+++ b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/example/ExampleV1Dto.java
@@ -0,0 +1,15 @@
+package com.loopers.interfaces.api.example;
+
+import com.loopers.application.example.ExampleInfo;
+
+public class ExampleV1Dto {
+    public record ExampleResponse(Long id, String name, String description) {
+        public static ExampleResponse from(ExampleInfo info) {
+            return new ExampleResponse(
+                info.id(),
+                info.name(),
+                info.description()
+            );
+        }
+    }
+}
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1ApiSpec.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1ApiSpec.java
deleted file mode 100644
index 6f0458399..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1ApiSpec.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.loopers.interfaces.api.point;
-
-import com.loopers.interfaces.api.ApiResponse;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.media.Schema;
-import io.swagger.v3.oas.annotations.tags.Tag;
-
-@Tag(name = "Point V1 API", description = "Point API 입니다.")
-public interface PointV1ApiSpec {
-
-    @Operation(
-            summary = "포인트 회원 조회",
-            description = "회원의 포인트를 조회한다."
-    )
-    ApiResponse<PointV1Dto.PointResponse> getPoint(
-            @Schema(name = "회원 Id", description = "조회할 회원 ID")
-            String userId
-    );
-
-    @Operation(
-            summary = "포인트 충전",
-            description = "회원의 포인트를 충전한다."
-    )
-    ApiResponse<PointV1Dto.PointResponse> chargePoint(
-            @Schema(name = "포인트 충전 요청", description = "충전할 포인트 정보를 포함한 요청")
-            PointV1Dto.ChargePointRequest request
-    );
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1Controller.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1Controller.java
deleted file mode 100644
index 866fce9b3..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1Controller.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.loopers.interfaces.api.point;
-
-import com.loopers.application.point.PointFacade;
-import com.loopers.application.point.PointInfo;
-import com.loopers.interfaces.api.ApiResponse;
-import lombok.RequiredArgsConstructor;
-import org.springframework.web.bind.annotation.*;
-
-@RequiredArgsConstructor
-@RestController
-@RequestMapping("/api/v1/points")
-public class PointV1Controller implements PointV1ApiSpec {
-
-    private final PointFacade pointFacade;
-
-    @Override
-    @GetMapping
-    public ApiResponse<PointV1Dto.PointResponse> getPoint(@RequestHeader("X-USER-ID") String userId) {
-        PointInfo pointInfo = pointFacade.getPoint(userId);
-        PointV1Dto.PointResponse response = PointV1Dto.PointResponse.from(pointInfo);
-        return ApiResponse.success(response);
-    }
-
-    @Override
-    @PatchMapping("/charge")
-    public ApiResponse<PointV1Dto.PointResponse> chargePoint(@RequestBody PointV1Dto.ChargePointRequest request) {
-        PointInfo pointInfo = pointFacade.chargePoint(request);
-        PointV1Dto.PointResponse response = PointV1Dto.PointResponse.from(pointInfo);
-        return ApiResponse.success(response);
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1Dto.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1Dto.java
deleted file mode 100644
index b0b3d050e..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/point/PointV1Dto.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.loopers.interfaces.api.point;
-
-import com.loopers.application.point.PointInfo;
-
-public class PointV1Dto {
-
-    public record ChargePointRequest(String userId, Long chargeAmount) {
-    }
-
-    public record PointResponse(String userId, Long amount) {
-        public static PointResponse from(PointInfo info) {
-            return new PointResponse(
-                    info.userId(),
-                    info.amount()
-            );
-        }
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1ApiSpec.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1ApiSpec.java
deleted file mode 100644
index 1bed68e62..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1ApiSpec.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.loopers.interfaces.api.user;
-
-import com.loopers.interfaces.api.ApiResponse;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.media.Schema;
-import io.swagger.v3.oas.annotations.tags.Tag;
-
-@Tag(name = "Users V1 API", description = "Users API 입니다.")
-public interface UserV1ApiSpec {
-
-    @Operation(
-            summary = "회원 가입",
-            description = "회원 가입을 합니다."
-    )
-    ApiResponse<UserV1Dto.UserResponse> register(
-            @Schema(name = "회원 가입 요청", description = "회원가입")
-            UserV1Dto.RegisterRequest request
-    );
-
-    @Operation(
-            summary = "회원 조회",
-            description = "해당 회원을 조회합니다."
-    )
-    ApiResponse<UserV1Dto.UserResponse> getUser(
-            @Schema(name = "회원 ID", description = "조회할 회원 ID")
-            String userId
-    );
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Controller.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Controller.java
deleted file mode 100644
index aed39ae1f..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Controller.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.loopers.interfaces.api.user;
-
-import com.loopers.application.user.UserFacade;
-import com.loopers.application.user.UserInfo;
-import com.loopers.interfaces.api.ApiResponse;
-import lombok.RequiredArgsConstructor;
-import org.springframework.web.bind.annotation.*;
-
-@RequiredArgsConstructor
-@RestController
-@RequestMapping("/api/v1/users")
-public class UserV1Controller implements UserV1ApiSpec {
-
-    private final UserFacade userFacade;
-
-    @Override
-    @PostMapping("/register")
-    public ApiResponse<UserV1Dto.UserResponse> register(@RequestBody UserV1Dto.RegisterRequest request) {
-        UserInfo userInfo = userFacade.register(request.userId(), request.mail(), request.birth(), request.gender());
-        UserV1Dto.UserResponse response = UserV1Dto.UserResponse.from(userInfo);
-        return ApiResponse.success(response);
-    }
-
-    @Override
-    @GetMapping("/{userId}")
-    public ApiResponse<UserV1Dto.UserResponse> getUser(@PathVariable String userId) {
-        UserInfo userInfo = userFacade.getUser(userId);
-        UserV1Dto.UserResponse response = UserV1Dto.UserResponse.from(userInfo);
-        return ApiResponse.success(response);
-    }
-}
diff --git a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Dto.java b/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Dto.java
deleted file mode 100644
index 263214848..000000000
--- a/apps/commerce-api/src/main/java/com/loopers/interfaces/api/user/UserV1Dto.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.loopers.interfaces.api.user;
-
-import com.loopers.application.user.UserInfo;
-
-public class UserV1Dto {
-    public record RegisterRequest(
-            String userId,
-            String mail,
-            String birth,
-            String gender
-    ) {
-    }
-
-    public record UserResponse(String userId, String email, String birth, String gender) {
-        public static UserResponse from(UserInfo info) {
-            return new UserResponse(
-                    info.userId(),
-                    info.email(),
-                    info.birth(),
-                    info.gender()
-            );
-        }
-    }
-}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/brand/BrandTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/brand/BrandTest.java
deleted file mode 100644
index 9541c11f4..000000000
--- a/apps/commerce-api/src/test/java/com/loopers/domain/brand/BrandTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.loopers.domain.brand;
-
-import com.loopers.support.error.CoreException;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-/**
- * packageName : com.loopers.domain.brand
- * fileName     : BrandTest
- * author      : byeonsungmun
- * date        : 2025. 11. 14.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 14.     byeonsungmun       최초 생성
- */
-class BrandTest {
-
-    @DisplayName("Brand 단위 테스트")
-    @Nested
-    class CreateBrandTest {
-
-        @Test
-        @DisplayName("브랜드 생성 성공")
-        void createBrandSuccess() {
-            Brand brand = Brand.create("Nike");
-            assertThat(brand.getName()).isEqualTo("Nike");
-        }
-
-        @Test
-        @DisplayName("브랜드 이름이 없으면 예외")
-        void createBrandFail() {
-            assertThatThrownBy(() -> Brand.create(""))
-                    .isInstanceOf(CoreException.class);
-        }
-    }
-}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/example/ExampleModelTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/example/ExampleModelTest.java
new file mode 100644
index 000000000..44ca7576e
--- /dev/null
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/example/ExampleModelTest.java
@@ -0,0 +1,65 @@
+package com.loopers.domain.example;
+
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class ExampleModelTest {
+    @DisplayName("예시 모델을 생성할 때, ")
+    @Nested
+    class Create {
+        @DisplayName("제목과 설명이 모두 주어지면, 정상적으로 생성된다.")
+        @Test
+        void createsExampleModel_whenNameAndDescriptionAreProvided() {
+            // arrange
+            String name = "제목";
+            String description = "설명";
+
+            // act
+            ExampleModel exampleModel = new ExampleModel(name, description);
+
+            // assert
+            assertAll(
+                () -> assertThat(exampleModel.getId()).isNotNull(),
+                () -> assertThat(exampleModel.getName()).isEqualTo(name),
+                () -> assertThat(exampleModel.getDescription()).isEqualTo(description)
+            );
+        }
+
+        @DisplayName("제목이 빈칸으로만 이루어져 있으면, BAD_REQUEST 예외가 발생한다.")
+        @Test
+        void throwsBadRequestException_whenTitleIsBlank() {
+            // arrange
+            String name = "   ";
+
+            // act
+            CoreException result = assertThrows(CoreException.class, () -> {
+                new ExampleModel(name, "설명");
+            });
+
+            // assert
+            assertThat(result.getErrorType()).isEqualTo(ErrorType.BAD_REQUEST);
+        }
+
+        @DisplayName("설명이 비어있으면, BAD_REQUEST 예외가 발생한다.")
+        @Test
+        void throwsBadRequestException_whenDescriptionIsEmpty() {
+            // arrange
+            String description = "";
+
+            // act
+            CoreException result = assertThrows(CoreException.class, () -> {
+                new ExampleModel("제목", description);
+            });
+
+            // assert
+            assertThat(result.getErrorType()).isEqualTo(ErrorType.BAD_REQUEST);
+        }
+    }
+}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/example/ExampleServiceIntegrationTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/example/ExampleServiceIntegrationTest.java
new file mode 100644
index 000000000..bbd5fdbe1
--- /dev/null
+++ b/apps/commerce-api/src/test/java/com/loopers/domain/example/ExampleServiceIntegrationTest.java
@@ -0,0 +1,72 @@
+package com.loopers.domain.example;
+
+import com.loopers.infrastructure.example.ExampleJpaRepository;
+import com.loopers.support.error.CoreException;
+import com.loopers.support.error.ErrorType;
+import com.loopers.utils.DatabaseCleanUp;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@SpringBootTest
+class ExampleServiceIntegrationTest {
+    @Autowired
+    private ExampleService exampleService;
+
+    @Autowired
+    private ExampleJpaRepository exampleJpaRepository;
+
+    @Autowired
+    private DatabaseCleanUp databaseCleanUp;
+
+    @AfterEach
+    void tearDown() {
+        databaseCleanUp.truncateAllTables();
+    }
+
+    @DisplayName("예시를 조회할 때,")
+    @Nested
+    class Get {
+        @DisplayName("존재하는 예시 ID를 주면, 해당 예시 정보를 반환한다.")
+        @Test
+        void returnsExampleInfo_whenValidIdIsProvided() {
+            // arrange
+            ExampleModel exampleModel = exampleJpaRepository.save(
+                new ExampleModel("예시 제목", "예시 설명")
+            );
+
+            // act
+            ExampleModel result = exampleService.getExample(exampleModel.getId());
+
+            // assert
+            assertAll(
+                () -> assertThat(result).isNotNull(),
+                () -> assertThat(result.getId()).isEqualTo(exampleModel.getId()),
+                () -> assertThat(result.getName()).isEqualTo(exampleModel.getName()),
+                () -> assertThat(result.getDescription()).isEqualTo(exampleModel.getDescription())
+            );
+        }
+
+        @DisplayName("존재하지 않는 예시 ID를 주면, NOT_FOUND 예외가 발생한다.")
+        @Test
+        void throwsException_whenInvalidIdIsProvided() {
+            // arrange
+            Long invalidId = 999L; // Assuming this ID does not exist
+
+            // act
+            CoreException exception = assertThrows(CoreException.class, () -> {
+                exampleService.getExample(invalidId);
+            });
+
+            // assert
+            assertThat(exception.getErrorType()).isEqualTo(ErrorType.NOT_FOUND);
+        }
+    }
+}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/like/LikeServiceIntegrationTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/like/LikeServiceIntegrationTest.java
deleted file mode 100644
index 0be07a6fb..000000000
--- a/apps/commerce-api/src/test/java/com/loopers/domain/like/LikeServiceIntegrationTest.java
+++ /dev/null
@@ -1,155 +0,0 @@
-package com.loopers.domain.like;
-
-import com.loopers.domain.product.Product;
-import com.loopers.domain.product.ProductRepository;
-import com.loopers.domain.user.User;
-import com.loopers.domain.user.UserRepository;
-import com.loopers.utils.DatabaseCleanUp;
-import org.junit.jupiter.api.*;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.transaction.annotation.Transactional;
-
-import static org.assertj.core.api.Assertions.*;
-
-/**
- * packageName : com.loopers.domain.like
- * fileName     : LikeServiceIntegrationTest
- * author      : byeonsungmun
- * date        : 2025. 11. 14.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 14.     byeonsungmun       최초 생성
- */
-@SpringBootTest
-class LikeServiceIntegrationTest {
-
-    @Autowired
-    private LikeService likeService;
-
-    @Autowired
-    private LikeRepository likeRepository;
-
-    @Autowired
-    private ProductRepository productRepository;
-
-    @Autowired
-    private UserRepository userRepository;
-
-    @Autowired
-    private DatabaseCleanUp cleanUp;
-
-    @AfterEach
-    void tearDown() {
-        cleanUp.truncateAllTables();
-    }
-
-    @Nested
-    @DisplayName("좋아요 기능 통합 테스트")
-    class LikeTests {
-
-        @Test
-        @DisplayName("좋아요 생성 성공 → 좋아요 저장 + 상품의 likeCount 증가")
-        @Transactional
-        void likeSuccess() {
-            // given
-            User user = userRepository.save(new User("user1", "u1@mail.com", "1990-01-01", "MALE"));
-            Product product = productRepository.save(Product.create(1L, "상품A", 1000L, 10L));
-
-            // when
-            likeService.like(user.getUserId(), product.getId());
-
-            // then
-            Like saved = likeRepository.findByUserIdAndProductId("user1", 1L).orElse(null);
-            assertThat(saved).isNotNull();
-
-            Product updated = productRepository.findById(1L).get();
-            assertThat(updated.getLikeCount()).isEqualTo(1L);
-        }
-
-        @Test
-        @DisplayName("중복 좋아요 시 likeCount 증가 안 하고 저장도 안 됨")
-        @Transactional
-        void duplicateLike() {
-            // given
-            userRepository.save(new User("user1", "u1@mail.com", "1990-01-01", "MALE"));
-            productRepository.save(Product.create(1L, "상품A", 1000L, 10L));
-
-            likeService.like("user1", 1L);
-
-            // when
-            likeService.like("user1", 1L); // 중복 호출
-
-            // then
-            long likeCount = likeRepository.countByProductId(1L);
-            assertThat(likeCount).isEqualTo(1L);
-
-            Product updated = productRepository.findById(1L).get();
-            assertThat(updated.getLikeCount()).isEqualTo(1L); // 증가 X
-        }
-
-        @Test
-        @DisplayName("좋아요 취소 성공 → like 삭제 + 상품의 likeCount 감소")
-        @Transactional
-        void unlikeSuccess() {
-            // given
-            userRepository.save(new User("user1", "u1@mail.com", "1990-01-01", "MALE"));
-            productRepository.save(Product.create(1L, "상품A", 1000L, 10L));
-
-            likeService.like("user1", 1L);
-
-            // when
-            likeService.unlike("user1", 1L);
-
-            // then
-            Like like = likeRepository.findByUserIdAndProductId("user1", 1L).orElse(null);
-            assertThat(like).isNull();
-
-            Product updated = productRepository.findById(1L).get();
-            assertThat(updated.getLikeCount()).isEqualTo(0L);
-        }
-
-        @Test
-        @DisplayName("없는 좋아요 취소 시 likeCount 감소 안 함")
-        @Transactional
-        void unlikeNonExisting() {
-            // given
-            userRepository.save(new User("user1", "u1@mail.com", "1990-01-01", "MALE"));
-            Product product = Product.create(1L, "상품A", 1000L, 10L);
-            product.increaseLikeCount();
-            product.increaseLikeCount();
-            product.increaseLikeCount();
-            product.increaseLikeCount();
-            product.increaseLikeCount();
-
-            productRepository.save(product);
-            // when — 호출은 해도
-            likeService.unlike("user1", 1L);
-
-            // then — 변화 없음
-            Product updated = productRepository.findById(1L).get();
-            assertThat(updated.getLikeCount()).isEqualTo(5L);
-        }
-
-        @Test
-        @DisplayName("countByProductId 정상 조회")
-        @Transactional
-        void countTest() {
-            // given
-            userRepository.save(new User("user1", "u1@mail.com", "1990-01-01", "MALE"));
-            userRepository.save(new User("user2", "u2@mail.com", "1991-01-01", "MALE"));
-            productRepository.save(Product.create(1L, "상품A", 1000L, 10L));
-
-            likeService.like("user1", 1L);
-            likeService.like("user2", 1L);
-
-            // when
-            long count = likeService.countByProductId(1L);
-
-            // then
-            assertThat(count).isEqualTo(2L);
-        }
-    }
-}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/like/LikeTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/like/LikeTest.java
deleted file mode 100644
index d5b8bd851..000000000
--- a/apps/commerce-api/src/test/java/com/loopers/domain/like/LikeTest.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package com.loopers.domain.like;
-
-import com.loopers.support.error.CoreException;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-
-import java.time.LocalDateTime;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-/**
- * packageName : com.loopers.domain.like
- * fileName     : LikeTest
- * author      : byeonsungmun
- * date        : 2025. 11. 13.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 13.     byeonsungmun       최초 생성
- */
-class LikeTest {
-
-
-    @DisplayName("정상적으로 Like 엔티티를 생성수 할 있다")
-    @Nested
-    class LikeCreate {
-
-        @DisplayName("Like생성자를 생성한다")
-        @Test
-        void createLike_success() {
-            // given
-            String userId = "user-001";
-            Long productId = 100L;
-
-            // when
-            Like like = Like.create(userId, productId);
-
-            // then
-            assertThat(like.getUserId()).isEqualTo(userId);
-            assertThat(like.getProductId()).isEqualTo(productId);
-            assertThat(like.getCreatedAt()).isBeforeOrEqualTo(LocalDateTime.now());
-        }
-
-        @Test
-        @DisplayName("userId가 null이면 예외가 발생한다")
-        void createLike_invalidUserId_null() {
-            // given
-            String userId = null;
-            Long productId = 100L;
-
-            // when & then
-            assertThrows(CoreException.class, () -> Like.create(userId, productId));
-        }
-
-        @Test
-        @DisplayName("userId가 빈 문자열이면 예외가 발생한다")
-        void createLike_invalidUserId_empty() {
-            // given
-            String userId = "";
-            Long productId = 100L;
-
-            // when & then
-            assertThrows(CoreException.class, () -> Like.create(userId, productId));
-        }
-
-        @Test
-        @DisplayName("productId가 null이면 예외가 발생한다")
-        void createLike_invalidProductId_null() {
-            // given
-            String userId = "user-001";
-            Long productId = null;
-
-            // when & then
-            assertThrows(CoreException.class, () -> Like.create(userId, productId));
-        }
-
-        @Test
-        @DisplayName("productId가 0 이하이면 예외가 발생한다")
-        void createLike_invalidProductId_zeroOrNegative() {
-            // given
-            String userId = "user-001";
-            Long productId = -1L;
-
-            // when & then
-            assertThrows(CoreException.class, () -> Like.create(userId, productId));
-        }
-    }
-}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/order/OrderServiceIntegrationTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/order/OrderServiceIntegrationTest.java
deleted file mode 100644
index 149e71540..000000000
--- a/apps/commerce-api/src/test/java/com/loopers/domain/order/OrderServiceIntegrationTest.java
+++ /dev/null
@@ -1,170 +0,0 @@
-package com.loopers.domain.order;
-
-import com.loopers.application.order.CreateOrderCommand;
-import com.loopers.application.order.OrderFacade;
-import com.loopers.application.order.OrderInfo;
-import com.loopers.application.order.OrderItemCommand;
-import com.loopers.domain.point.Point;
-import com.loopers.domain.point.PointRepository;
-import com.loopers.domain.product.Product;
-import com.loopers.domain.product.ProductRepository;
-import com.loopers.utils.DatabaseCleanUp;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.List;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-/**
- * packageName : com.loopers.domain.order
- * fileName     : OrderServiceIntegrationTest
- * author      : byeonsungmun
- * date        : 2025. 11. 14.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 14.     byeonsungmun       최초 생성
- */
-@SpringBootTest
-public class OrderServiceIntegrationTest {
-
-    @Autowired
-    private OrderFacade orderFacade;
-
-    @Autowired
-    private ProductRepository productRepository;
-
-    @Autowired
-    private PointRepository pointRepository;
-
-    @Autowired
-    private OrderRepository orderRepository;
-
-    @Autowired
-    private DatabaseCleanUp databaseCleanUp;
-
-    @AfterEach
-    void tearDown() {
-        databaseCleanUp.truncateAllTables();
-    }
-
-    @Nested
-    @DisplayName("주문 생성 성공")
-    class OrderCreateSuccess {
-
-        @Test
-        @Transactional
-        void createOrder_success() {
-
-            // given
-            Product p1 = productRepository.save(Product.create(1L, "아메리카노", 3000L, 100L));
-            Product p2 = productRepository.save(Product.create(1L, "라떼", 4000L, 200L));
-
-            pointRepository.save(Point.create("user1", 20000L));
-
-            CreateOrderCommand command = new CreateOrderCommand(
-                    "user1",
-                    List.of(
-                            new OrderItemCommand(p1.getId(), 2L),  // 6000원
-                            new OrderItemCommand(p2.getId(), 1L)   // 4000원
-                    )
-            );
-
-            // when
-            OrderInfo info = orderFacade.createOrder(command);
-
-            // then
-            Order saved = orderRepository.findById(info.orderId()).orElseThrow();
-
-            assertThat(saved.getStatus()).isEqualTo(OrderStatus.COMPLETE);
-            assertThat(saved.getTotalAmount()).isEqualTo(10000L);
-            assertThat(saved.getOrderItems()).hasSize(2);
-
-            // 재고 감소 확인
-            Product updated1 = productRepository.findById(p1.getId()).get();
-            Product updated2 = productRepository.findById(p2.getId()).get();
-            assertThat(updated1.getStock()).isEqualTo(98);
-            assertThat(updated2.getStock()).isEqualTo(199);
-
-            // 포인트 감소 확인
-            Point point = pointRepository.findByUserId("user1").get();
-            assertThat(point.getBalance()).isEqualTo(10000L);  // 20000 - 10000
-
-        }
-    }
-
-    @Nested
-    @DisplayName("주문 실패 케이스")
-    class OrderCreateFail {
-
-        @Test
-        @Transactional
-        @DisplayName("재고 부족으로 실패")
-        void insufficientStock_fail() {
-            Product item = productRepository.save(Product.create(1L, "상품", 1000L, 1L));
-            pointRepository.save(Point.create("user1", 5000L));
-
-            CreateOrderCommand command = new CreateOrderCommand(
-                    "user1",
-                    List.of(new OrderItemCommand(item.getId(), 5L))
-            );
-
-            assertThatThrownBy(() -> orderFacade.createOrder(command))
-                    .isInstanceOf(RuntimeException.class); // 너의 도메인 예외 타입 맞춰도 됨
-        }
-
-        @Test
-        @Transactional
-        @DisplayName("포인트 부족으로 실패")
-        void insufficientPoint_fail() {
-            Product item = productRepository.save(Product.create(1L, "상품", 1000L, 10L));
-            pointRepository.save(Point.create("user1", 2000L)); // 부족
-
-            CreateOrderCommand command = new CreateOrderCommand(
-                    "user1",
-                    List.of(new OrderItemCommand(item.getId(), 5L)) // 총 5000원
-            );
-
-            assertThatThrownBy(() -> orderFacade.createOrder(command))
-                    .hasMessageContaining("포인트"); // 메시지 맞추면 더 정확하게 가능
-        }
-
-        @Test
-        @Transactional
-        @DisplayName("없는 상품 주문 시 실패")
-        void noProduct_fail() {
-            pointRepository.save(Point.create("user1", 10000L));
-
-            CreateOrderCommand command = new CreateOrderCommand(
-                    "user1",
-                    List.of(new OrderItemCommand(999L, 1L))
-            );
-
-            assertThatThrownBy(() -> orderFacade.createOrder(command))
-                    .isInstanceOf(RuntimeException.class);
-        }
-
-        @Test
-        @Transactional
-        @DisplayName("유저 포인트 정보 없으면 실패")
-        void noUserPoint_fail() {
-            Product item = productRepository.save(Product.create(1L, "상품", 1000L, 10L));
-
-            CreateOrderCommand command = new CreateOrderCommand(
-                    "user1",
-                    List.of(new OrderItemCommand(item.getId(), 1L))
-            );
-
-            assertThatThrownBy(() -> orderFacade.createOrder(command))
-                    .isInstanceOf(RuntimeException.class);
-        }
-    }
-}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/order/OrderTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/order/OrderTest.java
deleted file mode 100644
index 60ed16ecc..000000000
--- a/apps/commerce-api/src/test/java/com/loopers/domain/order/OrderTest.java
+++ /dev/null
@@ -1,122 +0,0 @@
-package com.loopers.domain.order;
-
-import com.loopers.support.error.CoreException;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-/**
- * packageName : com.loopers.domain.order
- * fileName     : OrderTest
- * author      : byeonsungmun
- * date        : 2025. 11. 14.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 14.     byeonsungmun       최초 생성
- */
-class OrderTest {
-
-    @Nested
-    @DisplayName("Order 생성 테스트")
-    class CreateOrderTest {
-
-        @Test
-        @DisplayName("주문 생성 성공")
-        void createOrderSuccess() {
-            // when
-            Order order = Order.create("user123");
-
-            // then
-            assertThat(order.getUserId()).isEqualTo("user123");
-            assertThat(order.getStatus()).isEqualTo(OrderStatus.PENDING);
-            assertThat(order.getTotalAmount()).isEqualTo(0L);
-            assertThat(order.getCreatedAt()).isNotNull();
-            assertThat(order.getOrderItems()).isEmpty();
-        }
-
-        @Test
-        @DisplayName("userId가 null이면 생성 실패")
-        void createOrderFailUserIdNull() {
-            assertThatThrownBy(() -> Order.create(null))
-                    .isInstanceOf(CoreException.class)
-                    .hasMessageContaining("사용자 ID는 필수");
-        }
-
-        @Test
-        @DisplayName("userId가 공백이면 생성 실패")
-        void createOrderFailUserIdBlank() {
-            assertThatThrownBy(() -> Order.create(""))
-                    .isInstanceOf(CoreException.class)
-                    .hasMessageContaining("사용자 ID는 필수");
-        }
-    }
-
-    @Nested
-    @DisplayName("Order 상태 업데이트 테스트")
-    class UpdateStatusTest {
-
-        @Test
-        @DisplayName("주문 상태 업데이트 성공")
-        void updateStatusSuccess() {
-            // given
-            Order order = Order.create("user123");
-
-            // when
-            order.updateStatus(OrderStatus.COMPLETE);
-
-            // then
-            assertThat(order.getStatus()).isEqualTo(OrderStatus.COMPLETE);
-        }
-    }
-
-    @Nested
-    @DisplayName("총액 업데이트 테스트")
-    class UpdateAmountTest {
-
-        @Test
-        @DisplayName("총액 업데이트 성공")
-        void updateTotalAmountSuccess() {
-            // given
-            Order order = Order.create("user123");
-
-            // when
-            order.updateTotalAmount(5000L);
-
-            // then
-            assertThat(order.getTotalAmount()).isEqualTo(5000L);
-        }
-    }
-
-    @Nested
-    @DisplayName("OrderItem 추가 테스트")
-    class AddOrderItemTest {
-
-        @Test
-        @DisplayName("OrderItem 추가 성공")
-        void addOrderItemSuccess() {
-            // given
-            Order order = Order.create("user123");
-
-            OrderItem item = OrderItem.create(
-                    1L,
-                    "상품명",
-                    2L,
-                    1000L
-            );
-
-            // when
-            order.addOrderItem(item);
-            item.setOrder(order);
-
-            // then
-            assertThat(order.getOrderItems()).hasSize(1);
-            assertThat(order.getOrderItems().getFirst().getProductName()).isEqualTo("상품명");
-            assertThat(item.getOrder()).isEqualTo(order);
-        }
-    }
-}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/point/PointServiceIntegrationTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/point/PointServiceIntegrationTest.java
deleted file mode 100644
index b623bc9c7..000000000
--- a/apps/commerce-api/src/test/java/com/loopers/domain/point/PointServiceIntegrationTest.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package com.loopers.domain.point;
-
-import com.loopers.domain.user.User;
-import com.loopers.domain.user.UserRepository;
-import com.loopers.support.error.CoreException;
-import com.loopers.support.error.ErrorType;
-import com.loopers.utils.DatabaseCleanUp;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-@SpringBootTest
-class PointServiceIntegrationTest {
-
-    @Autowired
-    private PointRepository pointRepository;
-
-    @Autowired
-    private UserRepository userRepository;
-
-    @Autowired
-    private PointService pointService;
-
-    @Autowired
-    private DatabaseCleanUp databaseCleanUp;
-
-    @AfterEach
-    void tearDown() {
-        databaseCleanUp.truncateAllTables();
-    }
-
-    @DisplayName("포인트 조회 통합 테스트")
-    @Nested
-    class PointUser {
-
-        @DisplayName("해당 ID의 회원이 존재할 경우, 보유 포인트가 반환된다.")
-        @Test
-        void returnPointInfo_whenValidIdIsProvided() {
-            //given
-            String id = "yh45g";
-            String email = "yh45g@loopers.com";
-            String birth = "1994-12-05";
-            String gender = "MALE";
-
-            userRepository.save(new User(id, email, birth, gender));
-            pointRepository.save(Point.create(id, 0L));
-
-            //when
-            Point result = pointService.findPointByUserId(id);
-
-            //then
-            assertThat(result.getUserId()).isEqualTo(id);
-            assertThat(result.getBalance()).isEqualTo(0L);
-        }
-
-        @DisplayName("회원이 존재 하지 않을 경우, null 이 반환된다.")
-        @Test
-        void returnNull_whenInvalidUserIdIsProvided() {
-            //given
-            String id = "yh45g";
-
-            //when
-            Point point = pointService.findPointByUserId(id);
-
-            //then
-            assertThat(point).isNull();
-        }
-    }
-
-    @DisplayName("포인트 충전 통합 테스트")
-    @Nested
-    class Charge {
-
-        @DisplayName("존재하지 않는 유저 ID 로 충전을 시도한 경우, 실패한다.")
-        @Test
-        void throwsChargeAmountFailException_whenUserIDIsNotProvided() {
-            //given
-            String id = "yh45g";
-
-            //when
-            CoreException exception = assertThrows(CoreException.class, () -> pointService.chargePoint(id, 1000L));
-
-            //then
-            assertThat(exception.getErrorType()).isEqualTo(ErrorType.NOT_FOUND);
-        }
-
-        @Test
-        @DisplayName("회원이 존재하면 포인트 충전 성공")
-        void chargeSuccess() {
-            // given
-            String userId = "user2";
-            userRepository.save(new User(userId, "yh45g@loopers.com", "1994-12-05", "MALE"));
-            pointRepository.save(Point.create(userId, 1000L));
-
-            // when
-            Point updated = pointService.chargePoint(userId, 500L);
-
-            // then
-            assertThat(updated.getBalance()).isEqualTo(1500L);
-        }
-    }
-}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/point/PointTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/point/PointTest.java
deleted file mode 100644
index f33fb2821..000000000
--- a/apps/commerce-api/src/test/java/com/loopers/domain/point/PointTest.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package com.loopers.domain.point;
-
-import com.loopers.support.error.CoreException;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-
-import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
-import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
-
-class PointTest {
-
-    @Nested
-    @DisplayName("포인트 생성 테스트")
-    class CreatePointTest {
-
-        @Test
-        @DisplayName("포인트 생성 성공")
-        void createPointSuccess() {
-            // when
-            Point point = Point.create("user123", 100L);
-
-            // then
-            assertThat(point.getUserId()).isEqualTo("user123");
-            assertThat(point.getBalance()).isEqualTo(100L);
-        }
-
-        @Test
-        @DisplayName("userId가 null이면 생성 실패")
-        void createPointFailUserIdNull() {
-            assertThatThrownBy(() -> Point.create(null, 100L))
-                    .isInstanceOf(CoreException.class)
-                    .hasMessageContaining("사용자 ID가 비어있을 수 없습니다.");
-        }
-
-        @Test
-        @DisplayName("userId가 공백이면 생성 실패")
-        void createPointFailUserIdBlank() {
-            assertThatThrownBy(() -> Point.create("", 100L))
-                    .isInstanceOf(CoreException.class)
-                    .hasMessageContaining("사용자 ID가 비어있을 수 없습니다.");
-        }
-    }
-
-    @Nested
-    @DisplayName("포인트 충전 테스트")
-    class ChargePointTest {
-
-        @Test
-        @DisplayName("포인트 충전 성공")
-        void chargeSuccess() {
-            // given
-            Point point = Point.create("user123", 100L);
-
-            // when
-            point.charge(50L);
-
-            // then
-            assertThat(point.getBalance()).isEqualTo(150L);
-        }
-
-        @Test
-        @DisplayName("포인트 충전 실패 - 0 이하 입력")
-        void chargeFailZeroOrNegative() {
-            Point point = Point.create("user123", 100L);
-
-            assertThatThrownBy(() -> point.charge(0L))
-                    .isInstanceOf(CoreException.class)
-                    .hasMessageContaining("충전");
-
-            assertThatThrownBy(() -> point.charge(-10L))
-                    .isInstanceOf(CoreException.class);
-        }
-    }
-
-    @Nested
-    @DisplayName("포인트 사용 테스트")
-    class UsePointTest {
-
-        @Test
-        @DisplayName("포인트 사용 성공")
-        void useSuccess() {
-            // given
-            Point point = Point.create("user123", 100L);
-
-            // when
-            point.use(40L);
-
-            // then
-            assertThat(point.getBalance()).isEqualTo(60L);
-        }
-
-        @Test
-        @DisplayName("포인트 사용 실패 - 0 이하 입력")
-        void useFailZeroOrNegative() {
-            Point point = Point.create("user123", 100L);
-
-            assertThatThrownBy(() -> point.use(0L))
-                    .isInstanceOf(CoreException.class)
-                    .hasMessageContaining("사용할 수 없습니다.");
-
-            assertThatThrownBy(() -> point.use(-10L))
-                    .isInstanceOf(CoreException.class);
-        }
-
-        @Test
-        @DisplayName("포인트 사용 실패 - 잔액 부족")
-        void useFailNotEnough() {
-            Point point = Point.create("user123", 50L);
-
-            assertThatThrownBy(() -> point.use(100L))
-                    .isInstanceOf(CoreException.class)
-                    .hasMessageContaining("포인트가 부족");
-        }
-    }
-
-}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/product/ProductServiceIntegrationTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/product/ProductServiceIntegrationTest.java
deleted file mode 100644
index 8ad61a194..000000000
--- a/apps/commerce-api/src/test/java/com/loopers/domain/product/ProductServiceIntegrationTest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.loopers.domain.product;
-
-import com.loopers.utils.DatabaseCleanUp;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Nested;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-
-/**
- * packageName : com.loopers.domain.product
- * fileName     : ProductServiceIntegrationTest
- * author      : byeonsungmun
- * date        : 2025. 11. 13.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 13.     byeonsungmun       최초 생성
- */
-
-@SpringBootTest
-public class ProductServiceIntegrationTest {
-
-    @Autowired
-    private ProductService productService;
-
-    @Autowired
-    private DatabaseCleanUp databaseCleanUp;
-
-    @AfterEach
-    void tearDown() {
-        databaseCleanUp.truncateAllTables();
-    }
-
-    @Nested
-    @DisplayName("상품 목록 조회 테스트")
-    class ProductListTests {
-
-        Product product;
-
-    }
-}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/product/ProductTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/product/ProductTest.java
deleted file mode 100644
index c2c6fdd9b..000000000
--- a/apps/commerce-api/src/test/java/com/loopers/domain/product/ProductTest.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package com.loopers.domain.product;
-
-import com.loopers.support.error.CoreException;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-/**
- * packageName : com.loopers.domain.product
- * fileName     : ProductTest
- * author      : byeonsungmun
- * date        : 2025. 11. 10.
- * description :
- * ===========================================
- * DATE         AUTHOR       NOTE
- * -------------------------------------------
- * 2025. 11. 10.     byeonsungmun       최초 생성
- */
-class ProductTest {
-    @DisplayName("Product 좋아요 수 증감 테스트")
-    @Nested
-    class LikeCountChange {
-
-        @DisplayName("좋아요 수를 증가시킨다.")
-        @Test
-        void increaseLikeCount_incrementsLikeCount() {
-            // given
-            Product product = Product.create(11L, "나이키 에어2", 30000L, 10L);
-
-            // when
-            product.increaseLikeCount();
-
-            // then
-            assertEquals(1L, product.getLikeCount());
-        }
-
-        @DisplayName("좋아요 수를 감소시킨다. 0 미만으로는 감소하지 않는다.")
-        @Test
-        void decreaseLikeCount_decrementsLikeCountButNotBelowZero() {
-            // given
-            Product product = Product.create(11L, "나이키 에어2", 30000L, 1L);
-
-            // when
-            product.decreaseLikeCount();
-
-            // then
-            assertEquals(0L, product.getLikeCount());
-
-            // when decrease again
-            product.decreaseLikeCount();
-
-            // then likeCount should not go below 0
-            assertEquals(0L, product.getLikeCount());
-        }
-    }
-
-    @DisplayName("Product 재고 차감 테스트")
-    @Nested
-    class Stock {
-
-        @DisplayName("재고를 정상 차감한다.")
-        @Test
-        void decreaseStock_successfullyDecreasesStock() {
-            // given
-            Product product = Product.create(1L, "나이키 에어2", 30000L, 10L);
-
-            // when
-            product.decreaseStock(3L);
-
-            // then
-            assertEquals(7, product.getStock());
-        }
-
-        @DisplayName("차감 수량이 0 이하이면 예외 발생")
-        @Test
-        void decreaseStock_withInvalidQuantity_throwsException() {
-            Product product = Product.create(1L, "나이키 에어2", 30000L, 10L);
-
-            assertThrows(CoreException.class, () -> product.decreaseStock(0L));
-            assertThrows(CoreException.class, () -> product.decreaseStock(-1L));
-        }
-
-        @DisplayName("재고보다 큰 수량 차감 시 예외 발생")
-        @Test
-        void decreaseStock_withInsufficientStock_throwsException() {
-            Product product = Product.create(1L, "나이키 에어2", 30000L, 10L);
-
-            assertThrows(CoreException.class, () -> product.decreaseStock(11L));
-        }
-    }
-}
-
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java
deleted file mode 100644
index 71091883f..000000000
--- a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserServiceIntegrationTest.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package com.loopers.domain.user;
-
-import com.loopers.support.error.CoreException;
-import com.loopers.utils.DatabaseCleanUp;
-import org.junit.jupiter.api.*;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertAll;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-@SpringBootTest
-class UserServiceIntegrationTest {
-
-    @Autowired
-    private UserRepository userRepository;
-
-    @Autowired
-    private UserService userService;
-
-    @Autowired
-    private DatabaseCleanUp databaseCleanUp;
-
-    @AfterEach
-    void tearDown() {
-        databaseCleanUp.truncateAllTables();
-    }
-
-    @DisplayName("회원 가입 통합 테스트")
-    @Nested
-    class UserRegister {
-
-        @DisplayName("회원 가입시 User 저장이 수행된다.")
-        @Test
-        void save_whenUserRegister() {
-            //given
-            String userId = "yh45g";
-            String email = "yh45g@loopers.com";
-            String brith = "1994-12-05";
-            String gender = "Male";
-
-            UserRepository userRepositorySpy = spy(userRepository);
-            UserService userServiceSpy = new UserService(userRepositorySpy);
-
-            //when
-            userServiceSpy.register(userId, email, brith, gender);
-
-            //then
-            verify(userRepositorySpy).save(any(User.class));
-        }
-
-        @DisplayName("이미 가입된 ID 로 회원가입 시도 시, 실패한다.")
-        @Test
-        void throwsException_whenDuplicateUserId() {
-            //given
-            String userId = "yh45g";
-            String email = "yh45g@loopers.com";
-            String brith = "1994-12-05";
-            String gender = "Male";
-
-            //when
-            userService.register(userId, email, brith, gender);
-
-            //then
-            Assertions.assertThrows(CoreException.class, ()
-                    -> userService.register(userId, email, brith, gender));
-        }
-    }
-
-    @DisplayName("내 정보 조회 통합 테스트")
-    @Nested
-    class Get {
-
-        @DisplayName("해당 ID 의 회원이 존재할 경우, 회원 정보가 반환된다.")
-        @Test
-        void returnsUser_whenValidIdIsProvided() {
-            //given
-            String userId = "yh45g";
-            String email = "yh45g@loopers.com";
-            String brith = "1994-12-05";
-            String gender = "Male";
-
-            //when
-            userService.register(userId, email, brith, gender);
-            User user = userService.findUserByUserId(userId);
-
-            //then
-            assertAll(
-                    () -> assertThat(user.getUserId()).isEqualTo(userId),
-                    () -> assertThat(user.getEmail()).isEqualTo(email),
-                    () -> assertThat(user.getBirth()).isEqualTo(brith),
-                    () -> assertThat(user.getGender()).isEqualTo(gender)
-            );
-        }
-
-        @DisplayName("해당 ID 의 회원이 존재하지 않을 경우, null 이 반환된다.")
-        @Test
-        void returnNull_whenInvalidUserIdIsProvided() {
-            //given
-            String userId = "yh45g";
-
-            //when
-            User user = userService.findUserByUserId(userId);
-
-            //then
-            assertThat(user).isNull();
-        }
-    }
-}
diff --git a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserTest.java b/apps/commerce-api/src/test/java/com/loopers/domain/user/UserTest.java
deleted file mode 100644
index 7d74fdfe2..000000000
--- a/apps/commerce-api/src/test/java/com/loopers/domain/user/UserTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.loopers.domain.user;
-
-import com.loopers.support.error.CoreException;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-class UserTest {
-    @DisplayName("User 단위 테스트")
-    @Nested
-    class Create {
-        @DisplayName("ID 가 영문 및 숫자 10자 이내 형식에 맞지 않으면, User 객체 생성에 실패한다.")
-        @Test
-        void throwsException_whenInvalidUserIdFormat() {
-            // given
-            String invalidUserId = "invalid_id_123"; // 10자 초과 + 특수문자 포함
-            String email = "valid@loopers.com";
-            String birth = "1994-12-05";
-            String gender = "MALE";
-
-            // when & then
-            assertThrows(CoreException.class, () -> new User(invalidUserId, email, birth, gender));
-        }
-
-        @DisplayName("이메일이 `xx@yy.zz` 형식에 맞지 않으면, User 객체 생성에 실패한다.")
-        @Test
-        void throwsException_whenInvalidEmailFormat() {
-            // given
-            String userId = "yh45g";
-            String invalidEmail = "invalid-email-format"; // '@' 없음
-            String birth = "1994-12-05";
-            String gender = "MALE";
-
-            // when & then
-            assertThrows(CoreException.class, () -> new User(userId, invalidEmail, birth, gender));
-        }
-
-        @DisplayName("생년월일이 `yyyy-MM-dd` 형식에 맞지 않으면, User 객체 생성에 실패한다.")
-        @Test
-        void throwsException_whenInvalidBirthFormat() {
-            // given
-            String userId = "yh45g";
-            String email = "valid@loopers.com";
-            String invalidBirth = "19941205"; // 형식 오류: 하이픈 없음
-            String gender = "MALE";
-
-            // when & then
-            assertThrows(CoreException.class, () -> new User(userId, email, invalidBirth, gender));
-        }
-    }
-}
diff --git a/apps/commerce-api/src/test/java/com/loopers/interfaces/api/ExampleV1ApiE2ETest.java b/apps/commerce-api/src/test/java/com/loopers/interfaces/api/ExampleV1ApiE2ETest.java
new file mode 100644
index 000000000..1bb3dba65
--- /dev/null
+++ b/apps/commerce-api/src/test/java/com/loopers/interfaces/api/ExampleV1ApiE2ETest.java
@@ -0,0 +1,114 @@
+package com.loopers.interfaces.api;
+
+import com.loopers.domain.example.ExampleModel;
+import com.loopers.infrastructure.example.ExampleJpaRepository;
+import com.loopers.interfaces.api.example.ExampleV1Dto;
+import com.loopers.utils.DatabaseCleanUp;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+
+import java.util.function.Function;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+class ExampleV1ApiE2ETest {
+
+    private static final Function<Long, String> ENDPOINT_GET = id -> "/api/v1/examples/" + id;
+
+    private final TestRestTemplate testRestTemplate;
+    private final ExampleJpaRepository exampleJpaRepository;
+    private final DatabaseCleanUp databaseCleanUp;
+
+    @Autowired
+    public ExampleV1ApiE2ETest(
+        TestRestTemplate testRestTemplate,
+        ExampleJpaRepository exampleJpaRepository,
+        DatabaseCleanUp databaseCleanUp
+    ) {
+        this.testRestTemplate = testRestTemplate;
+        this.exampleJpaRepository = exampleJpaRepository;
+        this.databaseCleanUp = databaseCleanUp;
+    }
+
+    @AfterEach
+    void tearDown() {
+        databaseCleanUp.truncateAllTables();
+    }
+
+    @DisplayName("GET /api/v1/examples/{id}")
+    @Nested
+    class Get {
+        @DisplayName("존재하는 예시 ID를 주면, 해당 예시 정보를 반환한다.")
+        @Test
+        void returnsExampleInfo_whenValidIdIsProvided() {
+            // arrange
+            ExampleModel exampleModel = exampleJpaRepository.save(
+                new ExampleModel("예시 제목", "예시 설명")
+            );
+            String requestUrl = ENDPOINT_GET.apply(exampleModel.getId());
+
+            // act
+            ParameterizedTypeReference<ApiResponse<ExampleV1Dto.ExampleResponse>> responseType = new ParameterizedTypeReference<>() {};
+            ResponseEntity<ApiResponse<ExampleV1Dto.ExampleResponse>> response =
+                testRestTemplate.exchange(requestUrl, HttpMethod.GET, new HttpEntity<>(null), responseType);
+
+            // assert
+            assertAll(
+                () -> assertTrue(response.getStatusCode().is2xxSuccessful()),
+                () -> assertThat(response.getBody().data().id()).isEqualTo(exampleModel.getId()),
+                () -> assertThat(response.getBody().data().name()).isEqualTo(exampleModel.getName()),
+                () -> assertThat(response.getBody().data().description()).isEqualTo(exampleModel.getDescription())
+            );
+        }
+
+        @DisplayName("숫자가 아닌 ID 로 요청하면, 400 BAD_REQUEST 응답을 받는다.")
+        @Test
+        void throwsBadRequest_whenIdIsNotProvided() {
+            // arrange
+            String requestUrl = "/api/v1/examples/나나";
+
+            // act
+            ParameterizedTypeReference<ApiResponse<ExampleV1Dto.ExampleResponse>> responseType = new ParameterizedTypeReference<>() {};
+            ResponseEntity<ApiResponse<ExampleV1Dto.ExampleResponse>> response =
+                testRestTemplate.exchange(requestUrl, HttpMethod.GET, new HttpEntity<>(null), responseType);
+
+            // assert
+            assertAll(
+                () -> assertTrue(response.getStatusCode().is4xxClientError()),
+                () -> assertThat(response.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST)
+            );
+        }
+
+        @DisplayName("존재하지 않는 예시 ID를 주면, 404 NOT_FOUND 응답을 받는다.")
+        @Test
+        void throwsException_whenInvalidIdIsProvided() {
+            // arrange
+            Long invalidId = -1L;
+            String requestUrl = ENDPOINT_GET.apply(invalidId);
+
+            // act
+            ParameterizedTypeReference<ApiResponse<ExampleV1Dto.ExampleResponse>> responseType = new ParameterizedTypeReference<>() {};
+            ResponseEntity<ApiResponse<ExampleV1Dto.ExampleResponse>> response =
+                testRestTemplate.exchange(requestUrl, HttpMethod.GET, new HttpEntity<>(null), responseType);
+
+            // assert
+            assertAll(
+                () -> assertTrue(response.getStatusCode().is4xxClientError()),
+                () -> assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND)
+            );
+        }
+    }
+}
diff --git a/apps/commerce-api/src/test/java/com/loopers/interfaces/api/point/PointV1ControllerTest.java b/apps/commerce-api/src/test/java/com/loopers/interfaces/api/point/PointV1ControllerTest.java
deleted file mode 100644
index 7d7a2c18c..000000000
--- a/apps/commerce-api/src/test/java/com/loopers/interfaces/api/point/PointV1ControllerTest.java
+++ /dev/null
@@ -1,156 +0,0 @@
-package com.loopers.interfaces.api.point;
-
-import com.loopers.domain.point.Point;
-import com.loopers.domain.point.PointRepository;
-import com.loopers.domain.user.User;
-import com.loopers.domain.user.UserRepository;
-import com.loopers.interfaces.api.ApiResponse;
-import com.loopers.utils.DatabaseCleanUp;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.web.client.TestRestTemplate;
-import org.springframework.core.ParameterizedTypeReference;
-import org.springframework.http.*;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertAll;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
-class PointV1ControllerTest {
-
-    private static final String GET_USER_POINT_ENDPOINT = "/api/v1/points";
-    private static final String POST_USER_POINT_ENDPOINT = "/api/v1/points/charge";
-
-    @Autowired
-    private PointRepository pointRepository;
-
-    @Autowired
-    private UserRepository userRepository;
-
-    @Autowired
-    private DatabaseCleanUp databaseCleanUp;
-
-    @Autowired
-    private TestRestTemplate testRestTemplate;
-
-    @AfterEach
-    void tearDown() {
-        databaseCleanUp.truncateAllTables();
-    }
-
-    @DisplayName("GET /api/v1/points")
-    @Nested
-    class UserPoint {
-
-        @DisplayName("포인트 조회에 성공할 경우, 보유 포인트를 응답으로 반환한다.")
-        @Test
-        void returnPoint_whenValidUserIdIsProvided() {
-            //given
-            String id = "yh45g";
-            String email = "yh45g@loopers.com";
-            String birth = "1994-12-05";
-            String gender = "MALE";
-            Long amount = 1000L;
-
-            userRepository.save(new User(id, email, birth, gender));
-            pointRepository.save(Point.create(id, amount));
-
-            HttpHeaders headers = new HttpHeaders();
-            headers.add("X-USER-ID", id);
-
-            //when
-            ParameterizedTypeReference<ApiResponse<PointV1Dto.PointResponse>> responseType = new ParameterizedTypeReference<>() {};
-            ResponseEntity<ApiResponse<PointV1Dto.PointResponse>> response =
-                    testRestTemplate.exchange(GET_USER_POINT_ENDPOINT, HttpMethod.GET, new HttpEntity<>(null, headers), responseType);
-
-            //then
-            assertAll(
-                    () -> assertTrue(response.getStatusCode().is2xxSuccessful()),
-                    () -> assertThat(response.getBody().data().userId()).isEqualTo(id),
-                    () -> assertThat(response.getBody().data().amount()).isEqualTo(1000L)
-            );
-        }
-
-        @DisplayName("해당 ID의 회원이 존재하지 않을 경우, null을 반환한다.")
-        @Test
-        void returnNull_whenUserIdExists() {
-            //given
-            String id = "yh45g";
-
-            HttpHeaders headers = new HttpHeaders();
-            headers.add("X-USER-ID", id);
-
-            //when
-            ParameterizedTypeReference<ApiResponse<PointV1Dto.PointResponse>> responseType = new ParameterizedTypeReference<>() {};
-            ResponseEntity<ApiResponse<PointV1Dto.PointResponse>> response =
-                    testRestTemplate.exchange(GET_USER_POINT_ENDPOINT, HttpMethod.GET, new HttpEntity<>(null, headers), responseType);
-
-            //then
-            assertAll(
-                    () -> assertTrue(response.getStatusCode().is4xxClientError()),
-                    () -> assertThat(response.getBody().data()).isNull()
-            );
-        }
-    }
-
-    @DisplayName("POST /api/v1/points/charge")
-    @Nested
-    class Charge {
-
-        @DisplayName("존재하는 유저가 1000원을 충전할 경우, 충전된 보유 총량을 응답으로 반환한다.")
-        @Test
-        void returnsTotalPoint_whenChargeUserPoint() {
-            //given
-            String id = "yh45g";
-            String email = "yh45g@loopers.com";
-            String birth = "1994-12-05";
-            String gender = "MALE";
-
-            userRepository.save(new User(id, email, birth, gender));
-            pointRepository.save(Point.create(id, 0L));
-
-            PointV1Dto.ChargePointRequest request = new PointV1Dto.ChargePointRequest(id, 1000L);
-
-            HttpHeaders headers = new HttpHeaders();
-            headers.add("X-USER-ID", id);
-
-            //when
-            ParameterizedTypeReference<ApiResponse<PointV1Dto.PointResponse>> responseType = new ParameterizedTypeReference<>() {};
-            ResponseEntity<ApiResponse<PointV1Dto.PointResponse>> response =
-                    testRestTemplate.exchange(POST_USER_POINT_ENDPOINT, HttpMethod.PATCH, new HttpEntity<>(request, headers), responseType);
-
-            //then
-            assertAll(
-                    () -> assertTrue(response.getStatusCode().is2xxSuccessful()),
-                    () -> assertThat(response.getBody().data().userId()).isEqualTo(id),
-                    () -> assertThat(response.getBody().data().amount()).isEqualTo(1000L)
-            );
-        }
-
-        @DisplayName("존재하지 않는 유저로 요청할 경우, 404 Not Found 응답을 반환한다.")
-        @Test
-        void throwsException_whenInvalidUserIdIsProvided() {
-            //given
-            String id = "yh45g";
-
-            HttpHeaders headers = new HttpHeaders();
-            headers.add("X-USER-ID", id);
-
-            //when
-            ParameterizedTypeReference<ApiResponse<PointV1Dto.PointResponse>> responseType = new ParameterizedTypeReference<>() {};
-            ResponseEntity<ApiResponse<PointV1Dto.PointResponse>> response =
-                    testRestTemplate.exchange(POST_USER_POINT_ENDPOINT, HttpMethod.PATCH, new HttpEntity<>(null, headers), responseType);
-
-            //then
-            assertAll(
-                    () -> assertTrue(response.getStatusCode().is4xxClientError()),
-                    () -> assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND)
-            );
-        }
-    }
-}
diff --git a/apps/commerce-api/src/test/java/com/loopers/interfaces/api/user/UserV1ControllerTest.java b/apps/commerce-api/src/test/java/com/loopers/interfaces/api/user/UserV1ControllerTest.java
deleted file mode 100644
index defe2fcd5..000000000
--- a/apps/commerce-api/src/test/java/com/loopers/interfaces/api/user/UserV1ControllerTest.java
+++ /dev/null
@@ -1,148 +0,0 @@
-package com.loopers.interfaces.api.user;
-
-import com.loopers.domain.user.User;
-import com.loopers.infrastructure.user.UserJpaRepository;
-import com.loopers.interfaces.api.ApiResponse;
-import com.loopers.utils.DatabaseCleanUp;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.web.client.TestRestTemplate;
-import org.springframework.core.ParameterizedTypeReference;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-
-import java.util.function.Function;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertAll;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
-class UserV1ControllerTest {
-
-    private static final String USER_REGISTER_ENDPOINT = "/api/v1/users/register";
-    private static final Function<String, String> GET_USER_ENDPOINT = id -> "/api/v1/users/" + id;
-
-    @Autowired
-    private TestRestTemplate testRestTemplate;
-
-    @Autowired
-    private UserJpaRepository userJpaRepository;
-
-    @Autowired
-    private DatabaseCleanUp databaseCleanUp;
-
-    @AfterEach
-    void tearDown() {
-        databaseCleanUp.truncateAllTables();
-    }
-
-    @DisplayName("POST /api/v1/users")
-    @Nested
-    class RegisterUser {
-        @DisplayName("회원 가입이 성공할 경우, 생성된 유저 정보를 응답으로 반환한다.")
-        @Test
-        void registerUser_whenSuccessResponseUser() {
-            //given
-            String userId = "yh45g";
-            String email = "yh45g@loopers.com";
-            String birth = "1994-12-05";
-            String gender = "MALE";
-
-            UserV1Dto.RegisterRequest request = new UserV1Dto.RegisterRequest(userId, email, birth, gender);
-
-            //when
-            ParameterizedTypeReference<ApiResponse<UserV1Dto.UserResponse>> responseType = new ParameterizedTypeReference<>() {};
-            ResponseEntity<ApiResponse<UserV1Dto.UserResponse>> response =
-                    testRestTemplate.exchange(USER_REGISTER_ENDPOINT, HttpMethod.POST, new HttpEntity<>(request), responseType);
-
-            //then
-            assertAll(
-                    () -> assertTrue(response.getStatusCode().is2xxSuccessful()),
-                    () -> assertThat(response.getBody().data().userId()).isEqualTo(userId),
-                    () -> assertThat(response.getBody().data().email()).isEqualTo(email),
-                    () -> assertThat(response.getBody().data().birth()).isEqualTo(birth),
-                    () -> assertThat(response.getBody().data().gender()).isEqualTo(gender)
-            );
-        }
-        @DisplayName("회원 가입 시에 성별이 없을 경우, 400 BAD_REQUEST 응답을 받는다.")
-        @Test
-        void throwsBadRequest_whenGenderIsNotProvided() {
-            //given
-            String userId = "yh45g";
-            String email = "yh45g@loopers.com";
-            String birth = "1994-12-05";
-            String gender =  null;
-
-            UserV1Dto.RegisterRequest request = new UserV1Dto.RegisterRequest(userId, email, birth, gender);
-
-            //when
-            ParameterizedTypeReference<ApiResponse<UserV1Dto.UserResponse>> responseType = new ParameterizedTypeReference<>() {};
-            ResponseEntity<ApiResponse<UserV1Dto.UserResponse>> response =
-                    testRestTemplate.exchange(USER_REGISTER_ENDPOINT, HttpMethod.POST, new HttpEntity<>(request), responseType);
-
-            //then
-            assertAll(
-                    () -> assertTrue(response.getStatusCode().is4xxClientError()),
-                    () -> assertThat(response.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST)
-            );
-        }
-    }
-
-    @DisplayName("GET /api/v1/users/{userId}")
-    @Nested
-    class GetUserById {
-        @DisplayName("내 정보 조회에 성공할 경우, 해당하는 유저 정보를 반환한다.")
-        @Test
-        void getUserById_whenSuccessResponseUser() {
-            //given
-            String userId = "yh45g";
-            String email = "yh45g@loopers.com";
-            String birth = "1994-12-05";
-            String gender = "MALE";
-
-            userJpaRepository.save(new User(userId, email, birth, gender));
-
-            String requestUrl = GET_USER_ENDPOINT.apply(userId);
-
-            //when
-            ParameterizedTypeReference<ApiResponse<UserV1Dto.UserResponse>> responseType = new ParameterizedTypeReference<>() {};
-            ResponseEntity<ApiResponse<UserV1Dto.UserResponse>> response =
-                    testRestTemplate.exchange(requestUrl, HttpMethod.GET, new HttpEntity<>(null), responseType);
-
-            //then
-            assertAll(
-                    () -> assertTrue(response.getStatusCode().is2xxSuccessful()),
-                    () -> assertThat(response.getBody().data().userId()).isEqualTo(userId),
-                    () -> assertThat(response.getBody().data().email()).isEqualTo(email),
-                    () -> assertThat(response.getBody().data().birth()).isEqualTo(birth),
-                    () -> assertThat(response.getBody().data().gender()).isEqualTo(gender)
-            );
-        }
-
-        @DisplayName("존재하지 않는 ID 로 조회할 경우, 404 Not Found 응답을 반환한다.")
-        @Test
-        void throwsException_whenInvalidUserIdIsProvided() {
-            //given
-            String userId = "notUserId";
-            String requestUrl = GET_USER_ENDPOINT.apply(userId);
-
-            //when
-            ParameterizedTypeReference<ApiResponse<UserV1Dto.UserResponse>> responseType = new ParameterizedTypeReference<>() {};
-            ResponseEntity<ApiResponse<UserV1Dto.UserResponse>> response =
-                    testRestTemplate.exchange(requestUrl, HttpMethod.GET, new HttpEntity<>(null), responseType);
-
-            //then
-            assertAll(
-                    () -> assertTrue(response.getStatusCode().is4xxClientError()),
-                    () -> assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND)
-            );
-        }
-    }
-}
diff --git a/docs/1round/1round.md b/docs/1round/1round.md
deleted file mode 100644
index 106d6c809..000000000
--- a/docs/1round/1round.md
+++ /dev/null
@@ -1,67 +0,0 @@
-## 🧪 Implementation Quest
-
-> 지정된 **단위 테스트 / 통합 테스트 / E2E 테스트 케이스**를 필수로 구현하고, 모든 테스트를 통과시키는 것을 목표로 합니다.
->
-
-### 회원 가입
-
-**🧱 단위 테스트**
-
-- [x]  ID 가 `영문 및 숫자 10자 이내` 형식에 맞지 않으면, User 객체 생성에 실패한다.
-- [x]  이메일이 `xx@yy.zz` 형식에 맞지 않으면, User 객체 생성에 실패한다.
-- [x]  생년월일이 `yyyy-MM-dd` 형식에 맞지 않으면, User 객체 생성에 실패한다.
-
-**🔗 통합 테스트**
-
-- [x]  회원 가입시 User 저장이 수행된다. ( spy 검증 )
-- [x]  이미 가입된 ID 로 회원가입 시도 시, 실패한다.
-
-**🌐 E2E 테스트**
-
-- [x]  회원 가입이 성공할 경우, 생성된 유저 정보를 응답으로 반환한다.
-- [x]  회원 가입 시에 성별이 없을 경우, `400 Bad Request` 응답을 반환한다.
-
-### 내 정보 조회
-
-**🔗 통합 테스트**
-
-- [x]  해당 ID 의 회원이 존재할 경우, 회원 정보가 반환된다.
-- [x]  해당 ID 의 회원이 존재하지 않을 경우, null 이 반환된다.
-
-**🌐 E2E 테스트**
-
-- [x]  내 정보 조회에 성공할 경우, 해당하는 유저 정보를 응답으로 반환한다.
-- [x]  존재하지 않는 ID 로 조회할 경우, `404 Not Found` 응답을 반환한다.
-
-### 포인트 조회
-
-**🔗 통합 테스트**
-
-- [x]  해당 ID 의 회원이 존재할 경우, 보유 포인트가 반환된다.
-- [x]  해당 ID 의 회원이 존재하지 않을 경우, null 이 반환된다.
-
-**🌐 E2E 테스트**
-
-- [x]  포인트 조회에 성공할 경우, 보유 포인트를 응답으로 반환한다.
-- [x]  `X-USER-ID` 헤더가 없을 경우, `400 Bad Request` 응답을 반환한다.
-
-### 포인트 충전
-
-**🧱 단위 테스트**
-
-- [X]  0 이하의 정수로 포인트를 충전 시 실패한다.
-
-**🔗 통합 테스트**
-
-- [X]  존재하지 않는 유저 ID 로 충전을 시도한 경우, 실패한다.
-
-**🌐 E2E 테스트**
-
-- [X]  존재하는 유저가 1000원을 충전할 경우, 충전된 보유 총량을 응답으로 반환한다.
-- [X]  존재하지 않는 유저로 요청할 경우, `404 Not Found` 응답을 반환한다.
-
-## ✅ Checklist
-
-- [X]  테스트는 모두 통과해야 하며, `@Test` 기반으로 명시적으로 작성
-- [X]  각 테스트는 테스트 명/설명/입력/예상 결과가 분명해야 함
-- [X]  E2E 테스트는 실제 HTTP 요청을 통해 흐름을 검증할 것
\ No newline at end of file
diff --git a/docs/2round/01-requirements.md b/docs/2round/01-requirements.md
deleted file mode 100644
index 3296c21c6..000000000
--- a/docs/2round/01-requirements.md
+++ /dev/null
@@ -1,104 +0,0 @@
-# 유저-시나리오
-
-## 상품 목록
-1. 사용자가 모든 상품에 대해서 볼수 있다.
-2. 판매중인 상품에 대한 판매명, 판매금액, 판매브랜드, 이미지, 좋아요한 상품을 볼수있다.
-3. 사용자는 원하는 브랜드별로 상품을 볼수 있다.
-4. 사용자는 원하는 상품에대해서 좋아요를 누를수있다.
-5. 사용자는 원하는 조건에 따라 상품을 볼수있다.
-6. 사용자는 원하는 페이지로 이동할수있다.
-
--[기능]
-1. 전체 상품 목록 조회
-2. 브랜드 상품 목록 조회
-3. 상품 좋아요 등록
-4. 필터링 (최신순, 판매순, 좋아요 순, 남자/여자)
-5. 페이징
-
--[제약]
-1. 로그인은 X-USER-ID로 판단, 비회원일경우 "로그인 후 좋아요 가능합니다" 메시지 전달한다
-2. 상품이 없을경우 404_NOTFOUND 제공한다.
-
----
-## 상품 상세
-1. 사용자는 원하는 판매중 상품(판매명,판매금액,판매브랜드,이미지,좋아요한 상품을 볼수있다.
-   -[기능]
-1. 사용자가 원하는 상품번호로 조회
-2. 상품 좋아요 등록 / 취소
-   -[제약]
-1. 로그인은 X-USER-ID로 판단, 비회원일경우 "로그인 후 좋아요 가능합니다" 메시지 전달한다
-2. 상품이 존재하지 않을 경우 404_NOTFOUND 제공한다.
-
----
-## 좋아요
-1. 사용자가 원하는 상품에 대해서 좋아요를 누를 수 있다.
-2. 사용자가 원하는 상품에 대해서 좋아요를 취소 할 수 있다.
-2. 사용자가 좋아하는 상품에 대해 목록을 볼수있다.
-   -[기능]
-1. 좋아요 누른 상품에대해 목록 조회
-2. 사용가 원하는 상품에 대한 등록/취소, 단 등록/해제 (멱등성)
-   -[제약]
-1. 로그인은 X-USER-ID로 판단, 비회원일경우 "로그인 후 좋아요 가능합니다" 메시지 전달한다
-2. 해당 상품에 좋아요를 처음 등록 할때는 201_Created 제공한다
-3. 해당 상품에 좋아요를 한번더 등록 할때는 200_OK 제공한다
-4. 해당 상품에 좋아요가 등록 된 상태에서 취소 할때는 204 No Content 제공한다
-5. 해당 상품에 좋아요가 취소가 된 상태에서 한번더 취소 할때는 204 No Content 제공한다
----
-## 브랜드
-1. 사용자는 모든 브랜드의 상품을 볼수있다.
-2. 사용자는 특정 브랜드에 대한 상품만 볼수있다.
-3. 사용자는 특정 기준으로 상품을 볼수있다. (최신순, 판매순, 좋아요 순)
-4. 사용자는 원하는 페이지로 이동할수있다.
-   [기능]
-1. 모든 브랜드 상품 조회
-2. 특정 브랜드 상품 조회
-3. 필터링 (최신순, 판매순, 좋아요 순, 남자/여자)
-4. 페이징
-   [제약]
-1. 브랜드가 없을시 404_NOTFOUND를 제공한다
----
-## 주문
-1. 사용자가 상품 목록에서 원하는 상품을 선택하여 주문할 수 있다.
-2. 한개의 주문은 여러 상품을 포함할 수 있다.
-3. 사용자가 주문 내역을 조회해 어떤 상품을 주문했는지 확인할 수 있다.
-4. 사용자는 결제 전이라면 주문을 취소할 수 있다.
-5. 사용자는 주문 상세 화면에서 상품 정보, 수량, 결제 금액, 상태 등을 볼 수 있다.
-   [기능]
-1. 주문 생성
-2. 주문 목록 조회
-3. 주문 상세 조회
-4. 주문 취소
-5. 주문에 대한 상태관리
-   [제약]
-1. 주문 시 상품 재고 확인 및 부족 시 예외 발생
-2. 포인트 잔액 부족 시 주문 불가
-3. 동일한 주문 요청이 중복으로 들어와도 한 번만 처리
----
-## 결제
-1. 사용자는 주문한 상품에 대해 포인트로 결제할 수 있다.
-2. 결제가 완료되면 주문 상태가 결제 완료로 변경된다.
-3. 결제 중 문제가 발생하면 결제 실패로 처리되며 포인트와 재고는 복구된다.
-4. 결제 완료 후에는 주문 취소가 불가능하다.
-   [기능]
-1. 결제요청
-2. 결제 결과 반영
-3. 결제 실패 처리
-4. 결제 내역 조회
-   [제약]
-1. 동일 주문에 대해 중복 결제 요청 시 한 번만 처리
-2. 포인트 차감실패 시 복구
-3. 외부결제 시스템 결제 시스템 처리 실패시 예외처리
-
-----
-## Ubiquitous
-| 한국어 | 영어 |
-|--------|------|
-| 사용자 | User |
-| 포인트 | Point |
-| 상품 | Product |
-| 브랜드 | Brand |
-| 좋아요 | Like |
-| 주문 | Order |
-| 재고 | Stock |
-| 가격 | Price |
-| 결제 | Payment |
\ No newline at end of file
diff --git a/docs/2round/02-sequence-diagrams.md b/docs/2round/02-sequence-diagrams.md
deleted file mode 100644
index 5264a4dc0..000000000
--- a/docs/2round/02-sequence-diagrams.md
+++ /dev/null
@@ -1,164 +0,0 @@
-# 시퀀스 다이어그램
-
-### 1. 상품 목록 조회
-```mermaid
-sequenceDiagram
-    participant User
-    participant ProductController
-    participant ProductService
-    participant ProductRepository
-    participant BrandRepository
-    participant LikeRepository
-
-    User->>ProductController: GET /api/v1/products
-    ProductController->>ProductService: getProductList
-    ProductService->>ProductRepository: findAllWithPaging
-    ProductService->>BrandRepository: findBrandInfoForProducts()
-    ProductService->>LikeRepository: countLikesForProducts()
-    ProductRepository-->>ProductService: productList
-    ProductService-->>ProductController: productListResponse
-    ProductController-->>User: 200 OK (상품 목록 + 브랜드 + 좋아요 수)
-```
----
-### 2. 상품 상세 조회
-```mermaid
-sequenceDiagram
-    participant User
-    participant ProductController
-    participant ProductService
-    participant ProductRepository
-    participant BrandRepository
-    participant LikeRepository
-
-    User->>ProductController: GET /api/v1/products/{productId}
-    ProductController->>ProductService: getProductDetail(productId, userId)
-    ProductService->>ProductRepository: findById(productId)
-    ProductService->>BrandRepository: findBrandInfo(brandId)
-    ProductService->>LikeRepository: existsByUserIdAndProductId(userId, productId)
-    ProductRepository-->>ProductService: productDetail
-    ProductService-->>ProductController: productDetailResponse
-    ProductController-->>User: 200 OK (상품 상세 정보)
-```
----
-### 3. 상품 좋아요 등록/취소
-```mermaid
-sequenceDiagram
-    participant User
-    participant LikeController
-    participant LikeService
-    participant LikeRepository
-
-    User->>LikeController: POST /api/v1/like/products/{productId}
-    LikeController->>LikeService: toggleLike(userId, productId)
-    LikeService->>LikeRepository: existsByUserIdAndProductId(userId, productId)
-    alt 좋아요가 존재하지 않음
-        LikeService->>LikeRepository: save(userId, productId)
-        LikeService-->>LikeController: 201 Created
-    else 이미 좋아요 되어있음
-        LikeService->>LikeRepository: delete(userId, productId)
-        LikeService-->>LikeController: 204 No Content
-    end
-    LikeController-->>User: 응답 (상태코드에 따라 다름)
-```
----
-
-### 4. 브랜드별 상품 조회
-```mermaid
-sequenceDiagram
-    participant User
-    participant BrandController
-    participant BrandService
-    participant ProductRepository
-    participant BrandRepository
-
-    User->>BrandController: GET /api/v1/brands/{brandId}/products
-    BrandController->>BrandService: getProductsByBrand(brandId, sort, page)
-    BrandService->>BrandRepository: findById(brandId)
-    BrandService->>ProductRepository: findByBrandId(brandId, sort, page)
-    BrandRepository-->>BrandService: brandInfo
-    ProductRepository-->>BrandService: productList
-    BrandService-->>BrandController: productListResponse
-    BrandController-->>User: 200 OK (브랜드 상품 목록)
-```
----
-### 5. 주문 생성
-```mermaid
-sequenceDiagram
-    participant User
-    participant OrderController
-    participant OrderService
-    participant ProductReader
-    participant StockService
-    participant PointService
-    participant OrderRepository
-
-    User->>OrderController: POST /api/v1/orders (items[])
-    OrderController->>OrderService: createOrder(userId, items)
-    OrderService->>ProductReader: getProductsByIds(productIds)
-    loop 각 상품에 대해
-        OrderService->>StockService: checkAndDecreaseStock(productId, quantity)
-    end
-    OrderService->>PointService: deductPoint(userId, totalPrice)
-    alt 재고 또는 포인트 부족
-        OrderService-->>OrderController: throw Exception
-        OrderController-->>User: 400 Bad Request
-    else 정상
-        OrderService->>OrderRepository: save(order, orderItems)
-        OrderService-->>OrderController: OrderResponse
-        OrderController-->>User: 201 Created (주문 완료)
-    end
-```
----
-### 6. 주문 목록 및 상세 조회
-```mermaid
-sequenceDiagram
-    participant User
-    participant OrderController
-    participant OrderService
-    participant OrderRepository
-    participant ProductRepository
-
-    User->>OrderController: GET /api/v1/orders
-    OrderController->>OrderService: getOrderList(userId)
-    OrderService->>OrderRepository: findByUserId(userId)
-    OrderRepository-->>OrderService: orderList
-    OrderService-->>OrderController: orderListResponse
-    OrderController-->>User: 200 OK (주문 목록)
-
-    User->>OrderController: GET /api/v1/orders/{orderId}
-    OrderController->>OrderService: getOrderDetail(orderId, userId)
-    OrderService->>OrderRepository: findById(orderId)
-    OrderService->>ProductRepository: findProductsInOrder(orderId)
-    OrderRepository-->>OrderService: orderDetail
-    OrderService-->>OrderController: orderDetailResponse
-    OrderController-->>User: 200 OK (주문 상세)
-```
----
-### 7. 결제 처리
-```mermaid
-sequenceDiagram
-    participant User
-    participant PaymentController
-    participant PaymentService
-    participant PaymentGateway
-    participant OrderRepository
-    participant PointService
-    participant StockService
-
-    User->>PaymentController: POST /api/v1/payments (orderId)
-    PaymentController->>PaymentService: processPayment(orderId, userId)
-    PaymentService->>OrderRepository: findById(orderId)
-    PaymentService->>PaymentGateway: requestPayment(orderId, amount)
-    alt 결제 성공
-        PaymentGateway-->>PaymentService: SUCCESS
-        PaymentService->>OrderRepository: updateStatus(orderId, PAID)
-        PaymentService-->>PaymentController: successResponse
-        PaymentController-->>User: 200 OK (결제 완료)
-    else 결제 실패
-        PaymentGateway-->>PaymentService: FAILED
-        PaymentService->>PointService: rollbackPoint(userId, amount)
-        PaymentService->>StockService: restoreStock(orderId)
-        PaymentService->>OrderRepository: updateStatus(orderId, FAILED)
-        PaymentController-->>User: 500 Internal Server Error (결제 실패)
-    end
-```
diff --git a/docs/2round/03-class-diagram.md b/docs/2round/03-class-diagram.md
deleted file mode 100644
index 8d39cfd0a..000000000
--- a/docs/2round/03-class-diagram.md
+++ /dev/null
@@ -1,78 +0,0 @@
-# 클래스 다이어그램
-
-```mermaid
-classDiagram
-direction TB
-
-class User {
-  Long id
-  String userId
-  String name
-  String email
-  String gender
-}
-
-class Point {
-  Long id
-  String userId
-  Long balance
-}
-
-class Brand {
-  Long id
-  String name
-}
-
-class Product {
-  Long id
-  Long brandId
-  String name
-  Long price
-  Long likeCount;
-  Long stock
-}
-
-class Like {
-  Long id
-  String userId
-  Long productId
-  LocalDateTime createdAt
-}
-
-class Order {
-  Long id
-  String userId
-  Long totalPrice
-  OrderStatus status
-  LocalDateTime createdAt
-  List<OrderItem> orderItems
-}
-
-class OrderItem {
-  Long id
-  Order order
-  Long productId
-  String productName
-  Long quantity
-  Long price
-}
-
-class Payment {
-  Long id
-  Long orderId
-  String status
-  String paymentRequestId
-  LocalDateTime createdAt
-}
-
-%% 관계 설정
-User --> Point
-Brand --> Product
-Product --> Like
-User --> Like 
-User --> Order 
-Order --> OrderItem 
-Order --> Payment 
-OrderItem --> Product
-
-```
\ No newline at end of file
diff --git a/docs/2round/04-erd.md b/docs/2round/04-erd.md
deleted file mode 100644
index 6389b2202..000000000
--- a/docs/2round/04-erd.md
+++ /dev/null
@@ -1,74 +0,0 @@
-# erd
-
-```mermaid
-erDiagram
-    USER {
-        bigint id PK
-        varchar user_id
-        varchar name
-        varchar email
-        varchar gender
-    }
-
-    POINT {
-        bigint id PK
-        varchar user_id FK
-        bigint balance
-    }
-
-    BRAND {
-        bigint id PK
-        varchar name
-    }
-
-    PRODUCT {
-        bigint id PK
-        bigint brand_id FK
-        varchar name
-        bigint price
-        bigint like_count
-        bigint stock
-    }
-
-    LIKE {
-        bigint id PK
-        varchar user_id FK
-        bigint product_id FK
-        datetime created_at
-    }
-
-    ORDERS {
-        bigint id PK
-        varchar user_id FK
-        bigint total_amount
-        varchar status
-        datetime created_at
-    }
-
-    ORDER_ITEM {
-        bigint id PK
-        bigint order_id FK
-        bigint product_id FK
-        varchar product_name
-        bigint quantity
-        bigint price
-    }
-
-    PAYMENT {
-        bigint id PK
-        bigint order_id FK
-        varchar status
-        varchar payment_request_id
-        datetime created_at
-    }
-
-    %% 관계 (cardinality)
-    USER ||--|| POINT : "1:1"
-    BRAND ||--o{ PRODUCT : "1:N"
-    PRODUCT ||--o{ LIKE : "1:N"
-    USER ||--o{ LIKE : "1:N"
-    USER ||--o{ ORDERS : "1:N"
-    ORDERS ||--o{ ORDER_ITEM : "1:N"
-    ORDER_ITEM }o--|| PRODUCT : "N:1"
-    ORDERS ||--|| PAYMENT : "1:1"
-```
\ No newline at end of file
diff --git a/docs/2round/2round.md b/docs/2round/2round.md
deleted file mode 100644
index 84fdc982c..000000000
--- a/docs/2round/2round.md
+++ /dev/null
@@ -1,37 +0,0 @@
-## ✍️ Design Quest
-
-> **이커머스 도메인(상품, 브랜드, 좋아요, 주문 등)에 대한 설계**를 완료하고, 다음 주부터 개발 가능한 수준의 설계 문서를 정리하여 PR로 제출합니다.
->
-
-### 📋 과제 정보
-
-- **설계 범위**
-    - 상품 목록 / 상품 상세 / 브랜드 조회
-    - 상품 좋아요 등록/취소 (멱등 동작)
-    - 주문 생성 및 결제 흐름 (재고 차감, 포인트 차감, 외부 시스템 연동)
-- **제외 도메인**
-    - 회원가입, 포인트 충전 (1주차 구현 완료 기준)
-- **요구사항 기반**
-    - 루프팩 이커머스 시나리오 문서를 기준으로 기능/제약사항을 설계에 반영합니다.
-- **제출 방식**
-    1. 아래 파일들을 프로젝트 내 `docs/week2/` 폴더에 `.md`로 저장
-    2. Github PR로 제출
-        - PR 제목: `[2주차] 설계 문서 제출 - 홍길동`
-        - PR 본문에 리뷰 포인트 포함 (예: 고민한 지점 등)
-
-### ✅ 제출 파일 목록 (.docs/design 디렉토리 내)
-
-| 파일명 | 내용 |
-| --- | --- |
-| `01-requirements.md` | 유저 시나리오 기반 기능 정의, 요구사항 명세 |
-| `02-sequence-diagrams.md` | 시퀀스 다이어그램 최소 2개 이상 (Mermaid 기반 작성 권장) |
-| `03-class-diagram.md` | 도메인 객체 설계 (클래스 다이어그램 or 설명 중심) |
-| `04-erd.md` | 전체 테이블 구조 및 관계 정리 (ERD Mermaid 작성 가능) |
-
-## ✅ Checklist
-
-- [ ]  상품/브랜드/좋아요/주문 도메인이 모두 포함되어 있는가?
-- [ ]  기능 요구사항이 유저 중심으로 정리되어 있는가?
-- [ ]  시퀀스 다이어그램에서 책임 객체가 드러나는가?
-- [ ]  클래스 구조가 도메인 설계를 잘 표현하고 있는가?
-- [ ]  ERD 설계 시 데이터 정합성을 고려하여 구성하였는가?
\ No newline at end of file
diff --git a/docs/3round/3round.md b/docs/3round/3round.md
deleted file mode 100644
index b9f333cca..000000000
--- a/docs/3round/3round.md
+++ /dev/null
@@ -1,60 +0,0 @@
-# 📝 Round 3 Quests
-
----
-
-## 💻 Implementation Quest
-
-> *** 도메인 모델링**을 통해 Product, Brand, Like, Order 기능의 핵심 개념을 **Entity, Value Object, Domain Service 등 적합한** **코드**로 작성합니다.
-* 레이어드 아키텍처 + DIP 를 적용해 유연하고 테스트 가능한 구조로 구성합니다.
-* **Application Layer를 경량 수준**으로 구성하여, 도메인 객체를 조합하는 흐름을 실제 구현해봅니다.
-* **단위 테스트를 작성**하여 도메인 로직의 정합성과 규칙을 검증합니다.
->
-
-### 📋 과제 정보
-
-- 상품, 브랜드, 좋아요, 주문 기능의 **도메인 모델 및 도메인 서비스**를 구현합니다.
-- 도메인 간 협력 흐름을 설계하고, 필요한 로직을 **도메인 서비스**로 분리합니다.
-- Application Layer에서 도메인 객체를 조합하는 흐름을 구현합니다.
-  (예: `ProductFacade.getProductDetail(productId)` → `Product + Brand + Like 조합`)
-- Repository Interface 와 구현체는 분리하고, 테스트 가능성을 고려한 구조를 설계합니다.
-- 모든 핵심 도메인 로직에 대해 단위 테스트를 작성하고, 예외/경계 케이스도 포함합니다.
-
-### 🏷 Product / Brand 도메인
-
-## ✅ Checklist
-
-- [x]  상품 정보 객체는 브랜드 정보, 좋아요 수를 포함한다.
-- [x]  상품의 정렬 조건(`latest`, `price_asc`, `likes_desc`) 을 고려한 조회 기능을 설계했다
-- [x]  상품은 재고를 가지고 있고, 주문 시 차감할 수 있어야 한다
-- [x]  재고는 감소만 가능하며 음수 방지는 도메인 레벨에서 처리된다
-
-### 👍 Like 도메인
-
-- [x]  좋아요는 유저와 상품 간의 관계로 별도 도메인으로 분리했다
-- [x]  중복 좋아요 방지를 위한 멱등성 처리가 구현되었다
-- [x]  상품의 좋아요 수는 상품 상세/목록 조회에서 함께 제공된다
-- [x]  단위 테스트에서 좋아요 등록/취소/중복 방지 흐름을 검증했다
-
-### 🛒 Order 도메인
-
-- [x]  주문은 여러 상품을 포함할 수 있으며, 각 상품의 수량을 명시한다
-- [x]  주문 시 상품의 재고 차감, 유저 포인트 차감 등을 수행한다
-- [x]  재고 부족, 포인트 부족 등 예외 흐름을 고려해 설계되었다
-- [x]  단위 테스트에서 정상 주문 / 예외 주문 흐름을 모두 검증했다
-
-### 🧩 도메인 서비스
-
-- [x]  도메인 간 협력 로직은 Domain Service에 위치시켰다
-- [x]  상품 상세 조회 시 Product + Brand 정보 조합은 도메인 서비스에서 처리했다
-- [x]  복합 유스케이스는 Application Layer에 존재하고, 도메인 로직은 위임되었다
-- [x]  도메인 서비스는 상태 없이, 도메인 객체의 협력 중심으로 설계되었다
-
-### **🧱 소프트웨어 아키텍처 & 설계**
-
-- [x]  전체 프로젝트의 구성은 아래 아키텍처를 기반으로 구성되었다
-    - Application → **Domain** ← Infrastructure
-- [x]  Application Layer는 도메인 객체를 조합해 흐름을 orchestration 했다
-- [x]  핵심 비즈니스 로직은 Entity, VO, Domain Service 에 위치한다
-- [x]  Repository Interface는 Domain Layer 에 정의되고, 구현체는 Infra에 위치한다
-- [x]  패키지는 계층 + 도메인 기준으로 구성되었다 (`/domain/order`, `/application/like` 등)
-- [x]  테스트는 외부 의존성을 분리하고, Fake/Stub 등을 사용해 단위 테스트가 가능하게 구성되었다
\ No newline at end of file
