Skip to content

feat: AI 인사이트 및 S3 이미지 업로드 인프라 설정 개선 - #136

Merged
Junhyukkkk merged 6 commits into
developfrom
feat/ai-s3-infra-settings
May 20, 2026
Merged

Junhyukkkk merged 6 commits into
developfrom
feat/ai-s3-infra-settings

Conversation

@Junhyukkkk

@Junhyukkkk Junhyukkkk commented May 20, 2026 •

Copy link
Copy Markdown
Member

📌 관련 이슈

  • closes #

🔍 작업 내용

AI 인사이트 자동 생성(Gemini) 및 S3 이미지 업로드 기능을 추가하고, 외부 서비스 의존성 없이도 로컬/테스트 환경에서 애플리케이션이 정상 실행되도록 조건부 빈 설정을 개선했습니다.

📝 변경 사항

  • S3 이미지 업로드 기능 추가: ImageController, ImageService 및 S3Config 조건부 빈 설정
  • Gemini AI 인사이트 자동 생성: AiInsightService, GeminiConfig 조건부 빈 설정 추가
  • 투표 결과 인사이트 처리 개선: locked 상태 처리 수정, VoteResultResponse 필드명 isMyGroup으로 통일
  • 로컬/테스트 환경 설정: application-local.yml, application-test.yml 업데이트
  • 배포 스크립트 개선: S3, Gemini, Firebase 환경변수 설정 추가

💬 리뷰어에게

  • S3, Gemini API 키가 없는 환경에서도 앱이 정상 실행되는지 조건부 빈 설정을 확인해주세요
  • 투표 결과 인사이트의 locked 상태 처리 로직이 적절한지 검토 부탁드립니다

Summary by CodeRabbit

릴리스 노트

  • New Features

    • 비회원 투표자의 무료 투표권 조회 응답 개선
  • Bug Fixes

    • 투표 인사이트 응답 데이터 구조 정규화
  • Chores

    • 배포 자동화 및 서비스 통합 설정 최적화
    • 외부 서비스 조건부 활성화 체계 개선

Review Change Stack

  - VertexAI 빈에 ConditionalOnProperty 추가
  - AiInsightService에서 Optional<VertexAI>로 null-safe 처리
  - S3Config에 ConditionalOnExpression 적용
  - ImageController의 ConditionalOnBean을 S3Client로 변경
  - locked 상태에서도 insight 데이터 반환하도록 수정
  - 테스트 코드 findAllById로 수정
  - release.yml에 환경변수 추가
  - deploy.sh에 선택적 Docker 옵션 구성
  - application-local.yml에 Firebase, Gemini, S3 설정 추가
  - application-test.yml에 테스트용 더미 설정 추가
@Junhyukkkk Junhyukkkk self-assigned this May 20, 2026
@coderabbitai

coderabbitai Bot commented May 20, 2026 •

Copy link
Copy Markdown

Walkthrough

외부 서비스(Firebase, Gemini, S3) 통합을 위해 배포 구조를 정비하고, 조건부 빈 등록을 도입하며, Optional 타입을 적용하고, 투표 API 응답을 개선했습니다.

Changes

외부 서비스 조건부 등록 및 배포 개선

Layer / File(s) Summary
배포 인프라 환경변수 처리 개선
.github/workflows/release.yml, scripts/deploy.sh
워크플로우는 Firebase 서비스 계정 JSON을 원격에 전달하고 파일로 생성합니다. 배포 스크립트는 DOCKER_OPTS 배열을 사용하여 S3/Gemini 설정 존재 시에만 관련 환경변수와 볼륨 마운트를 조건부로 추가합니다.
Gemini 서비스 조건부 등록 및 Optional 적용
src/main/java/com/ject/vs/ai/config/GeminiConfig.java, src/main/java/com/ject/vs/ai/port/AiInsightService.java, src/main/resources/application-local.yml, src/test/resources/application-test.yml
GeminiConfig는 @ConditionalOnProperty를 사용하여 gemini.enabled=true일 때만 VertexAI 빈을 등록합니다. AiInsightService는 VertexAI를 Optional로 래핑하고 isEmpty() 검사로 안전하게 처리합니다. 설정파일은 환경별 Gemini 활성화 상태를 정의합니다.
S3 서비스 조건부 등록
src/main/java/com/ject/vs/config/S3Config.java, src/main/java/com/ject/vs/image/adapter/web/ImageController.java
S3Config는 ConditionalOnExpression을 사용하여 aws.s3.bucket이 비어있지 않을 때만 활성화됩니다. ImageController의 조건부 활성화를 ImageService에서 S3Client로 변경하여 S3 설정 존재 여부에 직접 의존합니다.
투표 API 응답 구조 개선 및 회원 차별화
src/main/java/com/ject/vs/vote/adapter/web/GuestFreeVoteController.java, src/main/java/com/ject/vs/vote/adapter/web/dto/FreeVotesResponse.java, src/main/java/com/ject/vs/vote/adapter/web/dto/VoteResultResponse.java, src/test/java/com/ject/vs/vote/adapter/web/VoteResultControllerTest.java, src/test/java/com/ject/vs/vote/port/VoteResultQueryServiceTest.java
FreeVotesResponse 필드를 Integer로 변경하여 null 가능성을 표현합니다. GuestFreeVoteController는 회원 식별자를 추가로 받아 회원에 대해 null 응답을 반환합니다. VoteResultResponse는 AgeDistributionResponse의 isHighlighted를 isMyGroup으로 개명하고 locked 시 조건부 처리를 제거합니다.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Firebase 비밀을 도시락에 담고,
Gemini는 선택지로 부드럽게,
S3는 조건부로 춤을 춘다네.
Optional의 품에 안긴 null들,
투표응답 새 옷을 입고 무대 밝히네! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 주요 변경 사항을 명확하고 간결하게 요약합니다. Gemini AI 인사이트 및 S3 이미지 업로드 인프라 설정 개선이라는 핵심 목표를 적절히 반영하고 있습니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/ai-s3-infra-settings

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/release.yml:
- Around line 133-135: Do not create an empty Firebase service account file and
restrict its permissions: check that the environment variable
FIREBASE_SERVICE_ACCOUNT_JSON is non-empty before running mkdir/echo to write
/home/ubuntu/app/secrets/firebase-service-account.json (skip creation if empty),
and after writing the file set restrictive permissions (e.g., chmod 600 or chown
to the deploy user) and then export FIREBASE_SERVICE_ACCOUNT_PATH; reference the
variables/paths FIREBASE_SERVICE_ACCOUNT_JSON, FIREBASE_SERVICE_ACCOUNT_PATH and
the target file /home/ubuntu/app/secrets/firebase-service-account.json when
making the change.

In `@src/main/resources/application-local.yml`:
- Around line 61-72: The local config currently enables external integrations by
default; change gemini.enabled to false (and remove or blank gemini.project-id)
and clear or set aws.s3.* values (aws.s3.bucket, aws.s3.region,
aws.s3.access-key, aws.s3.secret-key) to empty/default placeholders so local
profile does not require external services; ensure these values are only enabled
via environment variables or explicit overrides rather than hardcoded defaults.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2ada9264-d86a-480e-b5c3-a62ba3cec8d1

📥 Commits

Reviewing files that changed from the base of the PR and between 2c8a523 and 463a953.

📒 Files selected for processing (13)
  • .github/workflows/release.yml
  • scripts/deploy.sh
  • src/main/java/com/ject/vs/ai/config/GeminiConfig.java
  • src/main/java/com/ject/vs/ai/port/AiInsightService.java
  • src/main/java/com/ject/vs/config/S3Config.java
  • src/main/java/com/ject/vs/image/adapter/web/ImageController.java
  • src/main/java/com/ject/vs/vote/adapter/web/GuestFreeVoteController.java
  • src/main/java/com/ject/vs/vote/adapter/web/dto/FreeVotesResponse.java
  • src/main/java/com/ject/vs/vote/adapter/web/dto/VoteResultResponse.java
  • src/main/resources/application-local.yml
  • src/test/java/com/ject/vs/vote/adapter/web/VoteResultControllerTest.java
  • src/test/java/com/ject/vs/vote/port/VoteResultQueryServiceTest.java
  • src/test/resources/application-test.yml

Comment on lines +133 to +135
mkdir -p /home/ubuntu/app/secrets
echo "$FIREBASE_SERVICE_ACCOUNT_JSON" > /home/ubuntu/app/secrets/firebase-service-account.json
export FIREBASE_SERVICE_ACCOUNT_PATH=/app/secrets/firebase-service-account.json

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Firebase 시크릿 파일은 비어있는 값일 때 생성하지 말고 권한을 제한해주세요.

Line 133-135은 FIREBASE_SERVICE_ACCOUNT_JSON이 비어도 파일을 생성해 optional 동작을 깨뜨립니다(빈 JSON 파일 마운트). 또한 서비스 계정 파일 권한 제한이 없어 민감정보 노출 위험이 있습니다.

🔧 제안 수정안
-            mkdir -p /home/ubuntu/app/secrets
-            echo "$FIREBASE_SERVICE_ACCOUNT_JSON" > /home/ubuntu/app/secrets/firebase-service-account.json
-            export FIREBASE_SERVICE_ACCOUNT_PATH=/app/secrets/firebase-service-account.json
+            install -d -m 700 /home/ubuntu/app/secrets
+            if [ -n "${FIREBASE_SERVICE_ACCOUNT_JSON:-}" ]; then
+              printf '%s' "$FIREBASE_SERVICE_ACCOUNT_JSON" > /home/ubuntu/app/secrets/firebase-service-account.json
+              chmod 600 /home/ubuntu/app/secrets/firebase-service-account.json
+              export FIREBASE_SERVICE_ACCOUNT_PATH=/app/secrets/firebase-service-account.json
+            else
+              rm -f /home/ubuntu/app/secrets/firebase-service-account.json
+              unset FIREBASE_SERVICE_ACCOUNT_PATH
+            fi
📝 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
mkdir -p /home/ubuntu/app/secrets
echo "$FIREBASE_SERVICE_ACCOUNT_JSON" > /home/ubuntu/app/secrets/firebase-service-account.json
export FIREBASE_SERVICE_ACCOUNT_PATH=/app/secrets/firebase-service-account.json
install -d -m 700 /home/ubuntu/app/secrets
if [ -n "${FIREBASE_SERVICE_ACCOUNT_JSON:-}" ]; then
printf '%s' "$FIREBASE_SERVICE_ACCOUNT_JSON" > /home/ubuntu/app/secrets/firebase-service-account.json
chmod 600 /home/ubuntu/app/secrets/firebase-service-account.json
export FIREBASE_SERVICE_ACCOUNT_PATH=/app/secrets/firebase-service-account.json
else
rm -f /home/ubuntu/app/secrets/firebase-service-account.json
unset FIREBASE_SERVICE_ACCOUNT_PATH
fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml around lines 133 - 135, Do not create an empty
Firebase service account file and restrict its permissions: check that the
environment variable FIREBASE_SERVICE_ACCOUNT_JSON is non-empty before running
mkdir/echo to write /home/ubuntu/app/secrets/firebase-service-account.json (skip
creation if empty), and after writing the file set restrictive permissions
(e.g., chmod 600 or chown to the deploy user) and then export
FIREBASE_SERVICE_ACCOUNT_PATH; reference the variables/paths
FIREBASE_SERVICE_ACCOUNT_JSON, FIREBASE_SERVICE_ACCOUNT_PATH and the target file
/home/ubuntu/app/secrets/firebase-service-account.json when making the change.

Comment on lines +61 to +72
# Gemini AI 인사이트
gemini:
project-id: jectvsserver
enabled: true

# AWS S3 이미지 업로드
aws:
s3:
bucket: ject-vs-images
region: ap-southeast-2
access-key: ${AWS_S3_ACCESS_KEY}
secret-key: ${AWS_S3_SECRET_KEY}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

local 프로필에서 외부 연동을 기본 활성화하면 “의존성 없이 실행” 목표와 충돌합니다.

Line 61-64(gemini.enabled: true)와 Line 67-72(고정 bucket)는 로컬 기본 실행 시 외부 연동을 사실상 강제합니다. 기본값은 비활성/빈 값으로 두고, 필요 시 환경변수로만 켜는 쪽이 안전합니다.

🔧 제안 수정안
 gemini:
-  project-id: jectvsserver
-  enabled: true
+  enabled: ${GEMINI_ENABLED:false}
+  project-id: ${GEMINI_PROJECT_ID:}

 aws:
   s3:
-    bucket: ject-vs-images
-    region: ap-southeast-2
-    access-key: ${AWS_S3_ACCESS_KEY}
-    secret-key: ${AWS_S3_SECRET_KEY}
+    bucket: ${AWS_S3_BUCKET:}
+    region: ${AWS_S3_REGION:ap-southeast-2}
+    access-key: ${AWS_S3_ACCESS_KEY:}
+    secret-key: ${AWS_S3_SECRET_KEY:}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/resources/application-local.yml` around lines 61 - 72, The local
config currently enables external integrations by default; change gemini.enabled
to false (and remove or blank gemini.project-id) and clear or set aws.s3.*
values (aws.s3.bucket, aws.s3.region, aws.s3.access-key, aws.s3.secret-key) to
empty/default placeholders so local profile does not require external services;
ensure these values are only enabled via environment variables or explicit
overrides rather than hardcoded defaults.

@Junhyukkkk
Junhyukkkk merged commit 20f8ddb into develop May 20, 2026
4 checks passed
@Junhyukkkk
Junhyukkkk deleted the feat/ai-s3-infra-settings branch May 20, 2026 17:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant