diff --git a/apps/graduate/docker-compose.yml b/apps/graduate/docker-compose.yml new file mode 100644 index 00000000..214a0190 --- /dev/null +++ b/apps/graduate/docker-compose.yml @@ -0,0 +1,158 @@ +networks: + aics-network: + driver: bridge + +services: + postgres: + image: postgres:18-alpine + container_name: aics-postgres + restart: unless-stopped + env_file: + - .env + ports: + - '${POSTGRES_PORT:-5432}:5432' + environment: + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: ${POSTGRES_DB} + volumes: + - ./volumes/aics-postgres:/var/lib/postgresql/18/docker + healthcheck: + test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}'] + interval: 10s + timeout: 5s + retries: 5 + networks: + - aics-network + + redis: + image: redis:8-alpine + container_name: aics-redis + restart: unless-stopped + command: ['redis-server', '--requirepass', '${REDIS_PASSWORD}'] + ports: + - '${REDIS_PORT:-6379}:6379' + env_file: + - .env + environment: + REDIS_PASSWORD: ${REDIS_PASSWORD} + volumes: + - ./volumes/aics-redis:/data + healthcheck: + test: ['CMD', 'redis-cli', '-a', '${REDIS_PASSWORD}', 'ping'] + interval: 10s + timeout: 5s + retries: 5 + networks: + - aics-network + + aics-api: + image: kgudevelopers/aics-api:prod + container_name: aics-api + restart: unless-stopped + env_file: + - .env + environment: + SPRING_PROFILES_ACTIVE: prod + DB_HOST: aics-postgres + DB_PORT: 5432 + DB_NAME: ${POSTGRES_DB} + DB_USERNAME: ${POSTGRES_USER} + DB_PASSWORD: ${POSTGRES_PASSWORD} + JWT_ISSUER: kgudevelopers@gmail.com + JWT_SECRET_KEY: ${JWT_SECRET_KEY} + REDIS_HOST: aics-redis + REDIS_PASSWORD: ${REDIS_PASSWORD} + FILE_SECRET_KEY: ${FILE_SECRET_KEY} + expose: + - '8080' + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + volumes: + - aics-data:/app/cloud + networks: + - aics-network + + aics-admin: + image: kgudevelopers/aics-admin:prod + container_name: aics-admin + restart: unless-stopped + env_file: + - .env + environment: + SPRING_PROFILES_ACTIVE: prod + DB_HOST: aics-postgres + DB_PORT: 5432 + DB_NAME: ${POSTGRES_DB} + DB_USERNAME: ${POSTGRES_USER} + DB_PASSWORD: ${POSTGRES_PASSWORD} + JWT_ISSUER: kgudevelopers@gmail.com + JWT_SECRET_KEY: ${JWT_SECRET_KEY} + REDIS_HOST: aics-redis + REDIS_PASSWORD: ${REDIS_PASSWORD} + FILE_SECRET_KEY: ${FILE_SECRET_KEY} + expose: + - '8081' + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + volumes: + - aics-data:/app/cloud + networks: + - aics-network + + aics-auth: + image: kgudevelopers/aics-auth:prod + container_name: aics-auth + restart: unless-stopped + env_file: + - .env + environment: + SPRING_PROFILES_ACTIVE: prod + DB_HOST: aics-postgres + DB_PORT: 5432 + DB_NAME: ${POSTGRES_DB} + DB_USERNAME: ${POSTGRES_USER} + DB_PASSWORD: ${POSTGRES_PASSWORD} + JWT_ISSUER: kgudevelopers@gmail.com + JWT_SECRET_KEY: ${JWT_SECRET_KEY} + REDIS_HOST: aics-redis + REDIS_PASSWORD: ${REDIS_PASSWORD} + FILE_SECRET_KEY: ${FILE_SECRET_KEY} + expose: + - '8082' + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + volumes: + - aics-data:/app/cloud + networks: + - aics-network + + aics-client-graduate: + image: kgudevelopers/aics-client-graduate:latest + container_name: aics-client-graduate + restart: unless-stopped + ports: + - 80:80 + depends_on: + - aics-api + - aics-admin + - aics-auth + networks: + - aics-network + +volumes: + aics-data: + driver: local + driver_opts: + type: none + o: bind + device: ./volumes/aics-data diff --git a/apps/graduate/nginx.conf b/apps/graduate/nginx.conf index 51abb17a..217cab01 100644 --- a/apps/graduate/nginx.conf +++ b/apps/graduate/nginx.conf @@ -2,16 +2,31 @@ server { listen 80; server_name _; - # Vite/React 등 SPA 빌드 결과 위치 root /usr/share/nginx/html; index index.html; location / { - # 정적 파일이 없으면 SPA 라우팅을 위해 index.html 반환 try_files $uri /index.html; } + location /proxy-api/ { + proxy_pass http://aics-api:8080/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + + location /proxy-admin/ { + proxy_pass http://aics-admin:8081/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + + location /proxy-auth/ { + proxy_pass http://aics-auth:8082/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + access_log /var/log/nginx/graduate_access.log; error_log /var/log/nginx/graduate_error.log; -} - +} \ No newline at end of file diff --git a/apps/graduate/src/shared/api/axios.ts b/apps/graduate/src/shared/api/axios.ts index abd0e55f..17b08b2b 100644 --- a/apps/graduate/src/shared/api/axios.ts +++ b/apps/graduate/src/shared/api/axios.ts @@ -51,23 +51,14 @@ interface RefreshTokenResponse { refreshToken?: string; } -/** - * https://aics-api.ummdev.com/ - * 에 전송하는 사용자 API baseURL이 적용된 Instance입니다 */ const userInstance = axios.create({ baseURL: API_URL, }); -/** - * https://aics-admin.ummdev.com/ - * 에 전송하는 관리자 API baseURL이 적용된 Instance입니다 */ const adminInstance = axios.create({ baseURL: API_ADMIN_URL, }); -/** - * https://aics-auth.ummdev.com/ - * 에 전송하는 인증 API baseURL이 적용된 Instance입니다 */ const authInstance = axios.create({ baseURL: API_AUTH_URL, }); diff --git a/apps/graduate/src/shared/constants/endpoint.ts b/apps/graduate/src/shared/constants/endpoint.ts index 649007ff..6c924350 100644 --- a/apps/graduate/src/shared/constants/endpoint.ts +++ b/apps/graduate/src/shared/constants/endpoint.ts @@ -2,16 +2,9 @@ import type { WorkflowStage } from '~/shared/types/graduation'; import { SubmissionType } from '../types'; -export const API_URL = - import.meta.env.VITE_API_URL || 'https://aics-api.kgudevelopers.monster'; - -export const API_AUTH_URL = - import.meta.env.VITE_AUTH_API_URL || - 'https://aics-auth.kgudevelopers.monster'; - -export const API_ADMIN_URL = - import.meta.env.VITE_ADMIN_API_URL || - 'https://aics-admin.kgudevelopers.monster'; +export const API_URL = import.meta.env.VITE_API_URL; +export const API_ADMIN_URL = import.meta.env.VITE_ADMIN_API_URL; +export const API_AUTH_URL = import.meta.env.VITE_AUTH_API_URL; // Request path typing is used by the shared axios wrapper to select base URLs. // Keep this object shallow and extend the current depth instead of nesting deeper. @@ -26,10 +19,7 @@ export const END_POINT = { GRADUATION_USER: (graduationUserId: number) => `/api/v1/admin/graduation-users/${graduationUserId}`, GRADUATION_USERS_BATCH: '/api/v1/admin/graduation-users/batch', - GRADUATION_USER_APPROVE: ( - graduationUserId: number, - submissionId: number, - ) => + GRADUATION_USER_APPROVE: (graduationUserId: number, submissionId: number) => `/api/v1/admin/graduation-users/approve/${graduationUserId}/${submissionId}`, GRADUATION_USER_DISAPPROVE: ( graduationUserId: number,