ProcessCenter 배포·인증 기준
이 문서는 ProcessCenter를 특정 배포 플랫폼에 종속되지 않은 단일 Node 서버로 운영하기 위한 기준을 정의한다. API(dist/index.js)와 SPA(dist/public)를 한 프로세스가 함께 제공하므로 컨테이너·자체 호스팅·관리형 클라우드 어디에서도 동일한 코드와 동일한 환경변수로 동작한다.
1. 실행 모델
| 항목 | 내용 |
|---|---|
| 프로세스 | 장기 실행 Node 서버가 API와 정적 자산(dist/public)을 함께 제공 |
| 진입점 | server/_core/index.ts — 마이그레이션·레거시 보정 후 PORT에서 listen |
| 요청 처리 | server/app.ts의 createApp()이 Express 앱을 구성 |
| 플랫폼 종속 | 없음. 서버리스 전용 진입점과 플랫폼 전용 설정 파일을 두지 않는다 |
pnpm install --frozen-lockfile
pnpm run build
pnpm start # NODE_ENV=production node dist/index.js, PORT 기본 3000DB 마이그레이션은 애플리케이션 기동과 분리해 release 단계에서 실행하는 것을 권장한다(PostgreSQL: pnpm db:postgres:migrate:node, MySQL: drizzle-kit migrate).
2. 필수 환경변수
NODE_ENV=production
DATABASE_URL=postgresql://user:password@db-host:5432/processcenter
DATABASE_DIALECT=postgresql
APP_ORIGIN=https://process-center.example.com
PORTAL_CONSOLE_ORIGIN=https://directoryservice.example.com
PORTAL_CONSOLE_API_KEY=<server-only-secret>
PORTAL_CONSOLE_PORTAL_ID=process-center
CORS_ORIGINS=https://process-center.example.com
PORTAL_JWT_SECRET=<long-random-secret>
DEPLOYMENT_PROFILE=CLOUDAPP_ORIGIN은 인증 콜백을 결정하는 정규 주소다. 운영에서는 요청 Host 헤더에만 의존하지 않고 이 값을 우선 사용한다. PORTAL_CONSOLE_API_KEY, PORTAL_JWT_SECRET, DATABASE_URL은 절대로 VITE_ 접두사를 붙이지 않고 서버 전용 환경변수로 저장한다.
DEPLOYMENT_PROFILE은 호스팅 종류를 운영자가 명시하는 값이며 CLOUD(기본) 또는 ON_PREM만 사용한다. 애플리케이션은 배포 플랫폼을 자동 감지하지 않는다.
3. 콜백 주소 등록
PortalConsole의 process-center 포털 클라이언트에 공개 주소별로 callback을 등록한다. 형식은 항상 <APP_ORIGIN>/auth/callback이다.
| 환경 | APP_ORIGIN | PortalConsole 허용 callback |
|---|---|---|
| 운영 | https://process-center.example.com | https://process-center.example.com/auth/callback |
| 스테이징·검증 | https://process-center-staging.example.com | https://process-center-staging.example.com/auth/callback |
| 온프레미스 | https://process-center.company.internal | https://process-center.company.internal/auth/callback |
외부 인증 제공자는 /auth/callback으로 돌아오며 애플리케이션 서버가 이 경로를 직접 처리한다. 리버스 프록시가 /api를 애플리케이션으로 전달하도록 구성하면 경로 rewrite 규칙은 필요 없다.
4. 쿠키 정책
ProcessCenter와 API를 같은 origin으로 서비스하는 구성이 가장 안전하다. 이 경우 SameSite=Lax; Secure; HttpOnly 세션 쿠키를 사용하며 별도 CORS가 필요하지 않다.
| 구성 | 쿠키 권장값 | CORS |
|---|---|---|
| API와 SPA가 같은 origin | HttpOnly; Secure; SameSite=Lax; Path=/ | 불필요 |
SPA 정적 호스팅 + API 서버, 리버스 프록시로 /api 연결 | HttpOnly; Secure; SameSite=Lax | 불필요에 가깝고 같은 public origin 권장 |
| 프론트와 API가 서로 다른 site | HttpOnly; Secure; SameSite=None; Path=/ | 정확한 origin allowlist와 credentials 필요 |
서로 다른 site에서 SameSite=None을 사용할 때는 HTTPS가 필수이며, 프론트엔드 요청은 credentials: "include"를 사용해야 한다. Access-Control-Allow-Origin: *와 Access-Control-Allow-Credentials: true를 함께 사용하면 안 된다.
5. CORS 설정
분리 배포가 필요한 경우 API 서버에 다음처럼 정확한 origin만 등록한다.
CORS_ORIGINS=https://process-center.example.com,https://portal.example.com공통 Express 앱은 CORS_ORIGINS 또는 APP_ORIGIN을 comma-separated allowlist로 읽고, 허용된 요청에만 다음 응답 헤더를 설정한다.
Access-Control-Allow-Origin: <exact-request-origin>
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Content-Type, X-Requested-With
Access-Control-Allow-Methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
Vary: OriginPortalConsole 자체의 브라우저 CORS가 필요한 구조라면 PortalConsole에서도 ProcessCenter public origin을 allowlist에 추가해야 한다. API key는 브라우저에서 PortalConsole로 직접 보내지 않고 ProcessCenter 서버가 서버 간 요청으로 사용한다.
6. 컨테이너·자체 호스팅 배포
컨테이너 이미지를 사용하는 구성을 표준으로 삼는다.
docker build -t process-center:latest .
docker run --env-file .env.production -p 3000:3000 process-center:latest외부 reverse proxy가 public 도메인을 TLS로 제공하고 내부 ProcessCenter 컨테이너로 전달한다. X-Forwarded-Proto와 X-Forwarded-Host를 전달해야 하며, 애플리케이션의 APP_ORIGIN은 reverse proxy의 public origin으로 설정한다. 관리형 클라우드를 사용하더라도 위 환경변수와 헬스 체크만 동일하게 구성하면 코드 변경은 필요 없다.
PortalConsole 동기화 스케줄러는 애플리케이션 프로세스에서 실행된다. replica를 여러 개 띄우는 경우 동기화 리스(lease) 설정과 중복 실행 정책을 함께 확인한다.
7. 온프레미스 점검표
온프레미스 운영 자체에는 구조적인 제약이 없지만, 다음 조건이 충족되어야 한다.
| 영역 | 점검 내용 |
|---|---|
| DB | MySQL 또는 PostgreSQL 연결, 마이그레이션, 백업·복구 검증 |
| 인증 | 온프레미스 public origin의 /auth/callback을 PortalConsole에 등록 |
| 네트워크 | ProcessCenter 서버가 PortalConsole HTTPS endpoint에 접근 가능 |
| TLS | reverse proxy 인증서, HSTS, Secure 쿠키 검증 |
| 저장소 | 업로드 파일을 영속 볼륨 또는 S3 호환 스토리지에 저장 |
| 스케줄러 | 다중 replica에서 PortalConsole 동기화 중복 실행 방지 |
| 비밀값 | API key·JWT secret·DB password를 secret store에 저장 |
| 운영 | health check, 로그 수집, 자동 재시작, 정기 백업 구성 |
프론트엔드와 API를 서로 다른 호스트로 운영하지 않는다면 CORS와 cross-site cookie 문제를 크게 줄일 수 있다. 내부망 전용으로 운영하더라도 PortalConsole가 외부 또는 다른 내부 네트워크에 있다면 DNS와 방화벽의 양방향 정책을 별도로 검증한다.
8. 로그인 진입 동작
세션이 없는 사용자는 업무 화면 대신 전체 화면 로그인 카드를 보게 된다. 중앙 인증(PortalConsole)이 활성이면 클릭 없이 자동으로 /api/auth/login → PortalConsole /connect/authorize로 이동한다.
자동 이동은 다음 조건을 모두 만족할 때만 수행한다.
| 조건 | 이유 |
|---|---|
/api/auth/config 응답을 실제로 받았고 enabled: true | 설정 조회 실패나 중앙 인증 비활성 상태에서 이동하면 안내 없는 반복 이동이 된다 |
URL에 auth_error가 없음 | 이미 실패한 왕복이므로 카드에 오류를 표시하고 사용자가 직접 판단하게 한다 |
?login=manual이 아님 | 테스트·스크린샷·수동 로그인용 우회 경로 |
이번 탭에서 아직 시도하지 않음(sessionStorage) | 중앙 로그인 화면을 닫고 돌아온 경우 무한 리다이렉트를 막는다 |
로그인에 성공하면 시도 기록을 지워, 로그아웃 후에는 다시 자동 이동한다. 자동 이동이 걸리지 않은 경우에도 카드의 “PortalConsole에서 계속” 버튼은 그대로 남는다.
9. 인증 장애 진단 순서
첫째, GET /api/auth/config가 200과 함께 enabled: true를 반환하는지 확인한다. 둘째, GET /api/auth/login이 404가 아니라 PortalConsole의 /connect/authorize로 302 redirect를 반환하는지 확인한다. 셋째, redirect query의 redirect_uri가 PortalConsole에 등록된 값과 완전히 같은지 확인한다. 넷째, callback 이후 process_center_directory_session 쿠키가 발급되는지 확인한다. 마지막으로 브라우저에서 /api/trpc 요청이 해당 쿠키와 함께 전송되는지 확인한다.
curl -i https://process-center.example.com/api/auth/config
curl -I 'https://process-center.example.com/api/auth/login?returnTo=/'/api/auth/login이 404를 반환하면 서버 번들(dist/index.js)이 최신인지와 reverse proxy의 /api 라우팅을 확인한다. 302가 반환되지만 PortalConsole에서 거부하면 callback allowlist, client_id, redirect_uri, portal ID를 확인한다.