Skip to content

chore/#243 운영 배포를 위한 스테이징 환경 구축 및 스크립트 구성#244

Merged
LeeHanEum merged 8 commits intodevelopfrom
chore/#243-production-deploy
Aug 18, 2025
Merged

chore/#243 운영 배포를 위한 스테이징 환경 구축 및 스크립트 구성#244
LeeHanEum merged 8 commits intodevelopfrom
chore/#243-production-deploy

Conversation

@LeeHanEum
Copy link
Copy Markdown
Member

Summary

폐쇄망으로 구축된 운영 환경에서 원활한 배포를 위해 스테이징 환경을 유사하게 구축하였습니다.
GitHub Actions와 scp 기반으로 docker image를 압축하여 복사하며, 별도의 deploy 셸 스크립트를 통해 컨테이너를 구동합니다.

Tasks

  • 스테이징 환경 구성
  • admin 엔드포인트 프리픽스를 추가하여, Nginx가 어드민 서비스에 대해 정상적으로 리버스 프록시를 수행하도록 구성
  • docker compose yml 파일 및 deploy.sh 작성

To Reviewer

보안 상 중요한 파일은 노션에 추가하였습니다

@LeeHanEum LeeHanEum self-assigned this Aug 18, 2025
@LeeHanEum LeeHanEum added the ✨feature create new feature label Aug 18, 2025
@LeeHanEum LeeHanEum linked an issue Aug 18, 2025 that may be closed by this pull request
1 task
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Aug 18, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

스테이징 배포 파이프라인을 추가하고, 관리자용 컨트롤러들의 기본 경로를 /api/v1/admin/*로 변경했다. prod 프로필에서 SpringDoc(Swagger UI, API Docs)을 비활성화했다. 스테이징용 Docker Compose, Nginx 설정, 원격 배포 스크립트, GitHub Actions 워크플로우를 신규 추가했다.

Changes

Cohort / File(s) Change Summary
CI/CD: Staging 워크플로우 추가
.github/workflows/staging-build-deploy.yml
수동 트리거(workflow_dispatch). JDK 17 세팅, Gradle 빌드(테스트 스킵) 후 aics-admin/api/auth 이미지 빌드·tar 저장·SCP 업로드, 원격 서버에서 deploy.sh 실행.
Admin API 경로 접두어 변경 (/api/v1 → /api/v1/admin)
aics-admin/.../about/.../AboutAdminControllerImpl.java, .../carousel/.../CarouselAdminControllerImpl.java, .../club/.../ClubAdminControllerImpl.java, .../comment/.../CommentAdminControllerImpl.java, .../file/.../FileAdminControllerImpl.java, .../lab/.../LabAdminControllerImpl.java, .../post/.../PostAdminControllerImpl.java, .../professor/.../ProfessorAdminControllerImpl.java, .../user/.../UserAdminControllerImpl.java
각 컨트롤러 클래스의 @RequestMapping 기본 경로를 /api/v1/*에서 /api/v1/admin/*로 변경. 메서드 로직 변경 없음.
Prod 환경에서 문서 비활성화
aics-admin/src/main/resources/application-prod.yml, aics-api/src/main/resources/application-prod.yml, aics-auth/src/main/resources/application-prod.yml
springdoc.swagger-ui.enabled: false, springdoc.api-docs.enabled: false 추가. 기타 기능 변화 없음.
스테이징 배포 스크립트
deploy/staging/deploy.sh
도커 이미지 로드(tar), 기존 컨테이너 down(허용오류), env 파일로 compose up -d 실행.
Docker Compose: Staging 구성 추가
docker/staging/docker-compose.yml, docker/staging/networks.yml, docker/staging/service/service-application.yml, docker/staging/service/service-nginx.yml, docker/staging/service/service-postgres.yml, docker/staging/service/service-redis.yml, docker/staging/docker-compose-db.yml
네트워크 선언, 애플리케이션 3종(aics-api/admin/auth) 서비스 정의, Nginx 서비스, Postgres/Redis 서비스, 상위 compose에서 include 구성.
Nginx: Staging 리버스 프록시
nginx/staging/nginx.conf
/api/v1/auth → aics-auth:8082, /api/v1/admin → aics-admin:8081, /api/v1 → aics-api:8080, / → aics-app:3000 프록시 라우팅 및 헤더/업그레이드 처리.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Suggested reviewers

  • LeeShinHaeng
✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/#243-production-deploy

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • 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.
  • 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 the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

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

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions
Copy link
Copy Markdown

Test Coverage Report

Overall Project 94.32% 🍏

There is no coverage information present for the Files changed

@codecov
Copy link
Copy Markdown

codecov bot commented Aug 18, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.

Impacted file tree graph

@@            Coverage Diff             @@
##             develop     #244   +/-   ##
==========================================
  Coverage      91.42%   91.42%           
  Complexity       159      159           
==========================================
  Files             49       49           
  Lines            455      455           
  Branches           9        9           
==========================================
  Hits             416      416           
  Misses            29       29           
  Partials          10       10           

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update b3606e5...4c77460. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🧹 Nitpick comments (36)
aics-admin/src/main/resources/application-prod.yml (1)

21-21: YAMLLint 경고: 파일 끝 개행 누락(EOL).

CI/Lint 안정화를 위해 마지막 줄에 개행을 추가해 주세요.

다음처럼 마지막에 빈 줄 1줄을 추가하면 됩니다:

   api-docs:
     enabled: false
+
aics-auth/src/main/resources/application-prod.yml (1)

21-21: YAMLLint 경고: 파일 끝 개행 누락(EOL).

관리형 린트 오류를 없애기 위해 마지막 줄에 개행을 추가해 주세요.

수정 예시:

   api-docs:
     enabled: false
+
aics-admin/src/main/java/kgu/developers/admin/carousel/presentation/CarouselAdminControllerImpl.java (1)

24-26: 클라이언트/프록시 측 영향 검토 및 점진적 이전 전략 제안(선택).

기존 /api/v1/carousels 호출이 남아있다면 단기적으로 Nginx에서 리라이트로 완충하는 것도 고려해볼 수 있습니다.

예시(Nginx):

location ~ ^/api/v1/(comments|carousels|users|abouts|clubs|files|labs|posts|professors)(/.*)?$ {
  return 308 /api/v1/admin/$1$2;
}

운영 반영 전/후 일정에 맞춰 제거하면 안전하게 마이그레이션 가능합니다.

aics-admin/src/main/java/kgu/developers/admin/lab/presentation/LabAdminControllerImpl.java (1)

26-26: 하드코딩된 경로 상수화 제안(선택): 중복/오타 리스크 감소

여러 Admin 컨트롤러에서 동일 접두어가 반복됩니다. 공통 상수로 추출하면 유지보수가 쉬워집니다.

적용 예시(현재 파일):

-@RequestMapping("/api/v1/admin/labs")
+@RequestMapping(AdminApiPaths.V1 + "/labs")

추가: 공용 상수 정의(새 파일 예시)

// aics-admin 모듈 내 적절한 패키지에 생성 (예: kgu.developers.admin.support)
package kgu.developers.admin.support;

public final class AdminApiPaths {
  private AdminApiPaths() {}
  public static final String V1 = "/api/v1/admin";
}

컨트롤러에 import 추가:
import kgu.developers.admin.support.AdminApiPaths;

aics-admin/src/main/java/kgu/developers/admin/about/presentation/AboutAdminControllerImpl.java (1)

25-25: 경로 상수화(선택): 다수 컨트롤러 공통 접두어 중앙집중화

다른 Admin 컨트롤러와 동일하게 상수 재사용을 권장합니다.

-@RequestMapping("/api/v1/admin/abouts")
+@RequestMapping(AdminApiPaths.V1 + "/abouts")

상수 정의 예시는 이전 코멘트의 AdminApiPaths 참고.

aics-admin/src/main/java/kgu/developers/admin/file/presentation/FileAdminControllerImpl.java (1)

25-25: 경로 상수화(선택)

여타 컨트롤러와 동일하게 경로 상수 사용을 권장합니다.

-@RequestMapping("/api/v1/admin/files")
+@RequestMapping(AdminApiPaths.V1 + "/files")
aics-admin/src/main/java/kgu/developers/admin/professor/presentation/ProfessorAdminControllerImpl.java (1)

24-24: 경로 상수화(선택)

다른 파일과 동일한 제안입니다.

-@RequestMapping("/api/v1/admin/professors")
+@RequestMapping(AdminApiPaths.V1 + "/professors")
aics-admin/src/main/java/kgu/developers/admin/club/presentation/ClubAdminControllerImpl.java (2)

26-26: 경로 상수화(선택)

여타 컨트롤러와 동일 제안입니다.

-@RequestMapping("/api/v1/admin/clubs")
+@RequestMapping(AdminApiPaths.V1 + "/clubs")

34-34: 경미: fileId에 양수 제약 일관 적용 제안

동일 패턴의 LabAdminControllerImpl는 @Positive @RequestParam(required = false) Long fileId로 검증을 일관 적용합니다. Club도 동일하게 두면 입력 검증이 명확해집니다. null은 허용되며, 값이 있을 때만 양수 검증이 적용됩니다.

-		@RequestParam(required = false) Long fileId,
+		@Positive @RequestParam(required = false) Long fileId,
aics-api/src/main/resources/application-prod.yml (1)

17-21: SpringDoc(prod) 비활성화 설정 적절 — 파일 끝 개행(EOF newline) 추가 필요

  • springdoc.swagger-ui.enabled=false, springdoc.api-docs.enabled=false 적용은 운영 보안 관점에서 적절합니다.
  • YAMLlint 경고(new-line-at-end-of-file)를 해소하기 위해 파일 끝에 개행을 1줄 추가해 주세요.

적용 예:

   api-docs:
     enabled: false
+
docker/staging/networks.yml (1)

1-3: 네트워크 정의 LGTM — EOF 개행 추가

  • aics-network 브리지 네트워크 정의는 적절합니다.
  • 파일 끝 개행 1줄 추가로 YAMLlint 경고를 제거해 주세요.
docker/staging/service/service-redis.yml (4)

9-10: 호스트 포트 공개 범위 축소 또는 제거 권장.

스테이징이라도 불필요한 외부 노출은 줄이는 게 안전합니다. 내부 네트워크에서만 사용한다면 ports를 제거하거나, 호스트 바인딩을 loopback으로 제한하세요.

예시:

-    ports:
-      - "6379:6379"
+    # 내부 테스트 용도로만 필요할 때:
+    ports:
+      - "127.0.0.1:6379:6379"

3-3: 이미지 태그 고정 권장.

latest는 재현성과 보안 측면에서 리스크가 큽니다. 메이저/마이너 또는 digest로 고정해 주세요.

예시:

-    image: redis:latest
+    image: redis:7-alpine

1-14: 옵션: 데이터 지속성(필요 시)과 헬스체크 추가 제안.

캐시로만 쓰지 않고 재시작 시 데이터 유지가 필요하다면 볼륨을 마운트하고, 기동 상태 판단을 위해 간단한 헬스체크를 권장합니다.

예시:

 services:
   redis:
@@
-    networks:
-      - aics-network
+    networks:
+      - aics-network
+    # 필요 시 데이터 지속성
+    volumes:
+      - redis-data:/data
+
+volumes:
+  redis-data:

주의: 동일 docker compose 묶음 내 다른 파일에서 이미 volumes를 선언한다면 중복 선언을 피하세요.


14-14: 파일 끝 개행 추가.

일부 툴(yamllint 등)과 VCS에서 경고가 발생합니다. 마지막 줄에 개행을 추가해 주세요.

docker/staging/service/service-postgres.yml (4)

8-9: DB 포트 외부 노출 축소 권장.

내부 네트워크 사용만 필요하다면 포트 매핑을 제거하거나 loopback으로 제한해 주세요.

-    ports:
-      - "5432:5432"
+    # 로컬 호스트에서만 접근 필요 시:
+    ports:
+      - "127.0.0.1:5432:5432"
+    # 전혀 필요 없다면 ports 섹션 제거

3-3: 이미지 태그 고정 권장.

postgres:15는 최신 마이너로 부동입니다. 재현성을 위해 패치 버전 또는 alpine 변형 등으로 고정해 주세요.

-    image: postgres:15
+    image: postgres:15-alpine

10-17: 헬스체크를 추가해 서비스 의존성 안정화.

DB가 준비되기 전에 앱이 붙으면서 실패/재시도되는 현상을 줄일 수 있습니다.

     environment:
       POSTGRES_USER: ${POSTGRES_USER}
       POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
       POSTGRES_DB: ${POSTGRES_DB}
+    healthcheck:
+      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
+      interval: 10s
+      timeout: 5s
+      retries: 5

20-20: 파일 끝 개행 추가.

yamllint 경고(new-line-at-end-of-file)가 있습니다. 마지막 줄에 개행을 추가해 주세요.

docker/staging/service/service-nginx.yml (3)

3-3: 이미지 태그 고정 권장.

배포 재현성과 예측 가능성을 위해 특정 버전으로 고정해 주세요.

-    image: nginx:latest
+    image: nginx:1.25-alpine

2-9: 옵션: depends_on으로 초기 502 빈도 완화.

백엔드 컨테이너가 준비되기 전에 Nginx가 먼저 떠서 502가 발생할 수 있습니다. 엄밀한 readiness가 아니지만 초기 실패를 줄이는 데 도움이 됩니다.

   nginx:
     image: nginx:latest
+    depends_on:
+      - aics-api
+      - aics-admin
+      - aics-auth
+      - aics-app

9-9: 파일 끝 개행 추가.

yamllint 경고(new-line-at-end-of-file)가 있습니다.

nginx/staging/nginx.conf (4)

4-9: 프록시 표준 헤더 보강(X-Forwarded-For/Proto).

백엔드에서 클라이언트 IP/프로토콜을 정확히 인지하도록 표준 프록시 헤더를 추가하세요.

     location ^~ /api/v1/auth/ {
         proxy_pass http://aics-auth:8082/api/v1/;
         proxy_set_header Host $host;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header Origin $http_origin;
+        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+        proxy_set_header X-Forwarded-Proto $scheme;
     }

11-16: 프록시 표준 헤더 보강(X-Forwarded-For/Proto).

     location ^~ /api/v1/admin/ {
         proxy_pass http://aics-admin:8081/api/v1/admin/;
         proxy_set_header Host $host;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header Origin $http_origin;
+        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+        proxy_set_header X-Forwarded-Proto $scheme;
     }

18-23: 프록시 표준 헤더 보강(X-Forwarded-For/Proto).

     location ^~ /api/v1/ {
         proxy_pass http://aics-api:8080/api/v1/;
         proxy_set_header Host $host;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header Origin $http_origin;
+        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+        proxy_set_header X-Forwarded-Proto $scheme;
     }

25-32: WebSocket 블록에서도 표준 헤더 추가 및 Connection 헤더 따옴표 일관화.

실사용 시 앱이 클라이언트 IP/프로토콜을 필요로 할 수 있습니다. 또한 관례적으로 Connection 값은 큰따옴표를 사용합니다.

     location / {
         proxy_pass http://aics-app:3000/;
         proxy_http_version 1.1;
         proxy_set_header Upgrade $http_upgrade;
-        proxy_set_header Connection 'upgrade';
+        proxy_set_header Connection "upgrade";
         proxy_set_header Host $host;
         proxy_cache_bypass $http_upgrade;
+        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+        proxy_set_header X-Forwarded-Proto $scheme;
     }
.github/workflows/staging-build-deploy.yml (1)

24-28: Gradle 빌드 최적화 제안(선택).

모듈별로 clean build를 각각 실행하면 캐시 이점을 잃습니다. 루트에서 멀티프로젝트 빌드하거나 clean은 1회만 수행하는 편이 빠릅니다.

-          ./gradlew clean build -p aics-admin -x test
-          ./gradlew clean build -p aics-api -x test
-          ./gradlew clean build -p aics-auth -x test
+          ./gradlew clean
+          ./gradlew :aics-admin:build :aics-api:build :aics-auth:build -x test
deploy/staging/deploy.sh (3)

2-2: 셸 스크립트 안전성 강화: set -u -o pipefail 추가 제안

정의되지 않은 변수 접근과 파이프라인 오류를 조기에 감지하도록 엄격 모드를 권장합니다.

-set -e
+set -Eeuo pipefail

4-4: APP_HOME 계산 방식이 취약합니다 — 스크립트 위치 기준으로 계산하도록 변경 권장

현재 $(pwd)/backend는 실행 디렉터리에 의존해 오작동 가능성이 큽니다. 스크립트 파일 위치를 기준으로 APP_HOME을 계산하세요.

-APP_HOME=$(pwd)/backend
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+# 레포 루트 기준으로 backend 위치 추적 (deploy/staging/deploy.sh → ../../backend)
+APP_HOME="$(cd "$SCRIPT_DIR/../.." && pwd)/backend"

6-10: 이미지 tar 존재 여부 확인 및 반복 로드로 간결화

지정 경로에 tar 파일이 없으면 실패합니다. 존재 검증과 반복 처리로 가독성과 견고성을 높일 수 있습니다. 경로에 공백이 있을 경우를 대비해 인용도 추가합니다.

-echo "===== Loading Docker images ====="
-sudo docker load -i $APP_HOME/tar/aics-api.tar
-sudo docker load -i $APP_HOME/tar/aics-admin.tar
-sudo docker load -i $APP_HOME/tar/aics-auth.tar
+echo "===== Loading Docker images ====="
+for img in aics-api aics-admin aics-auth; do
+  TAR_PATH="$APP_HOME/tar/${img}.tar"
+  if [[ ! -f "$TAR_PATH" ]]; then
+    echo "ERROR: Image tar not found: $TAR_PATH" >&2
+    exit 1
+  fi
+  sudo docker load -i "$TAR_PATH"
+done
docker/staging/service/service-application.yml (6)

3-7: 가용성: 재시작 정책 추가 제안

의도치 않은 종료 시 자동 복구를 위해 restart: unless-stopped 권장합니다.

   aics-api:
     image: ${DOCKER_USERNAME}/aics-api:latest
     container_name: aics-api
+    restart: unless-stopped

25-29: 가용성: 재시작 정책 추가 제안 (aics-admin)

   aics-admin:
     image: ${DOCKER_USERNAME}/aics-admin:latest
     container_name: aics-admin
+    restart: unless-stopped

47-51: 가용성: 재시작 정책 추가 제안 (aics-auth)

   aics-auth:
     image: ${DOCKER_USERNAME}/aics-auth:latest
     container_name: aics-auth
+    restart: unless-stopped

9-21: 환경변수 중복 정의를 YAML 앵커로 제거하여 유지보수성 향상

3개 서비스에 동일한 env가 반복됩니다. YAML 앵커/alias로 중복 제거를 권장합니다.

예시(참고용, 파일 상단에 공통 정의 추가):

x-common-env: &common-env
  SPRING_PROFILES_ACTIVE: prod
  DB_HOST: postgres
  DB_PORT: 5432
  DB_NAME: ${POSTGRES_DB}
  DB_USERNAME: ${POSTGRES_USER}
  DB_PASSWORD: ${POSTGRES_PASSWORD}
  JWT_ISSUER: kgudevelopers@gmail.com
  JWT_SECRET_KEY: ${JWT_SECRET_KEY}
  REDIS_HOST: redis
  REDIS_PASSWORD: ${REDIS_PASSWORD}
  FILE_SECRET_KEY: ${FILE_SECRET_KEY}

서비스 내 적용:

environment:
  <<: *common-env

Also applies to: 31-43, 53-65


21-22: 의존성 기동 순서 관리: depends_on(+헬스체크) 고려

Postgres/Redis가 준비되기 전에 앱이 시작되면 초기 연결 실패가 발생할 수 있습니다. depends_on과 헬스체크(별도 서비스 파일에서 정의 필요)를 활용하세요.

예시:

depends_on:
  postgres:
    condition: service_healthy
  redis:
    condition: service_healthy

주의: service-postgres.yml, service-redis.yml에 적절한 healthcheck가 정의되어 있어야 합니다. 없다면 추가가 필요합니다.

Also applies to: 44-45, 65-66


66-66: EOF 개행 누락

파일 끝에 개행 문자가 없습니다. 일부 도구에서 경고가 발생합니다. 개행 추가를 권장합니다.

📜 Review details

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

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b3606e5 and ba2d1de.

📒 Files selected for processing (22)
  • .github/workflows/staging-build-deploy.yml (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/about/presentation/AboutAdminControllerImpl.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/carousel/presentation/CarouselAdminControllerImpl.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/club/presentation/ClubAdminControllerImpl.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/comment/presentation/CommentAdminControllerImpl.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/file/presentation/FileAdminControllerImpl.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/lab/presentation/LabAdminControllerImpl.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/post/presentation/PostAdminControllerImpl.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/professor/presentation/ProfessorAdminControllerImpl.java (1 hunks)
  • aics-admin/src/main/java/kgu/developers/admin/user/presentation/UserAdminControllerImpl.java (1 hunks)
  • aics-admin/src/main/resources/application-prod.yml (1 hunks)
  • aics-api/src/main/resources/application-prod.yml (1 hunks)
  • aics-auth/src/main/resources/application-prod.yml (1 hunks)
  • deploy/staging/deploy.sh (1 hunks)
  • docker/staging/docker-compose-db.yml (1 hunks)
  • docker/staging/docker-compose.yml (1 hunks)
  • docker/staging/networks.yml (1 hunks)
  • docker/staging/service/service-application.yml (1 hunks)
  • docker/staging/service/service-nginx.yml (1 hunks)
  • docker/staging/service/service-postgres.yml (1 hunks)
  • docker/staging/service/service-redis.yml (1 hunks)
  • nginx/staging/nginx.conf (1 hunks)
🧰 Additional context used
🪛 YAMLlint (1.37.1)
docker/staging/service/service-redis.yml

[error] 14-14: no new line character at the end of file

(new-line-at-end-of-file)

docker/staging/service/service-postgres.yml

[error] 20-20: no new line character at the end of file

(new-line-at-end-of-file)

docker/staging/networks.yml

[error] 3-3: no new line character at the end of file

(new-line-at-end-of-file)

docker/staging/docker-compose-db.yml

[error] 4-4: no new line character at the end of file

(new-line-at-end-of-file)

aics-api/src/main/resources/application-prod.yml

[error] 21-21: no new line character at the end of file

(new-line-at-end-of-file)

docker/staging/docker-compose.yml

[error] 4-4: no new line character at the end of file

(new-line-at-end-of-file)

aics-admin/src/main/resources/application-prod.yml

[error] 21-21: no new line character at the end of file

(new-line-at-end-of-file)

docker/staging/service/service-nginx.yml

[error] 9-9: no new line character at the end of file

(new-line-at-end-of-file)

docker/staging/service/service-application.yml

[error] 66-66: no new line character at the end of file

(new-line-at-end-of-file)

aics-auth/src/main/resources/application-prod.yml

[error] 21-21: no new line character at the end of file

(new-line-at-end-of-file)

🪛 actionlint (1.7.7)
.github/workflows/staging-build-deploy.yml

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

(action)


31-31: shellcheck reported issue in this script: SC2086:info:1:28: Double quote to prevent globbing and word splitting

(shellcheck)


31-31: shellcheck reported issue in this script: SC2086:info:2:26: Double quote to prevent globbing and word splitting

(shellcheck)


31-31: shellcheck reported issue in this script: SC2086:info:3:27: Double quote to prevent globbing and word splitting

(shellcheck)


37-37: shellcheck reported issue in this script: SC2086:info:2:24: Double quote to prevent globbing and word splitting

(shellcheck)


37-37: shellcheck reported issue in this script: SC2086:info:3:22: Double quote to prevent globbing and word splitting

(shellcheck)


37-37: shellcheck reported issue in this script: SC2086:info:4:23: Double quote to prevent globbing and word splitting

(shellcheck)

🔇 Additional comments (17)
aics-admin/src/main/java/kgu/developers/admin/comment/presentation/CommentAdminControllerImpl.java (2)

12-12: 관리자 네임스페이스로의 경로 변경 적절합니다.

Nginx 리버스 프록시 설계(/api/v1/admin/**)와 일관성이 생겨 운영/스테이징 분리에 유리합니다.


12-12: 레거시 API 호출 경로 검토: 실제 호출 지점 확인 필요

제공된 스크립트 실행 결과, 아래 파일들은 모두 컨트롤러 정의(@RequestMapping) 및 SecurityConfig 설정으로 검출되었으며, 의도된 동작입니다.
실제 레거시 경로(/api/v1/comments 등)가 호출되고 있는지를 확인하려면 다음 영역을 추가 점검해주세요:

  • 프론트엔드 코드(UI 레포지토리)
  • 통합/인수 테스트(src/**/*Test.java 등)
  • 외부 클라이언트 설정 및 API 문서화된 클라이언트 SDK
aics-admin/src/main/resources/application-prod.yml (1)

17-21: prod 환경에서 OpenAPI/Swagger 비활성화 적절합니다.

운영 노출 최소화와 공격면 축소에 도움이 됩니다. 개발/스테이징에서는 별도 프로필로만 활성화되도록 유지하면 좋습니다.

aics-auth/src/main/resources/application-prod.yml (1)

17-21: prod 환경에서 OpenAPI/Swagger 비활성화 일관성 유지 좋습니다.

인증 서비스는 특히 민감하므로 운영에서 문서/스키마 노출 차단은 바람직합니다.

aics-admin/src/main/java/kgu/developers/admin/carousel/presentation/CarouselAdminControllerImpl.java (1)

24-24: 관리자 네임스페이스(/api/v1/admin/carousels)로의 변경 적절합니다.

리버스 프록시와 보안 경계가 명확해졌습니다.

aics-admin/src/main/java/kgu/developers/admin/user/presentation/UserAdminControllerImpl.java (1)

23-23: 관리자 네임스페이스(/api/v1/admin/users)로의 경로 정비 좋습니다.

엔드포인트 경계가 명확해지고, 프록시 라우팅 규칙과의 일관성도 올라갑니다. 클라이언트(관리 콘솔 등) 호출 경로 업데이트만 확인해 주세요.

aics-admin/src/main/java/kgu/developers/admin/lab/presentation/LabAdminControllerImpl.java (1)

26-26: /api/v1/admin/labs 경로 변경 영향 범위 점검 결과

  • 구 경로(/api/v1/labs) 참조
    • 리포지터리 전역 검색 결과, API 컨트롤러 매핑 외 별도 리터럴 참조 없음
    • aics-api/src/main/java/kgu/developers/api/lab/presentation/LabControllerImpl.java:14 (@RequestMapping("/api/v1/labs"))
  • 보안 설정
    • 컨트롤러별 @PreAuthorize("hasRole('ROLE_ADMIN')") 적용 중
    HttpSecurity에서 global하게 /api/v1/admin/**를 매칭하는 antMatchers/mvcMatchers/requestMatchers 구문 미발견
    ⇒ 메서드 보안 활성화 여부 및 추가 인가 규칙 필요 여부 확인 권장
  • 프록시(Nginx/GW) 설정
    • 리포지터리 내 프록시 설정 파일 미발견
    ⇒ 운영 환경의 /api/v1/admin/ → admin 서비스 라우팅 정책 확인 필요
aics-admin/src/main/java/kgu/developers/admin/about/presentation/AboutAdminControllerImpl.java (1)

25-25: /api/v1/admin/abouts 경로 변경 전후 호출자·보안·프록시 점검 필요

경로 변경 자체는 문제가 없으나, 연관된 호출자·인가·프록시 설정 일치 여부를 꼭 확인해 주세요:

  • 구 경로(/api/v1/abouts) 참조
    • aics-admin 모듈 내에서는 더 이상 발견되지 않음
    • aics-api 모듈의 AboutControllerImpl에서만 남아 있으므로, admin 쪽에는 잔여 참조가 없는지 재확인
  • Spring Security 인가 규칙
    /api/v1/admin/** 경로에 대한 antMatchers/mvcMatchers 등 인가 설정이 등록되어 있는지 확인
  • Nginx/프록시 라우팅
    /api/v1/admin/ 경로로 요청이 올바르게 전달되도록 proxy_pass 혹은 location 블록에 라우팅이 정의되어 있는지 확인
aics-admin/src/main/java/kgu/developers/admin/file/presentation/FileAdminControllerImpl.java (1)

25-25: /api/v1/admin/files 변경 완료 — Nginx 업로드 프록시 설정 검토 필요

코드베이스에서 /api/v1/files 참조는 모두 제거된 것을 확인했습니다. 운영 환경의 Nginx 설정 파일을 열어 아래 항목을 직접 점검해 주세요:

  • client_max_body_size: 업로드 최대 허용 크기
  • proxy_request_buffering / proxy_read_timeout: 대용량 파일 및 느린 네트워크 대응
  • /api/v1/admin/ 경로가 admin 서비스로 정상 라우팅되는지
aics-admin/src/main/java/kgu/developers/admin/professor/presentation/ProfessorAdminControllerImpl.java (1)

24-24: /api/v1/admin/professors 경로 변경 영향 범위 점검 결과

  • 구 경로(/api/v1/professors) 참조
    • aics-api/src/main/java/kgu/developers/api/professor/presentation/ProfessorControllerImpl.java 에서 여전히 /api/v1/professors 로 매핑되어 있어, 관리용 경로 변경이 기존 퍼블릭 API에 영향을 주지 않음이 확인되었습니다.
  • 보안 설정
    antMatchers, mvcMatchers, requestMatchers 검색 결과 /api/v1/admin/** 매칭이 발견되지 않았습니다. 관리용 엔드포인트 접근 제어를 위해 보안 설정에 해당 경로를 추가·검토해 주세요.
  • Nginx/프록시 설정
    • repository 내 파일 검색에서 /api/v1/admin 관련 라우팅 설정이 탐지되지 않았습니다. 프록시(Nginx 등)에서 admin 경로를 올바르게 라우팅하는지 확인해 주세요.

기능상 문제는 없으나, 위 보안 설정프록시 라우팅 부분만 보완 후 머지하시길 권장드립니다.

aics-admin/src/main/java/kgu/developers/admin/post/presentation/PostAdminControllerImpl.java (1)

26-28: 인터페이스 중복 매핑 없음 · @PreAuthorize prefix 전략 검토

  • 인터페이스(PostAdminController)에는 별도의 @RequestMapping이 없으므로 이중 경로 매핑이 발생하지 않습니다.
  • 모든 AdminControllerImpl에서 @PreAuthorize("hasRole('ROLE_ADMIN')")만 사용 중이며, hasAuthority(...)는 호출된 곳이 없습니다.

Spring Security 기본 ROLE_ 접두사를 유지한다면
hasRole('ADMIN')
또는
hasAuthority('ROLE_ADMIN')
중 하나로 통일해야 합니다.
만약 커스텀으로 접두사를 제거하도록 설정(GrantedAuthorityDefaults 등)했다면, 현재 사용 중인 hasRole('ROLE_ADMIN')도 정상 동작합니다.

확인할 위치:

  • Security 설정 클래스(ex. SecurityConfig.java)에서 rolePrefix 또는 GrantedAuthorityDefaults 빈 등록 여부 확인
docker/staging/docker-compose.yml (1)

1-4: 스테이징 컴포즈: 프로젝트 이름 고정 및 파일 끝 개행 추가

  • docker/staging/docker-compose.yml 최상단에
    name: aics-staging
    를 추가해 DB 스택(예: docker-compose-db.yml)과 동일 네트워크(aics-network)에 연결되도록 합니다.
  • 파일 맨 끝에 빈 줄 한 줄을 추가해 YAMLlint 경고를 해소합니다.
  • Nginx 프록시 설정(/api/v1/admin → aics-admin)을 정의한 .conf 파일이 저장소에서 확인되지 않아, 실제로 해당 경로를 프록시하도록 설정되어 있는지 직접 검토해 주세요.

패치 예:

+name: aics-staging
 include:
   - networks.yml
   - service-application.yml
   - service-nginx.yml
+
.github/workflows/staging-build-deploy.yml (2)

54-59: SSH 액션도 태그/커밋 핀 고정 상태 유지 권장.

현재 appleboy/ssh-action@v1.1.0은 버전 지정이 되어 있어 양호합니다. 보안 정책상 주기적 갱신 여부만 확인해 주세요.


53-64: 배포 스크립트·이미지 태그 일관성 확인 요청

현재 .github/workflows/staging-build-deploy.yml에서 원격 서버로 backend/deploy.sh를 실행하도록만 설정되어 있습니다.
이 스크립트가 다음 요건을 충족하는지 확인이 필요합니다. 불일치할 경우 새로운 컨테이너가 기동되지 않을 수 있습니다.

확인 사항:

  • backend/deploy.sh 내부에
    • docker load로 tar 이미지를 로드한 뒤
    • 동일한 SHA 태그(aics-*:GITHUB_SHA)로 참조하거나
    • latest 등으로 재태깅(docker tag)하는 로직
    • docker-compose up 또는 docker-compose pull 호출 로직
  • 서버에 배포된 docker-compose.yml(또는 유사 파일)에서
    • image: aics-admin:…, aics-api:…, aics-auth:… 등의 태그가
      실제 로드/태깅된 태그와 일치하는지

위 검증이 어려운 경우, 직접 해당 파일들을 열어 로직을 검토하거나 아래와 같은 예시 스크립트를 참고해 수동 확인해 주세요.

deploy/staging/deploy.sh (2)

6-15: 전반적 구성은 목적에 부합합니다

에어갭 환경에서 tar 로딩 → 기존 컨테이너 down → 새로 up 플로우는 합리적입니다. 위 제안 적용 시 재현성과 내고장성이 더 좋아질 것입니다.


11-15: 경로 확인 및 스크립트 개선 제안

fd 실행 결과, 레포에 존재하는 docker-compose.yml 파일은 다음 경로뿐입니다.

  • docker/development/docker-compose.yml
  • docker/staging/docker-compose.yml

현재 deploy/staging/deploy.sh에서는 $APP_HOME/docker-compose.yml을 사용 중인데, 실제 파일이 있는 경로(docker/staging/docker-compose.yml)와 불일치할 가능성이 높습니다.
아래 예시처럼 파일 존재 여부 검증, 변수 인용, --remove-orphans 옵션을 추가하고, COMPOSE_FILE·ENV_FILE 경로를 실제 위치로 수정해 주세요.

 echo "===== Stopping existing containers ====="
-COMPOSE_FILE="$APP_HOME/docker-compose.yml"
+COMPOSE_FILE="$APP_HOME/docker/staging/docker-compose.yml"
+ENV_FILE="$APP_HOME/docker/staging/.env"
+
+if [[ ! -f "$COMPOSE_FILE" ]]; then
+  echo "ERROR: Compose file not found: $COMPOSE_FILE" >&2
+  exit 1
+fi
 sudo docker compose -f "$COMPOSE_FILE" down --remove-orphans || true

 echo "===== Starting containers ====="
-if [[ ! -f "$ENV_FILE" ]]; then
+if [[ ! -f "$ENV_FILE" ]]; then
   echo "ERROR: .env file not found: $ENV_FILE" >&2
   exit 1
 fi
 sudo docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" up -d --remove-orphans

위 경로가 맞는지, $APP_HOME이 어디를 가리키는지 재확인 후 반영해 주세요.

docker/staging/service/service-application.yml (1)

10-10: 스테이징에서 prod 프로필 사용 확인 필요

SPRING_PROFILES_ACTIVE: prod 설정으로 Swagger 비활성 등 프로덕션 특성이 적용됩니다. 스테이징에서 API 문서 접근이 차단되어도 문제 없다는 팀 컨센서스가 있는지 확인 바랍니다.

Also applies to: 32-32, 54-54

Copy link
Copy Markdown
Contributor

@JangYeongHu JangYeongHu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍👍👍

Copy link
Copy Markdown
Contributor

@dkdltm221 dkdltm221 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@LeeHanEum LeeHanEum merged commit c23aa85 into develop Aug 18, 2025
5 checks passed
@LeeHanEum LeeHanEum deleted the chore/#243-production-deploy branch August 18, 2025 13:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨feature create new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Production CD 스크립트 작성

3 participants