diff --git a/.gitignore b/.gitignore index 26fdcbad..c97a31dc 100644 --- a/.gitignore +++ b/.gitignore @@ -245,3 +245,31 @@ cache/ .vscode/settings.json .idea/workspace.xml *.user + +# ===== Gradle 관련 파일들 (레거시 Java 프로젝트) ===== +# Gradle 캐시 및 빌드 파일들 +.gradle/ +*/.gradle/ +gradle/ +gradlew +gradlew.bat +gradle.properties +build/ +*/build/ + +# Gradle Wrapper +gradle-wrapper.jar +gradle-wrapper.properties + +# IntelliJ IDEA 관련 (Gradle 프로젝트) +.idea/ +*.iml +*.ipr +*.iws +out/ + +# Eclipse 관련 (Gradle 프로젝트) +.project +.classpath +.settings/ +bin/ diff --git a/DOCKER.md b/DOCKER.md new file mode 100644 index 00000000..59ddbdbf --- /dev/null +++ b/DOCKER.md @@ -0,0 +1,386 @@ +# 🐳 Docker 가이드 - PLM 솔루션 (ERP-node) + +이 문서는 PLM 솔루션의 Docker 환경 설정 및 사용법을 설명합니다. + +## 📋 개요 + +**기술 스택:** + +- **백엔드**: Node.js + TypeScript + Prisma + PostgreSQL +- **프론트엔드**: Next.js + TypeScript + Tailwind CSS +- **컨테이너**: Docker + Docker Compose + +**환경:** + +- **개발**: Mac (볼륨 마운트 + Hot Reload) +- **운영**: Linux 서버 (최적화된 프로덕션 빌드) + +--- + +## 🔧 개발 환경 (Mac) + +### 빠른 시작 + +```bash +# 전체 서비스 시작 (병렬 빌드 - 가장 빠름!) +./scripts/dev/start-all-parallel.sh +``` + +### 개별 서비스 시작 + +```bash +# 백엔드만 시작 +./scripts/dev/start-backend.sh + +# 프론트엔드만 시작 +./scripts/dev/start-frontend.sh +``` + +### 개발용 Docker Compose 파일들 + +- **`docker/dev/docker-compose.backend.mac.yml`** - Mac 개발용 백엔드 + + - 볼륨 마운트: `./backend-node:/app` (Hot Reload) + - Dockerfile: `docker/dev/backend.Dockerfile` + - 포트: `8080` + +- **`docker/dev/docker-compose.frontend.mac.yml`** - Mac 개발용 프론트엔드 + - 볼륨 마운트: `./frontend:/app` (Hot Reload) + - Dockerfile: `docker/dev/frontend.Dockerfile` + - 포트: `3000` + +### 개발 환경 특징 + +- ✅ **Hot Reload**: 코드 변경 시 자동 반영 +- ✅ **볼륨 마운트**: 실시간 개발 +- ✅ **디버그 모드**: 상세 로그 출력 +- ✅ **빠른 재시작**: Docker 재빌드 불필요 + +### 🔥 Hot Reload 상세 가이드 + +#### ✅ **바로 반영되는 것들 (즉시 Hot Reload)** + +**백엔드 (Node.js + TypeScript):** + +```bash +backend-node/src/controllers/*.ts # API 컨트롤러 수정 +backend-node/src/services/*.ts # 비즈니스 로직 수정 +backend-node/src/routes/*.ts # 라우터 설정 수정 +backend-node/src/middleware/*.ts # 미들웨어 수정 +backend-node/src/utils/*.ts # 유틸리티 함수 수정 +backend-node/src/types/*.ts # 타입 정의 수정 +backend-node/src/config/*.ts # 애플리케이션 설정 +``` + +→ **반영 시간**: 1-2초 (nodemon 자동 재시작) + +**프론트엔드 (Next.js + TypeScript):** + +```bash +frontend/components/**/*.tsx # React 컴포넌트 수정 +frontend/app/**/*.tsx # 페이지 컴포넌트 수정 +frontend/lib/**/*.ts # 유틸리티 함수 수정 +frontend/hooks/*.ts # 커스텀 훅 수정 +frontend/types/*.ts # 타입 정의 수정 +frontend/constants/*.ts # 상수 정의 수정 +CSS/SCSS 파일 수정 # 스타일 변경 +``` + +→ **반영 시간**: 즉시 (Fast Refresh) + +#### ❌ **Docker 재시작이 필요한 것들** + +**의존성 변경:** + +```bash +package.json 수정 # 새 패키지 추가/제거 +npm install / npm uninstall # 패키지 설치/제거 +package-lock.json 변경 # 의존성 잠금 파일 +``` + +**Prisma 관련:** + +```bash +backend-node/prisma/schema.prisma # DB 스키마 변경 +npx prisma migrate # 마이그레이션 실행 +npx prisma generate # 클라이언트 재생성 +``` + +**설정 파일:** + +```bash +next.config.mjs # Next.js 설정 +tsconfig.json # TypeScript 설정 +tailwind.config.js # Tailwind CSS 설정 +.env / .env.local # 환경 변수 +eslint.config.mjs # ESLint 설정 +``` + +**Docker 관련:** + +```bash +Dockerfile / Dockerfile.dev # 도커 파일 수정 +docker-compose.*.yml # Docker Compose 설정 +.dockerignore # Docker 무시 파일 +``` + +#### 🔄 **재시작 방법** + +**특정 서비스만 재시작:** + +```bash +# 백엔드만 재시작 +docker-compose -f docker-compose.backend.mac.yml restart backend + +# 프론트엔드만 재시작 +docker-compose -f docker-compose.frontend.mac.yml restart frontend +``` + +**전체 재빌드:** + +```bash +# 의존성 변경 시 (rebuild 필요) +docker-compose -f docker-compose.backend.mac.yml up --build -d +docker-compose -f docker-compose.frontend.mac.yml up --build -d +``` + +--- + +## 🚀 운영 환경 (Linux) + +### 운영 서버 배포 + +```bash +# Linux 서버에서 실행 +./scripts/prod/start-all-linux.sh +``` + +### 개별 서비스 시작 (운영용) + +```bash +# 직접 Docker Compose 사용 +docker-compose -f docker/prod/docker-compose.backend.prod.yml up -d +docker-compose -f docker/prod/docker-compose.frontend.prod.yml up -d +``` + +### 운영용 Docker Compose 파일들 + +- **`docker/prod/docker-compose.backend.prod.yml`** - 운영용 백엔드 + + - Dockerfile: `docker/prod/backend.Dockerfile` (프로덕션 최적화) + - 포트: `8080` + - 환경: `NODE_ENV=production` + +- **`docker/prod/docker-compose.frontend.prod.yml`** - 운영용 프론트엔드 + - Dockerfile: `docker/prod/frontend.Dockerfile` (프로덕션 최적화) + - 포트: `3000` + - 환경: 최적화된 빌드 + +### 운영 환경 특징 + +- ✅ **최적화된 빌드**: 프로덕션용 이미지 +- ✅ **보안 강화**: 운영 환경 설정 +- ✅ **성능 최적화**: 이미지 크기 최소화 +- ✅ **안정성**: 프로덕션 모드 + +--- + +## 📁 프로젝트 구조 + +``` +ERP-node/ +├── 🔧 개발용 (Mac) +│ ├── start-all-parallel.sh # 병렬 시작 (추천) +│ ├── start-backend.sh # 백엔드만 +│ ├── start-frontend.sh # 프론트엔드만 +│ ├── docker-compose.backend.mac.yml # Mac 개발용 백엔드 +│ └── docker-compose.frontend.mac.yml# Mac 개발용 프론트엔드 +│ +├── 🚀 운영용 (Linux) +│ ├── start-all-separated-linux.sh # Linux 운영용 +│ ├── start-backend-linux.sh # 백엔드만 (Linux) +│ ├── start-frontend-linux.sh # 프론트엔드만 (Linux) +│ ├── docker-compose.backend.prod.yml# 운영용 백엔드 +│ └── docker-compose.frontend.prod.yml# 운영용 프론트엔드 +│ +├── 📁 백엔드 +│ ├── backend-node/ +│ │ ├── Dockerfile # 프로덕션용 +│ │ └── Dockerfile.dev # 개발용 +│ └── src/, prisma/, package.json... +│ +├── 📁 프론트엔드 +│ ├── frontend/ +│ │ ├── Dockerfile # 프로덕션용 +│ │ └── Dockerfile.dev # 개발용 +│ └── app/, components/, hooks/... +│ +└── 🗂️ 기타 + ├── db/00-create-roles.sh # DB 초기화 + └── README.md, DOCKER.md... +``` + +--- + +## 🌐 접속 정보 + +### 개발 환경 + +- **프론트엔드**: http://localhost:3000 +- **백엔드 API**: http://localhost:8080 +- **전체 앱**: http://localhost:9771 (프록시 설정 시) + +### 운영 환경 + +- **서버 IP에 따라 다름** (Linux 서버 설정 확인) + +--- + +## 🛠️ 주요 명령어 + +### Docker 컨테이너 관리 + +```bash +# 실행 중인 컨테이너 확인 +docker ps + +# 모든 컨테이너 중지 +docker stop $(docker ps -q) + +# 사용하지 않는 컨테이너/이미지 정리 +docker system prune -f +``` + +### 로그 확인 + +```bash +# 백엔드 로그 +docker logs pms-backend-mac -f # 개발용 +docker logs pms-backend-prod -f # 운영용 + +# 프론트엔드 로그 +docker logs pms-frontend-mac -f # 개발용 +docker logs pms-frontend-prod -f # 운영용 +``` + +### 컨테이너 내부 접속 + +```bash +# 백엔드 컨테이너 접속 +docker exec -it pms-backend-mac bash # 개발용 +docker exec -it pms-backend-prod bash # 운영용 + +# 프론트엔드 컨테이너 접속 +docker exec -it pms-frontend-mac sh # 개발용 +docker exec -it pms-frontend-prod sh # 운영용 +``` + +--- + +## 🚨 트러블슈팅 + +### 자주 발생하는 문제들 + +#### 1. 포트 충돌 + +```bash +# 포트 사용 중인 프로세스 확인 +lsof -i :8080 +lsof -i :3000 + +# 프로세스 종료 +kill -9 +``` + +#### 2. Docker 빌드 오류 + +```bash +# Docker 캐시 클리어 후 재빌드 +docker builder prune -f +./start-all-parallel.sh +``` + +#### 3. 볼륨 마운트 문제 (개발환경) + +```bash +# Docker Desktop 설정에서 파일 공유 확인 +# Docker Desktop > Settings > Resources > File Sharing +``` + +#### 4. 데이터베이스 연결 오류 + +```bash +# 데이터베이스 초기화 +./db/00-create-roles.sh + +# PostgreSQL 연결 확인 +docker exec -it psql -U postgres +``` + +### Warning 메시지들 (무시해도 됨) + +``` +WARN: the attribute `version` is obsolete +Network Error (일시적) +``` + +이런 메시지들은 Docker Compose 버전 차이로 발생하며, 기능에는 영향 없습니다. + +--- + +## 📈 성능 최적화 + +### 개발 환경 최적화 + +- ✅ **병렬 빌드**: `start-all-parallel.sh` 사용 +- ✅ **Docker 캐시**: `--no-cache` 제거됨 +- ✅ **npm 최적화**: `--prefer-offline --no-audit` 적용 + +### 운영 환경 최적화 + +- ✅ **멀티 스테이지 빌드**: Dockerfile 최적화 +- ✅ **이미지 크기 최소화**: Alpine Linux 기반 +- ✅ **의존성 캐시**: 레이어 캐싱 활용 + +--- + +## 🔄 업데이트 가이드 + +### 개발 환경 업데이트 + +```bash +# 코드 변경 시 (Hot Reload 자동 반영) +# 별도 작업 불필요 + +# 의존성 변경 시 +docker-compose -f docker-compose.backend.mac.yml up --build -d +``` + +### 운영 환경 업데이트 + +```bash +# 새로운 버전 배포 +./start-all-separated-linux.sh +``` + +--- + +## 📞 지원 + +**문제 발생 시:** + +1. 이 문서의 트러블슈팅 섹션 확인 +2. Docker 로그 확인 (`docker logs `) +3. 개발팀에 문의 + +**프로젝트 관련:** + +- Node.js 백엔드: `backend-node/` 디렉토리 +- Next.js 프론트엔드: `frontend/` 디렉토리 +- 데이터베이스: PostgreSQL (JNDI 설정) + +--- + +**버전**: 1.0.0 +**마지막 업데이트**: 2024년 12월 28일 +**작성자**: PLM 개발팀 diff --git a/DOCKER_SETUP.md b/DOCKER_SETUP.md deleted file mode 100644 index 037f1c0d..00000000 --- a/DOCKER_SETUP.md +++ /dev/null @@ -1,321 +0,0 @@ -# PLM WACE Docker 설정 가이드 - -## 개요 -이 문서는 PLM WACE 애플리케이션을 Docker로 실행하는 방법을 설명합니다. - -## 시스템 요구사항 - -### 리눅스 환경 -- Ubuntu 18.04 이상 또는 CentOS 7 이상 -- Docker 20.10 이상 -- Docker Compose 1.29 이상 -- Git (운영환경 배포 시) - -### 필수 소프트웨어 설치 - -#### Docker 설치 (Ubuntu) -```bash -# Docker 공식 GPG 키 추가 -curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg - -# Docker 리포지토리 추가 -echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null - -# Docker 설치 -sudo apt update -sudo apt install docker-ce docker-ce-cli containerd.io - -# Docker Compose 설치 -sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose -sudo chmod +x /usr/local/bin/docker-compose - -# 사용자를 docker 그룹에 추가 -sudo usermod -aG docker $USER -``` - -#### Docker 설치 (CentOS) -```bash -# Docker 설치 -sudo yum install -y yum-utils -sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo -sudo yum install docker-ce docker-ce-cli containerd.io - -# Docker Compose 설치 -sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose -sudo chmod +x /usr/local/bin/docker-compose - -# Docker 서비스 시작 -sudo systemctl start docker -sudo systemctl enable docker - -# 사용자를 docker 그룹에 추가 -sudo usermod -aG docker $USER -``` - -## 환경 설정 - -### 1. 환경 변수 파일 생성 - -#### 개발환경 -```bash -# 개발환경 환경 변수 파일 생성 -cp env.development.example .env.development - -# 필요에 따라 설정 수정 -vim .env.development -``` - -#### 운영환경 -```bash -# 운영환경 환경 변수 파일 생성 -cp env.production.example .env.production - -# 운영환경에 맞게 설정 수정 (특히 비밀번호) -vim .env.production -``` - -### 2. 환경 변수 설정 항목 - -#### 주요 설정 항목 -- `DB_URL`: 데이터베이스 연결 URL -- `DB_USERNAME`: 데이터베이스 사용자명 -- `DB_PASSWORD`: 데이터베이스 비밀번호 -- `JAVA_OPTS`: JVM 옵션 (메모리 설정 등) -- `LOG_LEVEL`: 로그 레벨 (DEBUG, INFO, WARN, ERROR) - -## 스크립트 사용법 - -### 기본 사용법 -```bash -# 실행 권한 부여 (최초 1회) -chmod +x start-docker-linux.sh - -# 개발환경 실행 -./start-docker-linux.sh - -# 운영환경 실행 -./start-docker-linux.sh -e prod -``` - -### 주요 옵션 - -#### 환경 설정 -```bash -# 개발환경 실행 -./start-docker-linux.sh -e dev - -# 운영환경 실행 -./start-docker-linux.sh -e prod -``` - -#### 컨테이너 관리 -```bash -# 컨테이너 중지 -./start-docker-linux.sh -s - -# 컨테이너 재시작 -./start-docker-linux.sh -r - -# Docker 시스템 정리 후 실행 -./start-docker-linux.sh -c -``` - -#### 로그 및 모니터링 -```bash -# 실시간 로그 확인 -./start-docker-linux.sh -l - -# 도움말 확인 -./start-docker-linux.sh -h -``` - -### 옵션 조합 -```bash -# 개발환경에서 Docker 정리 후 재시작 -./start-docker-linux.sh -e dev -c -r - -# 운영환경에서 재시작 -./start-docker-linux.sh -e prod -r -``` - -## 접속 정보 - -### 개발환경 -- 애플리케이션: http://localhost:8090 -- 데이터베이스: localhost:5432 (내부 DB 사용 시) - -### 운영환경 -- 애플리케이션: https://ilshin.esgrin.com -- 대체 도메인: https://autoclave.co.kr - -## 트러블슈팅 - -### 일반적인 문제 - -#### 1. Docker 서비스 오류 -```bash -# Docker 서비스 상태 확인 -sudo systemctl status docker - -# Docker 서비스 시작 -sudo systemctl start docker - -# Docker 서비스 자동 시작 설정 -sudo systemctl enable docker -``` - -#### 2. 권한 오류 -```bash -# 사용자를 docker 그룹에 추가 -sudo usermod -aG docker $USER - -# 로그아웃 후 재로그인 또는 그룹 변경 적용 -newgrp docker -``` - -#### 3. 포트 충돌 -```bash -# 포트 사용 확인 -sudo netstat -tlnp | grep :8090 - -# 프로세스 종료 -sudo kill -9 -``` - -#### 4. 환경 변수 파일 오류 -```bash -# 환경 변수 파일 존재 확인 -ls -la .env.* - -# 환경 변수 파일 내용 확인 -cat .env.development -``` - -### 로그 확인 - -#### 컨테이너 로그 -```bash -# 전체 로그 확인 -./start-docker-linux.sh -l - -# 특정 서비스 로그 확인 -docker-compose -f docker-compose.dev.yml logs plm-ilshin - -# 로그 파일 확인 (컨테이너 내부) -docker exec -it plm-ilshin-container tail -f /usr/local/tomcat/logs/catalina.out -``` - -#### 시스템 로그 -```bash -# Docker 데몬 로그 확인 -sudo journalctl -u docker.service - -# 시스템 로그 확인 -sudo journalctl -xe -``` - -## 고급 사용법 - -### 수동 Docker Compose 사용 -```bash -# 개발환경 수동 실행 -docker-compose -f docker-compose.dev.yml up -d - -# 운영환경 수동 실행 -docker-compose -f docker-compose.prod.yml up -d - -# 컨테이너 중지 -docker-compose -f docker-compose.dev.yml down -``` - -### 컨테이너 내부 접근 -```bash -# 컨테이너 내부 접근 -docker exec -it plm-ilshin-container bash - -# 데이터베이스 접근 (내부 DB 사용 시) -docker exec -it plm-ilshin-db-container psql -U postgres -d ilshin -``` - -### 백업 및 복원 -```bash -# 데이터베이스 백업 -docker exec plm-ilshin-db-container pg_dump -U postgres ilshin > backup.sql - -# 데이터베이스 복원 -docker exec -i plm-ilshin-db-container psql -U postgres ilshin < backup.sql -``` - -## 보안 고려사항 - -### 운영환경 보안 -1. 환경 변수 파일 권한 설정 - ```bash - chmod 600 .env.production - ``` - -2. 방화벽 설정 - ```bash - # 필요한 포트만 열기 - sudo ufw allow 80/tcp - sudo ufw allow 443/tcp - sudo ufw enable - ``` - -3. SSL 인증서 설정 (Traefik 사용) - - Let's Encrypt 자동 갱신 설정 - - 도메인 검증 설정 - -### 개발환경 보안 -1. 개발용 비밀번호 사용 -2. 외부 접근 제한 -3. 정기적인 이미지 업데이트 - -## 성능 최적화 - -### JVM 튜닝 -```bash -# .env 파일에서 JVM 옵션 조정 -JAVA_OPTS=-Xms1024m -Xmx2048m -XX:PermSize=512m -XX:MaxPermSize=1024m -``` - -### Docker 리소스 제한 -```yaml -# docker-compose.yml에서 리소스 제한 -services: - plm-ilshin: - deploy: - resources: - limits: - cpus: '2.0' - memory: 2G - reservations: - cpus: '1.0' - memory: 1G -``` - -## 모니터링 - -### 컨테이너 상태 모니터링 -```bash -# 컨테이너 상태 확인 -docker ps - -# 리소스 사용량 확인 -docker stats - -# 컨테이너 로그 모니터링 -docker logs -f plm-ilshin-container -``` - -### 애플리케이션 모니터링 -- 애플리케이션 로그 확인 -- 데이터베이스 연결 상태 확인 -- 메모리 사용량 모니터링 - -## 지원 및 문의 - -문제가 발생하거나 추가 도움이 필요한 경우: -1. 로그 파일 확인 -2. 환경 설정 검토 -3. 개발팀 문의 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 3d1a3cd1..00000000 --- a/Dockerfile +++ /dev/null @@ -1,20 +0,0 @@ -FROM localhost:8787/tomcat:7.0.94-jre7-alpine.linux AS production - -# Remove default webapps -RUN rm -rf /usr/local/tomcat/webapps/* - -# Copy web application content (compiled classes and web resources) -COPY WebContent /usr/local/tomcat/webapps/ROOT -COPY src /usr/local/tomcat/webapps/ROOT/WEB-INF/src - -# Copy custom Tomcat context configuration for JNDI -COPY ./tomcat-conf/context.xml /usr/local/tomcat/conf/context.xml - -# Copy database driver if needed (PostgreSQL driver is already in WEB-INF/lib) -# COPY path/to/postgresql-driver.jar /usr/local/tomcat/lib/ - -# Expose Tomcat port -EXPOSE 8080 - -# Start Tomcat -CMD ["catalina.sh", "run"] \ No newline at end of file diff --git a/Dockerfile.dev b/Dockerfile.dev deleted file mode 100644 index bab0fe55..00000000 --- a/Dockerfile.dev +++ /dev/null @@ -1,20 +0,0 @@ -FROM localhost:8787/tomcat:7.0.94-jre7-alpine.linux AS Development - -# Remove default webapps -RUN rm -rf /usr/local/tomcat/webapps/* - -# Copy web application content (compiled classes and web resources) -COPY WebContent /usr/local/tomcat/webapps/ROOT -COPY src /usr/local/tomcat/webapps/ROOT/WEB-INF/src - -# Copy custom Tomcat context configuration for JNDI -COPY ./tomcat-conf/context.xml /usr/local/tomcat/conf/context.xml - -# Copy database driver if needed (PostgreSQL driver is already in WEB-INF/lib) -# COPY path/to/postgresql-driver.jar /usr/local/tomcat/lib/ - -# Expose Tomcat port -EXPOSE 8080 - -# Start Tomcat -CMD ["catalina.sh", "run"] \ No newline at end of file diff --git a/Dockerfile.win b/Dockerfile.win deleted file mode 100644 index 4a4d07ee..00000000 --- a/Dockerfile.win +++ /dev/null @@ -1,47 +0,0 @@ -# 윈도우용 PLM 애플리케이션 Dockerfile -FROM tomcat:7.0.94-jre7-alpine - -# 메타데이터 -LABEL maintainer="PLM Development Team" -LABEL description="PLM Application for Windows Environment" -LABEL version="1.0" - -# 작업 디렉토리 설정 -WORKDIR /usr/local/tomcat - -# 필수 패키지 설치 (curl 포함) -RUN apk add --no-cache curl tzdata - -# 환경 변수 설정 -ENV CATALINA_HOME=/usr/local/tomcat -ENV CATALINA_BASE=/usr/local/tomcat -ENV JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms512m -Xmx1024m" -ENV TZ=Asia/Seoul - -# 타임존 설정 (서울) -RUN cp /usr/share/zoneinfo/Asia/Seoul /etc/localtime && \ - echo "Asia/Seoul" > /etc/timezone - -# 기본 Tomcat 애플리케이션 제거 -RUN rm -rf /usr/local/tomcat/webapps/* - -# 애플리케이션 복사 -COPY WebContent/ /usr/local/tomcat/webapps/ROOT/ -COPY tomcat-conf/context.xml /usr/local/tomcat/conf/ - -# 로그 디렉토리 생성 -RUN mkdir -p /usr/local/tomcat/logs - -# 권한 설정 -RUN chmod -R 755 /usr/local/tomcat/webapps/ROOT && \ - chmod 644 /usr/local/tomcat/conf/context.xml - -# 포트 노출 -EXPOSE 8080 - -# 개선된 헬스체크 (윈도우 환경 고려) -HEALTHCHECK --interval=30s --timeout=15s --start-period=90s --retries=5 \ - CMD curl -f http://localhost:8080/ROOT/ || curl -f http://localhost:8080/ || exit 1 - -# 실행 명령 -CMD ["catalina.sh", "run"] \ No newline at end of file diff --git a/backend-build-only.bat b/backend-build-only.bat deleted file mode 100644 index 84711cbe..00000000 --- a/backend-build-only.bat +++ /dev/null @@ -1,14 +0,0 @@ -@echo off -echo ================================= -echo 백엔드 빌드만 실행 -echo ================================= - -cd /d %~dp0 - -echo [1/1] 백엔드 빌드 중... -docker-compose -f docker-compose.springboot.yml build backend - -echo. -echo 백엔드 빌드 완료! -echo. -pause \ No newline at end of file diff --git a/backend-gradle-build.bat b/backend-gradle-build.bat deleted file mode 100644 index aaf0e167..00000000 --- a/backend-gradle-build.bat +++ /dev/null @@ -1,32 +0,0 @@ -@echo off -echo ================================= -echo Gradle 백엔드 로컬 빌드 -echo ================================= - -cd /d %~dp0\backend - -echo [1/3] Gradle 권한 설정... -if not exist "gradlew.bat" ( - echo gradlew.bat 파일을 찾을 수 없습니다. - pause - exit /b 1 -) - -echo [2/3] 이전 빌드 정리... -call gradlew clean - -echo [3/3] 프로젝트 빌드... -call gradlew build -x test - -if %errorlevel% equ 0 ( - echo. - echo 백엔드 빌드 성공! - echo JAR 파일 위치: backend\build\libs\ - echo. -) else ( - echo. - echo 빌드 실패! 오류를 확인하세요. - echo. -) - -pause \ No newline at end of file diff --git a/backend-logs.bat b/backend-logs.bat deleted file mode 100644 index 05f8d2ef..00000000 --- a/backend-logs.bat +++ /dev/null @@ -1,12 +0,0 @@ -@echo off -echo ================================= -echo 백엔드 로그 확인 -echo ================================= - -cd /d %~dp0 - -echo 백엔드 컨테이너 로그를 실시간으로 확인합니다... -echo Ctrl+C를 눌러서 종료할 수 있습니다. -echo. - -docker-compose -f docker-compose.springboot.yml logs -f backend \ No newline at end of file diff --git a/backend-node/src/controllers/adminController.ts b/backend-node/src/controllers/adminController.ts index 2ebfcb28..0ec055ba 100644 --- a/backend-node/src/controllers/adminController.ts +++ b/backend-node/src/controllers/adminController.ts @@ -3,10 +3,13 @@ import { logger } from "../utils/logger"; import { AuthenticatedRequest } from "../types/auth"; import { ApiResponse } from "../types/common"; import { Client } from "pg"; +import { PrismaClient } from "@prisma/client"; import config from "../config/environment"; import { AdminService } from "../services/adminService"; import { EncryptUtil } from "../utils/encryptUtil"; +const prisma = new PrismaClient(); + /** * 관리자 메뉴 목록 조회 */ @@ -347,10 +350,9 @@ export const getUserList = async (req: AuthenticatedRequest, res: Response) => { const countParams = [...queryParams]; // 총 개수 조회를 위해 기존 쿼리를 COUNT로 변환 - const countQuery = query.replace( - /SELECT[\s\S]*?FROM/i, - "SELECT COUNT(*) as total FROM" - ).replace(/ORDER BY.*$/i, ""); + const countQuery = query + .replace(/SELECT[\s\S]*?FROM/i, "SELECT COUNT(*) as total FROM") + .replace(/ORDER BY.*$/i, ""); const countResult = await client.query(countQuery, countParams); const totalCount = parseInt(countResult.rows[0].total); @@ -1737,6 +1739,7 @@ export const getUserInfo = async (req: AuthenticatedRequest, res: Response) => { u.fax_no, u.partner_objid, u.rank, + u.photo, u.locale, u.company_code, u.data_type, @@ -1789,6 +1792,9 @@ export const getUserInfo = async (req: AuthenticatedRequest, res: Response) => { faxNo: user.fax_no, partnerObjid: user.partner_objid, rank: user.rank, + photo: user.photo + ? `data:image/jpeg;base64,${user.photo.toString("base64")}` + : null, locale: user.locale, companyCode: user.company_code, dataType: user.data_type, @@ -2686,6 +2692,127 @@ export const deleteCompany = async ( * 사용자 비밀번호 초기화 API * 기존 Java AdminController.resetUserPassword() 포팅 */ +export const updateProfile = async ( + req: AuthenticatedRequest, + res: Response +) => { + try { + const userId = req.user?.userId; + if (!userId) { + res.status(401).json({ + result: false, + error: { + code: "TOKEN_MISSING", + details: "인증 토큰이 필요합니다.", + }, + }); + return; + } + + const { + userName, + userNameEng, + userNameCn, + email, + tel, + cellPhone, + photo, + locale, + } = req.body; + + // 사용자 정보 업데이트 + const updateData: any = {}; + if (userName !== undefined) updateData.user_name = userName; + if (userNameEng !== undefined) updateData.user_name_eng = userNameEng; + if (userNameCn !== undefined) updateData.user_name_cn = userNameCn; + if (email !== undefined) updateData.email = email; + if (tel !== undefined) updateData.tel = tel; + if (cellPhone !== undefined) updateData.cell_phone = cellPhone; + + // photo 데이터 처리 (Base64를 Buffer로 변환하여 저장) + if (photo !== undefined) { + if (photo && typeof photo === "string") { + try { + // Base64 헤더 제거 (data:image/jpeg;base64, 등) + const base64Data = photo.replace(/^data:image\/[a-z]+;base64,/, ""); + // Base64를 Buffer로 변환 + updateData.photo = Buffer.from(base64Data, "base64"); + } catch (error) { + console.error("Base64 이미지 처리 오류:", error); + updateData.photo = null; + } + } else { + updateData.photo = null; // 빈 값이면 null로 설정 + } + } + + if (locale !== undefined) updateData.locale = locale; + + // 업데이트할 데이터가 없으면 에러 + if (Object.keys(updateData).length === 0) { + res.status(400).json({ + result: false, + error: { + code: "NO_DATA", + details: "업데이트할 데이터가 없습니다.", + }, + }); + return; + } + + // 데이터베이스 업데이트 + await prisma.user_info.update({ + where: { user_id: userId }, + data: updateData, + }); + + // 업데이트된 사용자 정보 조회 + const updatedUser = await prisma.user_info.findUnique({ + where: { user_id: userId }, + select: { + user_id: true, + user_name: true, + user_name_eng: true, + user_name_cn: true, + dept_code: true, + dept_name: true, + position_code: true, + position_name: true, + email: true, + tel: true, + cell_phone: true, + user_type: true, + user_type_name: true, + photo: true, + locale: true, + }, + }); + + // photo가 Buffer 타입인 경우 Base64로 변환 + const responseData = { + ...updatedUser, + photo: updatedUser?.photo + ? `data:image/jpeg;base64,${updatedUser.photo.toString("base64")}` + : null, + }; + + res.json({ + result: true, + message: "프로필이 성공적으로 업데이트되었습니다.", + data: responseData, + }); + } catch (error) { + console.error("프로필 업데이트 오류:", error); + res.status(500).json({ + result: false, + error: { + code: "UPDATE_FAILED", + details: "프로필 업데이트 중 오류가 발생했습니다.", + }, + }); + } +}; + export const resetUserPassword = async ( req: AuthenticatedRequest, res: Response diff --git a/backend-node/src/controllers/authController.ts b/backend-node/src/controllers/authController.ts index c9e5b6ce..43a82f2e 100644 --- a/backend-node/src/controllers/authController.ts +++ b/backend-node/src/controllers/authController.ts @@ -166,15 +166,33 @@ export class AuthController { const userInfo = JwtUtils.verifyToken(token); + // DB에서 최신 사용자 정보 조회 (locale 포함) + const dbUserInfo = await AuthService.getUserInfo(userInfo.userId); + + if (!dbUserInfo) { + res.status(401).json({ + success: false, + message: "사용자 정보를 찾을 수 없습니다.", + error: { + code: "USER_NOT_FOUND", + details: "사용자 정보가 삭제되었거나 존재하지 않습니다.", + }, + }); + return; + } + const userInfoResponse: UserInfo = { - userId: userInfo.userId, - userName: userInfo.userName || "", - deptName: userInfo.deptName || "", - companyCode: userInfo.companyCode || "ILSHIN", - userType: userInfo.userType || "USER", - userTypeName: userInfo.userTypeName || "일반사용자", + userId: dbUserInfo.userId, + userName: dbUserInfo.userName || "", + deptName: dbUserInfo.deptName || "", + companyCode: dbUserInfo.companyCode || "ILSHIN", + userType: dbUserInfo.userType || "USER", + userTypeName: dbUserInfo.userTypeName || "일반사용자", + email: dbUserInfo.email || "", + photo: dbUserInfo.photo, + locale: dbUserInfo.locale || "KR", // locale 정보 추가 isAdmin: - userInfo.userType === "ADMIN" || userInfo.userId === "plm_admin", + dbUserInfo.userType === "ADMIN" || dbUserInfo.userId === "plm_admin", }; res.status(200).json({ diff --git a/backend-node/src/routes/adminRoutes.ts b/backend-node/src/routes/adminRoutes.ts index afdfb284..895b96e9 100644 --- a/backend-node/src/routes/adminRoutes.ts +++ b/backend-node/src/routes/adminRoutes.ts @@ -12,6 +12,7 @@ import { getUserHistory, // 사용자 변경이력 조회 changeUserStatus, // 사용자 상태 변경 resetUserPassword, // 사용자 비밀번호 초기화 + updateProfile, // 프로필 수정 getDepartmentList, // 부서 목록 조회 checkDuplicateUserId, // 사용자 ID 중복 체크 saveUser, // 사용자 등록/수정 @@ -45,6 +46,7 @@ router.get("/users/:userId", getUserInfo); // 사용자 상세 조회 router.get("/users/:userId/history", getUserHistory); // 사용자 변경이력 조회 router.patch("/users/:userId/status", changeUserStatus); // 사용자 상태 변경 router.post("/users", saveUser); // 사용자 등록/수정 +router.put("/profile", updateProfile); // 프로필 수정 router.post("/users/check-duplicate", checkDuplicateUserId); // 사용자 ID 중복 체크 router.post("/users/reset-password", resetUserPassword); // 사용자 비밀번호 초기화 diff --git a/backend-node/src/services/authService.ts b/backend-node/src/services/authService.ts index 5aafc132..a7e32d5c 100644 --- a/backend-node/src/services/authService.ts +++ b/backend-node/src/services/authService.ts @@ -146,6 +146,8 @@ export class AuthService { user_type_name: true, partner_objid: true, company_code: true, + locale: true, + photo: true, }, }); @@ -189,6 +191,8 @@ export class AuthService { partnerObjid: userInfo.partner_objid || undefined, authName: authInfo.length > 0 ? authInfo[0].auth_name : undefined, companyCode: userInfo.company_code || "ILSHIN", + photo: userInfo.photo ? `data:image/jpeg;base64,${userInfo.photo.toString('base64')}` : undefined, + locale: userInfo.locale || "KR", }; logger.info(`사용자 정보 조회 완료: ${userId}`); diff --git a/backend-node/src/types/auth.ts b/backend-node/src/types/auth.ts index 785157f9..c1384b51 100644 --- a/backend-node/src/types/auth.ts +++ b/backend-node/src/types/auth.ts @@ -15,6 +15,9 @@ export interface UserInfo { companyCode: string; userType?: string; userTypeName?: string; + email?: string; + photo?: string; + locale?: string; isAdmin?: boolean; } @@ -47,6 +50,8 @@ export interface PersonBean { partnerObjid?: string; authName?: string; companyCode?: string; + photo?: string; + locale?: string; } // 로그인 결과 타입 (기존 LoginService.loginPwdCheck 반환값) diff --git a/build-windows.bat b/build-windows.bat deleted file mode 100644 index edd9c295..00000000 --- a/build-windows.bat +++ /dev/null @@ -1,126 +0,0 @@ -@echo off -setlocal enabledelayedexpansion - -echo =============================================== -echo Java 애플리케이션 빌드 (윈도우용) -echo =============================================== -echo. - -REM Java 환경 확인 -echo [빌드 1] Java 환경 확인... -java -version >nul 2>&1 -if %errorlevel% neq 0 ( - echo [오류] Java가 설치되지 않았거나 PATH에 설정되지 않았습니다. - echo Java 7 이상을 설치하고 PATH를 설정해주세요. - exit /b 1 -) - -javac -version >nul 2>&1 -if %errorlevel% neq 0 ( - echo [오류] Java 컴파일러(javac)를 찾을 수 없습니다. - echo JDK가 설치되어 있는지 확인해주세요. - exit /b 1 -) -echo ✓ Java 환경 확인 완료 - -REM 빌드 디렉토리 정리 -echo [빌드 2] 이전 빌드 결과 정리... -if exist "WebContent\WEB-INF\classes" ( - rmdir /s /q "WebContent\WEB-INF\classes" -) -echo ✓ 이전 빌드 결과 정리 완료 - -REM 필요한 디렉토리 생성 -echo [빌드 3] 빌드 디렉토리 생성... -if not exist "WebContent\WEB-INF\classes" mkdir "WebContent\WEB-INF\classes" -if not exist "WebContent\WEB-INF\lib" mkdir "WebContent\WEB-INF\lib" -if not exist "logs" mkdir "logs" -echo ✓ 빌드 디렉토리 생성 완료 - -REM Servlet API JAR 확인 -echo [빌드 4] 라이브러리 의존성 확인... -set "SERVLET_JAR_1=WebContent\WEB-INF\lib\javax.servlet-api-4.0.1.jar" -set "SERVLET_JAR_2=WebContent\WEB-INF\lib\servlet-api.jar" - -if not exist "%SERVLET_JAR_1%" if not exist "%SERVLET_JAR_2%" ( - echo [오류] Servlet API JAR 파일을 찾을 수 없습니다. - echo 다음 중 하나가 필요합니다: - echo - %SERVLET_JAR_1% - echo - %SERVLET_JAR_2% - echo. - echo Maven Central에서 다운로드하거나 Tomcat lib 폴더에서 복사해주세요. - exit /b 1 -) -echo ✓ 라이브러리 의존성 확인 완료 - -REM 클래스패스 설정 -set "CLASSPATH=src;WebContent\WEB-INF\lib\*" -echo [빌드 5] 클래스패스: %CLASSPATH% - -REM Java 소스 파일 목록 생성 -echo [빌드 6] Java 소스 파일 검색... -if exist java_sources.tmp del java_sources.tmp - -set "java_count=0" -for /r src %%f in (*.java) do ( - echo %%f >> java_sources.tmp - set /a java_count+=1 -) - -if %java_count% equ 0 ( - echo [경고] 컴파일할 Java 소스 파일이 없습니다. -) else ( - echo ✓ %java_count%개의 Java 소스 파일을 찾았습니다. -) - -REM Java 컴파일 -if exist java_sources.tmp ( - echo [빌드 7] Java 소스 컴파일... - javac -encoding UTF-8 -source 1.7 -target 1.7 -d WebContent\WEB-INF\classes -cp "%CLASSPATH%" @java_sources.tmp - - if !errorlevel! neq 0 ( - echo [오류] Java 컴파일에 실패했습니다. - if exist java_sources.tmp del java_sources.tmp - exit /b 1 - ) - - del java_sources.tmp - echo ✓ Java 컴파일 완료 -) - -REM 리소스 파일 복사 -echo [빌드 8] 리소스 파일 복사... -set "resource_count=0" - -for /r src %%f in (*.xml *.properties *.sql) do ( - set "source_file=%%f" - set "relative_path=!source_file:%CD%\src\=!" - set "target_file=WebContent\WEB-INF\classes\!relative_path!" - - REM 대상 디렉토리 생성 - for %%d in ("!target_file!") do ( - if not exist "%%~dpd" mkdir "%%~dpd" 2>nul - ) - - REM 파일 복사 - copy "!source_file!" "!target_file!" >nul 2>&1 - if !errorlevel! equ 0 ( - set /a resource_count+=1 - ) else ( - echo [경고] 리소스 파일 복사 실패: !source_file! - ) -) - -echo ✓ %resource_count%개의 리소스 파일 복사 완료 - -REM 빌드 결과 요약 -echo. -echo =============================================== -echo ✓ 빌드 완료! -echo =============================================== -echo 컴파일된 클래스: WebContent\WEB-INF\classes\ -echo 라이브러리: WebContent\WEB-INF\lib\ -echo 로그 디렉토리: logs\ -echo. - -endlocal \ No newline at end of file diff --git a/compile_only.sh b/compile_only.sh deleted file mode 100644 index fba2da35..00000000 --- a/compile_only.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash - -# MAC OS 만 실행 -# if [[ "$(uname -s)" != "Darwin" ]]; then -# echo "This script runs on MAC OS only." -# echo "Current OS: $(uname -s)" -# exit 1 -# fi - -# ---------------------------------------------------------------------- -# 기존 빌드 폴더 삭제 및 새로운 빌드 시작 -# ---------------------------------------------------------------------- -echo "Cleaning up old build artifacts..." -rm -rf WebContent/WEB-INF/classes/* - -echo "Building Java application for development..." - -# 필요한 디렉토리 생성 -mkdir -p WebContent/WEB-INF/classes -mkdir -p WebContent/WEB-INF/lib # lib 폴더 존재 확인 - -# ---------------------------------------------------------------------- -# Servlet API JAR 파일 존재 여부 확인 (단순화된 방식) -# ---------------------------------------------------------------------- -SERVLET_API_JAR_PRIMARY_PATH="WebContent/WEB-INF/lib/javax.servlet-api-4.0.1.jar" -SERVLET_API_JAR_ALTERNATIVE_PATH="WebContent/WEB-INF/lib/servlet-api.jar" - -if [ ! -f "$SERVLET_API_JAR_PRIMARY_PATH" ] && [ ! -f "$SERVLET_API_JAR_ALTERNATIVE_PATH" ]; then - echo "---------------------------------------------------------------------------------" - echo "ERROR: Servlet API JAR (javax.servlet-api-4.0.1.jar or servlet-api.jar)" - echo " not found in WebContent/WEB-INF/lib/" - echo "" - echo "Please add the appropriate Servlet API JAR for your project." - echo "You can typically find this JAR in a Tomcat distribution's 'lib' folder," - echo "or download it from a trusted source like Maven Central Repository." - echo "" - echo "Build cannot proceed without it." - echo "---------------------------------------------------------------------------------" - exit 1 -else - if [ -f "$SERVLET_API_JAR_PRIMARY_PATH" ]; then - echo "DEBUG: Confirmed Servlet API JAR is present at $SERVLET_API_JAR_PRIMARY_PATH" - elif [ -f "$SERVLET_API_JAR_ALTERNATIVE_PATH" ]; then - echo "DEBUG: Confirmed Servlet API JAR is present at $SERVLET_API_JAR_ALTERNATIVE_PATH" - fi -fi -# ---------------------------------------------------------------------- - -# 클래스패스 설정 (단순화된 방식) -EFFECTIVE_CLASSPATH="src:WebContent/WEB-INF/lib/*" -echo "DEBUG: Effective classpath for javac: $EFFECTIVE_CLASSPATH" - -# src 폴더 내의 모든 .java 파일 컴파일 -echo "Compiling Java files for development..." - -find src -name "*.java" -print0 | xargs -0 javac -encoding UTF-8 -source 1.7 -target 1.7 -d WebContent/WEB-INF/classes -cp "$EFFECTIVE_CLASSPATH" -if [ $? -ne 0 ]; then - echo "Java compilation failed. Exiting script." - exit 1 -fi - -echo "Java compilation successful." -# ---------------------------------------------------------------------- - -# src 폴더 내의 리소스 파일(.xml, .properties 등)을 classes 폴더로 복사 (macOS 호환 방식) -echo "Copying resource files for development..." -find src -type f \( -name "*.xml" -o -name "*.properties" \) | while read -r filepath; do - # 'src/' 접두사를 제거하여 상대 경로 생성 - relative_path="${filepath#src/}" - target_file="WebContent/WEB-INF/classes/$relative_path" - - # 대상 디렉토리 생성 - mkdir -p "$(dirname "$target_file")" || { echo "Error: Failed to create directory $(dirname "$target_file")"; exit 1; } - - # 파일 복사 - cp "$filepath" "$target_file" || { echo "Error: Failed to copy $filepath to $target_file"; exit 1; } -done - -echo "Java application build complete for development." -echo "Build process finished successfully!" \ No newline at end of file diff --git a/dev-backend.bat b/dev-backend.bat deleted file mode 100644 index 208efe5d..00000000 --- a/dev-backend.bat +++ /dev/null @@ -1,57 +0,0 @@ -@echo off -chcp 65001 > nul -echo ================================= -echo 백엔드 개발 관리 도구 -echo ================================= - -cd /d %~dp0 - -:menu -echo. -echo 선택하세요: -echo 1. 백엔드 재시작 (완전 재빌드) -echo 2. 백엔드 빠른 재시작 (캐시 사용) -echo 3. 백엔드 빌드만 실행 -echo 4. 백엔드 로그 실시간 확인 -echo 5. Gradle 로컬 빌드 -echo 6. 백엔드 상태 확인 -echo 0. 종료 -echo. - -set /p choice="번호를 입력하세요: " - -if "%choice%"=="1" ( - call restart-backend.bat - goto menu -) -if "%choice%"=="2" ( - call quick-restart-backend.bat - goto menu -) -if "%choice%"=="3" ( - call backend-build-only.bat - goto menu -) -if "%choice%"=="4" ( - call backend-logs.bat - goto menu -) -if "%choice%"=="5" ( - call backend-gradle-build.bat - goto menu -) -if "%choice%"=="6" ( - echo 백엔드 컨테이너 상태: - docker-compose -f docker-compose.springboot.yml ps backend - echo. - echo 아무 키나 누르세요... - pause > nul - goto menu -) -if "%choice%"=="0" ( - echo 프로그램을 종료합니다. - exit /b 0 -) - -echo 잘못된 선택입니다. 다시 선택해주세요. -goto menu \ No newline at end of file diff --git a/dev_git_only.bat b/dev_git_only.bat deleted file mode 100644 index 47f5bec6..00000000 --- a/dev_git_only.bat +++ /dev/null @@ -1,173 +0,0 @@ -@echo off -setlocal enabledelayedexpansion - -REM ---------------------------------------------------------------------- -REM 기존 빌드 폴더 삭제 및 새로운 빌드 시작 -REM ---------------------------------------------------------------------- -echo Cleaning up old build artifacts... -if exist "WebContent\WEB-INF\classes\*" ( - rmdir /s /q "WebContent\WEB-INF\classes" -) - -echo Building Java application for development... - -REM 필요한 디렉토리 생성 -if not exist "WebContent\WEB-INF\classes" mkdir "WebContent\WEB-INF\classes" -if not exist "WebContent\WEB-INF\lib" mkdir "WebContent\WEB-INF\lib" - -REM ---------------------------------------------------------------------- -REM Servlet API JAR 파일 존재 여부 확인 -REM ---------------------------------------------------------------------- -set "SERVLET_API_JAR_PRIMARY_PATH=WebContent\WEB-INF\lib\javax.servlet-api-4.0.1.jar" -set "SERVLET_API_JAR_ALTERNATIVE_PATH=WebContent\WEB-INF\lib\servlet-api.jar" - -if not exist "%SERVLET_API_JAR_PRIMARY_PATH%" if not exist "%SERVLET_API_JAR_ALTERNATIVE_PATH%" ( - echo --------------------------------------------------------------------------------- - echo ERROR: Servlet API JAR (javax.servlet-api-4.0.1.jar or servlet-api.jar^) - echo not found in WebContent\WEB-INF\lib\ - echo. - echo Please add the appropriate Servlet API JAR for your project. - echo You can typically find this JAR in a Tomcat distribution's 'lib' folder, - echo or download it from a trusted source like Maven Central Repository. - echo. - echo Build cannot proceed without it. - echo --------------------------------------------------------------------------------- - exit /b 1 -) else ( - if exist "%SERVLET_API_JAR_PRIMARY_PATH%" ( - echo DEBUG: Confirmed Servlet API JAR is present at %SERVLET_API_JAR_PRIMARY_PATH% - ) else if exist "%SERVLET_API_JAR_ALTERNATIVE_PATH%" ( - echo DEBUG: Confirmed Servlet API JAR is present at %SERVLET_API_JAR_ALTERNATIVE_PATH% - ) -) - -REM ---------------------------------------------------------------------- -REM 클래스패스 설정 -set "EFFECTIVE_CLASSPATH=src;WebContent\WEB-INF\lib\*" -echo DEBUG: Effective classpath for javac: %EFFECTIVE_CLASSPATH% - -REM src 폴더 내의 모든 .java 파일 컴파일 -echo Compiling Java files for development... - -REM Java 파일 목록을 임시 파일에 저장 -if exist temp_java_files.txt del temp_java_files.txt -for /r src %%f in (*.java) do echo %%f >> temp_java_files.txt - -if exist temp_java_files.txt ( - javac -encoding UTF-8 -source 1.7 -target 1.7 -d WebContent\WEB-INF\classes -cp "%EFFECTIVE_CLASSPATH%" @temp_java_files.txt - if !errorlevel! neq 0 ( - echo Java compilation failed. Exiting script. - del temp_java_files.txt - exit /b 1 - ) - del temp_java_files.txt -) - -echo Java compilation successful. - -REM ---------------------------------------------------------------------- -REM src 폴더 내의 리소스 파일(.xml, .properties 등)을 classes 폴더로 복사 -echo Copying resource files for development... - -for /r src %%f in (*.xml *.properties) do ( - set "filepath=%%f" - REM src\ 부분을 제거하여 상대 경로 생성 - set "relative_path=%%f" - call set "relative_path=%%relative_path:*src\=%%" - set "target_file=WebContent\WEB-INF\classes\!relative_path!" - - REM 대상 디렉토리 생성 - for %%d in ("!target_file!") do ( - if not exist "%%~dpd" mkdir "%%~dpd" - ) - - REM 파일 복사 - copy "!filepath!" "!target_file!" >nul - if !errorlevel! neq 0 ( - echo Error: Failed to copy !filepath! to !target_file! - exit /b 1 - ) -) - -echo Java application build complete for development. - -REM ---------------------------------------------------------------------- -REM Git 변경사항 커밋 및 푸시 -REM ---------------------------------------------------------------------- -git add . -git commit -am "auto commit" - -REM 현재 브랜치 확인 -for /f "tokens=*" %%i in ('git branch --show-current') do set "current_branch=%%i" - -git push origin %current_branch% - -REM 마스터 브랜치와 병합 여부 확인 -echo You are currently on branch: %current_branch% -set /p "proceed_merge=Would you like to merge the current branch with main? (Y/N) [Y]: " -if "%proceed_merge%"=="" set "proceed_merge=Y" - -if /i "%proceed_merge%"=="Y" ( - REM 마스터 브랜치로 전환 및 업데이트 - git checkout main - git pull origin main - - REM 현재 브랜치를 마스터에 병합 - git merge --no-edit %current_branch% - - REM 병합 결과 푸시 - git push origin main - - REM 원래 브랜치로 돌아가기 - git checkout %current_branch% -) - -REM 새로운 브랜치 생성 -REM 현재 날짜를 YYYYMMDD 형식으로 가져오기 -for /f "tokens=2 delims==" %%i in ('wmic OS Get localdatetime /value') do set "dt=%%i" -set "current_date=%dt:~0,8%" - -REM 브랜치 이름에서 날짜 부분 추출 -set "branch_date=%current_branch:~1,8%" - -REM 현재 날짜와 브랜치 날짜가 같으면 뒤의 2자리 숫자를 증가시킴 -if "%branch_date%"=="%current_date%" ( - set "branch_number=%current_branch:~9,2%" - set /a "branch_number=branch_number+1" -) else ( - set "branch_number=1" -) - -REM 사용 가능한 브랜치 이름 찾기 -:find_branch -if %branch_number% lss 10 ( - set "formatted_number=0%branch_number%" -) else ( - set "formatted_number=%branch_number%" -) -set "new_branch=V%current_date%%formatted_number%" - -REM 로컬과 원격에 해당 이름의 브랜치가 존재하는지 확인 -git show-ref --quiet refs/heads/%new_branch% >nul 2>&1 -if !errorlevel! equ 0 goto increment_branch - -git ls-remote --exit-code --heads origin %new_branch% >nul 2>&1 -if !errorlevel! equ 0 goto increment_branch - -goto create_branch - -:increment_branch -set /a "branch_number=branch_number+1" -goto find_branch - -:create_branch -REM 새로운 브랜치 생성 -git checkout -b %new_branch% - -REM 새로운 브랜치 푸시 -git push origin %new_branch% - -REM 변경 사항 확인 -git status - -endlocal \ No newline at end of file diff --git a/dev_git_only.sh b/dev_git_only.sh deleted file mode 100644 index 6d6cd20c..00000000 --- a/dev_git_only.sh +++ /dev/null @@ -1,145 +0,0 @@ -#!/bin/bash - -# MAC OS 만 실행 -# if [[ "$(uname -s)" != "Darwin" ]]; then -# echo "This script runs on MAC OS only." -# echo "Current OS: $(uname -s)" -# exit 1 -# fi - -# ---------------------------------------------------------------------- -# 기존 빌드 폴더 삭제 및 새로운 빌드 시작 -# ---------------------------------------------------------------------- -echo "Cleaning up old build artifacts..." -rm -rf WebContent/WEB-INF/classes/* - -echo "Building Java application for development..." - -# 필요한 디렉토리 생성 -mkdir -p WebContent/WEB-INF/classes -mkdir -p WebContent/WEB-INF/lib # lib 폴더 존재 확인 - -# ---------------------------------------------------------------------- -# Servlet API JAR 파일 존재 여부 확인 (단순화된 방식) -# ---------------------------------------------------------------------- -SERVLET_API_JAR_PRIMARY_PATH="WebContent/WEB-INF/lib/javax.servlet-api-4.0.1.jar" -SERVLET_API_JAR_ALTERNATIVE_PATH="WebContent/WEB-INF/lib/servlet-api.jar" - -if [ ! -f "$SERVLET_API_JAR_PRIMARY_PATH" ] && [ ! -f "$SERVLET_API_JAR_ALTERNATIVE_PATH" ]; then - echo "---------------------------------------------------------------------------------" - echo "ERROR: Servlet API JAR (javax.servlet-api-4.0.1.jar or servlet-api.jar)" - echo " not found in WebContent/WEB-INF/lib/" - echo "" - echo "Please add the appropriate Servlet API JAR for your project." - echo "You can typically find this JAR in a Tomcat distribution's 'lib' folder," - echo "or download it from a trusted source like Maven Central Repository." - echo "" - echo "Build cannot proceed without it." - echo "---------------------------------------------------------------------------------" - exit 1 -else - if [ -f "$SERVLET_API_JAR_PRIMARY_PATH" ]; then - echo "DEBUG: Confirmed Servlet API JAR is present at $SERVLET_API_JAR_PRIMARY_PATH" - elif [ -f "$SERVLET_API_JAR_ALTERNATIVE_PATH" ]; then - echo "DEBUG: Confirmed Servlet API JAR is present at $SERVLET_API_JAR_ALTERNATIVE_PATH" - fi -fi -# ---------------------------------------------------------------------- - -# 클래스패스 설정 (단순화된 방식) -EFFECTIVE_CLASSPATH="src:WebContent/WEB-INF/lib/*" -echo "DEBUG: Effective classpath for javac: $EFFECTIVE_CLASSPATH" - -# src 폴더 내의 모든 .java 파일 컴파일 -echo "Compiling Java files for development..." - -find src -name "*.java" -print0 | xargs -0 javac -encoding UTF-8 -source 1.7 -target 1.7 -d WebContent/WEB-INF/classes -cp "$EFFECTIVE_CLASSPATH" -if [ $? -ne 0 ]; then - echo "Java compilation failed. Exiting script." - exit 1 -fi - -echo "Java compilation successful." -# ---------------------------------------------------------------------- - -# src 폴더 내의 리소스 파일(.xml, .properties 등)을 classes 폴더로 복사 (macOS 호환 방식) -echo "Copying resource files for development..." -find src -type f \( -name "*.xml" -o -name "*.properties" \) | while read -r filepath; do - # 'src/' 접두사를 제거하여 상대 경로 생성 - relative_path="${filepath#src/}" - target_file="WebContent/WEB-INF/classes/$relative_path" - - # 대상 디렉토리 생성 - mkdir -p "$(dirname "$target_file")" || { echo "Error: Failed to create directory $(dirname "$target_file")"; exit 1; } - - # 파일 복사 - cp "$filepath" "$target_file" || { echo "Error: Failed to copy $filepath to $target_file"; exit 1; } -done -# 파이프라인의 마지막 명령어의 종료 코드를 확인하기 위해 추가적인 검사가 필요할 수 있으나, -# while 루프 내에서 오류 발생 시 exit 하므로, 이 지점에 도달하면 성공으로 간주합니다. -# 만약 find가 아무 파일도 찾지 못해도 오류가 아니어야 하므로 $? 검사는 주의해야 합니다. - -echo "Java application build complete for development." -# ---------------------------------------------------------------------- -# 빌드 종료 -# ---------------------------------------------------------------------- - -# Git 변경사항 커밋 및 푸시 -git add . -git commit -am "auto commit" -current_branch=$(git branch --show-current) -git push origin $current_branch -# 마스터 브랜치와 병합 여부 확인 -echo "You are currently on branch: $current_branch" -echo "Would you like to merge the current branch with main? (Y/N) [Y]" -read proceed_merge -proceed_merge=${proceed_merge:-Y} -if [ "$proceed_merge" == "Y" ] || [ "$proceed_merge" == "y" ]; then - # 마스터 브랜치로 전환 및 업데이트 - git checkout main - git pull origin main - # 현재 브랜치를 마스터에 병합 - git merge --no-edit $current_branch - # 병합 결과 푸시 - git push origin main - # 원래 브랜치로 돌아가기 - git checkout $current_branch -fi -# 새로운 브랜치 생성 -# 현재 날짜를 YYYYMMDD 형식으로 가져오기 -current_date=$(date +'%Y%m%d') -# 브랜치 이름에서 날짜 부분 추출 -branch_date=${current_branch:1:8} -# 현재 날짜와 브랜치 날짜가 같으면 뒤의 2자리 숫자를 증가시킴 -if [ "$branch_date" == "$current_date" ]; then - # 브랜치 이름에서 뒤의 2자리 숫자 추출 - branch_number=${current_branch:9:2} - # 숫자를 10진수로 변환하고 1 증가시킴 - branch_number=$((10#$branch_number + 1)) -else - # 날짜가 다르면 01부터 시작 - branch_number=1 -fi -# 사용 가능한 브랜치 이름 찾기 -while true; do - # 2자리 숫자로 포맷팅 - formatted_number=$(printf "%02d" $branch_number) - new_branch="V${current_date}${formatted_number}" - - # 로컬과 원격에 해당 이름의 브랜치가 존재하는지 확인 - if ! git show-ref --quiet refs/heads/$new_branch && \ - ! git ls-remote --exit-code --heads origin $new_branch > /dev/null 2>&1; then - break - fi - - # 존재한다면 숫자 증가 - branch_number=$((branch_number + 1)) -done -# 새로운 브랜치 생성 -git checkout -b $new_branch -# 새로운 브랜치 푸시 (원격 브랜치로 푸시하려면 git push origin $new_branch 실행) -git push origin $new_branch -# 변경 사항 확인 -git status -# .env-dev 파일을 .env로 복사하여 원래 상태로 복원 -# docker-compose -f docker-compose-dev.yml up -d --build \ No newline at end of file diff --git a/docker-compose.backend.linux.yml b/docker-compose.backend.linux.yml deleted file mode 100644 index 39bdacb1..00000000 --- a/docker-compose.backend.linux.yml +++ /dev/null @@ -1,36 +0,0 @@ -version: "3.8" - -services: - # Node.js 백엔드 - backend: - build: - context: ./backend-node - dockerfile: Dockerfile - container_name: pms-backend-linux - ports: - - "8080:8080" - environment: - - NODE_ENV=development - - PORT=8080 - - DATABASE_URL=postgresql://postgres:ph0909!!@39.117.244.52:11132/plm - - JWT_SECRET=ilshin-plm-super-secret-jwt-key-2024 - - JWT_EXPIRES_IN=24h - - CORS_ORIGIN=http://localhost:9771 - - CORS_CREDENTIALS=true - - LOG_LEVEL=debug - volumes: - - ./backend-node:/app - - /app/node_modules - networks: - - pms-network - restart: unless-stopped - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:8080/health"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 60s - -networks: - pms-network: - driver: bridge diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml deleted file mode 100644 index 203d610e..00000000 --- a/docker-compose.dev.yml +++ /dev/null @@ -1,23 +0,0 @@ -version: '3.8' - -services: - plm: - build: - context: . - dockerfile: dockerfile.dev - container_name: plm - ports: - - "9090:8080" - environment: - CATALINA_OPTS: >- - -DDB_URL=jdbc:postgresql://39.117.244.52:11132/plm - -DDB_USERNAME=postgres - -DDB_PASSWORD=ph0909!! - volumes: - - plm-project_data:/data_storage - - plm-app_data:/path/inside/container - restart: unless-stopped - -volumes: - plm-project_data: - plm-app_data: diff --git a/docker-compose.frontend.win.yml b/docker-compose.frontend.win.yml deleted file mode 100644 index d8865567..00000000 --- a/docker-compose.frontend.win.yml +++ /dev/null @@ -1,25 +0,0 @@ -version: "3.8" - -services: - # Next.js 프론트엔드만 - frontend: - build: - context: ./frontend - dockerfile: Dockerfile.dev - container_name: pms-frontend-win - ports: - - "9771:3000" - environment: - - NEXT_PUBLIC_API_URL=http://localhost:8080/api - volumes: - - ./frontend:/app - - /app/node_modules - - /app/.next - networks: - - pms-network - restart: unless-stopped - -networks: - pms-network: - driver: bridge - external: true diff --git a/docker-compose.springboot.yml b/docker-compose.springboot.yml deleted file mode 100644 index 1894d774..00000000 --- a/docker-compose.springboot.yml +++ /dev/null @@ -1,54 +0,0 @@ -version: '3.8' - -services: - # Spring Boot 백엔드 - backend: - build: - context: ./backend - dockerfile: Dockerfile - container_name: pms-backend - ports: - - "8080:8080" - environment: - - SPRING_PROFILES_ACTIVE=dev - - SPRING_DATASOURCE_URL=jdbc:postgresql://39.117.244.52:11132/plm?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Seoul - - SPRING_DATASOURCE_USERNAME=postgres - - SPRING_DATASOURCE_PASSWORD=ph0909!! - - LANG=ko_KR.UTF-8 - - LANGUAGE=ko_KR:ko - - LC_ALL=ko_KR.UTF-8 - - TZ=Asia/Seoul - - JAVA_OPTS=-Xms512m -Xmx1024m -Dfile.encoding=UTF-8 -Duser.timezone=Asia/Seoul -Djava.awt.headless=true - networks: - - pms-network - restart: unless-stopped - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:8080/api/actuator/health"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 60s - - # Next.js 프론트엔드 - frontend: - build: - context: ./frontend - dockerfile: Dockerfile.dev - container_name: pms-frontend - ports: - - "3000:3000" - environment: - - NEXT_PUBLIC_API_URL=http://localhost:8080/api - volumes: - - ./frontend:/app - - /app/node_modules - - /app/.next - networks: - - pms-network - restart: unless-stopped - depends_on: - - backend - -networks: - pms-network: - driver: bridge \ No newline at end of file diff --git a/docker-compose.win.yml b/docker-compose.win.yml deleted file mode 100644 index 67d83bc6..00000000 --- a/docker-compose.win.yml +++ /dev/null @@ -1,62 +0,0 @@ -services: - # 백엔드 서비스 (기존) - plm-app: - build: - context: . - dockerfile: Dockerfile.win - platforms: - - linux/amd64 - container_name: plm-windows - ports: - - "9090:8080" - environment: - - CATALINA_OPTS=-DDB_URL=jdbc:postgresql://39.117.244.52:11132/plm -DDB_USERNAME=postgres -DDB_PASSWORD=ph0909!! -Xms512m -Xmx1024m - - TZ=Asia/Seoul - - APP_ENV=development - - LOG_LEVEL=INFO - - DB_HOST=39.117.244.52 - - DB_PORT=11132 - - DB_NAME=plm - - DB_USERNAME=postgres - - DB_PASSWORD=ph0909!! - volumes: - - plm-win-project:/data_storage - - plm-win-app:/app_data - - ./logs:/usr/local/tomcat/logs - - ./WebContent:/usr/local/tomcat/webapps/ROOT - restart: unless-stopped - networks: - - plm-network - - # 프론트엔드 서비스 (새로 추가) - plm-frontend: - build: - context: ./frontend - dockerfile: Dockerfile.dev - container_name: plm-frontend - ports: - - "3000:3000" - environment: - - NODE_ENV=development - - TZ=Asia/Seoul - - NEXT_PUBLIC_API_URL=http://localhost:9090 - - WATCHPACK_POLLING=true - volumes: - - ./frontend:/app - - /app/node_modules - - /app/.next - depends_on: - - plm-app - restart: unless-stopped - networks: - - plm-network - -volumes: - plm-win-project: - driver: local - plm-win-app: - driver: local - -networks: - plm-network: - driver: bridge \ No newline at end of file diff --git a/docker/dev/backend.Dockerfile b/docker/dev/backend.Dockerfile new file mode 100644 index 00000000..9099b18e --- /dev/null +++ b/docker/dev/backend.Dockerfile @@ -0,0 +1,24 @@ +# 개발용 백엔드 Dockerfile +FROM node:20-bookworm-slim + +WORKDIR /app + +# 시스템 패키지 설치 +RUN apt-get update \ + && apt-get install -y --no-install-recommends openssl ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# package.json 복사 및 의존성 설치 (개발 의존성 포함) +COPY package*.json ./ +RUN npm ci --prefer-offline --no-audit + +# 소스 코드는 볼륨 마운트로 처리 +# Prisma 클라이언트 생성용 스키마만 복사 +COPY prisma ./prisma +RUN npx prisma generate + +# 포트 노출 +EXPOSE 8080 + +# 개발 서버 시작 (nodemon 사용) +CMD ["npm", "run", "dev"] diff --git a/docker-compose.backend.mac.yml b/docker/dev/docker-compose.backend.mac.yml similarity index 76% rename from docker-compose.backend.mac.yml rename to docker/dev/docker-compose.backend.mac.yml index 68a916a6..06618628 100644 --- a/docker-compose.backend.mac.yml +++ b/docker/dev/docker-compose.backend.mac.yml @@ -1,11 +1,9 @@ -version: "3.8" - services: # Node.js 백엔드 backend: build: - context: ./backend-node - dockerfile: Dockerfile + context: ../../backend-node + dockerfile: ../docker/dev/backend.Dockerfile container_name: pms-backend-mac ports: - "8080:8080" @@ -18,9 +16,9 @@ services: - CORS_ORIGIN=http://localhost:9771 - CORS_CREDENTIALS=true - LOG_LEVEL=debug - # volumes: - # - ./backend-node:/app # 개발 모드가 아닐 때는 이 볼륨 마운트를 비활성화 - # - /app/node_modules + volumes: + - ../../backend-node:/app # 개발 모드: 코드 변경 시 자동 반영 + - /app/node_modules networks: - pms-network restart: unless-stopped diff --git a/docker-compose.frontend.mac.yml b/docker/dev/docker-compose.frontend.mac.yml similarity index 76% rename from docker-compose.frontend.mac.yml rename to docker/dev/docker-compose.frontend.mac.yml index 280cf8a1..e02a1287 100644 --- a/docker-compose.frontend.mac.yml +++ b/docker/dev/docker-compose.frontend.mac.yml @@ -1,18 +1,16 @@ -version: "3.8" - services: # Next.js 프론트엔드만 frontend: build: - context: ./frontend - dockerfile: Dockerfile.dev + context: ../../frontend + dockerfile: ../docker/dev/frontend.Dockerfile container_name: pms-frontend-mac ports: - "9771:3000" environment: - NEXT_PUBLIC_API_URL=http://localhost:8080/api volumes: - - ./frontend:/app + - ../../frontend:/app - /app/node_modules - /app/.next networks: diff --git a/frontend/Dockerfile.dev b/docker/dev/frontend.Dockerfile similarity index 65% rename from frontend/Dockerfile.dev rename to docker/dev/frontend.Dockerfile index de7f23d7..390e8324 100644 --- a/frontend/Dockerfile.dev +++ b/docker/dev/frontend.Dockerfile @@ -7,8 +7,8 @@ WORKDIR /app # package.json과 package-lock.json 복사 COPY package*.json ./ -# 의존성 설치 (개발 의존성 포함) -RUN npm ci +# 의존성 설치 (개발 의존성 포함) - 최적화 옵션 추가 +RUN npm ci --prefer-offline --no-audit # 소스 코드 복사 COPY . . diff --git a/backend-node/Dockerfile b/docker/prod/backend.Dockerfile similarity index 80% rename from backend-node/Dockerfile rename to docker/prod/backend.Dockerfile index 5385fd71..23e9210a 100644 --- a/backend-node/Dockerfile +++ b/docker/prod/backend.Dockerfile @@ -12,7 +12,7 @@ RUN apt-get update \ # Dependencies stage (install deps and generate Prisma client) FROM base AS deps COPY package*.json ./ -RUN npm ci --omit=dev && npm cache clean --force +RUN npm ci --omit=dev --prefer-offline --no-audit && npm cache clean --force # Copy prisma schema and generate client (glibc target will be detected) COPY prisma ./prisma ENV PRISMA_SKIP_POSTINSTALL_GENERATE=true @@ -22,21 +22,16 @@ RUN npx prisma generate FROM node:20-bookworm-slim AS build WORKDIR /app COPY package*.json ./ -RUN npm ci && npm cache clean --force +RUN npm ci --prefer-offline --no-audit && npm cache clean --force COPY tsconfig.json ./ COPY src ./src COPY prisma ./prisma RUN npx prisma generate RUN npm run build -# Runtime image -FROM node:20-bookworm-slim AS runner -WORKDIR /app +# Runtime image - base 이미지 재사용으로 중복 설치 제거 +FROM base AS runner ENV NODE_ENV=production -# Ensure OpenSSL present -RUN apt-get update \ - && apt-get install -y --no-install-recommends openssl ca-certificates \ - && rm -rf /var/lib/apt/lists/* # Create non-root user RUN groupadd -r appgroup && useradd -r -g appgroup appuser diff --git a/docker-compose.backend.win.yml b/docker/prod/docker-compose.backend.prod.yml similarity index 66% rename from docker-compose.backend.win.yml rename to docker/prod/docker-compose.backend.prod.yml index 67557614..d06327fc 100644 --- a/docker-compose.backend.win.yml +++ b/docker/prod/docker-compose.backend.prod.yml @@ -1,26 +1,22 @@ -version: "3.8" - services: - # Node.js 백엔드 + # Node.js 백엔드 (운영용) backend: build: - context: ./backend-node - dockerfile: Dockerfile - container_name: pms-backend-win + context: ../../backend-node + dockerfile: ../docker/prod/backend.Dockerfile # 운영용 Dockerfile + container_name: pms-backend-prod ports: - "8080:8080" environment: - - NODE_ENV=development + - NODE_ENV=production - PORT=8080 - DATABASE_URL=postgresql://postgres:ph0909!!@39.117.244.52:11132/plm - JWT_SECRET=ilshin-plm-super-secret-jwt-key-2024 - JWT_EXPIRES_IN=24h - CORS_ORIGIN=http://localhost:9771 - CORS_CREDENTIALS=true - - LOG_LEVEL=debug - volumes: - - ./backend-node:/app - - /app/node_modules + - LOG_LEVEL=info + # 운영용에서는 볼륨 마운트 없음 (보안상 이유) networks: - pms-network restart: unless-stopped diff --git a/docker-compose.frontend.linux.yml b/docker/prod/docker-compose.frontend.prod.yml similarity index 82% rename from docker-compose.frontend.linux.yml rename to docker/prod/docker-compose.frontend.prod.yml index e8e9346d..558d6c2e 100644 --- a/docker-compose.frontend.linux.yml +++ b/docker/prod/docker-compose.frontend.prod.yml @@ -1,11 +1,9 @@ -version: '3.8' - services: # Next.js 프론트엔드만 frontend: build: - context: ./frontend - dockerfile: Dockerfile + context: ../../frontend + dockerfile: ../docker/prod/frontend.Dockerfile args: - NEXT_PUBLIC_API_URL=http://192.168.0.70:8080/api container_name: pms-frontend-linux @@ -24,4 +22,4 @@ services: networks: pms-network: driver: bridge - external: true \ No newline at end of file + external: true diff --git a/frontend/Dockerfile b/docker/prod/frontend.Dockerfile similarity index 100% rename from frontend/Dockerfile rename to docker/prod/frontend.Dockerfile diff --git a/frontend/components/layout/AppLayout.tsx b/frontend/components/layout/AppLayout.tsx index 35597eb3..079844c9 100644 --- a/frontend/components/layout/AppLayout.tsx +++ b/frontend/components/layout/AppLayout.tsx @@ -194,7 +194,7 @@ export function AppLayout({ children }: AppLayoutProps) { const router = useRouter(); const pathname = usePathname(); const { user, logout, refreshUserData } = useAuth(); - const { userMenus, adminMenus, loading } = useMenu(); + const { userMenus, adminMenus, loading, refreshMenus } = useMenu(); const [sidebarOpen, setSidebarOpen] = useState(false); const [expandedMenus, setExpandedMenus] = useState>(new Set()); @@ -204,6 +204,7 @@ export function AppLayout({ children }: AppLayoutProps) { formData, selectedImage, isSaving, + departments, alertModal, closeAlert, openProfileModal, @@ -212,7 +213,7 @@ export function AppLayout({ children }: AppLayoutProps) { selectImage, removeImage, saveProfile, - } = useProfile(user, refreshUserData); + } = useProfile(user, refreshUserData, refreshMenus); // 현재 경로에 따라 어드민 모드인지 판단 const isAdminMode = pathname.startsWith("/admin"); @@ -394,6 +395,7 @@ export function AppLayout({ children }: AppLayoutProps) { formData={formData} selectedImage={selectedImage} isSaving={isSaving} + departments={departments} alertModal={alertModal} onClose={closeProfileModal} onFormChange={updateFormData} diff --git a/frontend/components/layout/ProfileModal.tsx b/frontend/components/layout/ProfileModal.tsx index a99fd23d..d2467bac 100644 --- a/frontend/components/layout/ProfileModal.tsx +++ b/frontend/components/layout/ProfileModal.tsx @@ -53,6 +53,10 @@ interface ProfileModalProps { formData: ProfileFormData; selectedImage: string; isSaving: boolean; + departments: Array<{ + deptCode: string; + deptName: string; + }>; alertModal: { isOpen: boolean; title: string; @@ -76,6 +80,7 @@ export function ProfileModal({ formData, selectedImage, isSaving, + departments, alertModal, onClose, onFormChange, @@ -99,12 +104,14 @@ export function ProfileModal({ {selectedImage ? ( + ) : user?.photo ? ( + ) : ( {formData.userName?.substring(0, 1) || "U"} )} - {selectedImage && ( + {(selectedImage || user?.photo) && (