Repository: sleppy-navigators/study-up-backend
Pull request #48: 깃허브 액션 CD 반영
Author: login: pjy1368
Labels: name: size/M
Created: 2025-04-26T05:21:14Z | Merged: 2025-04-27T01:56:38Z

## 개요

> 3줄 이내로 정리해주세요. 그 이상을 넘어간다면 PR 을 나누는것을 고민해주세요

- 배경
- 변경사항
- 목표가 아닌 것

## 리뷰 시 참고 사항

> 리뷰어에게 의견이 필요하거나, 리뷰어가 중점적으로 보면 좋을 부분을 나열해주세요

- 샘플 참고 사항

## TODO

> 해당 PR이 머지 된 이후에 챙겨야할 부분을 나열해주세요

1. 샘플 Todo

## References

> 사용된 레퍼런스에 대한 링크를 남겨주세요.

[1] [샘플 링크](https://example.com)

## 체크리스트

- [ ] PR 제목을 간결하게 작성했습니다
- [ ] 리뷰 리퀘스트 전에 셀프 리뷰를 진행했습니다
- [ ] 변경사항에 대한 테스트코드를 추가했습니다. 또는, 테스트코드가 필요없는 이유가 있습니다
- [ ] Bug fix, New feature, Breaking Change, Refactoring 등의 Label을 달았습니다


<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **Chores**
  - 새로운 지속적 배포(Continuous Deployment) 워크플로우가 추가되어, main 브랜치 푸시 시 자동 빌드 및 원격 서버에 배포가 진행됩니다.
  - 테스트 환경 설정에 AWS 클라우드 관련 설정이 추가되어, S3 버킷 및 리전 정보가 포함되었습니다.
  - 내부 서브프로젝트 커밋 참조가 최신 버전으로 업데이트되었습니다.
  - `.gitignore`에서 Dockerfile 제외가 해제되어 Dockerfile이 버전 관리에 포함됩니다.
  - Swagger 설정에서 스테이징 서버가 제거되고, 프로덕션 서버가 추가되어 API 서버 정보가 최신화되었습니다.

- **New Features**
  - OpenJDK 17 기반의 Docker 이미지 빌드가 가능해졌습니다.
  - `docker-compose.yaml` 파일이 추가되어, 웹 애플리케이션 서버를 도커 컨테이너로 쉽게 실행할 수 있습니다.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/.github/workflows/cd.yaml b/.github/workflows/cd.yaml
new file mode 100644
index 00000000..8f20544e
--- /dev/null
+++ b/.github/workflows/cd.yaml
@@ -0,0 +1,65 @@
+name: Continuous Deployment
+
+on:
+  push:
+    branches: [ main ]
+
+jobs:
+  build:
+
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@v2
+        with:
+          token: ${{ secrets.CD_PAT }}
+          submodules: recursive
+
+      - name: Set up JDK 17
+        uses: actions/setup-java@v2
+        with:
+          java-version: '17'
+          distribution: 'adopt'
+
+      - name: Setup timezone
+        uses: zcong1993/setup-timezone@master
+        with:
+          timezone: Asia/Seoul
+
+      - name: Grant execute permission for gradlew
+        run: chmod +x gradlew
+
+      - name: Build with Gradle
+        run: ./gradlew clean build
+
+      - name: Copy built project
+        if: success()
+        uses: appleboy/scp-action@master
+        env:
+          GIT_USERNAME: ${{ secrets.GIT_USERNAME }}
+          GIT_PASSWORD: ${{ secrets.GIT_PASSWORD }}
+        with:
+          host: ${{ secrets.EC2_HOST }}
+          username: ${{ secrets.EC2_USERNAME }}
+          key: ${{ secrets.EC2_PRIVATE_KEY }}
+          envs: GIT_USERNAME, GIT_PASSWORD
+          source: '.'
+          target: '/home/ubuntu/application/study-up/backend'
+          strip_components: 1
+
+      - name: Oracle Cloud EC2에 ssh로 접속해서 scripts 실행시키기
+        if: success()
+        uses: appleboy/ssh-action@master
+        env:
+          GIT_USERNAME: ${{ secrets.GIT_USERNAME }}
+          GIT_PASSWORD: ${{ secrets.GIT_PASSWORD }}
+        with:
+          host: ${{ secrets.EC2_HOST }}
+          username: ${{ secrets.EC2_USERNAME }}
+          key: ${{ secrets.EC2_PRIVATE_KEY }}
+          envs: GIT_USERNAME, GIT_PASSWORD
+          script: |
+            cd /home/ubuntu/application/study-up/backend
+            docker-compose up --build -d
+      # TODO: If there's a problem running the new version, should revert to the previous version
diff --git a/.gitignore b/.gitignore
index 56d0e9b5..61d69bed 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,7 +6,6 @@ build/
 !**/src/test/**/build/
 .env
 **/cache
-Dockerfile
 
 ### STS ###
 .apt_generated
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 00000000..295ab9d5
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,4 @@
+FROM openjdk:17
+ARG JAR_FILE=build/libs/*.jar
+COPY ${JAR_FILE} app.jar
+ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=prod", "/app.jar"]
diff --git a/docker-compose.yaml b/docker-compose.yaml
new file mode 100644
index 00000000..752ddb36
--- /dev/null
+++ b/docker-compose.yaml
@@ -0,0 +1,10 @@
+version: "3.7"
+services:
+  web-application-server:
+    container_name: web-application-server
+    build:
+      context: .
+      dockerfile: Dockerfile
+    ports:
+      - "8080:8080"
+    network_mode: "host"
diff --git a/src/main/java/sleppynavigators/studyupbackend/presentation/common/config/SwaggerConfig.java b/src/main/java/sleppynavigators/studyupbackend/presentation/common/config/SwaggerConfig.java
index ba58fcfb..5c9815d4 100644
--- a/src/main/java/sleppynavigators/studyupbackend/presentation/common/config/SwaggerConfig.java
+++ b/src/main/java/sleppynavigators/studyupbackend/presentation/common/config/SwaggerConfig.java
@@ -46,11 +46,9 @@ private Components securitySchemeComponents() {
     }
 
     private List<Server> servers() {
+        Server productionServer = new Server().url("https://api.study-up.site").description("Production server");
         Server localServer = new Server().url("http://localhost:8080").description("Local server");
 
-        // TODO: change the URL of the staging server to the actual URL of the staging server.
-        Server stagingServer = new Server().url("https://whitepiano-codeserver.pe.kr").description("Staging server");
-
-        return List.of(stagingServer, localServer);
+        return List.of(productionServer, localServer);
     }
 }
diff --git a/src/main/resources/config b/src/main/resources/config
index e1d40750..a3616620 160000
--- a/src/main/resources/config
+++ b/src/main/resources/config
@@ -1 +1 @@
-Subproject commit e1d40750e661431d2bb3bf230a63908355af0e56
+Subproject commit a361662009a2c1c26c295d3f7cf7518e0e5e4c6c
diff --git a/src/test/resources/application-test.yaml b/src/test/resources/application-test.yaml
index adaebf8b..fd415471 100644
--- a/src/test/resources/application-test.yaml
+++ b/src/test/resources/application-test.yaml
@@ -16,6 +16,16 @@ spring:
     hibernate:
       ddl-auto: create
     database-platform: org.hibernate.dialect.H2Dialect
+  cloud:
+    aws:
+      credentials:
+        access-key: accesskey
+        secret-key: secretkey
+      region:
+        static: ap-northeast-2
+      s3:
+        bucket: studyup-stage
+        expiration-in-minutes: 5
 
 authentication:
   refresh-token:


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 2**

<details>
<summary>🧹 Nitpick comments (5)</summary><blockquote>

<details>
<summary>.github/workflows/cd.yaml (5)</summary><blockquote>

`1-4`: **배포 트리거 검토: 이벤트 설정**  
현재 워크플로우가 `pull_request` 이벤트로만 트리거됩니다. CD는 일반적으로 `main` 브랜치로의 `push` 또는 태그 생성 시 수행하는 것이 권장되므로, `on.push`나 `on.workflow_dispatch` 설정을 추가하는 방안을 고려하세요.

---

`24-27`: **타임존 액션 버전 고정 권고**  
`zcong1993/setup-timezone@master` 대신 특정 릴리스 태그(예: `v1.x.x`)를 사용해 예측 가능한 빌드 환경을 확보하세요.

---

`32-33`: **Gradle 캐싱으로 빌드 최적화 제안**  
`./gradlew clean build` 단계에 `actions/cache`를 활용해 의존성 캐싱을 추가하면 빌드 시간을 단축할 수 있습니다.

---

`35-48`: **SCP 액션 버전 고정 및 전송 방식 개선**  
`appleboy/scp-action@master` 대신 고정된 버전을 사용하고, 변경된 파일만 전송할 수 있는 `rsync` 또는 incremental deploy 방안을 검토하세요.  
  
```diff
- uses: appleboy/scp-action@master
+ uses: appleboy/scp-action@v0.1.3
```

---

`50-63`: **SSH 액션 안정성 강화**  
`appleboy/ssh-action@master` 대신 특정 버전으로 고정하고, 원격 스크립트 실행 시 첫 줄에 `set -e`를 추가해 오류 발생 시 즉시 중단하도록 설정하세요.  
  
```diff
- uses: appleboy/ssh-action@master
+ uses: appleboy/ssh-action@v0.1.5
...
+ script: |
+   set -e
    cd /home/ubuntu/application/study-up/backend
    docker-compose up --build -d
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 310446c9e9628f22dc54595a861aa8eb136ddb67 and fb676e04a4722c9b1210cf5eb64012e3b7a0283d.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `.github/workflows/cd.yaml` (1 hunks)
* `src/main/resources/config` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 GitHub Actions: Continuous Integration</summary>

<details>
<summary>src/main/resources/config</summary>

[error] 1-1: Git submodule update failed: fatal: remote error: upload-pack: not our ref 5ce5a526898a034bc8365ac84925e0b04bb59ed1

</details>

</details>
<details>
<summary>🪛 GitHub Actions: Continuous Deployment</summary>

<details>
<summary>src/main/resources/config</summary>

[error] 1-1: Git submodule update failed: fatal: remote error: upload-pack: not our ref 5ce5a526898a034bc8365ac84925e0b04bb59ed1

</details>

</details>
<details>
<summary>🪛 actionlint (1.7.4)</summary>

<details>
<summary>.github/workflows/cd.yaml</summary>

12-12: the runner of "actions/checkout@v2" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

---

18-18: the runner of "actions/setup-java@v2" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (2)</summary><blockquote>

<details>
<summary>src/main/resources/config (1)</summary>

`1-1`: <details>
<summary>❓ Verification inconclusive</summary>

**서브모듈 커밋 해시 불일치**  
CD 워크플로우가 `5ce5a526898a034bc8365ac84925e0b04bb59ed1` 커밋을 체크아웃하려 하나, 파이프라인 에러(`fatal: upload-pack: not our ref`)로 보아 해당 해시가 원격 리포지토리에 없습니다. 올바른 커밋 해시로 수정하거나, 원격에 해당 커밋이 푸시되었는지 확인해주세요.  
  
아래 스크립트를 통해 원격 서브모듈에 커밋 존재 여부를 검증할 수 있습니다:

---

🏁 Script executed:

```shell
#!/bin/bash
# 원격 서브모듈 URL 조회
submodule_url=$(git config -f .gitmodules --get-regexp submodule\..*\.url | awk '{print $2}')
echo "Submodule URL: $submodule_url"
# 커밋 존재 여부 확인
if git ls-remote "$submodule_url" 5ce5a526898a034bc8365ac84925e0b04bb59ed1 | grep -q '5ce5a526898a034bc8365ac84925e0b04bb59ed1'; then
  echo "✅ 커밋이 원격에 존재합니다."
else
  echo "❌ 커밋을 찾을 수 없습니다. 해시를 다시 확인하세요."
  exit 1
fi
```

Length of output: 694

---



</details>

**서브모듈 접근 오류 발생 – URL/인증 및 커밋 검증 필요**  
`git ls-remote` 실행 시 `Repository not found` 오류가 발생했습니다. CI 환경에서 사용하는 프로토콜(SSH/HTTPS)과 인증 정보가 올바른지, `.gitmodules`에 지정된 URL이 정확한지 확인한 후 아래 사항을 점검해주세요.  

- `.gitmodules`에 설정된 서브모듈 URL 검토  
- CI 실행 계정의 접근 권한(토큰·SSH 키) 확인  
- 원격 저장소에 해당 커밋 해시가 푸시되어 있는지 검증 및 필요 시 해시 수정

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Actions: Continuous Integration</summary>

[error] 1-1: Git submodule update failed: fatal: remote error: upload-pack: not our ref 5ce5a526898a034bc8365ac84925e0b04bb59ed1

</details>
<details>
<summary>🪛 GitHub Actions: Continuous Deployment</summary>

[error] 1-1: Git submodule update failed: fatal: remote error: upload-pack: not our ref 5ce5a526898a034bc8365ac84925e0b04bb59ed1

</details>

</details>

</details>
<details>
<summary>.github/workflows/cd.yaml (1)</summary>

`29-30`: **gradlew 실행 권한 부여 확인**  
`chmod +x gradlew`로 실행 권한을 적절히 설정하고 있어 문제가 없습니다.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-26T05:24:22Z
user: login: goldentrash
body: 고생하셨습니다! 몇가지 의견 남겨뒀어욥
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-26T16:47:15Z
user: login: goldentrash
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-26T16:48:24Z
user: login: goldentrash
body: 고생하셨습니다. CD에 사용할 Actions 버저닝은 다음번에 다듬도록 하지요
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-27T01:51:08Z

Review comments:
diff_hunk: @@ -0,0 +1,62 @@
+name: Continuous Deployment
+
+on: pull_request
+
+jobs:
+  build:
+
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@v2
+        with:
+          token: ${{ secrets.CD_PAT }}
+          submodules: recursive
+
path: .github/workflows/cd.yaml
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**actions/checkout 최신 버전 사용 및 옵션 보강**  
`actions/checkout@v2`는 구버전입니다. 보안 및 기능 개선을 위해 `@v3`로 업그레이드하고, `fetch-depth: 0`을 설정해 전체 히스토리를 가져오도록 개선하세요.  
  
```diff
- uses: actions/checkout@v2
- with:
-   token: ${{ secrets.CD_PAT }}
-   submodules: recursive
+ uses: actions/checkout@v3
+ with:
+   token: ${{ secrets.CD_PAT }}
+   submodules: recursive
+   fetch-depth: 0
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
        uses: actions/checkout@v3
        with:
          token: ${{ secrets.CD_PAT }}
          submodules: recursive
          fetch-depth: 0
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 actionlint (1.7.4)</summary>

12-12: the runner of "actions/checkout@v2" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-26T05:24:22Z
author_association: NONE
diff_hunk: @@ -0,0 +1,62 @@
+name: Continuous Deployment
+
+on: pull_request
+
+jobs:
+  build:
+
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@v2
+        with:
+          token: ${{ secrets.CD_PAT }}
+          submodules: recursive
+
+      - name: Set up JDK 17
+        uses: actions/setup-java@v2
+        with:
+          java-version: '17'
+          distribution: 'adopt'
+
path: .github/workflows/cd.yaml
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**actions/setup-java 버전 및 distribution 갱신**  
`actions/setup-java@v2` 대신 `@v3`을 사용하고, 기존 `distribution: 'adopt'`는 `temurin`으로 변경하여 최신 릴리스 채널을 활용하세요.  
  
```diff
- uses: actions/setup-java@v2
+ uses: actions/setup-java@v3
  with:
-   java-version: '17'
-   distribution: 'adopt'
+   java-version: '17'
+   distribution: 'temurin'
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 actionlint (1.7.4)</summary>

18-18: the runner of "actions/setup-java@v2" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-26T05:24:22Z
author_association: NONE
diff_hunk: @@ -51,6 +51,8 @@ private List<Server> servers() {
         // TODO: change the URL of the staging server to the actual URL of the staging server.
         Server stagingServer = new Server().url("https://whitepiano-codeserver.pe.kr").description("Staging server");
 
-        return List.of(stagingServer, localServer);
+        Server productionServer = new Server().url("https://api.study-up.site").description("Production server");
+
+        return List.of(stagingServer, localServer, productionServer);
path: src/main/java/sleppynavigators/studyupbackend/presentation/common/config/SwaggerConfig.java
user: login: goldentrash
body: Production Server가 생긴 만큼, Staging 서버는 더 이상 필요하지 않을 것 같습니다. 아래와 같은 수정은 어떠신가요?

```java
    private List<Server> servers() {
        Server localServer = new Server().url("http://localhost:8080").description("Local server");
        Server productionServer = new Server().url("https://api.study-up.site").description("Production server");

        return List.of(productionServer, localServer);
    }
```

ps. 위와 같은 순서로 List를 생성해야, 기본값이 프로덕션 서버가 되고, @algoORgoal 이 작업하기 편할 것으로 보입니다.
created_at: 2025-04-26T16:41:16Z
author_association: CONTRIBUTOR
path: .github/workflows/cd.yaml
user: login: goldentrash
body: 코더래빗이 지적했듯이 Actions의 버전이 낮은 몇몇이 눈에 띄네요. 그리고 일부 불필요해보이는 설정이 포함된 것처럼 느껴집니다. 마지막으로, CD라면 배포 실패에 대한 리커버리가 있어야 하겠네요. 당장 모든 것을 고려하기에는 어려우니 아래와 같이 내용을 수정하는건 어떤가요? (Actions 버전 최신화, 불필요한 프로퍼티 제거, 배포 리커버리 코멘트)

```yaml
name: Continuous Deployment

on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          token: ${{ secrets.CD_PAT }}
          submodules: recursive

      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'adopt'

      - name: Setup timezone
        uses: zcong1993/setup-timezone@master
        with:
          timezone: Asia/Seoul

      - name: Grant execute permission for gradlew
        run: chmod +x gradlew

      - name: Build with Gradle
        run: ./gradlew clean build

      - name: Copy built project
        if: success()
        uses: appleboy/scp-action@master
        with:
          host: ${{ secrets.EC2_HOST }}
          username: ${{ secrets.EC2_USERNAME }}
          key: ${{ secrets.EC2_PRIVATE_KEY }}
          source: '.'
          target: '/home/ubuntu/application/study-up/backend'
          strip_components: 1

      - name: Connect to OCI Compute Instance using ssh and run the script below.
        if: success()
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.EC2_HOST }}
          username: ${{ secrets.EC2_USERNAME }}
          key: ${{ secrets.EC2_PRIVATE_KEY }}
          script: |
            cd /home/ubuntu/application/study-up/backend
            docker-compose up --build -d

      # TODO: If there's a problem running the new version, should revert to the previous version
```
created_at: 2025-04-26T16:46:16Z
author_association: CONTRIBUTOR
path: Dockerfile
user: login: goldentrash
body: Dockerfile을 추가하셨군요! 우리가 앞으로 해당 파일을 통해서 이미지를 빌드하게 되었으니, `.gitignore`에서 Dockerfile을 제거해 주세요
created_at: 2025-04-26T16:48:24Z
author_association: CONTRIBUTOR

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-04-26T05:21:21Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- This is an auto-generated comment: failure by coderabbit.ai -->

> [!CAUTION]
> ## Review failed
> 
> The pull request is closed.

<!-- end of auto-generated comment: failure by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough

이번 변경에서는 GitHub Actions를 활용한 새로운 지속적 배포(Continuous Deployment) 워크플로우가 추가되었습니다. 이 워크플로우는 main 브랜치에 푸시될 때 트리거되며, 코드 체크아웃, JDK 17 환경 설정, 시간대 설정, Gradle 빌드, Oracle Cloud EC2 인스턴스로의 파일 복사 및 원격 Docker Compose 실행까지 일련의 자동화된 배포 과정을 포함합니다. 또한, 서브프로젝트 커밋 참조가 업데이트되었고, 테스트 환경 설정 파일에 AWS 클라우드 관련 설정이 추가되었습니다. 신규 Dockerfile과 docker-compose.yaml 파일도 도입되어 컨테이너 이미지 빌드 및 실행 구성이 포함되었습니다. 마지막으로 Swagger 설정에서 스테이징 서버 대신 프로덕션 서버가 등록되었습니다.

## Changes

| 파일/경로                                  | 변경 요약                                                         |
|--------------------------------------------|-------------------------------------------------------------------|
| .github/workflows/cd.yaml                  | 지속적 배포를 위한 GitHub Actions 워크플로우 신규 추가             |
| Dockerfile, docker-compose.yaml            | OpenJDK 17 기반 Docker 이미지 정의 및 docker-compose 서비스 구성 추가 |
| src/main/resources/config                  | 서브프로젝트 커밋 참조 업데이트(e1d4075 → a361662)               |
| src/test/resources/application-test.yaml  | AWS 클라우드 설정(spring.cloud.aws) 추가, S3 버킷 및 인증 정보 포함 |
| src/main/java/.../SwaggerConfig.java       | Swagger 서버 설정 변경: 스테이징 서버 제거, 프로덕션 서버 추가       |
| .gitignore                                 | Dockerfile 제외 해제, Dockerfile 버전 관리 포함                      |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant Developer
    participant GitHub Actions
    participant Oracle Cloud EC2

    Developer->>GitHub Actions: main 브랜치에 푸시
    GitHub Actions->>GitHub Actions: 코드 체크아웃 및 JDK 17 설정
    GitHub Actions->>GitHub Actions: 시간대 설정 및 Gradle 빌드 수행
    GitHub Actions->>Oracle Cloud EC2: 빌드 결과물 SCP 전송
    GitHub Actions->>Oracle Cloud EC2: SSH 접속 후 Docker Compose 실행
```

## Poem

> 🐇  
> 깃허브 위에 춤추는 자동화의 빛,  
> 빌드와 배포가 한 번에 착착!  
> 서울의 시간에 맞춰 준비 완료,  
> EC2로 빌드 파일이 날아가네.  
> 도커 컨테이너가 기지개를 켜면,  
> 토끼는 기쁨에 귀를 쫑긋!  
> 자동화 세상, 참으로 멋져요!  
>

<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->

---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 73f88bc0d2a78a1ad889722ecee3a4040ef7ea9f and 10b8c22ac3f263f60147cdb74427ee0c54d6ae49.

</details>

<details>
<summary>📒 Files selected for processing (3)</summary>

* `.github/workflows/cd.yaml` (1 hunks)
* `.gitignore` (0 hunks)
* `src/main/java/sleppynavigators/studyupbackend/presentation/common/config/SwaggerConfig.java` (1 hunks)

</details>

</details>
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=sleppy-navigators/study-up-backend&utm_content=48):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: NONE
user: login: sonarqubecloud[bot]
created_at: 2025-04-27T01:50:44Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=sleppy-navigators_study-up-backend&pullRequest=48) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [106 New issues](https://sonarcloud.io/project/issues?id=sleppy-navigators_study-up-backend&pullRequest=48&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=sleppy-navigators_study-up-backend&pullRequest=48&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=sleppy-navigators_study-up-backend&pullRequest=48&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [83.2% Coverage on New Code](https://sonarcloud.io/component_measures?id=sleppy-navigators_study-up-backend&pullRequest=48&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=sleppy-navigators_study-up-backend&pullRequest=48&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=sleppy-navigators_study-up-backend&pullRequest=48)


author_association: NONE