Files
wace_rps/deploy/onpremise/docker-compose.yml
T
hjjeong 905d5c0976 PR-D G9 수주복사 + G11 Amaranth 수주 결재상신 (wace 1:1)
[G9 수주복사 — wace copyEstimateAndOrderInfo 1:1]
- salesOrderMgmtService.copyOrder: 새 영업번호({YY}C-{NNNN}) 채번 +
  contract_mgmt 23컬럼 INSERT-SELECT(contract_result='', is_direct_order='Y' 강제) +
  contract_item + contract_item_serial 통째 복제
- POST /api/sales/order-mgmt/:id/copy 라우트
- 주문관리 그리드 "수주복사" 버튼 (Copy 아이콘) + handleCopyOrder

[G11 Amaranth 수주 결재상신 — wace ApprovalService.getAmaranthSsoUrl 1:1]
- chpark의 amaranthApprovalClient(HMAC-SHA256 + AES-128-CBC) 재사용
- amaranth_approval만 사용(자체 approval 미경유, wace 운영 패턴 동일)
- target_type='CONTRACT_ORDER', formId='1161', compSeq='1000'
- approKey 분기: 신규 / reject·delete·create는 새 approKey UPDATE / 그 외 재사용
- salesOrderMgmtService.startOrderApproval: user_info.emp_seq 조회 →
  라인 0건 가드 → 매핑 분기 → SSO URL 발급 → INSERT/UPDATE → fullUrl 반환
- POST /api/sales/order-mgmt/:id/amaranth-approval 라우트
- 주문관리 그리드 "결재상신" 버튼 (Send 아이콘, sky-600) + handleAmaranthApproval
- getList SQL에 LEFT JOIN amaranth_approval AMR_ORDER 추가 +
  order_appr_status(작성중/결재중/결재완료/반려 한글) + order_amaranth_status 노출

[DB 스키마]
- amaranth_approval.target_objid BIGINT → VARCHAR(80) (wace 운영 1:1)
  · 출처: wace 매퍼 T.OBJID::VARCHAR = AMR_ORDER.TARGET_OBJID
  · 사유: contract_mgmt.objid가 'CM-' prefix varchar라 bigint cast 불가
  · 데이터 0건 무손실, ECR/CS는 bigint→varchar 자동 cast로 무영향
- approvalTableMigration.ts 동기화

[운영 배포 환경변수 — wace Constants 1:1 default 박힘]
- AMARANTH_OUT_PROCESS_CODE=RPSPLM_00001 (wace Constants.java:81)
- AMARANTH_FORM_ID_CONTRACT_ORDER=1161 (wace orderMgmtList.jsp:558)
- AMARANTH_COMP_SEQ=1000 (wace orderMgmtList.jsp:559)
- 3개 docker-compose(deploy/onpremise, docker/deploy, docker/prod) 모두
  ${VAR:-default} 형식으로 매핑 — 호스트 .env 미설정 시 default 동작

[검증]
- G9: BEGIN/ROLLBACK으로 26C-0800(라인 3건) 복사 시뮬레이션 — 헤더 23컬럼 1:1,
  채번 26C-0803, 라인 3→3건 + seq 보존
- G11: 4단계 상태 라벨(create→inProcess→complete→reject) 모두 정상,
  VARCHAR PK(CM-... prefix) JOIN도 정상
- 문서: docs/migration/sales/06-copy-order-verify.md, 07-amaranth-approval-verify.md
- GAP: G9 , G10 (영업 GAP 아님 — Admin 도메인), G11 

[운영 트러블슈팅 노트 — 07-verify.md 트러블슈팅 섹션]
dev에서 amaranth 측이 "API Proxy 호출 시 유효한 레디스 값이 존재하지 않습니다"로
거부. 우리 코드는 정상 — 'Amaranth - 결재' accessToken을 amaranth 서버 측
Redis에 등록받아야 동작. chpark/RPS ERP 담당자 협조 영역(코드 변경 없음).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:44:54 +09:00

174 lines
5.9 KiB
YAML

# Vexplor 온프레미스(공장) 배포용 Docker Compose
# 사용법: docker compose up -d
services:
# ============================================
# 1. 데이터베이스 (PostgreSQL)
# ============================================
database:
image: postgres:15-alpine
container_name: vexplor-db
environment:
POSTGRES_USER: ${DB_USER:-vexplor}
POSTGRES_PASSWORD: ${DB_PASSWORD:?DB_PASSWORD is required}
POSTGRES_DB: ${DB_NAME:-vexplor}
TZ: Asia/Seoul
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init-db:/docker-entrypoint-initdb.d # 초기화 스크립트 (선택)
ports:
- "${DB_PORT:-5432}:5432"
restart: always
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-vexplor}"]
interval: 10s
timeout: 5s
retries: 5
networks:
- vexplor-network
# ============================================
# 2. 백엔드 API (Node.js)
# ============================================
backend:
image: harbor.wace.me/speefox_vexplor/vexplor-backend:${IMAGE_TAG:-latest}
container_name: vexplor-backend
environment:
NODE_ENV: production
PORT: 3001
HOST: 0.0.0.0
TZ: Asia/Seoul
# DB 연결
DB_HOST: database
DB_PORT: 5432
DB_USER: ${DB_USER:-vexplor}
DB_PASSWORD: ${DB_PASSWORD}
DB_NAME: ${DB_NAME:-vexplor}
# JWT
JWT_SECRET: ${JWT_SECRET:?JWT_SECRET is required}
JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-24h}
# 암호화 키 (메일 등 민감정보 암호화용)
ENCRYPTION_KEY: ${ENCRYPTION_KEY:-vexplor-encryption-key-32characters-secure}
# 회사 코드 (온프레미스는 단일 회사)
DEFAULT_COMPANY_CODE: ${COMPANY_CODE:-SPIFOX}
# 로깅
LOG_LEVEL: ${LOG_LEVEL:-info}
# SMTP (견적서/발주서 등 메일 발송) — 호스트 .env에서 실값 주입
SMTP_HOST: ${SMTP_HOST:-erp.rps-korea.com}
SMTP_PORT: ${SMTP_PORT:-25}
SMTP_TLS: ${SMTP_TLS:-false}
SMTP_SEND_SWITCH: ${SMTP_SEND_SWITCH:-Y}
SMTP_USER_ERP: ${SMTP_USER_ERP:-}
SMTP_PW_ERP: ${SMTP_PW_ERP:-}
SMTP_USER_SALES: ${SMTP_USER_SALES:-}
SMTP_PW_SALES: ${SMTP_PW_SALES:-}
SMTP_USER_PURCHASE: ${SMTP_USER_PURCHASE:-}
SMTP_PW_PURCHASE: ${SMTP_PW_PURCHASE:-}
# Amaranth 전자결재 (수주/견적 등) — 호스트 .env에서 실값 주입
# OUT_PROCESS_CODE: wace Constants.AMARANTH_OUT_PROCESS_CODE='RPSPLM_00001' 1:1
# 도메인별 fallback: AMARANTH_OUT_PROCESS_CODE_CONTRACT_ORDER → AMARANTH_OUT_PROCESS_CODE
AMARANTH_OUT_PROCESS_CODE: ${AMARANTH_OUT_PROCESS_CODE:-RPSPLM_00001}
AMARANTH_OUT_PROCESS_CODE_CONTRACT_ORDER: ${AMARANTH_OUT_PROCESS_CODE_CONTRACT_ORDER:-}
AMARANTH_FORM_ID_CONTRACT_ORDER: ${AMARANTH_FORM_ID_CONTRACT_ORDER:-1161}
AMARANTH_COMP_SEQ: ${AMARANTH_COMP_SEQ:-1000}
volumes:
- backend_uploads:/app/uploads
- backend_data:/app/data
- backend_logs:/app/logs
ports:
- "${BACKEND_PORT:-3001}:3001"
depends_on:
database:
condition: service_healthy
restart: always
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3001/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
networks:
- vexplor-network
labels:
- "com.centurylinklabs.watchtower.enable=true"
# ============================================
# 3. 프론트엔드 (Next.js)
# ============================================
frontend:
image: harbor.wace.me/speefox_vexplor/vexplor-frontend:${IMAGE_TAG:-latest}
container_name: vexplor-frontend
environment:
NODE_ENV: production
PORT: 3000
HOSTNAME: 0.0.0.0
TZ: Asia/Seoul
# 백엔드 API URL (내부 통신)
NEXT_PUBLIC_API_URL: http://${SERVER_IP:-localhost}:${BACKEND_PORT:-3001}/api
ports:
- "${FRONTEND_PORT:-80}:3000"
depends_on:
- backend
restart: always
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
networks:
- vexplor-network
labels:
- "com.centurylinklabs.watchtower.enable=true"
# ============================================
# 4. Watchtower (자동 업데이트)
# ============================================
watchtower:
image: containrrr/watchtower:latest
container_name: vexplor-watchtower
environment:
TZ: Asia/Seoul
DOCKER_API_VERSION: "1.44"
# Harbor 레지스트리 인증
REPO_USER: ${HARBOR_USER}
REPO_PASS: ${HARBOR_PASSWORD}
# 업데이트 설정
# WATCHTOWER_POLL_INTERVAL: ${UPDATE_INTERVAL:-300} # 간격 기반 (비활성화)
WATCHTOWER_SCHEDULE: "0 0 * * * *" # 매시 정각에 실행 (cron 형식)
WATCHTOWER_CLEANUP: "true" # 이전 이미지 자동 삭제
WATCHTOWER_INCLUDE_STOPPED: "true" # 중지된 컨테이너도 업데이트
WATCHTOWER_ROLLING_RESTART: "true" # 순차 재시작 (다운타임 최소화)
WATCHTOWER_LABEL_ENABLE: "true" # 라벨이 있는 컨테이너만 업데이트
# 알림 설정 (선택)
# WATCHTOWER_NOTIFICATIONS: slack
# WATCHTOWER_NOTIFICATION_SLACK_HOOK_URL: ${SLACK_WEBHOOK_URL}
volumes:
- /var/run/docker.sock:/var/run/docker.sock
# Harbor 인증 정보 (docker login 후 생성됨)
- ~/.docker/config.json:/config.json:ro
restart: always
networks:
- vexplor-network
# ============================================
# 볼륨 정의
# ============================================
volumes:
postgres_data:
driver: local
backend_uploads:
driver: local
backend_data:
driver: local
backend_logs:
driver: local
# ============================================
# 네트워크 정의
# ============================================
networks:
vexplor-network:
driver: bridge