feat: WTM 멀티프로젝트 플랫폼 구축 (BE + FE 전체 구현)

Phase 0: wbx-spring-core 라이브러리 전환
- java-library 플러그인, WbxAutoConfiguration, Admin 조건부 활성화
- 루트 settings.gradle + build.gradle (멀티모듈)

Phase 1: wtm-api 모듈 생성
- 23개 JPA Entity, 14개 Controller, 79개 API 엔드포인트
- Flyway V100~V107 MySQL 마이그레이션
- TimesheetRuleEngine, TimesheetApprovalHandler, P6WbsParser

Phase 2: wtm-frontend (Vue 3 + PrimeVue 4)
- 10개 도메인 모듈, 17개 View, 5개 서브컴포넌트
- 반응형 레이아웃 (AppLayout, AppSidebar, AppTopbar)
- BaseCrudTable, BaseFormDialog, BasePageHeader 표준 컴포넌트
- JWT 인터셉터, 역할 기반 메뉴 필터링

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
이 Commit은 다음에 포함되어 있습니다:
2026-03-25 21:01:43 +09:00
부모 783865266b
커밋 df723f1d59
533개의 변경된 파일15528개의 추가작업 그리고 154개의 파일을 삭제

파일 보기

@@ -0,0 +1,215 @@
#!/usr/bin/env bash
# ============================================================
# WBX Spring Core — 프로덕션 배포 스크립트 (Linux)
# 사용법: sudo ./scripts/deploy-prod.sh
# ============================================================
set -euo pipefail
# ---------- 색상 ----------
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
ok() { echo -e " ${GREEN}[OK]${NC} $1"; }
warn() { echo -e " ${YELLOW}[WARN]${NC} $1"; }
fail() { echo -e " ${RED}[FAIL]${NC} $1"; exit 1; }
info() { echo -e " ${CYAN}[INFO]${NC} $1"; }
APP_DIR="/opt/wbx-app"
SERVICE_USER="wbxapp"
SERVICE_NAME="wbx-app"
JAR_NAME="app.jar"
echo ""
echo "=========================================="
echo " WBX Spring Core — 프로덕션 배포"
echo "=========================================="
echo ""
# ---------- Root 권한 ----------
if [ "$EUID" -ne 0 ]; then
fail "root 권한이 필요합니다: sudo $0"
fi
# ---------- 1. 서비스 계정 ----------
echo "1. 서비스 계정 (${SERVICE_USER})"
if id "$SERVICE_USER" &>/dev/null; then
ok "이미 존재"
else
useradd -r -m -s /bin/bash "$SERVICE_USER"
ok "생성 완료"
fi
# ---------- 2. 타임존/로케일 ----------
echo "2. 시스템 설정"
timedatectl set-timezone Asia/Seoul 2>/dev/null && ok "타임존: Asia/Seoul" || warn "타임존 설정 실패 — 수동 확인"
# ---------- 3. 디렉토리 ----------
echo "3. 디렉토리 구조"
mkdir -p "${APP_DIR}"/{logs,uploads,backup}
chown -R "${SERVICE_USER}:${SERVICE_USER}" "${APP_DIR}"
ok "${APP_DIR}/{logs,uploads,backup}"
# ---------- 4. 시스템 리밋 ----------
echo "4. 파일 디스크립터 리밋"
LIMITS_FILE="/etc/security/limits.d/${SERVICE_USER}.conf"
if [ ! -f "$LIMITS_FILE" ]; then
cat > "$LIMITS_FILE" << EOF
${SERVICE_USER} soft nofile 65535
${SERVICE_USER} hard nofile 65535
EOF
ok "${LIMITS_FILE} 생성"
else
ok "이미 존재"
fi
# ---------- 5. JAR 복사 ----------
echo "5. JAR 배포"
JAR_SOURCE="build/libs/wbx-spring-core-*.jar"
FOUND_JAR=$(ls $JAR_SOURCE 2>/dev/null | head -1)
if [ -z "$FOUND_JAR" ]; then
warn "JAR 파일 없음 — 먼저 ./gradlew bootJar 실행 필요"
else
# 이전 버전 백업
if [ -f "${APP_DIR}/${JAR_NAME}" ]; then
cp "${APP_DIR}/${JAR_NAME}" "${APP_DIR}/backup/${JAR_NAME}.$(date +%Y%m%d_%H%M%S)"
info "이전 JAR 백업 완료"
fi
cp "$FOUND_JAR" "${APP_DIR}/${JAR_NAME}"
chown "${SERVICE_USER}:${SERVICE_USER}" "${APP_DIR}/${JAR_NAME}"
ok "$(basename "$FOUND_JAR")${APP_DIR}/${JAR_NAME}"
fi
# ---------- 6. .env 템플릿 ----------
echo "6. 환경변수 파일"
if [ ! -f "${APP_DIR}/.env" ]; then
cat > "${APP_DIR}/.env" << 'ENVEOF'
# ===== WBX Spring Core — 프로덕션 환경변수 =====
SPRING_PROFILES_ACTIVE=prod,mysql
SERVER_CONTEXT_PATH=/
# JWT (필수 변경!)
JWT_SECRET=your-production-secret-key-minimum-256-bits-long
# DB
DB_HOST=localhost
DB_PORT=3306
DB_NAME=wbx_spring
DB_USER=wbxapp
DB_PASS=StrongP@ss
# Redis
SPRING_DATA_REDIS_HOST=localhost
# CORS
CORS_ORIGINS=https://app.company.com
# 로그
LOG_PATH=/opt/wbx-app/logs/app.log
ENVEOF
chown "${SERVICE_USER}:${SERVICE_USER}" "${APP_DIR}/.env"
chmod 600 "${APP_DIR}/.env"
ok "${APP_DIR}/.env 생성 (값을 반드시 수정하세요!)"
else
ok "이미 존재 — 건너뜀"
fi
# ---------- 7. systemd 서비스 ----------
echo "7. systemd 서비스"
SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service"
cat > "$SERVICE_FILE" << EOF
[Unit]
Description=WBX Spring Application
After=network.target
[Service]
Type=simple
User=${SERVICE_USER}
WorkingDirectory=${APP_DIR}
EnvironmentFile=${APP_DIR}/.env
ExecStart=/usr/bin/java \\
-XX:+UseG1GC \\
-XX:MaxRAMPercentage=75.0 \\
-Dspring.profiles.active=\${SPRING_PROFILES_ACTIVE} \\
-jar ${APP_DIR}/${JAR_NAME}
Restart=always
RestartSec=5
StandardOutput=append:${APP_DIR}/logs/app.log
StandardError=append:${APP_DIR}/logs/app.log
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable "$SERVICE_NAME" --quiet
ok "${SERVICE_FILE}"
# ---------- 8. 백업 cron ----------
echo "8. DB 백업 cron"
BACKUP_SCRIPT="${APP_DIR}/backup/db-backup.sh"
if [ ! -f "$BACKUP_SCRIPT" ]; then
cat > "$BACKUP_SCRIPT" << 'CRONEOF'
#!/usr/bin/env bash
# WBX Spring — DB 백업 (crontab: 0 2 * * *)
set -euo pipefail
source /opt/wbx-app/.env
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/opt/wbx-app/backup"
mysqldump -h"${DB_HOST}" -u"${DB_USER}" -p"${DB_PASS}" "${DB_NAME}" \
| gzip > "${BACKUP_DIR}/${DB_NAME}_${DATE}.sql.gz"
# 30일 이상 백업 삭제
find "${BACKUP_DIR}" -name '*.gz' -mtime +30 -delete
echo "[$(date)] backup done: ${DB_NAME}_${DATE}.sql.gz"
CRONEOF
chmod +x "$BACKUP_SCRIPT"
chown "${SERVICE_USER}:${SERVICE_USER}" "$BACKUP_SCRIPT"
ok "${BACKUP_SCRIPT} 생성"
# crontab 등록
CRON_LINE="0 2 * * * ${BACKUP_SCRIPT} >> ${APP_DIR}/logs/backup.log 2>&1"
(crontab -u "$SERVICE_USER" -l 2>/dev/null | grep -v "db-backup.sh"; echo "$CRON_LINE") \
| crontab -u "$SERVICE_USER" -
ok "crontab 등록 (매일 02:00)"
else
ok "이미 존재 — 건너뜀"
fi
# ---------- 9. 방화벽 ----------
echo "9. 방화벽"
if command -v firewall-cmd &>/dev/null; then
firewall-cmd --permanent --add-service=http --quiet 2>/dev/null || true
firewall-cmd --permanent --add-service=https --quiet 2>/dev/null || true
firewall-cmd --reload --quiet 2>/dev/null || true
ok "HTTP/HTTPS 허용"
else
warn "firewalld 없음 — 수동으로 방화벽 설정 필요"
fi
# ---------- 10. SELinux ----------
echo "10. SELinux"
if command -v setsebool &>/dev/null && getenforce 2>/dev/null | grep -qi enforcing; then
setsebool -P httpd_can_network_connect 1 2>/dev/null
ok "httpd_can_network_connect = 1"
else
info "SELinux 비활성 또는 미설치 — 건너뜀"
fi
# ---------- 결과 ----------
echo ""
echo "=========================================="
echo -e " ${GREEN}배포 준비 완료${NC}"
echo ""
echo " 체크리스트:"
echo " [ ] ${APP_DIR}/.env 값 수정 (JWT_SECRET, DB_PASS 필수!)"
echo " [ ] DB 생성 + 사용자 권한 부여"
echo " [ ] Redis 설치 + bind 127.0.0.1 + requirepass"
echo " [ ] JAR 빌드: ./gradlew bootJar"
echo " [ ] 서비스 시작: sudo systemctl start ${SERVICE_NAME}"
echo " [ ] 확인: curl http://localhost:8080/actuator/health"
echo " [ ] 리버스 프록시 설정 (Nginx/Caddy)"
echo " [ ] SSL 인증서 설치"
echo "=========================================="
echo ""

파일 보기

@@ -0,0 +1,51 @@
#!/usr/bin/env bash
# ============================================================
# Gitea 사용자 일괄 등록
# 사용법: ./scripts/gitea-bulk-create.sh users.csv
#
# CSV 형식 (헤더 없이):
# username,email,password
# hong,hong@company.com,P@ssw0rd123
# kim,kim@company.com,P@ssw0rd123
# ============================================================
set -euo pipefail
if [ $# -lt 1 ]; then
echo "사용법: $0 <users.csv>"
echo ""
echo "CSV 형식:"
echo " username,email,password"
echo " hong,hong@company.com,P@ssw0rd123"
exit 1
fi
CSV_FILE="$1"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
if [ ! -f "$CSV_FILE" ]; then
echo "파일을 찾을 수 없습니다: $CSV_FILE"
exit 1
fi
COUNT=0
FAIL=0
while IFS=',' read -r username email password; do
# 빈 줄, 주석 건너뜀
[[ -z "$username" || "$username" =~ ^# ]] && continue
# 공백 제거
username=$(echo "$username" | xargs)
email=$(echo "$email" | xargs)
password=$(echo "$password" | xargs)
echo "--- ${username} (${email}) ---"
if "${SCRIPT_DIR}/gitea-create-user.sh" "$username" "$email" "$password"; then
COUNT=$((COUNT + 1))
else
FAIL=$((FAIL + 1))
fi
done < "$CSV_FILE"
echo ""
echo "완료: 성공 ${COUNT}건, 실패 ${FAIL}"

파일 보기

@@ -0,0 +1,82 @@
#!/usr/bin/env bash
# ============================================================
# Gitea 사용자 등록 스크립트
# 사용법: ./scripts/gitea-create-user.sh <username> <email> <password>
# 환경변수: GITEA_URL, GITEA_ADMIN_USER, GITEA_ADMIN_PASS
# ============================================================
set -euo pipefail
# ---------- 색상 ----------
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
ok() { echo -e "${GREEN}[OK]${NC} $1"; }
fail() { echo -e "${RED}[FAIL]${NC} $1"; exit 1; }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
# ---------- 인자 ----------
if [ $# -lt 3 ]; then
echo "사용법: $0 <username> <email> <password>"
echo ""
echo "예시:"
echo " $0 hong hong@company.com P@ssw0rd123"
echo " $0 kim kim@company.com P@ssw0rd123"
echo ""
echo "환경변수 (선택):"
echo " GITEA_URL Gitea 서버 URL (기본: https://git.wbx.kr)"
echo " GITEA_ADMIN_USER 관리자 계정 (기본: accura)"
echo " GITEA_ADMIN_PASS 관리자 비밀번호"
exit 1
fi
USERNAME="$1"
EMAIL="$2"
PASSWORD="$3"
GITEA_URL="${GITEA_URL:-https://git.wbx.kr}"
GITEA_ADMIN_USER="${GITEA_ADMIN_USER:-accura}"
if [ -z "${GITEA_ADMIN_PASS:-}" ]; then
read -s -p "Gitea 관리자(${GITEA_ADMIN_USER}) 비밀번호: " GITEA_ADMIN_PASS
echo ""
fi
API="${GITEA_URL}/api/v1"
# ---------- 서버 연결 확인 ----------
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "${API}/version" 2>/dev/null || echo "000")
if [ "$HTTP_CODE" != "200" ]; then
fail "Gitea 서버 연결 실패: ${GITEA_URL} (HTTP ${HTTP_CODE})"
fi
# ---------- 중복 확인 ----------
EXISTS=$(curl -s -o /dev/null -w "%{http_code}" \
-u "${GITEA_ADMIN_USER}:${GITEA_ADMIN_PASS}" \
"${API}/users/${USERNAME}" 2>/dev/null)
if [ "$EXISTS" = "200" ]; then
warn "사용자 '${USERNAME}'이 이미 존재합니다."
exit 0
fi
# ---------- 사용자 생성 ----------
RESPONSE=$(curl -s -w "\n%{http_code}" \
-X POST "${API}/admin/users" \
-u "${GITEA_ADMIN_USER}:${GITEA_ADMIN_PASS}" \
-H "Content-Type: application/json" \
-d "{
\"username\": \"${USERNAME}\",
\"email\": \"${EMAIL}\",
\"password\": \"${PASSWORD}\",
\"must_change_password\": true,
\"visibility\": \"public\"
}" 2>/dev/null)
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
BODY=$(echo "$RESPONSE" | sed '$d')
if [ "$HTTP_CODE" = "201" ]; then
ok "사용자 생성 완료: ${USERNAME} (${EMAIL})"
echo "${GITEA_URL}/${USERNAME}"
echo " → 첫 로그인 시 비밀번호 변경 필요"
else
fail "사용자 생성 실패 (HTTP ${HTTP_CODE}): ${BODY}"
fi

파일 보기

@@ -0,0 +1,233 @@
@echo off
chcp 65001 >nul 2>&1
setlocal EnableDelayedExpansion
:: ============================================================
:: WBX Spring Core — Windows 설치 스크립트
:: 사용법: scripts\install.bat
:: ============================================================
:: ---------- 프로젝트 루트 설정 ----------
set "PROJECT_ROOT=%~dp0.."
pushd "!PROJECT_ROOT!" || (
echo [FAIL] 프로젝트 루트를 찾을 수 없습니다: %~dp0..
exit /b 1
)
echo.
echo ==========================================
echo WBX Spring Core — 설치 점검
echo ==========================================
echo.
set ERRORS=0
:: ---------- 1. JDK 21 ----------
echo 1. JDK 확인
set "JDK_OK=0"
where java >nul 2>&1
if !ERRORLEVEL! equ 0 (
for /f "tokens=3" %%v in ('java -version 2^>^&1 ^| findstr /i "version"') do (
set "JAVA_FULL=%%~v"
)
for /f "tokens=1 delims=." %%m in ("!JAVA_FULL!") do set "JAVA_MAJOR=%%m"
if !JAVA_MAJOR! GEQ 21 (
echo [OK] JDK !JAVA_FULL!
set "JDK_OK=1"
) else (
echo [INFO] JDK !JAVA_FULL! — 21 이상 필요, 자동 설치 시도...
)
) else (
echo [INFO] java 명령어 없음 — 자동 설치 시도...
)
if !JDK_OK! equ 0 (
where winget >nul 2>&1
if !ERRORLEVEL! equ 0 (
echo [INFO] winget으로 Eclipse Temurin JDK 21 설치 중...
winget install --id EclipseAdoptium.Temurin.21.JDK --accept-source-agreements --accept-package-agreements --silent
if !ERRORLEVEL! equ 0 (
:: 설치된 JDK를 PATH에 추가
for /d %%j in ("C:\Program Files\Eclipse Adoptium\jdk-21*") do (
set "JAVA_HOME=%%j"
)
if defined JAVA_HOME (
set "PATH=!JAVA_HOME!\bin;!PATH!"
echo [OK] JDK 21 설치 완료 — !JAVA_HOME!
echo [INFO] 시스템 PATH 반영을 위해 설치 후 새 터미널을 여세요.
) else (
echo [FAIL] JDK 설치 경로를 찾을 수 없습니다
set /a ERRORS+=1
)
) else (
echo [FAIL] JDK 설치 실패 — 수동으로 JDK 21을 설치하세요
set /a ERRORS+=1
)
) else (
echo [FAIL] winget 없음 — https://adoptium.net 에서 JDK 21을 수동 설치하세요
set /a ERRORS+=1
)
)
:: ---------- 2. Git ----------
echo 2. Git 확인
where git >nul 2>&1
if !ERRORLEVEL! equ 0 (
for /f "delims=" %%g in ('git --version') do echo [OK] %%g
) else (
echo [FAIL] git 없음
set /a ERRORS+=1
)
:: ---------- 3. Docker (선택) ----------
echo 3. Docker 확인 (선택)
where docker >nul 2>&1
if !ERRORLEVEL! equ 0 (
for /f "delims=" %%d in ('docker --version') do echo [OK] %%d
) else (
echo [WARN] Docker 미설치 — DB/Redis를 직접 설치해야 합니다
)
:: ---------- 4. Redis 확인 ----------
echo 4. Redis 확인
set "REDIS_OK=0"
where redis-cli >nul 2>&1
if !ERRORLEVEL! equ 0 (
redis-cli -h localhost -p 6379 ping 2>nul | findstr /i "PONG" >nul 2>&1
if !ERRORLEVEL! equ 0 (
echo [OK] Redis 응답 OK
set "REDIS_OK=1"
)
)
if !REDIS_OK! equ 0 (
where docker >nul 2>&1
if !ERRORLEVEL! equ 0 (
docker ps --format "{{.Names}}" 2>nul | findstr /i "redis" >nul 2>&1
if !ERRORLEVEL! equ 0 (
echo [OK] Redis Docker 컨테이너 실행 중
) else (
echo [INFO] Redis 미실행 — Docker로 자동 시작...
docker run -d --name redis -p 6379:6379 redis:7-alpine >nul 2>&1
if !ERRORLEVEL! equ 0 (
echo [OK] Redis 컨테이너 시작 완료
) else (
echo [WARN] Redis 자동 시작 실패 — 수동으로 Redis를 실행하세요
)
)
) else (
echo [WARN] Redis 연결 불가 — Redis를 설치/실행하세요
)
)
:: ---------- 5. MySQL 연결 확인 ----------
echo 5. MySQL 연결 확인
where mysql >nul 2>&1
if !ERRORLEVEL! equ 0 (
mysql -h"%DB_HOST%" -P"%DB_PORT%" -u"%DB_USER%" -p"%DB_PASS%" -e "USE %DB_NAME%;" >nul 2>&1
if !ERRORLEVEL! equ 0 (
echo [OK] MySQL 연결 OK ^(%DB_USER%@%DB_HOST%:%DB_PORT%/%DB_NAME%^)
) else (
echo [WARN] MySQL 연결 실패 — .env 의 DB 설정을 확인하세요
)
) else (
echo [INFO] mysql 클라이언트 없음 — DB 연결은 앱 시작 시 확인됩니다
)
:: ---------- 6. 빌드 ----------
echo 6. Gradle 빌드
if !ERRORS! GTR 0 (
echo [FAIL] 사전 요구사항 미충족 — 빌드 건너뜀
) else (
call "!PROJECT_ROOT!\gradlew.bat" build -x test --console=plain -q
if !ERRORLEVEL! equ 0 (
echo [OK] BUILD SUCCESSFUL
) else (
echo [FAIL] 빌드 실패
set /a ERRORS+=1
)
)
:: ---------- 7. .env 템플릿 ----------
echo 7. 환경변수 파일
if not exist "!PROJECT_ROOT!\.env" (
(
echo # ===== WBX Spring Core — 환경변수 =====
echo # 이 파일을 환경에 맞게 수정하세요.
echo.
echo # --- 프로필 ---
echo SPRING_PROFILES_ACTIVE=prod,mysql
echo.
echo # --- 서버 ---
echo SERVER_CONTEXT_PATH=/
echo.
echo # --- JWT ^(필수 변경^^^!^) ---
echo JWT_SECRET=your-production-secret-key-minimum-256-bits-long
echo.
echo # --- DB ---
echo DB_HOST=ws.ubuilder.co.kr
echo DB_PORT=3306
echo DB_NAME=mos
echo DB_USER=jsh
echo DB_PASS=jsh@
echo.
echo # --- Redis ---
echo SPRING_DATA_REDIS_HOST=localhost
echo.
echo # --- CORS ---
echo CORS_ORIGINS=https://app.company.com
echo.
echo # --- 로그 경로 ---
echo LOG_PATH=D:\wbx-app\logs\app.log
echo.
echo # --- Azure SSO ^(azure 프로필 사용 시^) ---
echo # AZURE_CLIENT_ID=
echo # AZURE_CLIENT_SECRET=
echo # AZURE_TENANT_ID=
echo.
echo # --- Azure Blob Storage ---
echo # AZURE_STORAGE_ACCOUNT=
echo # AZURE_STORAGE_KEY=
echo # AZURE_CONTAINER=uploads
echo.
echo # --- AWS Cognito ^(aws 프로필 사용 시^) ---
echo # AWS_COGNITO_CLIENT_ID=
echo # AWS_COGNITO_CLIENT_SECRET=
echo # AWS_USER_POOL_ID=
echo # AWS_REGION=ap-northeast-2
echo.
echo # --- AWS S3 ---
echo # AWS_S3_BUCKET=
echo # AWS_ACCESS_KEY=
echo # AWS_SECRET_KEY=
) > "!PROJECT_ROOT!\.env"
echo [OK] .env 생성 완료 (값을 수정하세요)
) else (
echo [WARN] .env 이미 존재 — 건너뜀
)
:: ---------- 8. 디렉토리 ----------
echo 8. 디렉토리 생성
if not exist "!PROJECT_ROOT!\logs" mkdir "!PROJECT_ROOT!\logs"
if not exist "!PROJECT_ROOT!\uploads" mkdir "!PROJECT_ROOT!\uploads"
if not exist "!PROJECT_ROOT!\backup" mkdir "!PROJECT_ROOT!\backup"
echo [OK] logs\ uploads\ backup\
:: ---------- 결과 ----------
echo.
echo ==========================================
if !ERRORS! equ 0 (
echo 설치 점검 완료
echo.
echo 다음 단계:
echo 1. .env 파일을 환경에 맞게 수정
echo 2. DB 생성 ^(또는 docker compose -f docker-compose-dev.yml up -d^)
echo 3. gradlew.bat bootRun
echo 4. http://localhost:8080/actuator/health 확인
) else (
echo 오류 !ERRORS!건 — 위의 [FAIL] 항목을 해결하세요
)
echo ==========================================
echo.
popd
endlocal

파일 보기

@@ -0,0 +1,272 @@
#!/usr/bin/env bash
# ============================================================
# WBX Spring Core — Linux/macOS 설치 스크립트
# 사용법: chmod +x scripts/install.sh && ./scripts/install.sh
# ============================================================
# ---------- 색상 ----------
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
ok() { echo -e " ${GREEN}[OK]${NC} $1"; }
warn() { echo -e " ${YELLOW}[WARN]${NC} $1"; }
fail() { echo -e " ${RED}[FAIL]${NC} $1"; }
info() { echo -e " ${CYAN}[INFO]${NC} $1"; }
ERRORS=0
# ---------- 프로젝트 루트 설정 ----------
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
cd "$PROJECT_ROOT" || { echo "[FAIL] 프로젝트 루트를 찾을 수 없습니다: $SCRIPT_DIR/.."; exit 1; }
echo ""
echo "=========================================="
echo " WBX Spring Core — 설치 점검"
echo "=========================================="
echo ""
# ---------- 1. JDK 21 ----------
echo "1. JDK 확인"
JDK_OK=0
if command -v java &>/dev/null; then
JAVA_VER=$(java -version 2>&1 | head -1 | awk -F '"' '{print $2}' | cut -d. -f1)
if [ "$JAVA_VER" -ge 21 ] 2>/dev/null; then
ok "JDK $JAVA_VER"
JDK_OK=1
else
info "JDK $JAVA_VER — 21 이상 필요, 자동 설치 시도..."
fi
else
info "java 명령어 없음 — 자동 설치 시도..."
fi
if [ $JDK_OK -eq 0 ]; then
if [[ "$(uname)" == "Darwin" ]]; then
# macOS — Homebrew
if command -v brew &>/dev/null; then
info "Homebrew로 Temurin JDK 21 설치 중..."
if brew install --cask temurin@21; then
export JAVA_HOME=$(/usr/libexec/java_home -v 21 2>/dev/null || true)
if [ -n "$JAVA_HOME" ]; then
export PATH="$JAVA_HOME/bin:$PATH"
ok "JDK 21 설치 완료 — $JAVA_HOME"
else
fail "JDK 설치 경로를 찾을 수 없습니다"
ERRORS=$((ERRORS + 1))
fi
else
fail "JDK 설치 실패 — 수동으로 JDK 21을 설치하세요"
ERRORS=$((ERRORS + 1))
fi
else
fail "Homebrew 없음 — https://adoptium.net 에서 JDK 21을 수동 설치하세요"
ERRORS=$((ERRORS + 1))
fi
else
# Linux — apt / yum / dnf
INSTALL_OK=0
if command -v apt-get &>/dev/null; then
info "apt로 Temurin JDK 21 설치 중..."
if sudo apt-get update -qq && sudo apt-get install -y temurin-21-jdk 2>/dev/null; then
INSTALL_OK=1
else
# Adoptium 저장소 추가 후 재시도
info "Adoptium 저장소 추가 중..."
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://packages.adoptium.net/artifactory/api/gpg/key/public | sudo tee /etc/apt/keyrings/adoptium.asc >/dev/null
echo "deb [signed-by=/etc/apt/keyrings/adoptium.asc] https://packages.adoptium.net/artifactory/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/adoptium.list >/dev/null
if sudo apt-get update -qq && sudo apt-get install -y temurin-21-jdk; then
INSTALL_OK=1
fi
fi
elif command -v yum &>/dev/null; then
info "yum으로 Temurin JDK 21 설치 중..."
if sudo yum install -y temurin-21-jdk 2>/dev/null; then
INSTALL_OK=1
else
info "Adoptium 저장소 추가 중..."
cat <<-REPO | sudo tee /etc/yum.repos.d/adoptium.repo >/dev/null
[Adoptium]
name=Adoptium
baseurl=https://packages.adoptium.net/artifactory/rpm/rhel/\$releasever/\$basearch
enabled=1
gpgcheck=1
gpgkey=https://packages.adoptium.net/artifactory/api/gpg/key/public
REPO
if sudo yum install -y temurin-21-jdk; then
INSTALL_OK=1
fi
fi
else
fail "패키지 관리자를 찾을 수 없음 — https://adoptium.net 에서 JDK 21을 수동 설치하세요"
ERRORS=$((ERRORS + 1))
fi
# 설치 결과 확인
if [ $INSTALL_OK -eq 1 ]; then
if command -v java &>/dev/null; then
JAVA_VER=$(java -version 2>&1 | head -1 | awk -F '"' '{print $2}' | cut -d. -f1)
if [ "$JAVA_VER" -ge 21 ] 2>/dev/null; then
ok "JDK 21 설치 완료"
else
fail "JDK 설치 후에도 버전이 21 미만입니다"
ERRORS=$((ERRORS + 1))
fi
else
fail "JDK 설치 후 java 명령어를 찾을 수 없습니다"
ERRORS=$((ERRORS + 1))
fi
elif [ $INSTALL_OK -eq 0 ] && command -v apt-get &>/dev/null || command -v yum &>/dev/null; then
fail "JDK 설치 실패 — 수동으로 JDK 21을 설치하세요"
ERRORS=$((ERRORS + 1))
fi
fi
fi
# ---------- 2. Git ----------
echo "2. Git 확인"
if command -v git &>/dev/null; then
ok "$(git --version)"
else
fail "git 없음"
ERRORS=$((ERRORS + 1))
fi
# ---------- 3. Docker (선택) ----------
echo "3. Docker 확인 (선택)"
if command -v docker &>/dev/null; then
ok "$(docker --version | head -1)"
else
warn "Docker 미설치 — DB/Redis를 직접 설치해야 합니다"
fi
# ---------- 4. Redis 확인 ----------
echo "4. Redis 확인"
REDIS_HOST="${SPRING_DATA_REDIS_HOST:-localhost}"
REDIS_PORT="${SPRING_DATA_REDIS_PORT:-6379}"
if command -v redis-cli &>/dev/null && redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" ping 2>/dev/null | grep -q PONG; then
ok "Redis 응답 OK ($REDIS_HOST:$REDIS_PORT)"
elif command -v docker &>/dev/null; then
if docker ps --format '{{.Names}}' 2>/dev/null | grep -q redis; then
ok "Redis Docker 컨테이너 실행 중"
else
info "Redis 미실행 — Docker로 자동 시작..."
if docker run -d --name redis -p "${REDIS_PORT}:6379" redis:7-alpine &>/dev/null; then
ok "Redis 컨테이너 시작 완료"
else
warn "Redis 자동 시작 실패 — 수동으로 Redis를 실행하세요"
fi
fi
else
warn "Redis 연결 불가 ($REDIS_HOST:$REDIS_PORT) — Redis를 설치/실행하세요"
fi
# ---------- 5. MySQL 연결 확인 ----------
echo "5. MySQL 연결 확인"
DB_HOST="${DB_HOST:-ws.ubuilder.co.kr}"
DB_PORT="${DB_PORT:-3306}"
DB_NAME="${DB_NAME:-mos}"
DB_USER="${DB_USER:-jsh}"
if command -v mysql &>/dev/null; then
if mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"${DB_PASS:-}" -e "USE $DB_NAME;" 2>/dev/null; then
ok "MySQL 연결 OK ($DB_USER@$DB_HOST:$DB_PORT/$DB_NAME)"
else
warn "MySQL 연결 실패 — .env 의 DB 설정을 확인하세요"
fi
else
info "mysql 클라이언트 없음 — DB 연결은 앱 시작 시 확인됩니다"
fi
# ---------- 6. 빌드 ----------
echo "6. Gradle 빌드"
if [ $ERRORS -gt 0 ]; then
fail "사전 요구사항 미충족 — 빌드 건너뜀"
else
chmod +x "$PROJECT_ROOT/gradlew"
if "$PROJECT_ROOT/gradlew" build -x test --console=plain -q; then
ok "BUILD SUCCESSFUL"
else
fail "빌드 실패"
ERRORS=$((ERRORS + 1))
fi
fi
# ---------- 7. .env 템플릿 ----------
echo "7. 환경변수 파일"
if [ ! -f "$PROJECT_ROOT/.env" ]; then
cat > "$PROJECT_ROOT/.env" << 'ENVEOF'
# ===== WBX Spring Core — 환경변수 =====
# 이 파일을 환경에 맞게 수정하세요.
# --- 프로필 ---
SPRING_PROFILES_ACTIVE=prod,mysql
# --- 서버 ---
SERVER_CONTEXT_PATH=/
# --- JWT (필수 변경!) ---
JWT_SECRET=your-production-secret-key-minimum-256-bits-long
# --- DB ---
DB_HOST=ws.ubuilder.co.kr
DB_PORT=3306
DB_NAME=mos
DB_USER=jsh
DB_PASS=jsh@
# --- Redis ---
SPRING_DATA_REDIS_HOST=localhost
# --- CORS ---
CORS_ORIGINS=https://app.company.com
# --- 로그 경로 ---
LOG_PATH=/opt/wbx-app/logs/app.log
# --- Azure SSO (azure 프로필 사용 시) ---
# AZURE_CLIENT_ID=
# AZURE_CLIENT_SECRET=
# AZURE_TENANT_ID=
# --- Azure Blob Storage ---
# AZURE_STORAGE_ACCOUNT=
# AZURE_STORAGE_KEY=
# AZURE_CONTAINER=uploads
# --- AWS Cognito (aws 프로필 사용 시) ---
# AWS_COGNITO_CLIENT_ID=
# AWS_COGNITO_CLIENT_SECRET=
# AWS_USER_POOL_ID=
# AWS_REGION=ap-northeast-2
# --- AWS S3 ---
# AWS_S3_BUCKET=
# AWS_ACCESS_KEY=
# AWS_SECRET_KEY=
ENVEOF
chmod 600 "$PROJECT_ROOT/.env"
ok ".env 생성 완료 (값을 수정하세요)"
else
warn ".env 이미 존재 — 건너뜀"
fi
# ---------- 8. 디렉토리 ----------
echo "8. 디렉토리 생성"
mkdir -p "$PROJECT_ROOT/logs" "$PROJECT_ROOT/uploads" "$PROJECT_ROOT/backup"
ok "logs/ uploads/ backup/"
# ---------- 결과 ----------
echo ""
echo "=========================================="
if [ $ERRORS -eq 0 ]; then
echo -e " ${GREEN}설치 점검 완료${NC}"
echo ""
echo " 다음 단계:"
echo " 1. .env 파일을 환경에 맞게 수정"
echo " 2. DB 생성 (또는 docker compose -f docker-compose-dev.yml up -d)"
echo " 3. ./gradlew bootRun"
echo " 4. http://localhost:8080/actuator/health 확인"
else
echo -e " ${RED}오류 ${ERRORS}건 — 위의 [FAIL] 항목을 해결하세요${NC}"
fi
echo "=========================================="
echo ""

파일 보기

@@ -0,0 +1,5 @@
@echo off
set "JAVA_HOME=C:\Program Files\Eclipse Adoptium\jdk-21.0.10.7-hotspot"
set "PATH=%JAVA_HOME%\bin;%PATH%"
cd /d "%~dp0.."
call scripts\install.bat