Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
d425ac6
[test] 코드래빗 테스트용 코드 작성
seung-in-Yoo Jun 23, 2025
a33c2a1
[chore] CodeRabbit 설정 파일 추가
seung-in-Yoo Jun 23, 2025
18bc250
[test] test 코드 삭제
seung-in-Yoo Jun 23, 2025
f9449c5
[chore] CodeRabbit 리뷰 수위 완화 설정
seung-in-Yoo Jun 24, 2025
e161bd0
Merge pull request #3 from Wayble-Project/feature/seungin
seung-in-Yoo Jun 24, 2025
94665f5
[feat] Logger 구현 완료
KiSeungMin Jun 25, 2025
cd77b99
[feat] 응답 형식 통일 완료
KiSeungMin Jun 25, 2025
09f8054
[feat] 예외 핸들러, 예외 객체 구현 완료
KiSeungMin Jun 25, 2025
335e664
[feat] 예시 예외 객체, 컨트롤러 구현 완료
KiSeungMin Jun 25, 2025
b3ab8a9
[chore] PR 템플릿 위치 변경
KiSeungMin Jun 25, 2025
9d31476
[chore] PR 템플릿 이름 변경
KiSeungMin Jun 25, 2025
a18daf6
[fix] coderabbit 오류 수정
zyovn Jun 25, 2025
7018b16
[fix] 수정
zyovn Jun 25, 2025
99f5053
[fix] 브랜치 관련 설정 삭제
zyovn Jun 25, 2025
7a14b5e
[fix] enabled true 삭제
zyovn Jun 25, 2025
546b828
Merge pull request #8 from Wayble-Project/feature/jeongbin
zyovn Jun 25, 2025
fe179ef
[feat] AOP 적용
KiSeungMin Jun 26, 2025
0fa5042
[feat] BaseEntity 적용
KiSeungMin Jul 4, 2025
e726586
[feat] JPA, MySQL 의존성 추가
KiSeungMin Jul 4, 2025
7be9e31
[feat] 주소 정보를 담는 Address 구현 완료
KiSeungMin Jul 4, 2025
e4e8de0
[feat] 유저 엔티티 정의 완료
KiSeungMin Jul 4, 2025
321598c
[feat] 유저 관련 repository, service, controller 생성 완료
KiSeungMin Jul 4, 2025
f849e88
[feat] 유저 관련 예외 구조체 정의
KiSeungMin Jul 4, 2025
47f3ff5
[chore] 디렉터리 구조 수정
KiSeungMin Jul 4, 2025
5f9d400
[feat] 유저 관련 예외 발생 로직을 Service로 옮기기
KiSeungMin Jul 5, 2025
556defb
[feat] 웨이블존 예외 객체 생성 완료
KiSeungMin Jul 5, 2025
59b6cf1
[chore] 디렉토리명을 domain -> entity로 수정
KiSeungMin Jul 5, 2025
95f60cf
[feat] User 관련 Dto 생성 완료
KiSeungMin Jul 5, 2025
49f9701
[feat] 웨이블존 관련 Dto 생성 완료
KiSeungMin Jul 5, 2025
03945be
[feat] 웨이블존 관련 repository, service, controller 생성 완료
KiSeungMin Jul 5, 2025
c5df0ba
[feat] 웨이블존 엔티티 구현 완료
KiSeungMin Jul 5, 2025
63215be
[feat] 리뷰 관련 controller, service, repository 구현 완료
KiSeungMin Jul 5, 2025
3a8af36
[feat] 리뷰 관련 dto 구현 완료
KiSeungMin Jul 5, 2025
5f05e6b
[feat] Review 엔티티 구현 완료
KiSeungMin Jul 5, 2025
0ce6768
[feat] 길찾기 관련 controller, service, exception 구현 완료
KiSeungMin Jul 5, 2025
28847ec
[feat] 지도 검색 관련 controller, service, exception 구현 완료
KiSeungMin Jul 5, 2025
c61723c
[fix] 위도, 경도 필드 소숫점 설정 오류 해결
KiSeungMin Jul 5, 2025
6d7d78e
[fix] CodeRabbit이 알려준 개선사항 반영
KiSeungMin Jul 5, 2025
82400fe
Merge pull request #10 from Wayble-Project/feature/seungmin
KiSeungMin Jul 5, 2025
2ffba3a
CI:CI/CD 파이프라인 구축
Jul 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .coderabbit.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
reviewer: "code-review-bot"
language: "ko-KR"
frameworks:
- "Spring Boot"
- "JPA"
rules:
- name: "Spring Boot Best Practices"
- name: "Avoid Field Injection"
- name: "Avoid N+1 Queries"
- name: "Use Constructor Injection"
style: "concise"
ignore:
- path: "src/test/"
- path: "**/*.md"
reviews:
review_status: true
profile: "chill"
auto_review:
enabled: true
drafts: false
chat:
auto_reply: true
82 changes: 82 additions & 0 deletions .github/workflows/cd-develop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: CI/CD Pipeline

on:
push:
branches: [ develop ] # develop 브랜치에 push가 일어날 때 실행

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3 # 저장소 코드 체크아웃

- name: Set up JDK 17 # Java 개발 킷 설정
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'

- name: Make application.yml # application.yml 파일 생성
run: |
cd ./src/main/resources
echo "${{ secrets.APPLICATION_YML }}" > ./application.yml
shell: bash

- name: Grant execute permission for gradlew # gradlew 실행 권한 부여
run: chmod +x gradlew

- name: Build with Gradle # Gradle을 사용하여 프로젝트 빌드
uses: gradle/gradle-build-action@v2
with:
arguments: build

- name: Upload build artifact # 빌드된 아티팩트 업로드
uses: actions/upload-artifact@v3
with:
name: umc7thServer
path: build/libs/*.jar

deploy:
needs: build # build 작업이 성공적으로 완료된 후 실행
runs-on: ubuntu-latest

steps:
- name: Download build artifact # 이전 단계에서 업로드한 아티팩트 다운로드
uses: actions/download-artifact@v3
with:
name: umc7thServer
path: build/libs/

- name: Deploy to EC2 # EC2에 배포
env:
EC2_SSH_KEY: ${{ secrets.EC2_SSH_KEY }}
EC2_USERNAME: ${{ secrets.EC2_USERNAME }}
EC2_HOST: ${{ secrets.EC2_HOST }}
run: |
echo "$EC2_SSH_KEY" > private_key.pem
chmod 600 private_key.pem
jar_file=$(find build/libs -name '*.jar' ! -name '*plain.jar' | head -n 1)
scp -i private_key.pem -o StrictHostKeyChecking=no "$jar_file" $EC2_USERNAME@$EC2_HOST:/home/$EC2_USERNAME/umc7thServer.jar
ssh -i private_key.pem -o StrictHostKeyChecking=no $EC2_USERNAME@$EC2_HOST "
pgrep java | xargs -r kill -15 # 기존에 실행 중인 Java 프로세스 종료
sleep 10
nohup java -jar /home/$EC2_USERNAME/umc7thServer.jar > app.log 2>&1 & # 새 버전 애플리케이션 실행
"
rm -f private_key.pem # 민감한 정보 삭제




# name: CD - DEVELOP

# on: #이 워크플로우가 언제 실행될지 트리거를 정의함.
# pull_request:
# types : [closed] #누군가가 Pull request를 닫았을 때 실행됨.
# workflow_dispatch: #수동 실행도 가능하도록

# jobs: #실제 실행할 작업을 정의
# build: #작업 이름
# runs-on: ubuntu-latest #OS환경
# if: github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'develop'
# #닫힌 Pull Request 중에서, 병합된 것이고, 병합 대상 브랜치가 develop 브랜치일 경우에만 이 작업을 실행
27 changes: 25 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.5.3'
id 'org.springframework.boot' version '3.5.3' // 또는 사용 중인 최신 버전
id 'io.spring.dependency-management' version '1.1.7'
}

Expand All @@ -24,14 +24,37 @@ repositories {
}

dependencies {
//implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-aop'

runtimeOnly 'com.mysql:mysql-connector-j'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

// ✅ QueryDSL 수동 설정
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor 'com.querydsl:querydsl-apt:5.0.0:jakarta'

testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

tasks.named('test') {
useJUnitPlatform()
}


def querydslDir = "src/main/generated"

sourceSets {
main.java.srcDirs += [ querydslDir ]
}

tasks.withType(JavaCompile) {
options.annotationProcessorGeneratedSourcesDirectory = file(querydslDir)
}

tasks.named('clean') {
delete fileTree(dir: querydslDir, include: '**/*.java')
}
2 changes: 2 additions & 0 deletions src/main/java/com/wayble/server/ServerApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@SpringBootApplication
@EnableJpaAuditing
public class ServerApplication {

public static void main(String[] args) {
Expand Down
36 changes: 36 additions & 0 deletions src/main/java/com/wayble/server/common/MainController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.wayble.server.common;

import com.wayble.server.common.exception.ApplicationException;
import com.wayble.server.common.response.CommonResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/main")
public class MainController {

/**
* @return
* {
* "data": "main"
* }
*/

@GetMapping("")
public CommonResponse<String> mainTest() {
return CommonResponse.success("main");
}

/**
* @return
* {
* "errorCode": 1001,
* "message": "예외 메시지"
* }
*/
@GetMapping("/exception")
public CommonResponse<String> exceptionTest() {
throw new ApplicationException(MainErrorCase.MAIN_TEST_ERROR);
}
}
16 changes: 16 additions & 0 deletions src/main/java/com/wayble/server/common/MainErrorCase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.wayble.server.common;

import com.wayble.server.common.exception.ErrorCase;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum MainErrorCase implements ErrorCase {

MAIN_TEST_ERROR(400, 1001, "예외 메시지");

private final Integer httpStatusCode;
private final Integer errorCode;
private final String message;
}
54 changes: 54 additions & 0 deletions src/main/java/com/wayble/server/common/aop/LoggingAspect.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.wayble.server.common.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Slf4j
class LoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);

// 예외 발생 시 로깅
@AfterThrowing(pointcut = "execution(* com.wayble..service..*(..))",
throwing = "ex")
public void logAfterThrowing(JoinPoint joinPoint, Throwable ex) {
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getSignature().getDeclaringTypeName();
String layer = getLayerName(className);
logger.error("[{}] [Exception] {}.{}(): {}", layer, className, methodName, ex.getMessage());
}

// 메서드 실행 이전 로깅
@Before("execution(* com.wayble..service..*(..))")
public void logBefore(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getSignature().getDeclaringTypeName();
String layer = getLayerName(className);
logger.info("[{}] [Executing] {}.{}()", layer, className, methodName);
}

// 메서드 실행 이후 로깅
@After("execution(* com.wayble..service..*(..))")
public void logAfter(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getSignature().getDeclaringTypeName();
String layer = getLayerName(className);
logger.info("[{}] [Completed] {}.{}()", layer, className, methodName);
}

// 클래스 이름으로부터 계층(layer) 이름 추출
private String getLayerName(String className) {
if (className.contains("service")) {
return "Service";
}
return "Unknown";
}
}
37 changes: 37 additions & 0 deletions src/main/java/com/wayble/server/common/entity/Address.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.wayble.server.common.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import lombok.Getter;

@Getter
@Embeddable
public class Address {
/** 시·도 */
@Column(name = "state", length = 100, nullable = false)
private String state;

/** 시·군·구 */
@Column(name = "city", length = 100, nullable = false)
private String city;

/** 동·읍·면 */
@Column(name = "district", length = 100)
private String district;

/** 도로명 주소 */
@Column(name = "street_address", length = 200)
private String streetAddress;

/** 상세 주소 */
@Column(name = "detail_address", length = 200)
private String detailAddress;

/** 위도 */
@Column(name = "latitude", columnDefinition = "DECIMAL(10,7)", nullable = false)
private Double latitude;

/** 경도 */
@Column(name = "longitude", columnDefinition = "DECIMAL(10,7)", nullable = false)
private Double longitude;
}
26 changes: 26 additions & 0 deletions src/main/java/com/wayble/server/common/entity/BaseEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.wayble.server.common.entity;

import jakarta.persistence.Column;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;

import java.time.LocalDateTime;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

@MappedSuperclass
@Getter
@EntityListeners(AuditingEntityListener.class)
public class BaseEntity {

@CreatedDate
private LocalDateTime createdAt;

@LastModifiedDate
private LocalDateTime updatedAt;

@Column(name = "deleted_at")
private LocalDateTime deletedAt;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.wayble.server.common.exception;

import lombok.Getter;

@Getter
public class ApplicationException extends RuntimeException {

private final ErrorCase errorCase;

public ApplicationException(ErrorCase errorCase) {
super(errorCase.getMessage());
this.errorCase = errorCase;
}
}
10 changes: 10 additions & 0 deletions src/main/java/com/wayble/server/common/exception/ErrorCase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.wayble.server.common.exception;

public interface ErrorCase {

Integer getHttpStatusCode();

Integer getErrorCode();

String getMessage();
}
Loading
Loading