From f1cd9b7fdb0b30aa249527f249fc299348b152e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dean=5B=EB=B0=B1=EB=B3=91=EB=82=A8=5D?= Date: Wed, 12 Nov 2025 23:02:47 +0900 Subject: [PATCH] feat: cicd pipeline --- .gitignore | 36 ++ Dockerfile-dev | 15 + Jenkinsfile-dev | 94 +++++ README.md | 393 ++++++++++++++++++ build.gradle | 64 +-- docker-compose-dev.yml | 27 ++ .../cd/kamcoback/config/StartupLogger.java | 99 +++++ src/main/resources/application-dev.yml | 25 ++ src/main/resources/application-local.yml | 25 ++ src/main/resources/application-prod.yml | 24 ++ src/main/resources/application.yml | 118 +++--- 11 files changed, 821 insertions(+), 99 deletions(-) create mode 100644 Dockerfile-dev create mode 100644 Jenkinsfile-dev create mode 100644 README.md create mode 100644 docker-compose-dev.yml create mode 100644 src/main/java/com/kamco/cd/kamcoback/config/StartupLogger.java create mode 100644 src/main/resources/application-dev.yml create mode 100644 src/main/resources/application-local.yml create mode 100644 src/main/resources/application-prod.yml diff --git a/.gitignore b/.gitignore index c2065bc2..8fed8d34 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,39 @@ out/ ### VS Code ### .vscode/ + +### QueryDSL ### +/src/main/generated/ +**/generated/ + +### Logs ### +*.log +logs/ +*.log.* + +### OS ### +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +### Environment ### +.env +.env.local +.env.*.local +application-local.yml +application-secret.yml + +### Docker (local testing) ### +.dockerignore +docker-compose.override.yml + +### Temporary ### +*.tmp +*.temp +*.swp +*.swo +*~ diff --git a/Dockerfile-dev b/Dockerfile-dev new file mode 100644 index 00000000..5219a42c --- /dev/null +++ b/Dockerfile-dev @@ -0,0 +1,15 @@ +# Stage 1: Build stage (gradle build는 Jenkins에서 이미 수행) +FROM eclipse-temurin:21-jre-jammy + +# 작업 디렉토리 설정 +WORKDIR /app + +# JAR 파일 복사 (Jenkins에서 빌드된 ROOT.jar) +COPY build/libs/ROOT.jar app.jar + +# 포트 노출 +EXPOSE 8080 + +# 애플리케이션 실행 +# dev 프로파일로 실행 +ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=dev", "app.jar"] diff --git a/Jenkinsfile-dev b/Jenkinsfile-dev new file mode 100644 index 00000000..e018a112 --- /dev/null +++ b/Jenkinsfile-dev @@ -0,0 +1,94 @@ +pipeline { + agent any + tools { + jdk 'jdk21' + } + environment { + BRANCH = 'develop' + GIT_REPO = 'https://10.100.0.10:3210/dabeeo/kamco-dabeeo-backoffice.git' + } + + + stages { + stage('Checkout') { + steps { + checkout([ + $class: 'GitSCM', + branches: [[name: "${env.BRANCH}"]], + userRemoteConfigs: [[ + url: "${env.GIT_REPO}", + credentialsId: 'jenkins-dev-token' + ]] + ]) + } + } + stage('Get Commit Hash') { + steps { + script { + env.COMMIT_HASH = sh(script: "git rev-parse --short HEAD", returnStdout: true).trim() + echo "Current commit hash: ${env.COMMIT_HASH}" + } + } + } + + stage('Build') { + steps { + sh "./gradlew clean build -x test" + } + } + + stage('Docker Build & Deploy') { + steps { + script { + echo "Building Docker image with tag: ${env.COMMIT_HASH}" + + // IMAGE_TAG 환경변수 설정 후 docker-compose로 빌드 및 배포 + sh """ + export IMAGE_TAG=${env.COMMIT_HASH} + + # 기존 컨테이너 중지 및 제거 + docker-compose -f docker-compose-dev.yml down || true + + # 새 이미지 빌드 + docker-compose -f docker-compose-dev.yml build + + # latest 태그도 추가 + docker tag kamco-changedetection-api:${env.COMMIT_HASH} kamco-changedetection-api:latest + + # 컨테이너 시작 + docker-compose -f docker-compose-dev.yml up -d + """ + + // 헬스체크 대기 + echo "Waiting for application to be ready..." + sh """ + for i in {1..30}; do + if docker exec kamco-changedetection-api curl -f http://localhost:8080/monitor/health > /dev/null 2>&1; then + echo "✅ Application is healthy!" + docker-compose -f docker-compose-dev.yml ps + exit 0 + fi + echo "⏳ Waiting for application... (\$i/30)" + sleep 2 + done + echo "⚠️ Warning: Health check timeout, checking container status..." + docker-compose -f docker-compose-dev.yml ps + """ + } + } + } + + stage('Cleanup Old Images') { + steps { + script { + echo "Cleaning up old Docker images..." + sh """ + # Keep latest 5 images, remove older ones + docker images kamco-changedetection-api --format "{{.ID}} {{.Tag}}" | \ + grep -v latest | tail -n +6 | awk '{print \$1}' | xargs -r docker rmi || true + """ + } + } + } + } +} diff --git a/README.md b/README.md new file mode 100644 index 00000000..9b560246 --- /dev/null +++ b/README.md @@ -0,0 +1,393 @@ +# KAMCO Change Detection API + +> KAMCO 변화 탐지 시스템을 위한 백엔드 API 서버 + +## 📋 프로젝트 소개 + +**kamco-change-detection-api**는 공간 데이터의 변화를 탐지하고 관리하기 위한 RESTful API 서버입니다. +JTS(Java Topology Suite)를 활용한 지오메트리 데이터 처리와 PostgreSQL을 통한 공간 데이터 저장을 지원합니다. + +## 🛠️ 기술 스택 + +| Category | Technology | +|----------|------------| +| **Language** | Java 21 | +| **Framework** | Spring Boot 3.5.7 | +| **Database** | PostgreSQL (with PostGIS) | +| **ORM** | Spring Data JPA + Hibernate | +| **Query** | QueryDSL 5.0.0 (Jakarta) | +| **Geospatial** | JTS (Java Topology Suite) + GeoJSON | +| **Connection Pool** | HikariCP | +| **Build Tool** | Gradle 8.x | +| **Monitoring** | Spring Boot Actuator | +| **Container** | Docker + Docker Compose | +| **CI/CD** | Jenkins | + +## 🚀 시작하기 + +### 필수 요구사항 + +- Java 21 (JDK 21) +- PostgreSQL 12+ (PostGIS 확장 필요) +- Gradle 8.x (또는 Gradle Wrapper 사용) +- Docker & Docker Compose (선택사항) + +### 로컬 환경 설정 + +1. **저장소 클론** +```bash +git clone https://10.100.0.10:3210/dabeeo/kamco-dabeeo-backoffice.git +cd kamco-back +``` + +2. **데이터베이스 설정** + +PostgreSQL 데이터베이스를 준비하고 `src/main/resources/application-local.yml`을 생성: + +```yaml +spring: + config: + activate: + on-profile: local + datasource: + url: jdbc:postgresql://localhost:5432/your_database + username: your_username + password: your_password +``` + +> **참고**: `application-local.yml`은 `.gitignore`에 포함되어 있어 Git에 커밋되지 않습니다. + +3. **빌드 및 실행** + +```bash +# 빌드 +./gradlew build + +# 실행 (local 프로파일) +./gradlew bootRun + +# 또는 JAR 파일로 실행 +java -jar build/libs/ROOT.jar +``` + +서버가 시작되면 http://localhost:8080 에서 접근 가능합니다. + +## ⚙️ 프로파일 설정 + +애플리케이션은 환경별로 다른 설정을 사용합니다: + +| 프로파일 | 환경 | 포트 | 설정 파일 | +|---------|------|------|-----------| +| `local` | 로컬 개발 | 8080 | `application.yml` (기본) | +| `dev` | 개발 서버 | 7100 | `application-dev.yml` | +| `prod` | 운영 서버 | 8080 | `application-prod.yml` | + +### 프로파일 활성화 + +```bash +# 개발 환경으로 실행 +./gradlew bootRun --args='--spring.profiles.active=dev' + +# JAR 실행 시 +java -jar build/libs/ROOT.jar --spring.profiles.active=dev +``` + +## 🧪 테스트 + +```bash +# 전체 테스트 실행 +./gradlew test + +# 특정 테스트 클래스 실행 +./gradlew test --tests com.kamco.cd.kamcoback.KamcoBackApplicationTests + +# 테스트 리포트 확인 +open build/reports/tests/test/index.html +``` + +## 📦 빌드 + +```bash +# 전체 빌드 (테스트 포함) +./gradlew clean build + +# 테스트 제외 빌드 (CI/CD에서 사용) +./gradlew clean build -x test + +# JAR 파일만 생성 +./gradlew bootJar +``` + +빌드된 JAR 파일: `build/libs/ROOT.jar` + +## 🐳 Docker로 실행하기 + +### Docker Compose 사용 (권장) + +```bash +# 빌드 및 실행 +docker-compose -f docker-compose-dev.yml up -d + +# 로그 확인 +docker-compose -f docker-compose-dev.yml logs -f + +# 중지 +docker-compose -f docker-compose-dev.yml down +``` + +### Docker만 사용 + +```bash +# 이미지 빌드 +docker build -f Dockerfile-dev -t kamco-changedetection-api:latest . + +# 컨테이너 실행 +docker run -d \ + --name kamco-changedetection-api \ + -p 7100:8080 \ + kamco-changedetection-api:latest + +# 로그 확인 +docker logs -f kamco-changedetection-api +``` + +## 📡 API 및 모니터링 + +### Actuator 헬스체크 + +애플리케이션 상태를 확인할 수 있는 엔드포인트가 제공됩니다: + +```bash +# 헬스체크 +curl http://localhost:8080/monitor/health + +# 응답 예시 +{ + "status": "UP", + "components": { + "db": { + "status": "UP" + }, + "diskSpace": { + "status": "UP" + } + } +} +``` + +**Actuator 엔드포인트**: +- `/monitor/health` - 애플리케이션 헬스 체크 +- `/monitor/health/readiness` - Kubernetes Readiness Probe +- `/monitor/health/liveness` - Kubernetes Liveness Probe + +## 🏗️ 프로젝트 구조 + +``` +kamco-back/ +├── src/ +│ ├── main/ +│ │ ├── java/com/kamco/cd/kamcoback/ +│ │ │ ├── KamcoBackApplication.java # 메인 애플리케이션 +│ │ │ ├── config/ # 설정 클래스 +│ │ │ │ ├── WebConfig.java # Jackson, CORS 설정 +│ │ │ │ └── StartupLogger.java # 시작 로그 +│ │ │ ├── common/ # 공통 유틸리티 +│ │ │ │ └── utils/geometry/ # GeoJSON 직렬화 +│ │ │ ├── domain/ # 도메인 엔티티 (예정) +│ │ │ ├── repository/ # 리포지토리 (예정) +│ │ │ ├── service/ # 비즈니스 로직 (예정) +│ │ │ └── controller/ # REST 컨트롤러 (예정) +│ │ └── resources/ +│ │ ├── application.yml # 기본 설정 + local/prod +│ │ └── application-dev.yml # 개발 환경 설정 +│ └── test/ # 테스트 코드 +├── build.gradle # Gradle 빌드 설정 +├── Dockerfile-dev # Docker 이미지 정의 +├── docker-compose-dev.yml # Docker Compose 설정 +├── Jenkinsfile-dev # Jenkins CI/CD 파이프라인 +├── .editorconfig # 코드 스타일 설정 +├── intellij-java-google-style.xml # IntelliJ 코드 스타일 +└── README.md # 이 문서 +``` + +## 🎨 코드 스타일 + +프로젝트는 **Google Java Style Guide**를 따르며, 일부 커스터마이징이 적용되어 있습니다: + +- **들여쓰기**: 탭 (표시 너비: 2칸) +- **최대 줄 길이**: 100자 +- **줄 바꿈**: LF (Unix 스타일) +- **인코딩**: UTF-8 + +### IntelliJ IDEA 설정 + +1. `Preferences` → `Editor` → `Code Style` → `Java` +2. `Import Scheme` → `intellij-java-google-style.xml` 선택 + +## 📐 주요 기능 + +### GeoJSON 지원 + +JTS Geometry 타입이 자동으로 GeoJSON 형식으로 직렬화/역직렬화됩니다: + +```java +@Entity +public class SpatialEntity { + @Column(columnDefinition = "geometry(Point,4326)") + private Point location; + + @Column(columnDefinition = "geometry(Polygon,4326)") + private Polygon boundary; +} +``` + +**특징**: +- 16자리 정밀도 (기본 8자리에서 증가) +- Point, Polygon, Geometry 타입 지원 +- 자동 JSON 변환 (Jackson ObjectMapper 설정) + +### QueryDSL 설정 + +타입 안전한 쿼리를 위해 QueryDSL이 설정되어 있습니다: + +```java +// Q-class는 빌드 시 자동 생성됨 +QSpatialEntity entity = QSpatialEntity.spatialEntity; + +List results = queryFactory + .selectFrom(entity) + .where(entity.name.eq("example")) + .fetch(); +``` + +**Q-class 생성 위치**: `build/generated/sources/annotationProcessor/java/main` + +## 🚢 배포 + +### Jenkins CI/CD + +Jenkins를 통한 자동 배포가 설정되어 있습니다 (`Jenkinsfile-dev`): + +**파이프라인 단계**: +1. **Checkout**: Git 저장소에서 코드 가져오기 (develop 브랜치) +2. **Get Commit Hash**: 버전 태깅용 커밋 해시 추출 +3. **Build**: Gradle로 JAR 빌드 (테스트 제외) +4. **Docker Build & Deploy**: Docker 이미지 빌드 및 배포 +5. **Cleanup**: 오래된 이미지 정리 + +**자동 기능**: +- Git 커밋 해시로 이미지 태깅 +- 기존 컨테이너 자동 교체 +- 헬스체크로 배포 검증 +- 오래된 이미지 자동 정리 (최신 5개 유지) + +### 수동 배포 + +```bash +# 1. 빌드 +./gradlew clean build -x test + +# 2. Docker 이미지 빌드 +docker-compose -f docker-compose-dev.yml build + +# 3. 배포 +docker-compose -f docker-compose-dev.yml up -d + +# 4. 헬스체크 +curl http://localhost:7100/monitor/health +``` + +## 🔧 개발 가이드 + +### 새로운 엔티티 추가 + +1. `domain` 패키지에 엔티티 클래스 생성 +2. JPA 어노테이션 설정 +3. 빌드하여 Q-class 자동 생성 +4. Repository 인터페이스 작성 (QueryDSL custom 메서드 포함) + +### GeoJSON 데이터 다루기 + +```java +// Controller에서 GeoJSON 수신/반환 +@PostMapping("/spatial") +public ResponseEntity create(@RequestBody SpatialEntity entity) { + // Point, Polygon이 자동으로 GeoJSON에서 변환됨 + return ResponseEntity.ok(spatialService.save(entity)); +} + +// 응답 예시 +{ + "id": 1, + "location": { + "type": "Point", + "coordinates": [126.9779692, 37.5662952] + } +} +``` + +### 데이터베이스 마이그레이션 + +현재 설정은 `ddl-auto: validate`이므로 스키마 변경 시: + +1. 수동으로 마이그레이션 스크립트 작성 +2. 또는 개발 중에는 `ddl-auto: update` 사용 (주의 필요) +3. 운영 환경에서는 반드시 `validate` 유지 + +## 📝 환경 변수 + +Docker Compose 또는 시스템 환경 변수로 설정 가능: + +| 변수명 | 설명 | 기본값 | +|--------|------|--------| +| `SPRING_PROFILES_ACTIVE` | 활성 프로파일 | `local` | +| `IMAGE_TAG` | Docker 이미지 태그 | `latest` | +| `TZ` | 타임존 | `Asia/Seoul` | + +## 🐛 트러블슈팅 + +### DataSource 설정 오류 + +``` +Failed to configure a DataSource: 'url' attribute is not specified +``` + +**해결 방법**: +1. 프로파일 이름 확인: `dev`, `prod`, `local` (철자 정확히) +2. 해당 프로파일의 `application-{profile}.yml`에 datasource 설정 존재 확인 +3. PostgreSQL 접속 정보 확인 + +### Q-class가 생성되지 않음 + +```bash +# 강제로 Q-class 재생성 +./gradlew clean compileJava +``` + +생성 위치: `build/generated/sources/annotationProcessor/java/main` + +### Docker 컨테이너 헬스체크 실패 + +```bash +# 컨테이너 로그 확인 +docker logs kamco-changedetection-api + +# 직접 헬스체크 +docker exec kamco-changedetection-api curl http://localhost:8080/monitor/health +``` + +## 📚 참고 문서 + +- [Spring Boot 3.5.7 Documentation](https://docs.spring.io/spring-boot/3.5.7/reference/) +- [Spring Data JPA](https://docs.spring.io/spring-data/jpa/reference/) +- [QueryDSL](https://querydsl.com/static/querydsl/latest/reference/html/) +- [JTS Topology Suite](https://github.com/locationtech/jts) +- [GeoJSON Specification](https://geojson.org/) + +## 📄 라이선스 + +Copyright © 2024 KAMCO. All rights reserved. + +## 👥 기여자 + +- Development Team at KAMCO diff --git a/build.gradle b/build.gradle index f55ce79c..5c8b708c 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ plugins { - id 'java' - id 'org.springframework.boot' version '3.5.7' - id 'io.spring.dependency-management' version '1.1.7' + id 'java' + id 'org.springframework.boot' version '3.5.7' + id 'io.spring.dependency-management' version '1.1.7' } group = 'com.kamco.cd' @@ -9,44 +9,52 @@ version = '0.0.1-SNAPSHOT' description = 'kamco-back' java { - toolchain { - languageVersion = JavaLanguageVersion.of(21) - } + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } } configurations { - compileOnly { - extendsFrom annotationProcessor - } + compileOnly { + extendsFrom annotationProcessor + } } repositories { - mavenCentral() + mavenCentral() } dependencies { - implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - implementation 'org.springframework.boot:spring-boot-starter-web' - compileOnly 'org.projectlombok:lombok' - runtimeOnly 'org.postgresql:postgresql' - annotationProcessor 'org.projectlombok:lombok' - testImplementation 'org.springframework.boot:spring-boot-starter-test' - testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-web' + compileOnly 'org.projectlombok:lombok' + runtimeOnly 'org.postgresql:postgresql' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' - //geometry - implementation 'com.fasterxml.jackson.core:jackson-databind' - implementation 'org.locationtech.jts.io:jts-io-common:1.20.0' - implementation 'org.locationtech.jts:jts-core:1.19.0' + //geometry + implementation 'com.fasterxml.jackson.core:jackson-databind' + implementation 'org.locationtech.jts.io:jts-io-common:1.20.0' + implementation 'org.locationtech.jts:jts-core:1.19.0' - // QueryDSL JPA - implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' + // QueryDSL JPA + implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' - // Q클래스 생성용 annotationProcessor - annotationProcessor 'com.querydsl:querydsl-apt:5.0.0:jakarta' - annotationProcessor 'jakarta.annotation:jakarta.annotation-api' - annotationProcessor 'jakarta.persistence:jakarta.persistence-api' + // Q클래스 생성용 annotationProcessor + annotationProcessor 'com.querydsl:querydsl-apt:5.0.0:jakarta' + annotationProcessor 'jakarta.annotation:jakarta.annotation-api' + annotationProcessor 'jakarta.persistence:jakarta.persistence-api' + + // actuator + implementation 'org.springframework.boot:spring-boot-starter-actuator' } tasks.named('test') { - useJUnitPlatform() + useJUnitPlatform() +} + + +bootJar { + archiveFileName = 'ROOT.jar' } diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml new file mode 100644 index 00000000..68716f7b --- /dev/null +++ b/docker-compose-dev.yml @@ -0,0 +1,27 @@ +version: '3.8' + +services: + kamco-changedetection-api: + build: + context: . + dockerfile: Dockerfile-dev + image: kamco-changedetection-api:${IMAGE_TAG:-latest} + container_name: kamco-changedetection-api + ports: + - "7100:8080" + environment: + - SPRING_PROFILES_ACTIVE=dev + - TZ=Asia/Seoul + networks: + - plantation-network + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8080/monitor/health"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 40s + +networks: + plantation-network: + external: true diff --git a/src/main/java/com/kamco/cd/kamcoback/config/StartupLogger.java b/src/main/java/com/kamco/cd/kamcoback/config/StartupLogger.java new file mode 100644 index 00000000..1de2b594 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/config/StartupLogger.java @@ -0,0 +1,99 @@ +package com.kamco.cd.kamcoback.config; + + +import com.zaxxer.hikari.HikariDataSource; +import javax.sql.DataSource; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.event.EventListener; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@RequiredArgsConstructor +public class StartupLogger { + + private final Environment environment; + private final DataSource dataSource; + + @EventListener(ApplicationReadyEvent.class) + public void logStartupInfo() { + String[] activeProfiles = environment.getActiveProfiles(); + String profileInfo = + activeProfiles.length > 0 ? String.join(", ", activeProfiles) : "default"; + + // Database connection information + String dbUrl = environment.getProperty("spring.datasource.url"); + String dbUsername = environment.getProperty("spring.datasource.username"); + String dbDriver = environment.getProperty("spring.datasource.driver-class-name"); + + // HikariCP pool settings + String poolInfo = ""; + if (dataSource instanceof HikariDataSource hikariDs) { + poolInfo = + String.format( + """ + │ Pool Size : min=%d, max=%d + │ Connection Timeout: %dms + │ Idle Timeout : %dms + │ Max Lifetime : %dms""", + hikariDs.getMinimumIdle(), + hikariDs.getMaximumPoolSize(), + hikariDs.getConnectionTimeout(), + hikariDs.getIdleTimeout(), + hikariDs.getMaxLifetime()); + } + + // JPA/Hibernate settings + String showSql = environment.getProperty("spring.jpa.show-sql", "false"); + String ddlAuto = environment.getProperty("spring.jpa.hibernate.ddl-auto", "none"); + String batchSize = + environment.getProperty("spring.jpa.properties.hibernate.jdbc.batch_size", "N/A"); + String batchFetchSize = + environment.getProperty( + "spring.jpa.properties.hibernate.default_batch_fetch_size", "N/A"); + + String startupMessage = + String.format( + """ + + ╔════════════════════════════════════════════════════════════════════════════════╗ + ║ 🚀 APPLICATION STARTUP INFORMATION ║ + ╠════════════════════════════════════════════════════════════════════════════════╣ + ║ PROFILE CONFIGURATION ║ + ╠────────────────────────────────────────────────────────────────────────────────╣ + │ Active Profile(s): %s + ╠════════════════════════════════════════════════════════════════════════════════╣ + ║ DATABASE CONFIGURATION ║ + ╠────────────────────────────────────────────────────────────────────────────────╣ + │ Database URL : %s + │ Username : %s + │ Driver : %s + ╠════════════════════════════════════════════════════════════════════════════════╣ + ║ HIKARICP CONNECTION POOL ║ + ╠────────────────────────────────────────────────────────────────────────────────╣ + %s + ╠════════════════════════════════════════════════════════════════════════════════╣ + ║ JPA/HIBERNATE CONFIGURATION ║ + ╠────────────────────────────────────────────────────────────────────────────────╣ + │ Show SQL : %s + │ DDL Auto : %s + │ JDBC Batch Size : %s + │ Fetch Batch Size : %s + ╚════════════════════════════════════════════════════════════════════════════════╝ + """, + profileInfo, + dbUrl != null ? dbUrl : "N/A", + dbUsername != null ? dbUsername : "N/A", + dbDriver != null ? dbDriver : "PostgreSQL JDBC Driver (auto-detected)", + poolInfo, + showSql, + ddlAuto, + batchSize, + batchFetchSize); + + log.info(startupMessage); + } +} diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml new file mode 100644 index 00000000..5546dc61 --- /dev/null +++ b/src/main/resources/application-dev.yml @@ -0,0 +1,25 @@ +spring: + config: + activate: + on-profile: dev + + jpa: + show-sql: true + hibernate: + ddl-auto: validate + properties: + hibernate: + default_batch_fetch_size: 100 # ✅ 성능 - N+1 쿼리 방지 + order_updates: true # ✅ 성능 - 업데이트 순서 정렬로 데드락 방지 + use_sql_comments: true # ⚠️ 선택 - SQL에 주석 추가 (디버깅용) + format_sql: true # ⚠️ 선택 - SQL 포맷팅 (가독성) + + datasource: + url: jdbc:postgresql://10.100.0.10:25432/temp + username: temp + password: temp123! + hikari: + minimum-idle: 10 + maximum-pool-size: 20 + + diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml new file mode 100644 index 00000000..8979d647 --- /dev/null +++ b/src/main/resources/application-local.yml @@ -0,0 +1,25 @@ +spring: + config: + activate: + on-profile: local + + jpa: + show-sql: true + hibernate: + ddl-auto: validate + properties: + hibernate: + default_batch_fetch_size: 100 # ✅ 성능 - N+1 쿼리 방지 + order_updates: true # ✅ 성능 - 업데이트 순서 정렬로 데드락 방지 + use_sql_comments: true # ⚠️ 선택 - SQL에 주석 추가 (디버깅용) + format_sql: true # ⚠️ 선택 - SQL 포맷팅 (가독성) + + datasource: + url: jdbc:postgresql://10.100.0.10:25432/temp + username: temp + password: temp123! + hikari: + minimum-idle: 1 + maximum-pool-size: 5 + + diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml new file mode 100644 index 00000000..ab445619 --- /dev/null +++ b/src/main/resources/application-prod.yml @@ -0,0 +1,24 @@ +spring: + config: + activate: + on-profile: dev + + jpa: + show-sql: false + hibernate: + ddl-auto: validate + properties: + hibernate: + default_batch_fetch_size: 100 # ✅ 성능 - N+1 쿼리 방지 + order_updates: true # ✅ 성능 - 업데이트 순서 정렬로 데드락 방지 + use_sql_comments: true # ⚠️ 선택 - SQL에 주석 추가 (디버깅용) + + datasource: + url: jdbc:postgresql://10.100.0.10:25432/temp + username: temp + password: temp123! + hikari: + minimum-idle: 10 + maximum-pool-size: 20 + + diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 5b9989e5..62efaf28 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,83 +1,59 @@ +server: + port: 8080 + spring: application: - name: kamco-back + name: kamco-change-detection-api profiles: - default: local + active: local # 사용할 프로파일 지정 (ex. dev, prod, test) -server: - port: 8080 - -# ----------------------- -# local -# ----------------------- ---- -server: - port: 8080 - -spring: - config: - activate: - on-profile: local datasource: driver-class-name: org.postgresql.Driver - url: jdbc:postgresql://10.100.0.10:25432/temp - username: temp - password: temp123! hikari: - minimum-idle: 10 - maximum-pool-size: 50 + jdbc: + time_zone: UTC + batch_size: 50 + # 권장 설정 + minimum-idle: 2 + maximum-pool-size: 2 + connection-timeout: 20000 + idle-timeout: 300000 + max-lifetime: 1800000 + leak-detection-threshold: 60000 jpa: hibernate: - ddl-auto: none # 또는 update/create - show-sql: true + ddl-auto: validate properties: hibernate: - format_sql: true + jdbc: + batch_size: 50 + default_batch_fetch_size: 100 +logging: + level: + org: + springframework: + web: DEBUG + security: DEBUG + root: INFO +# actuator +management: + health: + readinessstate: + enabled: true + livenessstate: + enabled: true + endpoint: + health: + probes: + enabled: true + show-details: always + endpoints: + jmx: + exposure: + exclude: "*" + web: + base-path: /monitor + exposure: + include: + - "health" -# ----------------------- -# dev -# ----------------------- ---- -server: - port: 3333 - -spring: - config: - activate: - on-profile: dev - datasource: - driver-class-name: org.postgresql.Driver - url: jdbc:postgresql://10.100.0.10:25432/temp - username: temp - password: temp123! - jpa: - hibernate: - ddl-auto: none # 또는 update/create - show-sql: true - properties: - hibernate: - format_sql: true - -# ----------------------- -# prod -# ----------------------- ---- -server: - port: 8080 - -spring: - config: - activate: - on-profile: prod - datasource: - driver-class-name: org.postgresql.Driver - url: jdbc:postgresql://10.100.0.10:25432/temp - username: temp - password: temp123! - jpa: - hibernate: - ddl-auto: validate # 또는 update/create - show-sql: true - properties: - hibernate: - format_sql: true