diff --git a/.coderabbit.yaml b/.coderabbit.yaml
new file mode 100644
index 0000000..617b822
--- /dev/null
+++ b/.coderabbit.yaml
@@ -0,0 +1,63 @@
+# 리뷰 언어 설정 - 한국어로 피드백을 받습니다
+language: "ko-KR"
+
+reviews:
+ # 리뷰 강도 설정
+ # assertive(꼼꼼) / chill(부드럽게) 중 선택
+ profile: "chill"
+
+ # true로 설정 시, 모든 리뷰 코멘트가 resolve되면 자동으로 승인(Approve)
+ request_changes_workflow: false
+
+ # PR 요약
+ high_level_summary: true # PR 전반적인 변경 내용 요약
+ changed_files_summary: true # 파일별 변경 내용 요약
+
+ # 워크스루를 접힌 상태로 표시해 PR 페이지가 너무 길어지는 것을 방지
+ collapse_walkthrough: true
+
+ # 코드 흐름을 시각적으로 파악할 수 있는 시퀀스 다이어그램 생성
+ sequence_diagrams: true
+
+ # 연결된 이슈를 분석해 리뷰에 맥락을 추가
+ assess_linked_issues: true
+
+ # 관련 이슈/PR 자동 링크 (팀 규모가 작아 비활성화)
+ related_issues: false
+ related_prs: false
+
+ # 레이블 자동 제안/적용 (수동으로 관리)
+ suggested_labels: false
+ auto_apply_labels: false
+
+ # 리뷰어 추천/자동 할당 (수동으로 지정)
+ suggested_reviewers: false
+ auto_assign_reviewers: false
+
+ # -------------------------------------------------------------- #
+ # 자동 리뷰 설정 #
+ # -------------------------------------------------------------- #
+ auto_review:
+ # PR 생성 시 자동으로 리뷰 시작
+ enabled: true
+ # 기존 리뷰가 있는 PR에 새 커밋이 추가되면 변경분만 다시 리뷰
+ auto_incremental_review: true
+
+# ================================================================ #
+# 채팅 설정 #
+# ================================================================ #
+chat:
+ # @coderabbitai 멘션 없이도 PR 코멘트에 자동으로 응답
+ auto_reply: true
+
+# ================================================================ #
+# 지식 베이스 설정 #
+# ================================================================ #
+knowledge_base:
+ # 리뷰 시 최신 문서나 정보를 웹에서 검색해 참고할 수 있도록 허용
+ web_search:
+ enabled: true
+
+ # 레포에 코딩 컨벤션이나 가이드라인 문서가 있다면 리뷰에 반영
+ code_guidelines:
+ enabled: true
\ No newline at end of file
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index ea57d1d..6e2d5b8 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -5,7 +5,7 @@
- [ ] 기타 사소한 수정
## ❗️ 관련 이슈 링크
-Close #
+Closed #
## 📌 개요
-
diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml
new file mode 100644
index 0000000..5a77a76
--- /dev/null
+++ b/.github/workflows/cd.yml
@@ -0,0 +1,85 @@
+name: SCOI CD
+on:
+ push:
+ branches: [ "develop" ]
+
+env:
+ # 도커 허브 저장소 이름 (예: myusername/scoi-backend)
+ DOCKER_IMAGE_NAME: ${{ secrets.DOCKER_USERNAME }}/scoi-backend
+
+jobs:
+ # 📦 1단계: 빌드 및 도커 이미지 푸시
+ build-and-push:
+ runs-on: ubuntu-latest
+ steps:
+ - name: 체크아웃
+ uses: actions/checkout@v4
+
+ - name: 자바 설정 Set up JDK 21
+ uses: actions/setup-java@v4
+ with:
+ java-version: '21'
+ distribution: 'temurin'
+ cache: 'gradle'
+
+ - name: application.yml 주입
+ shell: bash
+ run: |
+ mkdir -p src/main/resources
+ cat > src/main/resources/application.yml <<'EOF'
+ ${{ secrets.DEV_APPLICATION_YML }}
+ EOF
+
+ - name: firebase json 주입
+ shell: bash
+ run: |
+ mkdir -p src/main/resources
+ cat > src/main/resources/firebase-scoi.json <<'EOF'
+ ${{ secrets.FIREBASE_JSON }}
+ EOF
+
+ - name: gradlew 실행 권한 부여
+ run: chmod +x gradlew
+
+ - name: gradle 빌드 (테스트 제외)
+ run: ./gradlew clean build -x test
+
+ - name: Docker Hub 로그인
+ uses: docker/login-action@v3
+ with:
+ username: ${{ secrets.DOCKER_USERNAME }}
+ password: ${{ secrets.DOCKER_PASSWORD }}
+
+ - name: Docker 이미지 빌드 및 푸시
+ uses: docker/build-push-action@v5
+ with:
+ context: .
+ push: true
+ tags: ${{ env.DOCKER_IMAGE_NAME }}:latest
+
+
+ deploy:
+ needs: build-and-push
+ runs-on: ubuntu-latest
+ steps:
+ - name: EC2에 배포 (SSH 접속)
+ uses: appleboy/ssh-action@master
+ with:
+ host: ${{ secrets.EC2_HOST }}
+ username: ${{ secrets.EC2_SSH_USER }}
+ key: ${{ secrets.EC2_SSH_KEY }}
+
+ script: |
+ cd ~/scoi-Backend
+
+ echo "${{ secrets.DEV_ENV_FILE }}" > .env
+ echo "DOCKER_USERNAME=${{ secrets.DOCKER_USERNAME }}" >> .env
+
+ # Docker Hub에서 방금 만든 최신 이미지 가져오기
+ sudo docker-compose pull
+
+ # 컨테이너 재실행
+ sudo docker-compose up -d
+
+ # 불필요한 이미지 삭제
+ sudo docker image prune -f
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..206cb9a
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,76 @@
+name: SCOI CI
+
+on:
+ push:
+ branches: [ "main", "develop" ]
+ pull_request:
+ branches: [ "main", "develop" ]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ # CI 서버 내부에서 테스트용 DB/Redis 컨테이너 실행
+ services:
+ mysql:
+ image: mysql:8.0
+ env:
+ MYSQL_ROOT_PASSWORD: root
+ MYSQL_DATABASE: scoi
+ ports:
+ - 3306:3306
+ options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
+
+ redis:
+ image: redis:latest
+ ports:
+ - 6379:6379
+ options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
+
+ steps:
+ - name: 체크아웃
+ uses: actions/checkout@v4
+
+ - name: 자바 설정 Set up JDK 21
+ uses: actions/setup-java@v4
+ with:
+ java-version: '21'
+ distribution: 'temurin'
+ cache: 'gradle'
+
+ - name: application.yml 주입
+ shell: bash
+ run: |
+ mkdir -p src/main/resources
+ cat > src/main/resources/application.yml <<'EOF'
+ ${{ secrets.DEV_APPLICATION_YML }}
+ EOF
+
+ # firebase 파일 생성
+ - name: firebase json 주입
+ shell: bash
+ run: |
+ mkdir -p src/main/resources
+ cat > src/main/resources/firebase-scoi.json <<'EOF'
+ ${{ secrets.FIREBASE_JSON }}
+ EOF
+
+ - name: gradlew 실행 권한 부여
+ run: chmod +x gradlew
+
+ - name: gradle 빌드
+ run: ./gradlew build
+
+ # CI용
+ env:
+ DB_URL: jdbc:mysql://localhost:3306/scoi?serverTimezone=Asia/Seoul
+ DB_USERNAME: root
+ DB_PASSWORD: root
+ REDIS_HOST: localhost
+ REDIS_PORT: 6379
+ JWT_KEY: scoi-test-key
+ JWT_SECRET: scoi-test-secret-keysdsdsdsdsdsdssdsdsdsdsdsdsdsdsdsdsdsdsdsdsds
+ COOLSMS_API_URL: test_coolsms_api_key
+ COOLSMS_API_SECRET: test_coolsms_secret_key
+ COOLSMS_API_KEY: test_coolsms_key
+ COOLSMS_FROM_NUMBER: 01000000000
\ No newline at end of file
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
deleted file mode 100644
index 10a708b..0000000
--- a/.github/workflows/deploy.yml
+++ /dev/null
@@ -1,92 +0,0 @@
-name: Deploy (dev/main, Java 21, firebase shared)
-
-on:
- push:
- branches: [ "develop" ] # "main" 주석처리
-
-jobs:
- deploy:
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Set up Java 21
- uses: actions/setup-java@v4
- with:
- distribution: 'temurin'
- java-version: '21'
-
- # 공통 firebase 파일 생성
- - name: Inject firebase json (shared)
- shell: bash
- run: |
- mkdir -p src/main/resources
- cat > src/main/resources/firebase-scoi.json <<'EOF'
- ${{ secrets.FIREBASE_JSON }}
- EOF
-
- # # main application.yml (주석처리 — develop만 배포)
- # - name: Inject application.yml (main)
- # if: github.ref_name == 'main'
- # shell: bash
- # run: |
- # mkdir -p src/main/resources
- # cat > src/main/resources/application.yml <<'EOF'
- # ${{ secrets.APP_YML_MAIN }}
- # EOF
-
- # dev application.yml
- - name: Inject application.yml (dev)
- if: github.ref_name == 'develop'
- shell: bash
- run: |
- mkdir -p src/main/resources
- cat > src/main/resources/application.yml <<'EOF'
- ${{ secrets.APP_YML_DEV }}
- EOF
-
- - name: Build bootJar
- run: |
- chmod +x ./gradlew
- ./gradlew clean bootJar -x test
-
- - name: Prepare SSH
- run: |
- mkdir -p ~/.ssh
- echo "${{ secrets.EC2_SSH_KEY }}" > ~/.ssh/id_ed25519
- chmod 600 ~/.ssh/id_ed25519
- ssh-keyscan -H "${{ secrets.EC2_HOST }}" >> ~/.ssh/known_hosts
-
- - name: Upload jar to EC2
- shell: bash
- run: |
- # bootJar/ plain.jar 혼동 방지: plain 제외 우선 선택
- JAR_PATH=$(ls build/libs/*.jar | grep -v plain | head -n 1)
- test -n "$JAR_PATH"
- scp "$JAR_PATH" ${{ secrets.EC2_USER }}@${{ secrets.EC2_HOST }}:/home/${{ secrets.EC2_USER }}/app.jar
-
- # - name: Deploy & restart (main) # 주석처리 — develop만 배포
- # if: github.ref_name == 'main'
- # run: |
- # ssh ${{ secrets.EC2_USER }}@${{ secrets.EC2_HOST }} << 'EOF'
- # set -e
- # sudo mkdir -p /opt/myapp-main
- # sudo mv /home/ec2-user/app.jar /opt/myapp-main/app.jar
- # sudo chown -R ec2-user:ec2-user /opt/myapp-main
- # sudo systemctl restart myapp-main
- # sudo systemctl status myapp-main --no-pager
- # EOF
-
- - name: Deploy & restart (dev)
- if: github.ref_name == 'develop'
- run: |
- ssh ${{ secrets.EC2_USER }}@${{ secrets.EC2_HOST }} << 'EOF'
- set -e
- sudo mkdir -p /opt/myapp-dev
- sudo mv /home/ec2-user/app.jar /opt/myapp-dev/app.jar
- sudo chown -R ec2-user:ec2-user /opt/myapp-dev
- sudo systemctl restart myapp-dev
- sudo systemctl status myapp-dev --no-pager
- EOF
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 060889e..9757ff1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,7 +2,7 @@
*.yml
*.properties
# GitHub Actions workflow는 예외로 추적
-!.github/workflows/deploy.yml
+!.github/workflows/
### workflow.yml 제외 ###
!workflow.yml
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..00ddcf2
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,7 @@
+FROM eclipse-temurin:21-jdk-alpine
+
+WORKDIR /app
+
+COPY build/libs/*SNAPSHOT.jar app.jar
+
+ENTRYPOINT ["java", "-jar", "-Duser.timezone=Asia/Seoul", "app.jar"]
\ No newline at end of file
diff --git a/README.md b/README.md
index 6ecb84f..5555b17 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,10 @@
# 스코이 : 편리한 스테이블 코인 결제 플랫폼
+
## 💡 Project Overview
-스코이는 스테이블코인을 일상적인 결제 수단으로 사용할 수 있도록 설계된 금융 플랫폼입니다.
-결제부터 투자까지, 누구나 쉽게 사용할 수 있는 편리한 스테이블 코인 금융 환경을 제공하는 것을 목표로 합니다.
+스코이는 스테이블코인을 일상적인 결제 수단으로 사용할 수 있도록 설계된 금융 플랫폼입니다
+결제부터 투자까지, 누구나 쉽게 사용할 수 있는 편리한 스테이블 코인 금융 환경을 제공하는 것을 목표로 합니다
diff --git a/build.gradle b/build.gradle
index 8bdb235..9d9c57e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -82,6 +82,12 @@ dependencies {
// Retry
implementation 'org.springframework.retry:spring-retry'
+
+ // Spring Actuator
+ implementation 'org.springframework.boot:spring-boot-starter-actuator'
+
+ // Prometheus
+ runtimeOnly 'io.micrometer:micrometer-registry-prometheus'
}
tasks.named('test') {
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..9c0ef24
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,32 @@
+version: '3.8'
+
+services:
+ scoi-backend:
+ image: ${DOCKER_USERNAME}/scoi-backend:latest
+ container_name: scoi-backend
+ ports:
+ - "8080:8080"
+
+ env_file:
+ - .env
+
+ depends_on:
+ - redis
+
+ networks:
+ - scoi-network
+
+ restart: always
+
+ redis:
+ image: redis:latest
+ container_name: scoi-redis
+ ports:
+ - "6379:6379"
+ networks:
+ - scoi-network
+ restart: always
+
+networks:
+ scoi-network:
+ driver: bridge
\ No newline at end of file
diff --git a/src/main/java/com/example/scoi/global/config/SecurityConfig.java b/src/main/java/com/example/scoi/global/config/SecurityConfig.java
index b017ef7..9343ee6 100644
--- a/src/main/java/com/example/scoi/global/config/SecurityConfig.java
+++ b/src/main/java/com/example/scoi/global/config/SecurityConfig.java
@@ -37,6 +37,7 @@ public class SecurityConfig {
"/auth/login", // 로그인
"/auth/reissue", // 토큰 재발급
"/auth/password/reset", // 비인증 비밀번호 재설정
+ "/actuator/**", // 모니터링
"/swagger-ui/**",
"/v3/api-docs/**",
"/swagger-resources/**",
diff --git a/src/main/java/com/example/scoi/global/config/SwaggerConfig.java b/src/main/java/com/example/scoi/global/config/SwaggerConfig.java
index 4add088..cdc676f 100644
--- a/src/main/java/com/example/scoi/global/config/SwaggerConfig.java
+++ b/src/main/java/com/example/scoi/global/config/SwaggerConfig.java
@@ -14,7 +14,7 @@ public class SwaggerConfig {
@Bean
public OpenAPI swagger() {
- Info info = new Info().title("스코이").description("스코이 Swagger").version("0.4.0");
+ Info info = new Info().title("스코이").description("스코이 Swagger").version("0.5.0");
// JWT 토큰 헤더 방식
String securityScheme = "JWT TOKEN";