Skip to content

Conversation

@move-hoon
Copy link
Member

@move-hoon move-hoon commented Jun 29, 2025

🔗 관련 이슈

📘 작업 유형

  • ✨ Feature (기능 추가)
  • 🐞 Bugfix (버그 수정)
  • 🔧 Refactor (코드 리팩토링)
  • ⚙️ Chore (환경 설정)
  • 📝 Docs (문서 작성 및 수정)
  • ✅ Test (기능 테스트)
  • 🎨 style (코드 스타일 수정)

📙 작업 내역

CI/CD 내용

develop에 머지 되었다는 가정하에 CI가 이루어져야 한다.

  • a,b 브랜치로 분기되었을 때, a 브랜치가 먼저 develop에 머지되었지만 b 브랜치에서 a 브랜치를 rebase or merge를 하지 않고 b 브랜치를 develop에 바로 머지하더라도 A, B 브랜치의 모든 변경사항이 dev 서버에 정상 반영되어야 한다.
  • 이렇게 하기 위해서는 PR 단계의 CI에서는 build 검증만 하고 dockerhub에 푸쉬하지 않아야 하며, merge시에 dockerhub에 푸쉬하여야 한다. (CI의 pr, push 과정을 분리)

위의 이유로 feature → develop, release → main의 경우 build 검증 및 정적분석을 진행한다.

  • ./gradlew check를 사용해서 jar 파일을 만들지 않고 빠르게 체크한다.
  • 정적 분석은 sonarcloud를 이용할 예정이다.
  • sonarcloud 분석 실패 시 머지를 차단한다.(bypass가 되면 유동적으로)

CD는 develop, main에 push(merge) 되었을 때 작동하도록 한다.

  • 해당 단계에서는 ./gradlew build를 사용해서 jar 파일을 만든다(docker build를 위해서는 jar 파일이 존재해야 한다.)
  • 해당 단계에서도 다시 한 번 gradle 빌드 시 테스트 체크를 하는 이유는 핫픽스를 위한 예방 장치이다.
    • 핫픽스는 develop, main에 바로 push가 진행되므로, PR 단계의 ./gradlew check를 통해 테스트 체크가 이루어지지 않기 때문이다.
  • 해당 단계에서 dockerhub push를 진행한다. (여기까지 CI 작업)

핫픽스 시에는 main, develop 동시 push가 이루어지므로(git flow 툴 이용), 이를 염두해두고 워크플로우를 짜야한다.

  • 위에서도 언급했듯이 PR이 진행되지 않으므로, ./gradlew check를 통해 테스트 체킹이 되지 않기에 push 이후도 ./gradlew build를 통해 체크해준다.

Main 기능

  • CI 및 PR 빌드 검증 자동화 워크플로우가 추가되었습니다.
  • 개발 및 프로덕션용 CI/CD 자동 빌드 및 배포 워크플로우가 추가되었습니다.
  • 각 모듈별 yml를 두어 각 모듈의 역할에 맞는 환경변수를 관리할 수 있도록 하였습니다.
  • prod에서는 Flyway를 통해 형상관리를 할 수 있도록 관련 설정을 추가했습니다.
  • Mysql, Redis 컨테이너를 활용한 테스트 환경 자동 구성 기능이 도입되었습니다.
  • 릴리즈 노트 자동 생성을 위한 Release Drafter 설정 및 워크플로우가 도입되었습니다.

추가 설명

CI/CD 플로우

  • dev의 경우 ninecraft0523/ninecraft-server:development-latest로 도커허브에 올라가게됩니다.

  • prod의 경우 ninecraft0523/ninecraft-server:2.1.0, ninecraft0523/ninecraft-server:production-latest로 도커허브에 올라가게됩니다. (cc. 2.1.0은 예시)

    • prod의 경우 버저닝 태그를 붙여 각 버전별로 관리를 할 수 있도록 하였습니다. (latest는 서브 태그)
  • 또한, prod의 경우 main에 Push를 할 시 CI/CD가 작동되는 것이 아닌, main push 후 작동한 릴리즈 드래프터를 publish 했을 때 작동됩니다. (dev는 Push만 하면 작동)

    • 해당 이유는 릴리즈 드래프터를 사용하고 있기 때문에, 해당 릴리즈 태그의 버저닝을 보고 도커 허브 Push 워크플로우에서 참고하기 때문에 우선순위가 앞당겨져야 했습니다.

🧪 테스트 내역

  • 브라우저/기기에서 동작 확인
  • 엣지 케이스 테스트 완료
  • 기존 기능 영향 없음

🎨 스크린샷 또는 시연 영상 (선택)

기능 미리보기 기능 미리보기
기능 설명 기능 설명

✅ PR 체크리스트

  • 커밋 메시지가 명확합니다
  • PR 제목이 컨벤션에 맞습니다
  • 관련 이슈 번호를 작성했습니다
  • 기능이 정상적으로 작동합니다
  • 불필요한 코드를 제거했습니다

💬 추가 설명 or 리뷰 포인트 (선택)

Mysql 컨테이너와 Redis 컨테이너의 차이점과 공통점 정리

image
  • MySQL은 Testcontainers JDBC 드라이버와 통합되어 있어, jdbc:tc: 접두사만으로 컨테이너를 자동 실행하고 Spring이 사용하는 DataSource에 연결해줍니다.
  • 반면 Redis는 JDBC 기반이 아니기 때문에 해당 방식이 불가능합니다.
  • 따라서 Redis의 경우에는 JUnit과 Testcontainers 통합 어노테이션(@testcontainers, @container)을 사용해 컨테이너 객체를 수동으로 선언하고, @DynamicPropertySource를 통해 Spring의 RedisConnectionFactory에 필요한 host와 port 정보를 주입해야 합니다.

Redis Testcontainer 자동 관리 관련 이슈 및 해결 방법 정리

문제 상황

  • RedisTestConfig를 사용할 테스트 클래스에 Import를 해도 redis 컨테이너가 띄워지지 않음.

이유

  • @Import(RedisTestConfig::class)로 Redis Testcontainer 설정 클래스를 스프링 빈으로 등록하면, 해당 컨테이너가 Spring 컨텍스트의 빈이 되어 JUnit의 @Testcontainers가 관리하는 컨테이너가 아님.
  • 따라서 JUnit이 컨테이너의 자동 시작(start())과 종료(stop())를 하지 않음.
  • 결과적으로 firstMappedPort 등 컨테이너 동적 정보가 제대로 할당되지 않거나, 실행 시점 문제로 예외 발생 가능.
  • 반면, @Testcontainers@Container 어노테이션이 붙은 클래스에서 직접 테스트를 실행하면 JUnit이 컨테이너 라이프사이클을 자동으로 관리하여, 포트 바인딩과 컨테이너 시작을 보장.
  • 하지만 매 테스트 클래스마다 중복 코드가 발생하거나, 별도 관리가 어려움.

왜 추상 클래스 상속 방식이 해결책인가?

  • @testcontainers@container는 JUnit 5 확장 기능이며,
  • JUnit은 상속받은 추상 클래스에 선언된 @container도 인식하여 자동으로 관리함.
  • 즉, 공통 컨테이너 설정을 추상 테스트 클래스에 두고, 실제 테스트 클래스가 상속만 하면
    • 컨테이너를 한 곳에서 관리하면서 자동 라이프사이클 제어 가능
    • 테스트 클래스에서는 편리하게 컨테이너를 공유하고 동적 프로퍼티도 주입 가능

즉, @import는 스프링 빈으로 관리하는 기능이며, JUnit의 컨테이너 자동 관리 기능과는 별개임을 알게되었습니다.

Summary by CodeRabbit

Summary by CodeRabbit

  • 신규 기능

    • CI 및 PR 빌드 검증 자동화 워크플로우가 추가되었습니다.
    • 릴리즈 노트 자동 생성을 위한 Release Drafter 설정 및 워크플로우가 도입되었습니다.
    • MySQL 기반 사용자 테이블 생성용 초기 마이그레이션 스크립트가 추가되었습니다.
    • JWT, Redis, Persistence 등 환경별 외부 설정 파일이 도입되어 보안 및 관리가 강화되었습니다.
    • 개발 및 프로덕션용 CI/CD 자동 빌드 및 배포 워크플로우가 추가되었습니다.
    • Redis 컨테이너를 활용한 테스트 환경 자동 구성 기능이 도입되었습니다.
  • 구성 및 설정 변경

    • 모든 모듈의 application.yml이 환경별(profile) 및 외부 시크릿 파일 구조로 리팩토링되었습니다.
    • Swagger/OpenAPI 설정이 환경별로 분리 및 관리됩니다.
    • .gitignore에 node_modules/ 및 시크릿 파일 패턴이 추가되었습니다.
    • Redis 연결 설정에 선택적 비밀번호 인증 기능이 추가되었습니다.
    • JWT 관련 설정이 별도 파일로 분리되어 관리됩니다.
    • 서버 포트 및 멀티파트 파일 업로드 제한 설정이 추가되었습니다.
  • 테스트

    • 통합 테스트 환경을 위한 Testcontainers 및 JUnit Jupiter 의존성이 추가되었습니다.
    • 테스트 클래스에 @testcontainers@activeprofiles("test") 어노테이션이 적용되었습니다.
  • 의존성 및 빌드

    • 불필요한 의존성이 제거되고, 모듈별로 필요한 의존성 및 테스트 관련 라이브러리가 정비되었습니다.
    • Flyway 및 MySQL 커넥터 의존성이 추가되었습니다.
  • 기타

    • 일부 application.properties 파일에서 spring.application.name 속성이 삭제되었습니다.
    • JWT 토큰 만료 시간 관리 방식이 개선되었습니다.

@move-hoon move-hoon requested a review from minwoo1999 June 29, 2025 17:46
@move-hoon move-hoon self-assigned this Jun 29, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jun 29, 2025

📝 Walkthrough

"""

Walkthrough

CI/CD 파이프라인과 릴리즈 자동화, 테스트 환경 개선, 설정 파일 외부화 등 인프라 및 개발 환경 관련 설정이 대규모로 추가 및 리팩터링되었습니다. GitHub Actions 기반의 CI, 릴리즈 드래프터, Testcontainers 통합, 환경별 설정 분리, 보안 파일 무시 규칙 등이 포함됩니다.

Changes

파일/그룹 변경 요약
.github/release-drafter-config.yml,
.github/workflows/release-drafter.yml
릴리즈 드래프터 설정 및 워크플로우 신규 추가, 자동 릴리즈 노트 생성
.github/workflows/ci-pr.yml PR 대상 CI 워크플로우 신규 추가
.github/workflows/dev-ci-cd.yml,
.github/workflows/prod-ci-cd.yml
개발 및 프로덕션 CI/CD 워크플로우 신규 추가, 빌드 및 배포 자동화
.gitignore node_modules, secret 프로퍼티 파일 무시 규칙 추가
apis/build.gradle.kts,
admin/build.gradle.kts,
batch/build.gradle.kts
TestContainers, OpenAPI 등 테스트 및 문서화 관련 의존성 추가/정리
buildSrc/src/main/kotlin/Dependencies.kt TestContainers, Flyway 의존성 상수 추가
apis/src/test/kotlin/org/yapp/apis/ApisApplicationTests.kt,
admin/src/test/kotlin/org/yapp/admin/AdminApplicationTests.kt,
batch/src/test/kotlin/org/yapp/batch/BatchApplicationTests.kt
@activeprofiles("test") 어노테이션 추가
apis/src/test/resources/db/migration/mysql/v1_init.sql users 테이블 생성 SQL 마이그레이션 스크립트 추가
apis/src/main/resources/application.yml,
admin/src/main/resources/application.yml,
batch/src/main/resources/application.yml
환경별 프로필 분리, 외부 secret 파일 import, swagger 설정 등 리팩터링
domain/src/main/resources/application.properties,
global-utils/src/main/resources/application.properties,
infra/src/main/resources/application.properties
spring.application.name 속성 제거
infra/build.gradle.kts MySQL, Flyway 의존성 추가 및 순서 정리
infra/src/main/resources/application-persistence.yml MySQL, JPA, Flyway, Testcontainers 환경별 persistence 설정 추가
infra/src/main/resources/application-redis.yml Redis 환경별 설정 파일 신규 추가
infra/src/main/kotlin/org/yapp/infra/config/external/redis/RedisConfig.kt RedisConfig에 nullable password 프로퍼티 추가 및 조건부 설정 반영
infra/src/test/kotlin/org/yapp/infra/config/AbstractRedisTestConfig.kt Redis Testcontainers 기반 추상 테스트 설정 클래스 추가
gateway/build.gradle.kts INFRA, DOMAIN 프로젝트 의존성 제거
gateway/src/main/kotlin/org/yapp/gateway/jwt/JwtTokenServiceImpl.kt refreshTokenExpiration 프로퍼티 제거, JwtTokenProvider 위임
gateway/src/main/resources/application-jwt.yml JWT 관련 설정 파일 신규 추가

Sequence Diagram(s)

sequenceDiagram
    participant Developer
    participant GitHub
    participant GitHub Actions
    participant Release Drafter

    Developer->>GitHub: Pull Request 생성/업데이트
    GitHub->>GitHub Actions: CI - Pull Request 워크플로우 트리거
    GitHub Actions->>GitHub Actions: Gradle 빌드/테스트, Testcontainers 환경 적용
    GitHub->>GitHub Actions: main 브랜치 push
    GitHub Actions->>Release Drafter: 릴리즈 드래프트 생성/업데이트
Loading

Assessment against linked issues

Objective Addressed Explanation
CI/CD 파이프라인 구축 (#10)
블루그린 배포 전략 적용 (#10) 블루그린 배포 관련 코드/설정은 포함되지 않음

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
users 테이블 생성 SQL 마이그레이션 추가 (apis/src/test/resources/db/migration/mysql/v1_init.sql) CI/CD 파이프라인 구축과 직접 관련 없는 DB 마이그레이션 추가
gateway/src/main/kotlin/org/yapp/gateway/jwt/JwtTokenServiceImpl.kt 내 로직 변경 JWT 토큰 만료 로직 리팩터링은 CI/CD 구축과 직접 관련 없음
gateway/src/main/resources/application-jwt.yml 신규 추가 JWT 설정 파일 추가는 CI/CD 구축 목적과 직접적 연관이 불분명함
infra/src/main/resources/application-persistence.yml, application-redis.yml 신규 추가 Persistence/Redis 환경설정 분리는 CI/CD 구축과 직접적 연관이 적음
spring.application.name 속성 제거 (여러 *.properties) CI/CD 목적과 직접적인 연관이 없음
"""

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.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

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

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

Documentation and Community

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

@move-hoon move-hoon changed the title chore: CI/CD 세팅 (테스트 PR) chore: CI/CD 세팅 진행중 (테스트 PR) Jun 29, 2025
Copy link

@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: 8

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e45c994 and 8b21085.

📒 Files selected for processing (6)
  • .github/release-drafter-config.yml (1 hunks)
  • .github/workflows/ci-pr.yml (1 hunks)
  • .github/workflows/release-drafter.yml (1 hunks)
  • .gitignore (1 hunks)
  • apis/src/main/resources/application-dev.yml (1 hunks)
  • apis/src/main/resources/application.yml (1 hunks)
🧰 Additional context used
🪛 YAMLlint (1.37.1)
.github/workflows/ci-pr.yml

[warning] 3-3: truthy value should be one of [false, true]

(truthy)


[error] 8-8: too many spaces inside brackets

(brackets)


[error] 8-8: too many spaces inside brackets

(brackets)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build-validation
🔇 Additional comments (5)
.github/release-drafter-config.yml (1)

4-25: 레이블 이름·이모지 일치 여부 확인 요청
Release Drafter는 config의 labels 배열 값과 PR 레이블을 100% 동일(이모지·대소문자 포함)하게 비교하여 분류합니다. 아래 레이블이 실제 저장소 레이블 목록에도 똑같이 존재하는지 확인해주세요.
불일치 시 해당 PR이 “Uncategorized” 섹션으로 분류될 수 있습니다.

  • ✨ feat
  • 🐞 fix
  • 🔨 refactor
  • 📃 docs
  • ⚙️ chore
  • ✅ test
  • 🎨 style

예: gh label list 명령으로 레이블 목록을 조회한 뒤 config와 대조 바랍니다.

.github/workflows/ci-pr.yml (1)

16-17: ubuntu-24.04 프리뷰 러너 대신 ubuntu-latest 사용 권장

예상치 못한 패키지 누락이나 러너 변경 이슈를 방지하려면, 아직 프리뷰 상태인 ubuntu-24.04 대신 안정화된 ubuntu-latest(현재 Ubuntu 22.04)로 변경하세요.

  • 파일: .github/workflows/ci-pr.yml (16–17줄)
  • 제안된 수정:
-runs-on: ubuntu-24.04
+runs-on: ubuntu-latest

위 변경이 CI 요구사항에 부합하는지 확인 부탁드립니다.

apis/src/main/resources/application.yml (1)

1-3: 프로필 기본값만 유지하는 변경 👍

환경별 설정을 application-dev.yml 로 분리하고, 루트 설정을 최소화한 방향이 명확합니다. 애플리케이션 실행 시 SPRING_PROFILES_ACTIVE 가 별도 지정되지 않을 경우 dev 프로필이 적용되니 의도에 부합합니다.

apis/src/main/resources/application-dev.yml (2)

6-9: application-secret.properties 경로 확인 필요

spring.config.import: optional:application-secret.properties 설정이 classpath 기준인지 파일 시스템 기준인지 명확하지 않습니다.
CI/CD 단계에서 파일이 원하는 위치로 복사되지 않으면 애플리케이션이 부팅에 실패할 수 있습니다.
필요 시 optional:file:./application-secret.properties 또는 optional:classpath:application-secret.properties 로 경로를 명시해 주세요.


34-38: JWT 시크릿 키 길이 확인

HS256/HS512 사용 시 충분히 긴(32/64바이트 이상) 랜덤 문자열이어야 합니다.
환경 변수가 짧거나 예측 가능하면 토큰 위조 위험이 있습니다. 길이와 복잡도를 다시 확인해 주세요.

Comment on lines 13 to 18
datasource:
url: jdbc:mysql://${MYSQL_HOST}:${MYSQL_PORT}/${MYSQL_DATABASE}?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
username: ${MYSQL_USERNAME}
password: ${MYSQL_PASSWORD}
driver-class-name: com.mysql.cj.jdbc.Driver

Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Datasource URL 파라미터 보강 제안

  1. 문자 인코딩을 명시하면 한글 데이터 처리 시 안전합니다.
  2. allowPublicKeyRetrieval=true 는 편의를 위해 켜두었지만 보안 면에서 권장되지 않습니다. 가능하면 dev 환경에서만 사용하도록 프로파일 분리 또는 제거를 고려해 주세요.
-jdbc:mysql://${MYSQL_HOST}:${MYSQL_PORT}/${MYSQL_DATABASE}?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
+jdbc:mysql://${MYSQL_HOST}:${MYSQL_PORT}/${MYSQL_DATABASE}?useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Seoul&allowPublicKeyRetrieval=true
📝 Committable suggestion

‼️ 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.

Suggested change
datasource:
url: jdbc:mysql://${MYSQL_HOST}:${MYSQL_PORT}/${MYSQL_DATABASE}?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
username: ${MYSQL_USERNAME}
password: ${MYSQL_PASSWORD}
driver-class-name: com.mysql.cj.jdbc.Driver
datasource:
- url: jdbc:mysql://${MYSQL_HOST}:${MYSQL_PORT}/${MYSQL_DATABASE}?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
+ url: jdbc:mysql://${MYSQL_HOST}:${MYSQL_PORT}/${MYSQL_DATABASE}?useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Seoul&allowPublicKeyRetrieval=true
username: ${MYSQL_USERNAME}
password: ${MYSQL_PASSWORD}
driver-class-name: com.mysql.cj.jdbc.Driver
🤖 Prompt for AI Agents
In apis/src/main/resources/application-dev.yml around lines 13 to 18, enhance
the datasource URL by explicitly specifying the character encoding parameter
(e.g., useUnicode=true&characterEncoding=utf8) to ensure safe handling of Korean
characters. Also, restrict the use of allowPublicKeyRetrieval=true to the
development environment only by separating it into a dev-specific profile or
removing it from production configurations to improve security.

Copy link

@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: 3

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8b21085 and a3ce8af.

📒 Files selected for processing (5)
  • apis/build.gradle.kts (1 hunks)
  • apis/src/main/resources/application-test.yml (1 hunks)
  • apis/src/test/kotlin/org/yapp/apis/ApisApplicationTests.kt (1 hunks)
  • apis/src/test/resources/db/migration/mysql/v1_init.sql (1 hunks)
  • buildSrc/src/main/kotlin/Dependencies.kt (1 hunks)
🔇 Additional comments (8)
buildSrc/src/main/kotlin/Dependencies.kt (1)

47-50: TestContainers 의존성 버전 검증 완료

  • org.testcontainers:mysql, org.testcontainers:junit-jupiter 모두 Maven Central에서 최신 버전(1.21.3)으로 확인됨
  • GitHub 보안 권고사항에도 취약점 보고 내역이 없음

위 변경사항을 승인합니다.

apis/build.gradle.kts (2)

10-10: 의존성 재구성이 개선되었습니다

Spring Boot Starter Test 의존성을 Spring 관련 의존성들과 함께 그룹핑한 것이 좋은 개선사항입니다.


27-28: TestContainers 의존성이 적절히 추가되었습니다

TestContainers MySQL과 JUnit Jupiter 의존성이 testImplementation 스코프로 올바르게 추가되었습니다. 이는 컨테이너 기반 통합 테스트 환경 구축에 필요한 설정입니다.

apis/src/test/kotlin/org/yapp/apis/ApisApplicationTests.kt (2)

5-6: 필수 import가 올바르게 추가되었습니다

TestContainers와 ActiveProfiles 사용을 위한 import가 적절히 추가되었습니다.


9-10: 테스트 환경 설정이 올바르게 구성되었습니다

@testcontainers@activeprofiles("test") 어노테이션이 적절히 추가되어 컨테이너 기반 테스트 환경이 구성되었습니다. 이를 통해 테스트 실행 시 MySQL 컨테이너가 자동으로 시작되고 테스트 프로필이 활성화됩니다.

apis/src/main/resources/application-test.yml (3)

1-3: 랜덤 포트 설정이 적절합니다

테스트 환경에서 포트 충돌을 방지하기 위한 랜덤 포트(0) 설정이 올바르게 구성되었습니다.


12-14: TestContainers MySQL 설정이 올바르게 구성되었습니다

TestContainers MySQL URL 형식과 초기화 스크립트 경로가 적절히 설정되었습니다. 테스트 실행 시 MySQL 8.0.39 컨테이너가 자동으로 시작되고 v1_init.sql로 초기화됩니다.


37-42: 테스트 환경에서 Swagger 비활성화가 적절합니다

테스트 실행 시 불필요한 Swagger UI와 API 문서 생성을 비활성화한 것이 성능과 테스트 격리에 도움이 됩니다.

Comment on lines +1 to +11
CREATE TABLE IF NOT EXISTS users (
id VARCHAR(36) NOT NULL PRIMARY KEY,
email VARCHAR(100) NOT NULL,
nickname VARCHAR(100) NOT NULL,
profile_image_url VARCHAR(255),
provider_type VARCHAR(20) NOT NULL,
provider_id VARCHAR(100) NOT NULL,
created_at TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP(6),
updated_at TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
deleted_at TIMESTAMP(6) NULL
);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

테이블 스키마에 인덱스와 제약조건 추가를 권장합니다

users 테이블 스키마가 기본적으로 잘 구성되어 있지만, 성능과 데이터 무결성을 위해 다음 개선사항을 고려해보세요:

 CREATE TABLE IF NOT EXISTS users (
     id VARCHAR(36) NOT NULL PRIMARY KEY,
-    email VARCHAR(100) NOT NULL,
+    email VARCHAR(100) NOT NULL UNIQUE,
     nickname VARCHAR(100) NOT NULL,
     profile_image_url VARCHAR(255),
     provider_type VARCHAR(20) NOT NULL,
     provider_id VARCHAR(100) NOT NULL,
     created_at TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP(6),
     updated_at TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
-    deleted_at TIMESTAMP(6) NULL
+    deleted_at TIMESTAMP(6) NULL,
+    INDEX idx_email (email),
+    INDEX idx_provider (provider_type, provider_id),
+    INDEX idx_deleted_at (deleted_at)
 );

주요 개선사항:

  1. 이메일 중복 방지를 위한 UNIQUE 제약조건
  2. 자주 조회될 컬럼들에 대한 인덱스 추가
  3. 소프트 딜리트 조회 최적화를 위한 deleted_at 인덱스
🤖 Prompt for AI Agents
In apis/src/test/resources/db/migration/mysql/v1_init.sql lines 1 to 11, the
users table lacks a UNIQUE constraint on the email column to prevent duplicates,
and it does not have indexes on frequently queried columns or on deleted_at for
optimizing soft delete queries. Add a UNIQUE constraint on the email column,
create indexes on columns that are often used in queries such as provider_type
and provider_id, and add an index on deleted_at to improve query performance
related to soft deletes.


jpa:
hibernate:
ddl-auto: create
Copy link
Member

Choose a reason for hiding this comment

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

dev환경에서는 update로하거나
none or validate로 설정해서
기존데이터가 날라가지 않도록하는 방향으로 가는건 어떨까요!?

Copy link
Member Author

Choose a reason for hiding this comment

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

좋습니다!! 해당부분 none으로 진행하고 flyway로 형상관리 할 수 있도록 진행하겠습니다~

move-hoon added 11 commits July 1, 2025 20:27
- jwtTokenProvider에서 알고 있기에 해당 객체에서 get
애플리케이션의 설정 관리 방식을 보다 명확하고 확장성 있게 개선했습니다.

주요 변경 사항:
1.  **프로파일 그룹 도입 (`spring.profiles.group`)**
- `dev`, `prod`, `test` 등 각 환경에서 필요한 기능별 설정(persistence, jwt, redis 등)을 그룹으로 묶어 관리합니다.
- 이를 통해 환경별 구성 요소를 한눈에 파악하고 쉽게 조합할 수 있습니다.

2.  **민감 정보 외부 분리**
- 데이터베이스 접속 정보, JWT 키 등 민감 정보를 프로젝트 루트의 `secret` 디렉토리로 분리했습니다.
- `spring.config.import`와 `file:` 경로를 사용하여 각 환경에 맞는 시크릿 파일을 안전하게 로드합니다.
- 이 구조는 `.gitignore`를 통해 Git에 민감 정보가 커밋되는 것을 방지하고, CI/CD 환경에서 외부 주입을 용이하게 합니다.
Copy link

@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: 5

♻️ Duplicate comments (3)
.gitignore (1)

175-176: application-*-secret.properties 패턴이 여전히 범위가 너무 넓습니다.
앞선 리뷰에서 동일 지적이 있었습니다. 특정 모듈(apis/src/main/resources/…)만 무시하려면 경로를 명시적으로 적어주세요.

.github/workflows/ci-pr.yml (2)

30-34: 시크릿 파일 생성 시 보안 및 안정성 개선 권장

현재 구현에서 몇 가지 개선사항이 있습니다:

  1. echo 명령은 파일 끝에 개행을 추가하여 프로퍼티 파일 형식을 변경시킬 수 있습니다
  2. secret 디렉터리가 이미 존재할 경우 실패할 수 있습니다
 run: |
-  mkdir ./secret
-  echo "${{ secrets.DEV_SECRET_PROPERTIES }}" > ./secret/application-dev-secret.properties
-  echo "${{ secrets.PROD_SECRET_PROPERTIES }}" > ./secret/application-prod-secret.properties  
-  echo "${{ secrets.TEST_SECRET_PROPERTIES }}" > ./secret/application-test-secret.properties
+  mkdir -p ./secret
+  printf "%s" "${{ secrets.DEV_SECRET_PROPERTIES }}" > ./secret/application-dev-secret.properties
+  printf "%s" "${{ secrets.PROD_SECRET_PROPERTIES }}" > ./secret/application-prod-secret.properties
+  printf "%s" "${{ secrets.TEST_SECRET_PROPERTIES }}" > ./secret/application-test-secret.properties
   chmod 600 ./secret/*

50-51: CI 빠른 실패를 위한 --continue 플래그 제거 권장

테스트 실패 시 즉시 빌드를 중단하여 빠른 피드백을 받을 수 있도록 --continue 플래그 제거를 권장합니다.

-run: ./gradlew check --parallel --build-cache --continue
+run: ./gradlew check --parallel --build-cache
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3ce8af and ef7ad0b.

📒 Files selected for processing (19)
  • .github/workflows/ci-pr.yml (1 hunks)
  • .gitignore (1 hunks)
  • admin/build.gradle.kts (1 hunks)
  • admin/src/main/resources/application.yml (1 hunks)
  • admin/src/test/kotlin/org/yapp/admin/AdminApplicationTests.kt (1 hunks)
  • apis/src/main/resources/application.yml (2 hunks)
  • batch/build.gradle.kts (1 hunks)
  • batch/src/main/resources/application.yml (1 hunks)
  • batch/src/test/kotlin/org/yapp/batch/BatchApplicationTests.kt (1 hunks)
  • buildSrc/src/main/kotlin/Dependencies.kt (1 hunks)
  • domain/src/main/resources/application.properties (0 hunks)
  • gateway/build.gradle.kts (0 hunks)
  • gateway/src/main/kotlin/org/yapp/gateway/jwt/JwtTokenServiceImpl.kt (1 hunks)
  • gateway/src/main/resources/application-jwt.yml (1 hunks)
  • global-utils/src/main/resources/application.properties (0 hunks)
  • infra/build.gradle.kts (1 hunks)
  • infra/src/main/resources/application-persistence.yml (1 hunks)
  • infra/src/main/resources/application-redis.yml (1 hunks)
  • infra/src/main/resources/application.properties (0 hunks)
💤 Files with no reviewable changes (4)
  • infra/src/main/resources/application.properties
  • gateway/build.gradle.kts
  • global-utils/src/main/resources/application.properties
  • domain/src/main/resources/application.properties
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: hoonyworld
PR: YAPP-Github/26th-App-Team-1-BE#17
File: .github/workflows/ci-pr.yml:8-9
Timestamp: 2025-07-01T09:50:45.498Z
Learning: hoonyworld 사용자는 Naver 코드 포맷터를 사용하며, 이 포맷터는 YAML 배열의 대괄호 내부에 자동으로 여분의 공백을 추가하는 특성이 있음.
.github/workflows/ci-pr.yml (1)
Learnt from: hoonyworld
PR: YAPP-Github/26th-App-Team-1-BE#17
File: .github/workflows/ci-pr.yml:8-9
Timestamp: 2025-07-01T09:50:45.498Z
Learning: hoonyworld 사용자는 Naver 코드 포맷터를 사용하며, 이 포맷터는 YAML 배열의 대괄호 내부에 자동으로 여분의 공백을 추가하는 특성이 있음.
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build-validation
🔇 Additional comments (29)
.gitignore (1)

172-173: node_modules/ 무시 패턴이 실제 필요 여부 확인 부탁드립니다.

Gradle/Kotlin 단일 프로젝트라면 node_modules/ 디렉터리가 생성되지 않을 가능성이 높습니다. 서브-모듈에 Node 기반 도구(예: 프론트엔드 빌드, CDK 등)가 없다면 패턴을 삭제해도 무방합니다.
확실히 하려면 저장소 내 package.json 존재 여부를 한 번 점검해주세요.

buildSrc/src/main/kotlin/Dependencies.kt (2)

52-54: Flyway 의존성 구성 확인됨

Flyway MySQL 의존성에서 버전을 명시하지 않은 것은 Spring Boot BOM에서 관리되므로 적절한 접근입니다.


47-50: TestContainers 버전 확인 완료

현재 사용 중인 TestContainers 버전 1.21.3는 2025년 7월 기준 Maven Central 및 공식 문서상 최신 안정화 버전입니다.
따라서 별도 업데이트는 필요하지 않습니다.

.github/workflows/ci-pr.yml (1)

8-11: YAML 배열 형식 개선됨

이전 리뷰에서 지적된 YAML 배열 공백 이슈가 멀티라인 형식으로 해결되었습니다. 이 형식이 더 읽기 쉽고 포맷터와의 호환성도 좋습니다.

gateway/src/main/resources/application-jwt.yml (1)

1-4: JWT 설정 외부화 및 보안 구성 우수

JWT 관련 설정을 별도 파일로 분리하고 환경변수를 통해 시크릿 키를 관리하는 접근이 우수합니다. 토큰 만료 시간 설정도 적절합니다 (액세스 토큰 30분, 리프레시 토큰 2주).

admin/src/test/kotlin/org/yapp/admin/AdminApplicationTests.kt (1)

5-10: Testcontainers 통합 설정 적절함

@Testcontainers@ActiveProfiles("test") 어노테이션 추가로 컨테이너 기반 통합 테스트 환경이 올바르게 설정되었습니다. 다른 모듈들과 일관된 테스트 설정입니다.

admin/build.gradle.kts (3)

12-12: 테스트 의존성 위치 변경 승인

테스트 의존성을 implementation 블록 근처로 이동한 것은 가독성 향상에 도움이 됩니다.


16-16: SpringDoc OpenAPI 의존성 추가 승인

API 문서화를 위한 SpringDoc 의존성 추가는 개발 및 운영에 유용합니다.


18-19: Testcontainers 의존성 추가로 테스트 환경 개선

MySQL과 JUnit Jupiter를 위한 Testcontainers 의존성 추가는 격리된 통합 테스트 환경을 제공하여 테스트 품질을 크게 향상시킵니다.

batch/build.gradle.kts (3)

4-4: DOMAIN 프로젝트 의존성 추가 승인

배치 모듈에서 도메인 로직에 접근하기 위한 의존성 추가는 적절합니다.


12-12: 테스트 의존성 스코프 정리

spring-boot-starter-testtestImplementation으로 명시적으로 선언한 것은 의존성 관리를 명확하게 합니다.


16-17: Testcontainers 의존성으로 테스트 환경 통일

admin 모듈과 동일한 Testcontainers 의존성을 추가하여 모듈 간 테스트 환경 일관성을 유지하고 있습니다.

infra/build.gradle.kts (1)

13-13: MySQL 커넥터 의존성 추가 승인

인프라 모듈에서 MySQL 연결을 위한 커넥터 의존성 추가는 적절합니다.

batch/src/test/kotlin/org/yapp/batch/BatchApplicationTests.kt (2)

5-6: 테스트 어노테이션을 위한 import 추가

Testcontainers와 ActiveProfiles 사용을 위한 import가 적절히 추가되었습니다.


9-10: @Testcontainers 애노테이션 검토 요청

현재 테스트 클래스에 실제로 @Container 필드나 컨테이너 기반 테스트 로직이 없으므로,
@Testcontainers 애노테이션이 아무런 효과를 발휘하지 않습니다.
반면 @ActiveProfiles("test")는 각 모듈의 application.ymltest: 설정이 정의되어 있어 정상적으로 테스트 전용 프로퍼티를 로드합니다.

확인 포인트:

  • batch/src/test/kotlin/org/yapp/batch/BatchApplicationTests.kt (9–10행):
    @Testcontainers 삭제 또는 실제 컨테이너 사용 로직 추가
  • apis, admin, batch 각 모듈의 application.yml에서 test: 설정이 존재함

위 내용을 바탕으로 @Testcontainers 애노테이션의 유지 필요 여부를 검토해주세요.

apis/src/main/resources/application.yml (4)

3-3: Graceful shutdown 설정 추가 승인

서버 종료 시 진행 중인 요청을 안전하게 완료하기 위한 graceful shutdown 설정은 운영 환경에서 중요합니다.


6-19: 프로필 그룹화로 설정 모듈화

dev, prod, test 환경별로 persistence, jwt, redis 프로필을 그룹화한 것은 설정 관리를 체계적으로 만듭니다. 각 환경에서 필요한 설정들이 일관되게 적용됩니다.


21-23: 멀티파트 파일 업로드 크기 제한 설정

파일 업로드 크기를 10MB, 전체 요청 크기를 30MB로 제한한 것은 적절합니다. 서버 리소스 보호와 사용성의 균형을 잘 맞췄습니다.


48-52: 프로덕션과 테스트 환경에서 Swagger UI 비활성화

프로덕션과 테스트 환경에서 Swagger UI를 비활성화한 것은 보안과 성능 측면에서 적절한 결정입니다.

Also applies to: 61-65

gateway/src/main/kotlin/org/yapp/gateway/jwt/JwtTokenServiceImpl.kt (1)

63-63: JWT 구성 중앙화를 위한 좋은 리팩터링입니다.

@Value 어노테이션을 통한 직접 주입 대신 JwtTokenProvider로 위임하는 방식으로 변경하여 JWT 관련 설정을 중앙화했습니다. 이는 설정 관리의 일관성을 향상시키는 좋은 아키텍처 변경입니다.

batch/src/main/resources/application.yml (2)

1-24: 프로필 기반 구성 관리로의 우수한 리팩터링입니다.

모놀리식 구성에서 프로필 그룹 기반 구성으로 전환하여 환경별 설정 관리가 크게 개선되었습니다. 서버 graceful shutdown 설정과 multipart 업로드 제한도 적절히 추가되었습니다.


22-23: multipart 업로드 제한 설정을 검토해주세요.

파일 크기 10MB, 요청 크기 30MB로 설정되어 있습니다. 배치 모듈의 요구사항에 맞는 적절한 크기인지 확인이 필요합니다.

admin/src/main/resources/application.yml (3)

1-33: 프로필 기반 구성과 Swagger 설정이 잘 구조화되었습니다.

배치 모듈과 동일한 프로필 기반 구성 패턴을 적용하여 일관성을 유지했습니다. Swagger UI와 API 문서가 기본적으로 활성화되어 개발자 경험을 향상시킵니다.


48-65: 프로덕션 환경에서 Swagger 비활성화 - 우수한 보안 관행입니다.

prodtest 프로필에서 Swagger UI와 API 문서를 비활성화한 것은 보안과 성능 측면에서 올바른 접근입니다. 프로덕션 환경에서 불필요한 엔드포인트 노출을 방지합니다.


57-57: test 프로필 시크릿 파일 경로 일관성 확인이 필요합니다.

test 프로필에서 ../secret/ 경로를 사용하고 있어 다른 프로필들과 경로 구조가 다릅니다. 배치 모듈과 동일한 패턴을 사용하고 있지만, 전체 프로젝트의 시크릿 파일 구조 일관성을 확인해주세요.

infra/src/main/resources/application-persistence.yml (4)

1-26: 중앙화된 persistence 구성이 잘 설계되었습니다.

환경 변수를 통한 데이터소스 설정, MySQL 8 dialect 사용, Flyway 마이그레이션 설정이 모두 적절히 구성되었습니다. 모듈 간 persistence 설정의 일관성을 제공하는 좋은 아키텍처입니다.


27-42: Testcontainers 기반 테스트 구성이 우수합니다.

테스트 프로필에서 Testcontainers를 사용한 MySQL 8.0.39 설정이 잘 구성되었습니다. create-drop DDL 설정과 Flyway 비활성화로 테스트 환경에 최적화되어 있습니다.


34-35: Testcontainers JDBC URL 형식 확인.

jdbc:tc:mysql:8.0.39:///testdb 형식이 올바른지 확인해주세요. 일반적으로 Testcontainers MySQL JDBC URL은 jdbc:tc:mysql:8.0.39:///testdb?TC_INITSCRIPT=... 형식을 사용할 수 있습니다.


3-6: 환경 변수 설정 누락 확인 및 검토 요청

infra/src/main/resources/application-persistence.yml (3–6)에서 참조하는 MySQL 환경 변수들이 실제로 어디에서도 설정되지 않은 것이 확인되었습니다.
필요한 변수:

  • MYSQL_HOST
  • MYSQL_PORT
  • MYSQL_DATABASE
  • MYSQL_USERNAME
  • MYSQL_PASSWORD

다음 항목들을 점검해 주세요:

  • 로컬/테스트/프로덕션 환경에서 .env 파일 또는 Docker Compose 설정에 해당 변수가 정의되어 있는지
  • Kubernetes ConfigMap/Secret, CI/CD 파이프라인 변수 주입 등으로 누락 없이 전달되고 있는지

Comment on lines 7 to 15
---
spring:
config:
activate:
on-profile: test
data:
redis:
host: ${REDIS_HOST}
port: ${REDIS_PORT}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

테스트 프로필의 Redis 설정 중복 검토 필요

현재 기본 설정과 test 프로필 설정이 동일합니다. 테스트 환경에서는 보통 다른 Redis 인스턴스나 포트를 사용하는 것이 일반적입니다.

 ---
 spring:
   config:
     activate:
       on-profile: test
   data:
     redis:
-      host: ${REDIS_HOST}
-      port: ${REDIS_PORT}
+      host: ${REDIS_HOST:localhost}
+      port: ${REDIS_PORT:6380}  # 테스트용 다른 포트 또는 TestContainers 포트
📝 Committable suggestion

‼️ 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.

Suggested change
---
spring:
config:
activate:
on-profile: test
data:
redis:
host: ${REDIS_HOST}
port: ${REDIS_PORT}
---
spring:
config:
activate:
on-profile: test
data:
redis:
host: ${REDIS_HOST:localhost}
port: ${REDIS_PORT:6380} # 테스트용 다른 포트 또는 TestContainers 포트
🤖 Prompt for AI Agents
In infra/src/main/resources/application-redis.yml around lines 7 to 15, the
Redis configuration for the test profile duplicates the default settings. To fix
this, modify the test profile Redis host and port to point to a separate Redis
instance or port specific for testing, ensuring it does not conflict with the
default environment.


implementation(Dependencies.Feign.STARTER_OPENFEIGN)

implementation(Dependencies.Flyway.MYSQL)
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Flyway MySQL 의존성 추가로 데이터베이스 마이그레이션 지원

데이터베이스 스키마 버전 관리를 위한 Flyway 의존성 추가는 운영 환경에서 매우 중요합니다.

Flyway 마이그레이션 파일들이 적절히 구성되어 있는지 확인해보겠습니다:


🏁 Script executed:

#!/bin/bash
# Flyway 마이그레이션 파일들의 존재 여부와 명명 규칙 확인
fd -e sql . -x echo "Found migration file: {}"

# Flyway 설정 파일 확인
fd "flyway" . -t f
fd "application.*yml" . -x grep -l "flyway" {}

Length of output: 250


Flyway 마이그레이션 파일 및 설정 내용을 추가로 확인합니다:


🏁 Script executed:

#!/bin/bash
# 1) 모든 SQL 마이그레이션 파일 확인 및 테스트/프로덕션 분류
python3 - << 'EOF'
import glob
for f in sorted(glob.glob("**/*.sql", recursive=True)):
    tag = "TEST" if "/test/" in f else "PROD"
    print(f"{tag} migration file: {f}")
EOF

# 2) Flyway 설정(application-persistence.yml) 내용 확인
config_file=$(fd application-persistence.yml -t f)
echo "=== Flyway 설정 내용 (${config_file}) ==="
grep -C2 flyway "${config_file}" || true

Length of output: 570


아래 스크립트로 application-persistence.yml 전체 프로파일 설정과 프로덕션용 마이그레이션 디렉터리 유무를 확인해보겠습니다:


🏁 Script executed:

#!/bin/bash
# 1) Flyway 프로파일별 설정 전체 확인
echo "=== application-persistence.yml 전체 내용 ==="
cat infra/src/main/resources/application-persistence.yml

# 2) 메인 리소스 경로의 마이그레이션 파일 확인
echo "=== src/main/resources/db/migration 경로 하위 SQL 파일 ==="
fd -e sql src/main/resources/db/migration -x echo "Found PROD migration file: {}" || echo "No PROD migration files found"

Length of output: 1292


프로덕션용 Flyway 마이그레이션 파일 누락 확인 및 보완 필요

infra/src/main/resources/application-persistence.yml에서 Flyway가 프로덕션 환경에서 활성화되어 있음에도 불구하고, 지정된 classpath:db/migration 경로에 SQL 마이그레이션 파일이 존재하지 않습니다. 현재 테스트 리소스에는 아래 파일만 확인되었습니다.

  • apis/src/test/resources/db/migration/mysql/v1_init.sql (테스트 전용)

프로덕션 마이그레이션을 위해 다음 사항을 반영해주세요:

  • src/main/resources/db/migration 경로에 프로덕션용 .sql 마이그레이션 파일 추가
  • 필요 시 src/main/resources/db/seed 디렉터리 생성 및 초기 데이터 스크립트 배치
🤖 Prompt for AI Agents
In infra/build.gradle.kts at line 17, although Flyway is enabled for production
in application-persistence.yml, there are no SQL migration files in the
production migration path. To fix this, add the required production SQL
migration files under src/main/resources/db/migration, and if needed, create
src/main/resources/db/seed for initial data scripts to ensure Flyway can run
migrations properly in production.

Comment on lines +23 to +25
locations:
- classpath:db/migration
- classpath:db/seed
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Flyway 마이그레이션 스크립트 위치를 확인해주세요.

classpath:db/migrationclasspath:db/seed 위치에 마이그레이션 스크립트들이 존재하는지 확인이 필요합니다.

다음 스크립트로 마이그레이션 파일들을 확인할 수 있습니다:


🏁 Script executed:

#!/bin/bash
# Description: Flyway 마이그레이션 스크립트 파일들 확인

echo "=== db/migration 디렉토리 내용 확인 ==="
fd -t f -e sql . --search-path="*/src/main/resources/db/migration" 2>/dev/null || echo "migration 디렉토리를 찾을 수 없습니다"

echo -e "\n=== db/seed 디렉토리 내용 확인 ==="
fd -t f -e sql . --search-path="*/src/main/resources/db/seed" 2>/dev/null || echo "seed 디렉토리를 찾을 수 없습니다"

echo -e "\n=== 전체 프로젝트에서 SQL 마이그레이션 파일 찾기 ==="
fd -e sql -t f | head -10

Length of output: 554


Flyway 마이그레이션 및 시드 디렉토리에 스크립트가 없습니다.

확인 결과 infra/src/main/resources/db/migrationinfra/src/main/resources/db/seed 디렉토리에서 SQL 파일을 찾을 수 없었습니다.
(테스트 리소스인 apis/src/test/resources/db/migration/mysql/v1_init.sql만 존재)

프로덕션에서 마이그레이션이 정상 동작하도록 아래 항목을 검토 후 조치해주세요:

  • infra/src/main/resources/db/migration 디렉토리에 마이그레이션 SQL 파일 추가
  • infra/src/main/resources/db/seed 디렉토리에 시드 데이터 SQL 파일 추가 또는 실제 파일이 위치한 경로를 locations 설정에 반영
🤖 Prompt for AI Agents
In infra/src/main/resources/application-persistence.yml around lines 23 to 25,
the Flyway migration and seed directories specified do not contain any SQL
scripts, causing migration to fail in production. To fix this, add the necessary
migration SQL files to infra/src/main/resources/db/migration and seed SQL files
to infra/src/main/resources/db/seed, or update the locations setting to point to
the actual directories where these SQL files exist.

move-hoon added 7 commits July 2, 2025 02:51
- 테스트 실행 시 실제 Redis 설정 파일이나 환경변수에 의존하지 않고,
Testcontainers로 실행되는 Redis 컨테이너를 사용하기 위해 test 프로필에서 redis 설정을 제외했습니다.
- JUnit 5 + Testcontainers 기반의 Redis 테스트 설정 클래스를 추가했습니다.
- 테스트 클래스에서 이 클래스를 상속하면 Redis 컨테이너가 자동으로 실행되며, 컨테이너의 host/port가 Spring 프로퍼티에 동적으로 주입됩니다.
- 추후, 모듈 간 테스트 코드 접근 문제로 인해, 추후 Gradle Test Fixture 도입이 필요합니다.
Copy link

@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: 4

♻️ Duplicate comments (4)
apis/src/main/resources/application.yml (1)

36-38: .gitignore에 비밀 설정 파일 무시 설정 추가 필요

이전 리뷰 코멘트와 동일한 이슈입니다. 외부 비밀 설정 파일들이 Git에 커밋되지 않도록 .gitignore에 패턴을 추가해야 합니다.

#!/bin/bash
# .gitignore 파일에서 secret 관련 패턴 확인
cat .gitignore | grep -i secret || echo "secret 패턴이 .gitignore에 없습니다"

# secret 디렉토리 존재 여부 확인
fd "secret" . -t d

Also applies to: 44-46, 57-59

admin/src/main/resources/application.yml (1)

1-65: APIs 모듈과 일관된 설정 구조

Admin 모듈의 설정이 APIs 모듈과 동일한 구조를 가지고 있어 일관성이 좋습니다. 프로필 기반 설정과 환경별 분리가 잘 되어 있습니다.

동일한 비밀 파일 관리 이슈가 적용됩니다:

  • .gitignore에 secret/ 패턴 추가 필요
  • 테스트 프로필의 ../secret/ 경로 확인 필요
infra/build.gradle.kts (1)

17-17: Flyway MySQL 의존성 추가에 따른 마이그레이션 파일 준비 상태 재확인

이전 리뷰에서 지적된 프로덕션용 Flyway 마이그레이션 파일 누락 문제가 여전히 해결되지 않았는지 확인이 필요합니다. Flyway 의존성을 추가했으니 해당 마이그레이션 파일들도 함께 준비되어야 합니다.

batch/src/main/resources/application.yml (1)

24-43: 외부 시크릿 파일 경로 일관성 문제

이전 리뷰에서 지적된 시크릿 파일 경로 문제가 여전히 해결되지 않았습니다. 특히 test 프로필의 ../secret/ 경로가 dev, prod 프로필의 secret/ 경로와 다른 상대 경로를 사용하고 있어 일관성이 부족합니다.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cd6ce05 and 880437a.

📒 Files selected for processing (12)
  • .gitignore (1 hunks)
  • admin/src/main/resources/application.yml (1 hunks)
  • admin/src/test/kotlin/org/yapp/admin/AdminApplicationTests.kt (1 hunks)
  • apis/build.gradle.kts (1 hunks)
  • apis/src/main/resources/application.yml (2 hunks)
  • apis/src/test/kotlin/org/yapp/apis/ApisApplicationTests.kt (1 hunks)
  • batch/src/main/resources/application.yml (1 hunks)
  • batch/src/test/kotlin/org/yapp/batch/BatchApplicationTests.kt (1 hunks)
  • buildSrc/src/main/kotlin/Dependencies.kt (1 hunks)
  • infra/build.gradle.kts (1 hunks)
  • infra/src/main/resources/application-redis.yml (1 hunks)
  • infra/src/test/kotlin/org/yapp/infra/config/AbstractRedisTestConfig.kt (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: hoonyworld
PR: YAPP-Github/26th-App-Team-1-BE#17
File: .github/workflows/ci-pr.yml:8-9
Timestamp: 2025-07-01T09:50:45.498Z
Learning: hoonyworld 사용자는 Naver 코드 포맷터를 사용하며, 이 포맷터는 YAML 배열의 대괄호 내부에 자동으로 여분의 공백을 추가하는 특성이 있음.
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build-validation
🔇 Additional comments (14)
.gitignore (1)

172-173: node_modules/ 무시 추가 👍

모노레포에서도 불필요한 대용량 디렉터리를 방지할 수 있어 적절한 선택입니다.

buildSrc/src/main/kotlin/Dependencies.kt (2)

47-51: TestContainers 의존성 추가가 적절합니다

MySQL과 JUnit Jupiter는 동일한 버전(1.21.3)을 사용하고 있어 일관성이 좋습니다. Redis TestContainers는 다른 패키지(com.redis)를 사용하고 있는데, 이는 공식 Redis TestContainers 구현체로 보입니다.


53-55: Flyway 의존성 버전 관리 확인 필요
org.flywaydb:flyway-mysql에 명시적인 버전이 없습니다.
프로젝트에서 아래 항목 중 하나로 Flyway 버전을 관리하고 있는지 확인해 주세요:

  • Spring Boot BOM(org.springframework.boot:spring-boot-dependencies)을 통해 관리
  • io.spring.dependency-management 플러그인을 통한 의존성 관리
apis/src/main/resources/application.yml (2)

5-18: 프로필 기반 설정 구조가 우수합니다

개발, 운영, 테스트 환경별로 적절히 분리되어 있고, 각 프로필이 persistence, jwt, redis 서브프로필을 포함하고 있습니다. 테스트 프로필에서 redis를 제외한 것도 적절한 선택입니다.


56-56: 테스트 프로필의 비밀 파일 경로 일관성 확인 필요

dev/prod 프로필에서는

import: optional:file:secret/application-*-secret.properties

를 사용하는 반면, test 프로필만

import: optional:file:../secret/application-test-secret.properties

를 사용하고 있습니다. 이 차이가 의도된 것인지 확인 부탁드립니다.

  • 파일: apis/src/main/resources/application.yml
  • 56행: import: optional:file:../secret/application-test-secret.properties
apis/src/test/kotlin/org/yapp/apis/ApisApplicationTests.kt (1)

5-5: 테스트 프로필 활성화가 적절합니다

새로운 프로필 기반 설정에 맞춰 테스트에서 "test" 프로필을 활성화하는 것이 올바른 접근입니다. 이는 테스트 환경에서 적절한 설정이 로드되도록 보장합니다.

Also applies to: 8-8

admin/src/test/kotlin/org/yapp/admin/AdminApplicationTests.kt (1)

5-5: 모듈 간 일관된 테스트 프로필 설정

APIs 모듈과 동일하게 테스트 프로필을 활성화하여 모듈 간 일관성을 유지하고 있습니다. 이는 프로필 기반 설정 구조에 맞는 올바른 접근입니다.

Also applies to: 8-8

batch/src/test/kotlin/org/yapp/batch/BatchApplicationTests.kt (1)

5-8: 테스트 프로필 활성화로 일관된 테스트 환경 구성 완료

다른 모듈들(apis, admin)과 동일하게 test 프로필을 활성화하여 일관된 테스트 환경을 구성한 점이 좋습니다. 이를 통해 프로필별 설정 분리가 제대로 적용될 것입니다.

apis/build.gradle.kts (1)

27-29: TestContainers 의존성 버전 확인 결과

  • buildSrc/src/main/kotlin/Dependencies.kt에서
    • MySQL, JUnit Jupiter → 1.21.3
    • Redis(com.redis:testcontainers-redis) → 2.2.2
  • 루트 build.gradle.kts에서 Spring Boot 플러그인 버전 → 3.5.0
  • Gradle 의존성 선언 순서는 테스트 로딩 순에 영향을 주지 않으므로 변경 불필요

위 설정은 buildSrc를 통해 일관되게 관리되고 있으나, Redis 모듈(com.redis:testcontainers-redis:2.2.2)이 TestContainers 코어(1.21.3)와 완전히 호환되는지 최종 확인 부탁드립니다.

infra/build.gradle.kts (1)

19-21: TestContainers 의존성 추가로 테스트 인프라 강화

MySQL, JUnit Jupiter, Redis TestContainers 의존성 추가로 인프라 모듈의 테스트 환경이 크게 개선됩니다. 실제 데이터베이스와 Redis 환경에서의 통합 테스트가 가능해집니다.

batch/src/main/resources/application.yml (2)

1-3: 서버 설정 추가로 운영 안정성 향상

graceful shutdown 설정 추가는 서비스 중단 시 요청 처리를 안전하게 종료할 수 있게 해주는 좋은 설정입니다.


16-18: test 프로필에서 redis 설정 제외 확인 필요

dev, prod 프로필과 달리 test 프로필에서는 redis 프로필이 제외되어 있습니다. 테스트 환경에서 Redis를 사용하지 않는 것이 의도된 설계인지 확인이 필요합니다.

       test:
         - persistence
         - jwt
+        - redis
infra/src/test/kotlin/org/yapp/infra/config/AbstractRedisTestConfig.kt (2)

1-8: 임포트 구성이 적절합니다.

필요한 Testcontainers, Spring Test, JUnit 관련 클래스들이 올바르게 임포트되어 있습니다.


20-22: 클래스 선언과 어노테이션이 적절합니다.

@testcontainers와 @TestConfiguration 어노테이션이 올바르게 사용되었고, 추상 클래스 설계가 재사용 가능한 테스트 설정에 적합합니다.

Comment on lines +24 to +38
companion object {
@Container
@JvmStatic
private val redisContainer = RedisContainer(
RedisContainer.DEFAULT_IMAGE_NAME.withTag(RedisContainer.DEFAULT_TAG)
)

@JvmStatic
@DynamicPropertySource
fun redisProperties(registry: DynamicPropertyRegistry) {
registry.add("spring.data.redis.host", redisContainer::getHost)
registry.add("spring.data.redis.port", redisContainer::getFirstMappedPort)
}
}
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Redis 컨테이너 설정이 올바르게 구현되었습니다.

정적 컨테이너 인스턴스와 동적 프로퍼티 주입이 적절히 구성되어 있습니다. 성능 최적화를 위한 추가 개선사항을 제안드립니다.

성능 향상을 위해 컨테이너 재사용을 고려해보세요:

 companion object {
+    init {
+        redisContainer.withReuse(true)
+    }
+    
     @Container
     @JvmStatic
     private val redisContainer = RedisContainer(
         RedisContainer.DEFAULT_IMAGE_NAME.withTag(RedisContainer.DEFAULT_TAG)
-    )
+    ).apply {
+        withReuse(true)
+    }

또한 필요시 Redis 이미지와 태그를 설정 가능하게 만들 수도 있습니다.

📝 Committable suggestion

‼️ 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.

Suggested change
companion object {
@Container
@JvmStatic
private val redisContainer = RedisContainer(
RedisContainer.DEFAULT_IMAGE_NAME.withTag(RedisContainer.DEFAULT_TAG)
)
@JvmStatic
@DynamicPropertySource
fun redisProperties(registry: DynamicPropertyRegistry) {
registry.add("spring.data.redis.host", redisContainer::getHost)
registry.add("spring.data.redis.port", redisContainer::getFirstMappedPort)
}
}
}
companion object {
init {
redisContainer.withReuse(true)
}
@Container
@JvmStatic
private val redisContainer = RedisContainer(
RedisContainer.DEFAULT_IMAGE_NAME.withTag(RedisContainer.DEFAULT_TAG)
).apply {
withReuse(true)
}
@JvmStatic
@DynamicPropertySource
fun redisProperties(registry: DynamicPropertyRegistry) {
registry.add("spring.data.redis.host", redisContainer::getHost)
registry.add("spring.data.redis.port", redisContainer::getFirstMappedPort)
}
}
}
🤖 Prompt for AI Agents
In infra/src/test/kotlin/org/yapp/infra/config/AbstractRedisTestConfig.kt around
lines 24 to 38, improve performance by enabling reuse of the RedisContainer
instance across tests to avoid repeated startup overhead. Refactor the
RedisContainer initialization to support container reuse, such as by making it a
singleton or using a shared container lifecycle. Additionally, modify the code
to allow configuration of the Redis image name and tag via external parameters
or environment variables, making the setup more flexible and customizable.

Copy link

@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: 4

♻️ Duplicate comments (3)
.github/workflows/ci-pr.yml (1)

28-34: 시크릿 파일 주입 시 echoprintf 사용 & mkdir -p로 방어적 디렉터리 생성

이전 커밋에서도 동일 지적이 있었습니다만(echo 개행 문제), 아직 반영되지 않았습니다. 개행으로 인해 프로퍼티 값이 변조될 수 있으니 한 줄 파일에는 printf가 안전합니다.

-run: |
-  mkdir ./secret
-  echo "${{ secrets.DEV_SECRET_PROPERTIES }}"  > ./secret/application-dev-secret.properties
-  echo "${{ secrets.PROD_SECRET_PROPERTIES }}" > ./secret/application-prod-secret.properties
-  echo "${{ secrets.TEST_SECRET_PROPERTIES }}" > ./secret/application-test-secret.properties
+run: |
+  mkdir -p ./secret
+  printf "%s" "${{ secrets.DEV_SECRET_PROPERTIES }}"  > ./secret/application-dev-secret.properties
+  printf "%s" "${{ secrets.PROD_SECRET_PROPERTIES }}" > ./secret/application-prod-secret.properties
+  printf "%s" "${{ secrets.TEST_SECRET_PROPERTIES }}" > ./secret/application-test-secret.properties
.github/workflows/dev-ci-cd.yml (1)

26-33: 시크릿 주입 로직 동일 문제 – printf 사용 권장

앞서 언급한 echo 개행 이슈가 dev 파이프라인에도 그대로 존재합니다. 위 CI-PR 파일과 동일한 방식으로 수정해 주세요.

.github/workflows/prod-ci-cd.yml (1)

28-34: 시크릿 파일 주입 – printf/mkdir -p 패턴 재사용 필요

prod 워크플로에도 동일한 개행·디렉터리 문제 존재합니다. 앞서 제시한 패치와 동일하게 적용해 주세요.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 880437a and 759ebc4.

📒 Files selected for processing (3)
  • .github/workflows/ci-pr.yml (1 hunks)
  • .github/workflows/dev-ci-cd.yml (1 hunks)
  • .github/workflows/prod-ci-cd.yml (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: hoonyworld
PR: YAPP-Github/26th-App-Team-1-BE#17
File: .github/workflows/ci-pr.yml:8-9
Timestamp: 2025-07-01T09:50:45.498Z
Learning: hoonyworld 사용자는 Naver 코드 포맷터를 사용하며, 이 포맷터는 YAML 배열의 대괄호 내부에 자동으로 여분의 공백을 추가하는 특성이 있음.
.github/workflows/ci-pr.yml (1)
Learnt from: hoonyworld
PR: YAPP-Github/26th-App-Team-1-BE#17
File: .github/workflows/ci-pr.yml:8-9
Timestamp: 2025-07-01T09:50:45.498Z
Learning: hoonyworld 사용자는 Naver 코드 포맷터를 사용하며, 이 포맷터는 YAML 배열의 대괄호 내부에 자동으로 여분의 공백을 추가하는 특성이 있음.
🪛 YAMLlint (1.37.1)
.github/workflows/dev-ci-cd.yml

[warning] 3-3: truthy value should be one of [false, true]

(truthy)


[error] 5-5: too many spaces inside brackets

(brackets)


[error] 5-5: too many spaces inside brackets

(brackets)

.github/workflows/prod-ci-cd.yml

[warning] 3-3: truthy value should be one of [false, true]

(truthy)


[error] 5-5: too many spaces inside brackets

(brackets)


[error] 5-5: too many spaces inside brackets

(brackets)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build-validation
🔇 Additional comments (3)
.github/workflows/ci-pr.yml (2)

19-20: ubuntu-24.04 런너는 프리뷰 상태 – 안정 버전(ubuntu-latest) 또는 22.04 사용 검토 필요

GitHub Actions의 ubuntu-24.04 이미지는 아직 preview 단계라 일부 액션(특히 도커 관련)에서 예기치 못한 오류가 발생할 수 있습니다.
안정성이 최우선인 CI 파이프라인이라면 runs-on: ubuntu-latest(현재 22.04)로 지정하거나, 최소한 22.04로 고정해 두는 것이 안전합니다.


50-51: --continue 제거 완료 👍

이전 리뷰에서 제안했던 --continue 플래그가 제거돼, 테스트 실패 시 즉시 파이프라인이 중단됩니다. 빠른 피드백 확보에 도움이 됩니다.

.github/workflows/dev-ci-cd.yml (1)

8-10: 동시 실행 제한이 해제돼 있어 중복 배포 가능성 존재

cancel-in-progress: false 로 설정되어 push 가 잦을 때 동일 브랜치에서 여러 파이프라인이 병렬 실행될 수 있습니다. 컨테이너 빌드/배포가 겹치면 레지스트리 태그 충돌이나 서버 롤백 현상이 발생할 수 있으니 필요한지 재검토 바랍니다.

Comment on lines 94 to 96
cd /opt/app
export IMAGE_TAG="${{ needs.build-and-push.outputs.tags }}"
./deploy.sh dev
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

needs.*.outputs.tags 는 개행 포함 가능 → 원격 스크립트 변수 파싱 오류 위험

docker/metadata-action은 여러 태그를 줄바꿈으로 반환합니다. 그대로 export IMAGE_TAG="..."에 넣으면 개행이 변수 값에 포함돼 SSH 스크립트가 오동작할 수 있습니다.

-export IMAGE_TAG="${{ needs.build-and-push.outputs.tags }}"
+export IMAGE_TAG="$(echo "${{ needs.build-and-push.outputs.tags }}" | head -n1)"

최소한 첫 번째 태그만 추출하거나, 스크립트 내에서 IFS 처리로 개행을 제거해 주세요.

📝 Committable suggestion

‼️ 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.

Suggested change
cd /opt/app
export IMAGE_TAG="${{ needs.build-and-push.outputs.tags }}"
./deploy.sh dev
cd /opt/app
export IMAGE_TAG="$(echo "${{ needs.build-and-push.outputs.tags }}" | head -n1)"
./deploy.sh dev
🤖 Prompt for AI Agents
In .github/workflows/dev-ci-cd.yml around lines 94 to 96, the export of
IMAGE_TAG uses needs.build-and-push.outputs.tags which may contain newline
characters causing parsing errors in the remote script. To fix this, modify the
export command to extract only the first tag from the multiline output or
sanitize the variable by removing newlines before exporting it, ensuring the
remote deploy.sh script receives a clean single-line tag value.

Comment on lines 98 to 102
cd /opt/app
export IMAGE_TAG="${{ needs.build-and-push.outputs.tags }}"
export VERSION_TAG="${{ needs.build-and-push.outputs.version }}"
export RELEASE_VERSION="${{ github.event.release.tag_name }}"
./deploy.sh prod
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

다중 태그·버전 문자열 개행 처리 필요

IMAGE_TAG / VERSION_TAG 변수 모두 docker/metadata-action 출력값을 그대로 사용하고 있어 개행 포함 위험이 있습니다. dev 파이프라인과 동일한 방식으로 첫 줄만 추출하거나 개행 제거 로직을 추가해 주세요.

🤖 Prompt for AI Agents
In .github/workflows/prod-ci-cd.yml around lines 98 to 102, the IMAGE_TAG and
VERSION_TAG environment variables are assigned values directly from
docker/metadata-action outputs, which may include newline characters. To fix
this, modify the assignments to extract only the first line or remove any
newline characters from these variables, similar to the approach used in the dev
pipeline, ensuring the tags are clean and do not contain unintended line breaks.

Copy link

@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: 4

♻️ Duplicate comments (2)
.github/workflows/prod-ci-cd.yml (1)

102-103: VERSION_TAG에도 개행 제거 로직 추가 필요
IMAGE_TAGhead -n1로 줄바꿈을 제거했지만 VERSION_TAG는 그대로 사용하고 있어 동일한 개행 포함 위험이 있습니다. 원격 스크립트에서 변수에 개행이 남아 있으면 파싱 오류가 날 수 있습니다.

-            export VERSION_TAG="${{ needs.build-and-push.outputs.version }}"
+            export VERSION_TAG="$(echo "${{ needs.build-and-push.outputs.version }}" | head -n1)"
.github/workflows/dev-ci-cd.yml (1)

98-98: needs.build-and-push.outputs.tags 개행 제거 누락
다중 태그가 줄바꿈으로 반환되면 export IMAGE_TAG="..." 변수에 개행이 포함돼 원격 deploy.sh가 오동작할 가능성이 있습니다. prod 워크플로와 동일하게 첫 줄만 추출해 주세요.

-            export IMAGE_TAG="${{ needs.build-and-push.outputs.tags }}"
+            export IMAGE_TAG="$(echo "${{ needs.build-and-push.outputs.tags }}" | head -n1)"
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 759ebc4 and 037997a.

📒 Files selected for processing (2)
  • .github/workflows/dev-ci-cd.yml (1 hunks)
  • .github/workflows/prod-ci-cd.yml (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: hoonyworld
PR: YAPP-Github/26th-App-Team-1-BE#17
File: .github/workflows/ci-pr.yml:8-9
Timestamp: 2025-07-01T09:50:45.498Z
Learning: hoonyworld 사용자는 Naver 코드 포맷터를 사용하며, 이 포맷터는 YAML 배열의 대괄호 내부에 자동으로 여분의 공백을 추가하는 특성이 있음.
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build-validation

Comment on lines +29 to +36
- name: Inject application-secret.properties from Secrets
run: |
mkdir ./secret
echo "${{ secrets.DEV_SECRET_PROPERTIES }}" > ./secret/application-dev-secret.properties
echo "${{ secrets.PROD_SECRET_PROPERTIES }}" > ./secret/application-prod-secret.properties
echo "${{ secrets.TEST_SECRET_PROPERTIES }}" > ./secret/application-test-secret.properties
chmod 600 ./secret/*
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Secrets 파일 생성 시 echo 보다는 cat <<EOF 패턴 사용 권장
echo는 역슬래시·따옴표 등이 포함된 multiline 시크릿에서 이스케이프 문제를 일으킬 수 있습니다. printf나 here-document로 안전하게 기록하는 방법이 더 견고합니다.
예시:

cat > ./secret/application-dev-secret.properties <<'EOF'
${{ secrets.DEV_SECRET_PROPERTIES }}
EOF
🤖 Prompt for AI Agents
In .github/workflows/prod-ci-cd.yml around lines 29 to 36, replace the echo
commands used to write secret properties files with a here-document pattern
using cat <<'EOF' to safely handle multiline secrets and avoid escape issues.
For each secret file, use cat > filename <<'EOF' followed by the secret variable
and EOF on a new line, ensuring the secrets are written correctly without
interpretation of special characters.

Comment on lines +55 to +63
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=semver,pattern={{version}}
type=raw,value=production-latest
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

이미지 태그에 커밋 SHA 등 고유 식별자 추가 권장
production-latest 만 사용하면 과거 이미지를 덮어쓰게 되어 롤백·캐시 히트 분석이 어려워집니다. docker/metadata-actiontype=sha 또는 type=ref,event=tag 등을 함께 사용해 태그를 다중화하는 방안을 고려해 보세요.

             tags: |
               type=semver,pattern={{version}}
               type=raw,value=production-latest
+              type=sha,format=short
📝 Committable suggestion

‼️ 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.

Suggested change
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=semver,pattern={{version}}
type=raw,value=production-latest
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=semver,pattern={{version}}
type=raw,value=production-latest
type=sha,format=short
🤖 Prompt for AI Agents
In .github/workflows/prod-ci-cd.yml around lines 55 to 63, the Docker image tags
only use 'production-latest', which can overwrite past images and hinder
rollback and cache analysis. Modify the tags input to add unique identifiers
like commit SHA by including 'type=sha' or 'type=ref,event=tag' alongside the
existing tags to enable multiple tags per image.

Comment on lines +50 to +52
- name: Run full Gradle build
run: ./gradlew build --parallel --build-cache

Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Gradle 빌드 옵션 통일 검토
prod 파이프라인에서는 --warning-mode all 등 엄격 모드를 사용하지만 dev에는 빠져 있습니다. 동일한 품질 게이트를 적용해 미리 오류를 발견하도록 하는 것이 좋습니다.

🤖 Prompt for AI Agents
In .github/workflows/dev-ci-cd.yml around lines 50 to 52, the Gradle build
command for the dev pipeline lacks the strict warning mode option used in prod,
such as --warning-mode all. To unify build quality gates and catch errors early,
add the --warning-mode all flag to the ./gradlew build command in the dev
pipeline.

Comment on lines +27 to +33
- name: Inject application-secret.properties from Secrets
run: |
mkdir ./secret
echo "${{ secrets.DEV_SECRET_PROPERTIES }}" > ./secret/application-dev-secret.properties
echo "${{ secrets.PROD_SECRET_PROPERTIES }}" > ./secret/application-prod-secret.properties
echo "${{ secrets.TEST_SECRET_PROPERTIES }}" > ./secret/application-test-secret.properties
chmod 600 ./secret/*
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Dev 파이프라인에 Prod 시크릿 주입 필요성 재검토
개발 환경 배포에서 application-prod-secret.properties는 사용되지 않을 가능성이 높습니다. 불필요한 시크릿 노출 범위를 줄이기 위해 dev 용도에 필요한 파일만 주입하는 것이 안전합니다.

🤖 Prompt for AI Agents
In .github/workflows/dev-ci-cd.yml around lines 27 to 33, the workflow injects
production secret properties into the development pipeline, which is likely
unnecessary and increases secret exposure risk. Remove the line that echoes
PROD_SECRET_PROPERTIES to the secret directory so only development and test
secrets are injected during the dev pipeline run.

Copy link
Member

@minwoo1999 minwoo1999 left a comment

Choose a reason for hiding this comment

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

좋아요 ! flyway는 개발환경에서 하나하나 일일이 하기에는 MVP 속도치기엔 너무 느릴 것 같아서
추후에 MVP끝나고 하는 방향으로 해요! 고생하셨습니다. LGTM

Copy link

@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: 2

♻️ Duplicate comments (1)
infra/src/main/resources/application-persistence.yml (1)

23-25: Flyway 스크립트 위치에 여전히 실제 SQL 파일이 없습니다.

지난 리뷰에서도 동일 지적이 있었습니다. classpath:db/migration, classpath:db/seed 디렉터리에 마이그레이션/시드 SQL이 없으면 애플리케이션 기동 시 Flyway가 빈 migration 상태로 인식합니다.
경로를 실제 스크립트 위치로 수정하거나, 디렉터리를 생성해 스크립트를 배치해주세요.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 037997a and 9074039.

📒 Files selected for processing (1)
  • infra/src/main/resources/application-persistence.yml (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: hoonyworld
PR: YAPP-Github/26th-App-Team-1-BE#17
File: .github/workflows/ci-pr.yml:8-9
Timestamp: 2025-07-01T09:50:45.498Z
Learning: hoonyworld 사용자는 Naver 코드 포맷터를 사용하며, 이 포맷터는 YAML 배열의 대괄호 내부에 자동으로 여분의 공백을 추가하는 특성이 있음.
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build-validation

Comment on lines +12 to +13
show-sql: true
open-in-view: false
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

운영 환경에서 show-sql 로그 노출은 과도합니다.

프로덕션 환경(기본 프로필)에서도 SQL 로그가 모두 출력됩니다.
운영 로그 노이즈·보안 관점에서 show-sql: truehibernate.format_sql 설정은 dev 프로필로 이동하거나 별도 debug(trace) 레벨로 제어하는 편이 안전합니다.

🤖 Prompt for AI Agents
In infra/src/main/resources/application-persistence.yml around lines 12 to 13,
the show-sql setting is enabled for all environments, causing excessive SQL log
output in production. Move the show-sql: true and hibernate.format_sql settings
from the default configuration to the dev profile or configure them to be
enabled only at debug or trace log levels to reduce noise and improve security
in production logs.

Comment on lines +48 to +49
driver-class-name: # Spring Boot의 Testcontainers 자동 설정 기능 동작 -> Testcontainers에 내장된 드라이버 동적 주입

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

driver-class-name에 빈 값이 지정되어 부트 바인딩 오류가 발생합니다.

Testcontainers JDBC URL(jdbc:tc:)을 사용하면 스프링 부트가 자동으로 드라이버 클래스를 주입하므로 속성 자체를 제거해야 합니다.
빈 문자열이 바인딩되면 Cannot load driver class '' 예외로 테스트 프로필이 실패합니다.

-    driver-class-name: # Spring Boot의 Testcontainers 자동 설정 기능 동작 -> Testcontainers에 내장된 드라이버 동적 주입
+    # driver-class-name:  # (제거) Testcontainers JDBC URL이 드라이버를 자동 주입합니다.
🤖 Prompt for AI Agents
In infra/src/main/resources/application-persistence.yml at lines 48 to 49, the
driver-class-name property is set to an empty value causing Spring Boot binding
errors. Remove the driver-class-name property entirely from the configuration
since Spring Boot automatically injects the driver class when using the
Testcontainers JDBC URL (jdbc:tc:). This will prevent the 'Cannot load driver
class ''' exception during test profile initialization.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Jul 2, 2025

Quality Gate Failed Quality Gate failed

Failed conditions
6 Security Hotspots

See analysis details on SonarQube Cloud

Copy link

@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: 1

♻️ Duplicate comments (5)
.github/workflows/dev-ci-cd.yml (3)

27-34: 멀티라인 시크릿은 here-doc 사용, DEV 파이프라인에서 PROD 시크릿 주입 불필요

echo로 멀티라인 시크릿을 기록하면 줄바꿈·이스케이프가 깨져 배포 시 앱이 기동되지 않는 사례가 많습니다. 또한 개발 배포에서 PROD_SECRET_PROPERTIES 파일까지 만들 필요성도 낮아 보입니다.

-echo "${{ secrets.PROD_SECRET_PROPERTIES }}" > ./secret/application-prod-secret.properties
+cat > ./secret/application-dev-secret.properties <<'EOF'
+${{ secrets.DEV_SECRET_PROPERTIES }}
+EOF
+# 필요 시 prod 시크릿 라인은 제거

50-52: --warning-mode all 누락으로 컴파일 경고가 dev 단계에서 숨겨집니다

prod 파이프라인과 동일한 품질 게이트를 위해 dev 빌드에도 strict warning mode를 적용해 주세요.

-run: ./gradlew build --parallel --build-cache
+run: ./gradlew build --parallel --build-cache --warning-mode all

96-99: needs.*.outputs.tags 개행 포함 위험 여전

docker/metadata-action이 여러 태그를 줄바꿈으로 반환합니다. 첫 줄만 추출하거나 개행 제거 후 전달하세요.

-export IMAGE_TAG="${{ needs.build-and-push.outputs.tags }}"
+export IMAGE_TAG="$(echo "${{ needs.build-and-push.outputs.tags }}" | head -n1)"
.github/workflows/prod-ci-cd.yml (2)

29-35: Here-doc 패턴으로 시크릿 기록 + 불필요한 DEV/TEST 시크릿 주입 점검

멀티라인 시크릿은 echo 대신 here-doc이 안전하며, prod 파이프라인에 dev/test 시크릿을 함께 주입할 필요성을 재검토해 주세요.

-echo "${{ secrets.DEV_SECRET_PROPERTIES }}" > ./secret/application-dev-secret.properties
-echo "${{ secrets.TEST_SECRET_PROPERTIES }}" > ./secret/application-test-secret.properties
+cat > ./secret/application-prod-secret.properties <<'EOF'
+${{ secrets.PROD_SECRET_PROPERTIES }}
+EOF

55-63: 고유 태그(예: commit SHA) 추가로 이미지 롤백·캐시 관리 용이화

production-latest 만으로는 이전 이미지를 덮어써 추적이 어려워집니다. SHA 또는 release tag 기반 태그를 함께 생성하는 방안을 다시 고려해 주세요.

           tags: |
             type=semver,pattern={{version}}
             type=raw,value=production-latest
+            type=sha,format=short
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9074039 and 7b742c6.

📒 Files selected for processing (2)
  • .github/workflows/dev-ci-cd.yml (1 hunks)
  • .github/workflows/prod-ci-cd.yml (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: hoonyworld
PR: YAPP-Github/26th-App-Team-1-BE#17
File: .github/workflows/ci-pr.yml:8-9
Timestamp: 2025-07-01T09:50:45.498Z
Learning: hoonyworld 사용자는 Naver 코드 포맷터를 사용하며, 이 포맷터는 YAML 배열의 대괄호 내부에 자동으로 여분의 공백을 추가하는 특성이 있음.
🪛 YAMLlint (1.37.1)
.github/workflows/dev-ci-cd.yml

[warning] 3-3: truthy value should be one of [false, true]

(truthy)


[error] 102-102: trailing spaces

(trailing-spaces)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build-validation

cd ~/deploy
chmod +x ./deploy.sh
./deploy.sh
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

스크립트 끝에 불필요한 공백 존재

YAMLlint trailing-spaces 오류가 발생합니다. 공백을 제거해 lint 통과율을 높여 주세요.

🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 102-102: trailing spaces

(trailing-spaces)

🤖 Prompt for AI Agents
In .github/workflows/dev-ci-cd.yml at line 102, there are unnecessary trailing
spaces at the end of the script line causing a YAMLlint trailing-spaces error.
Remove all trailing whitespace characters from the end of this line to fix the
linting issue and improve lint pass rate.

Copy link
Member

@minwoo1999 minwoo1999 left a comment

Choose a reason for hiding this comment

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

굳굳 고생하셨습니다 :)

@move-hoon move-hoon merged commit d4c1705 into develop Jul 2, 2025
2 of 3 checks passed
@move-hoon move-hoon changed the title chore: CI/CD 세팅 진행중 (테스트 PR) chore: 블루 그린 CI/CD 파이프라인 구축 Jul 3, 2025
@move-hoon move-hoon changed the title chore: 블루 그린 CI/CD 파이프라인 구축 chore: Blue/Green CI/CD 파이프라인 구축 Jul 3, 2025
@move-hoon move-hoon deleted the BOOK-50-chore/#10 branch August 12, 2025 06:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BOOK-50/chore] CI/CD 파이프라인 구축

3 participants