-
Notifications
You must be signed in to change notification settings - Fork 2
[FEAT] member 서버 분리 #64
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,17 @@ | ||||||||||
| # Stage 1: Build | ||||||||||
| FROM gradle:8.5-jdk21 AS build | ||||||||||
| WORKDIR /app | ||||||||||
| COPY . . | ||||||||||
| RUN gradle :domain-member:bootJar --no-daemon | ||||||||||
|
Comment on lines
+4
to
+5
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Docker 이미지 빌드 효율을 높이기 위해 Docker 레이어 캐시를 활용하는 것이 좋습니다. 현재 이를 개선하기 위해, 빌드 파일을 먼저 복사하여 의존성을 다운로드하고, 그 다음에 소스 코드를 복사하는 단계로 나누는 것을 권장합니다. 이렇게 하면 소스 코드만 변경되었을 때 의존성 다운로드 단계를 건너뛰어 빌드 시간을 크게 단축할 수 있습니다. 예시적인 구조는 다음과 같습니다: # 1. 빌드 관련 파일만 복사
COPY build.gradle settings.gradle ./
# (필요에 따라 각 모듈의 build.gradle도 복사)
# 2. 의존성 다운로드 (이 레이어가 캐시됨)
RUN gradle dependencies
# 3. 전체 소스 코드 복사
COPY . .
# 4. 애플리케이션 빌드
RUN gradle :domain-member:bootJar --no-daemon |
||||||||||
|
|
||||||||||
| # Stage 2: Runtime | ||||||||||
| FROM openjdk:21-jdk-slim | ||||||||||
| WORKDIR /app | ||||||||||
| COPY --from=build /app/domain-member/build/libs/*.jar app.jar | ||||||||||
|
|
||||||||||
| EXPOSE 8082 | ||||||||||
|
|
||||||||||
| HEALTHCHECK --interval=30s --timeout=3s --start-period=40s \ | ||||||||||
| CMD curl -f http://localhost:8082/actuator/health || exit 1 | ||||||||||
|
Comment on lines
+14
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. HEALTHCHECK가 실패할 수 있습니다. openjdk:21-jdk-slim 이미지에는 curl이 기본적으로 포함되어 있지 않습니다. 헬스체크가 실패하여 컨테이너가 unhealthy 상태가 됩니다. 해결 방법 1 (권장): 런타임 이미지에 curl 설치 # Stage 2: Runtime
FROM openjdk:21-jdk-slim
WORKDIR /app
+RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
COPY --from=build /app/domain-member/build/libs/*.jar app.jar해결 방법 2: wget 사용 (slim 이미지에 포함됨) HEALTHCHECK --interval=30s --timeout=3s --start-period=40s \
- CMD curl -f http://localhost:8082/actuator/health || exit 1
+ CMD wget --no-verbose --tries=1 --spider http://localhost:8082/actuator/health || exit 1📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||
|
|
||||||||||
| ENTRYPOINT ["java", "-Xms256m", "-Xmx512m", "-XX:+UseG1GC", "-jar", "app.jar"] | ||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| //package com.wellmeet.domain; | ||
| // | ||
| //import org.springframework.boot.SpringApplication; | ||
| //import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
| // | ||
| //@SpringBootApplication | ||
| //public class MemberServiceApplication { | ||
| // | ||
| // public static void main(String[] args) { | ||
| // SpringApplication.run(MemberServiceApplication.class, args); | ||
| // } | ||
| //} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| package com.wellmeet.domain.member.controller; | ||
|
|
||
| import com.wellmeet.domain.member.dto.FavoriteRestaurantResponse; | ||
| import com.wellmeet.domain.member.service.FavoriteRestaurantApplicationService; | ||
| import java.util.List; | ||
| import org.springframework.http.HttpStatus; | ||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.web.bind.annotation.DeleteMapping; | ||
| import org.springframework.web.bind.annotation.GetMapping; | ||
| import org.springframework.web.bind.annotation.PathVariable; | ||
| import org.springframework.web.bind.annotation.PostMapping; | ||
| import org.springframework.web.bind.annotation.RequestMapping; | ||
| import org.springframework.web.bind.annotation.RequestParam; | ||
| import org.springframework.web.bind.annotation.RestController; | ||
|
|
||
| @RestController | ||
| @RequestMapping("/api/favorites") | ||
| public class FavoriteRestaurantController { | ||
|
|
||
| private final FavoriteRestaurantApplicationService favoriteRestaurantApplicationService; | ||
|
|
||
| public FavoriteRestaurantController(FavoriteRestaurantApplicationService favoriteRestaurantApplicationService) { | ||
| this.favoriteRestaurantApplicationService = favoriteRestaurantApplicationService; | ||
| } | ||
|
Comment on lines
+22
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| @GetMapping("/check") | ||
| public ResponseEntity<Boolean> isFavorite( | ||
| @RequestParam String memberId, | ||
| @RequestParam String restaurantId | ||
| ) { | ||
| boolean isFavorite = favoriteRestaurantApplicationService.isFavorite(memberId, restaurantId); | ||
| return ResponseEntity.ok(isFavorite); | ||
| } | ||
|
|
||
| @GetMapping("/members/{memberId}") | ||
| public ResponseEntity<List<FavoriteRestaurantResponse>> getFavoritesByMemberId( | ||
| @PathVariable String memberId | ||
| ) { | ||
| List<FavoriteRestaurantResponse> responses = | ||
| favoriteRestaurantApplicationService.getFavoritesByMemberId(memberId); | ||
| return ResponseEntity.ok(responses); | ||
| } | ||
|
|
||
| @PostMapping | ||
| public ResponseEntity<FavoriteRestaurantResponse> addFavorite( | ||
| @RequestParam String memberId, | ||
| @RequestParam String restaurantId | ||
| ) { | ||
| FavoriteRestaurantResponse response = | ||
| favoriteRestaurantApplicationService.addFavorite(memberId, restaurantId); | ||
| return ResponseEntity.status(HttpStatus.CREATED).body(response); | ||
| } | ||
|
|
||
| @DeleteMapping | ||
| public ResponseEntity<Void> removeFavorite( | ||
| @RequestParam String memberId, | ||
| @RequestParam String restaurantId | ||
| ) { | ||
| favoriteRestaurantApplicationService.removeFavorite(memberId, restaurantId); | ||
| return ResponseEntity.noContent().build(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| package com.wellmeet.domain.member.controller; | ||
|
|
||
| import com.wellmeet.domain.member.dto.CreateMemberRequest; | ||
| import com.wellmeet.domain.member.dto.MemberIdsRequest; | ||
| import com.wellmeet.domain.member.dto.MemberResponse; | ||
| import com.wellmeet.domain.member.service.MemberApplicationService; | ||
| import jakarta.validation.Valid; | ||
| import java.util.List; | ||
| import org.springframework.http.HttpStatus; | ||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.web.bind.annotation.DeleteMapping; | ||
| import org.springframework.web.bind.annotation.GetMapping; | ||
| import org.springframework.web.bind.annotation.PathVariable; | ||
| import org.springframework.web.bind.annotation.PostMapping; | ||
| import org.springframework.web.bind.annotation.RequestBody; | ||
| import org.springframework.web.bind.annotation.RequestMapping; | ||
| import org.springframework.web.bind.annotation.RestController; | ||
|
|
||
| @RestController | ||
| @RequestMapping("/api/members") | ||
| public class MemberController { | ||
|
|
||
| private final MemberApplicationService memberApplicationService; | ||
|
|
||
| public MemberController(MemberApplicationService memberApplicationService) { | ||
| this.memberApplicationService = memberApplicationService; | ||
| } | ||
|
Comment on lines
+25
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| @PostMapping | ||
| public ResponseEntity<MemberResponse> createMember(@Valid @RequestBody CreateMemberRequest request) { | ||
| MemberResponse response = memberApplicationService.createMember( | ||
| request.name(), | ||
| request.nickname(), | ||
| request.email(), | ||
| request.phone() | ||
| ); | ||
| return ResponseEntity.status(HttpStatus.CREATED).body(response); | ||
| } | ||
|
|
||
| @GetMapping("/{id}") | ||
| public ResponseEntity<MemberResponse> getMember(@PathVariable String id) { | ||
| MemberResponse response = memberApplicationService.getMemberById(id); | ||
| return ResponseEntity.ok(response); | ||
| } | ||
|
|
||
| @PostMapping("/batch") | ||
| public ResponseEntity<List<MemberResponse>> getMembersByIds( | ||
| @Valid @RequestBody MemberIdsRequest request | ||
| ) { | ||
| List<MemberResponse> responses = memberApplicationService.getMembersByIds(request.memberIds()); | ||
| return ResponseEntity.ok(responses); | ||
| } | ||
|
|
||
| @DeleteMapping("/{id}") | ||
| public ResponseEntity<Void> deleteMember(@PathVariable String id) { | ||
| memberApplicationService.deleteMember(id); | ||
| return ResponseEntity.noContent().build(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| package com.wellmeet.domain.member.dto; | ||
|
|
||
| import jakarta.validation.constraints.NotBlank; | ||
|
|
||
| public record CreateMemberRequest( | ||
| @NotBlank | ||
| String name, | ||
|
|
||
| @NotBlank | ||
| String nickname, | ||
|
|
||
| @NotBlank | ||
| String email, | ||
|
Comment on lines
+12
to
+13
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. email 필드에 형식 검증이 필요합니다. email 필드가 @notblank만으로 검증되고 있습니다. 이메일 형식의 유효성을 보장하기 위해 @Email 어노테이션을 추가해야 합니다. 다음 diff를 적용하세요: +import jakarta.validation.constraints.Email;
+
public record CreateMemberRequest(
@NotBlank
String name,
@NotBlank
String nickname,
@NotBlank
+ @Email
String email,🤖 Prompt for AI Agents |
||
|
|
||
| @NotBlank | ||
| String phone | ||
| ) { | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
데이터베이스 비밀번호와 같은 민감한 정보를
docker-compose.yml에 직접 작성하는 것은 보안상 위험할 수 있습니다. 로컬 환경이라도.env파일을 활용하여 환경 변수로 주입하고,.env파일은.gitignore에 추가하여 관리하는 것이 좋습니다. 이렇게 하면 실수로 인증 정보가 Git에 커밋되는 것을 방지할 수 있습니다.