diff --git a/.coderabbit.yml b/.coderabbit.yml
new file mode 100644
index 0000000..8511537
--- /dev/null
+++ b/.coderabbit.yml
@@ -0,0 +1,35 @@
+language: "ko"
+early_access: false
+reviews:
+ profile: "chill"
+ request_changes_workflow: false
+ high_level_summary: true
+ poem: true
+ review_status: true
+ collapse_walkthrough: false
+ auto_review:
+ enabled: true
+ drafts: false
+ path_filters:
+ - "!**/*.md"
+ - "!**/docs/**"
+ - "!**/.github/**"
+ path_instructions:
+ - path: "**/*.java"
+ instructions: |
+ Review this Java code for:
+ 1. Spring Boot best practices
+ 2. Clean code principles
+ 3. Performance optimizations
+ 4. Security considerations
+ 5. Suggest more elegant solutions using Java features
+ 6. Check for proper exception handling
+ 7. Suggest better naming conventions
+ - path: "**/build.gradle"
+ instructions: |
+ Review Gradle configuration for:
+ 1. Dependency management best practices
+ 2. Build optimization opportunities
+ 3. Plugin usage efficiency
+chat:
+ auto_reply: true
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/MSA-SpringCloud-Kubernetes.iml b/.idea/MSA-SpringCloud-Kubernetes.iml
new file mode 100644
index 0000000..d6ebd48
--- /dev/null
+++ b/.idea/MSA-SpringCloud-Kubernetes.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/git_toolbox_blame.xml b/.idea/git_toolbox_blame.xml
new file mode 100644
index 0000000..7dc1249
--- /dev/null
+++ b/.idea/git_toolbox_blame.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..e9710cf
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..02f263b
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/api-gateway/build.gradle b/api-gateway/build.gradle
new file mode 100644
index 0000000..93e1aff
--- /dev/null
+++ b/api-gateway/build.gradle
@@ -0,0 +1,8 @@
+plugins {
+ id 'org.springframework.boot' version '3.1.5'
+}
+
+dependencies {
+ implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
+ implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
+}
\ No newline at end of file
diff --git a/api-gateway/src/main/java/com/example/gateway/ApiGatewayApplication.java b/api-gateway/src/main/java/com/example/gateway/ApiGatewayApplication.java
new file mode 100644
index 0000000..bdafec0
--- /dev/null
+++ b/api-gateway/src/main/java/com/example/gateway/ApiGatewayApplication.java
@@ -0,0 +1,15 @@
+package com.example.gateway;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+
+@SpringBootApplication
+@EnableEurekaClient
+public class ApiGatewayApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ApiGatewayApplication.class, args);
+ }
+
+}
\ No newline at end of file
diff --git a/api-gateway/src/main/resources/application.yml b/api-gateway/src/main/resources/application.yml
new file mode 100644
index 0000000..e6a1c81
--- /dev/null
+++ b/api-gateway/src/main/resources/application.yml
@@ -0,0 +1,32 @@
+spring:
+ application:
+ name: api-gateway
+ cloud:
+ gateway:
+ routes:
+ - id: user-service
+ uri: lb://user-service
+ predicates:
+ - Path=/api/users/**
+ - id: order-service
+ uri: lb://order-service
+ predicates:
+ - Path=/api/orders/**
+ discovery:
+ locator:
+ enabled: true
+ lower-case-service-id: true
+
+server:
+ port: 8080
+
+eureka:
+ client:
+ service-url:
+ defaultZone: http://localhost:8761/eureka/
+ instance:
+ prefer-ip-address: true
+
+logging:
+ level:
+ org.springframework.cloud.gateway: DEBUG
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..08db31f
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,48 @@
+plugins {
+ id 'java'
+}
+
+allprojects {
+ group = 'com.example'
+ version = '0.0.1-SNAPSHOT'
+
+ repositories {
+ mavenCentral()
+ }
+}
+
+subprojects {
+ apply plugin: 'java'
+ apply plugin: 'io.spring.dependency-management'
+
+ java {
+ sourceCompatibility = '17'
+ }
+
+ configurations {
+ compileOnly {
+ extendsFrom annotationProcessor
+ }
+ }
+
+ ext {
+ set('springCloudVersion', "2022.0.4")
+ }
+
+ // 공통 의존성
+ dependencies {
+ compileOnly 'org.projectlombok:lombok'
+ annotationProcessor 'org.projectlombok:lombok'
+ testImplementation 'org.springframework.boot:spring-boot-starter-test'
+ }
+
+ dependencyManagement {
+ imports {
+ mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
+ }
+ }
+
+ tasks.named('test') {
+ useJUnitPlatform()
+ }
+}
\ No newline at end of file
diff --git a/common/build.gradle b/common/build.gradle
new file mode 100644
index 0000000..9e8fb62
--- /dev/null
+++ b/common/build.gradle
@@ -0,0 +1,3 @@
+dependencies {
+ implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
+}
\ No newline at end of file
diff --git a/common/src/main/java/com/example/common/BaseEntity.java b/common/src/main/java/com/example/common/BaseEntity.java
new file mode 100644
index 0000000..5a55ff1
--- /dev/null
+++ b/common/src/main/java/com/example/common/BaseEntity.java
@@ -0,0 +1,33 @@
+package com.example.common;
+
+import jakarta.persistence.*;
+import lombok.Getter;
+import lombok.Setter;
+import java.time.LocalDateTime;
+
+@MappedSuperclass
+@Getter
+@Setter
+public abstract class BaseEntity {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @Column(nullable = false, updatable = false)
+ private LocalDateTime createdAt;
+
+ @Column(nullable = false)
+ private LocalDateTime updatedAt;
+
+ @PrePersist
+ protected void onCreate() {
+ createdAt = LocalDateTime.now();
+ updatedAt = LocalDateTime.now();
+ }
+
+ @PreUpdate
+ protected void onUpdate() {
+ updatedAt = LocalDateTime.now();
+ }
+}
\ No newline at end of file
diff --git a/docs/QNA.md b/docs/QNA.md
new file mode 100644
index 0000000..9754287
--- /dev/null
+++ b/docs/QNA.md
@@ -0,0 +1,116 @@
+# 🤔 개발 과정에서의 질문과 답변
+
+## MSA 아키텍처 관련
+
+### Q: Spring Cloud 없이도 MSA가 가능한데 왜 사용하나요?
+
+**A:** Spring Cloud를 사용하는 이유는 다음과 같습니다:
+
+1. **서비스 디스커버리 자동화**
+ ```java
+ // Spring Cloud 없으면
+ RestTemplate.getForObject("http://user-service-1:8081/api/users/1", User.class); // 하드코딩
+
+ // Spring Cloud 있으면
+ RestTemplate.getForObject("http://user-service/api/users/1", User.class); // 자동 발견
+ ```
+
+2. **로드밸런싱 자동화**
+ - 인스턴스 장애 시 자동 전환
+ - 인스턴스 추가/제거 시 자동 감지
+
+3. **개발 편의성**
+ ```java
+ @FeignClient(name = "user-service") // 간단한 서비스 간 통신
+ interface UserClient {
+ @GetMapping("/api/users/{id}")
+ User getUser(@PathVariable Long id);
+ }
+ ```
+
+**결론**: 작은 MSA는 Spring Cloud 없어도 되지만, 서비스가 많아질수록 Spring Cloud의 자동화 기능이 큰 도움이 됩니다.
+
+---
+
+## Gradle 멀티모듈 관련
+
+### Q: 멀티모듈에서 공통 설정은 어떻게 관리하나요?
+
+**A:** `subprojects` 블록을 활용해서 공통 설정을 자동 적용합니다:
+
+```groovy
+subprojects {
+ // 모든 하위 모듈에 자동 적용
+ dependencies {
+ compileOnly 'org.projectlombok:lombok'
+ testImplementation 'org.springframework.boot:spring-boot-starter-test'
+ }
+}
+```
+
+**장점**:
+- 중복 설정 제거
+- 새 서비스 추가 시 최소한의 설정만 필요
+- 일관된 의존성 관리
+
+### Q: 모든 서비스에서 공통 모듈을 꼭 사용해야 하나요?
+
+**A:** 아닙니다! 필요한 모듈만 의존성을 추가하면 됩니다:
+
+- **user-service**: `implementation project(':common')` ✅ (BaseEntity 사용)
+- **order-service**: `implementation project(':common')` ✅ (BaseEntity 사용)
+- **api-gateway**: 의존성 없음 ✅ (BaseEntity 안 씀)
+
+**원칙**: 필요한 모듈만 의존성 추가, 불필요한 의존성은 추가하지 않음
+
+---
+
+## FeignClient vs RestTemplate
+
+### Q: FeignClient를 왜 사용하나요? RestTemplate과 차이는?
+
+**A:** 둘 다 MSA에서 서비스 간 통신에 사용되지만 편의성에 차이가 있습니다:
+
+**RestTemplate (번거로움)**:
+```java
+val response = restTemplate.getForObject("http://user-service/api/users/$id", UserDto::class.java)
+```
+
+**FeignClient (간편함)**:
+```java
+@FeignClient(name = "user-service")
+interface UserClient {
+ @GetMapping("/api/users/{id}")
+ UserDto getUserById(@PathVariable Long id);
+}
+
+// 사용
+val user = userClient.getUserById(id)
+```
+
+**결론**: RestTemplate도 가능하지만 FeignClient가 더 선언적이고 간편합니다.
+
+---
+
+## 기술 선택 이유
+
+### Q: Maven 대신 Gradle을 선택한 이유는?
+
+**A:**
+- **빌드 속도**: Gradle이 더 빠름
+- **문법**: Groovy 문법이 XML보다 간결
+- **현대적**: 요즘 Spring 프로젝트에서 더 많이 사용
+- **유연성**: 복잡한 빌드 로직 구현 시 더 유연
+
+### Q: Java 대신 Kotlin을 처음에 시도한 이유는?
+
+**A:** Kotlin의 장점을 경험해보고 싶어서였지만, Java와 비교 학습을 위해 Java로 변경했습니다:
+
+**Kotlin 장점**:
+- data class로 boilerplate 코드 최소화
+- null safety
+- 간결한 문법
+
+**Java를 최종 선택한 이유**:
+- 두 언어의 차이점을 명확히 비교하기 위함
+- Lombok 적용 전후 비교 가능
\ No newline at end of file
diff --git a/order-service/build.gradle b/order-service/build.gradle
new file mode 100644
index 0000000..11f7929
--- /dev/null
+++ b/order-service/build.gradle
@@ -0,0 +1,14 @@
+plugins {
+ id 'org.springframework.boot' version '3.1.5'
+}
+
+dependencies {
+ implementation project(':common')
+ implementation 'org.springframework.boot:spring-boot-starter-web'
+ implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
+ implementation 'org.springframework.boot:spring-boot-starter-validation'
+ implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
+ implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
+
+ runtimeOnly 'com.h2database:h2'
+}
\ No newline at end of file
diff --git a/order-service/src/main/java/com/example/order/OrderServiceApplication.java b/order-service/src/main/java/com/example/order/OrderServiceApplication.java
new file mode 100644
index 0000000..040972b
--- /dev/null
+++ b/order-service/src/main/java/com/example/order/OrderServiceApplication.java
@@ -0,0 +1,17 @@
+package com.example.order;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+
+@SpringBootApplication
+@EnableEurekaClient
+@EnableFeignClients
+public class OrderServiceApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(OrderServiceApplication.class, args);
+ }
+
+}
\ No newline at end of file
diff --git a/order-service/src/main/java/com/example/order/controller/OrderController.java b/order-service/src/main/java/com/example/order/controller/OrderController.java
new file mode 100644
index 0000000..f328661
--- /dev/null
+++ b/order-service/src/main/java/com/example/order/controller/OrderController.java
@@ -0,0 +1,36 @@
+package com.example.order.controller;
+
+import com.example.order.entity.Order;
+import com.example.order.service.OrderService;
+import com.example.order.service.OrderService.CreateOrderRequest;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import java.util.List;
+
+@RestController
+@RequestMapping("/api/orders")
+@RequiredArgsConstructor
+public class OrderController {
+
+ private final OrderService orderService;
+
+ @PostMapping
+ public ResponseEntity createOrder(@RequestBody CreateOrderRequest request) {
+ Order order = orderService.createOrder(request);
+ return ResponseEntity.status(HttpStatus.CREATED).body(order);
+ }
+
+ @GetMapping
+ public ResponseEntity> getAllOrders() {
+ List orders = orderService.getAllOrders();
+ return ResponseEntity.ok(orders);
+ }
+
+ @GetMapping("/user/{userId}")
+ public ResponseEntity> getOrdersByUserId(@PathVariable Long userId) {
+ List orders = orderService.getOrdersByUserId(userId);
+ return ResponseEntity.ok(orders);
+ }
+}
\ No newline at end of file
diff --git a/order-service/src/main/java/com/example/order/entity/Order.java b/order-service/src/main/java/com/example/order/entity/Order.java
new file mode 100644
index 0000000..c923477
--- /dev/null
+++ b/order-service/src/main/java/com/example/order/entity/Order.java
@@ -0,0 +1,42 @@
+package com.example.order.entity;
+
+import com.example.common.BaseEntity;
+import jakarta.persistence.*;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import java.math.BigDecimal;
+
+@Entity
+@Table(name = "orders")
+@Getter
+@Setter
+@NoArgsConstructor
+public class Order extends BaseEntity {
+
+ @Column(nullable = false)
+ private Long userId;
+
+ @Column(nullable = false)
+ private String productName;
+
+ @Column(nullable = false)
+ private Integer quantity;
+
+ @Column(nullable = false, precision = 10, scale = 2)
+ private BigDecimal price;
+
+ @Enumerated(EnumType.STRING)
+ private OrderStatus status = OrderStatus.PENDING;
+
+ public Order(Long userId, String productName, Integer quantity, BigDecimal price) {
+ this.userId = userId;
+ this.productName = productName;
+ this.quantity = quantity;
+ this.price = price;
+ }
+}
+
+enum OrderStatus {
+ PENDING, CONFIRMED, SHIPPED, DELIVERED, CANCELLED
+}
\ No newline at end of file
diff --git a/order-service/src/main/java/com/example/order/repository/OrderRepository.java b/order-service/src/main/java/com/example/order/repository/OrderRepository.java
new file mode 100644
index 0000000..9efc4f6
--- /dev/null
+++ b/order-service/src/main/java/com/example/order/repository/OrderRepository.java
@@ -0,0 +1,11 @@
+package com.example.order.repository;
+
+import com.example.order.entity.Order;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+import java.util.List;
+
+@Repository
+public interface OrderRepository extends JpaRepository {
+ List findByUserId(Long userId);
+}
\ No newline at end of file
diff --git a/order-service/src/main/java/com/example/order/service/OrderService.java b/order-service/src/main/java/com/example/order/service/OrderService.java
new file mode 100644
index 0000000..7e3dc52
--- /dev/null
+++ b/order-service/src/main/java/com/example/order/service/OrderService.java
@@ -0,0 +1,53 @@
+package com.example.order.service;
+
+import com.example.order.entity.Order;
+import com.example.order.repository.OrderRepository;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+import org.springframework.stereotype.Service;
+import java.math.BigDecimal;
+import java.util.List;
+
+@Service
+@RequiredArgsConstructor
+public class OrderService {
+
+ private final OrderRepository orderRepository;
+
+ public Order createOrder(CreateOrderRequest request) {
+ Order order = new Order(
+ request.getUserId(),
+ request.getProductName(),
+ request.getQuantity(),
+ request.getPrice()
+ );
+ return orderRepository.save(order);
+ }
+
+ public List getAllOrders() {
+ return orderRepository.findAll();
+ }
+
+ public List getOrdersByUserId(Long userId) {
+ return orderRepository.findByUserId(userId);
+ }
+
+ @Getter
+ @Setter
+ @NoArgsConstructor
+ public static class CreateOrderRequest {
+ private Long userId;
+ private String productName;
+ private Integer quantity;
+ private BigDecimal price;
+
+ public CreateOrderRequest(Long userId, String productName, Integer quantity, BigDecimal price) {
+ this.userId = userId;
+ this.productName = productName;
+ this.quantity = quantity;
+ this.price = price;
+ }
+ }
+}
\ No newline at end of file
diff --git a/order-service/src/main/resources/application.yml b/order-service/src/main/resources/application.yml
new file mode 100644
index 0000000..750cfd3
--- /dev/null
+++ b/order-service/src/main/resources/application.yml
@@ -0,0 +1,29 @@
+spring:
+ application:
+ name: order-service
+
+ datasource:
+ url: jdbc:h2:mem:orderdb
+ driverClassName: org.h2.Driver
+ username: sa
+ password:
+
+ h2:
+ console:
+ enabled: true
+ path: /h2-console
+
+ jpa:
+ hibernate:
+ ddl-auto: create-drop
+ show-sql: true
+
+server:
+ port: 8082
+
+eureka:
+ client:
+ service-url:
+ defaultZone: http://localhost:8761/eureka/
+ instance:
+ prefer-ip-address: true
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..d3006fd
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,6 @@
+rootProject.name = 'msa-spring-cloud-kubernetes'
+
+include 'common'
+include 'user-service'
+include 'order-service'
+include 'api-gateway'
\ No newline at end of file
diff --git a/user-service/build.gradle b/user-service/build.gradle
new file mode 100644
index 0000000..ca33c0b
--- /dev/null
+++ b/user-service/build.gradle
@@ -0,0 +1,13 @@
+plugins {
+ id 'org.springframework.boot' version '3.1.5'
+}
+
+dependencies {
+ implementation project(':common')
+ implementation 'org.springframework.boot:spring-boot-starter-web'
+ implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
+ implementation 'org.springframework.boot:spring-boot-starter-validation'
+ implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
+
+ runtimeOnly 'com.h2database:h2'
+}
\ No newline at end of file
diff --git a/user-service/src/main/java/com/example/user/UserServiceApplication.java b/user-service/src/main/java/com/example/user/UserServiceApplication.java
new file mode 100644
index 0000000..a7eb5b2
--- /dev/null
+++ b/user-service/src/main/java/com/example/user/UserServiceApplication.java
@@ -0,0 +1,15 @@
+package com.example.user;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+
+@SpringBootApplication
+@EnableEurekaClient
+public class UserServiceApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(UserServiceApplication.class, args);
+ }
+
+}
\ No newline at end of file
diff --git a/user-service/src/main/java/com/example/user/controller/UserController.java b/user-service/src/main/java/com/example/user/controller/UserController.java
new file mode 100644
index 0000000..7bfbee6
--- /dev/null
+++ b/user-service/src/main/java/com/example/user/controller/UserController.java
@@ -0,0 +1,44 @@
+package com.example.user.controller;
+
+import com.example.user.entity.User;
+import com.example.user.service.UserService;
+import com.example.user.service.UserService.CreateUserRequest;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Optional;
+
+@RestController
+@RequestMapping("/api/users")
+@RequiredArgsConstructor
+public class UserController {
+
+ private final UserService userService;
+
+ @PostMapping
+ public ResponseEntity createUser(@RequestBody CreateUserRequest request) {
+ User user = userService.createUser(request);
+ return ResponseEntity.status(HttpStatus.CREATED).body(user);
+ }
+
+ @GetMapping
+ public ResponseEntity> getAllUsers() {
+ List users = userService.getAllUsers();
+ return ResponseEntity.ok(users);
+ }
+
+ @GetMapping("/{id}")
+ public ResponseEntity getUserById(@PathVariable Long id) {
+ User user = userService.getUserById(id);
+ return ResponseEntity.ok(user);
+ }
+
+ @GetMapping("/email/{email}")
+ public ResponseEntity> getUserByEmail(@PathVariable String email) {
+ Optional user = userService.getUserByEmail(email);
+ return ResponseEntity.ok(user);
+ }
+}
\ No newline at end of file
diff --git a/user-service/src/main/java/com/example/user/entity/User.java b/user-service/src/main/java/com/example/user/entity/User.java
new file mode 100644
index 0000000..4b03169
--- /dev/null
+++ b/user-service/src/main/java/com/example/user/entity/User.java
@@ -0,0 +1,27 @@
+package com.example.user.entity;
+
+import com.example.common.BaseEntity;
+import jakarta.persistence.*;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Entity
+@Table(name = "users")
+@Getter
+@Setter
+@NoArgsConstructor
+public class User extends BaseEntity {
+
+ @Column(nullable = false, unique = true)
+ private String email;
+
+ @Column(nullable = false)
+ private String name;
+
+ // 필요한 생성자만 직접 정의
+ public User(String email, String name) {
+ this.email = email;
+ this.name = name;
+ }
+}
\ No newline at end of file
diff --git a/user-service/src/main/java/com/example/user/repository/UserRepository.java b/user-service/src/main/java/com/example/user/repository/UserRepository.java
new file mode 100644
index 0000000..663c20d
--- /dev/null
+++ b/user-service/src/main/java/com/example/user/repository/UserRepository.java
@@ -0,0 +1,12 @@
+package com.example.user.repository;
+
+import com.example.user.entity.User;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.Optional;
+
+@Repository
+public interface UserRepository extends JpaRepository {
+ Optional findByEmail(String email);
+}
\ No newline at end of file
diff --git a/user-service/src/main/java/com/example/user/service/UserService.java b/user-service/src/main/java/com/example/user/service/UserService.java
new file mode 100644
index 0000000..747ab4c
--- /dev/null
+++ b/user-service/src/main/java/com/example/user/service/UserService.java
@@ -0,0 +1,50 @@
+package com.example.user.service;
+
+import com.example.user.entity.User;
+import com.example.user.repository.UserRepository;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Optional;
+
+@Service
+@RequiredArgsConstructor
+public class UserService {
+
+ private final UserRepository userRepository;
+
+ public User createUser(CreateUserRequest request) {
+ User user = new User(request.getEmail(), request.getName());
+ return userRepository.save(user);
+ }
+
+ public List getAllUsers() {
+ return userRepository.findAll();
+ }
+
+ public User getUserById(Long id) {
+ return userRepository.findById(id)
+ .orElseThrow(() -> new IllegalArgumentException("User not found with id: " + id));
+ }
+
+ public Optional getUserByEmail(String email) {
+ return userRepository.findByEmail(email);
+ }
+
+ @Getter
+ @Setter
+ @NoArgsConstructor
+ public static class CreateUserRequest {
+ private String email;
+ private String name;
+
+ public CreateUserRequest(String email, String name) {
+ this.email = email;
+ this.name = name;
+ }
+ }
+}
\ No newline at end of file
diff --git a/user-service/src/main/resources/application.yml b/user-service/src/main/resources/application.yml
new file mode 100644
index 0000000..4f35a5c
--- /dev/null
+++ b/user-service/src/main/resources/application.yml
@@ -0,0 +1,36 @@
+spring:
+ application:
+ name: user-service
+
+ datasource:
+ url: jdbc:h2:mem:userdb
+ driverClassName: org.h2.Driver
+ username: sa
+ password:
+
+ h2:
+ console:
+ enabled: true
+ path: /h2-console
+
+ jpa:
+ hibernate:
+ ddl-auto: create-drop
+ show-sql: true
+ properties:
+ hibernate:
+ format_sql: true
+
+server:
+ port: 8081
+
+eureka:
+ client:
+ service-url:
+ defaultZone: http://localhost:8761/eureka/
+ instance:
+ prefer-ip-address: true
+
+logging:
+ level:
+ com.example: DEBUG
\ No newline at end of file