Conversation
📝 Walkthrough개요mannabom-server 프로젝트의 초기 설정을 구성합니다. Gradle 빌드 시스템, Spring Boot 애플리케이션 구조, Docker 컨테이너화, PostgreSQL 및 Redis 데이터베이스 초기화, GitHub Actions CI/CD 워크플로우, 그리고 관련 설정 파일을 추가합니다. 변경사항
예상 코드 리뷰 노력🎯 4 (복잡함) | ⏱️ ~45분 관련 가능성 있는 PR
제안 리뷰어
시
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 11
🧹 Nitpick comments (7)
mannabom-server/.github/pull_request_template.md (2)
10-14: 테스트 체크리스트에 추가 항목을 고려해볼 수 있습니다.현재 체크리스트는 잘 구성되어 있으나, 다음 항목들도 유용할 수 있습니다:
- [ ] 관련 문서 업데이트(README, API 문서 등)- [ ] Breaking changes 확인(기존 기능에 영향을 주는 변경 사항)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mannabom-server/.github/pull_request_template.md` around lines 10 - 14, Add two additional checklist items under the existing "## 테스트" section: include "- [ ] 관련 문서 업데이트" to ensure README/API docs are updated and "- [ ] Breaking changes 확인" to verify whether changes introduce breaking behavior; update the checklist near the existing items (the "## 테스트" heading and the three checkboxes) so reviewers must confirm documentation updates and breaking-change checks before merging.
22-22: 파일 끝에 빈 줄 추가를 권장합니다.POSIX 표준과 Git 관례에 따라 텍스트 파일은 newline으로 끝나는 것이 좋습니다. 일부 에디터나 Git 도구에서 경고를 표시할 수 있습니다.
📝 제안하는 수정
파일 마지막에 빈 줄을 하나 추가하세요:
## 참고 사항 - +🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mannabom-server/.github/pull_request_template.md` at line 22, Add a single trailing newline to the end of the pull request template file so the file ends with a blank line; open mannabom-server/.github/pull_request_template.md and append one newline character at the end of the file (ensure the file terminates with '\n') to comply with POSIX/Git conventions.mannabom-server/Dockerfile (1)
5-6:COPY build/libs/*.jar는 다중 JAR 산출 시 빌드가 불안정할 수 있습니다.배포 대상 JAR를 명시적으로 지정하는 편이 안전합니다.
🔧 제안 수정
-ARG JAR_FILE=build/libs/*.jar +ARG JAR_FILE=build/libs/mannabom-server.jar COPY ${JAR_FILE} app.jar🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mannabom-server/Dockerfile` around lines 5 - 6, The Dockerfile currently uses a glob ARG and COPY (${JAR_FILE} / app.jar), which is unstable when multiple JARs exist; update the ARG JAR_FILE and COPY to reference the exact artifact name (e.g., set ARG JAR_FILE=build/libs/your-artifact-name.jar and keep COPY ${JAR_FILE} app.jar) or require passing the precise --build-arg JAR_FILE=<artifact> during docker build so the intended JAR is unambiguous; ensure the change touches the ARG JAR_FILE and the COPY ${JAR_FILE} app.jar lines.mannabom-server/src/main/resources/db/migration/V3__add_request_table_and_extra_photo_table_and_rating_table.sql (1)
46-77: 타임스탬프 컬럼의 일관성을 검토해 주세요.
like_request와message_request테이블은created_at NOT NULL을 사용하지만,profile_extra_photo_unlock과profile_rating테이블은created_at이 nullable입니다.도메인 요구사항에 따른 의도적인 설계라면 문제없지만, 일관성을 위해 모든 테이블에서
created_at NOT NULL을 적용하는 것을 권장합니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mannabom-server/src/main/resources/db/migration/V3__add_request_table_and_extra_photo_table_and_rating_table.sql` around lines 46 - 77, Update the two CREATE TABLE statements so their timestamp columns follow the same not-null policy as other tables: change profile_extra_photo_unlock.created_at and profile_rating.created_at to be declared TIMESTAMP NOT NULL (and optionally make updated_at NOT NULL as well if your schema requires it) so the tables profile_extra_photo_unlock and profile_rating match the non-null created_at behavior of like_request and message_request.mannabom-server/docker-compose.prod.yml (2)
2-17: 운영 안정성을 위해restart정책과 헬스체크 추가를 권장합니다.
mannabom-server서비스에 재시작 정책이 없어 컨테이너 충돌 시 자동 복구되지 않습니다. 또한depends_on만으로는 Redis가 실제로 요청을 받을 준비가 되었는지 보장하지 않습니다.♻️ 제안된 개선사항
mannabom-server: image: ${ECR_REGISTRY_URI}:${IMAGE_TAG} container_name: mannabom-server environment: - SPRING_PROFILES_ACTIVE=prod env_file: - .env ports: - 8080:8080 + restart: unless-stopped depends_on: - - redis + redis: + condition: service_healthy networks: - mannabom-net volumes: - /opt/mannabom/firebase:/opt/mannabom/firebase + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"] + interval: 30s + timeout: 10s + retries: 3🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mannabom-server/docker-compose.prod.yml` around lines 2 - 17, 서비스 블록 mannabom-server에 restart 정책과 헬스체크를 추가하여 컨테이너 충돌 시 자동 재시작과 상태 기반 의존성을 보장하십시오: mannabom-server에 restart (예: "always" 또는 "unless-stopped")를 설정하고 healthcheck를 추가하여 HTTP/TCP 또는 커맨드 기반 상태 확인을 수행하도록 구성하고, depends_on 항목을 condition: service_healthy로 전환하거나 redis에 healthcheck를 추가하여 Redis가 실제로 준비되었을 때만 mannabom-server가 시작되게 하세요; 관련 키: mannabom-server, restart, healthcheck, depends_on, redis, condition: service_healthy.
19-26: 프로덕션 환경에서 Redis 인증 설정을 권장합니다.현재 Redis가 인증 없이 구성되어 있습니다. 네트워크가 격리되어 있더라도 프로덕션 환경에서는 보안을 위해 비밀번호를 설정하는 것이 좋습니다.
🔒 제안된 개선사항
redis: image: redis:alpine container_name: redis + command: redis-server --requirepass ${REDIS_PASSWORD} volumes: - redis_data:/data restart: unless-stopped networks: - mannabom-net + healthcheck: + test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"] + interval: 10s + timeout: 5s + retries: 3
.env파일에REDIS_PASSWORD를 추가하고,application-prod.yml의 Redis 설정에도 비밀번호를 반영해야 합니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mannabom-server/docker-compose.prod.yml` around lines 19 - 26, Add Redis authentication by requiring a password for the redis service: add a REDIS_PASSWORD variable to your environment (.env) and update the redis service in docker-compose.prod.yml to pass that password into the container (e.g., via environment or command/entrypoint that sets Redis' requirepass). Also update your application-prod.yml Redis client configuration to use REDIS_PASSWORD for authentication so the app connects with the password. Ensure the redis service name "redis", the env var "REDIS_PASSWORD", and the Redis config in application-prod.yml are all updated consistently.mannabom-server/src/main/resources/application.yaml (1)
5-10: 베이스 설정 파일에 로컬 전용 값이 너무 많이 들어가 있습니다.
application.yaml은 모든 프로필의 공통 베이스인데, 여기서 로컬 DB/Redis/Mail/File 경로와 개발용 JWT/Kakao fallback을 함께 들고 있으면 프로필 누락 시 그대로 적용됩니다. 이미application-local.yml를 분리해 둔 만큼, 공통값만 남기고 환경별 값은 각 프로필 파일로 옮기는 편이 안전합니다.Also applies to: 33-57, 67-95
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mannabom-server/src/main/resources/application.yaml` around lines 5 - 10, The base application.yaml currently contains environment-specific values (e.g., datasource.url, datasource.username, datasource.password, datasource.driver-class-name and similar Redis, mail, file path, JWT and Kakao fallback settings) that should live in profile-specific files; remove those local/dev values from application.yaml leaving only generic/common keys and move the local DB/Redis/Mail/File paths and development JWT/Kakao fallback settings into application-local.yml (and other profile files as needed), ensuring application.yaml contains defaults or placeholders only and reference to profile-specific properties remains via the existing property names (e.g., datasource.*, redis.*, mail.*, jwt.*, kakao.*) so code (config classes or `@Value` usages) continues to load them per active Spring profile.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@mannabom-server/.gitignore`:
- Around line 47-48: The .gitignore entries "mannabom-server/.env*" and
"mannabom-server/src/.env*" are wrong for a .gitignore located inside the
mannabom-server directory; update them to use repository-relative patterns so
local .env files are actually ignored—for example replace those two lines with
".env*" and "src/.env*" (or use "/.env*" and "/src/.env*" if you prefer explicit
root-anchored ignores) so the .env files in the project root and src are
reliably excluded.
In `@mannabom-server/build.gradle`:
- Around line 30-33: The JJWT dependencies use mixed versions (jjwt-api and
jjwt-jackson at 0.12.3 while jjwt-impl is 0.12.6); update the dependency
declarations so jjwt-api, jjwt-impl, and jjwt-jackson all use the exact same
version (e.g., change jjwt-api and jjwt-jackson to 0.12.6 to match jjwt-impl),
then rebuild and run tests to ensure no runtime NoSuchMethodError or
serialization mismatches; check the dependency lines for jjwt-api, jjwt-impl,
and jjwt-jackson and make the version uniform.
In `@mannabom-server/Dockerfile`:
- Around line 1-11: The Dockerfile currently runs the container as root
(ENTRYPOINT ["java","-jar","app.jar"]); create a non-root user and group (e.g.,
appuser), chown the working directory and app.jar to that user, and switch to it
via USER before the ENTRYPOINT so the JVM runs unprivileged; update referenced
Dockerfile steps around WORKDIR, COPY, and ENTRYPOINT to add user/group
creation, chown for app.jar, and the USER instruction.
In `@mannabom-server/src/main/resources/application-prod.yml`:
- Around line 93-95: 현재 application-prod.yml의 meeting.cursor.secret에 예측 가능한
기본값(local-dev-key-do-not-user-in-prod)이 설정되어 있어 운영에서 환경변수가 없을 때 취약해집니다; 수정 방법은
기본값을 제거하고 secret을 환경변수로 강제하도록 설정하세요 — 즉, 변경 대상은 키 meeting.cursor.secret과 환경변수 이름
MEETING_SECRET_KEY이며 파일 값을 ${MEETING_SECRET_KEY}로 바꾸고(기본값 제거) 애플리케이션 시작 시 해당 변수
누락 시 실패하도록(예: 스프링 프로퍼티로 기본값 없이 사용하거나 추가적인 프로퍼티 검증/빈 초기화 검증을 추가) 구성하세요.
- Around line 58-65: The production config under the kakao block currently
enables development overrides (development.skip-age-verification: true and dummy
default-birth-year/default-gender) which bypass age checks and inject fake
profiles in prod; turn off or remove these development keys for production by
deleting or moving the development subtree (including skip-age-verification,
default-birth-year, default-gender) into a non-prod/dev-only config and ensure
production uses only kakao.client-id and kakao.redirect-uri so age verification
runs normally in production.
- Around line 19-22: The Flyway config sets baseline-on-migrate: true which can
skip V1 and cause failures if migrations V2+ assume V1 objects; update the
flyway configuration in the application YAML (the flyway block containing
enabled, locations, baseline-on-migrate) to remove or set baseline-on-migrate to
false, and instead handle baselining explicitly via a controlled migration or a
documented manual baseline step so that V1 migrations always run in fresh
schemas and partially-populated schemas are treated safely.
In `@mannabom-server/src/main/resources/application.yaml`:
- Around line 13-20: The Hibernate properties are placed under the wrong path
and one key is duplicated; move default_batch_fetch_size into the
spring.jpa.properties.hibernate namespace and rename/remove the duplicated
hibernate.hibernate.use_sql_comments key so the setting becomes
spring.jpa.properties.hibernate.use_sql_comments (or remove the extra
"hibernate." prefix) to ensure both default_batch_fetch_size and
use_sql_comments live under spring.jpa.properties.hibernate.* and are applied by
Spring Boot 3.5.
In `@mannabom-server/src/main/resources/db/migration/V1__baseline.sql`:
- Around line 7-17: Add a foreign key constraint on public.device_token.user_id
to ensure it references public.users(user_id) and prevent orphan tokens; modify
the V1__baseline.sql by adding a CONSTRAINT (e.g., fk_device_token_user)
referencing public.users(user_id) with an appropriate ON DELETE behavior
(recommend ON DELETE CASCADE to remove tokens when a user is deleted, or ON
DELETE SET NULL if you prefer keeping tokens) so look for table device_token and
column user_id and add the FK constraint alongside the existing primary
key/unique definitions.
In
`@mannabom-server/src/main/resources/db/migration/V2__add_meeting_and_chat.sql`:
- Around line 90-110: The column chat_members.last_read_message_id uses int4
while chat_messages.id is int8; change chat_members.last_read_message_id to int8
(bigint) to match chat_messages.id and add a nullable foreign key constraint
(e.g., fk_chat_members_last_read_message) referencing public.chat_messages(id)
so the read-pointer aligns with the message PK and can enforce referential
integrity; ensure nullability remains allowed if no read message exists.
In
`@mannabom-server/src/main/resources/db/migration/V7__add_source_to_message_request.sql`:
- Around line 1-2: 현재 마이그레이션(V7__add_source_to_message_request.sql)의 ALTER TABLE
message_request ADD COLUMN source 구문이 비멱등이라 이미 컬럼이 있는 DB에서 실패할 수 있으니, 마이그레이션을 컬럼
존재 여부를 확인한 후에만 컬럼을 추가하도록 수정하세요; 구체적으로 V7__add_source_to_message_request.sql에서
컬럼이 없을 때만 추가되도록 하는 방식(예: DB가 지원하면 ALTER TABLE ... ADD COLUMN IF NOT EXISTS를
사용하거나, 정보 스키마를 조회해 존재 여부를 확인하고 조건부로 ALTER를 실행하는 로직으로 변경)으로 바꿔 배포 실패를 방지하세요.
In
`@mannabom-server/src/main/resources/db/migration/V8__migrate_profile_data_and_add_column_chat_room_table.sql`:
- Around line 3-21: The migration drops original columns immediately after a
best-effort UPDATE, risking data loss; modify the migration to (1) preserve
source data by copying public.profile.university, region_sido, region_sigungu
into a backup table or new backup columns before any DELETE/DROP, (2) add a
verification step that compares how many rows were successfully migrated to
university_id and region_id (using selectors on public.profile.university_id and
region_id) and reports or fails the migration if there are any unmatched rows,
and (3) only perform ALTER TABLE DROP COLUMN for university, region_sido,
region_sigungu after successful verification (or provide a safe manual
remediation path), referencing the UPDATE statements on public.profile (SET
university_id = u.university_id ... FROM public.university u) and (SET region_id
= r.sigungu_code ... FROM public.regions r) and the ALTER TABLE DROP COLUMN
statements so you can locate and change them.
---
Nitpick comments:
In `@mannabom-server/.github/pull_request_template.md`:
- Around line 10-14: Add two additional checklist items under the existing "##
테스트" section: include "- [ ] 관련 문서 업데이트" to ensure README/API docs are updated
and "- [ ] Breaking changes 확인" to verify whether changes introduce breaking
behavior; update the checklist near the existing items (the "## 테스트" heading and
the three checkboxes) so reviewers must confirm documentation updates and
breaking-change checks before merging.
- Line 22: Add a single trailing newline to the end of the pull request template
file so the file ends with a blank line; open
mannabom-server/.github/pull_request_template.md and append one newline
character at the end of the file (ensure the file terminates with '\n') to
comply with POSIX/Git conventions.
In `@mannabom-server/docker-compose.prod.yml`:
- Around line 2-17: 서비스 블록 mannabom-server에 restart 정책과 헬스체크를 추가하여 컨테이너 충돌 시 자동
재시작과 상태 기반 의존성을 보장하십시오: mannabom-server에 restart (예: "always" 또는
"unless-stopped")를 설정하고 healthcheck를 추가하여 HTTP/TCP 또는 커맨드 기반 상태 확인을 수행하도록 구성하고,
depends_on 항목을 condition: service_healthy로 전환하거나 redis에 healthcheck를 추가하여 Redis가
실제로 준비되었을 때만 mannabom-server가 시작되게 하세요; 관련 키: mannabom-server, restart,
healthcheck, depends_on, redis, condition: service_healthy.
- Around line 19-26: Add Redis authentication by requiring a password for the
redis service: add a REDIS_PASSWORD variable to your environment (.env) and
update the redis service in docker-compose.prod.yml to pass that password into
the container (e.g., via environment or command/entrypoint that sets Redis'
requirepass). Also update your application-prod.yml Redis client configuration
to use REDIS_PASSWORD for authentication so the app connects with the password.
Ensure the redis service name "redis", the env var "REDIS_PASSWORD", and the
Redis config in application-prod.yml are all updated consistently.
In `@mannabom-server/Dockerfile`:
- Around line 5-6: The Dockerfile currently uses a glob ARG and COPY
(${JAR_FILE} / app.jar), which is unstable when multiple JARs exist; update the
ARG JAR_FILE and COPY to reference the exact artifact name (e.g., set ARG
JAR_FILE=build/libs/your-artifact-name.jar and keep COPY ${JAR_FILE} app.jar) or
require passing the precise --build-arg JAR_FILE=<artifact> during docker build
so the intended JAR is unambiguous; ensure the change touches the ARG JAR_FILE
and the COPY ${JAR_FILE} app.jar lines.
In `@mannabom-server/src/main/resources/application.yaml`:
- Around line 5-10: The base application.yaml currently contains
environment-specific values (e.g., datasource.url, datasource.username,
datasource.password, datasource.driver-class-name and similar Redis, mail, file
path, JWT and Kakao fallback settings) that should live in profile-specific
files; remove those local/dev values from application.yaml leaving only
generic/common keys and move the local DB/Redis/Mail/File paths and development
JWT/Kakao fallback settings into application-local.yml (and other profile files
as needed), ensuring application.yaml contains defaults or placeholders only and
reference to profile-specific properties remains via the existing property names
(e.g., datasource.*, redis.*, mail.*, jwt.*, kakao.*) so code (config classes or
`@Value` usages) continues to load them per active Spring profile.
In
`@mannabom-server/src/main/resources/db/migration/V3__add_request_table_and_extra_photo_table_and_rating_table.sql`:
- Around line 46-77: Update the two CREATE TABLE statements so their timestamp
columns follow the same not-null policy as other tables: change
profile_extra_photo_unlock.created_at and profile_rating.created_at to be
declared TIMESTAMP NOT NULL (and optionally make updated_at NOT NULL as well if
your schema requires it) so the tables profile_extra_photo_unlock and
profile_rating match the non-null created_at behavior of like_request and
message_request.
🪄 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: c410a967-d772-4c70-89a8-12c7b8c4dd8c
⛔ Files ignored due to path filters (3)
mannabom-server/gradle/wrapper/gradle-wrapper.jaris excluded by!**/*.jarmannabom-server/src/main/resources/data/regions.csvis excluded by!**/*.csvmannabom-server/src/main/resources/data/regions_original.csvis excluded by!**/*.csv
📒 Files selected for processing (23)
mannabom-server/.gitattributesmannabom-server/.github/pull_request_template.mdmannabom-server/.gitignoremannabom-server/Dockerfilemannabom-server/build.gradlemannabom-server/docker-compose.local.ymlmannabom-server/docker-compose.prod.ymlmannabom-server/gradle/wrapper/gradle-wrapper.propertiesmannabom-server/gradlewmannabom-server/gradlew.batmannabom-server/settings.gradlemannabom-server/src/main/java/com/mannabom/mannabom_server/MannabomServerApplication.javamannabom-server/src/main/resources/application-prod.ymlmannabom-server/src/main/resources/application.yamlmannabom-server/src/main/resources/db/migration/V1__baseline.sqlmannabom-server/src/main/resources/db/migration/V2__add_meeting_and_chat.sqlmannabom-server/src/main/resources/db/migration/V3__add_request_table_and_extra_photo_table_and_rating_table.sqlmannabom-server/src/main/resources/db/migration/V4__add_reject_reason_to_like_request.sqlmannabom-server/src/main/resources/db/migration/V5__add_reject_reason_to_message_request.sqlmannabom-server/src/main/resources/db/migration/V6__add_source_to_like_request.sqlmannabom-server/src/main/resources/db/migration/V7__add_source_to_message_request.sqlmannabom-server/src/main/resources/db/migration/V8__migrate_profile_data_and_add_column_chat_room_table.sqlmannabom-server/src/test/java/com/mannabom/mannabom_server/MannabomServerApplicationTests.java
| FROM eclipse-temurin:17-jre-alpine | ||
|
|
||
| WORKDIR /app | ||
|
|
||
| ARG JAR_FILE=build/libs/*.jar | ||
| COPY ${JAR_FILE} app.jar | ||
|
|
||
| ENV TZ=Asia/Seoul | ||
| RUN apk add --no-cache tzdata | ||
|
|
||
| ENTRYPOINT ["java", "-jar","app.jar"] No newline at end of file |
There was a problem hiding this comment.
컨테이너가 root 사용자로 실행됩니다.
런타임은 non-root로 강제하는 것이 안전합니다.
🔧 제안 수정
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar
ENV TZ=Asia/Seoul
RUN apk add --no-cache tzdata
+RUN addgroup -S app && adduser -S app -G app
+RUN chown -R app:app /app
+USER app
ENTRYPOINT ["java", "-jar","app.jar"]📝 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.
| FROM eclipse-temurin:17-jre-alpine | |
| WORKDIR /app | |
| ARG JAR_FILE=build/libs/*.jar | |
| COPY ${JAR_FILE} app.jar | |
| ENV TZ=Asia/Seoul | |
| RUN apk add --no-cache tzdata | |
| ENTRYPOINT ["java", "-jar","app.jar"] | |
| FROM eclipse-temurin:17-jre-alpine | |
| WORKDIR /app | |
| ARG JAR_FILE=build/libs/*.jar | |
| COPY ${JAR_FILE} app.jar | |
| ENV TZ=Asia/Seoul | |
| RUN apk add --no-cache tzdata | |
| RUN addgroup -S app && adduser -S app -G app | |
| RUN chown -R app:app /app | |
| USER app | |
| ENTRYPOINT ["java", "-jar","app.jar"] |
🧰 Tools
🪛 Trivy (0.69.3)
[error] 1-1: Image user should not be 'root'
Specify at least 1 USER command in Dockerfile with non-root user as argument
Rule: DS-0002
(IaC/Dockerfile)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@mannabom-server/Dockerfile` around lines 1 - 11, The Dockerfile currently
runs the container as root (ENTRYPOINT ["java","-jar","app.jar"]); create a
non-root user and group (e.g., appuser), chown the working directory and app.jar
to that user, and switch to it via USER before the ENTRYPOINT so the JVM runs
unprivileged; update referenced Dockerfile steps around WORKDIR, COPY, and
ENTRYPOINT to add user/group creation, chown for app.jar, and the USER
instruction.
| flyway: | ||
| enabled: true | ||
| locations: classpath:db/migration | ||
| baseline-on-migrate: true |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Flyway에서 baselineOnMigrate=true일 때, non-empty 스키마에 flyway_schema_history가 없으면 V1__baseline.sql은 실제로 실행되나요? 아니면 baseline version으로만 마킹하고 V2부터 진행하나요?
💡 Result:
baselineOnMigrate=true이고 (1) 스키마가 non-empty인데 (2) flyway_schema_history가 없으면, migrate 실행 시 Flyway는 먼저 **baseline을 수행(= 스키마 히스토리 테이블 생성 + baseline row 기록)**하고, 그 다음 baseline version보다 큰 마이그레이션부터 적용합니다. 즉, 보통 baselineVersion 기본값이 1이면:
V1__baseline.sql은 실제로 실행되지 않습니다.- DB에는
flyway_schema_history에 type=BASELINE, version=1 같은 식으로 “baseline으로 마킹”만 되고 - 실제 마이그레이션은
V2...부터 진행됩니다. (documentation.red-gate.com)
추가로, 파일로 “baseline 스크립트”를 두고 실행시키는 방식(보통 B... prefix의 baseline migration)은 baselineOnMigrate만으로 자동 실행되는 개념이 아니라, 별도 프로세스/콜백 등으로 명시적으로 구성해야 한다는 점도 문서에서 언급됩니다. (documentation.red-gate.com)
Citations:
- 1: https://documentation.red-gate.com/fd/baselines-273973441.html?utm_source=openai
- 2: https://documentation.red-gate.com/fd/baselines-273973441.html?utm_source=openai
baseline-on-migrate: true은 이번 마이그레이션 구성과 충돌할 수 있습니다.
운영 DB가 비어 있지 않지만 flyway_schema_history만 없는 상태에서 마이그레이션을 실행하면, Flyway는 V1__baseline.sql을 실행하지 않고 baseline으로 표시한 뒤 V2부터 진행합니다. 이번 PR에서 V2+ 마이그레이션들이 V1의 객체 존재를 가정한다면, 부분적으로 채워진 스키마에서 배포가 중간에 멈출 수 있습니다.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@mannabom-server/src/main/resources/application-prod.yml` around lines 19 -
22, The Flyway config sets baseline-on-migrate: true which can skip V1 and cause
failures if migrations V2+ assume V1 objects; update the flyway configuration in
the application YAML (the flyway block containing enabled, locations,
baseline-on-migrate) to remove or set baseline-on-migrate to false, and instead
handle baselining explicitly via a controlled migration or a documented manual
baseline step so that V1 migrations always run in fresh schemas and
partially-populated schemas are treated safely.
| # 카카오 OAuth 설정 (프로덕션) | ||
| kakao: | ||
| client-id: ${KAKAO_CLIENT_ID} | ||
| redirect-uri: ${KAKAO_REDIRECT_URI:https://your-domain.com/api/auth/login/kakao} | ||
| development: | ||
| skip-age-verification: true # 이거 아직 카카오 디벨로퍼 준비 안되서 | ||
| default-birth-year: 2000 | ||
| default-gender: "MALE" |
There was a problem hiding this comment.
운영 프로필에서 연령 검증 우회가 켜져 있습니다.
Line 63의 skip-age-verification: true와 Line 64-65의 더미값은 운영 가입 데이터를 검증 없이 통과시키거나 가짜 프로필 값으로 채우게 만들 수 있습니다. prod 설정에서는 우회를 꺼야 합니다.
🔧 제안 수정
kakao:
client-id: ${KAKAO_CLIENT_ID}
redirect-uri: ${KAKAO_REDIRECT_URI:https://your-domain.com/api/auth/login/kakao}
development:
- skip-age-verification: true # 이거 아직 카카오 디벨로퍼 준비 안되서
- default-birth-year: 2000
- default-gender: "MALE"
+ skip-age-verification: false📝 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.
| # 카카오 OAuth 설정 (프로덕션) | |
| kakao: | |
| client-id: ${KAKAO_CLIENT_ID} | |
| redirect-uri: ${KAKAO_REDIRECT_URI:https://your-domain.com/api/auth/login/kakao} | |
| development: | |
| skip-age-verification: true # 이거 아직 카카오 디벨로퍼 준비 안되서 | |
| default-birth-year: 2000 | |
| default-gender: "MALE" | |
| # 카카오 OAuth 설정 (프로덕션) | |
| kakao: | |
| client-id: ${KAKAO_CLIENT_ID} | |
| redirect-uri: ${KAKAO_REDIRECT_URI:https://your-domain.com/api/auth/login/kakao} | |
| development: | |
| skip-age-verification: false |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@mannabom-server/src/main/resources/application-prod.yml` around lines 58 -
65, The production config under the kakao block currently enables development
overrides (development.skip-age-verification: true and dummy
default-birth-year/default-gender) which bypass age checks and inject fake
profiles in prod; turn off or remove these development keys for production by
deleting or moving the development subtree (including skip-age-verification,
default-birth-year, default-gender) into a non-prod/dev-only config and ensure
production uses only kakao.client-id and kakao.redirect-uri so age verification
runs normally in production.
| CREATE TABLE public.device_token ( | ||
| id int8 GENERATED BY DEFAULT AS IDENTITY( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1 NO CYCLE) NOT NULL, | ||
| active bool NOT NULL, | ||
| last_seen_at timestamptz(6) NULL, | ||
| "token" varchar(255) NOT NULL, | ||
| user_id int8 NULL, | ||
| CONSTRAINT device_token_pkey PRIMARY KEY (id), | ||
| CONSTRAINT idx_device_token_token UNIQUE (token) | ||
| ); | ||
| CREATE INDEX idx_device_token_active ON public.device_token USING btree (active); | ||
| CREATE INDEX idx_device_token_user ON public.device_token USING btree (user_id); |
There was a problem hiding this comment.
device_token.user_id에 FK가 빠져 있습니다.
public.device_token.user_id는 인덱스만 있고 public.users(user_id)를 보장하지 않습니다. 사용자 삭제/정리 이후 고아 토큰이 남으면 푸시 대상 조회가 틀어질 수 있습니다.
🔧 제안 수정
CREATE TABLE public.refresh_tokens (
token_id int8 GENERATED BY DEFAULT AS IDENTITY( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1 NO CYCLE) NOT NULL,
created_at timestamp(6) NOT NULL,
updated_at timestamp(6) NOT NULL,
expires_at timestamp(6) NOT NULL,
refresh_token varchar(512) NOT NULL,
user_id int8 NOT NULL,
CONSTRAINT refresh_tokens_pkey PRIMARY KEY (token_id),
CONSTRAINT uk1yihy5j142kjit22kgccjixro UNIQUE (refresh_token),
CONSTRAINT uk7tdcd6ab5wsgoudnvj7xf1b7l UNIQUE (user_id),
CONSTRAINT fk1lih5y2npsf8u5o3vhdb9y0os FOREIGN KEY (user_id) REFERENCES public.users(user_id)
);
+
+ALTER TABLE public.device_token
+ ADD CONSTRAINT fk_device_token_user
+ FOREIGN KEY (user_id) REFERENCES public.users(user_id);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@mannabom-server/src/main/resources/db/migration/V1__baseline.sql` around
lines 7 - 17, Add a foreign key constraint on public.device_token.user_id to
ensure it references public.users(user_id) and prevent orphan tokens; modify the
V1__baseline.sql by adding a CONSTRAINT (e.g., fk_device_token_user) referencing
public.users(user_id) with an appropriate ON DELETE behavior (recommend ON
DELETE CASCADE to remove tokens when a user is deleted, or ON DELETE SET NULL if
you prefer keeping tokens) so look for table device_token and column user_id and
add the FK constraint alongside the existing primary key/unique definitions.
| CREATE TABLE public.chat_members ( | ||
| id int8 GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, | ||
| joined_at timestamptz(6) NULL, | ||
| last_read_message_id int4 NULL, | ||
| room_id int8 NOT NULL, | ||
| user_id int8 NOT NULL, | ||
| CONSTRAINT fk_chat_members_room FOREIGN KEY (room_id) REFERENCES public.chat_rooms(id), | ||
| CONSTRAINT fk_chat_members_user FOREIGN KEY (user_id) REFERENCES public.users(user_id) | ||
| ); | ||
|
|
||
| CREATE TABLE public.chat_messages ( | ||
| id int8 GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, | ||
| created_at timestamptz(6) NOT NULL, | ||
| updated_at timestamptz(6) NOT NULL, | ||
| "content" varchar(255) NULL, | ||
| "type" int2 NULL, | ||
| room_id int8 NULL, | ||
| sender_user_id int8 NULL, | ||
| CONSTRAINT fk_chat_msg_room FOREIGN KEY (room_id) REFERENCES public.chat_rooms(id), | ||
| CONSTRAINT fk_chat_msg_user FOREIGN KEY (sender_user_id) REFERENCES public.users(user_id) | ||
| ); |
There was a problem hiding this comment.
last_read_message_id 타입이 실제 메시지 PK와 다릅니다.
Line 93은 int4인데, 같은 파일 Line 101의 public.chat_messages.id는 int8입니다. 읽음 포인터를 메시지 PK로 쓰면 범위 초과 가능성이 있고, 나중에 FK를 붙이기도 어렵습니다.
🔧 제안 수정
CREATE TABLE public.chat_members (
id int8 GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
joined_at timestamptz(6) NULL,
- last_read_message_id int4 NULL,
+ last_read_message_id int8 NULL,
room_id int8 NOT NULL,
user_id int8 NOT NULL,
CONSTRAINT fk_chat_members_room FOREIGN KEY (room_id) REFERENCES public.chat_rooms(id),
CONSTRAINT fk_chat_members_user FOREIGN KEY (user_id) REFERENCES public.users(user_id)
);📝 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.
| CREATE TABLE public.chat_members ( | |
| id int8 GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, | |
| joined_at timestamptz(6) NULL, | |
| last_read_message_id int4 NULL, | |
| room_id int8 NOT NULL, | |
| user_id int8 NOT NULL, | |
| CONSTRAINT fk_chat_members_room FOREIGN KEY (room_id) REFERENCES public.chat_rooms(id), | |
| CONSTRAINT fk_chat_members_user FOREIGN KEY (user_id) REFERENCES public.users(user_id) | |
| ); | |
| CREATE TABLE public.chat_messages ( | |
| id int8 GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, | |
| created_at timestamptz(6) NOT NULL, | |
| updated_at timestamptz(6) NOT NULL, | |
| "content" varchar(255) NULL, | |
| "type" int2 NULL, | |
| room_id int8 NULL, | |
| sender_user_id int8 NULL, | |
| CONSTRAINT fk_chat_msg_room FOREIGN KEY (room_id) REFERENCES public.chat_rooms(id), | |
| CONSTRAINT fk_chat_msg_user FOREIGN KEY (sender_user_id) REFERENCES public.users(user_id) | |
| ); | |
| CREATE TABLE public.chat_members ( | |
| id int8 GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, | |
| joined_at timestamptz(6) NULL, | |
| last_read_message_id int8 NULL, | |
| room_id int8 NOT NULL, | |
| user_id int8 NOT NULL, | |
| CONSTRAINT fk_chat_members_room FOREIGN KEY (room_id) REFERENCES public.chat_rooms(id), | |
| CONSTRAINT fk_chat_members_user FOREIGN KEY (user_id) REFERENCES public.users(user_id) | |
| ); | |
| CREATE TABLE public.chat_messages ( | |
| id int8 GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, | |
| created_at timestamptz(6) NOT NULL, | |
| updated_at timestamptz(6) NOT NULL, | |
| "content" varchar(255) NULL, | |
| "type" int2 NULL, | |
| room_id int8 NULL, | |
| sender_user_id int8 NULL, | |
| CONSTRAINT fk_chat_msg_room FOREIGN KEY (room_id) REFERENCES public.chat_rooms(id), | |
| CONSTRAINT fk_chat_msg_user FOREIGN KEY (sender_user_id) REFERENCES public.users(user_id) | |
| ); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@mannabom-server/src/main/resources/db/migration/V2__add_meeting_and_chat.sql`
around lines 90 - 110, The column chat_members.last_read_message_id uses int4
while chat_messages.id is int8; change chat_members.last_read_message_id to int8
(bigint) to match chat_messages.id and add a nullable foreign key constraint
(e.g., fk_chat_members_last_read_message) referencing public.chat_messages(id)
so the read-pointer aligns with the message PK and can enforce referential
integrity; ensure nullability remains allowed if no read message exists.
| ALTER TABLE message_request | ||
| ADD COLUMN source VARCHAR(30); |
There was a problem hiding this comment.
source 컬럼 추가가 비멱등이라 특정 환경에서 마이그레이션 실패 가능성이 있습니다.
이미 컬럼이 존재하는 DB(수동 반영/부분 이관 환경)에서는 배포가 중단될 수 있습니다.
🔧 제안 수정
ALTER TABLE message_request
-ADD COLUMN source VARCHAR(30);
+ADD COLUMN IF NOT EXISTS source VARCHAR(30);📝 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.
| ALTER TABLE message_request | |
| ADD COLUMN source VARCHAR(30); | |
| ALTER TABLE message_request | |
| ADD COLUMN IF NOT EXISTS source VARCHAR(30); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@mannabom-server/src/main/resources/db/migration/V7__add_source_to_message_request.sql`
around lines 1 - 2, 현재 마이그레이션(V7__add_source_to_message_request.sql)의 ALTER
TABLE message_request ADD COLUMN source 구문이 비멱등이라 이미 컬럼이 있는 DB에서 실패할 수 있으니,
마이그레이션을 컬럼 존재 여부를 확인한 후에만 컬럼을 추가하도록 수정하세요; 구체적으로
V7__add_source_to_message_request.sql에서 컬럼이 없을 때만 추가되도록 하는 방식(예: DB가 지원하면 ALTER
TABLE ... ADD COLUMN IF NOT EXISTS를 사용하거나, 정보 스키마를 조회해 존재 여부를 확인하고 조건부로 ALTER를
실행하는 로직으로 변경)으로 바꿔 배포 실패를 방지하세요.
| UPDATE public.profile p | ||
| SET university_id = u.university_id | ||
| FROM public.university u | ||
| WHERE p.university = u.name | ||
| AND p.university_id IS NULL; -- 이미 값이 있는 건 건드리지 않음 | ||
|
|
||
| -- 2. [데이터 이관] 기존 문자열(region) -> 새로운 ID(region_id) 매핑 | ||
| -- 시도/시군구 이름이 모두 일치하는 경우 업데이트 | ||
| UPDATE public.profile p | ||
| SET region_id = r.sigungu_code | ||
| FROM public.regions r | ||
| WHERE p.region_sido = r.sido_name | ||
| AND p.region_sigungu = r.sigungu_name | ||
| AND p.region_id IS NULL; | ||
|
|
||
| -- 3. [컬럼 삭제] 데이터 이관이 끝났으므로 기존 컬럼 삭제 | ||
| ALTER TABLE public.profile DROP COLUMN IF EXISTS university; | ||
| ALTER TABLE public.profile DROP COLUMN IF EXISTS region_sido; | ||
| ALTER TABLE public.profile DROP COLUMN IF EXISTS region_sigungu; |
There was a problem hiding this comment.
이관 검증 없이 원본 컬럼을 바로 드롭하면 데이터가 유실됩니다.
현재 UPDATE는 이름이 정확히 일치한 행만 채우고, 바로 university/region_* 컬럼을 삭제합니다. 공백·표기 차이·누락 마스터 데이터가 한 건이라도 있으면 복구 경로 없이 원본값을 잃습니다.
🔧 제안 수정
UPDATE public.profile p
SET region_id = r.sigungu_code
FROM public.regions r
WHERE p.region_sido = r.sido_name
AND p.region_sigungu = r.sigungu_name
AND p.region_id IS NULL;
+DO $$
+BEGIN
+ IF EXISTS (
+ SELECT 1
+ FROM public.profile p
+ WHERE p.university IS NOT NULL
+ AND p.university_id IS NULL
+ ) THEN
+ RAISE EXCEPTION 'Unmapped university rows remain in public.profile';
+ END IF;
+
+ IF EXISTS (
+ SELECT 1
+ FROM public.profile p
+ WHERE (p.region_sido IS NOT NULL OR p.region_sigungu IS NOT NULL)
+ AND p.region_id IS NULL
+ ) THEN
+ RAISE EXCEPTION 'Unmapped region rows remain in public.profile';
+ END IF;
+END $$;
+
-- 3. [컬럼 삭제] 데이터 이관이 끝났으므로 기존 컬럼 삭제
ALTER TABLE public.profile DROP COLUMN IF EXISTS university;
ALTER TABLE public.profile DROP COLUMN IF EXISTS region_sido;
ALTER TABLE public.profile DROP COLUMN IF EXISTS region_sigungu;📝 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.
| UPDATE public.profile p | |
| SET university_id = u.university_id | |
| FROM public.university u | |
| WHERE p.university = u.name | |
| AND p.university_id IS NULL; -- 이미 값이 있는 건 건드리지 않음 | |
| -- 2. [데이터 이관] 기존 문자열(region) -> 새로운 ID(region_id) 매핑 | |
| -- 시도/시군구 이름이 모두 일치하는 경우 업데이트 | |
| UPDATE public.profile p | |
| SET region_id = r.sigungu_code | |
| FROM public.regions r | |
| WHERE p.region_sido = r.sido_name | |
| AND p.region_sigungu = r.sigungu_name | |
| AND p.region_id IS NULL; | |
| -- 3. [컬럼 삭제] 데이터 이관이 끝났으므로 기존 컬럼 삭제 | |
| ALTER TABLE public.profile DROP COLUMN IF EXISTS university; | |
| ALTER TABLE public.profile DROP COLUMN IF EXISTS region_sido; | |
| ALTER TABLE public.profile DROP COLUMN IF EXISTS region_sigungu; | |
| UPDATE public.profile p | |
| SET university_id = u.university_id | |
| FROM public.university u | |
| WHERE p.university = u.name | |
| AND p.university_id IS NULL; -- 이미 값이 있는 건 건드리지 않음 | |
| -- 2. [데이터 이관] 기존 문자열(region) -> 새로운 ID(region_id) 매핑 | |
| -- 시도/시군구 이름이 모두 일치하는 경우 업데이트 | |
| UPDATE public.profile p | |
| SET region_id = r.sigungu_code | |
| FROM public.regions r | |
| WHERE p.region_sido = r.sido_name | |
| AND p.region_sigungu = r.sigungu_name | |
| AND p.region_id IS NULL; | |
| DO $$ | |
| BEGIN | |
| IF EXISTS ( | |
| SELECT 1 | |
| FROM public.profile p | |
| WHERE p.university IS NOT NULL | |
| AND p.university_id IS NULL | |
| ) THEN | |
| RAISE EXCEPTION 'Unmapped university rows remain in public.profile'; | |
| END IF; | |
| IF EXISTS ( | |
| SELECT 1 | |
| FROM public.profile p | |
| WHERE (p.region_sido IS NOT NULL OR p.region_sigungu IS NOT NULL) | |
| AND p.region_id IS NULL | |
| ) THEN | |
| RAISE EXCEPTION 'Unmapped region rows remain in public.profile'; | |
| END IF; | |
| END $$; | |
| -- 3. [컬럼 삭제] 데이터 이관이 끝났으므로 기존 컬럼 삭제 | |
| ALTER TABLE public.profile DROP COLUMN IF EXISTS university; | |
| ALTER TABLE public.profile DROP COLUMN IF EXISTS region_sido; | |
| ALTER TABLE public.profile DROP COLUMN IF EXISTS region_sigungu; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@mannabom-server/src/main/resources/db/migration/V8__migrate_profile_data_and_add_column_chat_room_table.sql`
around lines 3 - 21, The migration drops original columns immediately after a
best-effort UPDATE, risking data loss; modify the migration to (1) preserve
source data by copying public.profile.university, region_sido, region_sigungu
into a backup table or new backup columns before any DELETE/DROP, (2) add a
verification step that compares how many rows were successfully migrated to
university_id and region_id (using selectors on public.profile.university_id and
region_id) and reports or fails the migration if there are any unmatched rows,
and (3) only perform ALTER TABLE DROP COLUMN for university, region_sido,
region_sigungu after successful verification (or provide a safe manual
remediation path), referencing the UPDATE statements on public.profile (SET
university_id = u.university_id ... FROM public.university u) and (SET region_id
= r.sigungu_code ... FROM public.regions r) and the ALTER TABLE DROP COLUMN
statements so you can locate and change them.
[Setting] 테스트 자동화 설정
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
mannabom-server/.github/workflows/ci.yml (1)
72-78: diff-cover 80% 임계치와jacocoTestCoverageVerification70% 임계치의 이원화 의도 확인이 필요합니다.
./gradlew ... jacocoTestCoverageVerification은 전체 번들 기준 70% 미만이면 이미 실패하며(build.gradle Line 108), 그 이후 단계인 diff-cover는 PR 변경분에 대해 80%를 요구합니다. 의도한 정책(전체 70% / 변경분 80%)이 맞다면 좋지만, 한 가지 주의점이 있습니다.jacocoTestCoverageVerification단계에서 먼저 실패하면 JaCoCo XML은 생성되지만 이후 diff-cover 단계는 실행되지 않아 PR 변경분의 커버리지 정보를 얻지 못합니다. 실패 상황에서도 변경분 커버리지 리포트가 필요하다면 diff-cover 단계에if: always()를 추가하거나jacocoTestCoverageVerification을check에서 분리해 CI에서 별도 단계로 실행하는 방식을 고려해 보세요.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mannabom-server/.github/workflows/ci.yml` around lines 72 - 78, The CI currently enforces a global jacocoTestCoverageVerification threshold (jacocoTestCoverageVerification) at 70% and then enforces an 80% diff-cover check for PR changes (diff-cover), which means if the jacoco verification step fails the job may stop before diff-cover can produce change-level coverage; to ensure diff-cover still runs (so you get PR-level coverage even when global verification fails) change the workflow so the diff-cover step runs regardless of prior failure (use if: always()) or separate jacocoTestCoverageVerification out from the main check flow into its own step/job so diff-cover always executes and emits its report.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@mannabom-server/.github/workflows/ci.yml`:
- Around line 15-16: The CI workflow uses an EOL PostgreSQL image ("image:
postgres:13" under the "postgres:" service); update the image tag to a supported
release such as "postgres:16" (or a specific variant like "postgres:16-alpine")
to restore security/bug fixes and reproducible builds—replace "image:
postgres:13" with the newer tag and run the CI to verify
migrations/compatibility.
In `@mannabom-server/build.gradle`:
- Around line 97-114: The current jacocoTestCoverageVerification rule
(jacocoTestCoverageVerification, violationRules -> rule, element = 'BUNDLE',
limit -> minimum = 0.70) will fail CI immediately for initial PRs; update the
task by either lowering the minimum (e.g., 0.0–0.3), removing
jacocoTestCoverageVerification from check (remove check.dependsOn
jacocoTestCoverageVerification) and run it as a separate CI task, or add
excludes via afterEvaluate and classDirectories to omit
generated/entrypoint/config/dto classes (use patterns like **/Q*.class,
**/*Application*, **/config/**, **/dto/**) so the BUNDLE denominator excludes
those files; pick one approach and apply it to jacocoTestCoverageVerification
configuration.
---
Nitpick comments:
In `@mannabom-server/.github/workflows/ci.yml`:
- Around line 72-78: The CI currently enforces a global
jacocoTestCoverageVerification threshold (jacocoTestCoverageVerification) at 70%
and then enforces an 80% diff-cover check for PR changes (diff-cover), which
means if the jacoco verification step fails the job may stop before diff-cover
can produce change-level coverage; to ensure diff-cover still runs (so you get
PR-level coverage even when global verification fails) change the workflow so
the diff-cover step runs regardless of prior failure (use if: always()) or
separate jacocoTestCoverageVerification out from the main check flow into its
own step/job so diff-cover always executes and emits its report.
🪄 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: 7cb4de70-4b32-4571-927c-5de48d6205cd
📒 Files selected for processing (5)
.gitignoremannabom-server/.github/PULL_REQUEST_TEMPLATE/default.mdmannabom-server/.github/workflows/ci.ymlmannabom-server/build.gradlemannabom-server/src/main/resources/application-test.yml
✅ Files skipped from review due to trivial changes (3)
- mannabom-server/.github/PULL_REQUEST_TEMPLATE/default.md
- .gitignore
- mannabom-server/src/main/resources/application-test.yml
| postgres: | ||
| image: postgres:13 |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
🌐 Web query:
PostgreSQL 13 end of life date community support
💡 Result:
PostgreSQL 13 reached end of life for community support on November 13, 2025. After this date, it no longer receives security patches or bug fixes from the PostgreSQL Global Development Group. As of April 23, 2026, it is unsupported.
Citations:
- 1: http://www.postgresql.com/support/versioning/
- 2: https://www.postgresql.org/support/versioning/
- 3: https://www.postgresql.org/support/versioning/?azure-portal=true
- 4: https://postgres.org/support/versioning
PostgreSQL 13은 이미 EOL 지원이 종료되었습니다.
PostgreSQL 13의 커뮤니티 지원은 2025년 11월 13일에 종료되었으며, 현재 보안 패치나 버그 수정을 받지 않습니다. CI 환경에서 지원 종료된 데이터베이스 버전을 사용하는 것은 보안 및 유지보수 측면에서 권장되지 않습니다. postgres:15 또는 postgres:16으로 업그레이드하고, 재현성을 위해 postgres:16-alpine 같이 좀 더 구체적인 태그를 사용하세요.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@mannabom-server/.github/workflows/ci.yml` around lines 15 - 16, The CI
workflow uses an EOL PostgreSQL image ("image: postgres:13" under the
"postgres:" service); update the image tag to a supported release such as
"postgres:16" (or a specific variant like "postgres:16-alpine") to restore
security/bug fixes and reproducible builds—replace "image: postgres:13" with the
newer tag and run the CI to verify migrations/compatibility.
| jacocoTestCoverageVerification { | ||
| dependsOn test | ||
|
|
||
| violationRules { | ||
| rule { | ||
| enabled = true | ||
| element = 'BUNDLE' | ||
|
|
||
| limit { | ||
| counter = 'LINE' | ||
| value = 'COVEREDRATIO' | ||
| minimum = 0.70 | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| check.dependsOn jacocoTestCoverageVerification No newline at end of file |
There was a problem hiding this comment.
전체 번들 70% 기준이 초기 이관 단계에서 CI를 즉시 실패시킬 수 있습니다.
초기 세팅 PR 단계에서는 테스트 코드가 거의 없어 check 실행 시 jacocoTestCoverageVerification이 바로 실패하여 빌드·배포 파이프라인이 막힐 수 있습니다. 또한 현재 element = 'BUNDLE' 한 가지 룰만 있어 generated 코드(Q-class, Lombok 산출물), DTO, Config 등이 모두 분모에 포함됩니다. 아래 중 상황에 맞게 선택하시길 권장합니다.
- 초기 단계에서는
minimum을 낮추거나(예: 0.0~0.3),excludes로 엔트리포인트/Q-class/DTO를 제외 - CI 워크플로에서 PR 변경분 80%(diff-cover)로 실질 게이팅하고, 번들 기준은 점진적으로 상향
jacocoTestCoverageVerification을check에서 떼어내고 별도 태스크로 CI에서만 호출
afterEvaluate + classDirectories에 exclude 패턴을 추가하는 패턴도 함께 검토해 보세요 (**/Q*.class, **/*Application*, **/config/**, **/dto/** 등).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@mannabom-server/build.gradle` around lines 97 - 114, The current
jacocoTestCoverageVerification rule (jacocoTestCoverageVerification,
violationRules -> rule, element = 'BUNDLE', limit -> minimum = 0.70) will fail
CI immediately for initial PRs; update the task by either lowering the minimum
(e.g., 0.0–0.3), removing jacocoTestCoverageVerification from check (remove
check.dependsOn jacocoTestCoverageVerification) and run it as a separate CI
task, or add excludes via afterEvaluate and classDirectories to omit
generated/entrypoint/config/dto classes (use patterns like **/Q*.class,
**/*Application*, **/config/**, **/dto/**) so the BUNDLE denominator excludes
those files; pick one approach and apply it to jacocoTestCoverageVerification
configuration.
작업 내용
변경 이유
주요 변경 사항
프로젝트 기본 실행 구조 추가
MannabomServerApplication.java
MannabomServerApplicationTests.java
환경설정 파일 추가
application.yaml
application-local.yml
application-prod.yml
빌드 및 실행 환경 파일 추가
build.gradle
settings.gradle
gradlew
gradle/wrapper/*
Dockerfile
Docker Compose 파일 추가
docker-compose.local.yml
docker-compose.prod.yml
DB 마이그레이션 파일 추가
V1__baseline.sql
V2__add_meeting_and_chat.sql
V3__add_request_table_and_extra_photo_table_and_rating_table.sql
V4__add_reject_reason_to_like_request.sql
V5__add_reject_reason_to_message_request.sql
V6__add_source_to_like_request.sql
V7__add_source_to_message_request.sql
V8__migrate_profile_data_and_add_column_chat_room_table.sql
초기 데이터 파일 추가
regions.csv
regions_original.csv
테스트
관련 이슈
closes #
리뷰 포인트
참고 사항
Summary by CodeRabbit
Release Notes
Chores
Tests