Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
mannabom-server/HELP.md
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/

### IntelliJ IDEA ###
.idea/
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/

### VS Code ###
.vscode/

# Logs
*.log

# Spring local configs / secrets
**/application-local.yml
**/application-local.properties
**/*.secret.*

mannabom-server/.env*
mannabom-server/src/.env*
Comment thread
Sehi55 marked this conversation as resolved.
.DS_Store

#firebase 비밀키
**/src/main/resources/firebase/
**/src/main/resources/firebase/*.json
3 changes: 3 additions & 0 deletions mannabom-server/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/gradlew text eol=lf
*.bat text eol=crlf
*.jar binary
22 changes: 22 additions & 0 deletions mannabom-server/.github/PULL_REQUEST_TEMPLATE/default.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
## 작업 내용
-

## 변경 이유
-

## 주요 변경 사항
-

## 테스트
- [ ] 로컬 실행 확인
- [ ] API 테스트 확인
- [ ] DB 마이그레이션 확인

## 관련 이슈
- closes #

## 리뷰 포인트
-

## 참고 사항
-
85 changes: 85 additions & 0 deletions mannabom-server/.github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: CI

on:
pull_request:
branches: [ "main", "dev" ]
push:
branches: [ "main", "dev" ]

jobs:
test-and-coverage:
name: test-and-coverage
runs-on: ubuntu-latest

services:
postgres:
image: postgres:13
Comment on lines +15 to +16
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ 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:


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.

env:
POSTGRES_DB: mannabom_test
POSTGRES_USER: testuser
POSTGRES_PASSWORD: testpass
ports:
- 5432:5432
options: >-
--health-cmd="pg_isready -U testuser -d mannabom_test"
--health-interval=10s
--health-timeout=5s
--health-retries=5

redis:
image: redis:6-alpine
ports:
- 6379:6379
options: >-
--health-cmd="redis-cli ping"
--health-interval=10s
--health-timeout=5s
--health-retries=5

steps:
- name: Repository 체크 아웃
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: JDK 17 설치
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17

- name: Gradle 세팅
uses: gradle/actions/setup-gradle@v4

- name: 실행 권한 부여
working-directory: mannabom-server
run: chmod +x gradlew

- name: Gradle 실행 및 테스트 결과 리포트 작성
working-directory: mannabom-server
env:
SPRING_PROFILES_ACTIVE: test
run: ./gradlew clean test jacocoTestReport jacocoTestCoverageVerification

- name: Python 설치
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: diff-cover 설치
run: pip install diff-cover

- name: PR 변경항목에 대해 테스트 커버리지 충족 여부 확인
if: github.event_name == 'pull_request'
working-directory: mannabom-server
run: |
diff-cover build/reports/jacoco/test/jacocoTestReport.xml \
--compare-branch=origin/${{ github.base_ref }} \
--fail-under=80

- name: 테스트 결과 리포트 업로드
if: always()
uses: actions/upload-artifact@v4
with:
name: jacoco-report
path: mannabom-server/build/reports/jacoco/test/html/
11 changes: 11 additions & 0 deletions mannabom-server/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
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"]
Comment on lines +1 to +11
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

컨테이너가 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.

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

Learn more

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

114 changes: 114 additions & 0 deletions mannabom-server/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.5.4'
id 'io.spring.dependency-management' version '1.1.7'
id 'jacoco'
}

group = 'com.mannabom'
version = '0.0.1-SNAPSHOT'

java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}

repositories {
mavenCentral()
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-websocket'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa' // JPA/Hibernate
implementation 'org.springframework.boot:spring-boot-starter-security' // Spring Security
implementation 'org.springframework.boot:spring-boot-starter-web' // REST API
implementation 'org.springframework.boot:spring-boot-starter-validation' // 입력값 검증
implementation 'org.springframework.boot:spring-boot-starter-data-redis' // Redis 연동
implementation 'org.springframework.boot:spring-boot-starter-webflux' // 카카오 API 호출용
implementation 'org.springframework.boot:spring-boot-starter-mail' // 이메일 SMTP

// JWT 토큰 처리
implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
implementation 'io.jsonwebtoken:jjwt-impl:0.12.6'
implementation 'io.jsonwebtoken:jjwt-jackson:0.12.3'
Comment thread
Sehi55 marked this conversation as resolved.

// 파일 업로드 처리 (로컬 개발용)
implementation 'commons-io:commons-io:2.14.0'

// 파일 업로드 처리: AWS S3 SDK v2 (AWS S3 배포용)
implementation 'software.amazon.awssdk:s3:2.20.26'
implementation 'software.amazon.awssdk:auth:2.20.26'
implementation 'software.amazon.awssdk:regions:2.20.26'

// Lombok
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'

// DB
runtimeOnly 'org.postgresql:postgresql'

// fcm
implementation 'com.google.firebase:firebase-admin:9.2.0'

testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'


// QueryDSL 설정
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"

//매칭 시간 만료를 위한 redisson
implementation 'org.redisson:redisson-spring-boot-starter:3.26.0'

//db 형상관리 flyway
implementation 'org.flywaydb:flyway-core'
implementation 'org.flywaydb:flyway-database-postgresql'


}

test {
useJUnitPlatform()
finalizedBy jacocoTestReport
}

jacoco {
toolVersion = "0.8.13"
}

jacocoTestReport {
dependsOn test

reports {
xml.required = true
csv.required = false
html.required = true
}
}

jacocoTestCoverageVerification {
dependsOn test

violationRules {
rule {
enabled = true
element = 'BUNDLE'

limit {
counter = 'LINE'
value = 'COVEREDRATIO'
minimum = 0.70
}
}
}
}

check.dependsOn jacocoTestCoverageVerification
Comment on lines +97 to +114
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 | 🟡 Minor

전체 번들 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)로 실질 게이팅하고, 번들 기준은 점진적으로 상향
  • jacocoTestCoverageVerificationcheck에서 떼어내고 별도 태스크로 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.

32 changes: 32 additions & 0 deletions mannabom-server/docker-compose.local.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Docker Compose 설정
version: '3.8'

services:
# PostgreSQL DB
postgres:
image: postgres:13
container_name: mannabom-postgres
environment:
POSTGRES_DB: mannabom_db
POSTGRES_USER: postgres # 사용자명
POSTGRES_PASSWORD: password # 비밀번호
ports:
- "5432:5432" # 호스트:컨테이너 포트 매핑
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped # 재부팅 시 자동 시작

# Redis 캐시/세션 저장소
redis:
image: redis:6-alpine
container_name: mannabom-redis
ports:
- "6379:6379" # 호스트:컨테이너 포트 매핑
volumes:
- redis_data:/data
restart: unless-stopped

# 볼륨 정의
volumes:
postgres_data:
redis_data:
33 changes: 33 additions & 0 deletions mannabom-server/docker-compose.prod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@

services:
mannabom-server:
image: ${ECR_REGISTRY_URI}:${IMAGE_TAG}
container_name: mannabom-server
environment:
- SPRING_PROFILES_ACTIVE=prod
env_file:
- .env
ports:
- 8080:8080
depends_on:
- redis
networks:
- mannabom-net
volumes:
- /opt/mannabom/firebase:/opt/mannabom/firebase

redis:
image: redis:alpine
container_name: redis
volumes:
- redis_data:/data
restart: unless-stopped
networks:
- mannabom-net

networks:
mannabom-net:
driver: bridge

volumes:
redis_data: {}
Binary file added mannabom-server/gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
7 changes: 7 additions & 0 deletions mannabom-server/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading