diff --git a/.gitea/workflows/eapim-admin-ci.yml b/.gitea/workflows/eapim-admin-ci.yml
new file mode 100644
index 0000000..c0d7b08
--- /dev/null
+++ b/.gitea/workflows/eapim-admin-ci.yml
@@ -0,0 +1,140 @@
+name: eapim-admin CI
+
+on:
+ push:
+ branches:
+ - master
+ - develop
+ - stage
+ - feats/ci-test
+
+jobs:
+ build:
+ runs-on: [self-hosted, linux, eapim-admin]
+ env:
+ JAVA_HOME: /apps/opts/jdk8
+ JAVA_HOME_TOMCAT: /apps/opts/jdk17
+ CATALINA_BASE: /prod/eapim/adminportal
+ CATALINA_HOME: /prod/eapim/apache-tomcat-9.0.116
+ CATALINA_PID: /prod/eapim/adminportal/temp/catalina.pid
+ DEPLOY_HTTP_PORT: "30120"
+ defaults:
+ run:
+ working-directory: eapim-admin
+
+ steps:
+ - name: Checkout eapim-admin (trigger SHA)
+ uses: http://172.30.1.50:3000/actions/checkout@v4
+ with:
+ path: eapim-admin
+
+ - name: Checkout sibling modules (master)
+ working-directory: ${{ github.workspace }}
+ run: |
+ set -e
+ mkdir -p eapim-online
+
+ # eapim-online/* — 5 modules referenced from settings.gradle
+ for REPO in elink-online-core elink-online-core-jpa elink-online-transformer elink-online-common elink-online-emsclient; do
+ rm -rf "eapim-online/$REPO"
+ git clone --depth=1 --branch master \
+ http://oauth2:${{ secrets.CI_TOKEN }}@172.30.1.50:3000/djb-eapim/$REPO.git \
+ "eapim-online/$REPO"
+ done
+
+ # standalone siblings
+ for REPO in elink-portal-common eapim-admin-djb; do
+ rm -rf "$REPO"
+ git clone --depth=1 --branch master \
+ http://oauth2:${{ secrets.CI_TOKEN }}@172.30.1.50:3000/djb-eapim/$REPO.git \
+ "$REPO"
+ done
+
+ - name: Verify toolchain
+ run: |
+ java -version
+ gradle --version
+
+ - name: Gradle build (no tests)
+ run: gradle clean build -x test --no-daemon
+
+ - name: Upload WAR artifact
+ uses: http://172.30.1.50:3000/actions/upload-artifact@v3
+ with:
+ name: eapim-admin-war-${{ github.sha }}
+ path: eapim-admin/build/libs/eapim-admin.war
+ if-no-files-found: error
+
+ - name: Sync systemd user unit
+ working-directory: ${{ github.workspace }}
+ run: |
+ install -D -m 644 eapim-admin/deploy/systemd/eapim-admin.service \
+ "$HOME/.config/systemd/user/eapim-admin.service"
+ systemctl --user daemon-reload
+ systemctl --user enable eapim-admin 2>/dev/null || true
+
+ - name: Stop tomcat (pre-clean)
+ working-directory: ${{ github.workspace }}
+ run: |
+ # 1) systemd 관리 인스턴스 정지 (이번 워크플로가 띄운 것)
+ systemctl --user stop eapim-admin 2>/dev/null || true
+
+ # 2) systemd 외부 detached 인스턴스 정리
+ if [ -f "$CATALINA_PID" ] && kill -0 "$(cat $CATALINA_PID)" 2>/dev/null; then
+ JAVA_HOME=$JAVA_HOME_TOMCAT "$CATALINA_HOME/bin/shutdown.sh" 30 -force || true
+ for i in $(seq 1 30); do
+ [ -f "$CATALINA_PID" ] && kill -0 "$(cat $CATALINA_PID)" 2>/dev/null || break
+ sleep 1
+ done
+ fi
+ rm -f "$CATALINA_PID"
+
+ - name: Deploy war as /monitoring
+ working-directory: ${{ github.workspace }}
+ run: |
+ DEPLOY_DIR="$CATALINA_BASE/webapps"
+ rm -rf "$DEPLOY_DIR/monitoring" "$DEPLOY_DIR/monitoring.war"
+ cp eapim-admin/build/libs/eapim-admin.war "$DEPLOY_DIR/monitoring.war"
+ ls -la "$DEPLOY_DIR"
+
+ - name: Start tomcat and readiness probe (timeout 120s)
+ working-directory: ${{ github.workspace }}
+ run: |
+ LOG="$CATALINA_BASE/logs/catalina.$(date +%Y-%m-%d).log"
+ BEFORE=0
+ [ -f "$LOG" ] && BEFORE=$(stat -c %s "$LOG")
+
+ # systemd 가 Tomcat 을 새 cgroup 으로 띄움 — runner step 종료와 무관하게 살아남음
+ systemctl --user start eapim-admin
+
+ DEADLINE=$(($(date +%s) + 120))
+ STATUS=000
+ while [ $(date +%s) -lt $DEADLINE ]; do
+ STATUS=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 3 \
+ "http://localhost:$DEPLOY_HTTP_PORT/monitoring/login.do" 2>/dev/null || echo "000")
+ case "$STATUS" in
+ 200|302|401)
+ echo "Readiness OK (/monitoring/login.do HTTP $STATUS)"
+ break
+ ;;
+ esac
+
+ if [ -f "$LOG" ] && tail -c +$((BEFORE+1)) "$LOG" | grep -qE "Application listener .* Exception|SEVERE.*startup.Catalina"; then
+ echo "::error::Startup error detected in log"
+ tail -c +$((BEFORE+1)) "$LOG" | tail -80
+ exit 1
+ fi
+ sleep 2
+ done
+
+ case "$STATUS" in
+ 200|302|401) ;;
+ *)
+ echo "::error::Readiness probe failed within 120s (last HTTP status: $STATUS)"
+ [ -f "$LOG" ] && tail -c +$((BEFORE+1)) "$LOG" | tail -100
+ exit 1
+ ;;
+ esac
+
+ echo "--- key boot log lines ---"
+ tail -c +$((BEFORE+1)) "$LOG" | grep -E "Server startup|Deployment of web" | head -10 || true
diff --git a/.gitignore b/.gitignore
index 41a9225..67a1cbc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -246,3 +246,6 @@ eapim-admin-kjb/
*.report.md
*.claude.md
tmpclaude-*-cwd
+logs
+rinjae_
+tomcat-base
\ No newline at end of file
diff --git a/CLAUDE.md b/CLAUDE.md
index e51bbbb..7e15c4b 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -10,7 +10,7 @@ AI 어시스턴트가 작업을 시작하기 전에 반드시 이해해야 할
- **신규 기능**: 항상 **JPA**와 Spring Data 리포지토리를 사용해야 합니다.
- **레거시 코드**: 기존 iBATIS (`*.xml` 매퍼) 코드를 수정할 때는 해당 패턴을 따라야 합니다.
- **멀티 모듈 Gradle 프로젝트**: `settings.gradle`에 정의된 것처럼 여러 하위 모듈(`elink-online-*`, `kjb-*` 등)로 구성되어 있습니다. 특정 기능은 다른 모듈에 위치할 수 있습니다.
-- **QueryDSL 코드 생성**: 빌드 시 `QueryDSL`을 사용하여 Q-class가 자동으로 생성됩니다. IDE에서 엔티티를 찾을 수 없다고 표시되면, `kjb-gradle.sh compileJava`를 먼저 실행하여 코드를 생성해야 합니다.
+- **QueryDSL 코드 생성**: 빌드 시 `QueryDSL`을 사용하여 Q-class가 자동으로 생성됩니다. IDE에서 엔티티를 찾을 수 없다고 표시되면, `./gradlew compileJava` 를 먼저 실행하여 코드를 생성해야 합니다.
- **고객사별 커스터마이징**: `ext.kjb` 또는 `custom` 패키지는 특정 고객사(광주은행)를 위한 코드를 포함하므로, 일반적인 기능 수정 시에는 주의가 필요합니다.
## 프로젝트 개요
@@ -39,50 +39,48 @@ eLink EMS (eLink Management System)는 eLink의 웹 기반 관리 서비스로,
### 빌드 명령어
-**⚠️ 중요**: 환경변수 문제로 인해 `gradle` 대신 `kjb-gradle.sh` 스크립트를 사용해야 합니다.
-- 스크립트 위치: `/c/eactive/workspaces/shell-scripts/kjb-gradle.sh`
-- PATH에 등록되어 있으므로 바로 `kjb-gradle.sh` 명령어 사용 가능
+프로젝트 루트의 Gradle wrapper(`./gradlew`)를 사용합니다. JDK 8 toolchain 위치는 `.envrc` 등으로 잡습니다(아래 "기술 스택" 섹션 참조).
```bash
# 표준 빌드
-kjb-gradle.sh build
+./gradlew build
# Weblogic 배포용 빌드 (테스트 제외)
-kjb-gradle.sh build -x test -Pprofile=weblogic
+./gradlew build -x test -Pprofile=weblogic
# WAR 파일 빌드
-kjb-gradle.sh war
+./gradlew war
# 클린 빌드
-kjb-gradle.sh clean build
+./gradlew clean build
```
### 테스트 실행
```bash
# 모든 테스트 실행
-kjb-gradle.sh test
+./gradlew test
# 특정 테스트 클래스 실행
-kjb-gradle.sh test --tests "com.example.ClassName"
+./gradlew test --tests "com.example.ClassName"
# 특정 테스트 패키지 실행 (JUnit 플랫폼 사용)
-kjb-gradle.sh test --tests "com.eactive.eai.rms.*"
+./gradlew test --tests "com.eactive.eai.rms.*"
```
### 개발 태스크
```bash
# 패키징 없이 클래스만 컴파일
-kjb-gradle.sh classes
+./gradlew classes
# QueryDSL Q-classes 및 기타 애노테이션 생성
-kjb-gradle.sh compileJava
+./gradlew compileJava
# 의존성 트리 보기
-kjb-gradle.sh dependencies
+./gradlew dependencies
# 사용 가능한 모든 태스크 목록
-kjb-gradle.sh tasks --all
+./gradlew tasks --all
```
## 로컬 개발 빠른 시작
@@ -92,26 +90,26 @@ kjb-gradle.sh tasks --all
1. **IDE 설정 파일 생성 (최초 1회)**
```bash
# Eclipse 사용 시 (기본)
- kjb-gradle.sh eclipse
+ ./gradlew eclipse
# IntelliJ IDEA 사용 시 (build.gradle.intellij 파일 사용 필요)
# 1. build.gradle을 build.gradle.eclipse로 백업
# 2. build.gradle.intellij를 build.gradle로 복사
- # 3. kjb-gradle.sh idea 실행
+ # 3. ./gradlew idea 실행
```
2. **QueryDSL 등 소스 코드 생성**
```bash
- kjb-gradle.sh compileJava
+ ./gradlew compileJava
```
3. **전체 빌드 및 테스트 실행**
```bash
- kjb-gradle.sh build
+ ./gradlew build
```
4. **IDE에서 프로젝트 열기**
- - Eclipse: `kjb-gradle.sh eclipse` 실행 후, IDE에서 프로젝트를 엽니다.
+ - Eclipse: `./gradlew eclipse` 실행 후, IDE에서 프로젝트를 엽니다.
- IntelliJ: IntelliJ 전용 `build.gradle.intellij`를 `build.gradle`로 교체 후 사용합니다.
5. **실행 구성(Run Configuration) 설정**
@@ -162,14 +160,14 @@ eapim-admin (root project)
#### Q-Class 생성 위치
Q-classes는 `build/generated/java/` 디렉토리에 생성됩니다.
-- `kjb-gradle.sh compileJava` 또는 `kjb-gradle.sh build` 실행 시 Gradle이 자동으로 생성
+- `./gradlew compileJava` 또는 `./gradlew build` 실행 시 Gradle이 자동으로 생성
- 이 디렉토리는 `.gitignore`에 포함되어 있으며 커밋해서는 안 됩니다
#### 생성된 코드 작업하기
- **Gradle 빌드**: `build/generated/java/`의 Q-classes가 자동으로 classpath에 포함됩니다
-- **업데이트 pull 후**: `kjb-gradle.sh compileJava`를 실행하여 Q-classes를 재생성합니다
-- **Q-classes IDE 오류 시**: `kjb-gradle.sh clean compileJava`로 재생성합니다
+- **업데이트 pull 후**: `./gradlew compileJava` 를 실행하여 Q-classes를 재생성합니다
+- **Q-classes IDE 오류 시**: `./gradlew clean compileJava` 로 재생성합니다
#### IDE별 빌드 설정 파일
@@ -255,12 +253,21 @@ IntelliJ를 사용하려면 `build.gradle.intellij`를 `build.gradle`로 교체
WebLogic용 빌드 시, DefaultServlet 문제를 해결하기 위해 `web.xml`을 `weblogic-web.xml`로 교체하는 `weblogic` 프로필을 사용합니다:
```bash
-kjb-gradle.sh build -x test -Pprofile=weblogic
+./gradlew build -x test -Pprofile=weblogic
```
## 기술 스택
-- **Java 8**: Gradle toolchain을 통해 강제
+- **Java 8**: Gradle toolchain을 통해 강제 (`JavaLanguageVersion.of(8)`). 프로젝트의 `gradle.properties` 에는 JDK 경로를 기입하지 않습니다 — 개인 환경별로 `.envrc`(direnv) 또는 셸 rc 파일에서 `JAVA_HOME` 을 JDK 8 위치로 export 하세요. Gradle 8 의 toolchain auto-detect 가 `JAVA_HOME` 도 후보 경로로 인식합니다.
+
+ ```bash
+ # 예: 프로젝트 루트의 .envrc (Zulu 8 / macOS Apple Silicon)
+ JAVA_HOME=${HOME}/opts/jdks/zulu8.94.0.17-ca-jdk8.0.492-macosx_aarch64
+ GRADLE_USER_HOME=${HOME}/eactive/djb-eapim/gradle-home
+ export PATH=${JAVA_HOME}/bin:${PATH}
+ ```
+
+ Gradle 표준 위치(`/Library/Java/JavaVirtualMachines/...`, Homebrew, SDKMAN 등)에 설치한 경우는 별도 설정 없이도 auto-detect 됩니다.
- **Spring Framework 5.3.27**: 코어 프레임워크 (MVC, Data JPA)
- **Spring Data JPA 2.5.2**: 리포지토리 추상화
- **Hibernate 5.4.33/5.6.15**: ORM 구현 (JPA/ORM)
@@ -271,9 +278,10 @@ kjb-gradle.sh build -x test -Pprofile=weblogic
- **Jackson 2.13.1**: JSON 처리
- **Logback 1.2.10**: 로깅 프레임워크 (SLF4J와 함께)
- **AWS SDK 2.20.142**: S3 연동
-- **Kubernetes Client 18.0.1**: K8s 관리
- **EhCache**: 캐싱, **Lombok**: 코드 생성, **MapStruct**: 객체 매핑
+> Kubernetes Client 의존성은 JDK 8 호환 문제로 제거됨(`io.kubernetes:client-java:18.0.1` 은 JDK 11+ 필요). K8s 모드 기능이 필요하면 `≤13.0.2` 로 다운그레이드 후 재도입 검토.
+
## 프로젝트 규칙
### 패키지 구조
@@ -376,7 +384,7 @@ com.eactive.eai
### IntelliJ IDEA (권장)
```bash
-kjb-gradle.sh idea
+./gradlew idea
```
또는 IntelliJ에서 직접 "Import Gradle Project"를 사용합니다.
@@ -395,7 +403,7 @@ cp build.gradle build.gradle.intellij
cp build.gradle.eclipse build.gradle
# 3. Eclipse 프로젝트 생성
-kjb-gradle.sh eclipse
+./gradlew eclipse
```
Eclipse 전용 설정(`build.gradle.eclipse`)은 다음을 포함합니다:
diff --git a/WebContent/WEB-INF/applicationContext-udpip.xml b/WebContent/WEB-INF/applicationContext-udpip.xml
index b473faf..58279fc 100644
--- a/WebContent/WEB-INF/applicationContext-udpip.xml
+++ b/WebContent/WEB-INF/applicationContext-udpip.xml
@@ -115,7 +115,7 @@
-
+
diff --git a/WebContent/jsp/onl/apim/approval/portalApprovalMan.jsp b/WebContent/jsp/onl/apim/approval/portalApprovalMan.jsp
index c00c10b..5c949b0 100644
--- a/WebContent/jsp/onl/apim/approval/portalApprovalMan.jsp
+++ b/WebContent/jsp/onl/apim/approval/portalApprovalMan.jsp
@@ -17,6 +17,7 @@