이 가이드는 두 가지 프로덕션 경로를 다룹니다. 글로벌 npm 패키지를 자체 PostgreSQL과 Redis에 연결해 실행하는 방법, 그리고 저장소의 설치 프로그램으로 함께 제공되는 AWS 스택을 프로비저닝하는 방법입니다. 단일 머신에서 시험해 보려면 [시작하기](/ko/guides/getting-started/)를 따르고, 컨테이너 배포는 [Docker로 배포](/ko/guides/deploy-docker/)를 참고하세요. 부트스트랩 인증 정보, 싱글 사인온, 안전한 업그레이드는 [셀프 호스팅 Chorus 운영하기](/ko/guides/deploy-operations/)에서 다룹니다.

## 외부 PostgreSQL에 연결해 글로벌 패키지 실행하기

웹 애플리케이션을 실행할 호스트에 Chorus 명령을 글로벌로 설치합니다.

```sh
npm install --global @chorus-aidlc/chorus
```

`DATABASE_URL`로 Chorus가 기존 PostgreSQL 데이터베이스를 사용하도록 지정하고, 필요한 인증 및 비밀 변수를 설정한 다음 시작합니다.

```sh
DATABASE_URL='postgresql://chorus:password@db.internal:5432/chorus' \
NEXTAUTH_SECRET="${NEXTAUTH_SECRET:?Set a persistent random secret first}" \
SUPER_ADMIN_EMAIL='admin@example.com' \
SUPER_ADMIN_PASSWORD_HASH='$2b$10$...' \
chorus
```

시작 시 Chorus는 보류 중인 데이터베이스 마이그레이션을 자동으로 적용하고(`prisma migrate deploy`), 그런 다음 웹 애플리케이션을 `8637` 포트에서 제공합니다. 데이터베이스는 미리 만들어져 있고 접속할 수 있어야 합니다. 이 경로에서는 Chorus가 데이터베이스를 만들어 주지 않습니다.

프로덕션 실행에서 Chorus가 읽는 변수는 다음과 같습니다.

<div class="table-scroll" role="region" aria-label="프로덕션 환경 변수" tabindex="0">

| 변수 | 필수 | 설명 |
| --- | --- | --- |
| `DATABASE_URL` | 예 | PostgreSQL 연결 문자열, `postgresql://user:password@host:port/dbname`. |
| `NEXTAUTH_SECRET` | 여러 인스턴스에서 필수 | 모든 레플리카가 공유하는 서명 비밀 키. 단일 npm 인스턴스에서는 생략할 수 있으며, 이 경우 `chorus`가 기본적으로 `~/.chorus-data/.secret`에 키를 생성해 저장합니다. 환경 변수에 알려진 자리 표시자가 있으면 경고를 남기고 무시합니다. 저장된 키가 비어 있거나 공개 자리 표시자이면 시작을 중단합니다. |
| `SUPER_ADMIN_EMAIL` | 예 | `/admin` 슈퍼 관리자 패널을 부트스트랩하는 이메일. |
| `SUPER_ADMIN_PASSWORD_HASH` | 예 | 슈퍼 관리자 비밀번호의 bcrypt 해시. |
| `DEFAULT_USER` | 선택 | 첫 접근을 위한 내장 이메일/비밀번호 로그인을 활성화합니다. |
| `DEFAULT_PASSWORD` | 선택 | 내장 로그인의 비밀번호. |
| `REDIS_URL` | 선택 | Redis 연결 문자열. 인스턴스를 두 개 이상 실행하면 필수입니다(아래 참고). |

</div>

이 부트스트랩 인증 정보의 작동 방식, bcrypt 해시 생성 방법, 그리고 내장 로그인을 끄는 방법은 [셀프 호스팅 Chorus 운영하기](/ko/guides/deploy-operations/)를 참고하세요.

:::caution[비밀 정보를 신중히 다루세요]
`NEXTAUTH_SECRET`과 슈퍼 관리자 인증 정보는 완전한 접근 권한을 부여합니다. 셸 히스토리와 소스 관리에 남기지 말고, 공유 호스트에서 명령줄에 직접 입력하는 대신 프로세스 매니저, systemd 유닛 또는 비밀 저장소를 통해 제공하세요.
:::

## 인스턴스를 두 개 이상 실행하기

Chorus는 Redis를 통해 인스턴스 간에 실시간 업데이트(SSE 이벤트 스트림)를 전파합니다. `REDIS_URL`을 공유 Redis로 설정해 모든 인스턴스가 같은 이벤트를 게시하고 수신하도록 하세요.

```sh
REDIS_URL='redis://default:password@redis.internal:6379'
```

**인스턴스 간 이벤트 전파에는 Redis가 필수입니다.** `REDIS_URL`이 없으면 Chorus는 단일 프로세스 안에서만 동작하는 메모리 내 이벤트 버스를 대신 사용하므로, 한 인스턴스에서 일어난 업데이트가 다른 인스턴스에 전달되지 않습니다. 단일 인스턴스 배포는 이 메모리 내 이벤트 버스로 Redis 없이 실행할 수 있지만, 인스턴스가 두 개 이상인 배포는 공유 Redis를 반드시 구성해야 합니다.

또한 모든 인스턴스에 같은 안전한 `NEXTAUTH_SECRET`을 설정해, 어느 인스턴스가 요청을 받더라도 Chorus가 서명한 세션이 유효하도록 하세요.

## AWS CDK 스택 배포하기

Chorus에는 `packages/chorus-cdk` 아래의 AWS CDK 스택과, 이 스택을 대화형으로 배포하는 저장소 루트의 `install.sh`가 포함되어 있습니다. 이 스택은 관리형 PostgreSQL과 Redis를 갖추고 HTTPS로 접근하는 완전한 배포를 구축합니다.

### 전제 조건

`install.sh`는 `aws`, `node`, `pnpm`과 유효한 AWS 인증 정보가 있는지 확인합니다. 먼저 `aws configure` 또는
`AWS_PROFILE`을 설정하세요. 인증서 요구 사항은 아래 모드에 따라 다릅니다.

### 배포 모드 선택

- **`alb`(기본값)**: 공개 ALB의 HTTPS 포트 443을 사용합니다. 배포 리전의 ACM 인증서는 필수이며
  커스텀 도메인은 선택 사항입니다.
- **`cloudfront`**: CloudFront가 공개 HTTPS를 제공하고 VPC origin을 통해 프라이빗 ALB의 HTTP 포트 80으로
  전달합니다. 기본 `*.cloudfront.net` 도메인은 인증서를 준비할 필요가 없습니다. 커스텀 도메인에는
  도메인과 **`us-east-1`** ACM 인증서를 함께 제공하세요. 캐시는 비활성화되어 인증된 페이지와 API 응답을 캐시하지 않습니다.

`./install.sh`에서 선택하거나 CDK에 `-c deployMode=cloudfront`를 전달하세요. 선택한 모드는
`default_deploy.sh`에도 저장됩니다. 비대화형 설치에는 `CHORUS_INSTALL_NONINTERACTIVE=1`, `DEPLOY_MODE=alb|cloudfront`와
그 밖의 필수 설치 변수를 사용합니다. 어느 모드도 DNS 레코드를 만들지 않으므로, 커스텀 도메인이 `AlbDnsName` 또는
`CloudFrontDomainName` 스택 출력을 가리키도록 설정하고 OIDC 콜백 URL도 갱신하세요.

:::caution[기존 배포의 모드 변경]
모드를 전환하면 ALB가 교체되고 DNS 이름도 바뀝니다. 새 스택을 배포하고 데이터와 DNS를 이전해
검증한 뒤에 기존 스택을 제거하세요. `alb`를 유지하면 기존 구성이 그대로 유지됩니다. `cloudfront`의 ALB는
비공개이므로 CloudFront URL, ECS 로그 또는 대상 그룹 상태로 진단하세요.
배포 리전에서 CloudFront VPC origin을 지원하는지도 확인하세요.
:::

### 설치 프로그램 실행하기

저장소 루트에서:

```sh
./install.sh
```

설치 프로그램은 배포 구성을 묻습니다.

<div class="table-scroll" role="region" aria-label="install.sh 대화 프롬프트" tabindex="0">

| 프롬프트 | 필수 | 참고 |
| --- | --- | --- |
| Deployment mode | 아니요 | `alb`(기본값) 또는 `cloudfront`. |
| Stack name | 아니요 | 기본값 `Chorus`. |
| ACM Certificate ARN | 모드에 따라 다름 | `alb`는 배포 리전의 인증서가 필수. `cloudfront`는 커스텀 도메인을 사용할 때만 `us-east-1` 인증서가 필수. |
| Custom domain | 아니요 | `cloudfront`에서는 `us-east-1` 인증서와 함께 제공. 생략하면 CloudFront 배포(distribution) 도메인을 사용. |
| Super admin email | 예 | `/admin` 슈퍼 관리자 계정을 부트스트랩합니다. |
| Super admin password | 예 | 최소 8자. synth 시점에 bcrypt로 해시되며, 평문은 템플릿에 저장되지 않습니다. |
| NextAuth secret | 아니요 | 비워 두면 synth마다 생성됩니다. 재배포 후에도 세션을 유지하려면 같은 영구 값을 제공하세요. |

스택은 Secrets Manager로 `NEXTAUTH_SECRET`을 공유하지만 synth 시 기존 값을 다시 읽지 않습니다.
배포할 때마다 설치 프로그램이나 CDK의 `nextAuthSecret` context에 같은 값을 사용하세요.
이전에 비워 두었다면 재배포하기 전에 Secrets Manager에 있는 기존 값을 그대로 유지해 키가 교체되지 않도록 하세요.

</div>

답변을 모두 받으면 `install.sh`는 CDK 패키지를 설치·빌드하고, CDK 환경을 부트스트랩한 뒤 스택을 배포합니다. 또한 답변을 담아 다시 실행할 수 있는 `default_deploy.sh`를 작성하므로, 이후 배포에서는 다시 묻지 않습니다.

### 스택이 프로비저닝하는 것

이 스택은 다음을 만듭니다.

<div class="table-scroll" role="region" aria-label="CDK 스택 구성 요소" tabindex="0">

| 구성 요소 | 무엇인가 | 주요 구성 |
| --- | --- | --- |
| Application Load Balancer | `alb`는 공개 HTTPS:443, `cloudfront`는 프라이빗 HTTP:80 오리진. | ECS로 전달. 유휴 타임아웃 60분. |
| CloudFront | `cloudfront` 모드에서만 생성되는 공개 HTTPS 진입점. | 프라이빗 VPC origin, 캐시 비활성화, 선택적 커스텀 도메인. |
| ECS Fargate 서비스 | 프라이빗 서브넷에서 Chorus 컨테이너를 실행합니다. | 희망 태스크 수 2, 1024 CPU 단위 / 2048 MiB, 자동 롤백을 갖춘 배포 서킷 브레이커. |
| Aurora Serverless v2(PostgreSQL) | 관리형 PostgreSQL 클러스터. | 암호화 스토리지. 인증 정보는 자동 생성되어 Secrets Manager에 저장. 백업 보존 1일. |
| ElastiCache Serverless(Redis) | 인스턴스 간 이벤트를 위한 관리형 Redis. | RBAC 사용자. 비밀번호는 Secrets Manager에 저장. |
| Secrets Manager | 생성된 데이터베이스와 Redis 인증 정보, 그리고 앱 비밀 정보를 보관합니다. | 런타임에 ECS 작업에 주입됩니다. |

</div>

### 배포, 업데이트, 파기

<div class="table-scroll" role="region" aria-label="배포 명령" tabindex="0">

| 작업 | 명령 |
| --- | --- |
| 첫 배포 | `./install.sh` |
| 재배포 또는 업데이트 | `./default_deploy.sh`(또는 `pnpm cdk:deploy`) |
| 파기 | `pnpm cdk:destroy` |

</div>

이 스택의 기준이 되는 원본은 `packages/chorus-cdk`입니다. 정확한 리소스 정의가 필요하거나 용량, 보존, 네트워킹을 조정하고 싶을 때는 그곳을 참고하세요.
