diff --git a/apps/commerce-api/build.gradle.kts b/apps/commerce-api/build.gradle.kts
index 4a77a1518..743f65cd2 100644
--- a/apps/commerce-api/build.gradle.kts
+++ b/apps/commerce-api/build.gradle.kts
@@ -7,10 +7,7 @@ dependencies {
     implementation(project(":supports:monitoring"))
 
     //service
-    implementation(project(":core:service:user-service"))
-    implementation(project(":core:service:order-service"))
-    implementation(project(":core:service:product-service"))
-    implementation(project(":core:service:payment-service"))
+    implementation(project(":core:service"))
 
     //domain
     implementation(project(":core:domain"))
@@ -27,6 +24,7 @@ dependencies {
 
     // test-fixtures
     testImplementation(project(":core:infra:database:mysql:mysql-config"))
-    testImplementation(testFixtures(project(":core:infra:database:mysql:mysql-core")))
+    testImplementation(testFixtures(project(":core:domain")))
+    testImplementation(testFixtures(project(":core:infra:database:mysql")))
     testImplementation(testFixtures(project(":core:infra:database:redis:redis-config")))
 }
diff --git a/apps/commerce-api/src/main/java/com/loopers/application/api/payment/PaymentV1Dto.java b/apps/commerce-api/src/main/java/com/loopers/application/api/payment/PaymentV1Dto.java
index 87595fb4b..e33ddfc0d 100644
--- a/apps/commerce-api/src/main/java/com/loopers/application/api/payment/PaymentV1Dto.java
+++ b/apps/commerce-api/src/main/java/com/loopers/application/api/payment/PaymentV1Dto.java
@@ -9,12 +9,13 @@
 public class PaymentV1Dto {
 
     public record PaymentRequest(
-            @NotBlank String cardType,
-            @NotBlank String cardNo,
-            String couponId
+            String cardType,
+            String cardNo,
+            String couponId,
+            String paymentType
     ) {
         public PaymentCommand toCommand(String orderId, String userIdentifier) {
-            return new PaymentCommand(orderId, userIdentifier, cardType, cardNo, couponId);
+            return new PaymentCommand(orderId, userIdentifier, cardType, cardNo, couponId, paymentType);
         }
     }
 
diff --git a/apps/commerce-api/src/main/resources/application.yml b/apps/commerce-api/src/main/resources/application.yml
index 41802c03f..803550685 100644
--- a/apps/commerce-api/src/main/resources/application.yml
+++ b/apps/commerce-api/src/main/resources/application.yml
@@ -38,6 +38,14 @@ pg:
   callback:
     url: http://localhost:8080/api/v1/payments/callback
 
+retry:
+  exceptions:
+    retryable:
+      - com.loopers.core.domain.error.HttpClientException.ServiceUnavailable
+      - com.loopers.core.domain.error.HttpClientException.InternalServerError
+      - com.loopers.core.domain.error.HttpClientException.GatewayTimeout
+      - com.loopers.core.domain.error.HttpClientException.TooManyRequests
+
 resilience4j:
   retry:
     instances:
diff --git a/apps/commerce-api/src/main/resources/http/http-client.env.json b/apps/commerce-api/src/main/resources/http/http-client.env.json
new file mode 100644
index 000000000..744b6341c
--- /dev/null
+++ b/apps/commerce-api/src/main/resources/http/http-client.env.json
@@ -0,0 +1,14 @@
+{
+  "local": {
+    "commerce-api": "http://localhost:8080",
+    "identifier": "kilian",
+    "birthday": "1997-10-08",
+    "gender": "MALE",
+    "email": "audrb96@gmail.com",
+    "point": 100000000,
+    "orderId": "1",
+    "cardType": "SAMSUNG",
+    "cardNo": "1234-5678-9814-1451",
+    "paymentType": "CARD"
+  }
+}
diff --git a/apps/commerce-api/src/main/resources/http/payment/payment.http b/apps/commerce-api/src/main/resources/http/payment/payment.http
index f4920b539..928a5a528 100644
--- a/apps/commerce-api/src/main/resources/http/payment/payment.http
+++ b/apps/commerce-api/src/main/resources/http/payment/payment.http
@@ -4,5 +4,6 @@ X-USER-ID: {{identifier}}
 
 {
   "cardType": "{{cardType}}",
-  "cardNo": "{{cardNo}}"
+  "cardNo": "{{cardNo}}",
+  "paymentType": "{{paymentType}}"
 }
diff --git a/apps/commerce-api/src/test/java/com/loopers/application/api/brand/BrandV1ApiIntegrationTest.java b/apps/commerce-api/src/test/java/com/loopers/application/api/brand/BrandV1ApiIntegrationTest.java
index 2d5bb823b..047c1de19 100644
--- a/apps/commerce-api/src/test/java/com/loopers/application/api/brand/BrandV1ApiIntegrationTest.java
+++ b/apps/commerce-api/src/test/java/com/loopers/application/api/brand/BrandV1ApiIntegrationTest.java
@@ -3,9 +3,8 @@
 import com.loopers.application.api.ApiIntegrationTest;
 import com.loopers.application.api.common.dto.ApiResponse;
 import com.loopers.core.domain.brand.Brand;
+import com.loopers.core.domain.brand.BrandFixture;
 import com.loopers.core.domain.brand.repository.BrandRepository;
-import com.loopers.core.domain.brand.vo.BrandId;
-import org.instancio.Instancio;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
@@ -19,7 +18,6 @@
 
 import static com.loopers.application.api.brand.BrandV1Dto.GetBrandResponse;
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.instancio.Select.field;
 
 class BrandV1ApiIntegrationTest extends ApiIntegrationTest {
 
@@ -39,9 +37,7 @@ class 정상_요청인_경우 {
             @BeforeEach
             void setUp() {
                 brandId = brandRepository.save(
-                        Instancio.of(Brand.class)
-                                .set(field(Brand::getId), BrandId.empty())
-                                .create()
+                        BrandFixture.create()
                 ).getId().value();
             }
 
diff --git a/apps/commerce-api/src/test/java/com/loopers/application/api/order/OrderV1ApiIntegrationTest.java b/apps/commerce-api/src/test/java/com/loopers/application/api/order/OrderV1ApiIntegrationTest.java
index 1ed6000fb..0bfdda7c3 100644
--- a/apps/commerce-api/src/test/java/com/loopers/application/api/order/OrderV1ApiIntegrationTest.java
+++ b/apps/commerce-api/src/test/java/com/loopers/application/api/order/OrderV1ApiIntegrationTest.java
@@ -3,23 +3,24 @@
 import com.loopers.application.api.ApiIntegrationTest;
 import com.loopers.application.api.common.dto.ApiResponse;
 import com.loopers.core.domain.brand.Brand;
+import com.loopers.core.domain.brand.BrandFixture;
 import com.loopers.core.domain.brand.repository.BrandRepository;
-import com.loopers.core.domain.brand.vo.BrandId;
 import com.loopers.core.domain.order.Order;
+import com.loopers.core.domain.order.OrderFixture;
 import com.loopers.core.domain.order.OrderItem;
+import com.loopers.core.domain.order.OrderItemFixture;
 import com.loopers.core.domain.order.repository.OrderItemRepository;
 import com.loopers.core.domain.order.repository.OrderRepository;
-import com.loopers.core.domain.order.vo.OrderId;
-import com.loopers.core.domain.order.vo.OrderItemId;
 import com.loopers.core.domain.product.Product;
+import com.loopers.core.domain.product.ProductFixture;
 import com.loopers.core.domain.product.repository.ProductRepository;
 import com.loopers.core.domain.product.vo.ProductId;
 import com.loopers.core.domain.user.User;
+import com.loopers.core.domain.user.UserFixture;
 import com.loopers.core.domain.user.UserPoint;
+import com.loopers.core.domain.user.UserPointFixture;
 import com.loopers.core.domain.user.repository.UserPointRepository;
 import com.loopers.core.domain.user.repository.UserRepository;
-import com.loopers.core.domain.user.vo.*;
-import org.instancio.Instancio;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
@@ -33,7 +34,6 @@
 
 import static com.loopers.application.api.order.OrderV1Dto.*;
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.instancio.Select.field;
 
 class OrderV1ApiIntegrationTest extends ApiIntegrationTest {
 
@@ -70,32 +70,19 @@ class 정상_요청인_경우 {
             @BeforeEach
             void setUp() {
                 User user = userRepository.save(
-                        Instancio.of(User.class)
-                                .set(field(User::getId), UserId.empty())
-                                .set(field(User::getIdentifier), new UserIdentifier("kilian"))
-                                .set(field(User::getEmail), new UserEmail("kilian@gmail.com"))
-                                .create()
+                        UserFixture.createWith("kilian", "kilian@gmail.com")
                 );
                 userIdentifier = user.getIdentifier().value();
                 userPointRepository.save(
-                        Instancio.of(UserPoint.class)
-                                .set(field("id"), UserPointId.empty())
-                                .set(field("userId"), user.getId())
-                                .set(field("balance"), new UserPointBalance(new BigDecimal(100_000)))
-                                .create()
+                        UserPointFixture.createWith(user.getId(), new BigDecimal(100_000))
                 );
 
                 Brand brand = brandRepository.save(
-                        Instancio.of(Brand.class)
-                                .set(field(Brand::getId), BrandId.empty())
-                                .create()
+                        BrandFixture.create()
                 );
 
                 product = productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getBrandId), brand.getId())
-                                .create()
+                        ProductFixture.createWith(brand.getId())
                 );
                 productId = product.getId().value();
             }
@@ -201,11 +188,7 @@ class 존재하지_않는_상품_ID로_요청 {
             @BeforeEach
             void setUp() {
                 User user = userRepository.save(
-                        Instancio.of(User.class)
-                                .set(field(User::getId), UserId.empty())
-                                .set(field(User::getIdentifier), new UserIdentifier("kilian"))
-                                .set(field(User::getEmail), new UserEmail("kilian@gmail.com"))
-                                .create()
+                        UserFixture.createWith("kilian", "kilian@gmail.com")
                 );
                 userIdentifier = user.getIdentifier().value();
             }
@@ -251,26 +234,16 @@ class 정상_요청인_경우 {
             @BeforeEach
             void setUp() {
                 User user = userRepository.save(
-                        Instancio.of(User.class)
-                                .set(field(User::getId), UserId.empty())
-                                .set(field(User::getIdentifier), new UserIdentifier("kilian"))
-                                .set(field(User::getEmail), new UserEmail("kilian@gmail.com"))
-                                .create()
+                        UserFixture.createWith("kilian", "kilian@gmail.com")
                 );
 
                 userIdentifier = user.getIdentifier().value();
                 orderRepository.save(
-                        Instancio.of(Order.class)
-                                .set(field(Order::getId), OrderId.empty())
-                                .set(field(Order::getUserId), user.getId())
-                                .create()
+                        OrderFixture.createWith(user.getId())
                 );
 
                 orderRepository.save(
-                        Instancio.of(Order.class)
-                                .set(field(Order::getId), OrderId.empty())
-                                .set(field(Order::getUserId), user.getId())
-                                .create()
+                        OrderFixture.createWith(user.getId())
                 );
             }
 
@@ -329,26 +302,15 @@ class 정상_조회_되는_경우 {
             @BeforeEach
             void setUp() {
                 User user = userRepository.save(
-                        Instancio.of(User.class)
-                                .set(field(User::getId), UserId.empty())
-                                .set(field(User::getIdentifier), new UserIdentifier("kilian"))
-                                .set(field(User::getEmail), new UserEmail("kilian@gmail.com"))
-                                .create()
+                        UserFixture.createWith("kilian", "kilian@gmail.com")
                 );
 
                 userIdentifier = user.getIdentifier().value();
                 savedOrder = orderRepository.save(
-                        Instancio.of(Order.class)
-                                .set(field(Order::getId), OrderId.empty())
-                                .set(field(Order::getUserId), user.getId())
-                                .create()
+                        OrderFixture.createWith(user.getId())
                 );
                 orderItemRepository.save(
-                        Instancio.of(OrderItem.class)
-                                .set(field(OrderItem::getId), OrderItemId.empty())
-                                .set(field(OrderItem::getProductId), new ProductId("1"))
-                                .set(field(OrderItem::getOrderId), savedOrder.getId())
-                                .create()
+                        OrderItemFixture.createWith(savedOrder.getId(), new ProductId("1"))
                 );
             }
 
diff --git a/apps/commerce-api/src/test/java/com/loopers/application/api/payment/PaymentV1ApiTest.java b/apps/commerce-api/src/test/java/com/loopers/application/api/payment/PaymentV1ApiTest.java
index 21292b666..5df2802bf 100644
--- a/apps/commerce-api/src/test/java/com/loopers/application/api/payment/PaymentV1ApiTest.java
+++ b/apps/commerce-api/src/test/java/com/loopers/application/api/payment/PaymentV1ApiTest.java
@@ -4,26 +4,31 @@
 import com.loopers.application.api.common.dto.ApiResponse;
 import com.loopers.application.api.payment.PaymentV1Dto.PgCallbackRequest;
 import com.loopers.core.domain.brand.Brand;
+import com.loopers.core.domain.brand.BrandFixture;
 import com.loopers.core.domain.brand.repository.BrandRepository;
-import com.loopers.core.domain.brand.vo.BrandId;
 import com.loopers.core.domain.order.Order;
+import com.loopers.core.domain.order.OrderFixture;
+import com.loopers.core.domain.order.OrderItemFixture;
+import com.loopers.core.domain.order.repository.OrderItemRepository;
 import com.loopers.core.domain.order.repository.OrderRepository;
+import com.loopers.core.domain.order.vo.OrderKey;
 import com.loopers.core.domain.payment.Payment;
-import com.loopers.core.domain.payment.PgClient;
-import com.loopers.core.domain.payment.PgPayment;
+import com.loopers.core.domain.payment.PaymentFixture;
+import com.loopers.core.domain.payment.PgPaymentFixture;
 import com.loopers.core.domain.payment.repository.PaymentRepository;
-import com.loopers.core.domain.payment.type.PaymentStatus;
-import com.loopers.core.domain.payment.vo.FailedReason;
+import com.loopers.core.domain.payment.repository.PgPaymentRepository;
 import com.loopers.core.domain.payment.vo.TransactionKey;
 import com.loopers.core.domain.product.Product;
+import com.loopers.core.domain.product.ProductFixture;
 import com.loopers.core.domain.product.repository.ProductRepository;
-import com.loopers.core.domain.product.vo.*;
+import com.loopers.core.domain.product.vo.ProductName;
+import com.loopers.core.domain.product.vo.ProductPrice;
+import com.loopers.core.domain.product.vo.ProductStock;
 import com.loopers.core.domain.user.User;
-import com.loopers.core.domain.user.UserPoint;
+import com.loopers.core.domain.user.UserFixture;
+import com.loopers.core.domain.user.UserPointFixture;
 import com.loopers.core.domain.user.repository.UserPointRepository;
 import com.loopers.core.domain.user.repository.UserRepository;
-import com.loopers.core.domain.user.vo.*;
-import org.instancio.Instancio;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
@@ -31,7 +36,6 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.ParameterizedTypeReference;
 import org.springframework.http.*;
-import org.springframework.test.context.bean.override.mockito.MockitoBean;
 
 import java.math.BigDecimal;
 import java.util.List;
@@ -42,10 +46,6 @@
 import static com.loopers.application.api.payment.PaymentV1Dto.PaymentResponse;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.SoftAssertions.assertSoftly;
-import static org.instancio.Select.field;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.when;
 
 @DisplayName("결제 API")
 class PaymentV1ApiTest extends ApiIntegrationTest {
@@ -68,8 +68,11 @@ class PaymentV1ApiTest extends ApiIntegrationTest {
     @Autowired
     private PaymentRepository paymentRepository;
 
-    @MockitoBean
-    private PgClient pgClient;
+    @Autowired
+    private OrderItemRepository orderItemRepository;
+
+    @Autowired
+    private PgPaymentRepository pgPaymentRepository;
 
     private String userIdentifier;
     private String orderId;
@@ -87,40 +90,27 @@ class 정상_요청인_경우 {
             void setUp() {
                 // 사용자 생성
                 User user = userRepository.save(
-                        Instancio.of(User.class)
-                                .set(field(User::getId), UserId.empty())
-                                .set(field(User::getIdentifier), new UserIdentifier("testuser123"))
-                                .set(field(User::getEmail), new UserEmail("testuser@example.com"))
-                                .create()
+                        UserFixture.createWith("testuser1", "testuser@example.com")
                 );
                 userIdentifier = user.getIdentifier().value();
 
                 // 사용자 포인트 생성
                 userPointRepository.save(
-                        Instancio.of(UserPoint.class)
-                                .set(field("id"), UserPointId.empty())
-                                .set(field("userId"), user.getId())
-                                .set(field("balance"), new UserPointBalance(new BigDecimal(100_000)))
-                                .create()
+                        UserPointFixture.createWith(user.getId(), new BigDecimal(100_000))
                 );
 
                 // 브랜드 생성
                 Brand brand = brandRepository.save(
-                        Instancio.of(Brand.class)
-                                .set(field(Brand::getId), BrandId.empty())
-                                .create()
+                        BrandFixture.create()
                 );
 
                 // 상품 생성
                 Product product = productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getBrandId), brand.getId())
-                                .set(field(Product::getName), new ProductName("MacBook Pro"))
-                                .set(field(Product::getPrice), new ProductPrice(new BigDecimal("1500000")))
-                                .set(field(Product::getStock), new ProductStock(100L))
-                                .set(field(Product::getLikeCount), ProductLikeCount.init())
-                                .create()
+                        ProductFixture.createWith(
+                                brand.getId(),
+                                new ProductName("MacBook Pro"),
+                                new ProductPrice(new BigDecimal("1500000")),
+                                new ProductStock(100L))
                 );
                 productId = product.getId().value();
 
@@ -143,10 +133,6 @@ void setUp() {
                         testRestTemplate.exchange(orderEndPoint, HttpMethod.POST, orderHttpEntity, orderResponseType);
 
                 orderId = orderResponse.getBody().data().orderId();
-
-                // PG 클라이언트 Mock 설정
-                when(pgClient.pay(any(), anyString()))
-                        .thenReturn(new PgPayment(new TransactionKey("TXN_" + System.nanoTime()), PaymentStatus.PENDING, FailedReason.empty()));
             }
 
             @Test
@@ -161,7 +147,8 @@ void status200() {
                 PaymentRequest request = new PaymentRequest(
                         "CREDIT",
                         "1234567890123456",
-                        null
+                        null,
+                        "CARD"
                 );
 
                 HttpEntity<PaymentRequest> httpEntity = new HttpEntity<>(request, headers);
@@ -204,7 +191,8 @@ void status400() {
                 PaymentRequest request = new PaymentRequest(
                         "CREDIT",
                         "1234567890123456",
-                        null
+                        null,
+                        "CARD"
                 );
 
                 HttpEntity<PaymentRequest> httpEntity = new HttpEntity<>(request, headers);
@@ -243,7 +231,8 @@ void status404() {
                 PaymentRequest request = new PaymentRequest(
                         "CREDIT",
                         "1234567890123456",
-                        null
+                        null,
+                        "CARD"
                 );
 
                 HttpEntity<PaymentRequest> httpEntity = new HttpEntity<>(request, headers);
@@ -277,80 +266,31 @@ class 결제_성공_콜백 {
             @BeforeEach
             void setUp() {
                 // 사용자 생성
-                User user = userRepository.save(
-                        Instancio.of(User.class)
-                                .set(field(User::getId), UserId.empty())
-                                .set(field(User::getIdentifier), new UserIdentifier("callbackuser"))
-                                .set(field(User::getEmail), new UserEmail("callbackuser@example.com"))
-                                .create()
-                );
+                User user = userRepository.save(UserFixture.createWith("callback1", "callbackuser@example.com"));
                 userId = user.getId().value();
 
                 // 브랜드 및 상품 생성
-                Brand brand = brandRepository.save(
-                        Instancio.of(Brand.class)
-                                .set(field(Brand::getId), BrandId.empty())
-                                .create()
-                );
+                Brand brand = brandRepository.save(BrandFixture.create());
 
                 Product product = productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getBrandId), brand.getId())
-                                .set(field(Product::getName), new ProductName("Test Product"))
-                                .set(field(Product::getPrice), new ProductPrice(new BigDecimal("50000")))
-                                .set(field(Product::getStock), new ProductStock(100L))
-                                .set(field(Product::getLikeCount), ProductLikeCount.init())
-                                .create()
-                );
-
-                // 주문 생성 (API 호출)
-                String orderEndPoint = "/api/v1/orders";
-                HttpHeaders orderHeaders = new HttpHeaders();
-                orderHeaders.set("X-USER-ID", user.getIdentifier().value());
-                orderHeaders.setContentType(MediaType.APPLICATION_JSON);
-
-                OrderRequest orderRequest = new OrderRequest(
-                        List.of(new OrderRequest.OrderItemRequest(product.getId().value(), 1L))
+                        ProductFixture.createWith(
+                                brand.getId(),
+                                new ProductName("Test Product"),
+                                new ProductPrice(new BigDecimal("50000")),
+                                new ProductStock(100L)
+                        )
                 );
 
-                HttpEntity<OrderRequest> orderHttpEntity = new HttpEntity<>(orderRequest, orderHeaders);
-                ParameterizedTypeReference<ApiResponse<OrderResponse>> orderResponseType =
-                        new ParameterizedTypeReference<>() {
-                        };
-
-                ResponseEntity<ApiResponse<OrderResponse>> orderResponse =
-                        testRestTemplate.exchange(orderEndPoint, HttpMethod.POST, orderHttpEntity, orderResponseType);
-
-                orderId = orderResponse.getBody().data().orderId();
+                Order order = orderRepository.save(OrderFixture.createWith(user.getId()));
+                orderId = order.getId().value();
+                OrderKey orderKey = order.getOrderKey();
 
-                // Order 객체에서 OrderKey 조회
-                Order order = orderRepository.getById(new com.loopers.core.domain.order.vo.OrderId(orderId));
-                com.loopers.core.domain.order.vo.OrderKey orderKey = order.getOrderKey();
-
-                // 결제 생성 (API 호출)
-                String paymentEndPoint = "/api/v1/payments/orders/" + orderId;
-                HttpHeaders paymentHeaders = new HttpHeaders();
-                paymentHeaders.set("X-USER-ID", user.getIdentifier().value());
-                paymentHeaders.setContentType(MediaType.APPLICATION_JSON);
-
-                PaymentRequest paymentRequest = new PaymentRequest("CREDIT", "1234567890123456", null);
+                orderItemRepository.save(OrderItemFixture.createWith(order.getId(), product.getId(), 1L));
 
                 transactionKey = "TXN_" + System.nanoTime();
-                when(pgClient.pay(any(), anyString()))
-                        .thenReturn(new PgPayment(new TransactionKey(transactionKey), PaymentStatus.PENDING, FailedReason.empty()));
+                payment = paymentRepository.save(PaymentFixture.createWith(orderKey, user.getId()));
 
-                HttpEntity<PaymentRequest> paymentHttpEntity = new HttpEntity<>(paymentRequest, paymentHeaders);
-                ParameterizedTypeReference<ApiResponse<PaymentResponse>> paymentResponseType =
-                        new ParameterizedTypeReference<>() {
-                        };
-
-                ResponseEntity<ApiResponse<PaymentResponse>> paymentResponse =
-                        testRestTemplate.exchange(paymentEndPoint, HttpMethod.POST, paymentHttpEntity, paymentResponseType);
-
-                // 생성된 결제 객체 조회
-                payment = paymentRepository.findBy(orderKey, PaymentStatus.PENDING)
-                        .orElseThrow();
+                pgPaymentRepository.save(PgPaymentFixture.createWith(payment.getId(), new TransactionKey(transactionKey)));
             }
 
             @Test
@@ -395,81 +335,50 @@ class 결제_실패_콜백 {
             void setUp() {
                 // 사용자 생성
                 User user = userRepository.save(
-                        Instancio.of(User.class)
-                                .set(field(User::getId), UserId.empty())
-                                .set(field(User::getIdentifier), new UserIdentifier("failuser"))
-                                .set(field(User::getEmail), new UserEmail("failuser@example.com"))
-                                .create()
+                        UserFixture.createWith("failuser", "failuser@example.com")
                 );
 
                 // 사용자 포인트 생성
                 userPointRepository.save(
-                        Instancio.of(UserPoint.class)
-                                .set(field("id"), UserPointId.empty())
-                                .set(field("userId"), user.getId())
-                                .set(field("balance"), new UserPointBalance(new BigDecimal(100_000)))
-                                .create()
+                        UserPointFixture.createWith(user.getId(), new BigDecimal(100_000))
                 );
 
                 // 브랜드 및 상품 생성
                 Brand brand = brandRepository.save(
-                        Instancio.of(Brand.class)
-                                .set(field(Brand::getId), BrandId.empty())
-                                .create()
+                        BrandFixture.create()
                 );
 
                 Product product = productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getBrandId), brand.getId())
-                                .set(field(Product::getName), new ProductName("Test Product"))
-                                .set(field(Product::getPrice), new ProductPrice(new BigDecimal("50000")))
-                                .set(field(Product::getStock), new ProductStock(100L))
-                                .set(field(Product::getLikeCount), ProductLikeCount.init())
-                                .create()
+                        ProductFixture.createWith(
+                                brand.getId(),
+                                new ProductName("Test Product"),
+                                new ProductPrice(new BigDecimal("50000")),
+                                new ProductStock(100L)
+                        )
                 );
 
-                // 주문 생성 (API 호출)
-                String orderEndPoint = "/api/v1/orders";
-                HttpHeaders orderHeaders = new HttpHeaders();
-                orderHeaders.set("X-USER-ID", user.getIdentifier().value());
-                orderHeaders.setContentType(MediaType.APPLICATION_JSON);
-
-                OrderRequest orderRequest = new OrderRequest(
-                        List.of(new OrderRequest.OrderItemRequest(product.getId().value(), 1L))
+                // 주문 생성 (Repository 직접 저장)
+                Order order = orderRepository.save(
+                        OrderFixture.createWith(user.getId())
                 );
+                orderId = order.getId().value();
+                OrderKey orderKey = order.getOrderKey();
 
-                HttpEntity<OrderRequest> orderHttpEntity = new HttpEntity<>(orderRequest, orderHeaders);
-                ParameterizedTypeReference<ApiResponse<OrderResponse>> orderResponseType =
-                        new ParameterizedTypeReference<>() {
-                        };
-
-                ResponseEntity<ApiResponse<OrderResponse>> orderResponse =
-                        testRestTemplate.exchange(orderEndPoint, HttpMethod.POST, orderHttpEntity, orderResponseType);
-
-                orderId = orderResponse.getBody().data().orderId();
-
-                // Order 객체에서 OrderKey 조회
-                Order order = orderRepository.getById(new com.loopers.core.domain.order.vo.OrderId(orderId));
-
-                // 결제 생성 (API 호출)
-                String paymentEndPoint = "/api/v1/payments/orders/" + orderId;
-                HttpHeaders paymentHeaders = new HttpHeaders();
-                paymentHeaders.set("X-USER-ID", user.getIdentifier().value());
-                paymentHeaders.setContentType(MediaType.APPLICATION_JSON);
-
-                PaymentRequest paymentRequest = new PaymentRequest("CREDIT", "1234567890123456", null);
+                // 주문 상품 생성
+                orderItemRepository.save(
+                        OrderItemFixture.createWith(order.getId(), product.getId(), 1L)
+                );
 
+                // 결제 생성 (Repository 직접 저장)
                 transactionKey = "TXN_FAIL_" + System.nanoTime();
-                when(pgClient.pay(any(), anyString()))
-                        .thenReturn(new PgPayment(new TransactionKey(transactionKey), PaymentStatus.PENDING, FailedReason.empty()));
-
-                HttpEntity<PaymentRequest> paymentHttpEntity = new HttpEntity<>(paymentRequest, paymentHeaders);
-                ParameterizedTypeReference<ApiResponse<PaymentResponse>> paymentResponseType =
-                        new ParameterizedTypeReference<>() {
-                        };
+                payment = paymentRepository.save(
+                        PaymentFixture.createWith(orderKey, user.getId())
+                );
 
-                testRestTemplate.exchange(paymentEndPoint, HttpMethod.POST, paymentHttpEntity, paymentResponseType);
+                // PG 결제 생성 (Repository 직접 저장)
+                pgPaymentRepository.save(
+                        PgPaymentFixture.createWith(payment.getId(), new TransactionKey(transactionKey))
+                );
             }
 
             @Test
diff --git a/apps/commerce-api/src/test/java/com/loopers/application/api/product/ProductV1ApiIntegrationTest.java b/apps/commerce-api/src/test/java/com/loopers/application/api/product/ProductV1ApiIntegrationTest.java
index 27b05d5f7..0877f8991 100644
--- a/apps/commerce-api/src/test/java/com/loopers/application/api/product/ProductV1ApiIntegrationTest.java
+++ b/apps/commerce-api/src/test/java/com/loopers/application/api/product/ProductV1ApiIntegrationTest.java
@@ -3,13 +3,11 @@
 import com.loopers.application.api.ApiIntegrationTest;
 import com.loopers.application.api.common.dto.ApiResponse;
 import com.loopers.core.domain.brand.Brand;
+import com.loopers.core.domain.brand.BrandFixture;
 import com.loopers.core.domain.brand.repository.BrandRepository;
-import com.loopers.core.domain.brand.vo.BrandId;
-import com.loopers.core.domain.common.vo.DeletedAt;
 import com.loopers.core.domain.product.Product;
+import com.loopers.core.domain.product.ProductFixture;
 import com.loopers.core.domain.product.repository.ProductRepository;
-import com.loopers.core.domain.product.vo.ProductId;
-import org.instancio.Instancio;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
@@ -24,7 +22,6 @@
 import static com.loopers.application.api.product.ProductV1Dto.GetProductListResponse;
 import static com.loopers.application.api.product.ProductV1Dto.GetProductResponse;
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.instancio.Select.field;
 
 class ProductV1ApiIntegrationTest extends ApiIntegrationTest {
 
@@ -47,26 +44,16 @@ class 정상_요청인_경우 {
             @BeforeEach
             void setUp() {
                 Brand brand = brandRepository.save(
-                        Instancio.of(Brand.class)
-                                .set(field(Brand::getId), BrandId.empty())
-                                .create()
+                        BrandFixture.create()
                 );
                 brandId = brand.getId().value();
 
                 Product product1 = productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getBrandId), brand.getId())
-                                .set(field(Product::getDeletedAt), DeletedAt.empty())
-                                .create()
+                        ProductFixture.createWith(brand.getId())
                 );
 
                 Product product2 = productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getBrandId), brand.getId())
-                                .set(field(Product::getDeletedAt), DeletedAt.empty())
-                                .create()
+                        ProductFixture.createWith(brand.getId())
                 );
             }
 
@@ -103,17 +90,11 @@ class 정상_요청인_경우 {
             @BeforeEach
             void setUp() {
                 Brand brand = brandRepository.save(
-                        Instancio.of(Brand.class)
-                                .set(field(Brand::getId), BrandId.empty())
-                                .create()
+                        BrandFixture.create()
                 );
 
                 productId = productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getBrandId), brand.getId())
-                                .set(field(Product::getDeletedAt), DeletedAt.empty())
-                                .create()
+                        ProductFixture.createWith(brand.getId())
                 ).getId().value();
             }
 
diff --git a/apps/commerce-api/src/test/java/com/loopers/application/api/productlike/ProductLikeV1ApiIntegrationTest.java b/apps/commerce-api/src/test/java/com/loopers/application/api/productlike/ProductLikeV1ApiIntegrationTest.java
index 656265ded..98efadbb5 100644
--- a/apps/commerce-api/src/test/java/com/loopers/application/api/productlike/ProductLikeV1ApiIntegrationTest.java
+++ b/apps/commerce-api/src/test/java/com/loopers/application/api/productlike/ProductLikeV1ApiIntegrationTest.java
@@ -3,21 +3,19 @@
 import com.loopers.application.api.ApiIntegrationTest;
 import com.loopers.application.api.common.dto.ApiResponse;
 import com.loopers.core.domain.brand.Brand;
+import com.loopers.core.domain.brand.BrandFixture;
 import com.loopers.core.domain.brand.repository.BrandRepository;
 import com.loopers.core.domain.brand.vo.BrandDescription;
-import com.loopers.core.domain.brand.vo.BrandId;
 import com.loopers.core.domain.brand.vo.BrandName;
 import com.loopers.core.domain.product.Product;
+import com.loopers.core.domain.product.ProductFixture;
 import com.loopers.core.domain.product.repository.ProductRepository;
-import com.loopers.core.domain.product.vo.*;
+import com.loopers.core.domain.product.vo.ProductName;
+import com.loopers.core.domain.product.vo.ProductPrice;
+import com.loopers.core.domain.product.vo.ProductStock;
 import com.loopers.core.domain.user.User;
+import com.loopers.core.domain.user.UserFixture;
 import com.loopers.core.domain.user.repository.UserRepository;
-import com.loopers.core.domain.user.type.UserGender;
-import com.loopers.core.domain.user.vo.UserBirthDay;
-import com.loopers.core.domain.user.vo.UserEmail;
-import com.loopers.core.domain.user.vo.UserId;
-import com.loopers.core.domain.user.vo.UserIdentifier;
-import org.instancio.Instancio;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
@@ -29,7 +27,6 @@
 import java.math.BigDecimal;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.instancio.Select.field;
 
 class ProductLikeV1ApiIntegrationTest extends ApiIntegrationTest {
 
@@ -57,26 +54,16 @@ class 정상_요청인_경우 {
             @BeforeEach
             void setUp() {
                 User user = userRepository.save(
-                        Instancio.of(User.class)
-                                .set(field(User::getId), UserId.empty())
-                                .set(field(User::getIdentifier), new UserIdentifier("kilian"))
-                                .set(field(User::getEmail), new UserEmail("kilian@gmail.com"))
-                                .create()
+                        UserFixture.createWith("kilian", "kilian@gmail.com")
                 );
                 userId = user.getIdentifier().value();
 
                 Brand brand = brandRepository.save(
-                        Instancio.of(Brand.class)
-                                .set(field(Brand::getId), BrandId.empty())
-                                .create()
+                        BrandFixture.create()
                 );
 
                 product = productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getBrandId), brand.getId())
-                                .set(field(Product::getLikeCount), ProductLikeCount.init())
-                                .create()
+                        ProductFixture.createWith(brand.getId())
                 );
                 productId = product.getId().value();
             }
@@ -134,12 +121,7 @@ class 존재하지_않는_상품_ID로_요청 {
             @BeforeEach
             void setUp() {
                 User user = userRepository.save(
-                        User.create(
-                                UserIdentifier.create("kilian"),
-                                UserEmail.create("kilian@gmail.com"),
-                                UserBirthDay.create("1997-10-08"),
-                                UserGender.create("MALE")
-                        )
+                        UserFixture.createWith("kilian", "kilian@gmail.com")
                 );
                 userId = user.getIdentifier().value();
             }
@@ -202,25 +184,20 @@ class 좋아요가_등록되어_있을_경우 {
             @BeforeEach
             void setUp() {
                 User user = userRepository.save(
-                        User.create(
-                                UserIdentifier.create("kilian"),
-                                UserEmail.create("kilian@gmail.com"),
-                                UserBirthDay.create("1997-10-08"),
-                                UserGender.create("MALE")
-                        )
+                        UserFixture.createWith("kilian", "kilian@gmail.com")
                 );
                 userId = user.getIdentifier().value();
 
                 Brand brand = brandRepository.save(
-                        Brand.create(new BrandName("kilian"), new BrandDescription("향수 브랜드"))
+                        BrandFixture.createWith(new BrandName("kilian"), new BrandDescription("향수 브랜드"))
                 );
 
                 productId = productRepository.save(
-                        Product.create(
+                        ProductFixture.createWith(
                                 brand.getId(),
                                 new ProductName("엔젤스 쉐어"),
-                                new ProductPrice(new BigDecimal("150.00")),
-                                new ProductStock(10L)
+                                new ProductPrice(new BigDecimal("150.00"))
+                                , new ProductStock(10L)
                         )
                 ).getId().value();
 
@@ -287,11 +264,7 @@ class 존재하지_않는_상품_ID로_요청 {
             @BeforeEach
             void setUp() {
                 User user = userRepository.save(
-                        Instancio.of(User.class)
-                                .set(field(User::getId), UserId.empty())
-                                .set(field(User::getIdentifier), new UserIdentifier("kilian"))
-                                .set(field(User::getEmail), new UserEmail("kilian@gmail.com"))
-                                .create()
+                        UserFixture.createWith("kilian", "kilian@gmail.com")
                 );
                 userId = user.getIdentifier().value();
             }
@@ -351,35 +324,21 @@ class 좋아요한_상품_목록_조회 {
         void setUp() {
             // 사용자 생성
             User user = userRepository.save(
-                    Instancio.of(User.class)
-                            .set(field(User::getId), UserId.empty())
-                            .set(field(User::getIdentifier), new UserIdentifier("kilian"))
-                            .set(field(User::getEmail), new UserEmail("kilian@gmail.com"))
-                            .create()
+                    UserFixture.createWith("kilian", "kilian@gmail.com")
             );
             userId = user.getIdentifier().value();
 
             // 브랜드 생성
             Brand brand = brandRepository.save(
-                    Instancio.of(Brand.class)
-                            .set(field(Brand::getId), BrandId.empty())
-                            .create()
+                    BrandFixture.create()
             );
 
             // 상품 생성 (2개)
             Product product1 = productRepository.save(
-                    Instancio.of(Product.class)
-                            .set(field(Product::getId), ProductId.empty())
-                            .set(field(Product::getBrandId), brand.getId())
-                            .set(field(Product::getLikeCount), ProductLikeCount.init())
-                            .create()
+                    ProductFixture.createWith(brand.getId())
             );
             Product product2 = productRepository.save(
-                    Instancio.of(Product.class)
-                            .set(field(Product::getId), ProductId.empty())
-                            .set(field(Product::getBrandId), brand.getId())
-                            .set(field(Product::getLikeCount), ProductLikeCount.init())
-                            .create()
+                    ProductFixture.createWith(brand.getId())
             );
 
             // 좋아요 등록
diff --git a/core/domain/build.gradle.kts b/core/domain/build.gradle.kts
index 2e3ca6ab4..d581d547a 100644
--- a/core/domain/build.gradle.kts
+++ b/core/domain/build.gradle.kts
@@ -1,3 +1,7 @@
-dependencies {
+plugins {
+    `java-test-fixtures`
+}
 
+dependencies {
+    testFixturesImplementation("org.instancio:instancio-junit:${project.properties["instancioJUnitVersion"]}")
 }
diff --git a/core/domain/src/main/java/com/loopers/core/domain/event/EventOutbox.java b/core/domain/src/main/java/com/loopers/core/domain/event/EventOutbox.java
new file mode 100644
index 000000000..9da810b0d
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/event/EventOutbox.java
@@ -0,0 +1,100 @@
+package com.loopers.core.domain.event;
+
+import com.loopers.core.domain.common.vo.CreatedAt;
+import com.loopers.core.domain.common.vo.UpdatedAt;
+import com.loopers.core.domain.event.type.AggregateType;
+import com.loopers.core.domain.event.type.EventOutboxStatus;
+import com.loopers.core.domain.event.type.EventType;
+import com.loopers.core.domain.event.vo.AggregateId;
+import com.loopers.core.domain.event.vo.EventOutboxId;
+import com.loopers.core.domain.event.vo.EventPayload;
+import com.loopers.core.domain.event.vo.PublishedAt;
+import lombok.AccessLevel;
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+public class EventOutbox {
+
+    private final EventOutboxId id;
+
+    private final AggregateType aggregateType;
+
+    private final AggregateId aggregateId;
+
+    private final EventType eventType;
+
+    private final EventOutboxStatus status;
+
+    private final EventPayload payload;
+
+    private final PublishedAt publishedAt;
+
+    private final CreatedAt createdAt;
+
+    private final UpdatedAt updatedAt;
+
+    @Builder(access = AccessLevel.PRIVATE, toBuilder = true)
+    private EventOutbox(
+            EventOutboxId id,
+            AggregateType aggregateType,
+            AggregateId aggregateId,
+            EventType eventType,
+            EventOutboxStatus status,
+            EventPayload payload,
+            PublishedAt publishedAt,
+            CreatedAt createdAt,
+            UpdatedAt updatedAt
+    ) {
+        this.id = id;
+        this.aggregateType = aggregateType;
+        this.aggregateId = aggregateId;
+        this.eventType = eventType;
+        this.status = status;
+        this.payload = payload;
+        this.publishedAt = publishedAt;
+        this.createdAt = createdAt;
+        this.updatedAt = updatedAt;
+    }
+
+    public static EventOutbox create(
+            AggregateType aggregateType,
+            AggregateId aggregateId,
+            EventType eventType,
+            EventPayload payload
+    ) {
+        return new EventOutbox(
+                EventOutboxId.empty(),
+                aggregateType,
+                aggregateId,
+                eventType,
+                EventOutboxStatus.PENDING,
+                payload,
+                PublishedAt.empty(),
+                CreatedAt.now(),
+                UpdatedAt.now()
+        );
+    }
+
+    public static EventOutbox mappedBy(
+            EventOutboxId id,
+            AggregateType aggregateType,
+            AggregateId aggregateId,
+            EventType eventType,
+            EventOutboxStatus status,
+            EventPayload payload,
+            PublishedAt publishedAt,
+            CreatedAt createdAt,
+            UpdatedAt updatedAt
+    ) {
+        return new EventOutbox(id, aggregateType, aggregateId, eventType, status, payload, publishedAt, createdAt, updatedAt);
+    }
+
+    public EventOutbox publish() {
+        return this.toBuilder()
+                .status(EventOutboxStatus.PUBLISHED)
+                .publishedAt(PublishedAt.now())
+                .updatedAt(UpdatedAt.now())
+                .build();
+    }
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/event/repository/EventOutboxRepository.java b/core/domain/src/main/java/com/loopers/core/domain/event/repository/EventOutboxRepository.java
new file mode 100644
index 000000000..88beaba61
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/event/repository/EventOutboxRepository.java
@@ -0,0 +1,8 @@
+package com.loopers.core.domain.event.repository;
+
+import com.loopers.core.domain.event.EventOutbox;
+
+public interface EventOutboxRepository {
+
+    EventOutbox save(EventOutbox eventOutbox);
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/event/type/AggregateType.java b/core/domain/src/main/java/com/loopers/core/domain/event/type/AggregateType.java
new file mode 100644
index 000000000..dd3040431
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/event/type/AggregateType.java
@@ -0,0 +1,6 @@
+package com.loopers.core.domain.event.type;
+
+public enum AggregateType {
+
+    PAYMENT, ORDER, PRODUCT
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/event/type/EventOutboxStatus.java b/core/domain/src/main/java/com/loopers/core/domain/event/type/EventOutboxStatus.java
new file mode 100644
index 000000000..2a59ecd38
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/event/type/EventOutboxStatus.java
@@ -0,0 +1,7 @@
+package com.loopers.core.domain.event.type;
+
+public enum EventOutboxStatus {
+    PUBLISHED,
+    FAILED,
+    PENDING,
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/event/type/EventType.java b/core/domain/src/main/java/com/loopers/core/domain/event/type/EventType.java
new file mode 100644
index 000000000..826dcab85
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/event/type/EventType.java
@@ -0,0 +1,9 @@
+package com.loopers.core.domain.event.type;
+
+public enum EventType {
+    PG_PAYMENT_FAILED,
+    PAYMENT_DATA_PLATFORM_SENDING_FAILED,
+    ORDER_DATA_PLATFORM_SENDING_FAILED,
+    STOCK_INCREASE_FAIL,
+    PAYED_ORDER_STATUS_CHANGED_FAIL
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/event/vo/AggregateId.java b/core/domain/src/main/java/com/loopers/core/domain/event/vo/AggregateId.java
new file mode 100644
index 000000000..521d69614
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/event/vo/AggregateId.java
@@ -0,0 +1,4 @@
+package com.loopers.core.domain.event.vo;
+
+public record AggregateId(String value) {
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/event/vo/EventOutboxId.java b/core/domain/src/main/java/com/loopers/core/domain/event/vo/EventOutboxId.java
new file mode 100644
index 000000000..121570f4e
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/event/vo/EventOutboxId.java
@@ -0,0 +1,8 @@
+package com.loopers.core.domain.event.vo;
+
+public record EventOutboxId(String value) {
+
+    public static EventOutboxId empty() {
+        return new EventOutboxId(null);
+    }
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/event/vo/EventPayload.java b/core/domain/src/main/java/com/loopers/core/domain/event/vo/EventPayload.java
new file mode 100644
index 000000000..364b294ea
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/event/vo/EventPayload.java
@@ -0,0 +1,4 @@
+package com.loopers.core.domain.event.vo;
+
+public record EventPayload(String value) {
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/event/vo/PublishedAt.java b/core/domain/src/main/java/com/loopers/core/domain/event/vo/PublishedAt.java
new file mode 100644
index 000000000..3c4529292
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/event/vo/PublishedAt.java
@@ -0,0 +1,14 @@
+package com.loopers.core.domain.event.vo;
+
+import java.time.LocalDateTime;
+
+public record PublishedAt(LocalDateTime value) {
+
+    public static PublishedAt empty() {
+        return new PublishedAt(null);
+    }
+
+    public static PublishedAt now() {
+        return new PublishedAt(LocalDateTime.now());
+    }
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/order/Order.java b/core/domain/src/main/java/com/loopers/core/domain/order/Order.java
index b9e8e82b6..ce2b68dce 100644
--- a/core/domain/src/main/java/com/loopers/core/domain/order/Order.java
+++ b/core/domain/src/main/java/com/loopers/core/domain/order/Order.java
@@ -3,9 +3,12 @@
 import com.loopers.core.domain.common.vo.CreatedAt;
 import com.loopers.core.domain.common.vo.DeletedAt;
 import com.loopers.core.domain.common.vo.UpdatedAt;
+import com.loopers.core.domain.order.type.OrderStatus;
 import com.loopers.core.domain.order.vo.OrderId;
 import com.loopers.core.domain.order.vo.OrderKey;
 import com.loopers.core.domain.user.vo.UserId;
+import lombok.AccessLevel;
+import lombok.Builder;
 import lombok.Getter;
 
 @Getter
@@ -17,16 +20,20 @@ public class Order {
 
     private final OrderKey orderKey;
 
+    private final OrderStatus status;
+
     private final CreatedAt createdAt;
 
     private final UpdatedAt updatedAt;
 
     private final DeletedAt deletedAt;
 
+    @Builder(access = AccessLevel.PRIVATE, toBuilder = true)
     private Order(
             OrderId id,
             UserId userId,
             OrderKey orderKey,
+            OrderStatus status,
             CreatedAt createdAt,
             UpdatedAt updatedAt,
             DeletedAt deletedAt
@@ -34,6 +41,7 @@ private Order(
         this.id = id;
         this.userId = userId;
         this.orderKey = orderKey;
+        this.status = status;
         this.createdAt = createdAt;
         this.updatedAt = updatedAt;
         this.deletedAt = deletedAt;
@@ -43,14 +51,14 @@ public static Order mappedBy(
             OrderId id,
             UserId userId,
             OrderKey orderKey,
+            OrderStatus status,
             CreatedAt createdAt,
             UpdatedAt updatedAt,
             DeletedAt deletedAt
     ) {
-        return new Order(id, userId, orderKey, createdAt, updatedAt, deletedAt);
+        return new Order(id, userId, orderKey, status, createdAt, updatedAt, deletedAt);
     }
 
-
     public static Order create(
             UserId userId
     ) {
@@ -58,8 +66,17 @@ public static Order create(
                 OrderId.empty(),
                 userId,
                 OrderKey.generate(),
+                OrderStatus.WAITING_PAYMENT,
                 CreatedAt.now(),
                 UpdatedAt.now(),
-                DeletedAt.empty());
+                DeletedAt.empty()
+        );
+    }
+
+    public Order payed() {
+        return this.toBuilder()
+                .status(OrderStatus.PAYED)
+                .updatedAt(UpdatedAt.now())
+                .build();
     }
 }
diff --git a/core/domain/src/main/java/com/loopers/core/domain/order/OrderDataPlatformClient.java b/core/domain/src/main/java/com/loopers/core/domain/order/OrderDataPlatformClient.java
new file mode 100644
index 000000000..a23459acc
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/order/OrderDataPlatformClient.java
@@ -0,0 +1,6 @@
+package com.loopers.core.domain.order;
+
+public interface OrderDataPlatformClient {
+
+    void send(Order order);
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/order/type/OrderStatus.java b/core/domain/src/main/java/com/loopers/core/domain/order/type/OrderStatus.java
new file mode 100644
index 000000000..b4c4dc511
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/order/type/OrderStatus.java
@@ -0,0 +1,6 @@
+package com.loopers.core.domain.order.type;
+
+public enum OrderStatus {
+
+    WAITING_PAYMENT, PAYED, IN_DELIVERY, COMPLETED
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/order/vo/OrderCompletedEvent.java b/core/domain/src/main/java/com/loopers/core/domain/order/vo/OrderCompletedEvent.java
new file mode 100644
index 000000000..8dbefd03d
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/order/vo/OrderCompletedEvent.java
@@ -0,0 +1,4 @@
+package com.loopers.core.domain.order.vo;
+
+public record OrderCompletedEvent(OrderId orderId) {
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/order/vo/OrderDataPlatformSendingFailEvent.java b/core/domain/src/main/java/com/loopers/core/domain/order/vo/OrderDataPlatformSendingFailEvent.java
new file mode 100644
index 000000000..9f9a18ead
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/order/vo/OrderDataPlatformSendingFailEvent.java
@@ -0,0 +1,17 @@
+package com.loopers.core.domain.order.vo;
+
+public record OrderDataPlatformSendingFailEvent(
+        OrderId orderId,
+        boolean retryable,
+        int retryCount,
+        String message
+) {
+
+    public static OrderDataPlatformSendingFailEvent create(
+            OrderId orderId,
+            boolean retryable,
+            String message) {
+
+        return new OrderDataPlatformSendingFailEvent(orderId, retryable, 0, message);
+    }
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/order/vo/OrderId.java b/core/domain/src/main/java/com/loopers/core/domain/order/vo/OrderId.java
index 2b0de9c21..e299deecb 100644
--- a/core/domain/src/main/java/com/loopers/core/domain/order/vo/OrderId.java
+++ b/core/domain/src/main/java/com/loopers/core/domain/order/vo/OrderId.java
@@ -1,8 +1,14 @@
 package com.loopers.core.domain.order.vo;
 
+import com.loopers.core.domain.event.vo.AggregateId;
+
 public record OrderId(String value) {
 
     public static OrderId empty() {
         return new OrderId(null);
     }
+
+    public AggregateId toAggregateId() {
+        return new AggregateId(value);
+    }
 }
diff --git a/core/domain/src/main/java/com/loopers/core/domain/order/vo/PayedOrderFailEvent.java b/core/domain/src/main/java/com/loopers/core/domain/order/vo/PayedOrderFailEvent.java
new file mode 100644
index 000000000..a593b25f9
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/order/vo/PayedOrderFailEvent.java
@@ -0,0 +1,20 @@
+package com.loopers.core.domain.order.vo;
+
+import com.loopers.core.domain.payment.vo.PaymentId;
+
+public record PayedOrderFailEvent(
+        PaymentId paymentId,
+        OrderId orderId,
+        boolean retryable,
+        int retryCount,
+        String message
+) {
+    public static PayedOrderFailEvent create(
+            PaymentId paymentId,
+            OrderId orderId,
+            boolean retryable,
+            String message
+    ) {
+        return new PayedOrderFailEvent(paymentId, orderId, retryable, 0, message);
+    }
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/payment/Payment.java b/core/domain/src/main/java/com/loopers/core/domain/payment/Payment.java
index c3b24901e..5bfc766c3 100644
--- a/core/domain/src/main/java/com/loopers/core/domain/payment/Payment.java
+++ b/core/domain/src/main/java/com/loopers/core/domain/payment/Payment.java
@@ -5,6 +5,7 @@
 import com.loopers.core.domain.common.vo.UpdatedAt;
 import com.loopers.core.domain.order.vo.OrderKey;
 import com.loopers.core.domain.payment.type.PaymentStatus;
+import com.loopers.core.domain.payment.type.PaymentType;
 import com.loopers.core.domain.payment.vo.*;
 import com.loopers.core.domain.user.vo.UserId;
 import lombok.AccessLevel;
@@ -28,7 +29,7 @@ public class Payment {
 
     private final PaymentStatus status;
 
-    private final TransactionKey transactionKey;
+    private final PaymentType type;
 
     private final FailedReason failedReason;
 
@@ -47,7 +48,7 @@ private Payment(
             CardNo cardNo,
             PayAmount amount,
             PaymentStatus status,
-            TransactionKey transactionKey,
+            PaymentType type,
             FailedReason failedReason,
             CreatedAt createdAt,
             UpdatedAt updatedAt,
@@ -60,7 +61,7 @@ private Payment(
         this.cardNo = cardNo;
         this.amount = amount;
         this.status = status;
-        this.transactionKey = transactionKey;
+        this.type = type;
         this.failedReason = failedReason;
         this.createdAt = createdAt;
         this.updatedAt = updatedAt;
@@ -75,7 +76,7 @@ public static Payment mappedBy(
             CardNo cardNo,
             PayAmount amount,
             PaymentStatus status,
-            TransactionKey transactionKey,
+            PaymentType type,
             FailedReason failedReason,
             CreatedAt createdAt,
             UpdatedAt updatedAt,
@@ -89,12 +90,9 @@ public static Payment mappedBy(
                 cardNo,
                 amount,
                 status,
-                transactionKey,
+                type,
                 failedReason,
-                createdAt,
-                updatedAt,
-                deletedAt
-        );
+                createdAt, updatedAt, deletedAt);
     }
 
     public static Payment create(
@@ -102,7 +100,8 @@ public static Payment create(
             UserId userId,
             CardType cardType,
             CardNo cardNo,
-            PayAmount amount
+            PayAmount amount,
+            PaymentType type
     ) {
         return new Payment(
                 PaymentId.empty(),
@@ -112,49 +111,25 @@ public static Payment create(
                 cardNo,
                 amount,
                 PaymentStatus.PENDING,
-                TransactionKey.empty(),
+                type,
                 FailedReason.empty(),
                 CreatedAt.now(),
                 UpdatedAt.now(),
-                DeletedAt.empty()
-        );
-    }
-
-    public Payment withTransactionKey(TransactionKey transactionKey) {
-        return this.toBuilder()
-                .transactionKey(transactionKey)
-                .updatedAt(UpdatedAt.now())
-                .build();
-    }
-
-    public Payment withStatus(
-            PaymentStatus status
-    ) {
-        return this.toBuilder()
-                .status(status)
-                .updatedAt(UpdatedAt.now())
-                .build();
+                DeletedAt.empty());
     }
 
-    public Payment withFailedReason(FailedReason failedReason) {
+    public Payment success() {
         return this.toBuilder()
-                .failedReason(failedReason)
+                .status(PaymentStatus.SUCCESS)
                 .updatedAt(UpdatedAt.now())
                 .build();
     }
 
-    public Payment fail(FailedReason failedReason) {
+    public Payment failed(FailedReason failedReason) {
         return this.toBuilder()
                 .status(PaymentStatus.FAILED)
                 .failedReason(failedReason)
                 .updatedAt(UpdatedAt.now())
                 .build();
     }
-
-    public Payment success() {
-        return this.toBuilder()
-                .status(PaymentStatus.SUCCESS)
-                .updatedAt(UpdatedAt.now())
-                .build();
-    }
 }
diff --git a/core/domain/src/main/java/com/loopers/core/domain/payment/PaymentDataPlatformClient.java b/core/domain/src/main/java/com/loopers/core/domain/payment/PaymentDataPlatformClient.java
new file mode 100644
index 000000000..fc30e7ff3
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/payment/PaymentDataPlatformClient.java
@@ -0,0 +1,6 @@
+package com.loopers.core.domain.payment;
+
+public interface PaymentDataPlatformClient {
+
+    void send(Payment payment);
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/payment/PgPayment.java b/core/domain/src/main/java/com/loopers/core/domain/payment/PgPayment.java
index 82401d189..2ebdf1cb4 100644
--- a/core/domain/src/main/java/com/loopers/core/domain/payment/PgPayment.java
+++ b/core/domain/src/main/java/com/loopers/core/domain/payment/PgPayment.java
@@ -1,12 +1,111 @@
 package com.loopers.core.domain.payment;
 
-import com.loopers.core.domain.payment.type.PaymentStatus;
+import com.loopers.core.domain.common.vo.CreatedAt;
+import com.loopers.core.domain.common.vo.DeletedAt;
+import com.loopers.core.domain.common.vo.UpdatedAt;
+import com.loopers.core.domain.payment.type.PgPaymentStatus;
 import com.loopers.core.domain.payment.vo.FailedReason;
+import com.loopers.core.domain.payment.vo.PaymentId;
+import com.loopers.core.domain.payment.vo.PgPaymentId;
 import com.loopers.core.domain.payment.vo.TransactionKey;
+import lombok.AccessLevel;
+import lombok.Builder;
+import lombok.Getter;
 
-public record PgPayment(
-        TransactionKey transactionKey,
-        PaymentStatus status,
-        FailedReason failedReason
-) {
+@Getter
+public class PgPayment {
+
+    private final PgPaymentId id;
+
+    private final PaymentId paymentId;
+
+    private final TransactionKey transactionKey;
+
+    private final PgPaymentStatus status;
+
+    private final FailedReason failedReason;
+
+    private final CreatedAt createdAt;
+
+    private final UpdatedAt updatedAt;
+
+    private final DeletedAt deletedAt;
+
+    @Builder(access = AccessLevel.PRIVATE, toBuilder = true)
+    private PgPayment(
+            PgPaymentId id,
+            PaymentId paymentId,
+            TransactionKey transactionKey,
+            PgPaymentStatus status,
+            FailedReason failedReason,
+            CreatedAt createdAt,
+            UpdatedAt updatedAt,
+            DeletedAt deletedAt
+    ) {
+        this.id = id;
+        this.paymentId = paymentId;
+        this.transactionKey = transactionKey;
+        this.status = status;
+        this.failedReason = failedReason;
+        this.createdAt = createdAt;
+        this.updatedAt = updatedAt;
+        this.deletedAt = deletedAt;
+    }
+
+    public static PgPayment create(
+            TransactionKey transactionKey,
+            PgPaymentStatus status,
+            FailedReason failedReason
+    ) {
+        return new PgPayment(
+                PgPaymentId.empty(),
+                PaymentId.empty(),
+                transactionKey,
+                status,
+                failedReason,
+                CreatedAt.now(),
+                UpdatedAt.now(),
+                DeletedAt.empty()
+        );
+    }
+
+    public static PgPayment mappedBy(
+            PgPaymentId id,
+            PaymentId paymentId,
+            TransactionKey transactionKey,
+            PgPaymentStatus status,
+            FailedReason failedReason,
+            CreatedAt createdAt,
+            UpdatedAt updatedAt,
+            DeletedAt deletedAt
+    ) {
+        return new PgPayment(id, paymentId, transactionKey, status, failedReason, createdAt, updatedAt, deletedAt);
+    }
+
+    public PgPayment with(
+            PgPaymentStatus status,
+            FailedReason failedReason
+    ) {
+        return this.toBuilder()
+                .status(status)
+                .failedReason(failedReason)
+                .updatedAt(UpdatedAt.now())
+                .build();
+    }
+
+    public PgPayment with(PaymentId paymentId) {
+        return this.toBuilder()
+                .paymentId(paymentId)
+                .updatedAt(UpdatedAt.now())
+                .build();
+    }
+
+    public PgPayment merge(PgPayment pgPayment) {
+        return this.toBuilder()
+                .transactionKey(pgPayment.transactionKey)
+                .status(pgPayment.status)
+                .failedReason(pgPayment.failedReason)
+                .updatedAt(UpdatedAt.now())
+                .build();
+    }
 }
diff --git a/core/domain/src/main/java/com/loopers/core/domain/payment/repository/PaymentRepository.java b/core/domain/src/main/java/com/loopers/core/domain/payment/repository/PaymentRepository.java
index 0d9b3673b..e9b985102 100644
--- a/core/domain/src/main/java/com/loopers/core/domain/payment/repository/PaymentRepository.java
+++ b/core/domain/src/main/java/com/loopers/core/domain/payment/repository/PaymentRepository.java
@@ -3,17 +3,17 @@
 import com.loopers.core.domain.order.vo.OrderKey;
 import com.loopers.core.domain.payment.Payment;
 import com.loopers.core.domain.payment.type.PaymentStatus;
-import com.loopers.core.domain.payment.vo.TransactionKey;
+import com.loopers.core.domain.payment.vo.PaymentId;
 
 import java.util.Optional;
 
 public interface PaymentRepository {
 
-    Payment save(Payment payment);
+    Optional<Payment> findByWithLock(OrderKey orderKey, PaymentStatus status);
 
-    Payment getByWithLock(TransactionKey transactionKey);
+    Payment getById(PaymentId paymentId);
 
-    Optional<Payment> findBy(OrderKey orderKey, PaymentStatus status);
+    Payment save(Payment payment);
 
-    Optional<Payment> findByWithLock(OrderKey orderKey, PaymentStatus status);
+    Optional<Payment> findBy(OrderKey orderKey, PaymentStatus status);
 }
diff --git a/core/domain/src/main/java/com/loopers/core/domain/payment/repository/PgPaymentRepository.java b/core/domain/src/main/java/com/loopers/core/domain/payment/repository/PgPaymentRepository.java
new file mode 100644
index 000000000..42002725f
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/payment/repository/PgPaymentRepository.java
@@ -0,0 +1,16 @@
+package com.loopers.core.domain.payment.repository;
+
+import com.loopers.core.domain.payment.PgPayment;
+import com.loopers.core.domain.payment.vo.PaymentId;
+import com.loopers.core.domain.payment.vo.TransactionKey;
+
+import java.util.Optional;
+
+public interface PgPaymentRepository {
+
+    Optional<PgPayment> findBy(PaymentId paymentId);
+
+    PgPayment save(PgPayment pgPayment);
+
+    PgPayment getByWithLock(TransactionKey transactionKey);
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/payment/type/PaymentStatus.java b/core/domain/src/main/java/com/loopers/core/domain/payment/type/PaymentStatus.java
index 297d0c613..8520ee2ae 100644
--- a/core/domain/src/main/java/com/loopers/core/domain/payment/type/PaymentStatus.java
+++ b/core/domain/src/main/java/com/loopers/core/domain/payment/type/PaymentStatus.java
@@ -1,7 +1,6 @@
 package com.loopers.core.domain.payment.type;
 
 public enum PaymentStatus {
-
     SUCCESS,
     PENDING,
     NO_RESPONSE,
diff --git a/core/domain/src/main/java/com/loopers/core/domain/payment/type/PaymentType.java b/core/domain/src/main/java/com/loopers/core/domain/payment/type/PaymentType.java
new file mode 100644
index 000000000..9ddc41a44
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/payment/type/PaymentType.java
@@ -0,0 +1,6 @@
+package com.loopers.core.domain.payment.type;
+
+public enum PaymentType {
+
+    POINT, CARD
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/payment/type/PgPaymentStatus.java b/core/domain/src/main/java/com/loopers/core/domain/payment/type/PgPaymentStatus.java
new file mode 100644
index 000000000..216904472
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/payment/type/PgPaymentStatus.java
@@ -0,0 +1,9 @@
+package com.loopers.core.domain.payment.type;
+
+public enum PgPaymentStatus {
+
+    SUCCESS,
+    PENDING,
+    NO_RESPONSE,
+    FAILED
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/payment/vo/CardNo.java b/core/domain/src/main/java/com/loopers/core/domain/payment/vo/CardNo.java
index 5e8be8aa3..438386381 100644
--- a/core/domain/src/main/java/com/loopers/core/domain/payment/vo/CardNo.java
+++ b/core/domain/src/main/java/com/loopers/core/domain/payment/vo/CardNo.java
@@ -1,20 +1,5 @@
 package com.loopers.core.domain.payment.vo;
 
-import java.util.Objects;
-
-import static com.loopers.core.domain.error.DomainErrorCode.notNullMessage;
-
 public record CardNo(String value) {
 
-    private static final String FIELD_NAME = "카드 번호";
-
-    public CardNo {
-        validateNull(value);
-    }
-
-    private static void validateNull(String value) {
-        if (Objects.isNull(value)) {
-            throw new NullPointerException(notNullMessage(FIELD_NAME));
-        }
-    }
 }
diff --git a/core/domain/src/main/java/com/loopers/core/domain/payment/vo/CardType.java b/core/domain/src/main/java/com/loopers/core/domain/payment/vo/CardType.java
index 4f31cf980..e98e0bcee 100644
--- a/core/domain/src/main/java/com/loopers/core/domain/payment/vo/CardType.java
+++ b/core/domain/src/main/java/com/loopers/core/domain/payment/vo/CardType.java
@@ -1,20 +1,5 @@
 package com.loopers.core.domain.payment.vo;
 
-import java.util.Objects;
-
-import static com.loopers.core.domain.error.DomainErrorCode.notNullMessage;
-
 public record CardType(String value) {
 
-    private static final String FIELD_NAME = "카드 유형";
-
-    public CardType {
-        validateNull(value);
-    }
-
-    private static void validateNull(String value) {
-        if (Objects.isNull(value)) {
-            throw new NullPointerException(notNullMessage(FIELD_NAME));
-        }
-    }
 }
diff --git a/core/domain/src/main/java/com/loopers/core/domain/payment/vo/PaymentCompletedEvent.java b/core/domain/src/main/java/com/loopers/core/domain/payment/vo/PaymentCompletedEvent.java
new file mode 100644
index 000000000..846c9c576
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/payment/vo/PaymentCompletedEvent.java
@@ -0,0 +1,4 @@
+package com.loopers.core.domain.payment.vo;
+
+public record PaymentCompletedEvent(PaymentId paymentId) {
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/payment/vo/PaymentCreatedEvent.java b/core/domain/src/main/java/com/loopers/core/domain/payment/vo/PaymentCreatedEvent.java
new file mode 100644
index 000000000..bf0547301
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/payment/vo/PaymentCreatedEvent.java
@@ -0,0 +1,7 @@
+package com.loopers.core.domain.payment.vo;
+
+import com.loopers.core.domain.payment.type.PaymentType;
+
+public record PaymentCreatedEvent(PaymentId paymentId, PaymentType paymentType) {
+
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/payment/vo/PaymentDataPlatformSendingFailEvent.java b/core/domain/src/main/java/com/loopers/core/domain/payment/vo/PaymentDataPlatformSendingFailEvent.java
new file mode 100644
index 000000000..91dda545e
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/payment/vo/PaymentDataPlatformSendingFailEvent.java
@@ -0,0 +1,17 @@
+package com.loopers.core.domain.payment.vo;
+
+public record PaymentDataPlatformSendingFailEvent(
+        PaymentId paymentId,
+        boolean retryable,
+        int retryCount,
+        String message
+) {
+
+    public static PaymentDataPlatformSendingFailEvent create(
+            PaymentId paymentId,
+            boolean retryable,
+            String message) {
+
+        return new PaymentDataPlatformSendingFailEvent(paymentId, retryable, 0, message);
+    }
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/payment/vo/PaymentFailedEvent.java b/core/domain/src/main/java/com/loopers/core/domain/payment/vo/PaymentFailedEvent.java
new file mode 100644
index 000000000..6641f4b95
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/payment/vo/PaymentFailedEvent.java
@@ -0,0 +1,4 @@
+package com.loopers.core.domain.payment.vo;
+
+public record PaymentFailedEvent(PaymentId paymentId, FailedReason failedReason) {
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/payment/vo/PaymentId.java b/core/domain/src/main/java/com/loopers/core/domain/payment/vo/PaymentId.java
index d550fc57a..fc43217fa 100644
--- a/core/domain/src/main/java/com/loopers/core/domain/payment/vo/PaymentId.java
+++ b/core/domain/src/main/java/com/loopers/core/domain/payment/vo/PaymentId.java
@@ -1,8 +1,14 @@
 package com.loopers.core.domain.payment.vo;
 
+import com.loopers.core.domain.event.vo.AggregateId;
+
 public record PaymentId(String value) {
 
     public static PaymentId empty() {
         return new PaymentId(null);
     }
+
+    public AggregateId toAggregateId() {
+        return new AggregateId(value);
+    }
 }
diff --git a/core/domain/src/main/java/com/loopers/core/domain/payment/vo/PgPaymentId.java b/core/domain/src/main/java/com/loopers/core/domain/payment/vo/PgPaymentId.java
new file mode 100644
index 000000000..a30fd0f83
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/payment/vo/PgPaymentId.java
@@ -0,0 +1,8 @@
+package com.loopers.core.domain.payment.vo;
+
+public record PgPaymentId(String value) {
+
+    public static PgPaymentId empty() {
+        return new PgPaymentId(null);
+    }
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/payment/vo/PgPaymentRequestFailEvent.java b/core/domain/src/main/java/com/loopers/core/domain/payment/vo/PgPaymentRequestFailEvent.java
new file mode 100644
index 000000000..7e9c00827
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/payment/vo/PgPaymentRequestFailEvent.java
@@ -0,0 +1,17 @@
+package com.loopers.core.domain.payment.vo;
+
+public record PgPaymentRequestFailEvent(
+        PaymentId paymentId,
+        boolean retryable,
+        int retryCount,
+        String message
+) {
+
+    public static PgPaymentRequestFailEvent create(
+            PaymentId paymentId,
+            boolean retryable,
+            String message) {
+
+        return new PgPaymentRequestFailEvent(paymentId, retryable, 0, message);
+    }
+}
diff --git a/core/domain/src/main/java/com/loopers/core/domain/product/vo/StockIncreaseFailEvent.java b/core/domain/src/main/java/com/loopers/core/domain/product/vo/StockIncreaseFailEvent.java
new file mode 100644
index 000000000..c49585889
--- /dev/null
+++ b/core/domain/src/main/java/com/loopers/core/domain/product/vo/StockIncreaseFailEvent.java
@@ -0,0 +1,15 @@
+package com.loopers.core.domain.product.vo;
+
+import com.loopers.core.domain.payment.vo.PaymentId;
+
+public record StockIncreaseFailEvent(
+        PaymentId paymentId,
+        String message,
+        boolean retryable,
+        int retryCount
+) {
+
+    public static StockIncreaseFailEvent create(PaymentId paymentId, String message, boolean retryable) {
+        return new StockIncreaseFailEvent(paymentId, message, retryable, 0);
+    }
+}
diff --git a/core/domain/src/test/java/com/loopers/core/domain/order/AbstractCouponTest.java b/core/domain/src/test/java/com/loopers/core/domain/order/AbstractCouponTest.java
index 8b7831e64..efe634241 100644
--- a/core/domain/src/test/java/com/loopers/core/domain/order/AbstractCouponTest.java
+++ b/core/domain/src/test/java/com/loopers/core/domain/order/AbstractCouponTest.java
@@ -2,7 +2,6 @@
 
 import com.loopers.core.domain.order.type.CouponStatus;
 import com.loopers.core.domain.payment.vo.PayAmount;
-import org.instancio.Instancio;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
@@ -10,7 +9,6 @@
 import java.math.BigDecimal;
 
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.instancio.Select.field;
 
 class AbstractCouponTest {
 
@@ -25,9 +23,7 @@ class couponUnavailable {
             @Test
             @DisplayName("예외가 발생한다.")
             void throwException() {
-                DefaultCoupon defaultCoupon = Instancio.of(DefaultCoupon.class)
-                        .set(field(DefaultCoupon::getStatus), CouponStatus.USED)
-                        .create();
+                DefaultCoupon defaultCoupon = DefaultCouponFixture.createWith(CouponStatus.USED);
                 PayAmount payAmount = new PayAmount(new BigDecimal(1000));
                 assertThatThrownBy(() -> defaultCoupon.discount(payAmount))
                         .isInstanceOf(IllegalArgumentException.class)
diff --git a/core/domain/src/test/java/com/loopers/core/domain/order/AmountDiscountCouponTest.java b/core/domain/src/test/java/com/loopers/core/domain/order/AmountDiscountCouponTest.java
index 0a9bf3169..bd30466a5 100644
--- a/core/domain/src/test/java/com/loopers/core/domain/order/AmountDiscountCouponTest.java
+++ b/core/domain/src/test/java/com/loopers/core/domain/order/AmountDiscountCouponTest.java
@@ -2,7 +2,6 @@
 
 import com.loopers.core.domain.order.vo.CouponDiscountAmount;
 import com.loopers.core.domain.payment.vo.PayAmount;
-import org.instancio.Instancio;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
@@ -10,7 +9,6 @@
 import java.math.BigDecimal;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.instancio.Select.field;
 
 @DisplayName("정액 할인 쿠폰")
 class AmountDiscountCouponTest {
@@ -27,9 +25,7 @@ class DiscountAmount {
             @DisplayName("일정 양을 가진다.")
             void discountAmount() {
                 PayAmount payAmount = new PayAmount(new BigDecimal(10000));
-                AmountDiscountCoupon coupon = Instancio.of(AmountDiscountCoupon.class)
-                        .set(field(AmountDiscountCoupon::getAmount), new CouponDiscountAmount(new BigDecimal(1000)))
-                        .create();
+                AmountDiscountCoupon coupon = AmountDiscountCouponFixture.createWith(new CouponDiscountAmount(new BigDecimal(1000)));
 
                 assertThat(coupon.calculateDiscountAmount(payAmount)).isEqualByComparingTo(new BigDecimal(1000));
             }
diff --git a/core/domain/src/test/java/com/loopers/core/domain/order/RateDiscountCouponTest.java b/core/domain/src/test/java/com/loopers/core/domain/order/RateDiscountCouponTest.java
index 4a3f4b4da..1f7ea2fd4 100644
--- a/core/domain/src/test/java/com/loopers/core/domain/order/RateDiscountCouponTest.java
+++ b/core/domain/src/test/java/com/loopers/core/domain/order/RateDiscountCouponTest.java
@@ -2,7 +2,6 @@
 
 import com.loopers.core.domain.order.vo.CouponDiscountRate;
 import com.loopers.core.domain.payment.vo.PayAmount;
-import org.instancio.Instancio;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
@@ -10,7 +9,6 @@
 import java.math.BigDecimal;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.instancio.Select.field;
 
 class RateDiscountCouponTest {
 
@@ -26,9 +24,7 @@ class DiscountAmount {
             @DisplayName("일정 비율을 가진다.")
             void discountAmount() {
                 PayAmount payAmount = new PayAmount(new BigDecimal(10000));
-                RateDiscountCoupon coupon = Instancio.of(RateDiscountCoupon.class)
-                        .set(field(RateDiscountCoupon::getRate), new CouponDiscountRate(new BigDecimal(20)))
-                        .create();
+                RateDiscountCoupon coupon = RateDiscountCouponFixture.createWith(new CouponDiscountRate(new BigDecimal(20)));
 
                 assertThat(coupon.calculateDiscountAmount(payAmount)).isEqualByComparingTo(new BigDecimal(2000));
             }
diff --git a/core/domain/src/test/java/com/loopers/core/domain/payment/PaymentTest.java b/core/domain/src/test/java/com/loopers/core/domain/payment/PaymentTest.java
index ab615e3c9..0a9f8f77d 100644
--- a/core/domain/src/test/java/com/loopers/core/domain/payment/PaymentTest.java
+++ b/core/domain/src/test/java/com/loopers/core/domain/payment/PaymentTest.java
@@ -2,6 +2,7 @@
 
 import com.loopers.core.domain.order.vo.OrderKey;
 import com.loopers.core.domain.payment.type.PaymentStatus;
+import com.loopers.core.domain.payment.type.PaymentType;
 import com.loopers.core.domain.payment.vo.CardNo;
 import com.loopers.core.domain.payment.vo.CardType;
 import com.loopers.core.domain.payment.vo.PayAmount;
@@ -37,7 +38,7 @@ class 유효한_값으로_생성 {
                 PayAmount amount = new PayAmount(new BigDecimal(10000));
 
                 // when
-                Payment payment = Payment.create(orderKey, userId, cardType, cardNo, amount);
+                Payment payment = Payment.create(orderKey, userId, cardType, cardNo, amount, PaymentType.CARD);
 
                 // then
                 assertSoftly(softAssertions -> {
diff --git a/core/domain/src/test/java/com/loopers/core/domain/payment/vo/CardNoTest.java b/core/domain/src/test/java/com/loopers/core/domain/payment/vo/CardNoTest.java
index e977ff607..2f099c8e9 100644
--- a/core/domain/src/test/java/com/loopers/core/domain/payment/vo/CardNoTest.java
+++ b/core/domain/src/test/java/com/loopers/core/domain/payment/vo/CardNoTest.java
@@ -5,7 +5,6 @@
 import org.junit.jupiter.api.Test;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 @DisplayName("카드 번호")
 class CardNoTest {
@@ -31,19 +30,5 @@ class 유효한_값인_경우 {
                 assertThat(cardNo.value()).isEqualTo(cardNumber);
             }
         }
-
-        @Nested
-        @DisplayName("값이 null인 경우")
-        class 값이_null인_경우 {
-
-            @Test
-            @DisplayName("NullPointerException을 발생시킨다")
-            void 예외_발생() {
-                // when & then
-                assertThatThrownBy(() -> new CardNo(null))
-                        .isInstanceOf(NullPointerException.class)
-                        .hasMessage("카드 번호는(은) Null이 될 수 없습니다.");
-            }
-        }
     }
 }
diff --git a/core/domain/src/test/java/com/loopers/core/domain/payment/vo/CardTypeTest.java b/core/domain/src/test/java/com/loopers/core/domain/payment/vo/CardTypeTest.java
index d2f6a72b6..4c17b1a3c 100644
--- a/core/domain/src/test/java/com/loopers/core/domain/payment/vo/CardTypeTest.java
+++ b/core/domain/src/test/java/com/loopers/core/domain/payment/vo/CardTypeTest.java
@@ -5,7 +5,6 @@
 import org.junit.jupiter.api.Test;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 @DisplayName("카드 유형")
 class CardTypeTest {
@@ -31,19 +30,5 @@ class 유효한_값인_경우 {
                 assertThat(type.value()).isEqualTo(cardType);
             }
         }
-
-        @Nested
-        @DisplayName("값이 null인 경우")
-        class 값이_null인_경우 {
-
-            @Test
-            @DisplayName("NullPointerException을 발생시킨다")
-            void 예외_발생() {
-                // when & then
-                assertThatThrownBy(() -> new CardType(null))
-                        .isInstanceOf(NullPointerException.class)
-                        .hasMessage("카드 유형는(은) Null이 될 수 없습니다.");
-            }
-        }
     }
 }
diff --git a/core/domain/src/testFixtures/java/com/loopers/core/domain/brand/BrandFixture.java b/core/domain/src/testFixtures/java/com/loopers/core/domain/brand/BrandFixture.java
new file mode 100644
index 000000000..4b8357085
--- /dev/null
+++ b/core/domain/src/testFixtures/java/com/loopers/core/domain/brand/BrandFixture.java
@@ -0,0 +1,35 @@
+package com.loopers.core.domain.brand;
+
+import com.loopers.core.domain.brand.vo.BrandDescription;
+import com.loopers.core.domain.brand.vo.BrandId;
+import com.loopers.core.domain.brand.vo.BrandName;
+import org.instancio.Instancio;
+
+import static org.instancio.Select.field;
+
+public class BrandFixture {
+
+    public static Brand create() {
+        return Instancio.of(Brand.class)
+                .set(field(Brand::getId), BrandId.empty())
+                .set(field(Brand::getName), new BrandName("테스트 브랜드"))
+                .set(field(Brand::getDescription), new BrandDescription("테스트 브랜드 설명"))
+                .create();
+    }
+
+    public static Brand createWith(String name) {
+        return Instancio.of(Brand.class)
+                .set(field(Brand::getId), BrandId.empty())
+                .set(field(Brand::getName), new BrandName(name))
+                .set(field(Brand::getDescription), new BrandDescription("테스트 브랜드 설명"))
+                .create();
+    }
+
+    public static Brand createWith(BrandName brandName, BrandDescription brandDescription) {
+        return Instancio.of(Brand.class)
+                .set(field(Brand::getId), BrandId.empty())
+                .set(field(Brand::getName), brandName)
+                .set(field(Brand::getDescription), brandDescription)
+                .create();
+    }
+}
diff --git a/core/domain/src/testFixtures/java/com/loopers/core/domain/order/AmountDiscountCouponFixture.java b/core/domain/src/testFixtures/java/com/loopers/core/domain/order/AmountDiscountCouponFixture.java
new file mode 100644
index 000000000..284eebc7c
--- /dev/null
+++ b/core/domain/src/testFixtures/java/com/loopers/core/domain/order/AmountDiscountCouponFixture.java
@@ -0,0 +1,43 @@
+package com.loopers.core.domain.order;
+
+import com.loopers.core.domain.order.type.CouponStatus;
+import com.loopers.core.domain.order.vo.AmountDiscountCouponId;
+import com.loopers.core.domain.order.vo.CouponDiscountAmount;
+import com.loopers.core.domain.order.vo.CouponId;
+import com.loopers.core.domain.user.vo.UserId;
+import org.instancio.Instancio;
+
+import java.math.BigDecimal;
+
+import static org.instancio.Select.field;
+
+public class AmountDiscountCouponFixture {
+
+    public static AmountDiscountCoupon create() {
+        return Instancio.of(AmountDiscountCoupon.class)
+                .set(field(AmountDiscountCoupon::getCouponId), CouponId.empty())
+                .set(field(AmountDiscountCoupon::getId), AmountDiscountCouponId.empty())
+                .set(field(AmountDiscountCoupon::getUserId), new UserId("1"))
+                .set(field(AmountDiscountCoupon::getAmount), new CouponDiscountAmount(new BigDecimal(1000)))
+                .create();
+    }
+
+    public static AmountDiscountCoupon createWith(CouponDiscountAmount couponDiscountAmount) {
+        return Instancio.of(AmountDiscountCoupon.class)
+                .set(field(AmountDiscountCoupon::getCouponId), CouponId.empty())
+                .set(field(AmountDiscountCoupon::getId), AmountDiscountCouponId.empty())
+                .set(field(AmountDiscountCoupon::getUserId), new UserId("1"))
+                .set(field(AmountDiscountCoupon::getAmount), couponDiscountAmount)
+                .create();
+    }
+
+    public static AmountDiscountCoupon createWith(CouponStatus status) {
+        return Instancio.of(AmountDiscountCoupon.class)
+                .set(field(AmountDiscountCoupon::getCouponId), CouponId.empty())
+                .set(field(AmountDiscountCoupon::getId), AmountDiscountCouponId.empty())
+                .set(field(AmountDiscountCoupon::getUserId), new UserId("1"))
+                .set(field(AmountDiscountCoupon::getAmount), new CouponDiscountAmount(new BigDecimal(1000)))
+                .set(field(AmountDiscountCoupon::getStatus), status)
+                .create();
+    }
+}
diff --git a/core/domain/src/testFixtures/java/com/loopers/core/domain/order/DefaultCouponFixture.java b/core/domain/src/testFixtures/java/com/loopers/core/domain/order/DefaultCouponFixture.java
new file mode 100644
index 000000000..775b4ad38
--- /dev/null
+++ b/core/domain/src/testFixtures/java/com/loopers/core/domain/order/DefaultCouponFixture.java
@@ -0,0 +1,24 @@
+package com.loopers.core.domain.order;
+
+import com.loopers.core.domain.order.type.CouponStatus;
+import com.loopers.core.domain.user.vo.UserId;
+import org.instancio.Instancio;
+
+import static org.instancio.Select.field;
+
+public class DefaultCouponFixture {
+
+    public static DefaultCoupon create() {
+        return Instancio.of(DefaultCoupon.class)
+                .set(field(DefaultCoupon::getUserId), Instancio.create(UserId.class))
+                .set(field(DefaultCoupon::getStatus), CouponStatus.AVAILABLE)
+                .create();
+    }
+
+    public static DefaultCoupon createWith(CouponStatus status) {
+        return Instancio.of(DefaultCoupon.class)
+                .set(field(DefaultCoupon::getUserId), Instancio.create(UserId.class))
+                .set(field(DefaultCoupon::getStatus), status)
+                .create();
+    }
+}
diff --git a/core/domain/src/testFixtures/java/com/loopers/core/domain/order/OrderFixture.java b/core/domain/src/testFixtures/java/com/loopers/core/domain/order/OrderFixture.java
new file mode 100644
index 000000000..b276b03f4
--- /dev/null
+++ b/core/domain/src/testFixtures/java/com/loopers/core/domain/order/OrderFixture.java
@@ -0,0 +1,36 @@
+package com.loopers.core.domain.order;
+
+import com.loopers.core.domain.common.vo.CreatedAt;
+import com.loopers.core.domain.common.vo.DeletedAt;
+import com.loopers.core.domain.common.vo.UpdatedAt;
+import com.loopers.core.domain.order.vo.OrderId;
+import com.loopers.core.domain.order.vo.OrderKey;
+import com.loopers.core.domain.user.vo.UserId;
+import org.instancio.Instancio;
+
+import static org.instancio.Select.field;
+
+public class OrderFixture {
+
+    public static Order create() {
+        return Instancio.of(Order.class)
+                .set(field(Order::getId), OrderId.empty())
+                .set(field(Order::getUserId), Instancio.create(UserId.class))
+                .set(field(Order::getOrderKey), OrderKey.generate())
+                .set(field(Order::getCreatedAt), CreatedAt.now())
+                .set(field(Order::getUpdatedAt), UpdatedAt.now())
+                .set(field(Order::getDeletedAt), DeletedAt.empty())
+                .create();
+    }
+
+    public static Order createWith(UserId userId) {
+        return Instancio.of(Order.class)
+                .set(field(Order::getId), OrderId.empty())
+                .set(field(Order::getUserId), userId)
+                .set(field(Order::getOrderKey), OrderKey.generate())
+                .set(field(Order::getCreatedAt), CreatedAt.now())
+                .set(field(Order::getUpdatedAt), UpdatedAt.now())
+                .set(field(Order::getDeletedAt), DeletedAt.empty())
+                .create();
+    }
+}
diff --git a/core/domain/src/testFixtures/java/com/loopers/core/domain/order/OrderItemFixture.java b/core/domain/src/testFixtures/java/com/loopers/core/domain/order/OrderItemFixture.java
new file mode 100644
index 000000000..2d77c80df
--- /dev/null
+++ b/core/domain/src/testFixtures/java/com/loopers/core/domain/order/OrderItemFixture.java
@@ -0,0 +1,39 @@
+package com.loopers.core.domain.order;
+
+import com.loopers.core.domain.order.vo.OrderId;
+import com.loopers.core.domain.order.vo.OrderItemId;
+import com.loopers.core.domain.order.vo.Quantity;
+import com.loopers.core.domain.product.vo.ProductId;
+import org.instancio.Instancio;
+
+import static org.instancio.Select.field;
+
+public class OrderItemFixture {
+
+    public static OrderItem create() {
+        return Instancio.of(OrderItem.class)
+                .set(field(OrderItem::getId), OrderItemId.empty())
+                .set(field(OrderItem::getOrderId), Instancio.create(OrderId.class))
+                .set(field(OrderItem::getProductId), Instancio.create(ProductId.class))
+                .set(field(OrderItem::getQuantity), new Quantity(1L))
+                .create();
+    }
+
+    public static OrderItem createWith(OrderId orderId, ProductId productId) {
+        return Instancio.of(OrderItem.class)
+                .set(field(OrderItem::getId), OrderItemId.empty())
+                .set(field(OrderItem::getOrderId), orderId)
+                .set(field(OrderItem::getProductId), productId)
+                .set(field(OrderItem::getQuantity), new Quantity(1L))
+                .create();
+    }
+
+    public static OrderItem createWith(OrderId orderId, ProductId productId, long quantity) {
+        return Instancio.of(OrderItem.class)
+                .set(field(OrderItem::getId), OrderItemId.empty())
+                .set(field(OrderItem::getOrderId), orderId)
+                .set(field(OrderItem::getProductId), productId)
+                .set(field(OrderItem::getQuantity), new Quantity(quantity))
+                .create();
+    }
+}
diff --git a/core/domain/src/testFixtures/java/com/loopers/core/domain/order/RateDiscountCouponFixture.java b/core/domain/src/testFixtures/java/com/loopers/core/domain/order/RateDiscountCouponFixture.java
new file mode 100644
index 000000000..136b837ee
--- /dev/null
+++ b/core/domain/src/testFixtures/java/com/loopers/core/domain/order/RateDiscountCouponFixture.java
@@ -0,0 +1,26 @@
+package com.loopers.core.domain.order;
+
+import com.loopers.core.domain.order.vo.CouponDiscountRate;
+import com.loopers.core.domain.user.vo.UserId;
+import org.instancio.Instancio;
+
+import java.math.BigDecimal;
+
+import static org.instancio.Select.field;
+
+public class RateDiscountCouponFixture {
+
+    public static RateDiscountCoupon create() {
+        return Instancio.of(RateDiscountCoupon.class)
+                .set(field(RateDiscountCoupon::getUserId), Instancio.create(UserId.class))
+                .set(field(RateDiscountCoupon::getRate), new CouponDiscountRate(new BigDecimal(10)))
+                .create();
+    }
+
+    public static RateDiscountCoupon createWith(CouponDiscountRate rate) {
+        return Instancio.of(RateDiscountCoupon.class)
+                .set(field(RateDiscountCoupon::getUserId), Instancio.create(UserId.class))
+                .set(field(RateDiscountCoupon::getRate), rate)
+                .create();
+    }
+}
diff --git a/core/domain/src/testFixtures/java/com/loopers/core/domain/payment/PaymentFixture.java b/core/domain/src/testFixtures/java/com/loopers/core/domain/payment/PaymentFixture.java
new file mode 100644
index 000000000..994baa70e
--- /dev/null
+++ b/core/domain/src/testFixtures/java/com/loopers/core/domain/payment/PaymentFixture.java
@@ -0,0 +1,41 @@
+package com.loopers.core.domain.payment;
+
+import com.loopers.core.domain.order.vo.OrderKey;
+import com.loopers.core.domain.payment.type.PaymentStatus;
+import com.loopers.core.domain.payment.vo.CardNo;
+import com.loopers.core.domain.payment.vo.CardType;
+import com.loopers.core.domain.payment.vo.PayAmount;
+import com.loopers.core.domain.payment.vo.PaymentId;
+import com.loopers.core.domain.user.vo.UserId;
+import org.instancio.Instancio;
+
+import java.math.BigDecimal;
+
+import static org.instancio.Select.field;
+
+public class PaymentFixture {
+
+    public static Payment create() {
+        return Instancio.of(Payment.class)
+                .set(field(Payment::getId), PaymentId.empty())
+                .set(field(Payment::getOrderKey), OrderKey.generate())
+                .set(field(Payment::getUserId), Instancio.create(UserId.class))
+                .set(field(Payment::getCardType), new CardType("CREDIT"))
+                .set(field(Payment::getCardNo), new CardNo("1234567890123456"))
+                .set(field(Payment::getAmount), new PayAmount(new BigDecimal(10000)))
+                .set(field(Payment::getStatus), PaymentStatus.PENDING)
+                .create();
+    }
+
+    public static Payment createWith(OrderKey orderKey, UserId userId) {
+        return Instancio.of(Payment.class)
+                .set(field(Payment::getId), PaymentId.empty())
+                .set(field(Payment::getOrderKey), orderKey)
+                .set(field(Payment::getUserId), userId)
+                .set(field(Payment::getCardType), new CardType("CREDIT"))
+                .set(field(Payment::getCardNo), new CardNo("1234567890123456"))
+                .set(field(Payment::getAmount), new PayAmount(new BigDecimal(10000)))
+                .set(field(Payment::getStatus), PaymentStatus.PENDING)
+                .create();
+    }
+}
diff --git a/core/domain/src/testFixtures/java/com/loopers/core/domain/payment/PgPaymentFixture.java b/core/domain/src/testFixtures/java/com/loopers/core/domain/payment/PgPaymentFixture.java
new file mode 100644
index 000000000..0f0d2e5e6
--- /dev/null
+++ b/core/domain/src/testFixtures/java/com/loopers/core/domain/payment/PgPaymentFixture.java
@@ -0,0 +1,38 @@
+package com.loopers.core.domain.payment;
+
+import com.loopers.core.domain.payment.type.PgPaymentStatus;
+import com.loopers.core.domain.payment.vo.PaymentId;
+import com.loopers.core.domain.payment.vo.PgPaymentId;
+import com.loopers.core.domain.payment.vo.TransactionKey;
+import org.instancio.Instancio;
+
+import static org.instancio.Select.field;
+
+public class PgPaymentFixture {
+
+    public static PgPayment create() {
+        return Instancio.of(PgPayment.class)
+                .set(field(PgPayment::getId), PgPaymentId.empty())
+                .set(field(PgPayment::getPaymentId), Instancio.create(PaymentId.class))
+                .set(field(PgPayment::getTransactionKey), Instancio.create(TransactionKey.class))
+                .set(field(PgPayment::getStatus), PgPaymentStatus.PENDING)
+                .create();
+    }
+
+    public static PgPayment createWith(PaymentId paymentId) {
+        return Instancio.of(PgPayment.class)
+                .set(field(PgPayment::getId), PgPaymentId.empty())
+                .set(field(PgPayment::getPaymentId), paymentId)
+                .set(field(PgPayment::getStatus), PgPaymentStatus.PENDING)
+                .create();
+    }
+
+    public static PgPayment createWith(PaymentId paymentId, TransactionKey transactionKey) {
+        return Instancio.of(PgPayment.class)
+                .set(field(PgPayment::getId), PgPaymentId.empty())
+                .set(field(PgPayment::getPaymentId), paymentId)
+                .set(field(PgPayment::getTransactionKey), transactionKey)
+                .set(field(PgPayment::getStatus), PgPaymentStatus.PENDING)
+                .create();
+    }
+}
diff --git a/core/domain/src/testFixtures/java/com/loopers/core/domain/product/ProductFixture.java b/core/domain/src/testFixtures/java/com/loopers/core/domain/product/ProductFixture.java
new file mode 100644
index 000000000..033d5da84
--- /dev/null
+++ b/core/domain/src/testFixtures/java/com/loopers/core/domain/product/ProductFixture.java
@@ -0,0 +1,61 @@
+package com.loopers.core.domain.product;
+
+import com.loopers.core.domain.brand.vo.BrandId;
+import com.loopers.core.domain.common.vo.DeletedAt;
+import com.loopers.core.domain.product.vo.*;
+import org.instancio.Instancio;
+
+import java.math.BigDecimal;
+
+import static org.instancio.Select.field;
+
+public class ProductFixture {
+
+    public static Product create() {
+        return Instancio.of(Product.class)
+                .set(field(Product::getId), ProductId.empty())
+                .set(field(Product::getBrandId), Instancio.create(BrandId.class))
+                .set(field(Product::getName), new ProductName("테스트 상품"))
+                .set(field(Product::getPrice), new ProductPrice(new BigDecimal(10000)))
+                .set(field(Product::getStock), new ProductStock(100L))
+                .set(field(Product::getLikeCount), ProductLikeCount.init())
+                .set(field(Product::getDeletedAt), DeletedAt.empty())
+                .create();
+    }
+
+    public static Product createWith(BrandId brandId) {
+        return Instancio.of(Product.class)
+                .set(field(Product::getId), ProductId.empty())
+                .set(field(Product::getBrandId), brandId)
+                .set(field(Product::getName), new ProductName("테스트 상품"))
+                .set(field(Product::getPrice), new ProductPrice(new BigDecimal(10000)))
+                .set(field(Product::getStock), new ProductStock(100L))
+                .set(field(Product::getLikeCount), ProductLikeCount.init())
+                .set(field(Product::getDeletedAt), DeletedAt.empty())
+                .create();
+    }
+
+    public static Product createWith(BrandId brandId, ProductName name, ProductPrice price, ProductStock stock) {
+        return Instancio.of(Product.class)
+                .set(field(Product::getId), ProductId.empty())
+                .set(field(Product::getBrandId), brandId)
+                .set(field(Product::getName), name)
+                .set(field(Product::getPrice), price)
+                .set(field(Product::getStock), stock)
+                .set(field(Product::getLikeCount), ProductLikeCount.init())
+                .set(field(Product::getDeletedAt), DeletedAt.empty())
+                .create();
+    }
+
+    public static Product createWith(BrandId brandId, ProductLikeCount likeCount) {
+        return Instancio.of(Product.class)
+                .set(field(Product::getId), ProductId.empty())
+                .set(field(Product::getBrandId), brandId)
+                .set(field(Product::getName), new ProductName("테스트 상품"))
+                .set(field(Product::getPrice), new ProductPrice(new BigDecimal(10000)))
+                .set(field(Product::getStock), new ProductStock(100L))
+                .set(field(Product::getLikeCount), likeCount)
+                .set(field(Product::getDeletedAt), DeletedAt.empty())
+                .create();
+    }
+}
diff --git a/core/domain/src/testFixtures/java/com/loopers/core/domain/productlike/ProductLikeFixture.java b/core/domain/src/testFixtures/java/com/loopers/core/domain/productlike/ProductLikeFixture.java
new file mode 100644
index 000000000..dbf68dc0d
--- /dev/null
+++ b/core/domain/src/testFixtures/java/com/loopers/core/domain/productlike/ProductLikeFixture.java
@@ -0,0 +1,30 @@
+package com.loopers.core.domain.productlike;
+
+import com.loopers.core.domain.common.vo.CreatedAt;
+import com.loopers.core.domain.product.vo.ProductId;
+import com.loopers.core.domain.productlike.vo.ProductLikeId;
+import com.loopers.core.domain.user.vo.UserId;
+import org.instancio.Instancio;
+
+import static org.instancio.Select.field;
+
+public class ProductLikeFixture {
+
+    public static ProductLike create() {
+        return Instancio.of(ProductLike.class)
+                .set(field(ProductLike::getId), ProductLikeId.empty())
+                .set(field(ProductLike::getUserId), Instancio.create(UserId.class))
+                .set(field(ProductLike::getProductId), Instancio.create(ProductId.class))
+                .set(field(ProductLike::getCreatedAt), CreatedAt.now())
+                .create();
+    }
+
+    public static ProductLike createWith(UserId userId, ProductId productId) {
+        return Instancio.of(ProductLike.class)
+                .set(field(ProductLike::getId), ProductLikeId.empty())
+                .set(field(ProductLike::getUserId), userId)
+                .set(field(ProductLike::getProductId), productId)
+                .set(field(ProductLike::getCreatedAt), CreatedAt.now())
+                .create();
+    }
+}
diff --git a/core/domain/src/testFixtures/java/com/loopers/core/domain/user/UserFixture.java b/core/domain/src/testFixtures/java/com/loopers/core/domain/user/UserFixture.java
new file mode 100644
index 000000000..803cee60a
--- /dev/null
+++ b/core/domain/src/testFixtures/java/com/loopers/core/domain/user/UserFixture.java
@@ -0,0 +1,43 @@
+package com.loopers.core.domain.user;
+
+import com.loopers.core.domain.user.type.UserGender;
+import com.loopers.core.domain.user.vo.UserBirthDay;
+import com.loopers.core.domain.user.vo.UserEmail;
+import com.loopers.core.domain.user.vo.UserId;
+import com.loopers.core.domain.user.vo.UserIdentifier;
+import org.instancio.Instancio;
+
+import static org.instancio.Select.field;
+
+public class UserFixture {
+
+    public static User create() {
+        return Instancio.of(User.class)
+                .set(field(User::getId), UserId.empty())
+                .set(field(User::getIdentifier), UserIdentifier.create("testuser"))
+                .set(field(User::getEmail), UserEmail.create("test@example.com"))
+                .set(field(User::getBirthDay), UserBirthDay.create("1990-01-01"))
+                .set(field(User::getGender), UserGender.create("MALE"))
+                .create();
+    }
+
+    public static User createWith(String identifier) {
+        return Instancio.of(User.class)
+                .set(field(User::getId), UserId.empty())
+                .set(field(User::getIdentifier), UserIdentifier.create(identifier))
+                .set(field(User::getEmail), UserEmail.create("test@example.com"))
+                .set(field(User::getBirthDay), UserBirthDay.create("1990-01-01"))
+                .set(field(User::getGender), UserGender.create("MALE"))
+                .create();
+    }
+
+    public static User createWith(String identifier, String email) {
+        return Instancio.of(User.class)
+                .set(field(User::getId), UserId.empty())
+                .set(field(User::getIdentifier), UserIdentifier.create(identifier))
+                .set(field(User::getEmail), UserEmail.create(email))
+                .set(field(User::getBirthDay), UserBirthDay.create("1990-01-01"))
+                .set(field(User::getGender), UserGender.create("MALE"))
+                .create();
+    }
+}
diff --git a/core/domain/src/testFixtures/java/com/loopers/core/domain/user/UserPointFixture.java b/core/domain/src/testFixtures/java/com/loopers/core/domain/user/UserPointFixture.java
new file mode 100644
index 000000000..7d8cd90ee
--- /dev/null
+++ b/core/domain/src/testFixtures/java/com/loopers/core/domain/user/UserPointFixture.java
@@ -0,0 +1,29 @@
+package com.loopers.core.domain.user;
+
+import com.loopers.core.domain.user.vo.UserId;
+import com.loopers.core.domain.user.vo.UserPointBalance;
+import com.loopers.core.domain.user.vo.UserPointId;
+import org.instancio.Instancio;
+
+import java.math.BigDecimal;
+
+import static org.instancio.Select.field;
+
+public class UserPointFixture {
+
+    public static UserPoint create() {
+        return Instancio.of(UserPoint.class)
+                .set(field(UserPoint::getId), UserPointId.empty())
+                .set(field(UserPoint::getUserId), Instancio.create(UserId.class))
+                .set(field(UserPoint::getBalance), UserPointBalance.init())
+                .create();
+    }
+
+    public static UserPoint createWith(UserId userId, BigDecimal balance) {
+        return Instancio.of(UserPoint.class)
+                .set(field(UserPoint::getId), UserPointId.empty())
+                .set(field(UserPoint::getUserId), userId)
+                .set(field(UserPoint::getBalance), new UserPointBalance(balance))
+                .create();
+    }
+}
diff --git a/core/infra/database/mysql/mysql-core/build.gradle.kts b/core/infra/database/mysql/build.gradle.kts
similarity index 63%
rename from core/infra/database/mysql/mysql-core/build.gradle.kts
rename to core/infra/database/mysql/build.gradle.kts
index 356e58fd4..63ba52386 100644
--- a/core/infra/database/mysql/mysql-core/build.gradle.kts
+++ b/core/infra/database/mysql/build.gradle.kts
@@ -3,10 +3,14 @@ plugins {
     `java-test-fixtures`
 }
 
-
 dependencies {
+    implementation(project(":core:domain"))
     implementation("org.springframework.boot:spring-boot-starter-data-jpa")
-    runtimeOnly("com.mysql:mysql-connector-j")
+
+    implementation("com.querydsl:querydsl-jpa::jakarta")
+    annotationProcessor("com.querydsl:querydsl-apt::jakarta")
+    annotationProcessor("jakarta.persistence:jakarta.persistence-api")
+    annotationProcessor("jakarta.annotation:jakarta.annotation-api")
 
     testFixturesImplementation("org.testcontainers:mysql")
     testFixturesImplementation("org.springframework.boot:spring-boot-starter-test")
diff --git a/core/infra/database/mysql/order-mysql/build.gradle.kts b/core/infra/database/mysql/order-mysql/build.gradle.kts
deleted file mode 100644
index cd8f78cd8..000000000
--- a/core/infra/database/mysql/order-mysql/build.gradle.kts
+++ /dev/null
@@ -1,10 +0,0 @@
-dependencies {
-    implementation(project(":core:domain"))
-    implementation(project(":core:infra:database:mysql:mysql-core"))
-    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
-
-    implementation("com.querydsl:querydsl-jpa::jakarta")
-    annotationProcessor("com.querydsl:querydsl-apt::jakarta")
-    annotationProcessor("jakarta.persistence:jakarta.persistence-api")
-    annotationProcessor("jakarta.annotation:jakarta.annotation-api")
-}
diff --git a/core/infra/database/mysql/product-mysql/build.gradle.kts b/core/infra/database/mysql/product-mysql/build.gradle.kts
deleted file mode 100644
index cd8f78cd8..000000000
--- a/core/infra/database/mysql/product-mysql/build.gradle.kts
+++ /dev/null
@@ -1,10 +0,0 @@
-dependencies {
-    implementation(project(":core:domain"))
-    implementation(project(":core:infra:database:mysql:mysql-core"))
-    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
-
-    implementation("com.querydsl:querydsl-jpa::jakarta")
-    annotationProcessor("com.querydsl:querydsl-apt::jakarta")
-    annotationProcessor("jakarta.persistence:jakarta.persistence-api")
-    annotationProcessor("jakarta.annotation:jakarta.annotation-api")
-}
diff --git a/core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/brand/BrandJpaRepository.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/brand/BrandJpaRepository.java
similarity index 100%
rename from core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/brand/BrandJpaRepository.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/brand/BrandJpaRepository.java
diff --git a/core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/brand/entity/BrandEntity.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/brand/entity/BrandEntity.java
similarity index 100%
rename from core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/brand/entity/BrandEntity.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/brand/entity/BrandEntity.java
diff --git a/core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/brand/impl/BrandRepositoryImpl.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/brand/impl/BrandRepositoryImpl.java
similarity index 100%
rename from core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/brand/impl/BrandRepositoryImpl.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/brand/impl/BrandRepositoryImpl.java
diff --git a/core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/AmountDiscountCouponJpaRepository.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/AmountDiscountCouponJpaRepository.java
similarity index 100%
rename from core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/AmountDiscountCouponJpaRepository.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/AmountDiscountCouponJpaRepository.java
diff --git a/core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/CouponJpaRepository.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/CouponJpaRepository.java
similarity index 100%
rename from core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/CouponJpaRepository.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/CouponJpaRepository.java
diff --git a/core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/RateDiscountCouponJpaRepository.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/RateDiscountCouponJpaRepository.java
similarity index 100%
rename from core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/RateDiscountCouponJpaRepository.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/RateDiscountCouponJpaRepository.java
diff --git a/core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/entity/AmountDiscountCouponEntity.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/entity/AmountDiscountCouponEntity.java
similarity index 100%
rename from core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/entity/AmountDiscountCouponEntity.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/entity/AmountDiscountCouponEntity.java
diff --git a/core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/entity/CouponEntity.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/entity/CouponEntity.java
similarity index 100%
rename from core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/entity/CouponEntity.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/entity/CouponEntity.java
diff --git a/core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/entity/RateDiscountCouponEntity.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/entity/RateDiscountCouponEntity.java
similarity index 100%
rename from core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/entity/RateDiscountCouponEntity.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/entity/RateDiscountCouponEntity.java
diff --git a/core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/impl/CouponRepositoryImpl.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/impl/CouponRepositoryImpl.java
similarity index 100%
rename from core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/impl/CouponRepositoryImpl.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/coupon/impl/CouponRepositoryImpl.java
diff --git a/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/event/EventOutboxJpaRepository.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/event/EventOutboxJpaRepository.java
new file mode 100644
index 000000000..56487248d
--- /dev/null
+++ b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/event/EventOutboxJpaRepository.java
@@ -0,0 +1,7 @@
+package com.loopers.core.infra.database.mysql.event;
+
+import com.loopers.core.infra.database.mysql.event.entity.EventOutboxEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface EventOutboxJpaRepository extends JpaRepository<EventOutboxEntity, Long> {
+}
diff --git a/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/event/entity/EventOutboxEntity.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/event/entity/EventOutboxEntity.java
new file mode 100644
index 000000000..bfeb0d6e5
--- /dev/null
+++ b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/event/entity/EventOutboxEntity.java
@@ -0,0 +1,89 @@
+package com.loopers.core.infra.database.mysql.event.entity;
+
+import com.loopers.core.domain.common.vo.CreatedAt;
+import com.loopers.core.domain.common.vo.UpdatedAt;
+import com.loopers.core.domain.event.EventOutbox;
+import com.loopers.core.domain.event.type.AggregateType;
+import com.loopers.core.domain.event.type.EventOutboxStatus;
+import com.loopers.core.domain.event.type.EventType;
+import com.loopers.core.domain.event.vo.AggregateId;
+import com.loopers.core.domain.event.vo.EventOutboxId;
+import com.loopers.core.domain.event.vo.EventPayload;
+import com.loopers.core.domain.event.vo.PublishedAt;
+import jakarta.persistence.*;
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+import java.util.Optional;
+
+@Entity
+@Table(
+        name = "event_outbox",
+        indexes = {
+                @Index(name = "idx_event_outbox_aggregate_type_event_type_status", columnList = "aggregate_type,event_type,status")
+        }
+)
+@AllArgsConstructor(access = AccessLevel.PRIVATE)
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+public class EventOutboxEntity {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    @Column(nullable = false)
+    private String aggregateType;
+
+    @Column(nullable = false)
+    private String aggregateId;
+
+    @Column(nullable = false)
+    private String eventType;
+
+    @Column(nullable = false)
+    private String status;
+
+    @Lob
+    @Column(nullable = false)
+    private String payload;
+
+    private LocalDateTime publishedAt;
+
+    @Column(nullable = false)
+    private LocalDateTime createdAt;
+
+    private LocalDateTime updatedAt;
+
+    public static EventOutboxEntity from(EventOutbox eventOutbox) {
+        return new EventOutboxEntity(
+                Optional.ofNullable(eventOutbox.getId().value())
+                        .map(Long::parseLong)
+                        .orElse(null),
+                eventOutbox.getAggregateType().name(),
+                eventOutbox.getAggregateId().value(),
+                eventOutbox.getEventType().name(),
+                eventOutbox.getStatus().name(),
+                eventOutbox.getPayload().value(),
+                eventOutbox.getPublishedAt().value(),
+                eventOutbox.getCreatedAt().value(),
+                eventOutbox.getUpdatedAt().value()
+        );
+    }
+
+    public EventOutbox to() {
+        return EventOutbox.mappedBy(
+                new EventOutboxId(this.id.toString()),
+                AggregateType.valueOf(this.aggregateType),
+                new AggregateId(this.aggregateId),
+                EventType.valueOf(this.eventType),
+                EventOutboxStatus.valueOf(this.status),
+                new EventPayload(this.payload),
+                new PublishedAt(this.publishedAt),
+                new CreatedAt(this.createdAt),
+                new UpdatedAt(this.updatedAt)
+        );
+    }
+
+}
diff --git a/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/event/impl/EventOutboxRepositoryImpl.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/event/impl/EventOutboxRepositoryImpl.java
new file mode 100644
index 000000000..43c79ef0a
--- /dev/null
+++ b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/event/impl/EventOutboxRepositoryImpl.java
@@ -0,0 +1,20 @@
+package com.loopers.core.infra.database.mysql.event.impl;
+
+import com.loopers.core.domain.event.EventOutbox;
+import com.loopers.core.domain.event.repository.EventOutboxRepository;
+import com.loopers.core.infra.database.mysql.event.EventOutboxJpaRepository;
+import com.loopers.core.infra.database.mysql.event.entity.EventOutboxEntity;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Repository;
+
+@Repository
+@RequiredArgsConstructor
+public class EventOutboxRepositoryImpl implements EventOutboxRepository {
+
+    private final EventOutboxJpaRepository repository;
+
+    @Override
+    public EventOutbox save(EventOutbox eventOutbox) {
+        return repository.save(EventOutboxEntity.from(eventOutbox)).to();
+    }
+}
diff --git a/core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/order/dto/OrderListProjection.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/order/dto/OrderListProjection.java
similarity index 100%
rename from core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/order/dto/OrderListProjection.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/order/dto/OrderListProjection.java
diff --git a/core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/order/entity/OrderEntity.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/order/entity/OrderEntity.java
similarity index 91%
rename from core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/order/entity/OrderEntity.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/order/entity/OrderEntity.java
index f43437d52..4a453aa7e 100644
--- a/core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/order/entity/OrderEntity.java
+++ b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/order/entity/OrderEntity.java
@@ -4,6 +4,7 @@
 import com.loopers.core.domain.common.vo.DeletedAt;
 import com.loopers.core.domain.common.vo.UpdatedAt;
 import com.loopers.core.domain.order.Order;
+import com.loopers.core.domain.order.type.OrderStatus;
 import com.loopers.core.domain.order.vo.OrderId;
 import com.loopers.core.domain.order.vo.OrderKey;
 import com.loopers.core.domain.user.vo.UserId;
@@ -39,6 +40,9 @@ public class OrderEntity {
     @Column(nullable = false)
     private String orderKey;
 
+    @Column(nullable = false)
+    private String status;
+
     @Column(nullable = false)
     private LocalDateTime createdAt;
 
@@ -54,6 +58,7 @@ public static OrderEntity from(Order order) {
                         .orElse(null),
                 Long.parseLong(Objects.requireNonNull(order.getUserId().value())),
                 order.getOrderKey().value(),
+                order.getStatus().name(),
                 order.getCreatedAt().value(),
                 order.getUpdatedAt().value(),
                 order.getDeletedAt().value()
@@ -65,6 +70,7 @@ public Order to() {
                 new OrderId(this.id.toString()),
                 new UserId(this.userId.toString()),
                 new OrderKey(this.orderKey),
+                OrderStatus.valueOf(this.status),
                 new CreatedAt(this.createdAt),
                 new UpdatedAt(this.updatedAt),
                 new DeletedAt(this.deletedAt)
diff --git a/core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/order/entity/OrderItemEntity.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/order/entity/OrderItemEntity.java
similarity index 100%
rename from core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/order/entity/OrderItemEntity.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/order/entity/OrderItemEntity.java
diff --git a/core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/order/impl/OrderItemRepositoryImpl.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/order/impl/OrderItemRepositoryImpl.java
similarity index 100%
rename from core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/order/impl/OrderItemRepositoryImpl.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/order/impl/OrderItemRepositoryImpl.java
diff --git a/core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/order/impl/OrderRepositoryImpl.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/order/impl/OrderRepositoryImpl.java
similarity index 100%
rename from core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/order/impl/OrderRepositoryImpl.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/order/impl/OrderRepositoryImpl.java
diff --git a/core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/order/repository/OrderItemJpaRepository.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/order/repository/OrderItemJpaRepository.java
similarity index 100%
rename from core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/order/repository/OrderItemJpaRepository.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/order/repository/OrderItemJpaRepository.java
diff --git a/core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/order/repository/OrderJpaRepository.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/order/repository/OrderJpaRepository.java
similarity index 100%
rename from core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/order/repository/OrderJpaRepository.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/order/repository/OrderJpaRepository.java
diff --git a/core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/order/repository/OrderQuerydslRepository.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/order/repository/OrderQuerydslRepository.java
similarity index 100%
rename from core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/order/repository/OrderQuerydslRepository.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/order/repository/OrderQuerydslRepository.java
diff --git a/core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/order/repository/OrderQuerydslRepositoryImpl.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/order/repository/OrderQuerydslRepositoryImpl.java
similarity index 100%
rename from core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/order/repository/OrderQuerydslRepositoryImpl.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/order/repository/OrderQuerydslRepositoryImpl.java
diff --git a/core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/entity/PaymentEntity.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/entity/PaymentEntity.java
similarity index 91%
rename from core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/entity/PaymentEntity.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/entity/PaymentEntity.java
index 4fe995c70..dc7421b04 100644
--- a/core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/entity/PaymentEntity.java
+++ b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/entity/PaymentEntity.java
@@ -6,6 +6,7 @@
 import com.loopers.core.domain.order.vo.OrderKey;
 import com.loopers.core.domain.payment.Payment;
 import com.loopers.core.domain.payment.type.PaymentStatus;
+import com.loopers.core.domain.payment.type.PaymentType;
 import com.loopers.core.domain.payment.vo.*;
 import com.loopers.core.domain.user.vo.UserId;
 import jakarta.persistence.*;
@@ -23,7 +24,6 @@
         name = "payments",
         indexes = {
                 @Index(name = "idx_payment_order_key", columnList = "order_key"),
-                @Index(name = "idx_payment_transaction_key", columnList = "transaction_key"),
                 @Index(name = "idx_payment_user_id", columnList = "user_id"),
                 @Index(name = "idx_payment_created_at", columnList = "created_at")
         }
@@ -54,8 +54,10 @@ public class PaymentEntity {
     @Column(nullable = false)
     private String status;
 
-    private String transactionKey;
+    @Column(nullable = false)
+    private String type;
 
+    @Lob
     private String failedReason;
 
     @Column(nullable = false)
@@ -77,7 +79,7 @@ public static PaymentEntity from(Payment payment) {
                 payment.getCardNo().value(),
                 payment.getAmount().value(),
                 payment.getStatus().name(),
-                payment.getTransactionKey().value(),
+                payment.getType().name(),
                 payment.getFailedReason().value(),
                 payment.getCreatedAt().value(),
                 payment.getUpdatedAt().value(),
@@ -94,8 +96,8 @@ public Payment to() {
                 new CardNo(this.cardNo),
                 new PayAmount(this.amount),
                 PaymentStatus.valueOf(this.status),
-                new TransactionKey(this.transactionKey),
-                new FailedReason(this.failedReason),
+                PaymentType.valueOf(this.type),
+                new FailedReason(failedReason),
                 new CreatedAt(this.createdAt),
                 new UpdatedAt(this.updatedAt),
                 new DeletedAt(this.deletedAt)
diff --git a/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/entity/PgPaymentEntity.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/entity/PgPaymentEntity.java
new file mode 100644
index 000000000..8db7bf5a3
--- /dev/null
+++ b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/entity/PgPaymentEntity.java
@@ -0,0 +1,84 @@
+package com.loopers.core.infra.database.mysql.payment.entity;
+
+import com.loopers.core.domain.common.vo.CreatedAt;
+import com.loopers.core.domain.common.vo.DeletedAt;
+import com.loopers.core.domain.common.vo.UpdatedAt;
+import com.loopers.core.domain.payment.PgPayment;
+import com.loopers.core.domain.payment.type.PgPaymentStatus;
+import com.loopers.core.domain.payment.vo.FailedReason;
+import com.loopers.core.domain.payment.vo.PaymentId;
+import com.loopers.core.domain.payment.vo.PgPaymentId;
+import com.loopers.core.domain.payment.vo.TransactionKey;
+import jakarta.persistence.*;
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+import java.util.Optional;
+
+@Entity
+@Table(
+        name = "pg_payments",
+        indexes = {
+                @Index(name = "idx_pg_payment_transaction_key", columnList = "transaction_key"),
+                @Index(name = "idx_pg_payment_payment_id", columnList = "payment_id"),
+                @Index(name = "idx_pg_payment_created_at", columnList = "created_at")
+        }
+)
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@AllArgsConstructor(access = AccessLevel.PRIVATE)
+public class PgPaymentEntity {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    @Column(nullable = false)
+    private Long paymentId;
+
+    @Column(nullable = false)
+    private String transactionKey;
+
+    @Column(nullable = false)
+    private String status;
+
+    @Lob
+    private String failedReason;
+
+    @Column(nullable = false)
+    private LocalDateTime createdAt;
+
+    @Column(nullable = false)
+    private LocalDateTime updatedAt;
+
+    private LocalDateTime deletedAt;
+
+    public static PgPaymentEntity from(PgPayment pgPayment) {
+        return new PgPaymentEntity(
+                Optional.ofNullable(pgPayment.getId().value())
+                        .map(Long::parseLong)
+                        .orElse(null),
+                Long.parseLong(pgPayment.getPaymentId().value()),
+                pgPayment.getTransactionKey().value(),
+                pgPayment.getStatus().name(),
+                pgPayment.getFailedReason().value(),
+                pgPayment.getCreatedAt().value(),
+                pgPayment.getUpdatedAt().value(),
+                pgPayment.getDeletedAt().value()
+        );
+    }
+
+    public PgPayment to() {
+        return PgPayment.mappedBy(
+                new PgPaymentId(this.id.toString()),
+                new PaymentId(this.paymentId.toString()),
+                new TransactionKey(this.transactionKey),
+                PgPaymentStatus.valueOf(this.status),
+                new FailedReason(this.failedReason),
+                new CreatedAt(this.createdAt),
+                new UpdatedAt(this.updatedAt),
+                new DeletedAt(this.deletedAt)
+        );
+    }
+}
diff --git a/core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/impl/PaymentRepositoryImpl.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/impl/PaymentRepositoryImpl.java
similarity index 82%
rename from core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/impl/PaymentRepositoryImpl.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/impl/PaymentRepositoryImpl.java
index 01729d1fa..99e0cbed4 100644
--- a/core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/impl/PaymentRepositoryImpl.java
+++ b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/impl/PaymentRepositoryImpl.java
@@ -5,7 +5,7 @@
 import com.loopers.core.domain.payment.Payment;
 import com.loopers.core.domain.payment.repository.PaymentRepository;
 import com.loopers.core.domain.payment.type.PaymentStatus;
-import com.loopers.core.domain.payment.vo.TransactionKey;
+import com.loopers.core.domain.payment.vo.PaymentId;
 import com.loopers.core.infra.database.mysql.payment.entity.PaymentEntity;
 import com.loopers.core.infra.database.mysql.payment.repository.PaymentJpaRepository;
 import lombok.RequiredArgsConstructor;
@@ -21,26 +21,26 @@ public class PaymentRepositoryImpl implements PaymentRepository {
     private final PaymentJpaRepository repository;
 
     @Override
-    public Payment save(Payment payment) {
-        return repository.save(PaymentEntity.from(payment)).to();
+    public Optional<Payment> findByWithLock(OrderKey orderKey, PaymentStatus status) {
+        return repository.findByOrderKeyAndStatusWithLock(orderKey.value(), status.name())
+                .map(PaymentEntity::to);
     }
 
     @Override
-    public Payment getByWithLock(TransactionKey transactionKey) {
-        return repository.findByTransactionKeyWithLock(Objects.requireNonNull(transactionKey.value()))
-                .orElseThrow(() -> NotFoundException.withName("주문 정보"))
+    public Payment getById(PaymentId paymentId) {
+        return repository.findById(Long.parseLong(Objects.requireNonNull(paymentId.value())))
+                .orElseThrow(() -> NotFoundException.withName("결제"))
                 .to();
     }
 
     @Override
-    public Optional<Payment> findBy(OrderKey orderKey, PaymentStatus status) {
-        return repository.findByOrderKeyAndStatus(orderKey.value(), status.name())
-                .map(PaymentEntity::to);
+    public Payment save(Payment payment) {
+        return repository.save(PaymentEntity.from(payment)).to();
     }
 
     @Override
-    public Optional<Payment> findByWithLock(OrderKey orderKey, PaymentStatus status) {
-        return repository.findByOrderKeyAndStatusWithLock(orderKey.value(), status.name())
+    public Optional<Payment> findBy(OrderKey orderKey, PaymentStatus status) {
+        return repository.findByOrderKeyAndStatus(orderKey.value(), status.name())
                 .map(PaymentEntity::to);
     }
 }
diff --git a/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/impl/PgPaymentRepositoryImpl.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/impl/PgPaymentRepositoryImpl.java
new file mode 100644
index 000000000..b101db44d
--- /dev/null
+++ b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/impl/PgPaymentRepositoryImpl.java
@@ -0,0 +1,41 @@
+package com.loopers.core.infra.database.mysql.payment.impl;
+
+import com.loopers.core.domain.error.NotFoundException;
+import com.loopers.core.domain.payment.PgPayment;
+import com.loopers.core.domain.payment.repository.PgPaymentRepository;
+import com.loopers.core.domain.payment.vo.PaymentId;
+import com.loopers.core.domain.payment.vo.TransactionKey;
+import com.loopers.core.infra.database.mysql.payment.entity.PgPaymentEntity;
+import com.loopers.core.infra.database.mysql.payment.repository.PgPaymentJpaRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Objects;
+import java.util.Optional;
+
+@Repository
+@RequiredArgsConstructor
+public class PgPaymentRepositoryImpl implements PgPaymentRepository {
+
+    private final PgPaymentJpaRepository repository;
+
+    @Override
+    public Optional<PgPayment> findBy(PaymentId paymentId) {
+        return repository.findByPaymentId(Long.parseLong(Objects.requireNonNull(paymentId.value())))
+                .map(PgPaymentEntity::to);
+    }
+
+    @Override
+    @Transactional
+    public PgPayment save(PgPayment pgPayment) {
+        return repository.save(PgPaymentEntity.from(pgPayment)).to();
+    }
+
+    @Override
+    public PgPayment getByWithLock(TransactionKey transactionKey) {
+        return repository.findByTransactionKeyWithLock(transactionKey.value())
+                .orElseThrow(() -> NotFoundException.withName("PG 결제"))
+                .to();
+    }
+}
diff --git a/core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/repository/PaymentJpaRepository.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/repository/PaymentJpaRepository.java
similarity index 60%
rename from core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/repository/PaymentJpaRepository.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/repository/PaymentJpaRepository.java
index ff62f885f..dddfcaa1f 100644
--- a/core/infra/database/mysql/order-mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/repository/PaymentJpaRepository.java
+++ b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/repository/PaymentJpaRepository.java
@@ -5,18 +5,16 @@
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.Lock;
 import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
 
 import java.util.Optional;
 
 public interface PaymentJpaRepository extends JpaRepository<PaymentEntity, Long> {
 
-    @Lock(LockModeType.PESSIMISTIC_WRITE)
-    @Query("select p from PaymentEntity p where p.transactionKey = :transactionKey")
-    Optional<PaymentEntity> findByTransactionKeyWithLock(String transactionKey);
-
     Optional<PaymentEntity> findByOrderKeyAndStatus(String orderKey, String status);
 
     @Lock(LockModeType.PESSIMISTIC_WRITE)
-    @Query("select p from PaymentEntity p where p.orderKey = :orderKey and p.status = :status")
-    Optional<PaymentEntity> findByOrderKeyAndStatusWithLock(String orderKey, String status);
+    @Query("SELECT p FROM PaymentEntity p WHERE p.orderKey = :orderKey AND p.status = :status")
+    Optional<PaymentEntity> findByOrderKeyAndStatusWithLock(@Param("orderKey") String orderKey, @Param("status") String status);
+
 }
diff --git a/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/repository/PgPaymentJpaRepository.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/repository/PgPaymentJpaRepository.java
new file mode 100644
index 000000000..4f31f76a4
--- /dev/null
+++ b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/payment/repository/PgPaymentJpaRepository.java
@@ -0,0 +1,19 @@
+package com.loopers.core.infra.database.mysql.payment.repository;
+
+import com.loopers.core.infra.database.mysql.payment.entity.PgPaymentEntity;
+import jakarta.persistence.LockModeType;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Lock;
+import org.springframework.data.jpa.repository.Query;
+
+import java.util.Optional;
+
+public interface PgPaymentJpaRepository extends JpaRepository<PgPaymentEntity, Long> {
+
+    @Lock(LockModeType.PESSIMISTIC_WRITE)
+    @Query("select p from PgPaymentEntity p where p.transactionKey = :transactionKey")
+    Optional<PgPaymentEntity> findByTransactionKeyWithLock(String transactionKey);
+
+    Optional<PgPaymentEntity> findByPaymentId(Long paymentId);
+
+}
diff --git a/core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/product/ProductBulkRepository.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/product/ProductBulkRepository.java
similarity index 100%
rename from core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/product/ProductBulkRepository.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/product/ProductBulkRepository.java
diff --git a/core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/product/ProductBulkRepositoryImpl.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/product/ProductBulkRepositoryImpl.java
similarity index 100%
rename from core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/product/ProductBulkRepositoryImpl.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/product/ProductBulkRepositoryImpl.java
diff --git a/core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/product/ProductJpaRepository.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/product/ProductJpaRepository.java
similarity index 100%
rename from core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/product/ProductJpaRepository.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/product/ProductJpaRepository.java
diff --git a/core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/product/ProductQuerydslRepository.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/product/ProductQuerydslRepository.java
similarity index 100%
rename from core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/product/ProductQuerydslRepository.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/product/ProductQuerydslRepository.java
diff --git a/core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/product/ProductQuerydslRepositoryImpl.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/product/ProductQuerydslRepositoryImpl.java
similarity index 100%
rename from core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/product/ProductQuerydslRepositoryImpl.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/product/ProductQuerydslRepositoryImpl.java
diff --git a/core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/product/dto/ProductListProjection.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/product/dto/ProductListProjection.java
similarity index 100%
rename from core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/product/dto/ProductListProjection.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/product/dto/ProductListProjection.java
diff --git a/core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/product/entity/ProductEntity.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/product/entity/ProductEntity.java
similarity index 100%
rename from core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/product/entity/ProductEntity.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/product/entity/ProductEntity.java
diff --git a/core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/product/impl/ProductRepositoryImpl.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/product/impl/ProductRepositoryImpl.java
similarity index 100%
rename from core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/product/impl/ProductRepositoryImpl.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/product/impl/ProductRepositoryImpl.java
diff --git a/core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/ProductLikeBulkRepository.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/ProductLikeBulkRepository.java
similarity index 100%
rename from core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/ProductLikeBulkRepository.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/ProductLikeBulkRepository.java
diff --git a/core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/ProductLikeBulkRepositoryImpl.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/ProductLikeBulkRepositoryImpl.java
similarity index 100%
rename from core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/ProductLikeBulkRepositoryImpl.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/ProductLikeBulkRepositoryImpl.java
diff --git a/core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/ProductLikeJpaRepository.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/ProductLikeJpaRepository.java
similarity index 100%
rename from core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/ProductLikeJpaRepository.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/ProductLikeJpaRepository.java
diff --git a/core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/ProductLikeQuerydslRepository.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/ProductLikeQuerydslRepository.java
similarity index 100%
rename from core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/ProductLikeQuerydslRepository.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/ProductLikeQuerydslRepository.java
diff --git a/core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/ProductLikeQuerydslRepositoryImpl.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/ProductLikeQuerydslRepositoryImpl.java
similarity index 100%
rename from core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/ProductLikeQuerydslRepositoryImpl.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/ProductLikeQuerydslRepositoryImpl.java
diff --git a/core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/dto/LikeProductListProjection.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/dto/LikeProductListProjection.java
similarity index 100%
rename from core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/dto/LikeProductListProjection.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/dto/LikeProductListProjection.java
diff --git a/core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/entity/ProductLikeEntity.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/entity/ProductLikeEntity.java
similarity index 100%
rename from core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/entity/ProductLikeEntity.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/entity/ProductLikeEntity.java
diff --git a/core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/impl/ProductLikeRepositoryImpl.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/impl/ProductLikeRepositoryImpl.java
similarity index 100%
rename from core/infra/database/mysql/product-mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/impl/ProductLikeRepositoryImpl.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/productlike/impl/ProductLikeRepositoryImpl.java
diff --git a/core/infra/database/mysql/user-mysql/src/main/java/com/loopers/core/infra/database/mysql/user/UserJpaRepository.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/user/UserJpaRepository.java
similarity index 100%
rename from core/infra/database/mysql/user-mysql/src/main/java/com/loopers/core/infra/database/mysql/user/UserJpaRepository.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/user/UserJpaRepository.java
diff --git a/core/infra/database/mysql/user-mysql/src/main/java/com/loopers/core/infra/database/mysql/user/UserPointJpaRepository.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/user/UserPointJpaRepository.java
similarity index 100%
rename from core/infra/database/mysql/user-mysql/src/main/java/com/loopers/core/infra/database/mysql/user/UserPointJpaRepository.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/user/UserPointJpaRepository.java
diff --git a/core/infra/database/mysql/user-mysql/src/main/java/com/loopers/core/infra/database/mysql/user/entity/UserEntity.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/user/entity/UserEntity.java
similarity index 100%
rename from core/infra/database/mysql/user-mysql/src/main/java/com/loopers/core/infra/database/mysql/user/entity/UserEntity.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/user/entity/UserEntity.java
diff --git a/core/infra/database/mysql/user-mysql/src/main/java/com/loopers/core/infra/database/mysql/user/entity/UserPointEntity.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/user/entity/UserPointEntity.java
similarity index 100%
rename from core/infra/database/mysql/user-mysql/src/main/java/com/loopers/core/infra/database/mysql/user/entity/UserPointEntity.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/user/entity/UserPointEntity.java
diff --git a/core/infra/database/mysql/user-mysql/src/main/java/com/loopers/core/infra/database/mysql/user/impl/UserPointRepositoryImpl.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/user/impl/UserPointRepositoryImpl.java
similarity index 100%
rename from core/infra/database/mysql/user-mysql/src/main/java/com/loopers/core/infra/database/mysql/user/impl/UserPointRepositoryImpl.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/user/impl/UserPointRepositoryImpl.java
diff --git a/core/infra/database/mysql/user-mysql/src/main/java/com/loopers/core/infra/database/mysql/user/impl/UserRepositoryImpl.java b/core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/user/impl/UserRepositoryImpl.java
similarity index 100%
rename from core/infra/database/mysql/user-mysql/src/main/java/com/loopers/core/infra/database/mysql/user/impl/UserRepositoryImpl.java
rename to core/infra/database/mysql/src/main/java/com/loopers/core/infra/database/mysql/user/impl/UserRepositoryImpl.java
diff --git a/core/infra/database/mysql/mysql-core/src/testFixtures/java/com/loopers/core/infra/mysql/testcontainers/MySqlTestContainersExtension.java b/core/infra/database/mysql/src/testFixtures/java/com/loopers/core/infra/mysql/testcontainers/MySqlTestContainersExtension.java
similarity index 100%
rename from core/infra/database/mysql/mysql-core/src/testFixtures/java/com/loopers/core/infra/mysql/testcontainers/MySqlTestContainersExtension.java
rename to core/infra/database/mysql/src/testFixtures/java/com/loopers/core/infra/mysql/testcontainers/MySqlTestContainersExtension.java
diff --git a/core/infra/database/mysql/mysql-core/src/testFixtures/java/com/loopers/core/infra/mysql/util/DatabaseCleanUp.java b/core/infra/database/mysql/src/testFixtures/java/com/loopers/core/infra/mysql/util/DatabaseCleanUp.java
similarity index 100%
rename from core/infra/database/mysql/mysql-core/src/testFixtures/java/com/loopers/core/infra/mysql/util/DatabaseCleanUp.java
rename to core/infra/database/mysql/src/testFixtures/java/com/loopers/core/infra/mysql/util/DatabaseCleanUp.java
diff --git a/core/infra/database/mysql/user-mysql/build.gradle.kts b/core/infra/database/mysql/user-mysql/build.gradle.kts
deleted file mode 100644
index 1533786bb..000000000
--- a/core/infra/database/mysql/user-mysql/build.gradle.kts
+++ /dev/null
@@ -1,5 +0,0 @@
-dependencies {
-    implementation(project(":core:domain"))
-    implementation(project(":core:infra:database:mysql:mysql-core"))
-    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
-}
diff --git a/core/infra/database/redis/product-redis/build.gradle.kts b/core/infra/database/redis/build.gradle.kts
similarity index 100%
rename from core/infra/database/redis/product-redis/build.gradle.kts
rename to core/infra/database/redis/build.gradle.kts
diff --git a/core/infra/database/redis/product-redis/src/main/java/com/loopers/core/infra/database/redis/product/ProductDetailRedisRepository.java b/core/infra/database/redis/src/main/java/com/loopers/core/infra/database/redis/product/ProductDetailRedisRepository.java
similarity index 100%
rename from core/infra/database/redis/product-redis/src/main/java/com/loopers/core/infra/database/redis/product/ProductDetailRedisRepository.java
rename to core/infra/database/redis/src/main/java/com/loopers/core/infra/database/redis/product/ProductDetailRedisRepository.java
diff --git a/core/infra/database/redis/product-redis/src/main/java/com/loopers/core/infra/database/redis/product/ProductDetailRedisRepositoryImpl.java b/core/infra/database/redis/src/main/java/com/loopers/core/infra/database/redis/product/ProductDetailRedisRepositoryImpl.java
similarity index 100%
rename from core/infra/database/redis/product-redis/src/main/java/com/loopers/core/infra/database/redis/product/ProductDetailRedisRepositoryImpl.java
rename to core/infra/database/redis/src/main/java/com/loopers/core/infra/database/redis/product/ProductDetailRedisRepositoryImpl.java
diff --git a/core/infra/database/redis/product-redis/src/main/java/com/loopers/core/infra/database/redis/product/ProductLikeRedisRepository.java b/core/infra/database/redis/src/main/java/com/loopers/core/infra/database/redis/product/ProductLikeRedisRepository.java
similarity index 100%
rename from core/infra/database/redis/product-redis/src/main/java/com/loopers/core/infra/database/redis/product/ProductLikeRedisRepository.java
rename to core/infra/database/redis/src/main/java/com/loopers/core/infra/database/redis/product/ProductLikeRedisRepository.java
diff --git a/core/infra/database/redis/product-redis/src/main/java/com/loopers/core/infra/database/redis/product/entity/BrandRedisEntity.java b/core/infra/database/redis/src/main/java/com/loopers/core/infra/database/redis/product/entity/BrandRedisEntity.java
similarity index 100%
rename from core/infra/database/redis/product-redis/src/main/java/com/loopers/core/infra/database/redis/product/entity/BrandRedisEntity.java
rename to core/infra/database/redis/src/main/java/com/loopers/core/infra/database/redis/product/entity/BrandRedisEntity.java
diff --git a/core/infra/database/redis/product-redis/src/main/java/com/loopers/core/infra/database/redis/product/entity/ProductDetailRedisEntity.java b/core/infra/database/redis/src/main/java/com/loopers/core/infra/database/redis/product/entity/ProductDetailRedisEntity.java
similarity index 100%
rename from core/infra/database/redis/product-redis/src/main/java/com/loopers/core/infra/database/redis/product/entity/ProductDetailRedisEntity.java
rename to core/infra/database/redis/src/main/java/com/loopers/core/infra/database/redis/product/entity/ProductDetailRedisEntity.java
diff --git a/core/infra/database/redis/product-redis/src/main/java/com/loopers/core/infra/database/redis/product/entity/ProductRedisEntity.java b/core/infra/database/redis/src/main/java/com/loopers/core/infra/database/redis/product/entity/ProductRedisEntity.java
similarity index 100%
rename from core/infra/database/redis/product-redis/src/main/java/com/loopers/core/infra/database/redis/product/entity/ProductRedisEntity.java
rename to core/infra/database/redis/src/main/java/com/loopers/core/infra/database/redis/product/entity/ProductRedisEntity.java
diff --git a/core/infra/database/redis/product-redis/src/main/java/com/loopers/core/infra/database/redis/product/impl/ProductCacheRepositoryImpl.java b/core/infra/database/redis/src/main/java/com/loopers/core/infra/database/redis/product/impl/ProductCacheRepositoryImpl.java
similarity index 100%
rename from core/infra/database/redis/product-redis/src/main/java/com/loopers/core/infra/database/redis/product/impl/ProductCacheRepositoryImpl.java
rename to core/infra/database/redis/src/main/java/com/loopers/core/infra/database/redis/product/impl/ProductCacheRepositoryImpl.java
diff --git a/core/infra/database/redis/product-redis/src/main/java/com/loopers/core/infra/database/redis/product/impl/ProductLikeCacheRepositoryImpl.java b/core/infra/database/redis/src/main/java/com/loopers/core/infra/database/redis/product/impl/ProductLikeCacheRepositoryImpl.java
similarity index 100%
rename from core/infra/database/redis/product-redis/src/main/java/com/loopers/core/infra/database/redis/product/impl/ProductLikeCacheRepositoryImpl.java
rename to core/infra/database/redis/src/main/java/com/loopers/core/infra/database/redis/product/impl/ProductLikeCacheRepositoryImpl.java
diff --git a/core/infra/database/redis/product-redis/src/main/java/com/loopers/core/infra/database/redis/product/impl/ProductLikeRedisRepositoryImpl.java b/core/infra/database/redis/src/main/java/com/loopers/core/infra/database/redis/product/impl/ProductLikeRedisRepositoryImpl.java
similarity index 100%
rename from core/infra/database/redis/product-redis/src/main/java/com/loopers/core/infra/database/redis/product/impl/ProductLikeRedisRepositoryImpl.java
rename to core/infra/database/redis/src/main/java/com/loopers/core/infra/database/redis/product/impl/ProductLikeRedisRepositoryImpl.java
diff --git a/core/infra/http-client/pg-simulator-client/build.gradle.kts b/core/infra/http-client/build.gradle.kts
similarity index 100%
rename from core/infra/http-client/pg-simulator-client/build.gradle.kts
rename to core/infra/http-client/build.gradle.kts
diff --git a/core/infra/http-client/src/main/java/com/loopers/core/infra/httpclient/dataplatform/order/impl/OrderDataPlatformClientImpl.java b/core/infra/http-client/src/main/java/com/loopers/core/infra/httpclient/dataplatform/order/impl/OrderDataPlatformClientImpl.java
new file mode 100644
index 000000000..33030afb8
--- /dev/null
+++ b/core/infra/http-client/src/main/java/com/loopers/core/infra/httpclient/dataplatform/order/impl/OrderDataPlatformClientImpl.java
@@ -0,0 +1,14 @@
+package com.loopers.core.infra.httpclient.dataplatform.order.impl;
+
+import com.loopers.core.domain.order.Order;
+import com.loopers.core.domain.order.OrderDataPlatformClient;
+import org.springframework.stereotype.Component;
+
+@Component
+public class OrderDataPlatformClientImpl implements OrderDataPlatformClient {
+
+    @Override
+    public void send(Order order) {
+        
+    }
+}
diff --git a/core/infra/http-client/src/main/java/com/loopers/core/infra/httpclient/dataplatform/payment/impl/PaymentDataPlatformClientImpl.java b/core/infra/http-client/src/main/java/com/loopers/core/infra/httpclient/dataplatform/payment/impl/PaymentDataPlatformClientImpl.java
new file mode 100644
index 000000000..7e223674e
--- /dev/null
+++ b/core/infra/http-client/src/main/java/com/loopers/core/infra/httpclient/dataplatform/payment/impl/PaymentDataPlatformClientImpl.java
@@ -0,0 +1,14 @@
+package com.loopers.core.infra.httpclient.dataplatform.payment.impl;
+
+import com.loopers.core.domain.payment.Payment;
+import com.loopers.core.domain.payment.PaymentDataPlatformClient;
+import org.springframework.stereotype.Component;
+
+@Component
+public class PaymentDataPlatformClientImpl implements PaymentDataPlatformClient {
+
+    @Override
+    public void send(Payment payment) {
+
+    }
+}
diff --git a/core/infra/http-client/pg-simulator-client/src/main/java/com/loopers/core/infra/httpclient/pgsimulator/PgSimulatorClient.java b/core/infra/http-client/src/main/java/com/loopers/core/infra/httpclient/pgsimulator/PgSimulatorClient.java
similarity index 100%
rename from core/infra/http-client/pg-simulator-client/src/main/java/com/loopers/core/infra/httpclient/pgsimulator/PgSimulatorClient.java
rename to core/infra/http-client/src/main/java/com/loopers/core/infra/httpclient/pgsimulator/PgSimulatorClient.java
diff --git a/core/infra/http-client/pg-simulator-client/src/main/java/com/loopers/core/infra/httpclient/pgsimulator/dto/PgSimulatorPaymentResponse.java b/core/infra/http-client/src/main/java/com/loopers/core/infra/httpclient/pgsimulator/dto/PgSimulatorPaymentResponse.java
similarity index 100%
rename from core/infra/http-client/pg-simulator-client/src/main/java/com/loopers/core/infra/httpclient/pgsimulator/dto/PgSimulatorPaymentResponse.java
rename to core/infra/http-client/src/main/java/com/loopers/core/infra/httpclient/pgsimulator/dto/PgSimulatorPaymentResponse.java
diff --git a/core/infra/http-client/pg-simulator-client/src/main/java/com/loopers/core/infra/httpclient/pgsimulator/dto/PgSimulatorV1Dto.java b/core/infra/http-client/src/main/java/com/loopers/core/infra/httpclient/pgsimulator/dto/PgSimulatorV1Dto.java
similarity index 86%
rename from core/infra/http-client/pg-simulator-client/src/main/java/com/loopers/core/infra/httpclient/pgsimulator/dto/PgSimulatorV1Dto.java
rename to core/infra/http-client/src/main/java/com/loopers/core/infra/httpclient/pgsimulator/dto/PgSimulatorV1Dto.java
index 605200f60..d702dce5f 100644
--- a/core/infra/http-client/pg-simulator-client/src/main/java/com/loopers/core/infra/httpclient/pgsimulator/dto/PgSimulatorV1Dto.java
+++ b/core/infra/http-client/src/main/java/com/loopers/core/infra/httpclient/pgsimulator/dto/PgSimulatorV1Dto.java
@@ -2,7 +2,7 @@
 
 import com.loopers.core.domain.payment.Payment;
 import com.loopers.core.domain.payment.PgPayment;
-import com.loopers.core.domain.payment.type.PaymentStatus;
+import com.loopers.core.domain.payment.type.PgPaymentStatus;
 import com.loopers.core.domain.payment.vo.FailedReason;
 import com.loopers.core.domain.payment.vo.TransactionKey;
 
@@ -40,10 +40,10 @@ public record Data(
                 String reason
         ) {
             public PgPayment to() {
-                return new PgPayment(
+                return PgPayment.create(
                         new TransactionKey(this.transactionKey),
-                        PaymentStatus.PENDING,
-                        FailedReason.empty()
+                        PgPaymentStatus.valueOf(status),
+                        new FailedReason(reason)
                 );
             }
         }
diff --git a/core/infra/http-client/pg-simulator-client/src/main/java/com/loopers/core/infra/httpclient/pgsimulator/impl/PgClientImpl.java b/core/infra/http-client/src/main/java/com/loopers/core/infra/httpclient/pgsimulator/impl/PgClientImpl.java
similarity index 87%
rename from core/infra/http-client/pg-simulator-client/src/main/java/com/loopers/core/infra/httpclient/pgsimulator/impl/PgClientImpl.java
rename to core/infra/http-client/src/main/java/com/loopers/core/infra/httpclient/pgsimulator/impl/PgClientImpl.java
index 907d2ab45..553e12370 100644
--- a/core/infra/http-client/pg-simulator-client/src/main/java/com/loopers/core/infra/httpclient/pgsimulator/impl/PgClientImpl.java
+++ b/core/infra/http-client/src/main/java/com/loopers/core/infra/httpclient/pgsimulator/impl/PgClientImpl.java
@@ -3,7 +3,7 @@
 import com.loopers.core.domain.payment.Payment;
 import com.loopers.core.domain.payment.PgClient;
 import com.loopers.core.domain.payment.PgPayment;
-import com.loopers.core.domain.payment.type.PaymentStatus;
+import com.loopers.core.domain.payment.type.PgPaymentStatus;
 import com.loopers.core.domain.payment.vo.FailedReason;
 import com.loopers.core.domain.payment.vo.TransactionKey;
 import com.loopers.core.infra.httpclient.pgsimulator.PgSimulatorClient;
@@ -32,6 +32,6 @@ public PgPayment pay(Payment payment, String callbackUrl) {
     }
 
     public PgPayment fallback(Payment payment, String callbackUrl, Throwable throwable) {
-        return new PgPayment(TransactionKey.empty(), PaymentStatus.NO_RESPONSE, new FailedReason(throwable.getMessage()));
+        return PgPayment.create(TransactionKey.empty(), PgPaymentStatus.NO_RESPONSE, new FailedReason(throwable.getMessage()));
     }
 }
diff --git a/core/service/order-service/build.gradle.kts b/core/service/build.gradle.kts
similarity index 54%
rename from core/service/order-service/build.gradle.kts
rename to core/service/build.gradle.kts
index bc68ffc56..e1c818ce0 100644
--- a/core/service/order-service/build.gradle.kts
+++ b/core/service/build.gradle.kts
@@ -5,10 +5,13 @@ dependencies {
     implementation("org.springframework.boot:spring-boot-starter")
     implementation("org.springframework:spring-tx")
     // mysql
-    runtimeOnly(project(":core:infra:database:mysql:product-mysql"))
-    runtimeOnly(project(":core:infra:database:mysql:user-mysql"))
-    runtimeOnly(project(":core:infra:database:mysql:order-mysql"))
+    runtimeOnly(project(":core:infra:database:mysql"))
+    runtimeOnly(project(":core:infra:database:redis"))
+    runtimeOnly(project(":core:infra:http-client"))
 
-    testImplementation(testFixtures(project(":core:infra:database:mysql:mysql-core")))
+    implementation(project(":supports:jackson"))
+
+    testImplementation(testFixtures(project(":core:domain")))
+    testImplementation(testFixtures(project(":core:infra:database:mysql")))
     testImplementation(project(":core:infra:database:mysql:mysql-config"))
 }
diff --git a/core/service/order-service/src/test/java/com/loopers/OrderServiceTestApplication.java b/core/service/order-service/src/test/java/com/loopers/OrderServiceTestApplication.java
deleted file mode 100644
index 3890a8bb9..000000000
--- a/core/service/order-service/src/test/java/com/loopers/OrderServiceTestApplication.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.loopers;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-
-@SpringBootApplication
-public class OrderServiceTestApplication {
-    public static void main(String[] args) {
-        SpringApplication.run(OrderServiceTestApplication.class, args);
-    }
-}
diff --git a/core/service/order-service/src/test/java/com/loopers/core/service/ConcurrencyTestUtil.java b/core/service/order-service/src/test/java/com/loopers/core/service/ConcurrencyTestUtil.java
deleted file mode 100644
index 716207078..000000000
--- a/core/service/order-service/src/test/java/com/loopers/core/service/ConcurrencyTestUtil.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.loopers.core.service;
-
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.List;
-import java.util.concurrent.*;
-import java.util.function.Consumer;
-import java.util.function.Function;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-@Slf4j
-public final class ConcurrencyTestUtil {
-
-    private ConcurrencyTestUtil() {
-        throw new UnsupportedOperationException("이 클래스의 인스턴스는 생성될 수 없습니다.");
-    }
-
-    public static <T> List<T> executeInParallel(
-            int threadCount,
-            Function<Integer, T> task) throws InterruptedException {
-
-        CountDownLatch latch = new CountDownLatch(threadCount);
-        CopyOnWriteArrayList<T> results = new CopyOnWriteArrayList<>();
-
-        try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
-            for (int i = 0; i < threadCount; i++) {
-                final int index = i;
-                executor.submit(() -> {
-                    try {
-                        T result = task.apply(index);
-                        results.add(result);
-                    } catch (Exception e) {
-                        System.out.println(e.getMessage() + e.getClass().getName());
-                    } finally {
-                        latch.countDown();
-                    }
-                });
-            }
-        }
-
-        boolean completed = latch.await(30, TimeUnit.SECONDS);
-        assertThat(completed).isTrue();
-
-        return results;
-    }
-
-    public static void executeInParallelWithoutResult(
-            int threadCount,
-            Consumer<Integer> task) throws InterruptedException {
-
-        CountDownLatch latch = new CountDownLatch(threadCount);
-
-        try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
-            for (int i = 0; i < threadCount; i++) {
-                final int index = i;
-                executor.submit(() -> {
-                    try {
-                        task.accept(index);
-                    } finally {
-                        latch.countDown();
-                    }
-                });
-            }
-        }
-
-        boolean completed = latch.await(30, TimeUnit.SECONDS);
-        assertThat(completed).isTrue();
-    }
-}
diff --git a/core/service/order-service/src/test/resources/application-test.yml b/core/service/order-service/src/test/resources/application-test.yml
deleted file mode 100644
index 34f9eeeb0..000000000
--- a/core/service/order-service/src/test/resources/application-test.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-spring:
-  jpa:
-    hibernate:
-      ddl-auto: create-drop
diff --git a/core/service/payment-service/build.gradle.kts b/core/service/payment-service/build.gradle.kts
deleted file mode 100644
index 1d9f60c9c..000000000
--- a/core/service/payment-service/build.gradle.kts
+++ /dev/null
@@ -1,15 +0,0 @@
-dependencies {
-    implementation(project(":core:domain"))
-
-    // spring
-    implementation("org.springframework.boot:spring-boot-starter")
-    implementation("org.springframework:spring-tx")
-    // mysql
-    runtimeOnly(project(":core:infra:database:mysql:product-mysql"))
-    runtimeOnly(project(":core:infra:database:mysql:user-mysql"))
-    runtimeOnly(project(":core:infra:database:mysql:order-mysql"))
-    runtimeOnly(project(":core:infra:http-client:pg-simulator-client"))
-
-    testImplementation(testFixtures(project(":core:infra:database:mysql:mysql-core")))
-    testImplementation(project(":core:infra:database:mysql:mysql-config"))
-}
diff --git a/core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/DuplicateSuccessPaymentStrategy.java b/core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/DuplicateSuccessPaymentStrategy.java
deleted file mode 100644
index 8fa8040a9..000000000
--- a/core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/DuplicateSuccessPaymentStrategy.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.loopers.core.service.payment.component;
-
-import com.loopers.core.domain.payment.Payment;
-import com.loopers.core.domain.payment.vo.FailedReason;
-import org.springframework.stereotype.Component;
-
-@Component
-public class DuplicateSuccessPaymentStrategy implements PaymentCallbackStrategy {
-
-    @Override
-    public Payment pay(Payment payment, FailedReason failedReason) {
-        return payment.fail(
-                new FailedReason("이미 결제에 성공한 이력이 있는 주문입니다.")
-        );
-    }
-}
diff --git a/core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/FailedPaymentStrategy.java b/core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/FailedPaymentStrategy.java
deleted file mode 100644
index 338c969bb..000000000
--- a/core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/FailedPaymentStrategy.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.loopers.core.service.payment.component;
-
-import com.loopers.core.domain.order.Order;
-import com.loopers.core.domain.order.OrderItem;
-import com.loopers.core.domain.order.repository.OrderItemRepository;
-import com.loopers.core.domain.order.repository.OrderRepository;
-import com.loopers.core.domain.payment.Payment;
-import com.loopers.core.domain.payment.vo.FailedReason;
-import com.loopers.core.domain.product.Product;
-import com.loopers.core.domain.product.repository.ProductRepository;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Component;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.List;
-
-@Component
-@RequiredArgsConstructor
-public class FailedPaymentStrategy implements PaymentCallbackStrategy {
-
-    private final OrderRepository orderRepository;
-    private final OrderItemRepository orderItemRepository;
-    private final ProductRepository productRepository;
-
-    @Override
-    @Transactional
-    public Payment pay(Payment payment, FailedReason failedReason) {
-        Order order = orderRepository.getBy(payment.getOrderKey());
-        List<OrderItem> orderItems = orderItemRepository.findAllByOrderId(order.getId());
-
-        List<Product> products = orderItems.stream()
-                .map(orderItem -> {
-                    Product product = productRepository.getByIdWithLock(orderItem.getProductId());
-
-                    return product.increaseStock(orderItem.getQuantity());
-                }).toList();
-        productRepository.saveAll(products);
-
-        return payment.fail(failedReason);
-    }
-}
diff --git a/core/service/payment-service/src/test/java/com/loopers/PaymentServiceTestApplication.java b/core/service/payment-service/src/test/java/com/loopers/PaymentServiceTestApplication.java
deleted file mode 100644
index d5a953a7b..000000000
--- a/core/service/payment-service/src/test/java/com/loopers/PaymentServiceTestApplication.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.loopers;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-
-@SpringBootApplication
-public class PaymentServiceTestApplication {
-    public static void main(String[] args) {
-        SpringApplication.run(PaymentServiceTestApplication.class, args);
-    }
-}
diff --git a/core/service/payment-service/src/test/java/com/loopers/core/service/ConcurrencyTestUtil.java b/core/service/payment-service/src/test/java/com/loopers/core/service/ConcurrencyTestUtil.java
deleted file mode 100644
index 716207078..000000000
--- a/core/service/payment-service/src/test/java/com/loopers/core/service/ConcurrencyTestUtil.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.loopers.core.service;
-
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.List;
-import java.util.concurrent.*;
-import java.util.function.Consumer;
-import java.util.function.Function;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-@Slf4j
-public final class ConcurrencyTestUtil {
-
-    private ConcurrencyTestUtil() {
-        throw new UnsupportedOperationException("이 클래스의 인스턴스는 생성될 수 없습니다.");
-    }
-
-    public static <T> List<T> executeInParallel(
-            int threadCount,
-            Function<Integer, T> task) throws InterruptedException {
-
-        CountDownLatch latch = new CountDownLatch(threadCount);
-        CopyOnWriteArrayList<T> results = new CopyOnWriteArrayList<>();
-
-        try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
-            for (int i = 0; i < threadCount; i++) {
-                final int index = i;
-                executor.submit(() -> {
-                    try {
-                        T result = task.apply(index);
-                        results.add(result);
-                    } catch (Exception e) {
-                        System.out.println(e.getMessage() + e.getClass().getName());
-                    } finally {
-                        latch.countDown();
-                    }
-                });
-            }
-        }
-
-        boolean completed = latch.await(30, TimeUnit.SECONDS);
-        assertThat(completed).isTrue();
-
-        return results;
-    }
-
-    public static void executeInParallelWithoutResult(
-            int threadCount,
-            Consumer<Integer> task) throws InterruptedException {
-
-        CountDownLatch latch = new CountDownLatch(threadCount);
-
-        try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
-            for (int i = 0; i < threadCount; i++) {
-                final int index = i;
-                executor.submit(() -> {
-                    try {
-                        task.accept(index);
-                    } finally {
-                        latch.countDown();
-                    }
-                });
-            }
-        }
-
-        boolean completed = latch.await(30, TimeUnit.SECONDS);
-        assertThat(completed).isTrue();
-    }
-}
diff --git a/core/service/payment-service/src/test/java/com/loopers/core/service/IntegrationTest.java b/core/service/payment-service/src/test/java/com/loopers/core/service/IntegrationTest.java
deleted file mode 100644
index 56ee3dd13..000000000
--- a/core/service/payment-service/src/test/java/com/loopers/core/service/IntegrationTest.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.loopers.core.service;
-
-import com.loopers.core.infra.mysql.testcontainers.MySqlTestContainersExtension;
-import com.loopers.core.infra.mysql.util.DatabaseCleanUp;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-
-@SpringBootTest
-@ExtendWith(MySqlTestContainersExtension.class)
-public class IntegrationTest {
-
-    @Autowired
-    private DatabaseCleanUp databaseCleanUp;
-
-    @AfterEach
-    void databaseCleanUp() {
-        databaseCleanUp.truncateAllTables();
-    }
-}
diff --git a/core/service/payment-service/src/test/java/com/loopers/core/service/payment/PaymentServiceIntegrationTest.java b/core/service/payment-service/src/test/java/com/loopers/core/service/payment/PaymentServiceIntegrationTest.java
deleted file mode 100644
index c1fbce5b7..000000000
--- a/core/service/payment-service/src/test/java/com/loopers/core/service/payment/PaymentServiceIntegrationTest.java
+++ /dev/null
@@ -1,166 +0,0 @@
-package com.loopers.core.service.payment;
-
-import com.loopers.core.domain.brand.vo.BrandId;
-import com.loopers.core.domain.common.vo.CreatedAt;
-import com.loopers.core.domain.common.vo.DeletedAt;
-import com.loopers.core.domain.common.vo.UpdatedAt;
-import com.loopers.core.domain.order.Order;
-import com.loopers.core.domain.order.OrderItem;
-import com.loopers.core.domain.order.repository.OrderItemRepository;
-import com.loopers.core.domain.order.repository.OrderRepository;
-import com.loopers.core.domain.order.vo.OrderId;
-import com.loopers.core.domain.order.vo.OrderItemId;
-import com.loopers.core.domain.order.vo.Quantity;
-import com.loopers.core.domain.payment.Payment;
-import com.loopers.core.domain.payment.PgClient;
-import com.loopers.core.domain.payment.PgPayment;
-import com.loopers.core.domain.payment.repository.PaymentRepository;
-import com.loopers.core.domain.payment.type.PaymentStatus;
-import com.loopers.core.domain.payment.vo.FailedReason;
-import com.loopers.core.domain.payment.vo.TransactionKey;
-import com.loopers.core.domain.product.Product;
-import com.loopers.core.domain.product.repository.ProductRepository;
-import com.loopers.core.domain.product.vo.*;
-import com.loopers.core.domain.user.User;
-import com.loopers.core.domain.user.repository.UserRepository;
-import com.loopers.core.domain.user.vo.UserEmail;
-import com.loopers.core.domain.user.vo.UserId;
-import com.loopers.core.domain.user.vo.UserIdentifier;
-import com.loopers.core.service.ConcurrencyTestUtil;
-import com.loopers.core.service.IntegrationTest;
-import com.loopers.core.service.payment.command.PaymentCommand;
-import org.instancio.Instancio;
-import org.junit.jupiter.api.BeforeEach;
-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.test.context.bean.override.mockito.MockitoBean;
-
-import java.math.BigDecimal;
-import java.util.List;
-
-import static org.assertj.core.api.SoftAssertions.assertSoftly;
-import static org.instancio.Select.field;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.when;
-
-@DisplayName("결제 서비스")
-class PaymentServiceIntegrationTest extends IntegrationTest {
-
-    @Autowired
-    private PaymentService paymentService;
-
-    @Autowired
-    private OrderRepository orderRepository;
-
-    @Autowired
-    private OrderItemRepository orderItemRepository;
-
-    @Autowired
-    private ProductRepository productRepository;
-
-    @Autowired
-    private UserRepository userRepository;
-
-    @Autowired
-    private PaymentRepository paymentRepository;
-
-    @MockitoBean
-    private PgClient pgClient;
-
-    @Nested
-    @DisplayName("pay() 메서드")
-    class PayMethod {
-
-        @Nested
-        @DisplayName("동시에 같은 주문에 대해 결제 요청을 하면")
-        class 동시_결제_요청 {
-
-            private Order order;
-            private User user;
-            private Product product;
-            private PaymentCommand paymentCommand;
-
-            @BeforeEach
-            void setUp() {
-                // 사용자 생성
-                user = userRepository.save(
-                        Instancio.of(User.class)
-                                .set(field(User::getId), UserId.empty())
-                                .set(field(User::getIdentifier), UserIdentifier.create("user123"))
-                                .set(field(User::getEmail), new UserEmail("user@example.com"))
-                                .create()
-                );
-
-                // 상품 생성 (가격: 10,000, 재고: 100개)
-                product = productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getBrandId), new BrandId("1"))
-                                .set(field(Product::getName), new ProductName("MacBook Pro"))
-                                .set(field(Product::getPrice), new ProductPrice(new BigDecimal("1500000")))
-                                .set(field(Product::getStock), new ProductStock(100_000L))
-                                .set(field(Product::getLikeCount), ProductLikeCount.init())
-                                .create()
-                );
-
-                // 주문 생성
-                order = orderRepository.save(
-                        Instancio.of(Order.class)
-                                .set(field(Order::getId), OrderId.empty())
-                                .set(field(Order::getUserId), user.getId())
-                                .set(field(Order::getCreatedAt), CreatedAt.now())
-                                .set(field(Order::getUpdatedAt), UpdatedAt.now())
-                                .set(field(Order::getDeletedAt), DeletedAt.empty())
-                                .create()
-                );
-
-                // 주문 상품 생성
-                orderItemRepository.save(
-                        Instancio.of(OrderItem.class)
-                                .set(field(OrderItem::getId), OrderItemId.empty())
-                                .set(field(OrderItem::getOrderId), order.getId())
-                                .set(field(OrderItem::getProductId), product.getId())
-                                .set(field(OrderItem::getQuantity), new Quantity(1L))
-                                .create()
-                );
-
-                // 결제 명령 생성
-                paymentCommand = new PaymentCommand(
-                        order.getId().value(),
-                        user.getIdentifier().value(),
-                        "CREDIT",
-                        "1234567890123456",
-                        null
-                );
-
-                // PG 클라이언트 Mock 설정
-                when(pgClient.pay(any(Payment.class), anyString()))
-                        .thenReturn(new PgPayment(new TransactionKey("TXN_" + System.nanoTime()), PaymentStatus.PENDING, FailedReason.empty()));
-            }
-
-            @Test
-            @DisplayName("하나의 결제만 생성된다")
-            void 하나의_결제만_생성된다() throws InterruptedException {
-                // when - 동시에 20개의 결제 요청 실행
-                List<Payment> results = ConcurrencyTestUtil.executeInParallel(
-                        20,
-                        index -> paymentService.pay(paymentCommand)
-                );
-
-                // then - 성공한 결제 1개만 반환되어야 함
-                assertSoftly(softly -> {
-                    softly.assertThat(results)
-                            .as("성공한 결제 개수")
-                            .hasSize(1);
-                    boolean paymentExists = paymentRepository.findBy(order.getOrderKey(), PaymentStatus.PENDING).isPresent();
-                    softly.assertThat(paymentExists)
-                            .as("주문의 결제 상태 존재")
-                            .isTrue();
-                });
-            }
-        }
-    }
-}
diff --git a/core/service/payment-service/src/test/java/com/loopers/core/service/payment/PaymentServiceTest.java b/core/service/payment-service/src/test/java/com/loopers/core/service/payment/PaymentServiceTest.java
deleted file mode 100644
index a75dbc9fe..000000000
--- a/core/service/payment-service/src/test/java/com/loopers/core/service/payment/PaymentServiceTest.java
+++ /dev/null
@@ -1,213 +0,0 @@
-package com.loopers.core.service.payment;
-
-import com.loopers.core.domain.order.Order;
-import com.loopers.core.domain.order.OrderItem;
-import com.loopers.core.domain.order.repository.OrderItemRepository;
-import com.loopers.core.domain.order.repository.OrderRepository;
-import com.loopers.core.domain.payment.Payment;
-import com.loopers.core.domain.payment.PgClient;
-import com.loopers.core.domain.payment.PgPayment;
-import com.loopers.core.domain.payment.repository.PaymentRepository;
-import com.loopers.core.domain.payment.type.PaymentStatus;
-import com.loopers.core.domain.payment.vo.FailedReason;
-import com.loopers.core.domain.payment.vo.PayAmount;
-import com.loopers.core.domain.payment.vo.TransactionKey;
-import com.loopers.core.domain.user.User;
-import com.loopers.core.domain.user.repository.UserRepository;
-import com.loopers.core.domain.user.vo.UserIdentifier;
-import com.loopers.core.service.payment.command.PaymentCommand;
-import com.loopers.core.service.payment.component.OrderLineAggregator;
-import com.loopers.core.service.payment.component.PayAmountDiscountStrategy;
-import com.loopers.core.service.payment.component.PayAmountDiscountStrategySelector;
-import org.instancio.Instancio;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-import org.springframework.test.util.ReflectionTestUtils;
-
-import java.util.List;
-import java.util.Optional;
-
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.assertj.core.api.SoftAssertions.assertSoftly;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-@DisplayName("결제 서비스")
-@ExtendWith(MockitoExtension.class)
-class PaymentServiceTest {
-
-    @Mock
-    private UserRepository userRepository;
-
-    @Mock
-    private PaymentRepository paymentRepository;
-
-    @Mock
-    private OrderRepository orderRepository;
-
-    @Mock
-    private OrderItemRepository orderItemRepository;
-
-    @Mock
-    private OrderLineAggregator orderLineAggregator;
-
-    @Mock
-    private PayAmountDiscountStrategySelector discountStrategySelector;
-
-    @Mock
-    private PgClient pgClient;
-
-    @InjectMocks
-    private PaymentService paymentService;
-
-    @Nested
-    @DisplayName("pay() 메서드의 검증 로직")
-    class PayValidation {
-
-        @BeforeEach
-        void setUp() {
-            // @Value 주입 대신 ReflectionTestUtils로 설정
-            ReflectionTestUtils.setField(paymentService, "callbackUrl", "http://localhost:8080/callback");
-        }
-
-        @Nested
-        @DisplayName("이미 결제에 성공한 이력이 있으면")
-        class 이미_결제_성공_이력이_있는_경우 {
-
-            @Test
-            @DisplayName("예외를 발생시킨다")
-            void 예외_발생() {
-                // given
-                User user = Instancio.create(User.class);
-                Order order = Instancio.create(Order.class);
-                PaymentCommand command = new PaymentCommand(
-                        order.getId().value(),
-                        user.getIdentifier().value(),
-                        "CREDIT",
-                        "1234567890123456",
-                        null
-                );
-
-                when(userRepository.getByIdentifier(any(UserIdentifier.class)))
-                        .thenReturn(user);
-                when(orderRepository.getById(any()))
-                        .thenReturn(order);
-
-                // 이미 성공한 결제 존재
-                when(paymentRepository.findBy(order.getOrderKey(), PaymentStatus.SUCCESS))
-                        .thenReturn(Optional.of(Instancio.create(Payment.class)));
-
-                // when & then
-                assertThatThrownBy(() -> paymentService.pay(command))
-                        .isInstanceOf(IllegalStateException.class)
-                        .hasMessage("이미 결제에 성공한 이력이 있는 주문입니다.");
-            }
-        }
-
-        @Nested
-        @DisplayName("이미 결제가 진행 중이면")
-        class 이미_결제_진행_중인_경우 {
-
-            @Test
-            @DisplayName("예외를 발생시킨다")
-            void 예외_발생() {
-                // given
-                User user = Instancio.create(User.class);
-                Order order = Instancio.create(Order.class);
-                PaymentCommand command = new PaymentCommand(
-                        order.getId().value(),
-                        user.getIdentifier().value(),
-                        "CREDIT",
-                        "1234567890123456",
-                        null
-                );
-
-                when(userRepository.getByIdentifier(any(UserIdentifier.class)))
-                        .thenReturn(user);
-                when(orderRepository.getById(any()))
-                        .thenReturn(order);
-
-                // 성공한 결제는 없음
-                when(paymentRepository.findBy(order.getOrderKey(), PaymentStatus.SUCCESS))
-                        .thenReturn(Optional.empty());
-
-                // 진행 중인 결제 존재 (Lock 적용)
-                when(paymentRepository.findByWithLock(order.getOrderKey(), PaymentStatus.PENDING))
-                        .thenReturn(Optional.of(Instancio.create(Payment.class)));
-
-                // when & then
-                assertThatThrownBy(() -> paymentService.pay(command))
-                        .isInstanceOf(IllegalStateException.class)
-                        .hasMessage("이미 결제가 진행 중인 주문입니다.");
-            }
-        }
-
-        @Nested
-        @DisplayName("결제 가능한 상태이면")
-        class 결제_가능한_상태 {
-
-            @Test
-            @DisplayName("정상적으로 결제가 진행된다")
-            void 정상_결제_진행() {
-                // given
-                User user = Instancio.create(User.class);
-                Order order = Instancio.create(Order.class);
-                List<OrderItem> orderItems = Instancio.createList(OrderItem.class);
-                PayAmount payAmount = Instancio.create(PayAmount.class);
-                PaymentCommand command = new PaymentCommand(
-                        order.getId().value(),
-                        user.getIdentifier().value(),
-                        "CREDIT",
-                        "1234567890123456",
-                        null
-                );
-
-                when(userRepository.getByIdentifier(any(UserIdentifier.class)))
-                        .thenReturn(user);
-                when(orderRepository.getById(any()))
-                        .thenReturn(order);
-                when(orderItemRepository.findAllByOrderId(any()))
-                        .thenReturn(orderItems);
-
-                // 성공한 결제 없음
-                when(paymentRepository.findBy(order.getOrderKey(), PaymentStatus.SUCCESS))
-                        .thenReturn(Optional.empty());
-
-                // 진행 중인 결제 없음
-                when(paymentRepository.findByWithLock(order.getOrderKey(), PaymentStatus.PENDING))
-                        .thenReturn(Optional.empty());
-
-                // Discount Strategy Mock
-                PayAmountDiscountStrategy strategy = mock(PayAmountDiscountStrategy.class);
-                when(strategy.discount(any(), any()))
-                        .thenReturn(payAmount);
-                when(discountStrategySelector.select(any()))
-                        .thenReturn(strategy);
-
-                when(orderLineAggregator.aggregate(any()))
-                        .thenReturn(payAmount);
-                when(pgClient.pay(any(), anyString()))
-                        .thenReturn(new PgPayment(new TransactionKey("TXN_123"), PaymentStatus.PENDING, FailedReason.empty()));
-                when(paymentRepository.save(any()))
-                        .thenAnswer(invocation -> invocation.getArgument(0));
-
-                // when
-                Payment result = paymentService.pay(command);
-
-                // then
-                assertSoftly(softly -> {
-                    softly.assertThat(result).isNotNull();
-                    softly.assertThat(result.getStatus()).isEqualTo(PaymentStatus.PENDING);
-                });
-            }
-        }
-    }
-}
diff --git a/core/service/payment-service/src/test/java/com/loopers/core/service/payment/PgCallbackServiceTest.java b/core/service/payment-service/src/test/java/com/loopers/core/service/payment/PgCallbackServiceTest.java
deleted file mode 100644
index d8b7d5f9d..000000000
--- a/core/service/payment-service/src/test/java/com/loopers/core/service/payment/PgCallbackServiceTest.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.loopers.core.service.payment;
-
-import com.loopers.core.service.IntegrationTest;
-
-class PgCallbackServiceTest extends IntegrationTest {
-
-}
diff --git a/core/service/payment-service/src/test/java/com/loopers/core/service/payment/component/FailedPaymentStrategyIntegrationTest.java b/core/service/payment-service/src/test/java/com/loopers/core/service/payment/component/FailedPaymentStrategyIntegrationTest.java
deleted file mode 100644
index c62577773..000000000
--- a/core/service/payment-service/src/test/java/com/loopers/core/service/payment/component/FailedPaymentStrategyIntegrationTest.java
+++ /dev/null
@@ -1,474 +0,0 @@
-package com.loopers.core.service.payment.component;
-
-import com.loopers.core.domain.brand.vo.BrandId;
-import com.loopers.core.domain.common.vo.CreatedAt;
-import com.loopers.core.domain.common.vo.DeletedAt;
-import com.loopers.core.domain.common.vo.UpdatedAt;
-import com.loopers.core.domain.order.Order;
-import com.loopers.core.domain.order.OrderItem;
-import com.loopers.core.domain.order.repository.OrderItemRepository;
-import com.loopers.core.domain.order.repository.OrderRepository;
-import com.loopers.core.domain.order.vo.OrderId;
-import com.loopers.core.domain.order.vo.OrderItemId;
-import com.loopers.core.domain.order.vo.Quantity;
-import com.loopers.core.domain.payment.Payment;
-import com.loopers.core.domain.payment.type.PaymentStatus;
-import com.loopers.core.domain.payment.vo.FailedReason;
-import com.loopers.core.domain.product.Product;
-import com.loopers.core.domain.product.repository.ProductRepository;
-import com.loopers.core.domain.product.vo.*;
-import com.loopers.core.domain.user.User;
-import com.loopers.core.domain.user.repository.UserRepository;
-import com.loopers.core.domain.user.vo.UserEmail;
-import com.loopers.core.domain.user.vo.UserId;
-import com.loopers.core.domain.user.vo.UserIdentifier;
-import com.loopers.core.service.ConcurrencyTestUtil;
-import com.loopers.core.service.IntegrationTest;
-import org.instancio.Instancio;
-import org.junit.jupiter.api.BeforeEach;
-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 java.math.BigDecimal;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.SoftAssertions.assertSoftly;
-import static org.instancio.Select.field;
-
-@DisplayName("결제 실패 전략 통합 테스트")
-class FailedPaymentStrategyIntegrationTest extends IntegrationTest {
-
-    @Autowired
-    private FailedPaymentStrategy failedPaymentStrategy;
-
-    @Autowired
-    private OrderRepository orderRepository;
-
-    @Autowired
-    private OrderItemRepository orderItemRepository;
-
-    @Autowired
-    private ProductRepository productRepository;
-
-    @Autowired
-    private UserRepository userRepository;
-
-    private User testUser;
-    private Order testOrder;
-    private Product testProduct;
-
-    @BeforeEach
-    void setUp() {
-        // 사용자 생성
-        testUser = userRepository.save(
-                Instancio.of(User.class)
-                        .set(field(User::getId), UserId.empty())
-                        .set(field(User::getIdentifier), UserIdentifier.create("testuser"))
-                        .set(field(User::getEmail), new UserEmail("test@example.com"))
-                        .create()
-        );
-
-        // 상품 생성 (가격: 10,000, 재고: 1,000개)
-        testProduct = productRepository.save(
-                Instancio.of(Product.class)
-                        .set(field(Product::getId), ProductId.empty())
-                        .set(field(Product::getBrandId), new BrandId("1"))
-                        .set(field(Product::getName), new ProductName("테스트 상품"))
-                        .set(field(Product::getPrice), new ProductPrice(new BigDecimal("10000")))
-                        .set(field(Product::getStock), new ProductStock(1000L))
-                        .set(field(Product::getLikeCount), ProductLikeCount.init())
-                        .create()
-        );
-
-        // 주문 생성
-        testOrder = orderRepository.save(
-                Instancio.of(Order.class)
-                        .set(field(Order::getId), OrderId.empty())
-                        .set(field(Order::getUserId), testUser.getId())
-                        .set(field(Order::getCreatedAt), CreatedAt.now())
-                        .set(field(Order::getUpdatedAt), UpdatedAt.now())
-                        .set(field(Order::getDeletedAt), DeletedAt.empty())
-                        .create()
-        );
-
-        // 주문 상품 생성 (10개 구매)
-        orderItemRepository.save(
-                Instancio.of(OrderItem.class)
-                        .set(field(OrderItem::getId), OrderItemId.empty())
-                        .set(field(OrderItem::getOrderId), testOrder.getId())
-                        .set(field(OrderItem::getProductId), testProduct.getId())
-                        .set(field(OrderItem::getQuantity), new Quantity(10L))
-                        .create()
-        );
-    }
-
-    @Nested
-    @DisplayName("pay 메서드 - 결제 실패 시 재고 복구")
-    class PayMethod {
-
-        @Test
-        @DisplayName("결제 실패 시 차감된 재고를 다시 증가시킨다")
-        void shouldIncreaseStockWhenPaymentFails() {
-            // Given
-            long initialStock = testProduct.getStock().value();
-            FailedReason failedReason = new FailedReason("결제 게이트웨이 오류");
-
-            // 먼저 재고를 차감한 상태로 시뮬레이션 (실제로는 성공한 결제 후 실패)
-            Product decreasedProduct = testProduct.decreaseStock(new Quantity(10L));
-            productRepository.save(decreasedProduct);
-
-            Payment payment = Payment.create(
-                    testOrder.getOrderKey(),
-                    testUser.getId(),
-                    null,
-                    null,
-                    null
-            );
-
-            // When
-            Payment result = failedPaymentStrategy.pay(payment, failedReason);
-
-            // Then
-            Product restoredProduct = productRepository.findById(testProduct.getId()).orElseThrow();
-            assertSoftly(softly -> {
-                softly.assertThat(result.getStatus())
-                        .as("결제 상태가 FAILED로 변경되어야 함")
-                        .isEqualTo(PaymentStatus.FAILED);
-                softly.assertThat(result.getFailedReason().value())
-                        .as("실패 이유가 저장되어야 함")
-                        .isEqualTo("결제 게이트웨이 오류");
-                softly.assertThat(restoredProduct.getStock().value())
-                        .as("재고가 원래 상태로 복구되어야 함")
-                        .isEqualTo(initialStock);
-            });
-        }
-
-        @Test
-        @DisplayName("여러 상품의 재고를 모두 정확하게 복구한다")
-        void shouldRestoreStockForMultipleItems() {
-            // Given
-            Product product2 = productRepository.save(
-                    Instancio.of(Product.class)
-                            .set(field(Product::getId), ProductId.empty())
-                            .set(field(Product::getBrandId), new BrandId("2"))
-                            .set(field(Product::getName), new ProductName("테스트 상품 2"))
-                            .set(field(Product::getPrice), new ProductPrice(new BigDecimal("20000")))
-                            .set(field(Product::getStock), new ProductStock(500L))
-                            .set(field(Product::getLikeCount), ProductLikeCount.init())
-                            .create()
-            );
-
-            // 두 번째 상품도 주문에 추가 (20개 구매)
-            orderItemRepository.save(
-                    Instancio.of(OrderItem.class)
-                            .set(field(OrderItem::getId), OrderItemId.empty())
-                            .set(field(OrderItem::getOrderId), testOrder.getId())
-                            .set(field(OrderItem::getProductId), product2.getId())
-                            .set(field(OrderItem::getQuantity), new Quantity(20L))
-                            .create()
-            );
-
-            long product1InitialStock = testProduct.getStock().value();
-            long product2InitialStock = product2.getStock().value();
-
-            // 둘 다 재고 차감 상태로 시뮬레이션
-            Product decreasedProduct1 = testProduct.decreaseStock(new Quantity(10L));
-            Product decreasedProduct2 = product2.decreaseStock(new Quantity(20L));
-            productRepository.saveAll(java.util.List.of(decreasedProduct1, decreasedProduct2));
-
-            Payment payment = Payment.create(
-                    testOrder.getOrderKey(),
-                    testUser.getId(),
-                    null,
-                    null,
-                    null
-            );
-            FailedReason failedReason = new FailedReason("결제 처리 중 오류 발생");
-
-            // When
-            Payment result = failedPaymentStrategy.pay(payment, failedReason);
-
-            // Then
-            Product restoredProduct1 = productRepository.findById(testProduct.getId()).orElseThrow();
-            Product restoredProduct2 = productRepository.findById(product2.getId()).orElseThrow();
-
-            assertSoftly(softly -> {
-                softly.assertThat(result.getStatus())
-                        .as("결제 상태가 FAILED로 변경되어야 함")
-                        .isEqualTo(PaymentStatus.FAILED);
-                softly.assertThat(restoredProduct1.getStock().value())
-                        .as("첫 번째 상품 재고가 원래대로 복구되어야 함")
-                        .isEqualTo(product1InitialStock);
-                softly.assertThat(restoredProduct2.getStock().value())
-                        .as("두 번째 상품 재고가 원래대로 복구되어야 함")
-                        .isEqualTo(product2InitialStock);
-            });
-        }
-
-        @Test
-        @DisplayName("결제 실패 시 올바른 실패 이유를 반환한다")
-        void shouldReturnCorrectFailedReasonInPayment() {
-            // Given
-            String expectedReason = "신용카드 한도 초과";
-            FailedReason failedReason = new FailedReason(expectedReason);
-
-            Product decreasedProduct = testProduct.decreaseStock(new Quantity(10L));
-            productRepository.save(decreasedProduct);
-
-            Payment payment = Payment.create(
-                    testOrder.getOrderKey(),
-                    testUser.getId(),
-                    null,
-                    null,
-                    null
-            );
-
-            // When
-            Payment result = failedPaymentStrategy.pay(payment, failedReason);
-
-            // Then
-            assertThat(result.getFailedReason().value())
-                    .as("결제 객체에 올바른 실패 이유가 저장되어야 함")
-                    .isEqualTo(expectedReason);
-        }
-    }
-
-    @Nested
-    @DisplayName("동시성 제어 - 동시 결제 실패 시 재고 복구 검증")
-    class ConcurrencyControl {
-
-        @Test
-        @DisplayName("같은 상품에 대해 동시에 여러 결제가 실패할 때 재고 복구 일관성을 보장한다")
-        void shouldMaintainStockConsistencyUnderConcurrentFailedPayments() throws InterruptedException {
-            // Given
-            long initialStock = testProduct.getStock().value();
-            int concurrentFailedPaymentCount = 5;
-            int stockPerPayment = 10;
-
-            // 동시 결제 실패를 위한 주문들 생성
-            java.util.List<Order> concurrentOrders = new java.util.ArrayList<>();
-
-            for (int i = 0; i < concurrentFailedPaymentCount; i++) {
-                Order order = orderRepository.save(
-                        Instancio.of(Order.class)
-                                .set(field(Order::getId), OrderId.empty())
-                                .set(field(Order::getUserId), testUser.getId())
-                                .set(field(Order::getCreatedAt), CreatedAt.now())
-                                .set(field(Order::getUpdatedAt), UpdatedAt.now())
-                                .set(field(Order::getDeletedAt), DeletedAt.empty())
-                                .create()
-                );
-                orderItemRepository.save(
-                        Instancio.of(OrderItem.class)
-                                .set(field(OrderItem::getId), OrderItemId.empty())
-                                .set(field(OrderItem::getOrderId), order.getId())
-                                .set(field(OrderItem::getProductId), testProduct.getId())
-                                .set(field(OrderItem::getQuantity), new Quantity((long) stockPerPayment))
-                                .create()
-                );
-                concurrentOrders.add(order);
-            }
-
-            // 총 재고 차감 (5개 * 10 = 50)
-            Product decreasedProduct = testProduct.decreaseStock(new Quantity((long) (concurrentFailedPaymentCount * stockPerPayment)));
-            productRepository.save(decreasedProduct);
-
-            // When - Virtual Thread를 사용한 병렬 결제 실패 처리
-            ConcurrencyTestUtil.executeInParallelWithoutResult(
-                    concurrentFailedPaymentCount,
-                    index -> {
-                        Order order = concurrentOrders.get(index);
-
-                        Payment payment = Payment.create(
-                                order.getOrderKey(),
-                                testUser.getId(),
-                                null,
-                                null,
-                                null
-                        );
-
-                        FailedReason failedReason = new FailedReason("결제 게이트웨이 오류 #" + index);
-                        failedPaymentStrategy.pay(payment, failedReason);
-                    }
-            );
-
-            // Then - 재고 일관성 검증 (모두 복구되어야 함)
-            Product finalProduct = productRepository.findById(testProduct.getId()).orElseThrow();
-            assertThat(finalProduct.getStock().value())
-                    .as("동시 결제 실패로 인한 재고 복구가 정확하게 이루어져야 함 (초기: %d, 현재: %d)",
-                            initialStock, finalProduct.getStock().value())
-                    .isEqualTo(initialStock);
-        }
-
-        @Test
-        @DisplayName("10개의 동시 결제 실패에서 재고 복구 일관성을 보장한다")
-        void shouldMaintainStockConsistencyWith10ConcurrentFailedPayments() throws InterruptedException {
-            // Given
-            long initialStock = testProduct.getStock().value();
-            int concurrentFailedPaymentCount = 10;
-            int stockPerPayment = 5;
-
-            // 각 동시 결제 실패를 위한 주문 준비
-            java.util.List<Order> concurrentOrders = new java.util.ArrayList<>();
-
-            for (int i = 0; i < concurrentFailedPaymentCount; i++) {
-                Order order = orderRepository.save(
-                        Instancio.of(Order.class)
-                                .set(field(Order::getId), OrderId.empty())
-                                .set(field(Order::getUserId), testUser.getId())
-                                .set(field(Order::getCreatedAt), CreatedAt.now())
-                                .set(field(Order::getUpdatedAt), UpdatedAt.now())
-                                .set(field(Order::getDeletedAt), DeletedAt.empty())
-                                .create()
-                );
-                orderItemRepository.save(
-                        Instancio.of(OrderItem.class)
-                                .set(field(OrderItem::getId), OrderItemId.empty())
-                                .set(field(OrderItem::getOrderId), order.getId())
-                                .set(field(OrderItem::getProductId), testProduct.getId())
-                                .set(field(OrderItem::getQuantity), new Quantity((long) stockPerPayment))
-                                .create()
-                );
-                concurrentOrders.add(order);
-            }
-
-            // 총 재고 차감 (10개 * 5 = 50)
-            Product decreasedProduct = testProduct.decreaseStock(new Quantity((long) (concurrentFailedPaymentCount * stockPerPayment)));
-            productRepository.save(decreasedProduct);
-
-            // When - 10개 스레드로 동시 결제 실패 처리
-            ConcurrencyTestUtil.executeInParallelWithoutResult(
-                    concurrentFailedPaymentCount,
-                    index -> {
-                        Order order = concurrentOrders.get(index);
-
-                        Payment payment = Payment.create(
-                                order.getOrderKey(),
-                                testUser.getId(),
-                                null,
-                                null,
-                                null
-                        );
-
-                        FailedReason failedReason = new FailedReason("결제 실패: " + index);
-                        failedPaymentStrategy.pay(payment, failedReason);
-                    }
-            );
-
-            // Then - 최종 재고 검증
-            Product finalProduct = productRepository.findById(testProduct.getId()).orElseThrow();
-            assertThat(finalProduct.getStock().value())
-                    .as("10개의 동시 결제 실패로 인한 재고 복구 일관성 (초기: %d, 현재: %d)",
-                            initialStock, finalProduct.getStock().value())
-                    .isEqualTo(initialStock);
-        }
-
-        @Test
-        @DisplayName("서로 다른 상품에 대한 동시 결제 실패에서 각 상품의 재고가 독립적으로 복구된다")
-        void shouldRestoreStockIndependentlyForDifferentProducts() throws InterruptedException {
-            // Given
-            Product product1 = testProduct;
-            Product product2 = productRepository.save(
-                    Instancio.of(Product.class)
-                            .set(field(Product::getId), ProductId.empty())
-                            .set(field(Product::getBrandId), new BrandId("2"))
-                            .set(field(Product::getName), new ProductName("테스트 상품 2"))
-                            .set(field(Product::getPrice), new ProductPrice(new BigDecimal("10000")))
-                            .set(field(Product::getStock), new ProductStock(1000L))
-                            .set(field(Product::getLikeCount), ProductLikeCount.init())
-                            .create()
-            );
-            Product product3 = productRepository.save(
-                    Instancio.of(Product.class)
-                            .set(field(Product::getId), ProductId.empty())
-                            .set(field(Product::getBrandId), new BrandId("3"))
-                            .set(field(Product::getName), new ProductName("테스트 상품 3"))
-                            .set(field(Product::getPrice), new ProductPrice(new BigDecimal("10000")))
-                            .set(field(Product::getStock), new ProductStock(1000L))
-                            .set(field(Product::getLikeCount), ProductLikeCount.init())
-                            .create()
-            );
-
-            long product1InitialStock = product1.getStock().value();
-            long product2InitialStock = product2.getStock().value();
-            long product3InitialStock = product3.getStock().value();
-
-            int concurrentFailedPaymentCount = 9; // 3개 상품 × 3개 결제씩
-            java.util.List<Order> concurrentOrders = new java.util.ArrayList<>();
-
-            // 각 상품별로 3개씩 주문 생성
-            for (int i = 0; i < concurrentFailedPaymentCount; i++) {
-                Product targetProduct = switch (i / 3) {
-                    case 0 -> product1;
-                    case 1 -> product2;
-                    default -> product3;
-                };
-
-                Order order = orderRepository.save(
-                        Instancio.of(Order.class)
-                                .set(field(Order::getId), OrderId.empty())
-                                .set(field(Order::getUserId), testUser.getId())
-                                .set(field(Order::getCreatedAt), CreatedAt.now())
-                                .set(field(Order::getUpdatedAt), UpdatedAt.now())
-                                .set(field(Order::getDeletedAt), DeletedAt.empty())
-                                .create()
-                );
-                orderItemRepository.save(
-                        Instancio.of(OrderItem.class)
-                                .set(field(OrderItem::getId), OrderItemId.empty())
-                                .set(field(OrderItem::getOrderId), order.getId())
-                                .set(field(OrderItem::getProductId), targetProduct.getId())
-                                .set(field(OrderItem::getQuantity), new Quantity(10L))
-                                .create()
-                );
-                concurrentOrders.add(order);
-            }
-
-            // 각 상품별로 재고 일괄 차감 (각 상품당 3개 * 10 = 30)
-            productRepository.save(product1.decreaseStock(new Quantity(30L)));
-            productRepository.save(product2.decreaseStock(new Quantity(30L)));
-            productRepository.save(product3.decreaseStock(new Quantity(30L)));
-
-            // When - 각 상품별로 3개씩 동시 결제 실패 처리
-            ConcurrencyTestUtil.executeInParallelWithoutResult(
-                    concurrentFailedPaymentCount,
-                    index -> {
-                        Order order = concurrentOrders.get(index);
-
-                        Payment payment = Payment.create(
-                                order.getOrderKey(),
-                                testUser.getId(),
-                                null,
-                                null,
-                                null
-                        );
-
-                        FailedReason failedReason = new FailedReason("결제 실패 #" + index);
-                        failedPaymentStrategy.pay(payment, failedReason);
-                    }
-            );
-
-            // Then - 각 상품의 재고가 독립적으로 정확하게 복구되었는지 검증
-            Product finalProduct1 = productRepository.findById(product1.getId()).orElseThrow();
-            Product finalProduct2 = productRepository.findById(product2.getId()).orElseThrow();
-            Product finalProduct3 = productRepository.findById(product3.getId()).orElseThrow();
-
-            assertSoftly(softly -> {
-                softly.assertThat(finalProduct1.getStock().value())
-                        .as("상품1: 3개 결제 실패로 30개 복구 (초기 %d → 현재 %d)",
-                                product1InitialStock, finalProduct1.getStock().value())
-                        .isEqualTo(product1InitialStock);
-                softly.assertThat(finalProduct2.getStock().value())
-                        .as("상품2: 3개 결제 실패로 30개 복구 (초기 %d → 현재 %d)",
-                                product2InitialStock, finalProduct2.getStock().value())
-                        .isEqualTo(product2InitialStock);
-                softly.assertThat(finalProduct3.getStock().value())
-                        .as("상품3: 3개 결제 실패로 30개 복구 (초기 %d → 현재 %d)",
-                                product3InitialStock, finalProduct3.getStock().value())
-                        .isEqualTo(product3InitialStock);
-            });
-        }
-    }
-}
diff --git a/core/service/payment-service/src/test/resources/application-test.yml b/core/service/payment-service/src/test/resources/application-test.yml
deleted file mode 100644
index 571bc26a4..000000000
--- a/core/service/payment-service/src/test/resources/application-test.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-spring:
-  jpa:
-    hibernate:
-      ddl-auto: create-drop
-
-http-client:
-  pg-simulator:
-    url: http://localhost:8082
-    path: /api/v1/payments
-    
-pg:
-  callback:
-    url: http://localhost:8080/api/v1/payments/callback
diff --git a/core/service/product-service/build.gradle.kts b/core/service/product-service/build.gradle.kts
deleted file mode 100644
index 8b2836710..000000000
--- a/core/service/product-service/build.gradle.kts
+++ /dev/null
@@ -1,19 +0,0 @@
-dependencies {
-    implementation(project(":core:domain"))
-
-    // spring
-    implementation("org.springframework.boot:spring-boot-starter")
-    implementation("org.springframework:spring-tx")
-
-
-    // mysql
-    runtimeOnly(project(":core:infra:database:mysql:product-mysql"))
-    runtimeOnly(project(":core:infra:database:mysql:user-mysql"))
-
-    // redis
-    runtimeOnly(project(":core:infra:database:redis:product-redis"))
-
-    testImplementation(testFixtures(project(":core:infra:database:mysql:mysql-core")))
-    testImplementation(testFixtures(project(":core:infra:database:redis:redis-config")))
-    testImplementation(project(":core:infra:database:mysql:mysql-config"))
-}
diff --git a/core/service/product-service/src/test/java/com/loopers/ProductServiceTestApplication.java b/core/service/product-service/src/test/java/com/loopers/ProductServiceTestApplication.java
deleted file mode 100644
index 90142c9d0..000000000
--- a/core/service/product-service/src/test/java/com/loopers/ProductServiceTestApplication.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.loopers;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-
-@SpringBootApplication
-public class ProductServiceTestApplication {
-    public static void main(String[] args) {
-        SpringApplication.run(ProductServiceTestApplication.class, args);
-    }
-}
diff --git a/core/service/product-service/src/test/java/com/loopers/core/service/IntegrationTest.java b/core/service/product-service/src/test/java/com/loopers/core/service/IntegrationTest.java
deleted file mode 100644
index 56ee3dd13..000000000
--- a/core/service/product-service/src/test/java/com/loopers/core/service/IntegrationTest.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.loopers.core.service;
-
-import com.loopers.core.infra.mysql.testcontainers.MySqlTestContainersExtension;
-import com.loopers.core.infra.mysql.util.DatabaseCleanUp;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-
-@SpringBootTest
-@ExtendWith(MySqlTestContainersExtension.class)
-public class IntegrationTest {
-
-    @Autowired
-    private DatabaseCleanUp databaseCleanUp;
-
-    @AfterEach
-    void databaseCleanUp() {
-        databaseCleanUp.truncateAllTables();
-    }
-}
diff --git a/core/service/product-service/src/test/resources/application-test.yml b/core/service/product-service/src/test/resources/application-test.yml
deleted file mode 100644
index a3eb5d6a6..000000000
--- a/core/service/product-service/src/test/resources/application-test.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-spring:
-  jpa:
-    hibernate:
-      ddl-auto: create-drop
-    show-sql: true
-  config:
-    import: redis.yml
diff --git a/core/service/product-service/src/main/java/com/loopers/core/service/brand/BrandFakeDataInitializer.java b/core/service/src/main/java/com/loopers/core/service/brand/BrandFakeDataInitializer.java
similarity index 90%
rename from core/service/product-service/src/main/java/com/loopers/core/service/brand/BrandFakeDataInitializer.java
rename to core/service/src/main/java/com/loopers/core/service/brand/BrandFakeDataInitializer.java
index 047354621..39bae2a48 100644
--- a/core/service/product-service/src/main/java/com/loopers/core/service/brand/BrandFakeDataInitializer.java
+++ b/core/service/src/main/java/com/loopers/core/service/brand/BrandFakeDataInitializer.java
@@ -3,17 +3,11 @@
 import com.loopers.core.domain.brand.Brand;
 import com.loopers.core.domain.brand.repository.BrandRepository;
 import com.loopers.core.domain.brand.vo.BrandDescription;
-import com.loopers.core.domain.brand.vo.BrandId;
 import com.loopers.core.domain.brand.vo.BrandName;
-import com.loopers.core.domain.common.vo.CreatedAt;
-import com.loopers.core.domain.common.vo.DeletedAt;
-import com.loopers.core.domain.common.vo.UpdatedAt;
 import jakarta.annotation.PostConstruct;
 import org.springframework.context.annotation.Profile;
 import org.springframework.stereotype.Component;
 
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Random;
 
 @Component
diff --git a/core/service/product-service/src/main/java/com/loopers/core/service/brand/BrandQueryService.java b/core/service/src/main/java/com/loopers/core/service/brand/BrandQueryService.java
similarity index 100%
rename from core/service/product-service/src/main/java/com/loopers/core/service/brand/BrandQueryService.java
rename to core/service/src/main/java/com/loopers/core/service/brand/BrandQueryService.java
diff --git a/core/service/product-service/src/main/java/com/loopers/core/service/brand/query/GetBrandQuery.java b/core/service/src/main/java/com/loopers/core/service/brand/query/GetBrandQuery.java
similarity index 100%
rename from core/service/product-service/src/main/java/com/loopers/core/service/brand/query/GetBrandQuery.java
rename to core/service/src/main/java/com/loopers/core/service/brand/query/GetBrandQuery.java
diff --git a/core/service/src/main/java/com/loopers/core/service/config/RetryableExceptionsProperties.java b/core/service/src/main/java/com/loopers/core/service/config/RetryableExceptionsProperties.java
new file mode 100644
index 000000000..c85c58a05
--- /dev/null
+++ b/core/service/src/main/java/com/loopers/core/service/config/RetryableExceptionsProperties.java
@@ -0,0 +1,32 @@
+package com.loopers.core.service.config;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+@Getter
+@Setter
+@Component
+@ConfigurationProperties(prefix = "retry.exceptions")
+public class RetryableExceptionsProperties {
+
+    private List<String> retryable;
+
+    public boolean isRetryable(Exception exception) {
+        return retryable.stream()
+                .map(this::resolveExceptionClass)
+                .anyMatch(exceptionClass -> exceptionClass.isInstance(exception));
+    }
+
+    @SuppressWarnings("unchecked")
+    private Class<? extends Exception> resolveExceptionClass(String className) {
+        try {
+            return (Class<? extends Exception>) Class.forName(className);
+        } catch (ClassNotFoundException e) {
+            throw new IllegalArgumentException("예외 클래스를 찾을 수 없습니다: " + className, e);
+        }
+    }
+}
diff --git a/core/service/src/main/java/com/loopers/core/service/order/OrderDataPlatformHandler.java b/core/service/src/main/java/com/loopers/core/service/order/OrderDataPlatformHandler.java
new file mode 100644
index 000000000..8057b6c66
--- /dev/null
+++ b/core/service/src/main/java/com/loopers/core/service/order/OrderDataPlatformHandler.java
@@ -0,0 +1,39 @@
+package com.loopers.core.service.order;
+
+import com.loopers.core.domain.order.Order;
+import com.loopers.core.domain.order.OrderDataPlatformClient;
+import com.loopers.core.domain.order.repository.OrderRepository;
+import com.loopers.core.domain.order.vo.OrderCompletedEvent;
+import com.loopers.core.service.order.component.OrderDataPlatformSendingFailHandler;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.event.TransactionalEventListener;
+
+import static org.springframework.transaction.event.TransactionPhase.AFTER_COMMIT;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class OrderDataPlatformHandler {
+
+    private final OrderRepository orderRepository;
+    private final OrderDataPlatformClient dataPlatformClient;
+    private final OrderDataPlatformSendingFailHandler orderDataPlatformSendingFailHandler;
+
+    @Async
+    @Transactional(propagation = Propagation.REQUIRES_NEW)
+    @TransactionalEventListener(phase = AFTER_COMMIT)
+    public void handle(OrderCompletedEvent event) {
+        try {
+            Order order = orderRepository.getById(event.orderId());
+            dataPlatformClient.send(order);
+        } catch (Exception e) {
+            log.error("주문의 데이터플랫폼 전송중 오류가 발생했습니다.", e);
+            orderDataPlatformSendingFailHandler.handle(event, e);
+        }
+    }
+}
diff --git a/core/service/order-service/src/main/java/com/loopers/core/service/order/OrderQueryService.java b/core/service/src/main/java/com/loopers/core/service/order/OrderQueryService.java
similarity index 100%
rename from core/service/order-service/src/main/java/com/loopers/core/service/order/OrderQueryService.java
rename to core/service/src/main/java/com/loopers/core/service/order/OrderQueryService.java
diff --git a/core/service/order-service/src/main/java/com/loopers/core/service/order/OrderService.java b/core/service/src/main/java/com/loopers/core/service/order/OrderService.java
similarity index 88%
rename from core/service/order-service/src/main/java/com/loopers/core/service/order/OrderService.java
rename to core/service/src/main/java/com/loopers/core/service/order/OrderService.java
index ecc007936..80417c2a7 100644
--- a/core/service/order-service/src/main/java/com/loopers/core/service/order/OrderService.java
+++ b/core/service/src/main/java/com/loopers/core/service/order/OrderService.java
@@ -4,6 +4,7 @@
 import com.loopers.core.domain.order.OrderItem;
 import com.loopers.core.domain.order.repository.OrderItemRepository;
 import com.loopers.core.domain.order.repository.OrderRepository;
+import com.loopers.core.domain.order.vo.OrderCompletedEvent;
 import com.loopers.core.domain.order.vo.Quantity;
 import com.loopers.core.domain.product.Product;
 import com.loopers.core.domain.product.repository.ProductRepository;
@@ -13,6 +14,7 @@
 import com.loopers.core.domain.user.vo.UserIdentifier;
 import com.loopers.core.service.order.command.OrderProductsCommand;
 import lombok.RequiredArgsConstructor;
+import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -26,6 +28,7 @@ public class OrderService {
     private final ProductRepository productRepository;
     private final OrderRepository orderRepository;
     private final OrderItemRepository orderItemRepository;
+    private final ApplicationEventPublisher eventPublisher;
 
     @Transactional
     public Order order(OrderProductsCommand command) {
@@ -43,6 +46,7 @@ public Order order(OrderProductsCommand command) {
                 )
                 .toList();
         orderItemRepository.saveAll(orderItems);
+        eventPublisher.publishEvent(new OrderCompletedEvent(savedOrder.getId()));
 
         return savedOrder;
     }
diff --git a/core/service/src/main/java/com/loopers/core/service/order/PayedOrderHandler.java b/core/service/src/main/java/com/loopers/core/service/order/PayedOrderHandler.java
new file mode 100644
index 000000000..e0cb16771
--- /dev/null
+++ b/core/service/src/main/java/com/loopers/core/service/order/PayedOrderHandler.java
@@ -0,0 +1,41 @@
+package com.loopers.core.service.order;
+
+import com.loopers.core.domain.order.Order;
+import com.loopers.core.domain.order.repository.OrderRepository;
+import com.loopers.core.domain.payment.Payment;
+import com.loopers.core.domain.payment.repository.PaymentRepository;
+import com.loopers.core.domain.payment.vo.PaymentCompletedEvent;
+import com.loopers.core.service.order.component.PayedOrderFailHandler;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.event.TransactionalEventListener;
+
+import static org.springframework.transaction.event.TransactionPhase.AFTER_COMMIT;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class PayedOrderHandler {
+
+    private final OrderRepository orderRepository;
+    private final PaymentRepository paymentRepository;
+    private final PayedOrderFailHandler payedOrderFailHandler;
+
+    @Async
+    @Transactional(propagation = Propagation.REQUIRES_NEW)
+    @TransactionalEventListener(phase = AFTER_COMMIT)
+    public void handle(PaymentCompletedEvent event) {
+        try {
+            Payment payment = paymentRepository.getById(event.paymentId());
+            Order order = orderRepository.getBy(payment.getOrderKey());
+            orderRepository.save(order.payed());
+        } catch (Exception exception) {
+            log.error("주문의 결제완료 상태 변경중 오류가 발생했습니다.", exception);
+            payedOrderFailHandler.handle(event, exception);
+        }
+    }
+}
diff --git a/core/service/order-service/src/main/java/com/loopers/core/service/order/command/OrderProductsCommand.java b/core/service/src/main/java/com/loopers/core/service/order/command/OrderProductsCommand.java
similarity index 100%
rename from core/service/order-service/src/main/java/com/loopers/core/service/order/command/OrderProductsCommand.java
rename to core/service/src/main/java/com/loopers/core/service/order/command/OrderProductsCommand.java
diff --git a/core/service/src/main/java/com/loopers/core/service/order/component/OrderDataPlatformSendingFailHandler.java b/core/service/src/main/java/com/loopers/core/service/order/component/OrderDataPlatformSendingFailHandler.java
new file mode 100644
index 000000000..51294a539
--- /dev/null
+++ b/core/service/src/main/java/com/loopers/core/service/order/component/OrderDataPlatformSendingFailHandler.java
@@ -0,0 +1,46 @@
+package com.loopers.core.service.order.component;
+
+import com.loopers.JacksonUtil;
+import com.loopers.core.domain.event.EventOutbox;
+import com.loopers.core.domain.event.repository.EventOutboxRepository;
+import com.loopers.core.domain.event.type.AggregateType;
+import com.loopers.core.domain.event.type.EventType;
+import com.loopers.core.domain.event.vo.EventPayload;
+import com.loopers.core.domain.order.vo.OrderCompletedEvent;
+import com.loopers.core.domain.order.vo.OrderDataPlatformSendingFailEvent;
+import com.loopers.core.domain.order.vo.OrderId;
+import com.loopers.core.service.config.RetryableExceptionsProperties;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+@RequiredArgsConstructor
+public class OrderDataPlatformSendingFailHandler {
+
+    private final EventOutboxRepository eventOutboxRepository;
+    private final RetryableExceptionsProperties retryableExceptionsProperties;
+
+    @Transactional
+    public void handle(OrderCompletedEvent event, Exception exception) {
+        OrderId orderId = event.orderId();
+        boolean retryable = retryableExceptionsProperties.isRetryable(exception);
+
+        eventOutboxRepository.save(
+                EventOutbox.create(
+                        AggregateType.ORDER,
+                        orderId.toAggregateId(),
+                        EventType.ORDER_DATA_PLATFORM_SENDING_FAILED,
+                        new EventPayload(
+                                JacksonUtil.convertToString(
+                                        OrderDataPlatformSendingFailEvent.create(
+                                                orderId,
+                                                retryable,
+                                                exception.getMessage()
+                                        )
+                                )
+                        )
+                )
+        );
+    }
+}
diff --git a/core/service/src/main/java/com/loopers/core/service/order/component/PayedOrderFailHandler.java b/core/service/src/main/java/com/loopers/core/service/order/component/PayedOrderFailHandler.java
new file mode 100644
index 000000000..30d4bc6a1
--- /dev/null
+++ b/core/service/src/main/java/com/loopers/core/service/order/component/PayedOrderFailHandler.java
@@ -0,0 +1,51 @@
+package com.loopers.core.service.order.component;
+
+import com.loopers.JacksonUtil;
+import com.loopers.core.domain.event.EventOutbox;
+import com.loopers.core.domain.event.repository.EventOutboxRepository;
+import com.loopers.core.domain.event.type.AggregateType;
+import com.loopers.core.domain.event.type.EventType;
+import com.loopers.core.domain.event.vo.EventPayload;
+import com.loopers.core.domain.order.Order;
+import com.loopers.core.domain.order.repository.OrderRepository;
+import com.loopers.core.domain.order.vo.PayedOrderFailEvent;
+import com.loopers.core.domain.payment.Payment;
+import com.loopers.core.domain.payment.repository.PaymentRepository;
+import com.loopers.core.domain.payment.vo.PaymentCompletedEvent;
+import com.loopers.core.service.config.RetryableExceptionsProperties;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class PayedOrderFailHandler {
+
+    private final EventOutboxRepository eventOutboxRepository;
+    private final OrderRepository orderRepository;
+    private final PaymentRepository paymentRepository;
+    private final RetryableExceptionsProperties retryableExceptionsProperties;
+
+    public void handle(PaymentCompletedEvent event, Exception exception) {
+        Payment payment = paymentRepository.getById(event.paymentId());
+        Order order = orderRepository.getBy(payment.getOrderKey());
+        boolean retryable = retryableExceptionsProperties.isRetryable(exception);
+
+        eventOutboxRepository.save(
+                EventOutbox.create(
+                        AggregateType.ORDER,
+                        order.getId().toAggregateId(),
+                        EventType.PAYED_ORDER_STATUS_CHANGED_FAIL,
+                        new EventPayload(
+                                JacksonUtil.convertToString(
+                                        PayedOrderFailEvent.create(
+                                                payment.getId(),
+                                                order.getId(),
+                                                retryable,
+                                                exception.getMessage()
+                                        )
+                                )
+                        )
+                )
+        );
+    }
+}
diff --git a/core/service/order-service/src/main/java/com/loopers/core/service/order/query/GetOrderDetailQuery.java b/core/service/src/main/java/com/loopers/core/service/order/query/GetOrderDetailQuery.java
similarity index 100%
rename from core/service/order-service/src/main/java/com/loopers/core/service/order/query/GetOrderDetailQuery.java
rename to core/service/src/main/java/com/loopers/core/service/order/query/GetOrderDetailQuery.java
diff --git a/core/service/order-service/src/main/java/com/loopers/core/service/order/query/GetOrderListQuery.java b/core/service/src/main/java/com/loopers/core/service/order/query/GetOrderListQuery.java
similarity index 100%
rename from core/service/order-service/src/main/java/com/loopers/core/service/order/query/GetOrderListQuery.java
rename to core/service/src/main/java/com/loopers/core/service/order/query/GetOrderListQuery.java
diff --git a/core/service/src/main/java/com/loopers/core/service/payment/PaymentDataPlatformEventHandler.java b/core/service/src/main/java/com/loopers/core/service/payment/PaymentDataPlatformEventHandler.java
new file mode 100644
index 000000000..a2a4c63ba
--- /dev/null
+++ b/core/service/src/main/java/com/loopers/core/service/payment/PaymentDataPlatformEventHandler.java
@@ -0,0 +1,40 @@
+package com.loopers.core.service.payment;
+
+import com.loopers.core.domain.payment.Payment;
+import com.loopers.core.domain.payment.PaymentDataPlatformClient;
+import com.loopers.core.domain.payment.repository.PaymentRepository;
+import com.loopers.core.domain.payment.vo.PaymentCompletedEvent;
+import com.loopers.core.service.payment.component.PaymentDataPlatformSendingFailHandler;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.event.TransactionalEventListener;
+
+import static org.springframework.transaction.event.TransactionPhase.AFTER_COMMIT;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class PaymentDataPlatformEventHandler {
+
+    private final PaymentDataPlatformSendingFailHandler paymentDataPlatformSendingFailHandler;
+    private final PaymentRepository paymentRepository;
+    private final PaymentDataPlatformClient dataPlatformClient;
+
+
+    @Async
+    @Transactional(propagation = Propagation.REQUIRES_NEW)
+    @TransactionalEventListener(phase = AFTER_COMMIT)
+    void handle(PaymentCompletedEvent event) {
+        try {
+            Payment payment = paymentRepository.getById(event.paymentId());
+            dataPlatformClient.send(payment);
+        } catch (Exception exception) {
+            log.error("결제 데이터플랫폼 전송 중 오류가 발생했습니다.", exception);
+            paymentDataPlatformSendingFailHandler.handle(event, exception);
+        }
+    }
+}
diff --git a/core/service/payment-service/src/main/java/com/loopers/core/service/payment/PaymentService.java b/core/service/src/main/java/com/loopers/core/service/payment/PaymentService.java
similarity index 71%
rename from core/service/payment-service/src/main/java/com/loopers/core/service/payment/PaymentService.java
rename to core/service/src/main/java/com/loopers/core/service/payment/PaymentService.java
index 9b7b21c6a..35503b575 100644
--- a/core/service/payment-service/src/main/java/com/loopers/core/service/payment/PaymentService.java
+++ b/core/service/src/main/java/com/loopers/core/service/payment/PaymentService.java
@@ -7,10 +7,9 @@
 import com.loopers.core.domain.order.vo.CouponId;
 import com.loopers.core.domain.order.vo.OrderId;
 import com.loopers.core.domain.payment.Payment;
-import com.loopers.core.domain.payment.PgClient;
-import com.loopers.core.domain.payment.PgPayment;
 import com.loopers.core.domain.payment.repository.PaymentRepository;
 import com.loopers.core.domain.payment.type.PaymentStatus;
+import com.loopers.core.domain.payment.type.PaymentType;
 import com.loopers.core.domain.payment.vo.CardNo;
 import com.loopers.core.domain.payment.vo.CardType;
 import com.loopers.core.domain.payment.vo.PayAmount;
@@ -18,11 +17,8 @@
 import com.loopers.core.domain.user.repository.UserRepository;
 import com.loopers.core.domain.user.vo.UserIdentifier;
 import com.loopers.core.service.payment.command.PaymentCommand;
-import com.loopers.core.service.payment.component.OrderLineAggregator;
-import com.loopers.core.service.payment.component.PayAmountDiscountStrategy;
-import com.loopers.core.service.payment.component.PayAmountDiscountStrategySelector;
+import com.loopers.core.service.payment.component.*;
 import lombok.RequiredArgsConstructor;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -38,10 +34,7 @@ public class PaymentService {
     private final OrderRepository orderRepository;
     private final OrderItemRepository orderItemRepository;
     private final OrderLineAggregator orderLineAggregator;
-    private final PgClient pgClient;
-
-    @Value("${pg.callback.url}")
-    String callbackUrl;
+    private final PaymentStrategySelector paymentStrategySelector;
 
     @Transactional
     public Payment pay(PaymentCommand command) {
@@ -49,8 +42,11 @@ public Payment pay(PaymentCommand command) {
         Order order = orderRepository.getById(new OrderId(command.orderId()));
         List<OrderItem> orderItems = orderItemRepository.findAllByOrderId(order.getId());
         CouponId couponId = new CouponId(command.couponId());
+        CardType cardType = new CardType(command.cardType());
+        CardNo cardNo = new CardNo(command.cardNo());
+        PaymentType paymentType = PaymentType.valueOf(command.PaymentType());
 
-        boolean hasSuccessfulPayment = paymentRepository.findBy(order.getOrderKey(), PaymentStatus.SUCCESS).isPresent();
+        boolean hasSuccessfulPayment = paymentRepository.findByWithLock(order.getOrderKey(), PaymentStatus.SUCCESS).isPresent();
         if (hasSuccessfulPayment) {
             throw new IllegalStateException("이미 결제에 성공한 이력이 있는 주문입니다.");
         }
@@ -59,21 +55,26 @@ public Payment pay(PaymentCommand command) {
         if (hasPendingPayment) {
             throw new IllegalStateException("이미 결제가 진행 중인 주문입니다.");
         }
+        // 재고 차감 및 주문 항목 저장
+        PayAmount payAmount = orderLineAggregator.aggregate(orderItems);
 
         //결제 금액 계산
         PayAmountDiscountStrategy discountStrategy = discountStrategySelector.select(couponId);
-        PayAmount payAmount = orderLineAggregator.aggregate(orderItems);
         PayAmount discountedPayAmount = discountStrategy.discount(payAmount, couponId);
-        Payment payment = Payment.create(order.getOrderKey(), user.getId(), new CardType(command.cardType()), new CardNo(command.cardNo()), discountedPayAmount);
-
-        //PG 요청
-        PgPayment pgPayment = pgClient.pay(payment, callbackUrl);
+        Payment payment = Payment.create(
+                order.getOrderKey(),
+                user.getId(),
+                cardType,
+                cardNo,
+                discountedPayAmount,
+                paymentType
+        );
 
         //결제 저장
-        return paymentRepository.save(
-                payment.withTransactionKey(pgPayment.transactionKey())
-                        .withStatus(pgPayment.status())
-                        .withFailedReason(pgPayment.failedReason())
-        );
+        Payment savedPayment = paymentRepository.save(payment);
+        PaymentStrategy paymentStrategy = paymentStrategySelector.selectBy(paymentType);
+        paymentStrategy.pay(savedPayment);
+
+        return savedPayment;
     }
 }
diff --git a/core/service/payment-service/src/main/java/com/loopers/core/service/payment/PgCallbackService.java b/core/service/src/main/java/com/loopers/core/service/payment/PgCallbackService.java
similarity index 58%
rename from core/service/payment-service/src/main/java/com/loopers/core/service/payment/PgCallbackService.java
rename to core/service/src/main/java/com/loopers/core/service/payment/PgCallbackService.java
index fac36e654..8fd1d59ff 100644
--- a/core/service/payment-service/src/main/java/com/loopers/core/service/payment/PgCallbackService.java
+++ b/core/service/src/main/java/com/loopers/core/service/payment/PgCallbackService.java
@@ -2,14 +2,17 @@
 
 import com.loopers.core.domain.order.vo.OrderKey;
 import com.loopers.core.domain.payment.Payment;
-import com.loopers.core.domain.payment.repository.PaymentRepository;
-import com.loopers.core.domain.payment.type.PaymentStatus;
+import com.loopers.core.domain.payment.PgPayment;
+import com.loopers.core.domain.payment.repository.PgPaymentRepository;
+import com.loopers.core.domain.payment.type.PgPaymentStatus;
 import com.loopers.core.domain.payment.vo.FailedReason;
+import com.loopers.core.domain.payment.vo.PaymentCompletedEvent;
 import com.loopers.core.domain.payment.vo.TransactionKey;
 import com.loopers.core.service.payment.command.PgCallbackCommand;
 import com.loopers.core.service.payment.component.PaymentCallbackStrategy;
 import com.loopers.core.service.payment.component.PaymentCallbackStrategySelector;
 import lombok.RequiredArgsConstructor;
+import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -17,19 +20,22 @@
 @RequiredArgsConstructor
 public class PgCallbackService {
 
-    private final PaymentRepository paymentRepository;
+    private final PgPaymentRepository pgPaymentRepository;
     private final PaymentCallbackStrategySelector strategySelector;
+    private final ApplicationEventPublisher eventPublisher;
 
     @Transactional
     public void callback(PgCallbackCommand command) {
         TransactionKey transactionKey = new TransactionKey(command.transactionKey());
         OrderKey orderKey = new OrderKey(command.orderId());
-        PaymentStatus status = PaymentStatus.valueOf(command.status());
+        PgPaymentStatus status = PgPaymentStatus.valueOf(command.status());
         FailedReason failedReason = new FailedReason(command.reason());
 
-        Payment payment = paymentRepository.getByWithLock(transactionKey);
+        PgPayment pgPayment = pgPaymentRepository.getByWithLock(transactionKey);
+        pgPaymentRepository.save(pgPayment.with(status, failedReason));
         PaymentCallbackStrategy strategy = strategySelector.select(orderKey, status);
-        Payment processedPayment = strategy.pay(payment, failedReason);
-        paymentRepository.save(processedPayment);
+        Payment payment = strategy.pay(pgPayment, failedReason);
+
+        eventPublisher.publishEvent(new PaymentCompletedEvent(payment.getId()));
     }
 }
diff --git a/core/service/src/main/java/com/loopers/core/service/payment/PgPaymentHandler.java b/core/service/src/main/java/com/loopers/core/service/payment/PgPaymentHandler.java
new file mode 100644
index 000000000..4fdec27d7
--- /dev/null
+++ b/core/service/src/main/java/com/loopers/core/service/payment/PgPaymentHandler.java
@@ -0,0 +1,59 @@
+package com.loopers.core.service.payment;
+
+import com.loopers.core.domain.payment.Payment;
+import com.loopers.core.domain.payment.PgClient;
+import com.loopers.core.domain.payment.PgPayment;
+import com.loopers.core.domain.payment.repository.PaymentRepository;
+import com.loopers.core.domain.payment.repository.PgPaymentRepository;
+import com.loopers.core.domain.payment.type.PaymentType;
+import com.loopers.core.domain.payment.vo.FailedReason;
+import com.loopers.core.domain.payment.vo.PaymentCreatedEvent;
+import com.loopers.core.domain.payment.vo.PaymentId;
+import com.loopers.core.service.payment.component.PgPaymentRequestFailHandler;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.event.TransactionalEventListener;
+
+import static org.springframework.transaction.event.TransactionPhase.AFTER_COMMIT;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class PgPaymentHandler {
+
+    private final PgClient pgClient;
+    private final PgPaymentRepository pgPaymentRepository;
+    private final PaymentRepository paymentRepository;
+    private final PgPaymentRequestFailHandler pgPaymentRequestFailHandler;
+
+    @Value("${pg.callback.url}")
+    String callbackUrl;
+
+    @Async
+    @Transactional(propagation = Propagation.REQUIRES_NEW)
+    @TransactionalEventListener(phase = AFTER_COMMIT)
+    public void handle(PaymentCreatedEvent event) {
+        if (event.paymentType() == PaymentType.POINT) {
+            return;
+        }
+
+        PaymentId paymentId = event.paymentId();
+        Payment payment = paymentRepository.getById(paymentId);
+
+        try {
+            PgPayment pgPayment = pgClient.pay(payment, callbackUrl).with(paymentId);
+            pgPaymentRepository.findBy(paymentId)
+                    .map(exist -> pgPaymentRepository.save(exist.merge(pgPayment)))
+                    .orElseGet(() -> pgPaymentRepository.save(pgPayment));
+        } catch (Exception e) {
+            log.error("PG 결제 요청 처리중 에러가 발생했습니다.", e);
+            pgPaymentRequestFailHandler.handle(paymentId, e);
+            paymentRepository.save(payment.failed(new FailedReason(e.getMessage())));
+        }
+    }
+}
diff --git a/core/service/payment-service/src/main/java/com/loopers/core/service/payment/command/PaymentCommand.java b/core/service/src/main/java/com/loopers/core/service/payment/command/PaymentCommand.java
similarity index 78%
rename from core/service/payment-service/src/main/java/com/loopers/core/service/payment/command/PaymentCommand.java
rename to core/service/src/main/java/com/loopers/core/service/payment/command/PaymentCommand.java
index a880d4fe4..297fe572e 100644
--- a/core/service/payment-service/src/main/java/com/loopers/core/service/payment/command/PaymentCommand.java
+++ b/core/service/src/main/java/com/loopers/core/service/payment/command/PaymentCommand.java
@@ -5,7 +5,8 @@ public record PaymentCommand(
         String userIdentifier,
         String cardType,
         String cardNo,
-        String couponId
+        String couponId,
+        String PaymentType
 ) {
 
 }
diff --git a/core/service/payment-service/src/main/java/com/loopers/core/service/payment/command/PgCallbackCommand.java b/core/service/src/main/java/com/loopers/core/service/payment/command/PgCallbackCommand.java
similarity index 100%
rename from core/service/payment-service/src/main/java/com/loopers/core/service/payment/command/PgCallbackCommand.java
rename to core/service/src/main/java/com/loopers/core/service/payment/command/PgCallbackCommand.java
diff --git a/core/service/src/main/java/com/loopers/core/service/payment/component/CardPaymentStrategy.java b/core/service/src/main/java/com/loopers/core/service/payment/component/CardPaymentStrategy.java
new file mode 100644
index 000000000..f7ceceafe
--- /dev/null
+++ b/core/service/src/main/java/com/loopers/core/service/payment/component/CardPaymentStrategy.java
@@ -0,0 +1,25 @@
+package com.loopers.core.service.payment.component;
+
+import com.loopers.core.domain.payment.Payment;
+import com.loopers.core.domain.payment.type.PaymentType;
+import com.loopers.core.domain.payment.vo.PaymentCreatedEvent;
+import lombok.RequiredArgsConstructor;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class CardPaymentStrategy implements PaymentStrategy {
+
+    private final ApplicationEventPublisher eventPublisher;
+
+    @Override
+    public PaymentType getPaymentType() {
+        return PaymentType.CARD;
+    }
+
+    @Override
+    public void pay(Payment payment) {
+        eventPublisher.publishEvent(new PaymentCreatedEvent(payment.getId(), payment.getType()));
+    }
+}
diff --git a/core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/CouponDiscountStrategy.java b/core/service/src/main/java/com/loopers/core/service/payment/component/CouponDiscountStrategy.java
similarity index 100%
rename from core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/CouponDiscountStrategy.java
rename to core/service/src/main/java/com/loopers/core/service/payment/component/CouponDiscountStrategy.java
diff --git a/core/service/src/main/java/com/loopers/core/service/payment/component/DuplicateSuccessPaymentStrategy.java b/core/service/src/main/java/com/loopers/core/service/payment/component/DuplicateSuccessPaymentStrategy.java
new file mode 100644
index 000000000..24545454c
--- /dev/null
+++ b/core/service/src/main/java/com/loopers/core/service/payment/component/DuplicateSuccessPaymentStrategy.java
@@ -0,0 +1,21 @@
+package com.loopers.core.service.payment.component;
+
+import com.loopers.core.domain.payment.Payment;
+import com.loopers.core.domain.payment.PgPayment;
+import com.loopers.core.domain.payment.repository.PaymentRepository;
+import com.loopers.core.domain.payment.vo.FailedReason;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class DuplicateSuccessPaymentStrategy implements PaymentCallbackStrategy {
+
+    private final PaymentRepository paymentRepository;
+
+    @Override
+    public Payment pay(PgPayment pgPayment, FailedReason failedReason) {
+        Payment payment = paymentRepository.getById(pgPayment.getPaymentId());
+        return paymentRepository.save(payment.failed(new FailedReason("이미 결제에 성공한 이력이 있는 주문입니다.")));
+    }
+}
diff --git a/core/service/src/main/java/com/loopers/core/service/payment/component/FailedPaymentStrategy.java b/core/service/src/main/java/com/loopers/core/service/payment/component/FailedPaymentStrategy.java
new file mode 100644
index 000000000..193016e36
--- /dev/null
+++ b/core/service/src/main/java/com/loopers/core/service/payment/component/FailedPaymentStrategy.java
@@ -0,0 +1,28 @@
+package com.loopers.core.service.payment.component;
+
+import com.loopers.core.domain.payment.Payment;
+import com.loopers.core.domain.payment.PgPayment;
+import com.loopers.core.domain.payment.repository.PaymentRepository;
+import com.loopers.core.domain.payment.vo.FailedReason;
+import com.loopers.core.domain.payment.vo.PaymentFailedEvent;
+import lombok.RequiredArgsConstructor;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+@RequiredArgsConstructor
+public class FailedPaymentStrategy implements PaymentCallbackStrategy {
+
+    private final PaymentRepository paymentRepository;
+    private final ApplicationEventPublisher eventPublisher;
+
+    @Override
+    @Transactional
+    public Payment pay(PgPayment pgPayment, FailedReason failedReason) {
+        Payment payment = paymentRepository.getById(pgPayment.getPaymentId());
+        eventPublisher.publishEvent(new PaymentFailedEvent(payment.getId(), failedReason));
+
+        return paymentRepository.save(payment.failed(failedReason));
+    }
+}
diff --git a/core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/NoneDiscountStrategy.java b/core/service/src/main/java/com/loopers/core/service/payment/component/NoneDiscountStrategy.java
similarity index 100%
rename from core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/NoneDiscountStrategy.java
rename to core/service/src/main/java/com/loopers/core/service/payment/component/NoneDiscountStrategy.java
diff --git a/core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/OrderLineAggregator.java b/core/service/src/main/java/com/loopers/core/service/payment/component/OrderLineAggregator.java
similarity index 100%
rename from core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/OrderLineAggregator.java
rename to core/service/src/main/java/com/loopers/core/service/payment/component/OrderLineAggregator.java
diff --git a/core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/OrderLineAllocator.java b/core/service/src/main/java/com/loopers/core/service/payment/component/OrderLineAllocator.java
similarity index 100%
rename from core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/OrderLineAllocator.java
rename to core/service/src/main/java/com/loopers/core/service/payment/component/OrderLineAllocator.java
diff --git a/core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/PayAmountDiscountStrategy.java b/core/service/src/main/java/com/loopers/core/service/payment/component/PayAmountDiscountStrategy.java
similarity index 100%
rename from core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/PayAmountDiscountStrategy.java
rename to core/service/src/main/java/com/loopers/core/service/payment/component/PayAmountDiscountStrategy.java
diff --git a/core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/PayAmountDiscountStrategySelector.java b/core/service/src/main/java/com/loopers/core/service/payment/component/PayAmountDiscountStrategySelector.java
similarity index 100%
rename from core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/PayAmountDiscountStrategySelector.java
rename to core/service/src/main/java/com/loopers/core/service/payment/component/PayAmountDiscountStrategySelector.java
diff --git a/core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/PaymentCallbackStrategy.java b/core/service/src/main/java/com/loopers/core/service/payment/component/PaymentCallbackStrategy.java
similarity index 64%
rename from core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/PaymentCallbackStrategy.java
rename to core/service/src/main/java/com/loopers/core/service/payment/component/PaymentCallbackStrategy.java
index f854631aa..7a4c00ed9 100644
--- a/core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/PaymentCallbackStrategy.java
+++ b/core/service/src/main/java/com/loopers/core/service/payment/component/PaymentCallbackStrategy.java
@@ -1,9 +1,10 @@
 package com.loopers.core.service.payment.component;
 
 import com.loopers.core.domain.payment.Payment;
+import com.loopers.core.domain.payment.PgPayment;
 import com.loopers.core.domain.payment.vo.FailedReason;
 
 public interface PaymentCallbackStrategy {
 
-    Payment pay(Payment payment, FailedReason failedReason);
+    Payment pay(PgPayment payment, FailedReason failedReason);
 }
diff --git a/core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/PaymentCallbackStrategySelector.java b/core/service/src/main/java/com/loopers/core/service/payment/component/PaymentCallbackStrategySelector.java
similarity index 85%
rename from core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/PaymentCallbackStrategySelector.java
rename to core/service/src/main/java/com/loopers/core/service/payment/component/PaymentCallbackStrategySelector.java
index 44de5d145..cadcd7fe6 100644
--- a/core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/PaymentCallbackStrategySelector.java
+++ b/core/service/src/main/java/com/loopers/core/service/payment/component/PaymentCallbackStrategySelector.java
@@ -3,6 +3,7 @@
 import com.loopers.core.domain.order.vo.OrderKey;
 import com.loopers.core.domain.payment.repository.PaymentRepository;
 import com.loopers.core.domain.payment.type.PaymentStatus;
+import com.loopers.core.domain.payment.type.PgPaymentStatus;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Component;
 
@@ -15,7 +16,7 @@ public class PaymentCallbackStrategySelector {
     private final FailedPaymentStrategy failedPaymentStrategy;
     private final DuplicateSuccessPaymentStrategy duplicateSuccessPaymentStrategy;
 
-    public PaymentCallbackStrategy select(OrderKey orderKey, PaymentStatus status) {
+    public PaymentCallbackStrategy select(OrderKey orderKey, PgPaymentStatus status) {
         // 이미 성공한 결제가 있는 경우
         boolean hasSuccessfulPayment =
                 paymentRepository.findBy(orderKey, PaymentStatus.SUCCESS).isPresent();
@@ -25,7 +26,7 @@ public PaymentCallbackStrategy select(OrderKey orderKey, PaymentStatus status) {
         }
 
         // 결제가 실패한 경우
-        if (status != PaymentStatus.SUCCESS) {
+        if (status != PgPaymentStatus.SUCCESS) {
             return failedPaymentStrategy;
         }
 
diff --git a/core/service/src/main/java/com/loopers/core/service/payment/component/PaymentDataPlatformSendingFailHandler.java b/core/service/src/main/java/com/loopers/core/service/payment/component/PaymentDataPlatformSendingFailHandler.java
new file mode 100644
index 000000000..b5ced53d1
--- /dev/null
+++ b/core/service/src/main/java/com/loopers/core/service/payment/component/PaymentDataPlatformSendingFailHandler.java
@@ -0,0 +1,44 @@
+package com.loopers.core.service.payment.component;
+
+import com.loopers.JacksonUtil;
+import com.loopers.core.domain.event.EventOutbox;
+import com.loopers.core.domain.event.repository.EventOutboxRepository;
+import com.loopers.core.domain.event.type.AggregateType;
+import com.loopers.core.domain.event.type.EventType;
+import com.loopers.core.domain.event.vo.EventPayload;
+import com.loopers.core.domain.payment.vo.PaymentCompletedEvent;
+import com.loopers.core.domain.payment.vo.PaymentDataPlatformSendingFailEvent;
+import com.loopers.core.service.config.RetryableExceptionsProperties;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+@RequiredArgsConstructor
+public class PaymentDataPlatformSendingFailHandler {
+
+    private final EventOutboxRepository eventOutboxRepository;
+    private final RetryableExceptionsProperties retryableExceptionsProperties;
+
+    @Transactional
+    public void handle(PaymentCompletedEvent event, Exception exception) {
+        boolean retryable = retryableExceptionsProperties.isRetryable(exception);
+
+        eventOutboxRepository.save(
+                EventOutbox.create(
+                        AggregateType.PAYMENT,
+                        event.paymentId().toAggregateId(),
+                        EventType.PAYMENT_DATA_PLATFORM_SENDING_FAILED,
+                        new EventPayload(
+                                JacksonUtil.convertToString(
+                                        PaymentDataPlatformSendingFailEvent.create(
+                                                event.paymentId(),
+                                                retryable,
+                                                exception.getMessage()
+                                        )
+                                )
+                        )
+                )
+        );
+    }
+}
diff --git a/core/service/src/main/java/com/loopers/core/service/payment/component/PaymentStrategy.java b/core/service/src/main/java/com/loopers/core/service/payment/component/PaymentStrategy.java
new file mode 100644
index 000000000..884223596
--- /dev/null
+++ b/core/service/src/main/java/com/loopers/core/service/payment/component/PaymentStrategy.java
@@ -0,0 +1,11 @@
+package com.loopers.core.service.payment.component;
+
+import com.loopers.core.domain.payment.Payment;
+import com.loopers.core.domain.payment.type.PaymentType;
+
+public interface PaymentStrategy {
+
+    PaymentType getPaymentType();
+
+    void pay(Payment payment);
+}
diff --git a/core/service/src/main/java/com/loopers/core/service/payment/component/PaymentStrategySelector.java b/core/service/src/main/java/com/loopers/core/service/payment/component/PaymentStrategySelector.java
new file mode 100644
index 000000000..0f7f57692
--- /dev/null
+++ b/core/service/src/main/java/com/loopers/core/service/payment/component/PaymentStrategySelector.java
@@ -0,0 +1,23 @@
+package com.loopers.core.service.payment.component;
+
+import com.loopers.core.domain.payment.type.PaymentType;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Component
+public class PaymentStrategySelector {
+
+    private final Map<PaymentType, PaymentStrategy> paymentStrategyMap;
+
+    public PaymentStrategySelector(List<PaymentStrategy> paymentStrategies) {
+        this.paymentStrategyMap = paymentStrategies.stream()
+                .collect(Collectors.toMap(PaymentStrategy::getPaymentType, paymentStrategy -> paymentStrategy));
+    }
+
+    public PaymentStrategy selectBy(PaymentType paymentType) {
+        return paymentStrategyMap.get(paymentType);
+    }
+}
diff --git a/core/service/src/main/java/com/loopers/core/service/payment/component/PgPaymentRequestFailHandler.java b/core/service/src/main/java/com/loopers/core/service/payment/component/PgPaymentRequestFailHandler.java
new file mode 100644
index 000000000..98a46d968
--- /dev/null
+++ b/core/service/src/main/java/com/loopers/core/service/payment/component/PgPaymentRequestFailHandler.java
@@ -0,0 +1,42 @@
+package com.loopers.core.service.payment.component;
+
+import com.loopers.JacksonUtil;
+import com.loopers.core.domain.event.EventOutbox;
+import com.loopers.core.domain.event.repository.EventOutboxRepository;
+import com.loopers.core.domain.event.type.AggregateType;
+import com.loopers.core.domain.event.type.EventType;
+import com.loopers.core.domain.event.vo.EventPayload;
+import com.loopers.core.domain.payment.vo.PaymentId;
+import com.loopers.core.domain.payment.vo.PgPaymentRequestFailEvent;
+import com.loopers.core.service.config.RetryableExceptionsProperties;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class PgPaymentRequestFailHandler {
+
+    private final EventOutboxRepository eventOutboxRepository;
+    private final RetryableExceptionsProperties retryableExceptionsProperties;
+
+    public void handle(PaymentId paymentId, Exception exception) {
+        boolean retryable = retryableExceptionsProperties.isRetryable(exception);
+
+        eventOutboxRepository.save(
+                EventOutbox.create(
+                        AggregateType.PAYMENT,
+                        paymentId.toAggregateId(),
+                        EventType.PG_PAYMENT_FAILED,
+                        new EventPayload(
+                                JacksonUtil.convertToString(
+                                        PgPaymentRequestFailEvent.create(
+                                                paymentId,
+                                                retryable,
+                                                exception.getMessage()
+                                        )
+                                )
+                        )
+                )
+        );
+    }
+}
diff --git a/core/service/src/main/java/com/loopers/core/service/payment/component/PointPaymentStrategy.java b/core/service/src/main/java/com/loopers/core/service/payment/component/PointPaymentStrategy.java
new file mode 100644
index 000000000..824b62032
--- /dev/null
+++ b/core/service/src/main/java/com/loopers/core/service/payment/component/PointPaymentStrategy.java
@@ -0,0 +1,34 @@
+package com.loopers.core.service.payment.component;
+
+import com.loopers.core.domain.payment.Payment;
+import com.loopers.core.domain.payment.type.PaymentType;
+import com.loopers.core.domain.payment.vo.PaymentCompletedEvent;
+import com.loopers.core.domain.payment.vo.PaymentCreatedEvent;
+import com.loopers.core.domain.user.UserPoint;
+import com.loopers.core.domain.user.repository.UserPointRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+@RequiredArgsConstructor
+public class PointPaymentStrategy implements PaymentStrategy {
+
+    private final UserPointRepository userPointRepository;
+    private final ApplicationEventPublisher eventPublisher;
+
+    @Override
+    public PaymentType getPaymentType() {
+        return PaymentType.POINT;
+    }
+
+    @Override
+    @Transactional
+    public void pay(Payment payment) {
+        UserPoint userPoint = userPointRepository.getByUserId(payment.getUserId());
+        userPointRepository.save(userPoint.pay(payment.getAmount()));
+        eventPublisher.publishEvent(new PaymentCompletedEvent(payment.getId()));
+        eventPublisher.publishEvent(new PaymentCreatedEvent(payment.getId(), payment.getType()));
+    }
+}
diff --git a/core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/SuccessfulPaymentStrategy.java b/core/service/src/main/java/com/loopers/core/service/payment/component/SuccessfulPaymentStrategy.java
similarity index 54%
rename from core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/SuccessfulPaymentStrategy.java
rename to core/service/src/main/java/com/loopers/core/service/payment/component/SuccessfulPaymentStrategy.java
index 85961ed63..4a9a0dc99 100644
--- a/core/service/payment-service/src/main/java/com/loopers/core/service/payment/component/SuccessfulPaymentStrategy.java
+++ b/core/service/src/main/java/com/loopers/core/service/payment/component/SuccessfulPaymentStrategy.java
@@ -1,6 +1,8 @@
 package com.loopers.core.service.payment.component;
 
 import com.loopers.core.domain.payment.Payment;
+import com.loopers.core.domain.payment.PgPayment;
+import com.loopers.core.domain.payment.repository.PaymentRepository;
 import com.loopers.core.domain.payment.vo.FailedReason;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Component;
@@ -11,9 +13,12 @@
 @RequiredArgsConstructor
 public class SuccessfulPaymentStrategy implements PaymentCallbackStrategy {
 
+    private final PaymentRepository paymentRepository;
+
     @Override
     @Transactional
-    public Payment pay(Payment payment, FailedReason failedReason) {
-        return payment.success();
+    public Payment pay(PgPayment pgPayment, FailedReason failedReason) {
+        Payment payment = paymentRepository.getById(pgPayment.getPaymentId());
+        return paymentRepository.save(payment.success());
     }
 }
diff --git a/core/service/product-service/src/main/java/com/loopers/core/service/product/ProductFakeDataInitializer.java b/core/service/src/main/java/com/loopers/core/service/product/ProductFakeDataInitializer.java
similarity index 100%
rename from core/service/product-service/src/main/java/com/loopers/core/service/product/ProductFakeDataInitializer.java
rename to core/service/src/main/java/com/loopers/core/service/product/ProductFakeDataInitializer.java
diff --git a/core/service/product-service/src/main/java/com/loopers/core/service/product/ProductQueryService.java b/core/service/src/main/java/com/loopers/core/service/product/ProductQueryService.java
similarity index 100%
rename from core/service/product-service/src/main/java/com/loopers/core/service/product/ProductQueryService.java
rename to core/service/src/main/java/com/loopers/core/service/product/ProductQueryService.java
diff --git a/core/service/src/main/java/com/loopers/core/service/product/StockIncreaseHandler.java b/core/service/src/main/java/com/loopers/core/service/product/StockIncreaseHandler.java
new file mode 100644
index 000000000..0709668e7
--- /dev/null
+++ b/core/service/src/main/java/com/loopers/core/service/product/StockIncreaseHandler.java
@@ -0,0 +1,58 @@
+package com.loopers.core.service.product;
+
+import com.loopers.core.domain.order.Order;
+import com.loopers.core.domain.order.OrderItem;
+import com.loopers.core.domain.order.repository.OrderItemRepository;
+import com.loopers.core.domain.order.repository.OrderRepository;
+import com.loopers.core.domain.payment.Payment;
+import com.loopers.core.domain.payment.repository.PaymentRepository;
+import com.loopers.core.domain.payment.vo.PaymentFailedEvent;
+import com.loopers.core.domain.product.Product;
+import com.loopers.core.domain.product.repository.ProductRepository;
+import com.loopers.core.service.product.component.StockIncreaseFailHandler;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.event.TransactionalEventListener;
+
+import java.util.List;
+
+import static org.springframework.transaction.event.TransactionPhase.AFTER_COMMIT;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class StockIncreaseHandler {
+
+    private final ProductRepository productRepository;
+    private final PaymentRepository paymentRepository;
+    private final OrderRepository orderRepository;
+    private final OrderItemRepository orderItemRepository;
+    private final StockIncreaseFailHandler stockIncreaseFailHandler;
+
+    @Async
+    @Transactional(propagation = Propagation.REQUIRES_NEW)
+    @TransactionalEventListener(phase = AFTER_COMMIT)
+    public void handle(PaymentFailedEvent event) {
+        try {
+            Payment payment = paymentRepository.getById(event.paymentId());
+            Order order = orderRepository.getBy(payment.getOrderKey());
+
+            List<OrderItem> orderItems = orderItemRepository.findAllByOrderId(order.getId());
+            List<Product> products = orderItems.stream()
+                    .map(orderItem -> {
+                        Product product = productRepository.getByIdWithLock(orderItem.getProductId());
+
+                        return product.increaseStock(orderItem.getQuantity());
+                    }).toList();
+
+            productRepository.saveAll(products);
+        } catch (Exception exception) {
+            log.error("재고 원복 처리중 오류가 발생했습니다.", exception);
+            stockIncreaseFailHandler.handle(event, exception);
+        }
+    }
+}
diff --git a/core/service/src/main/java/com/loopers/core/service/product/component/StockIncreaseFailHandler.java b/core/service/src/main/java/com/loopers/core/service/product/component/StockIncreaseFailHandler.java
new file mode 100644
index 000000000..f351bccfb
--- /dev/null
+++ b/core/service/src/main/java/com/loopers/core/service/product/component/StockIncreaseFailHandler.java
@@ -0,0 +1,40 @@
+package com.loopers.core.service.product.component;
+
+import com.loopers.JacksonUtil;
+import com.loopers.core.domain.event.EventOutbox;
+import com.loopers.core.domain.event.repository.EventOutboxRepository;
+import com.loopers.core.domain.event.type.AggregateType;
+import com.loopers.core.domain.event.type.EventType;
+import com.loopers.core.domain.event.vo.EventPayload;
+import com.loopers.core.domain.payment.vo.PaymentFailedEvent;
+import com.loopers.core.domain.payment.vo.PaymentId;
+import com.loopers.core.domain.product.vo.StockIncreaseFailEvent;
+import com.loopers.core.service.config.RetryableExceptionsProperties;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class StockIncreaseFailHandler {
+
+    private final EventOutboxRepository eventOutboxRepository;
+    private final RetryableExceptionsProperties retryableExceptionsProperties;
+
+    public void handle(PaymentFailedEvent event, Exception exception) {
+        PaymentId paymentId = event.paymentId();
+        boolean retryable = retryableExceptionsProperties.isRetryable(exception);
+
+        eventOutboxRepository.save(
+                EventOutbox.create(
+                        AggregateType.PRODUCT,
+                        paymentId.toAggregateId(),
+                        EventType.STOCK_INCREASE_FAIL,
+                        new EventPayload(
+                                JacksonUtil.convertToString(
+                                        StockIncreaseFailEvent.create(paymentId, exception.getMessage(), retryable)
+                                )
+                        )
+                )
+        );
+    }
+}
diff --git a/core/service/product-service/src/main/java/com/loopers/core/service/product/query/GetProductDetailQuery.java b/core/service/src/main/java/com/loopers/core/service/product/query/GetProductDetailQuery.java
similarity index 100%
rename from core/service/product-service/src/main/java/com/loopers/core/service/product/query/GetProductDetailQuery.java
rename to core/service/src/main/java/com/loopers/core/service/product/query/GetProductDetailQuery.java
diff --git a/core/service/product-service/src/main/java/com/loopers/core/service/product/query/GetProductListQuery.java b/core/service/src/main/java/com/loopers/core/service/product/query/GetProductListQuery.java
similarity index 100%
rename from core/service/product-service/src/main/java/com/loopers/core/service/product/query/GetProductListQuery.java
rename to core/service/src/main/java/com/loopers/core/service/product/query/GetProductListQuery.java
diff --git a/core/service/product-service/src/main/java/com/loopers/core/service/product/query/GetProductQuery.java b/core/service/src/main/java/com/loopers/core/service/product/query/GetProductQuery.java
similarity index 100%
rename from core/service/product-service/src/main/java/com/loopers/core/service/product/query/GetProductQuery.java
rename to core/service/src/main/java/com/loopers/core/service/product/query/GetProductQuery.java
diff --git a/core/service/product-service/src/main/java/com/loopers/core/service/productlike/ProductLikeQueryService.java b/core/service/src/main/java/com/loopers/core/service/productlike/ProductLikeQueryService.java
similarity index 100%
rename from core/service/product-service/src/main/java/com/loopers/core/service/productlike/ProductLikeQueryService.java
rename to core/service/src/main/java/com/loopers/core/service/productlike/ProductLikeQueryService.java
diff --git a/core/service/product-service/src/main/java/com/loopers/core/service/productlike/ProductLikeService.java b/core/service/src/main/java/com/loopers/core/service/productlike/ProductLikeService.java
similarity index 100%
rename from core/service/product-service/src/main/java/com/loopers/core/service/productlike/ProductLikeService.java
rename to core/service/src/main/java/com/loopers/core/service/productlike/ProductLikeService.java
diff --git a/core/service/product-service/src/main/java/com/loopers/core/service/productlike/ProductLikeSyncService.java b/core/service/src/main/java/com/loopers/core/service/productlike/ProductLikeSyncService.java
similarity index 100%
rename from core/service/product-service/src/main/java/com/loopers/core/service/productlike/ProductLikeSyncService.java
rename to core/service/src/main/java/com/loopers/core/service/productlike/ProductLikeSyncService.java
diff --git a/core/service/product-service/src/main/java/com/loopers/core/service/productlike/command/ProductLikeCommand.java b/core/service/src/main/java/com/loopers/core/service/productlike/command/ProductLikeCommand.java
similarity index 100%
rename from core/service/product-service/src/main/java/com/loopers/core/service/productlike/command/ProductLikeCommand.java
rename to core/service/src/main/java/com/loopers/core/service/productlike/command/ProductLikeCommand.java
diff --git a/core/service/product-service/src/main/java/com/loopers/core/service/productlike/command/ProductUnlikeCommand.java b/core/service/src/main/java/com/loopers/core/service/productlike/command/ProductUnlikeCommand.java
similarity index 100%
rename from core/service/product-service/src/main/java/com/loopers/core/service/productlike/command/ProductUnlikeCommand.java
rename to core/service/src/main/java/com/loopers/core/service/productlike/command/ProductUnlikeCommand.java
diff --git a/core/service/product-service/src/main/java/com/loopers/core/service/productlike/component/ProductLikeCountSynchronizer.java b/core/service/src/main/java/com/loopers/core/service/productlike/component/ProductLikeCountSynchronizer.java
similarity index 100%
rename from core/service/product-service/src/main/java/com/loopers/core/service/productlike/component/ProductLikeCountSynchronizer.java
rename to core/service/src/main/java/com/loopers/core/service/productlike/component/ProductLikeCountSynchronizer.java
diff --git a/core/service/product-service/src/main/java/com/loopers/core/service/productlike/component/ProductLikeSynchronizer.java b/core/service/src/main/java/com/loopers/core/service/productlike/component/ProductLikeSynchronizer.java
similarity index 100%
rename from core/service/product-service/src/main/java/com/loopers/core/service/productlike/component/ProductLikeSynchronizer.java
rename to core/service/src/main/java/com/loopers/core/service/productlike/component/ProductLikeSynchronizer.java
diff --git a/core/service/product-service/src/main/java/com/loopers/core/service/productlike/query/GetLikeProductsListQuery.java b/core/service/src/main/java/com/loopers/core/service/productlike/query/GetLikeProductsListQuery.java
similarity index 100%
rename from core/service/product-service/src/main/java/com/loopers/core/service/productlike/query/GetLikeProductsListQuery.java
rename to core/service/src/main/java/com/loopers/core/service/productlike/query/GetLikeProductsListQuery.java
diff --git a/core/service/user-service/src/main/java/com/loopers/core/service/user/JoinUserService.java b/core/service/src/main/java/com/loopers/core/service/user/JoinUserService.java
similarity index 100%
rename from core/service/user-service/src/main/java/com/loopers/core/service/user/JoinUserService.java
rename to core/service/src/main/java/com/loopers/core/service/user/JoinUserService.java
diff --git a/core/service/user-service/src/main/java/com/loopers/core/service/user/UserPointQueryService.java b/core/service/src/main/java/com/loopers/core/service/user/UserPointQueryService.java
similarity index 100%
rename from core/service/user-service/src/main/java/com/loopers/core/service/user/UserPointQueryService.java
rename to core/service/src/main/java/com/loopers/core/service/user/UserPointQueryService.java
diff --git a/core/service/user-service/src/main/java/com/loopers/core/service/user/UserPointService.java b/core/service/src/main/java/com/loopers/core/service/user/UserPointService.java
similarity index 100%
rename from core/service/user-service/src/main/java/com/loopers/core/service/user/UserPointService.java
rename to core/service/src/main/java/com/loopers/core/service/user/UserPointService.java
diff --git a/core/service/user-service/src/main/java/com/loopers/core/service/user/UserQueryService.java b/core/service/src/main/java/com/loopers/core/service/user/UserQueryService.java
similarity index 100%
rename from core/service/user-service/src/main/java/com/loopers/core/service/user/UserQueryService.java
rename to core/service/src/main/java/com/loopers/core/service/user/UserQueryService.java
diff --git a/core/service/user-service/src/main/java/com/loopers/core/service/user/command/JoinUserCommand.java b/core/service/src/main/java/com/loopers/core/service/user/command/JoinUserCommand.java
similarity index 100%
rename from core/service/user-service/src/main/java/com/loopers/core/service/user/command/JoinUserCommand.java
rename to core/service/src/main/java/com/loopers/core/service/user/command/JoinUserCommand.java
diff --git a/core/service/user-service/src/main/java/com/loopers/core/service/user/command/UserPointChargeCommand.java b/core/service/src/main/java/com/loopers/core/service/user/command/UserPointChargeCommand.java
similarity index 100%
rename from core/service/user-service/src/main/java/com/loopers/core/service/user/command/UserPointChargeCommand.java
rename to core/service/src/main/java/com/loopers/core/service/user/command/UserPointChargeCommand.java
diff --git a/core/service/user-service/src/main/java/com/loopers/core/service/user/query/GetUserPointQuery.java b/core/service/src/main/java/com/loopers/core/service/user/query/GetUserPointQuery.java
similarity index 100%
rename from core/service/user-service/src/main/java/com/loopers/core/service/user/query/GetUserPointQuery.java
rename to core/service/src/main/java/com/loopers/core/service/user/query/GetUserPointQuery.java
diff --git a/core/service/user-service/src/main/java/com/loopers/core/service/user/query/GetUserQuery.java b/core/service/src/main/java/com/loopers/core/service/user/query/GetUserQuery.java
similarity index 100%
rename from core/service/user-service/src/main/java/com/loopers/core/service/user/query/GetUserQuery.java
rename to core/service/src/main/java/com/loopers/core/service/user/query/GetUserQuery.java
diff --git a/core/service/user-service/src/test/java/com/loopers/UserServiceTestApplication.java b/core/service/src/test/java/com/loopers/UserServiceTestApplication.java
similarity index 100%
rename from core/service/user-service/src/test/java/com/loopers/UserServiceTestApplication.java
rename to core/service/src/test/java/com/loopers/UserServiceTestApplication.java
diff --git a/core/service/product-service/src/test/java/com/loopers/core/service/ConcurrencyTestUtil.java b/core/service/src/test/java/com/loopers/core/service/ConcurrencyTestUtil.java
similarity index 100%
rename from core/service/product-service/src/test/java/com/loopers/core/service/ConcurrencyTestUtil.java
rename to core/service/src/test/java/com/loopers/core/service/ConcurrencyTestUtil.java
diff --git a/core/service/order-service/src/test/java/com/loopers/core/service/IntegrationTest.java b/core/service/src/test/java/com/loopers/core/service/IntegrationTest.java
similarity index 100%
rename from core/service/order-service/src/test/java/com/loopers/core/service/IntegrationTest.java
rename to core/service/src/test/java/com/loopers/core/service/IntegrationTest.java
diff --git a/core/service/product-service/src/test/java/com/loopers/core/service/brand/BrandQueryServiceTest.java b/core/service/src/test/java/com/loopers/core/service/brand/BrandQueryServiceTest.java
similarity index 79%
rename from core/service/product-service/src/test/java/com/loopers/core/service/brand/BrandQueryServiceTest.java
rename to core/service/src/test/java/com/loopers/core/service/brand/BrandQueryServiceTest.java
index f496fb60c..7c56a4ad1 100644
--- a/core/service/product-service/src/test/java/com/loopers/core/service/brand/BrandQueryServiceTest.java
+++ b/core/service/src/test/java/com/loopers/core/service/brand/BrandQueryServiceTest.java
@@ -1,14 +1,12 @@
 package com.loopers.core.service.brand;
 
 import com.loopers.core.domain.brand.Brand;
+import com.loopers.core.domain.brand.BrandFixture;
 import com.loopers.core.domain.brand.repository.BrandRepository;
-import com.loopers.core.domain.brand.vo.BrandDescription;
 import com.loopers.core.domain.brand.vo.BrandId;
-import com.loopers.core.domain.brand.vo.BrandName;
 import com.loopers.core.domain.error.NotFoundException;
 import com.loopers.core.service.IntegrationTest;
 import com.loopers.core.service.brand.query.GetBrandQuery;
-import org.instancio.Instancio;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
@@ -17,7 +15,6 @@
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.instancio.Select.field;
 
 class BrandQueryServiceTest extends IntegrationTest {
 
@@ -40,11 +37,7 @@ class 브랜드가_존재하는_경우 {
             @BeforeEach
             void setUp() {
                 brandId = brandRepository.save(
-                        Instancio.of(Brand.class)
-                                .set(field(Brand::getId), BrandId.empty())
-                                .set(field(Brand::getName), new BrandName("loopers"))
-                                .set(field(Brand::getDescription), new BrandDescription("education brand"))
-                                .create()
+                        BrandFixture.createWith("loopers")
                 ).getId();
             }
 
diff --git a/core/service/order-service/src/test/java/com/loopers/core/service/order/OrderQueryServiceIntegrationTest.java b/core/service/src/test/java/com/loopers/core/service/order/OrderQueryServiceIntegrationTest.java
similarity index 60%
rename from core/service/order-service/src/test/java/com/loopers/core/service/order/OrderQueryServiceIntegrationTest.java
rename to core/service/src/test/java/com/loopers/core/service/order/OrderQueryServiceIntegrationTest.java
index 1805e8bc1..d250eb7f7 100644
--- a/core/service/order-service/src/test/java/com/loopers/core/service/order/OrderQueryServiceIntegrationTest.java
+++ b/core/service/src/test/java/com/loopers/core/service/order/OrderQueryServiceIntegrationTest.java
@@ -1,38 +1,27 @@
 package com.loopers.core.service.order;
 
 import com.loopers.core.domain.brand.Brand;
+import com.loopers.core.domain.brand.BrandFixture;
 import com.loopers.core.domain.brand.repository.BrandRepository;
-import com.loopers.core.domain.brand.vo.BrandDescription;
 import com.loopers.core.domain.brand.vo.BrandId;
-import com.loopers.core.domain.brand.vo.BrandName;
-import com.loopers.core.domain.common.vo.CreatedAt;
-import com.loopers.core.domain.common.vo.DeletedAt;
-import com.loopers.core.domain.common.vo.UpdatedAt;
 import com.loopers.core.domain.error.NotFoundException;
-import com.loopers.core.domain.order.Order;
-import com.loopers.core.domain.order.OrderDetail;
-import com.loopers.core.domain.order.OrderItem;
-import com.loopers.core.domain.order.OrderListView;
+import com.loopers.core.domain.order.*;
 import com.loopers.core.domain.order.repository.OrderItemRepository;
 import com.loopers.core.domain.order.repository.OrderRepository;
 import com.loopers.core.domain.order.vo.OrderId;
-import com.loopers.core.domain.order.vo.OrderItemId;
-import com.loopers.core.domain.order.vo.Quantity;
 import com.loopers.core.domain.product.Product;
+import com.loopers.core.domain.product.ProductFixture;
 import com.loopers.core.domain.product.repository.ProductRepository;
-import com.loopers.core.domain.product.vo.ProductId;
 import com.loopers.core.domain.product.vo.ProductName;
 import com.loopers.core.domain.product.vo.ProductPrice;
 import com.loopers.core.domain.product.vo.ProductStock;
 import com.loopers.core.domain.user.User;
+import com.loopers.core.domain.user.UserFixture;
 import com.loopers.core.domain.user.repository.UserRepository;
-import com.loopers.core.domain.user.vo.UserEmail;
 import com.loopers.core.domain.user.vo.UserId;
-import com.loopers.core.domain.user.vo.UserIdentifier;
 import com.loopers.core.service.IntegrationTest;
 import com.loopers.core.service.order.query.GetOrderDetailQuery;
 import com.loopers.core.service.order.query.GetOrderListQuery;
-import org.instancio.Instancio;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
@@ -44,7 +33,6 @@
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.assertj.core.api.SoftAssertions.assertSoftly;
-import static org.instancio.Select.field;
 
 class OrderQueryServiceIntegrationTest extends IntegrationTest {
 
@@ -77,21 +65,13 @@ class 주문_리스트_조회_시 {
         @BeforeEach
         void setUp() {
             User user = userRepository.save(
-                    Instancio.of(User.class)
-                            .set(field(User::getId), UserId.empty())
-                            .set(field(User::getIdentifier), UserIdentifier.create("loopers"))
-                            .set(field(User::getEmail), new UserEmail("loopers@test.com"))
-                            .create()
+                    UserFixture.createWith("loopers", "loopers@test.com")
             );
             savedUserIdentifier = user.getIdentifier().value();
             savedUserId = user.getId();
 
             User otherUser = userRepository.save(
-                    Instancio.of(User.class)
-                            .set(field(User::getId), UserId.empty())
-                            .set(field(User::getIdentifier), UserIdentifier.create("other"))
-                            .set(field(User::getEmail), new UserEmail("other@test.com"))
-                            .create()
+                    UserFixture.createWith("other", "other@test.com")
             );
             otherUserId = otherUser.getId();
         }
@@ -102,33 +82,9 @@ class 조건에_맞는_주문이_존재하는_경우 {
 
             @BeforeEach
             void setUp() {
-                orderRepository.save(
-                        Instancio.of(Order.class)
-                                .set(field(Order::getId), OrderId.empty())
-                                .set(field(Order::getUserId), savedUserId)
-                                .set(field(Order::getCreatedAt), CreatedAt.now())
-                                .set(field(Order::getUpdatedAt), UpdatedAt.now())
-                                .set(field(Order::getDeletedAt), DeletedAt.empty())
-                                .create()
-                );
-                orderRepository.save(
-                        Instancio.of(Order.class)
-                                .set(field(Order::getId), OrderId.empty())
-                                .set(field(Order::getUserId), savedUserId)
-                                .set(field(Order::getCreatedAt), CreatedAt.now())
-                                .set(field(Order::getUpdatedAt), UpdatedAt.now())
-                                .set(field(Order::getDeletedAt), DeletedAt.empty())
-                                .create()
-                );
-                orderRepository.save(
-                        Instancio.of(Order.class)
-                                .set(field(Order::getId), OrderId.empty())
-                                .set(field(Order::getUserId), savedUserId)
-                                .set(field(Order::getCreatedAt), CreatedAt.now())
-                                .set(field(Order::getUpdatedAt), UpdatedAt.now())
-                                .set(field(Order::getDeletedAt), DeletedAt.empty())
-                                .create()
-                );
+                orderRepository.save(OrderFixture.createWith(savedUserId));
+                orderRepository.save(OrderFixture.createWith(savedUserId));
+                orderRepository.save(OrderFixture.createWith(savedUserId));
             }
 
             @Test
@@ -191,18 +147,8 @@ void setUp() {
             @Test
             @DisplayName("특정 사용자의 주문만 조회된다.")
             void 특정_사용자의_주문만_조회된다() {
-                orderRepository.save(
-                        Instancio.of(Order.class)
-                                .set(field(Order::getId), OrderId.empty())
-                                .set(field(Order::getUserId), otherUserId)
-                                .create()
-                );
-                orderRepository.save(
-                        Instancio.of(Order.class)
-                                .set(field(Order::getId), OrderId.empty())
-                                .set(field(Order::getUserId), otherUserId)
-                                .create()
-                );
+                orderRepository.save(OrderFixture.createWith(otherUserId));
+                orderRepository.save(OrderFixture.createWith(otherUserId));
 
                 GetOrderListQuery query = new GetOrderListQuery(
                         savedUserIdentifier,
@@ -279,46 +225,22 @@ class 주문_상세_조회_시 {
 
         @BeforeEach
         void setUp() {
-            Brand brand = brandRepository.save(
-                    Instancio.of(Brand.class)
-                            .set(field(Brand::getId), BrandId.empty())
-                            .set(field(Brand::getName), new BrandName("loopers"))
-                            .set(field(Brand::getDescription), new BrandDescription("education brand"))
-                            .create()
-            );
+            Brand brand = brandRepository.save(BrandFixture.createWith("loopers"));
             savedBrandId = brand.getId();
 
             User user = userRepository.save(
-                    Instancio.of(User.class)
-                            .set(field(User::getId), UserId.empty())
-                            .set(field(User::getIdentifier), UserIdentifier.create("loopers"))
-                            .set(field(User::getEmail), new UserEmail("loopers@test.com"))
-                            .create()
+                    UserFixture.createWith("loopers", "loopers@test.com")
             );
             savedUserId = user.getId();
 
             User otherUser = userRepository.save(
-                    Instancio.of(User.class)
-                            .set(field(User::getId), UserId.empty())
-                            .set(field(User::getIdentifier), UserIdentifier.create("other"))
-                            .set(field(User::getEmail), new UserEmail("other@test.com"))
-                            .create()
+                    UserFixture.createWith("other", "other@test.com")
             );
 
-            Order order = orderRepository.save(
-                    Instancio.of(Order.class)
-                            .set(field(Order::getId), OrderId.empty())
-                            .set(field(Order::getUserId), savedUserId)
-                            .create()
-            );
+            Order order = orderRepository.save(OrderFixture.createWith(savedUserId));
             savedOrderId = order.getId().value();
 
-            Order otherOrder = orderRepository.save(
-                    Instancio.of(Order.class)
-                            .set(field(Order::getId), OrderId.empty())
-                            .set(field(Order::getUserId), otherUser.getId())
-                            .create()
-            );
+            Order otherOrder = orderRepository.save(OrderFixture.createWith(otherUser.getId()));
         }
 
         @Nested
@@ -328,43 +250,26 @@ class 주문이_존재하는_경우 {
             @BeforeEach
             void setUp() {
                 Product product1 = productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getBrandId), savedBrandId)
-                                .set(field(Product::getName), new ProductName("MacBook Pro"))
-                                .set(field(Product::getPrice), new ProductPrice(new BigDecimal(1_300_000)))
-                                .set(field(Product::getStock), new ProductStock(100L))
-                                .create()
+                        ProductFixture.createWith(
+                                savedBrandId,
+                                new ProductName("MacBook Pro"),
+                                new ProductPrice(new BigDecimal(1_300_000)),
+                                new ProductStock(100L)
+                        )
                 );
 
                 Product product2 = productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getBrandId), savedBrandId)
-                                .set(field(Product::getName), new ProductName("iPad Air"))
-                                .set(field(Product::getPrice), new ProductPrice(new BigDecimal(800_000)))
-                                .set(field(Product::getStock), new ProductStock(100L))
-                                .create()
+                        ProductFixture.createWith(
+                                savedBrandId,
+                                new ProductName("iPad Air"),
+                                new ProductPrice(new BigDecimal(800_000)),
+                                new ProductStock(100L)
+                        )
                 );
 
                 OrderId orderId = new OrderId(savedOrderId);
-                orderItemRepository.save(
-                        Instancio.of(OrderItem.class)
-                                .set(field(OrderItem::getId), OrderItemId.empty())
-                                .set(field(OrderItem::getOrderId), orderId)
-                                .set(field(OrderItem::getProductId), product1.getId())
-                                .set(field(OrderItem::getQuantity), new Quantity(1L))
-                                .create()
-                );
-
-                orderItemRepository.save(
-                        Instancio.of(OrderItem.class)
-                                .set(field(OrderItem::getId), OrderItemId.empty())
-                                .set(field(OrderItem::getOrderId), orderId)
-                                .set(field(OrderItem::getProductId), product2.getId())
-                                .set(field(OrderItem::getQuantity), new Quantity(2L))
-                                .create()
-                );
+                orderItemRepository.save(OrderItemFixture.createWith(orderId, product1.getId(), 1L));
+                orderItemRepository.save(OrderItemFixture.createWith(orderId, product2.getId(), 2L));
             }
 
             @Test
diff --git a/core/service/src/test/java/com/loopers/core/service/payment/PaymentServiceIntegrationTest.java b/core/service/src/test/java/com/loopers/core/service/payment/PaymentServiceIntegrationTest.java
new file mode 100644
index 000000000..a750990ea
--- /dev/null
+++ b/core/service/src/test/java/com/loopers/core/service/payment/PaymentServiceIntegrationTest.java
@@ -0,0 +1,123 @@
+package com.loopers.core.service.payment;
+
+import com.loopers.core.domain.brand.vo.BrandId;
+import com.loopers.core.domain.order.Order;
+import com.loopers.core.domain.order.OrderFixture;
+import com.loopers.core.domain.order.OrderItemFixture;
+import com.loopers.core.domain.order.repository.OrderItemRepository;
+import com.loopers.core.domain.order.repository.OrderRepository;
+import com.loopers.core.domain.payment.Payment;
+import com.loopers.core.domain.payment.repository.PaymentRepository;
+import com.loopers.core.domain.payment.type.PaymentStatus;
+import com.loopers.core.domain.product.Product;
+import com.loopers.core.domain.product.ProductFixture;
+import com.loopers.core.domain.product.repository.ProductRepository;
+import com.loopers.core.domain.product.vo.ProductName;
+import com.loopers.core.domain.product.vo.ProductPrice;
+import com.loopers.core.domain.product.vo.ProductStock;
+import com.loopers.core.domain.user.User;
+import com.loopers.core.domain.user.UserFixture;
+import com.loopers.core.domain.user.repository.UserRepository;
+import com.loopers.core.service.ConcurrencyTestUtil;
+import com.loopers.core.service.IntegrationTest;
+import com.loopers.core.service.payment.command.PaymentCommand;
+import org.junit.jupiter.api.BeforeEach;
+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 java.math.BigDecimal;
+import java.util.List;
+
+import static org.assertj.core.api.SoftAssertions.assertSoftly;
+
+@DisplayName("결제 서비스")
+class PaymentServiceIntegrationTest extends IntegrationTest {
+
+    @Autowired
+    private PaymentService paymentService;
+
+    @Autowired
+    private OrderRepository orderRepository;
+
+    @Autowired
+    private OrderItemRepository orderItemRepository;
+
+    @Autowired
+    private ProductRepository productRepository;
+
+    @Autowired
+    private UserRepository userRepository;
+
+    @Autowired
+    private PaymentRepository paymentRepository;
+
+    @Nested
+    @DisplayName("pay() 메서드")
+    class PayMethod {
+
+        @Nested
+        @DisplayName("동시에 같은 주문에 대해 결제 요청을 하면")
+        class 동시_결제_요청 {
+
+            private Order order;
+            private User user;
+            private Product product;
+            private PaymentCommand paymentCommand;
+
+            @BeforeEach
+            void setUp() {
+                // 사용자 생성
+                user = userRepository.save(UserFixture.createWith("user123", "user@example.com"));
+
+                // 상품 생성 (가격: 1,500,000, 재고: 100,000개)
+                product = productRepository.save(
+                        ProductFixture.createWith(
+                                new BrandId("1"),
+                                new ProductName("MacBook Pro"),
+                                new ProductPrice(new BigDecimal("1500000")),
+                                new ProductStock(100_000L)
+                        )
+                );
+
+                // 주문 생성
+                order = orderRepository.save(OrderFixture.createWith(user.getId()));
+
+                // 주문 상품 생성
+                orderItemRepository.save(OrderItemFixture.createWith(order.getId(), product.getId(), 1L));
+
+                // 결제 명령 생성
+                paymentCommand = new PaymentCommand(
+                        order.getId().value(),
+                        user.getIdentifier().value(),
+                        "CREDIT",
+                        "1234567890123456",
+                        null,
+                        "CARD"
+                );
+            }
+
+            @Test
+            @DisplayName("하나의 결제만 생성된다")
+            void 하나의_결제만_생성된다() throws InterruptedException {
+                // when - 동시에 20개의 결제 요청 실행
+                List<Payment> results = ConcurrencyTestUtil.executeInParallel(
+                        20,
+                        index -> paymentService.pay(paymentCommand)
+                );
+
+                // then - 성공한 결제 1개만 반환되어야 함
+                assertSoftly(softly -> {
+                    softly.assertThat(results)
+                            .as("성공한 결제 개수")
+                            .hasSize(1);
+                    boolean paymentExists = paymentRepository.findBy(order.getOrderKey(), PaymentStatus.PENDING).isPresent();
+                    softly.assertThat(paymentExists)
+                            .as("주문의 결제 상태 존재")
+                            .isTrue();
+                });
+            }
+        }
+    }
+}
diff --git a/core/service/payment-service/src/test/java/com/loopers/core/service/payment/component/CouponDiscountStrategyTest.java b/core/service/src/test/java/com/loopers/core/service/payment/component/CouponDiscountStrategyTest.java
similarity index 70%
rename from core/service/payment-service/src/test/java/com/loopers/core/service/payment/component/CouponDiscountStrategyTest.java
rename to core/service/src/test/java/com/loopers/core/service/payment/component/CouponDiscountStrategyTest.java
index 3303e40f5..354452975 100644
--- a/core/service/payment-service/src/test/java/com/loopers/core/service/payment/component/CouponDiscountStrategyTest.java
+++ b/core/service/src/test/java/com/loopers/core/service/payment/component/CouponDiscountStrategyTest.java
@@ -1,17 +1,14 @@
 package com.loopers.core.service.payment.component;
 
 import com.loopers.core.domain.order.AmountDiscountCoupon;
+import com.loopers.core.domain.order.AmountDiscountCouponFixture;
 import com.loopers.core.domain.order.repository.CouponRepository;
 import com.loopers.core.domain.order.type.CouponStatus;
-import com.loopers.core.domain.order.vo.AmountDiscountCouponId;
-import com.loopers.core.domain.order.vo.CouponDiscountAmount;
 import com.loopers.core.domain.order.vo.CouponId;
 import com.loopers.core.domain.payment.PgClient;
 import com.loopers.core.domain.payment.vo.PayAmount;
-import com.loopers.core.domain.user.vo.UserId;
 import com.loopers.core.service.ConcurrencyTestUtil;
 import com.loopers.core.service.IntegrationTest;
-import org.instancio.Instancio;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
@@ -24,7 +21,6 @@
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.SoftAssertions.assertSoftly;
-import static org.instancio.Select.field;
 
 @DisplayName("쿠폰 할인전략")
 class CouponDiscountStrategyTest extends IntegrationTest {
@@ -51,13 +47,7 @@ class couponExist {
             @BeforeEach
             void setUp() {
                 AmountDiscountCoupon coupon = (AmountDiscountCoupon) couponRepository.save(
-                        Instancio.of(AmountDiscountCoupon.class)
-                                .set(field(AmountDiscountCoupon::getCouponId), CouponId.empty())
-                                .set(field(AmountDiscountCoupon::getId), AmountDiscountCouponId.empty())
-                                .set(field(AmountDiscountCoupon::getUserId), new UserId("1"))
-                                .set(field(AmountDiscountCoupon::getAmount), new CouponDiscountAmount(new BigDecimal(1000)))
-                                .set(field(AmountDiscountCoupon::getStatus), CouponStatus.AVAILABLE)
-                                .create()
+                        AmountDiscountCouponFixture.createWith(CouponStatus.AVAILABLE)
                 );
                 couponId = coupon.getCouponId();
             }
@@ -86,13 +76,7 @@ class concurrentlyUseCoupon {
             @BeforeEach
             void setUp() {
                 AmountDiscountCoupon coupon = (AmountDiscountCoupon) couponRepository.save(
-                        Instancio.of(AmountDiscountCoupon.class)
-                                .set(field(AmountDiscountCoupon::getCouponId), CouponId.empty())
-                                .set(field(AmountDiscountCoupon::getId), AmountDiscountCouponId.empty())
-                                .set(field(AmountDiscountCoupon::getUserId), new UserId("1"))
-                                .set(field(AmountDiscountCoupon::getAmount), new CouponDiscountAmount(new BigDecimal(1000)))
-                                .set(field(AmountDiscountCoupon::getStatus), CouponStatus.AVAILABLE)
-                                .create()
+                        AmountDiscountCouponFixture.createWith(CouponStatus.AVAILABLE)
                 );
                 couponId = coupon.getCouponId();
             }
diff --git a/core/service/src/test/java/com/loopers/core/service/payment/component/FailedPaymentStrategyIntegrationTest.java b/core/service/src/test/java/com/loopers/core/service/payment/component/FailedPaymentStrategyIntegrationTest.java
new file mode 100644
index 000000000..06c8874e8
--- /dev/null
+++ b/core/service/src/test/java/com/loopers/core/service/payment/component/FailedPaymentStrategyIntegrationTest.java
@@ -0,0 +1,203 @@
+package com.loopers.core.service.payment.component;
+
+import com.loopers.core.domain.brand.vo.BrandId;
+import com.loopers.core.domain.order.Order;
+import com.loopers.core.domain.order.OrderFixture;
+import com.loopers.core.domain.order.OrderItemFixture;
+import com.loopers.core.domain.order.repository.OrderItemRepository;
+import com.loopers.core.domain.order.repository.OrderRepository;
+import com.loopers.core.domain.order.vo.Quantity;
+import com.loopers.core.domain.payment.Payment;
+import com.loopers.core.domain.payment.PaymentFixture;
+import com.loopers.core.domain.payment.PgPayment;
+import com.loopers.core.domain.payment.PgPaymentFixture;
+import com.loopers.core.domain.payment.repository.PaymentRepository;
+import com.loopers.core.domain.payment.vo.FailedReason;
+import com.loopers.core.domain.product.Product;
+import com.loopers.core.domain.product.ProductFixture;
+import com.loopers.core.domain.product.repository.ProductRepository;
+import com.loopers.core.domain.product.vo.ProductName;
+import com.loopers.core.domain.product.vo.ProductPrice;
+import com.loopers.core.domain.product.vo.ProductStock;
+import com.loopers.core.domain.user.User;
+import com.loopers.core.domain.user.UserFixture;
+import com.loopers.core.domain.user.repository.UserRepository;
+import com.loopers.core.service.ConcurrencyTestUtil;
+import com.loopers.core.service.IntegrationTest;
+import org.junit.jupiter.api.BeforeEach;
+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 java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.SoftAssertions.assertSoftly;
+
+@DisplayName("결제 실패 전략 통합 테스트")
+class FailedPaymentStrategyIntegrationTest extends IntegrationTest {
+
+    @Autowired
+    private FailedPaymentStrategy failedPaymentStrategy;
+
+    @Autowired
+    private OrderRepository orderRepository;
+
+    @Autowired
+    private OrderItemRepository orderItemRepository;
+
+    @Autowired
+    private ProductRepository productRepository;
+
+    @Autowired
+    private UserRepository userRepository;
+
+    @Autowired
+    private PaymentRepository paymentRepository;
+
+    private User testUser;
+    private Order testOrder;
+    private Product testProduct;
+
+    @BeforeEach
+    void setUp() {
+        // 사용자 생성
+        testUser = userRepository.save(UserFixture.create());
+
+        // 상품 생성 (재고: 1,000개)
+        testProduct = productRepository.save(
+                ProductFixture.createWith(
+                        new BrandId("1"),
+                        new ProductName("테스트 상품"),
+                        new ProductPrice(new BigDecimal("10000")),
+                        new ProductStock(1000L)
+                )
+        );
+
+        // 주문 생성
+        testOrder = orderRepository.save(OrderFixture.createWith(testUser.getId()));
+    }
+
+    @Nested
+    @DisplayName("pay 메서드 - 결제 실패 시 재고 복구")
+    class PayMethod {
+
+        @Test
+        @DisplayName("결제 실패 시 차감된 재고를 다시 증가시킨다")
+        void shouldIncreaseStockWhenPaymentFails() {
+            // Given
+            long initialStock = testProduct.getStock().value();
+            FailedReason failedReason = new FailedReason("결제 게이트웨이 오류");
+
+            // 주문 상품 생성
+            orderItemRepository.save(
+                    OrderItemFixture.createWith(testOrder.getId(), testProduct.getId(), 10L)
+            );
+
+            Product decreasedProduct = testProduct.decreaseStock(new Quantity(10L));
+            productRepository.save(decreasedProduct);
+
+            Payment savedPayment = paymentRepository.save(
+                    PaymentFixture.createWith(testOrder.getOrderKey(), testUser.getId())
+            );
+
+            PgPayment pgPayment = PgPaymentFixture.createWith(savedPayment.getId());
+
+            // When
+            failedPaymentStrategy.pay(pgPayment, failedReason);
+
+            // Then
+            Product restoredProduct = productRepository.findById(testProduct.getId()).orElseThrow();
+            Payment updatedPayment = paymentRepository.getById(savedPayment.getId());
+
+            assertSoftly(softly -> {
+                softly.assertThat(restoredProduct.getStock().value())
+                        .as("재고가 원래 상태로 복구되어야 함")
+                        .isEqualTo(initialStock);
+                softly.assertThat(updatedPayment.getFailedReason().value())
+                        .as("결제의 실패 이유가 저장되어야 함")
+                        .isEqualTo("결제 게이트웨이 오류");
+            });
+        }
+
+        @Test
+        @DisplayName("여러 상품의 재고를 모두 정확하게 복구한다")
+        void shouldRestoreStockForMultipleItems() {
+            // Given
+            Product product2 = productRepository.save(
+                    ProductFixture.createWith(
+                            new BrandId("2"),
+                            new ProductName("테스트 상품 2"),
+                            new ProductPrice(new BigDecimal("15000")),
+                            new ProductStock(1000L)
+                    )
+            );
+
+            // 주문 상품 생성
+            orderItemRepository.save(OrderItemFixture.createWith(testOrder.getId(), testProduct.getId(), 10L));
+            orderItemRepository.save(OrderItemFixture.createWith(testOrder.getId(), product2.getId(), 20L));
+
+            long product1InitialStock = testProduct.getStock().value();
+            long product2InitialStock = product2.getStock().value();
+
+            Product decreasedProduct1 = testProduct.decreaseStock(new Quantity(10L));
+            Product decreasedProduct2 = product2.decreaseStock(new Quantity(20L));
+            productRepository.saveAll(List.of(decreasedProduct1, decreasedProduct2));
+
+            Payment savedPayment = paymentRepository.save(PaymentFixture.createWith(testOrder.getOrderKey(), testUser.getId()));
+
+            PgPayment pgPayment = PgPaymentFixture.createWith(savedPayment.getId());
+
+            FailedReason failedReason = new FailedReason("결제 처리 중 오류 발생");
+
+            // When
+            failedPaymentStrategy.pay(pgPayment, failedReason);
+
+            // Then
+            Product restoredProduct1 = productRepository.findById(testProduct.getId()).orElseThrow();
+            Product restoredProduct2 = productRepository.findById(product2.getId()).orElseThrow();
+
+            assertSoftly(softly -> {
+                softly.assertThat(restoredProduct1.getStock().value())
+                        .as("첫 번째 상품 재고가 원래대로 복구되어야 함")
+                        .isEqualTo(product1InitialStock);
+                softly.assertThat(restoredProduct2.getStock().value())
+                        .as("두 번째 상품 재고가 원래대로 복구되어야 함")
+                        .isEqualTo(product2InitialStock);
+            });
+        }
+
+        @Test
+        @DisplayName("결제 실패 시 올바른 실패 이유를 저장한다")
+        void shouldSaveCorrectFailedReasonInPayment() {
+            // Given
+            String expectedReason = "신용카드 한도 초과";
+            FailedReason failedReason = new FailedReason(expectedReason);
+
+            // 주문 상품 생성
+            orderItemRepository.save(
+                    OrderItemFixture.createWith(testOrder.getId(), testProduct.getId(), 10L)
+            );
+
+            Product decreasedProduct = testProduct.decreaseStock(new Quantity(10L));
+            productRepository.save(decreasedProduct);
+
+            Payment savedPayment = paymentRepository.save(PaymentFixture.createWith(testOrder.getOrderKey(), testUser.getId()));
+
+            PgPayment pgPayment = PgPaymentFixture.createWith(savedPayment.getId());
+
+
+            // When
+            failedPaymentStrategy.pay(pgPayment, failedReason);
+
+            // Then
+            Payment updatedPayment = paymentRepository.getById(savedPayment.getId());
+            assertThat(updatedPayment.getFailedReason().value())
+                    .as("결제 객체에 올바른 실패 이유가 저장되어야 함")
+                    .isEqualTo(expectedReason);
+        }
+    }
+}
diff --git a/core/service/payment-service/src/test/java/com/loopers/core/service/payment/component/OrderLineAllocatorIntegrationTest.java b/core/service/src/test/java/com/loopers/core/service/payment/component/OrderLineAllocatorIntegrationTest.java
similarity index 54%
rename from core/service/payment-service/src/test/java/com/loopers/core/service/payment/component/OrderLineAllocatorIntegrationTest.java
rename to core/service/src/test/java/com/loopers/core/service/payment/component/OrderLineAllocatorIntegrationTest.java
index 68be5678c..a2a507b2e 100644
--- a/core/service/payment-service/src/test/java/com/loopers/core/service/payment/component/OrderLineAllocatorIntegrationTest.java
+++ b/core/service/src/test/java/com/loopers/core/service/payment/component/OrderLineAllocatorIntegrationTest.java
@@ -1,27 +1,23 @@
 package com.loopers.core.service.payment.component;
 
 import com.loopers.core.domain.brand.vo.BrandId;
-import com.loopers.core.domain.common.vo.CreatedAt;
-import com.loopers.core.domain.common.vo.DeletedAt;
-import com.loopers.core.domain.common.vo.UpdatedAt;
 import com.loopers.core.domain.order.Order;
+import com.loopers.core.domain.order.OrderFixture;
 import com.loopers.core.domain.order.OrderItem;
+import com.loopers.core.domain.order.OrderItemFixture;
 import com.loopers.core.domain.order.repository.OrderItemRepository;
 import com.loopers.core.domain.order.repository.OrderRepository;
-import com.loopers.core.domain.order.vo.OrderId;
-import com.loopers.core.domain.order.vo.OrderItemId;
-import com.loopers.core.domain.order.vo.Quantity;
 import com.loopers.core.domain.product.Product;
+import com.loopers.core.domain.product.ProductFixture;
 import com.loopers.core.domain.product.repository.ProductRepository;
-import com.loopers.core.domain.product.vo.*;
+import com.loopers.core.domain.product.vo.ProductName;
+import com.loopers.core.domain.product.vo.ProductPrice;
+import com.loopers.core.domain.product.vo.ProductStock;
 import com.loopers.core.domain.user.User;
+import com.loopers.core.domain.user.UserFixture;
 import com.loopers.core.domain.user.repository.UserRepository;
-import com.loopers.core.domain.user.vo.UserEmail;
-import com.loopers.core.domain.user.vo.UserId;
-import com.loopers.core.domain.user.vo.UserIdentifier;
 import com.loopers.core.service.ConcurrencyTestUtil;
 import com.loopers.core.service.IntegrationTest;
-import org.instancio.Instancio;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
@@ -32,7 +28,6 @@
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.SoftAssertions.assertSoftly;
-import static org.instancio.Select.field;
 
 @DisplayName("주문 라인 할당자 통합 테스트")
 class OrderLineAllocatorIntegrationTest extends IntegrationTest {
@@ -62,36 +57,20 @@ class AllocateMethod {
         @BeforeEach
         void setUp() {
             // 사용자 생성
-            User testUser = userRepository.save(
-                    Instancio.of(User.class)
-                            .set(field(User::getId), UserId.empty())
-                            .set(field(User::getIdentifier), UserIdentifier.create("testuser"))
-                            .set(field(User::getEmail), new UserEmail("test@example.com"))
-                            .create()
-            );
+            User testUser = userRepository.save(UserFixture.create());
 
             // 상품 생성 (가격: 10,000, 재고: 1,000개)
             testProduct = productRepository.save(
-                    Instancio.of(Product.class)
-                            .set(field(Product::getId), ProductId.empty())
-                            .set(field(Product::getBrandId), new BrandId("1"))
-                            .set(field(Product::getName), new ProductName("테스트 상품"))
-                            .set(field(Product::getPrice), new ProductPrice(new BigDecimal("10000")))
-                            .set(field(Product::getStock), new ProductStock(1000L))
-                            .set(field(Product::getLikeCount), ProductLikeCount.init())
-                            .create()
+                    ProductFixture.createWith(
+                            new BrandId("1"),
+                            new ProductName("테스트 상품"),
+                            new ProductPrice(new BigDecimal("10000")),
+                            new ProductStock(1000L)
+                    )
             );
 
             // 주문 생성
-            testOrder = orderRepository.save(
-                    Instancio.of(Order.class)
-                            .set(field(Order::getId), OrderId.empty())
-                            .set(field(Order::getUserId), testUser.getId())
-                            .set(field(Order::getCreatedAt), CreatedAt.now())
-                            .set(field(Order::getUpdatedAt), UpdatedAt.now())
-                            .set(field(Order::getDeletedAt), DeletedAt.empty())
-                            .create()
-            );
+            testOrder = orderRepository.save(OrderFixture.createWith(testUser.getId()));
         }
 
         @Test
@@ -101,12 +80,11 @@ void shouldDecreaseStockCorrectlyForSingleOrderItem() {
             long initialStock = testProduct.getStock().value();
             long quantityToAllocate = 10L;
 
-            OrderItem orderItem = Instancio.of(OrderItem.class)
-                    .set(field(OrderItem::getId), OrderItemId.empty())
-                    .set(field(OrderItem::getOrderId), testOrder.getId())
-                    .set(field(OrderItem::getProductId), testProduct.getId())
-                    .set(field(OrderItem::getQuantity), new Quantity(quantityToAllocate))
-                    .create();
+            OrderItem orderItem = OrderItemFixture.createWith(
+                    testOrder.getId(),
+                    testProduct.getId(),
+                    quantityToAllocate
+            );
 
             // When
             orderLineAllocator.allocate(orderItem);
@@ -124,19 +102,17 @@ void shouldDecreaseStockCorrectlyForMultipleOrderItems() {
             // Given
             long initialStock = testProduct.getStock().value();
 
-            OrderItem orderItem1 = Instancio.of(OrderItem.class)
-                    .set(field(OrderItem::getId), OrderItemId.empty())
-                    .set(field(OrderItem::getOrderId), testOrder.getId())
-                    .set(field(OrderItem::getProductId), testProduct.getId())
-                    .set(field(OrderItem::getQuantity), new Quantity(10L))
-                    .create();
+            OrderItem orderItem1 = OrderItemFixture.createWith(
+                    testOrder.getId(),
+                    testProduct.getId(),
+                    10L
+            );
 
-            OrderItem orderItem2 = Instancio.of(OrderItem.class)
-                    .set(field(OrderItem::getId), OrderItemId.empty())
-                    .set(field(OrderItem::getOrderId), testOrder.getId())
-                    .set(field(OrderItem::getProductId), testProduct.getId())
-                    .set(field(OrderItem::getQuantity), new Quantity(20L))
-                    .create();
+            OrderItem orderItem2 = OrderItemFixture.createWith(
+                    testOrder.getId(),
+                    testProduct.getId(),
+                    20L
+            );
 
             // When
             orderLineAllocator.allocate(orderItem1);
@@ -153,12 +129,11 @@ void shouldDecreaseStockCorrectlyForMultipleOrderItems() {
         @DisplayName("주문 상품을 할당하면 데이터베이스에 저장된다")
         void shouldSaveOrderItemToDatabase() {
             // Given
-            OrderItem orderItem = Instancio.of(OrderItem.class)
-                    .set(field(OrderItem::getId), OrderItemId.empty())
-                    .set(field(OrderItem::getOrderId), testOrder.getId())
-                    .set(field(OrderItem::getProductId), testProduct.getId())
-                    .set(field(OrderItem::getQuantity), new Quantity(5L))
-                    .create();
+            OrderItem orderItem = OrderItemFixture.createWith(
+                    testOrder.getId(),
+                    testProduct.getId(),
+                    5L
+            );
 
             // When
             orderLineAllocator.allocate(orderItem);
@@ -185,36 +160,20 @@ class ConcurrencyControl {
         @BeforeEach
         void setUp() {
             // 사용자 생성
-            User testUser = userRepository.save(
-                    Instancio.of(User.class)
-                            .set(field(User::getId), UserId.empty())
-                            .set(field(User::getIdentifier), UserIdentifier.create("testuser"))
-                            .set(field(User::getEmail), new UserEmail("test@example.com"))
-                            .create()
-            );
+            User testUser = userRepository.save(UserFixture.create());
 
             // 상품 생성 (가격: 10,000, 재고: 1,000개)
             testProduct = productRepository.save(
-                    Instancio.of(Product.class)
-                            .set(field(Product::getId), ProductId.empty())
-                            .set(field(Product::getBrandId), new BrandId("1"))
-                            .set(field(Product::getName), new ProductName("테스트 상품"))
-                            .set(field(Product::getPrice), new ProductPrice(new BigDecimal("10000")))
-                            .set(field(Product::getStock), new ProductStock(1000L))
-                            .set(field(Product::getLikeCount), ProductLikeCount.init())
-                            .create()
+                    ProductFixture.createWith(
+                            new BrandId("1"),
+                            new ProductName("테스트 상품"),
+                            new ProductPrice(new BigDecimal("10000")),
+                            new ProductStock(1000L)
+                    )
             );
 
             // 주문 생성
-            testOrder = orderRepository.save(
-                    Instancio.of(Order.class)
-                            .set(field(Order::getId), OrderId.empty())
-                            .set(field(Order::getUserId), testUser.getId())
-                            .set(field(Order::getCreatedAt), CreatedAt.now())
-                            .set(field(Order::getUpdatedAt), UpdatedAt.now())
-                            .set(field(Order::getDeletedAt), DeletedAt.empty())
-                            .create()
-            );
+            testOrder = orderRepository.save(OrderFixture.createWith(testUser.getId()));
         }
 
         @Test
@@ -227,12 +186,11 @@ void shouldMaintainStockConsistencyUnderConcurrentAllocations() throws Interrupt
 
             java.util.List<OrderItem> orderItems = new java.util.ArrayList<>();
             for (int i = 0; i < concurrentAllocationCount; i++) {
-                OrderItem orderItem = Instancio.of(OrderItem.class)
-                        .set(field(OrderItem::getId), OrderItemId.empty())
-                        .set(field(OrderItem::getOrderId), testOrder.getId())
-                        .set(field(OrderItem::getProductId), testProduct.getId())
-                        .set(field(OrderItem::getQuantity), new Quantity(quantityPerAllocation))
-                        .create();
+                OrderItem orderItem = OrderItemFixture.createWith(
+                        testOrder.getId(),
+                        testProduct.getId(),
+                        quantityPerAllocation
+                );
                 orderItems.add(orderItem);
             }
 
@@ -265,12 +223,11 @@ void shouldMaintainStockConsistencyWith10ConcurrentAllocations() throws Interrup
 
             java.util.List<OrderItem> orderItems = new java.util.ArrayList<>();
             for (int i = 0; i < concurrentAllocationCount; i++) {
-                OrderItem orderItem = Instancio.of(OrderItem.class)
-                        .set(field(OrderItem::getId), OrderItemId.empty())
-                        .set(field(OrderItem::getOrderId), testOrder.getId())
-                        .set(field(OrderItem::getProductId), testProduct.getId())
-                        .set(field(OrderItem::getQuantity), new Quantity(quantityPerAllocation))
-                        .create();
+                OrderItem orderItem = OrderItemFixture.createWith(
+                        testOrder.getId(),
+                        testProduct.getId(),
+                        quantityPerAllocation
+                );
                 orderItems.add(orderItem);
             }
 
@@ -297,36 +254,32 @@ void shouldMaintainStockConsistencyWith10ConcurrentAllocations() throws Interrup
         @DisplayName("서로 다른 상품에 대한 동시 할당이 발생하면 각 상품의 재고가 독립적으로 관리된다")
         void shouldManageStockIndependentlyForDifferentProducts() throws InterruptedException {
             // Given
-            Product p1 = Instancio.of(Product.class)
-                    .set(field(Product::getId), ProductId.empty())
-                    .set(field(Product::getBrandId), new BrandId("1"))
-                    .set(field(Product::getName), new ProductName("테스트 상품 1"))
-                    .set(field(Product::getPrice), new ProductPrice(new BigDecimal("10000")))
-                    .set(field(Product::getStock), new ProductStock(1000L))
-                    .set(field(Product::getLikeCount), ProductLikeCount.init())
-                    .create();
-
-            Product p2 = Instancio.of(Product.class)
-                    .set(field(Product::getId), ProductId.empty())
-                    .set(field(Product::getBrandId), new BrandId("2"))
-                    .set(field(Product::getName), new ProductName("테스트 상품 2"))
-                    .set(field(Product::getPrice), new ProductPrice(new BigDecimal("15000")))
-                    .set(field(Product::getStock), new ProductStock(800L))
-                    .set(field(Product::getLikeCount), ProductLikeCount.init())
-                    .create();
-
-            Product p3 = Instancio.of(Product.class)
-                    .set(field(Product::getId), ProductId.empty())
-                    .set(field(Product::getBrandId), new BrandId("3"))
-                    .set(field(Product::getName), new ProductName("테스트 상품 3"))
-                    .set(field(Product::getPrice), new ProductPrice(new BigDecimal("20000")))
-                    .set(field(Product::getStock), new ProductStock(600L))
-                    .set(field(Product::getLikeCount), ProductLikeCount.init())
-                    .create();
-
-            Product product1 = productRepository.save(p1);
-            Product product2 = productRepository.save(p2);
-            Product product3 = productRepository.save(p3);
+            Product product1 = productRepository.save(
+                    ProductFixture.createWith(
+                            new BrandId("1"),
+                            new ProductName("테스트 상품 1"),
+                            new ProductPrice(new BigDecimal("10000")),
+                            new ProductStock(1000L)
+                    )
+            );
+
+            Product product2 = productRepository.save(
+                    ProductFixture.createWith(
+                            new BrandId("2"),
+                            new ProductName("테스트 상품 2"),
+                            new ProductPrice(new BigDecimal("15000")),
+                            new ProductStock(800L)
+                    )
+            );
+
+            Product product3 = productRepository.save(
+                    ProductFixture.createWith(
+                            new BrandId("3"),
+                            new ProductName("테스트 상품 3"),
+                            new ProductPrice(new BigDecimal("20000")),
+                            new ProductStock(600L)
+                    )
+            );
 
             long product1InitialStock = product1.getStock().value();
             long product2InitialStock = product2.getStock().value();
@@ -342,12 +295,11 @@ void shouldManageStockIndependentlyForDifferentProducts() throws InterruptedExce
                     default -> product3;
                 };
 
-                OrderItem orderItem = Instancio.of(OrderItem.class)
-                        .set(field(OrderItem::getId), OrderItemId.empty())
-                        .set(field(OrderItem::getOrderId), testOrder.getId())
-                        .set(field(OrderItem::getProductId), targetProduct.getId())
-                        .set(field(OrderItem::getQuantity), new Quantity(10L))
-                        .create();
+                OrderItem orderItem = OrderItemFixture.createWith(
+                        testOrder.getId(),
+                        targetProduct.getId(),
+                        10L
+                );
                 orderItems.add(orderItem);
             }
 
diff --git a/core/service/payment-service/src/test/java/com/loopers/core/service/payment/component/PayAmountDiscountStrategySelectorTest.java b/core/service/src/test/java/com/loopers/core/service/payment/component/PayAmountDiscountStrategySelectorTest.java
similarity index 100%
rename from core/service/payment-service/src/test/java/com/loopers/core/service/payment/component/PayAmountDiscountStrategySelectorTest.java
rename to core/service/src/test/java/com/loopers/core/service/payment/component/PayAmountDiscountStrategySelectorTest.java
diff --git a/core/service/payment-service/src/test/java/com/loopers/core/service/payment/component/PaymentCallbackStrategySelectorTest.java b/core/service/src/test/java/com/loopers/core/service/payment/component/PaymentCallbackStrategySelectorTest.java
similarity index 91%
rename from core/service/payment-service/src/test/java/com/loopers/core/service/payment/component/PaymentCallbackStrategySelectorTest.java
rename to core/service/src/test/java/com/loopers/core/service/payment/component/PaymentCallbackStrategySelectorTest.java
index 0ece8c2cb..d72bea347 100644
--- a/core/service/payment-service/src/test/java/com/loopers/core/service/payment/component/PaymentCallbackStrategySelectorTest.java
+++ b/core/service/src/test/java/com/loopers/core/service/payment/component/PaymentCallbackStrategySelectorTest.java
@@ -4,6 +4,7 @@
 import com.loopers.core.domain.payment.Payment;
 import com.loopers.core.domain.payment.repository.PaymentRepository;
 import com.loopers.core.domain.payment.type.PaymentStatus;
+import com.loopers.core.domain.payment.type.PgPaymentStatus;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
@@ -51,7 +52,7 @@ class WhenHasSuccessfulPayment {
             void shouldReturnDuplicateSuccessPaymentStrategy() {
                 // Given
                 OrderKey orderKey = new OrderKey("order-1");
-                PaymentStatus status = PaymentStatus.SUCCESS;
+                PgPaymentStatus status = PgPaymentStatus.SUCCESS;
                 Payment successfulPayment = org.mockito.Mockito.mock(Payment.class);
 
                 when(paymentRepository.findBy(orderKey, PaymentStatus.SUCCESS))
@@ -70,7 +71,7 @@ void shouldReturnDuplicateSuccessPaymentStrategy() {
             void shouldReturnDuplicateSuccessStrategyRegardlessOfStatus() {
                 // Given
                 OrderKey orderKey = new OrderKey("order-1");
-                PaymentStatus status = PaymentStatus.FAILED;
+                PgPaymentStatus status = PgPaymentStatus.FAILED;
                 Payment successfulPayment = org.mockito.Mockito.mock(Payment.class);
 
                 when(paymentRepository.findBy(orderKey, PaymentStatus.SUCCESS))
@@ -93,7 +94,7 @@ class WhenPaymentFailedAndNoSuccessfulPayment {
             void shouldReturnFailedPaymentStrategy() {
                 // Given
                 OrderKey orderKey = new OrderKey("order-2");
-                PaymentStatus status = PaymentStatus.FAILED;
+                PgPaymentStatus status = PgPaymentStatus.FAILED;
 
                 when(paymentRepository.findBy(orderKey, PaymentStatus.SUCCESS))
                         .thenReturn(Optional.empty()); // 성공한 결제 없음
@@ -111,7 +112,7 @@ void shouldReturnFailedPaymentStrategy() {
             void shouldReturnFailedPaymentStrategyForPendingStatus() {
                 // Given
                 OrderKey orderKey = new OrderKey("order-3");
-                PaymentStatus status = PaymentStatus.PENDING;
+                PgPaymentStatus status = PgPaymentStatus.PENDING;
 
                 when(paymentRepository.findBy(orderKey, PaymentStatus.SUCCESS))
                         .thenReturn(Optional.empty());
@@ -133,7 +134,7 @@ class WhenPaymentSuccessfulAndNoSuccessfulPayment {
             void shouldReturnSuccessfulPaymentStrategy() {
                 // Given
                 OrderKey orderKey = new OrderKey("order-4");
-                PaymentStatus status = PaymentStatus.SUCCESS;
+                PgPaymentStatus status = PgPaymentStatus.SUCCESS;
 
                 when(paymentRepository.findBy(orderKey, PaymentStatus.SUCCESS))
                         .thenReturn(Optional.empty()); // 성공한 결제 없음
@@ -163,11 +164,11 @@ void shouldPrioritizeDuplicateSuccessOverStatus() {
 
                 // When - 현재 상태가 SUCCESS인 경우
                 PaymentCallbackStrategy strategyForSuccess =
-                        strategySelector.select(orderKey, PaymentStatus.SUCCESS);
+                        strategySelector.select(orderKey, PgPaymentStatus.SUCCESS);
 
                 // When - 현재 상태가 FAILED인 경우
                 PaymentCallbackStrategy strategyForFailed =
-                        strategySelector.select(orderKey, PaymentStatus.FAILED);
+                        strategySelector.select(orderKey, PgPaymentStatus.FAILED);
 
                 // Then - 둘 다 DuplicateSuccessPaymentStrategy 반환
                 assertThat(strategyForSuccess).isEqualTo(duplicateSuccessPaymentStrategy);
@@ -185,11 +186,11 @@ void shouldSelectStrategyByStatusWhenNoSuccessfulPayment() {
 
                 // When - 현재 상태가 SUCCESS인 경우
                 PaymentCallbackStrategy strategyForSuccess =
-                        strategySelector.select(orderKey, PaymentStatus.SUCCESS);
+                        strategySelector.select(orderKey, PgPaymentStatus.SUCCESS);
 
                 // When - 현재 상태가 FAILED인 경우
                 PaymentCallbackStrategy strategyForFailed =
-                        strategySelector.select(orderKey, PaymentStatus.FAILED);
+                        strategySelector.select(orderKey, PgPaymentStatus.FAILED);
 
                 // Then - 각각 다른 전략 반환
                 assertThat(strategyForSuccess).isEqualTo(successfulPaymentStrategy);
diff --git a/core/service/product-service/src/test/java/com/loopers/core/service/product/ProductQueryServiceTest.java b/core/service/src/test/java/com/loopers/core/service/product/ProductQueryServiceTest.java
similarity index 69%
rename from core/service/product-service/src/test/java/com/loopers/core/service/product/ProductQueryServiceTest.java
rename to core/service/src/test/java/com/loopers/core/service/product/ProductQueryServiceTest.java
index a38cf3339..f87eded73 100644
--- a/core/service/product-service/src/test/java/com/loopers/core/service/product/ProductQueryServiceTest.java
+++ b/core/service/src/test/java/com/loopers/core/service/product/ProductQueryServiceTest.java
@@ -1,17 +1,15 @@
 package com.loopers.core.service.product;
 
 import com.loopers.core.domain.brand.Brand;
+import com.loopers.core.domain.brand.BrandFixture;
 import com.loopers.core.domain.brand.repository.BrandRepository;
-import com.loopers.core.domain.brand.vo.BrandDescription;
 import com.loopers.core.domain.brand.vo.BrandId;
-import com.loopers.core.domain.brand.vo.BrandName;
-import com.loopers.core.domain.common.vo.DeletedAt;
 import com.loopers.core.domain.error.NotFoundException;
 import com.loopers.core.domain.product.Product;
 import com.loopers.core.domain.product.ProductDetail;
+import com.loopers.core.domain.product.ProductFixture;
 import com.loopers.core.domain.product.ProductListView;
 import com.loopers.core.domain.product.repository.ProductRepository;
-import com.loopers.core.domain.product.vo.ProductId;
 import com.loopers.core.domain.product.vo.ProductName;
 import com.loopers.core.domain.product.vo.ProductPrice;
 import com.loopers.core.domain.product.vo.ProductStock;
@@ -19,7 +17,6 @@
 import com.loopers.core.service.product.query.GetProductDetailQuery;
 import com.loopers.core.service.product.query.GetProductListQuery;
 import com.loopers.core.service.product.query.GetProductQuery;
-import org.instancio.Instancio;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
@@ -31,7 +28,6 @@
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.assertj.core.api.SoftAssertions.assertSoftly;
-import static org.instancio.Select.field;
 
 class ProductQueryServiceTest extends IntegrationTest {
 
@@ -53,22 +49,10 @@ class 상품_리스트_조회_시 {
 
         @BeforeEach
         void setUp() {
-            Brand brand = brandRepository.save(
-                    Instancio.of(Brand.class)
-                            .set(field(Brand::getId), BrandId.empty())
-                            .set(field(Brand::getName), new BrandName("loopers"))
-                            .set(field(Brand::getDescription), new BrandDescription("education brand"))
-                            .create()
-            );
+            Brand brand = brandRepository.save(BrandFixture.createWith("loopers"));
             savedBrandId = brand.getId();
 
-            Brand otherBrand = brandRepository.save(
-                    Instancio.of(Brand.class)
-                            .set(field(Brand::getId), BrandId.empty())
-                            .set(field(Brand::getName), new BrandName("other"))
-                            .set(field(Brand::getDescription), new BrandDescription("other brand"))
-                            .create()
-            );
+            Brand otherBrand = brandRepository.save(BrandFixture.createWith("other"));
             otherBrandId = otherBrand.getId();
         }
 
@@ -79,34 +63,28 @@ class 조건에_맞는_상품이_존재하는_경우 {
             @BeforeEach
             void setUp() {
                 productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getBrandId), savedBrandId)
-                                .set(field(Product::getName), new ProductName("MacBook Pro"))
-                                .set(field(Product::getPrice), new ProductPrice(new BigDecimal(1_300_000)))
-                                .set(field(Product::getStock), new ProductStock(100_000L))
-                                .set(field(Product::getDeletedAt), DeletedAt.empty())
-                                .create()
+                        ProductFixture.createWith(
+                                savedBrandId,
+                                new ProductName("MacBook Pro"),
+                                new ProductPrice(new BigDecimal(1_300_000)),
+                                new ProductStock(100_000L)
+                        )
                 );
                 productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getBrandId), savedBrandId)
-                                .set(field(Product::getName), new ProductName("iPad Air"))
-                                .set(field(Product::getPrice), new ProductPrice(new BigDecimal(800_000)))
-                                .set(field(Product::getStock), new ProductStock(100_000L))
-                                .set(field(Product::getDeletedAt), DeletedAt.empty())
-                                .create()
+                        ProductFixture.createWith(
+                                savedBrandId,
+                                new ProductName("iPad Air"),
+                                new ProductPrice(new BigDecimal(800_000)),
+                                new ProductStock(100_000L)
+                        )
                 );
                 productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getBrandId), savedBrandId)
-                                .set(field(Product::getName), new ProductName("iPhone 15"))
-                                .set(field(Product::getPrice), new ProductPrice(new BigDecimal(1_500_000)))
-                                .set(field(Product::getStock), new ProductStock(100_000L))
-                                .set(field(Product::getDeletedAt), DeletedAt.empty())
-                                .create()
+                        ProductFixture.createWith(
+                                savedBrandId,
+                                new ProductName("iPhone 15"),
+                                new ProductPrice(new BigDecimal(1_500_000)),
+                                new ProductStock(100_000L)
+                        )
                 );
             }
 
@@ -215,13 +193,12 @@ void setUp() {
             @DisplayName("특정 브랜드의 상품만 조회된다.")
             void 특정_브랜드의_상품만_조회된다() {
                 productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getBrandId), otherBrandId)
-                                .set(field(Product::getName), new ProductName("Samsung Galaxy"))
-                                .set(field(Product::getPrice), new ProductPrice(new BigDecimal(1_000_000)))
-                                .set(field(Product::getStock), new ProductStock(100_000L))
-                                .create()
+                        ProductFixture.createWith(
+                                otherBrandId,
+                                new ProductName("Samsung Galaxy"),
+                                new ProductPrice(new BigDecimal(1_000_000)),
+                                new ProductStock(100_000L)
+                        )
                 );
 
                 GetProductListQuery query = new GetProductListQuery(
@@ -282,23 +259,16 @@ class ID로_상품_조회_시 {
 
         @BeforeEach
         void setUp() {
-            Brand brand = brandRepository.save(
-                    Instancio.of(Brand.class)
-                            .set(field(Brand::getId), BrandId.empty())
-                            .set(field(Brand::getName), new BrandName("loopers"))
-                            .set(field(Brand::getDescription), new BrandDescription("education brand"))
-                            .create()
-            );
+            Brand brand = brandRepository.save(BrandFixture.createWith("loopers"));
             savedBrandId = brand.getId();
 
             Product product = productRepository.save(
-                    Instancio.of(Product.class)
-                            .set(field(Product::getId), ProductId.empty())
-                            .set(field(Product::getBrandId), savedBrandId)
-                            .set(field(Product::getName), new ProductName("MacBook Pro"))
-                            .set(field(Product::getPrice), new ProductPrice(new BigDecimal(1_300_000)))
-                            .set(field(Product::getStock), new ProductStock(100_000L))
-                            .create()
+                    ProductFixture.createWith(
+                            savedBrandId,
+                            new ProductName("MacBook Pro"),
+                            new ProductPrice(new BigDecimal(1_300_000)),
+                            new ProductStock(100_000L)
+                    )
             );
             savedProductId = product.getId().value();
         }
@@ -347,23 +317,16 @@ class 상품_상세_조회_시 {
 
         @BeforeEach
         void setUp() {
-            savedBrand = brandRepository.save(
-                    Instancio.of(Brand.class)
-                            .set(field(Brand::getId), BrandId.empty())
-                            .set(field(Brand::getName), new BrandName("loopers"))
-                            .set(field(Brand::getDescription), new BrandDescription("education brand"))
-                            .create()
-            );
+            savedBrand = brandRepository.save(BrandFixture.createWith("loopers"));
             savedBrandId = savedBrand.getId();
 
             Product product = productRepository.save(
-                    Instancio.of(Product.class)
-                            .set(field(Product::getId), ProductId.empty())
-                            .set(field(Product::getBrandId), savedBrandId)
-                            .set(field(Product::getName), new ProductName("MacBook Pro"))
-                            .set(field(Product::getPrice), new ProductPrice(new BigDecimal(1_300_000)))
-                            .set(field(Product::getStock), new ProductStock(100_000L))
-                            .create()
+                    ProductFixture.createWith(
+                            savedBrandId,
+                            new ProductName("MacBook Pro"),
+                            new ProductPrice(new BigDecimal(1_300_000)),
+                            new ProductStock(100_000L)
+                    )
             );
             savedProductId = product.getId().value();
         }
@@ -439,13 +402,12 @@ class 브랜드가_존재하지_않는_경우 {
             void NotFoundException이_던져진다() {
                 // 먼저 상품을 생성하고, 브랜드를 삭제하는 시나리오
                 Product orphanProduct = productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getBrandId), new BrandId("99999"))
-                                .set(field(Product::getName), new ProductName("Orphan Product"))
-                                .set(field(Product::getPrice), new ProductPrice(new BigDecimal(100_000)))
-                                .set(field(Product::getStock), new ProductStock(100_000L))
-                                .create()
+                        ProductFixture.createWith(
+                                new BrandId("99999"),
+                                new ProductName("Orphan Product"),
+                                new ProductPrice(new BigDecimal(100_000)),
+                                new ProductStock(100_000L)
+                        )
                 );
 
                 GetProductDetailQuery query = new GetProductDetailQuery(orphanProduct.getId().value());
diff --git a/core/service/src/test/java/com/loopers/core/service/product/StockIncreaseHandlerIntegrationTest.java b/core/service/src/test/java/com/loopers/core/service/product/StockIncreaseHandlerIntegrationTest.java
new file mode 100644
index 000000000..72bc48ed6
--- /dev/null
+++ b/core/service/src/test/java/com/loopers/core/service/product/StockIncreaseHandlerIntegrationTest.java
@@ -0,0 +1,252 @@
+package com.loopers.core.service.product;
+
+import com.loopers.core.domain.brand.vo.BrandId;
+import com.loopers.core.domain.order.Order;
+import com.loopers.core.domain.order.OrderFixture;
+import com.loopers.core.domain.order.OrderItemFixture;
+import com.loopers.core.domain.order.repository.OrderItemRepository;
+import com.loopers.core.domain.order.repository.OrderRepository;
+import com.loopers.core.domain.payment.Payment;
+import com.loopers.core.domain.payment.PaymentFixture;
+import com.loopers.core.domain.payment.repository.PaymentRepository;
+import com.loopers.core.domain.payment.vo.FailedReason;
+import com.loopers.core.domain.payment.vo.PaymentFailedEvent;
+import com.loopers.core.domain.product.Product;
+import com.loopers.core.domain.product.ProductFixture;
+import com.loopers.core.domain.product.repository.ProductRepository;
+import com.loopers.core.domain.product.vo.ProductName;
+import com.loopers.core.domain.product.vo.ProductPrice;
+import com.loopers.core.domain.product.vo.ProductStock;
+import com.loopers.core.domain.user.User;
+import com.loopers.core.domain.user.UserFixture;
+import com.loopers.core.domain.user.repository.UserRepository;
+import com.loopers.core.service.ConcurrencyTestUtil;
+import com.loopers.core.service.IntegrationTest;
+import org.junit.jupiter.api.BeforeEach;
+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 java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.SoftAssertions.assertSoftly;
+
+@DisplayName("재고 증가 핸들러 동시성 테스트")
+class StockIncreaseHandlerIntegrationTest extends IntegrationTest {
+
+    @Autowired
+    private StockIncreaseHandler stockIncreaseHandler;
+
+    @Autowired
+    private OrderRepository orderRepository;
+
+    @Autowired
+    private OrderItemRepository orderItemRepository;
+
+    @Autowired
+    private ProductRepository productRepository;
+
+    @Autowired
+    private UserRepository userRepository;
+
+    @Autowired
+    private PaymentRepository paymentRepository;
+
+    private User testUser;
+    private Product testProduct;
+
+    @BeforeEach
+    void setUp() {
+        // 사용자 생성
+        testUser = userRepository.save(UserFixture.create());
+
+        // 상품 생성 (재고: 1,000개)
+        testProduct = productRepository.save(
+                ProductFixture.createWith(
+                        new BrandId("1"),
+                        new ProductName("테스트 상품"),
+                        new ProductPrice(new BigDecimal("10000")),
+                        new ProductStock(1000L)
+                )
+        );
+    }
+
+    @Nested
+    @DisplayName("동시성 제어 - 동시 결제 실패 시 재고 증가 검증")
+    class ConcurrencyControl {
+
+        @Test
+        @DisplayName("같은 상품에 대해 동시에 여러 결제가 실패할 때 재고 증가 일관성을 보장한다")
+        void shouldMaintainStockConsistencyUnderConcurrentFailedPayments() throws InterruptedException {
+            // Given
+            long initialStock = testProduct.getStock().value();
+            int concurrentFailedPaymentCount = 5;
+            int stockPerPayment = 10;
+
+            List<Payment> concurrentPayments = new ArrayList<>();
+            List<Order> concurrentOrders = new ArrayList<>();
+
+            for (int i = 0; i < concurrentFailedPaymentCount; i++) {
+                Order order = orderRepository.save(
+                        OrderFixture.createWith(testUser.getId())
+                );
+                concurrentOrders.add(order);
+
+                orderItemRepository.save(
+                        OrderItemFixture.createWith(order.getId(), testProduct.getId(), stockPerPayment)
+                );
+
+                concurrentPayments.add(
+                        paymentRepository.save(PaymentFixture.createWith(order.getOrderKey(), testUser.getId()))
+                );
+            }
+
+            // When
+            ConcurrencyTestUtil.executeInParallelWithoutResult(
+                    concurrentFailedPaymentCount,
+                    index -> {
+                        PaymentFailedEvent event = new PaymentFailedEvent(
+                                concurrentPayments.get(index).getId(),
+                                new FailedReason("결제 게이트웨이 오류 #" + index)
+                        );
+                        stockIncreaseHandler.handle(event);
+                    }
+            );
+
+            // Then
+            Product finalProduct = productRepository.findById(testProduct.getId()).orElseThrow();
+            long expectedStock = initialStock + (long) concurrentFailedPaymentCount * stockPerPayment;
+            assertThat(finalProduct.getStock().value())
+                    .as("동시 결제 실패로 인한 재고 증가가 정확하게 이루어져야 함")
+                    .isEqualTo(expectedStock);
+        }
+
+        @Test
+        @DisplayName("10개의 동시 결제 실패에서 재고 증가 일관성을 보장한다")
+        void shouldMaintainStockConsistencyWith10ConcurrentFailedPayments() throws InterruptedException {
+            // Given
+            long initialStock = testProduct.getStock().value();
+            int concurrentFailedPaymentCount = 10;
+            int stockPerPayment = 5;
+
+            List<Payment> concurrentPayments = new ArrayList<>();
+            List<Order> concurrentOrders = new ArrayList<>();
+
+            for (int i = 0; i < concurrentFailedPaymentCount; i++) {
+                Order order = orderRepository.save(
+                        OrderFixture.createWith(testUser.getId())
+                );
+                concurrentOrders.add(order);
+
+                orderItemRepository.save(
+                        OrderItemFixture.createWith(order.getId(), testProduct.getId(), stockPerPayment)
+                );
+
+                concurrentPayments.add(
+                        paymentRepository.save(PaymentFixture.createWith(order.getOrderKey(), testUser.getId()))
+                );
+            }
+
+            // When
+            ConcurrencyTestUtil.executeInParallelWithoutResult(
+                    concurrentFailedPaymentCount,
+                    index -> {
+                        PaymentFailedEvent event = new PaymentFailedEvent(
+                                concurrentPayments.get(index).getId(),
+                                new FailedReason("결제 실패: " + index)
+                        );
+                        stockIncreaseHandler.handle(event);
+                    }
+            );
+
+            // Then
+            Product finalProduct = productRepository.findById(testProduct.getId()).orElseThrow();
+            long expectedStock = initialStock + (long) concurrentFailedPaymentCount * stockPerPayment;
+            assertThat(finalProduct.getStock().value())
+                    .as("10개의 동시 결제 실패로 인한 재고 증가 일관성을 보장")
+                    .isEqualTo(expectedStock);
+        }
+
+        @Test
+        @DisplayName("서로 다른 상품에 대한 동시 결제 실패에서 각 상품의 재고가 독립적으로 증가된다")
+        void shouldIncreaseStockIndependentlyForDifferentProducts() throws InterruptedException {
+            // Given
+            Product product1 = testProduct;
+            Product product2 = productRepository.save(
+                    ProductFixture.createWith(
+                            new BrandId("2"),
+                            new ProductName("테스트 상품 2"),
+                            new ProductPrice(new BigDecimal("15000")),
+                            new ProductStock(1000L)
+                    )
+            );
+            Product product3 = productRepository.save(
+                    ProductFixture.createWith(
+                            new BrandId("3"),
+                            new ProductName("테스트 상품 3"),
+                            new ProductPrice(new BigDecimal("20000")),
+                            new ProductStock(1000L)
+                    )
+            );
+
+            long product1InitialStock = product1.getStock().value();
+            long product2InitialStock = product2.getStock().value();
+            long product3InitialStock = product3.getStock().value();
+
+            int concurrentFailedPaymentCount = 9; // 3개 상품 × 3개 결제씩
+            List<Payment> concurrentPayments = new ArrayList<>();
+
+            for (int i = 0; i < concurrentFailedPaymentCount; i++) {
+                Product targetProduct = switch (i / 3) {
+                    case 0 -> product1;
+                    case 1 -> product2;
+                    default -> product3;
+                };
+
+                Order order = orderRepository.save(
+                        OrderFixture.createWith(testUser.getId())
+                );
+                orderItemRepository.save(
+                        OrderItemFixture.createWith(order.getId(), targetProduct.getId(), 10L)
+                );
+
+                concurrentPayments.add(
+                        paymentRepository.save(PaymentFixture.createWith(order.getOrderKey(), testUser.getId()))
+                );
+            }
+
+            // When
+            ConcurrencyTestUtil.executeInParallelWithoutResult(
+                    concurrentFailedPaymentCount,
+                    index -> {
+                        PaymentFailedEvent event = new PaymentFailedEvent(
+                                concurrentPayments.get(index).getId(),
+                                new FailedReason("결제 실패 #" + index)
+                        );
+                        stockIncreaseHandler.handle(event);
+                    }
+            );
+
+            // Then
+            Product finalProduct1 = productRepository.findById(product1.getId()).orElseThrow();
+            Product finalProduct2 = productRepository.findById(product2.getId()).orElseThrow();
+            Product finalProduct3 = productRepository.findById(product3.getId()).orElseThrow();
+
+            assertSoftly(softly -> {
+                softly.assertThat(finalProduct1.getStock().value())
+                        .as("상품1 재고 증가")
+                        .isEqualTo(product1InitialStock + 30);
+                softly.assertThat(finalProduct2.getStock().value())
+                        .as("상품2 재고 증가")
+                        .isEqualTo(product2InitialStock + 30);
+                softly.assertThat(finalProduct3.getStock().value())
+                        .as("상품3 재고 증가")
+                        .isEqualTo(product3InitialStock + 30);
+            });
+        }
+    }
+}
diff --git a/core/service/product-service/src/test/java/com/loopers/core/service/productlike/ProductLikeQueryServiceTest.java b/core/service/src/test/java/com/loopers/core/service/productlike/ProductLikeQueryServiceTest.java
similarity index 60%
rename from core/service/product-service/src/test/java/com/loopers/core/service/productlike/ProductLikeQueryServiceTest.java
rename to core/service/src/test/java/com/loopers/core/service/productlike/ProductLikeQueryServiceTest.java
index 0f8db8bdf..0d4f792e3 100644
--- a/core/service/product-service/src/test/java/com/loopers/core/service/productlike/ProductLikeQueryServiceTest.java
+++ b/core/service/src/test/java/com/loopers/core/service/productlike/ProductLikeQueryServiceTest.java
@@ -1,26 +1,22 @@
 package com.loopers.core.service.productlike;
 
-import com.loopers.core.domain.brand.Brand;
+import com.loopers.core.domain.brand.BrandFixture;
 import com.loopers.core.domain.brand.repository.BrandRepository;
-import com.loopers.core.domain.brand.vo.BrandDescription;
 import com.loopers.core.domain.brand.vo.BrandId;
-import com.loopers.core.domain.brand.vo.BrandName;
-import com.loopers.core.domain.common.vo.DeletedAt;
 import com.loopers.core.domain.product.Product;
+import com.loopers.core.domain.product.ProductFixture;
 import com.loopers.core.domain.product.repository.ProductRepository;
-import com.loopers.core.domain.product.vo.*;
+import com.loopers.core.domain.product.vo.ProductName;
+import com.loopers.core.domain.product.vo.ProductPrice;
+import com.loopers.core.domain.product.vo.ProductStock;
 import com.loopers.core.domain.productlike.LikeProductListView;
-import com.loopers.core.domain.productlike.ProductLike;
+import com.loopers.core.domain.productlike.ProductLikeFixture;
 import com.loopers.core.domain.productlike.repository.ProductLikeRepository;
-import com.loopers.core.domain.productlike.vo.ProductLikeId;
 import com.loopers.core.domain.user.User;
+import com.loopers.core.domain.user.UserFixture;
 import com.loopers.core.domain.user.repository.UserRepository;
-import com.loopers.core.domain.user.vo.UserEmail;
-import com.loopers.core.domain.user.vo.UserId;
-import com.loopers.core.domain.user.vo.UserIdentifier;
 import com.loopers.core.service.IntegrationTest;
 import com.loopers.core.service.productlike.query.GetLikeProductsListQuery;
-import org.instancio.Instancio;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
@@ -31,7 +27,6 @@
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.SoftAssertions.assertSoftly;
-import static org.instancio.Select.field;
 
 public class ProductLikeQueryServiceTest extends IntegrationTest {
 
@@ -64,76 +59,39 @@ class 사용자가_좋아요한_상품이_존재하는_경우 {
             @BeforeEach
             void setUp() {
                 User user = userRepository.save(
-                        Instancio.of(User.class)
-                                .set(field(User::getId), UserId.empty())
-                                .set(field(User::getIdentifier), UserIdentifier.create("testUser"))
-                                .set(field(User::getEmail), new UserEmail("test@loopers.com"))
-                                .create()
+                        UserFixture.createWith("testUser", "test@loopers.com")
                 );
                 savedUserIdentifier = user.getIdentifier().value();
-                savedBrandId = brandRepository.save(
-                        Instancio.of(Brand.class)
-                                .set(field(Brand::getId), BrandId.empty())
-                                .set(field(Brand::getName), new BrandName("Test Brand"))
-                                .set(field(Brand::getDescription), new BrandDescription("Test Description"))
-                                .create()
-                ).getId();
+                savedBrandId = brandRepository.save(BrandFixture.createWith("Test Brand")).getId();
 
                 Product product1 = productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getBrandId), savedBrandId)
-                                .set(field(Product::getName), new ProductName("MacBook Pro"))
-                                .set(field(Product::getPrice), new ProductPrice(new BigDecimal(1_300_000)))
-                                .set(field(Product::getStock), new ProductStock(10L))
-                                .set(field(Product::getLikeCount), ProductLikeCount.init())
-                                .set(field(Product::getDeletedAt), DeletedAt.empty())
-                                .create()
+                        ProductFixture.createWith(
+                                savedBrandId,
+                                new ProductName("MacBook Pro"),
+                                new ProductPrice(new BigDecimal(1_300_000)),
+                                new ProductStock(10L)
+                        )
                 );
                 Product product2 = productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getBrandId), savedBrandId)
-                                .set(field(Product::getName), new ProductName("iPad Air"))
-                                .set(field(Product::getPrice), new ProductPrice(new BigDecimal(800_000)))
-                                .set(field(Product::getStock), new ProductStock(10L))
-                                .set(field(Product::getLikeCount), ProductLikeCount.init())
-                                .set(field(Product::getDeletedAt), DeletedAt.empty())
-                                .create()
+                        ProductFixture.createWith(
+                                savedBrandId,
+                                new ProductName("iPad Air"),
+                                new ProductPrice(new BigDecimal(800_000)),
+                                new ProductStock(10L)
+                        )
                 );
                 Product product3 = productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getBrandId), savedBrandId)
-                                .set(field(Product::getName), new ProductName("Galaxy S24"))
-                                .set(field(Product::getPrice), new ProductPrice(new BigDecimal(1_100_000)))
-                                .set(field(Product::getStock), new ProductStock(10L))
-                                .set(field(Product::getLikeCount), ProductLikeCount.init())
-                                .set(field(Product::getDeletedAt), DeletedAt.empty())
-                                .create()
+                        ProductFixture.createWith(
+                                savedBrandId,
+                                new ProductName("Galaxy S24"),
+                                new ProductPrice(new BigDecimal(1_100_000)),
+                                new ProductStock(10L)
+                        )
                 );
 
-                productLikeRepository.save(
-                        Instancio.of(ProductLike.class)
-                                .set(field(ProductLike::getId), ProductLikeId.empty())
-                                .set(field(ProductLike::getUserId), user.getId())
-                                .set(field(ProductLike::getProductId), product1.getId())
-                                .create()
-                );
-                productLikeRepository.save(
-                        Instancio.of(ProductLike.class)
-                                .set(field(ProductLike::getId), ProductLikeId.empty())
-                                .set(field(ProductLike::getUserId), user.getId())
-                                .set(field(ProductLike::getProductId), product2.getId())
-                                .create()
-                );
-                productLikeRepository.save(
-                        Instancio.of(ProductLike.class)
-                                .set(field(ProductLike::getId), ProductLikeId.empty())
-                                .set(field(ProductLike::getUserId), user.getId())
-                                .set(field(ProductLike::getProductId), product3.getId())
-                                .create()
-                );
+                productLikeRepository.save(ProductLikeFixture.createWith(user.getId(), product1.getId()));
+                productLikeRepository.save(ProductLikeFixture.createWith(user.getId(), product2.getId()));
+                productLikeRepository.save(ProductLikeFixture.createWith(user.getId(), product3.getId()));
             }
 
             @Test
@@ -252,11 +210,7 @@ class 사용자가_좋아요한_상품이_없는_경우 {
             @BeforeEach
             void setUp() {
                 User user = userRepository.save(
-                        Instancio.of(User.class)
-                                .set(field(User::getId), UserId.empty())
-                                .set(field(User::getIdentifier), UserIdentifier.create("testUser"))
-                                .set(field(User::getEmail), new UserEmail("test@loopers.com"))
-                                .create()
+                        UserFixture.createWith("testUser", "test@loopers.com")
                 );
                 savedUserIdentifier = user.getIdentifier().value();
             }
diff --git a/core/service/product-service/src/test/java/com/loopers/core/service/productlike/ProductLikeServiceTest.java b/core/service/src/test/java/com/loopers/core/service/productlike/ProductLikeServiceTest.java
similarity index 66%
rename from core/service/product-service/src/test/java/com/loopers/core/service/productlike/ProductLikeServiceTest.java
rename to core/service/src/test/java/com/loopers/core/service/productlike/ProductLikeServiceTest.java
index ddc607676..9d35b16a0 100644
--- a/core/service/product-service/src/test/java/com/loopers/core/service/productlike/ProductLikeServiceTest.java
+++ b/core/service/src/test/java/com/loopers/core/service/productlike/ProductLikeServiceTest.java
@@ -1,25 +1,25 @@
 package com.loopers.core.service.productlike;
 
 import com.loopers.core.domain.brand.Brand;
+import com.loopers.core.domain.brand.BrandFixture;
 import com.loopers.core.domain.brand.repository.BrandRepository;
-import com.loopers.core.domain.brand.vo.BrandDescription;
 import com.loopers.core.domain.brand.vo.BrandId;
-import com.loopers.core.domain.brand.vo.BrandName;
 import com.loopers.core.domain.error.NotFoundException;
 import com.loopers.core.domain.product.Product;
+import com.loopers.core.domain.product.ProductFixture;
 import com.loopers.core.domain.product.repository.ProductLikeCacheRepository;
 import com.loopers.core.domain.product.repository.ProductRepository;
-import com.loopers.core.domain.product.vo.*;
+import com.loopers.core.domain.product.vo.ProductLikeCount;
+import com.loopers.core.domain.product.vo.ProductName;
+import com.loopers.core.domain.product.vo.ProductPrice;
+import com.loopers.core.domain.product.vo.ProductStock;
 import com.loopers.core.domain.user.User;
+import com.loopers.core.domain.user.UserFixture;
 import com.loopers.core.domain.user.repository.UserRepository;
-import com.loopers.core.domain.user.vo.UserEmail;
-import com.loopers.core.domain.user.vo.UserId;
-import com.loopers.core.domain.user.vo.UserIdentifier;
 import com.loopers.core.service.ConcurrencyTestUtil;
 import com.loopers.core.service.IntegrationTest;
 import com.loopers.core.service.productlike.command.ProductLikeCommand;
 import com.loopers.core.service.productlike.command.ProductUnlikeCommand;
-import org.instancio.Instancio;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
@@ -31,7 +31,6 @@
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.assertj.core.api.SoftAssertions.assertSoftly;
-import static org.instancio.Select.field;
 
 @DisplayName("ProductLikeService 테스트")
 class ProductLikeServiceTest extends IntegrationTest {
@@ -61,33 +60,21 @@ class 상품_좋아요_등록 {
 
         @BeforeEach
         void setUp() {
-            Brand brand = brandRepository.save(
-                    Instancio.of(Brand.class)
-                            .set(field(Brand::getId), BrandId.empty())
-                            .set(field(Brand::getName), new BrandName("Apple"))
-                            .set(field(Brand::getDescription), new BrandDescription("Apple products"))
-                            .create()
-            );
+            Brand brand = brandRepository.save(BrandFixture.createWith("Apple"));
             brandId = brand.getId();
 
             Product product = productRepository.save(
-                    Instancio.of(Product.class)
-                            .set(field(Product::getId), ProductId.empty())
-                            .set(field(Product::getBrandId), brandId)
-                            .set(field(Product::getName), new ProductName("MacBook Pro"))
-                            .set(field(Product::getPrice), new ProductPrice(new BigDecimal("1500000")))
-                            .set(field(Product::getStock), new ProductStock(100_000L))
-                            .set(field(Product::getLikeCount), ProductLikeCount.init())
-                            .create()
+                    ProductFixture.createWith(
+                            brandId,
+                            new ProductName("MacBook Pro"),
+                            new ProductPrice(new BigDecimal("1500000")),
+                            new ProductStock(100_000L)
+                    )
             );
             productId = product.getId().value();
 
             User user = userRepository.save(
-                    Instancio.of(User.class)
-                            .set(field(User::getId), UserId.empty())
-                            .set(field(User::getIdentifier), UserIdentifier.create("user123"))
-                            .set(field(User::getEmail), new UserEmail("user@example.com"))
-                            .create()
+                    UserFixture.createWith("user123", "user@example.com")
             );
             userIdentifier = user.getIdentifier().value();
         }
@@ -154,11 +141,7 @@ class 동시에_여러_사용자가_좋아요를_누른_경우 {
                         requestCount,
                         index -> {
                             User user = userRepository.save(
-                                    Instancio.of(User.class)
-                                            .set(field(User::getId), UserId.empty())
-                                            .set(field(User::getIdentifier), new UserIdentifier("user_" + index))
-                                            .set(field(User::getEmail), new UserEmail("user_" + index + "@example.com"))
-                                            .create()
+                                    UserFixture.createWith("user" + index, "user_" + index + "@example.com")
                             );
                             productLikeService.like(new ProductLikeCommand(user.getIdentifier().value(), productId));
                         }
@@ -245,33 +228,21 @@ class 상품이_존재하고_이미_좋아요를_누른_경우 {
 
             @BeforeEach
             void setUp() {
-                Brand brand = brandRepository.save(
-                        Instancio.of(Brand.class)
-                                .set(field(Brand::getId), BrandId.empty())
-                                .set(field(Brand::getName), new BrandName("Apple"))
-                                .set(field(Brand::getDescription), new BrandDescription("Apple products"))
-                                .create()
-                );
+                Brand brand = brandRepository.save(BrandFixture.createWith("Apple"));
                 brandId = brand.getId();
 
                 Product product = productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getBrandId), brandId)
-                                .set(field(Product::getName), new ProductName("MacBook Pro"))
-                                .set(field(Product::getPrice), new ProductPrice(new BigDecimal("1500000")))
-                                .set(field(Product::getStock), new ProductStock(100_000L))
-                                .set(field(Product::getLikeCount), ProductLikeCount.init())
-                                .create()
+                        ProductFixture.createWith(
+                                brandId,
+                                new ProductName("MacBook Pro"),
+                                new ProductPrice(new BigDecimal("1500000")),
+                                new ProductStock(100_000L)
+                        )
                 );
                 productId = product.getId().value();
 
                 User user = userRepository.save(
-                        Instancio.of(User.class)
-                                .set(field(User::getId), UserId.empty())
-                                .set(field(User::getIdentifier), UserIdentifier.create("user123"))
-                                .set(field(User::getEmail), new UserEmail("user@example.com"))
-                                .create()
+                        UserFixture.createWith("user123", "user@example.com")
                 );
                 userIdentifier = user.getIdentifier().value();
 
@@ -301,30 +272,16 @@ class 동시에_하나의_사용자가_여러번_취소하면 {
 
             @BeforeEach
             void setUp() {
-                Brand brand = brandRepository.save(
-                        Instancio.of(Brand.class)
-                                .set(field(Brand::getId), BrandId.empty())
-                                .set(field(Brand::getName), new BrandName("Apple"))
-                                .set(field(Brand::getDescription), new BrandDescription("Apple products"))
-                                .create()
-                );
+                Brand brand = brandRepository.save(BrandFixture.createWith("Apple"));
                 brandId = brand.getId();
 
                 Product product = productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getBrandId), brandId)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getLikeCount), new ProductLikeCount(100L))
-                                .create()
+                        ProductFixture.createWith(brandId, new ProductLikeCount(100L))
                 );
                 productId = product.getId().value();
 
                 User user = userRepository.save(
-                        Instancio.of(User.class)
-                                .set(field(User::getId), UserId.empty())
-                                .set(field(User::getIdentifier), UserIdentifier.create("user123"))
-                                .set(field(User::getEmail), new UserEmail("user@example.com"))
-                                .create()
+                        UserFixture.createWith("user123", "user@example.com")
                 );
                 userIdentifier = user.getIdentifier().value();
 
@@ -361,21 +318,11 @@ class 동시에_여러_사용자가_취소하면 {
 
             @BeforeEach
             void setUp() {
-                Brand brand = brandRepository.save(
-                        Instancio.of(Brand.class)
-                                .set(field(Brand::getId), BrandId.empty())
-                                .set(field(Brand::getName), new BrandName("Apple"))
-                                .set(field(Brand::getDescription), new BrandDescription("Apple products"))
-                                .create()
-                );
+                Brand brand = brandRepository.save(BrandFixture.createWith("Apple"));
                 brandId = brand.getId();
 
                 Product product = productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getBrandId), brandId)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getLikeCount), new ProductLikeCount(100L))
-                                .create()
+                        ProductFixture.createWith(brandId, new ProductLikeCount(100L))
                 );
                 productId = product.getId().value();
             }
@@ -390,11 +337,7 @@ void setUp() {
                         requestCount,
                         index -> {
                             User user = userRepository.save(
-                                    Instancio.of(User.class)
-                                            .set(field(User::getId), UserId.empty())
-                                            .set(field(User::getIdentifier), new UserIdentifier("user_" + index))
-                                            .set(field(User::getEmail), new UserEmail("user_" + index + "@example.com"))
-                                            .create()
+                                    UserFixture.createWith("user" + index, "user_" + index + "@example.com")
                             );
                             // 먼저 좋아요 캐시에 저장
                             productLikeService.like(new ProductLikeCommand(user.getIdentifier().value(), productId));
@@ -418,29 +361,15 @@ class 상품이_존재하고_좋아요를_누른_적이_없는_경우 {
 
             @BeforeEach
             void setUp() {
-                Brand brand = brandRepository.save(
-                        Instancio.of(Brand.class)
-                                .set(field(Brand::getId), BrandId.empty())
-                                .set(field(Brand::getName), new BrandName("Apple"))
-                                .set(field(Brand::getDescription), new BrandDescription("Apple products"))
-                                .create()
-                );
+                Brand brand = brandRepository.save(BrandFixture.createWith("Apple"));
                 brandId = brand.getId();
 
                 Product product = productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getBrandId), brandId)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getLikeCount), new ProductLikeCount(100L))
-                                .create()
+                        ProductFixture.createWith(brandId, new ProductLikeCount(100L))
                 );
                 productId = product.getId().value();
                 User user = userRepository.save(
-                        Instancio.of(User.class)
-                                .set(field(User::getId), UserId.empty())
-                                .set(field(User::getIdentifier), UserIdentifier.create("user123"))
-                                .set(field(User::getEmail), new UserEmail("user@example.com"))
-                                .create()
+                        UserFixture.createWith("user123", "user@example.com")
                 );
                 userIdentifier = user.getIdentifier().value();
             }
@@ -468,11 +397,7 @@ class 상품이_존재하지_않는_경우 {
             @BeforeEach
             void setUp() {
                 User user = userRepository.save(
-                        Instancio.of(User.class)
-                                .set(field(User::getId), UserId.empty())
-                                .set(field(User::getIdentifier), UserIdentifier.create("user123"))
-                                .set(field(User::getEmail), new UserEmail("user@example.com"))
-                                .create()
+                        UserFixture.createWith("user123", "user@example.com")
                 );
                 userIdentifier = user.getIdentifier().value();
             }
@@ -494,21 +419,11 @@ class 사용자가_존재하지_않는_경우 {
 
             @BeforeEach
             void setUp() {
-                Brand brand = brandRepository.save(
-                        Instancio.of(Brand.class)
-                                .set(field(Brand::getId), BrandId.empty())
-                                .set(field(Brand::getName), new BrandName("Apple"))
-                                .set(field(Brand::getDescription), new BrandDescription("Apple products"))
-                                .create()
-                );
+                Brand brand = brandRepository.save(BrandFixture.createWith("Apple"));
                 brandId = brand.getId();
 
                 Product product = productRepository.save(
-                        Instancio.of(Product.class)
-                                .set(field(Product::getBrandId), brandId)
-                                .set(field(Product::getId), ProductId.empty())
-                                .set(field(Product::getLikeCount), new ProductLikeCount(100L))
-                                .create()
+                        ProductFixture.createWith(brandId, new ProductLikeCount(100L))
                 );
                 productId = product.getId().value();
             }
diff --git a/core/service/product-service/src/test/java/com/loopers/core/service/productlike/component/ProductLikeCountSynchronizerTest.java b/core/service/src/test/java/com/loopers/core/service/productlike/component/ProductLikeCountSynchronizerTest.java
similarity index 98%
rename from core/service/product-service/src/test/java/com/loopers/core/service/productlike/component/ProductLikeCountSynchronizerTest.java
rename to core/service/src/test/java/com/loopers/core/service/productlike/component/ProductLikeCountSynchronizerTest.java
index 59196cbed..eb5e4bc8a 100644
--- a/core/service/product-service/src/test/java/com/loopers/core/service/productlike/component/ProductLikeCountSynchronizerTest.java
+++ b/core/service/src/test/java/com/loopers/core/service/productlike/component/ProductLikeCountSynchronizerTest.java
@@ -7,11 +7,7 @@
 import com.loopers.core.domain.brand.vo.BrandName;
 import com.loopers.core.domain.product.Product;
 import com.loopers.core.domain.product.repository.ProductRepository;
-import com.loopers.core.domain.product.vo.ProductId;
-import com.loopers.core.domain.product.vo.ProductLikeCount;
-import com.loopers.core.domain.product.vo.ProductName;
-import com.loopers.core.domain.product.vo.ProductPrice;
-import com.loopers.core.domain.product.vo.ProductStock;
+import com.loopers.core.domain.product.vo.*;
 import com.loopers.core.domain.productlike.ProductLikeCache;
 import com.loopers.core.service.IntegrationTest;
 import org.instancio.Instancio;
diff --git a/core/service/product-service/src/test/java/com/loopers/core/service/productlike/component/ProductLikeSynchronizerTest.java b/core/service/src/test/java/com/loopers/core/service/productlike/component/ProductLikeSynchronizerTest.java
similarity index 100%
rename from core/service/product-service/src/test/java/com/loopers/core/service/productlike/component/ProductLikeSynchronizerTest.java
rename to core/service/src/test/java/com/loopers/core/service/productlike/component/ProductLikeSynchronizerTest.java
index 9d9241305..27c97b9bb 100644
--- a/core/service/product-service/src/test/java/com/loopers/core/service/productlike/component/ProductLikeSynchronizerTest.java
+++ b/core/service/src/test/java/com/loopers/core/service/productlike/component/ProductLikeSynchronizerTest.java
@@ -1,10 +1,10 @@
 package com.loopers.core.service.productlike.component;
 
 import com.loopers.core.domain.common.vo.CreatedAt;
+import com.loopers.core.domain.product.vo.ProductId;
 import com.loopers.core.domain.productlike.ProductLike;
 import com.loopers.core.domain.productlike.ProductLikeCache;
 import com.loopers.core.domain.productlike.repository.ProductLikeRepository;
-import com.loopers.core.domain.product.vo.ProductId;
 import com.loopers.core.domain.user.vo.UserId;
 import com.loopers.core.service.IntegrationTest;
 import org.junit.jupiter.api.DisplayName;
diff --git a/core/service/user-service/src/test/java/com/loopers/core/service/user/JoinUserServiceIntegrationTest.java b/core/service/src/test/java/com/loopers/core/service/user/JoinUserServiceIntegrationTest.java
similarity index 81%
rename from core/service/user-service/src/test/java/com/loopers/core/service/user/JoinUserServiceIntegrationTest.java
rename to core/service/src/test/java/com/loopers/core/service/user/JoinUserServiceIntegrationTest.java
index 979db3d74..646a0c7a3 100644
--- a/core/service/user-service/src/test/java/com/loopers/core/service/user/JoinUserServiceIntegrationTest.java
+++ b/core/service/src/test/java/com/loopers/core/service/user/JoinUserServiceIntegrationTest.java
@@ -1,23 +1,18 @@
 package com.loopers.core.service.user;
 
 import com.loopers.core.domain.user.User;
+import com.loopers.core.domain.user.UserFixture;
 import com.loopers.core.domain.user.repository.UserRepository;
-import com.loopers.core.domain.user.vo.UserEmail;
-import com.loopers.core.domain.user.vo.UserIdentifier;
-import com.loopers.core.domain.user.vo.UserId;
 import com.loopers.core.service.IntegrationTest;
 import com.loopers.core.service.user.command.JoinUserCommand;
 import org.assertj.core.api.Assertions;
 import org.assertj.core.api.SoftAssertions;
-import org.instancio.Instancio;
 import org.junit.jupiter.api.BeforeEach;
 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 static org.instancio.Select.field;
-
 import java.util.Optional;
 
 class JoinUserServiceIntegrationTest extends IntegrationTest {
@@ -63,11 +58,7 @@ class 이미_존재하는_회원의_ID인_경우 {
             @BeforeEach
             void setUp() {
                 userRepository.save(
-                        Instancio.of(User.class)
-                                .set(field(User::getId), UserId.empty())
-                                .set(field(User::getIdentifier), new UserIdentifier("kilian"))
-                                .set(field(User::getEmail), new UserEmail("kilian@gmail.com"))
-                                .create()
+                        UserFixture.createWith("kilian", "kilian@gmail.com")
                 );
             }
 
diff --git a/core/service/user-service/src/test/java/com/loopers/core/service/user/UserPointQueryServiceIntegrationTest.java b/core/service/src/test/java/com/loopers/core/service/user/UserPointQueryServiceIntegrationTest.java
similarity index 75%
rename from core/service/user-service/src/test/java/com/loopers/core/service/user/UserPointQueryServiceIntegrationTest.java
rename to core/service/src/test/java/com/loopers/core/service/user/UserPointQueryServiceIntegrationTest.java
index b3f196b36..772dc4115 100644
--- a/core/service/user-service/src/test/java/com/loopers/core/service/user/UserPointQueryServiceIntegrationTest.java
+++ b/core/service/src/test/java/com/loopers/core/service/user/UserPointQueryServiceIntegrationTest.java
@@ -1,23 +1,22 @@
 package com.loopers.core.service.user;
 
 import com.loopers.core.domain.user.User;
+import com.loopers.core.domain.user.UserFixture;
 import com.loopers.core.domain.user.UserPoint;
+import com.loopers.core.domain.user.UserPointFixture;
 import com.loopers.core.domain.user.repository.UserPointRepository;
 import com.loopers.core.domain.user.repository.UserRepository;
-import com.loopers.core.domain.user.vo.*;
+import com.loopers.core.domain.user.vo.UserPointBalance;
 import com.loopers.core.service.IntegrationTest;
 import com.loopers.core.service.user.query.GetUserPointQuery;
 import org.assertj.core.api.Assertions;
 import org.assertj.core.api.SoftAssertions;
-import org.instancio.Instancio;
 import org.junit.jupiter.api.BeforeEach;
 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 static org.instancio.Select.field;
-
 class UserPointQueryServiceIntegrationTest extends IntegrationTest {
 
     @Autowired
@@ -56,19 +55,11 @@ class 해당_ID의_회원이_존재할_경우 {
             @BeforeEach
             void setUp() {
                 savedUser = userRepository.save(
-                        Instancio.of(User.class)
-                                .set(field(User::getId), UserId.empty())
-                                .set(field(User::getIdentifier), new UserIdentifier("kilian"))
-                                .set(field(User::getEmail), new UserEmail("kilian@gmail.com"))
-                                .create()
+                        UserFixture.createWith("kilian", "kilian@gmail.com")
                 );
 
                 savedUserPoint = userPointRepository.save(
-                        Instancio.of(UserPoint.class)
-                                .set(field(UserPoint::getId), UserPointId.empty())
-                                .set(field(UserPoint::getUserId), savedUser.getId())
-                                .set(field(UserPoint::getBalance), UserPointBalance.init())
-                                .create()
+                        UserPointFixture.createWith(savedUser.getId(), UserPointBalance.init().value())
                 );
             }
 
diff --git a/core/service/user-service/src/test/java/com/loopers/core/service/user/UserPointServiceIntegrationTest.java b/core/service/src/test/java/com/loopers/core/service/user/UserPointServiceIntegrationTest.java
similarity index 74%
rename from core/service/user-service/src/test/java/com/loopers/core/service/user/UserPointServiceIntegrationTest.java
rename to core/service/src/test/java/com/loopers/core/service/user/UserPointServiceIntegrationTest.java
index dcffa0561..2f69c5f49 100644
--- a/core/service/user-service/src/test/java/com/loopers/core/service/user/UserPointServiceIntegrationTest.java
+++ b/core/service/src/test/java/com/loopers/core/service/user/UserPointServiceIntegrationTest.java
@@ -2,14 +2,15 @@
 
 import com.loopers.core.domain.error.NotFoundException;
 import com.loopers.core.domain.user.User;
+import com.loopers.core.domain.user.UserFixture;
 import com.loopers.core.domain.user.UserPoint;
+import com.loopers.core.domain.user.UserPointFixture;
 import com.loopers.core.domain.user.repository.UserPointRepository;
 import com.loopers.core.domain.user.repository.UserRepository;
-import com.loopers.core.domain.user.vo.*;
+import com.loopers.core.domain.user.vo.UserPointBalance;
 import com.loopers.core.service.ConcurrencyTestUtil;
 import com.loopers.core.service.IntegrationTest;
 import com.loopers.core.service.user.command.UserPointChargeCommand;
-import org.instancio.Instancio;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
@@ -21,7 +22,6 @@
 
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.assertj.core.api.SoftAssertions.assertSoftly;
-import static org.instancio.Select.field;
 
 class UserPointServiceIntegrationTest extends IntegrationTest {
 
@@ -47,18 +47,10 @@ class 정상_충전 {
             @BeforeEach
             void setUp() {
                 user = userRepository.save(
-                        Instancio.of(User.class)
-                                .set(field(User::getId), UserId.empty())
-                                .set(field(User::getIdentifier), new UserIdentifier("kilian"))
-                                .set(field(User::getEmail), new UserEmail("kilian@gmail.com"))
-                                .create()
+                        UserFixture.createWith("kilian", "kilian@gmail.com")
                 );
                 userPointRepository.save(
-                        Instancio.of(UserPoint.class)
-                                .set(field(UserPoint::getId), UserPointId.empty())
-                                .set(field(UserPoint::getUserId), user.getId())
-                                .set(field(UserPoint::getBalance), UserPointBalance.init())
-                                .create()
+                        UserPointFixture.createWith(user.getId(), UserPointBalance.init().value())
                 );
             }
 
@@ -109,18 +101,10 @@ class 동시_포인트_적립_정합성 {
                 @BeforeEach
                 void setUp() {
                     user = userRepository.save(
-                            Instancio.of(User.class)
-                                    .set(field(User::getId), UserId.empty())
-                                    .set(field(User::getIdentifier), new UserIdentifier("kilian"))
-                                    .set(field(User::getEmail), new UserEmail("kilian@gmail.com"))
-                                    .create()
+                            UserFixture.createWith("kilian", "kilian@gmail.com")
                     );
                     userPointRepository.save(
-                            Instancio.of(UserPoint.class)
-                                    .set(field(UserPoint::getId), UserPointId.empty())
-                                    .set(field(UserPoint::getUserId), user.getId())
-                                    .set(field(UserPoint::getBalance), UserPointBalance.init())
-                                    .create()
+                            UserPointFixture.createWith(user.getId(), UserPointBalance.init().value())
                     );
                 }
 
diff --git a/core/service/user-service/src/test/java/com/loopers/core/service/user/UserQueryServiceTest.java b/core/service/src/test/java/com/loopers/core/service/user/UserQueryServiceTest.java
similarity index 75%
rename from core/service/user-service/src/test/java/com/loopers/core/service/user/UserQueryServiceTest.java
rename to core/service/src/test/java/com/loopers/core/service/user/UserQueryServiceTest.java
index a8564cbc3..76a2fe923 100644
--- a/core/service/user-service/src/test/java/com/loopers/core/service/user/UserQueryServiceTest.java
+++ b/core/service/src/test/java/com/loopers/core/service/user/UserQueryServiceTest.java
@@ -1,24 +1,18 @@
 package com.loopers.core.service.user;
 
 import com.loopers.core.domain.user.User;
+import com.loopers.core.domain.user.UserFixture;
 import com.loopers.core.domain.user.repository.UserRepository;
-import com.loopers.core.domain.user.type.UserGender;
-import com.loopers.core.domain.user.vo.UserEmail;
-import com.loopers.core.domain.user.vo.UserIdentifier;
-import com.loopers.core.domain.user.vo.UserId;
 import com.loopers.core.service.IntegrationTest;
 import com.loopers.core.service.user.query.GetUserQuery;
 import org.assertj.core.api.Assertions;
 import org.assertj.core.api.SoftAssertions;
-import org.instancio.Instancio;
 import org.junit.jupiter.api.BeforeEach;
 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 static org.instancio.Select.field;
-
 class UserQueryServiceTest extends IntegrationTest {
 
     @Autowired
@@ -49,13 +43,7 @@ class ID에_해당하는_사용자가_존재할_경우 {
 
             @BeforeEach
             void setUp() {
-                userRepository.save(
-                        Instancio.of(User.class)
-                                .set(field(User::getId), UserId.empty())
-                                .set(field(User::getIdentifier), new UserIdentifier("kilian"))
-                                .set(field(User::getEmail), new UserEmail("kilian@gmail.com"))
-                                .create()
-                );
+                userRepository.save(UserFixture.createWith("kilian", "kilian@gmail.com"));
             }
 
             @Test
diff --git a/core/service/src/test/resources/application-test.yml b/core/service/src/test/resources/application-test.yml
new file mode 100644
index 000000000..eb6e98392
--- /dev/null
+++ b/core/service/src/test/resources/application-test.yml
@@ -0,0 +1,21 @@
+spring:
+  jpa:
+    hibernate:
+      ddl-auto: create-drop
+
+http-client:
+  pg-simulator:
+    url: http://localhost:8082
+    path: /api/v1/payments
+
+retry:
+  exceptions:
+    retryable:
+      - com.loopers.core.domain.error.HttpClientException.ServiceUnavailable
+      - com.loopers.core.domain.error.HttpClientException.InternalServerError
+      - com.loopers.core.domain.error.HttpClientException.GatewayTimeout
+      - com.loopers.core.domain.error.HttpClientException.TooManyRequests
+
+pg:
+  callback:
+    url: http://localhost:8080/api/v1/payments/callback
diff --git a/core/service/user-service/build.gradle.kts b/core/service/user-service/build.gradle.kts
deleted file mode 100644
index 9292dba55..000000000
--- a/core/service/user-service/build.gradle.kts
+++ /dev/null
@@ -1,12 +0,0 @@
-dependencies {
-    implementation(project(":core:domain"))
-
-    // spring
-    implementation("org.springframework.boot:spring-boot-starter")
-    implementation("org.springframework:spring-tx")
-    // mysql
-    runtimeOnly(project(":core:infra:database:mysql:user-mysql"))
-
-    testImplementation(testFixtures(project(":core:infra:database:mysql:mysql-core")))
-    testImplementation(project(":core:infra:database:mysql:mysql-config"))
-}
diff --git a/core/service/user-service/src/test/java/com/loopers/core/service/ConcurrencyTestUtil.java b/core/service/user-service/src/test/java/com/loopers/core/service/ConcurrencyTestUtil.java
deleted file mode 100644
index 260dcf8fa..000000000
--- a/core/service/user-service/src/test/java/com/loopers/core/service/ConcurrencyTestUtil.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.loopers.core.service;
-
-import java.util.List;
-import java.util.concurrent.*;
-import java.util.function.Consumer;
-import java.util.function.Function;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public final class ConcurrencyTestUtil {
-
-    private ConcurrencyTestUtil() {
-        throw new UnsupportedOperationException("이 클래스의 인스턴스는 생성될 수 없습니다.");
-    }
-
-    public static <T> List<T> executeInParallel(
-            int threadCount,
-            Function<Integer, T> task) throws InterruptedException {
-
-        CountDownLatch latch = new CountDownLatch(threadCount);
-        CopyOnWriteArrayList<T> results = new CopyOnWriteArrayList<>();
-
-        try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
-            for (int i = 0; i < threadCount; i++) {
-                final int index = i;
-                executor.submit(() -> {
-                    try {
-                        T result = task.apply(index);
-                        results.add(result);
-                    } finally {
-                        latch.countDown();
-                    }
-                });
-            }
-        }
-
-        boolean completed = latch.await(30, TimeUnit.SECONDS);
-        assertThat(completed).isTrue();
-
-        return results;
-    }
-
-    public static void executeInParallelWithoutResult(
-            int threadCount,
-            Consumer<Integer> task) throws InterruptedException {
-
-        CountDownLatch latch = new CountDownLatch(threadCount);
-
-        try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
-            for (int i = 0; i < threadCount; i++) {
-                final int index = i;
-                executor.submit(() -> {
-                    try {
-                        task.accept(index);
-                    } finally {
-                        latch.countDown();
-                    }
-                });
-            }
-        }
-
-        boolean completed = latch.await(30, TimeUnit.SECONDS);
-        assertThat(completed).isTrue();
-    }
-}
diff --git a/core/service/user-service/src/test/java/com/loopers/core/service/IntegrationTest.java b/core/service/user-service/src/test/java/com/loopers/core/service/IntegrationTest.java
deleted file mode 100644
index 56ee3dd13..000000000
--- a/core/service/user-service/src/test/java/com/loopers/core/service/IntegrationTest.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.loopers.core.service;
-
-import com.loopers.core.infra.mysql.testcontainers.MySqlTestContainersExtension;
-import com.loopers.core.infra.mysql.util.DatabaseCleanUp;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-
-@SpringBootTest
-@ExtendWith(MySqlTestContainersExtension.class)
-public class IntegrationTest {
-
-    @Autowired
-    private DatabaseCleanUp databaseCleanUp;
-
-    @AfterEach
-    void databaseCleanUp() {
-        databaseCleanUp.truncateAllTables();
-    }
-}
diff --git a/core/service/user-service/src/test/resources/application-test.yml b/core/service/user-service/src/test/resources/application-test.yml
deleted file mode 100644
index 34f9eeeb0..000000000
--- a/core/service/user-service/src/test/resources/application-test.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-spring:
-  jpa:
-    hibernate:
-      ddl-auto: create-drop
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 1e45c9235..14498378a 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -8,19 +8,13 @@ include(
     ":supports:logging",
     ":supports:monitoring",
     ":core:domain",
+    ":core:service",
     ":core:infra:database:mysql:mysql-config",
-    ":core:infra:database:mysql:mysql-core",
-    ":core:infra:database:mysql:user-mysql",
-    ":core:infra:database:mysql:product-mysql",
-    ":core:infra:database:mysql:order-mysql",
+    ":core:infra:database:mysql",
     ":core:infra:database:redis:redis-config",
-    ":core:infra:database:redis:product-redis",
+    ":core:infra:database:redis",
     ":core:infra:http-client:http-client-config",
-    ":core:infra:http-client:pg-simulator-client",
-    ":core:service:user-service",
-    ":core:service:product-service",
-    ":core:service:order-service",
-    ":core:service:payment-service",
+    ":core:infra:http-client",
     ":core:common"
 )
 
