본문으로 건너뛰기

배포

AISCouncil는 Cloudflare Pages의 정적 파일로 배포되며 API 로직은 Cloudflare Workers에서 실행됩니다. 통합 배포 스크립트가 모든 대상을 처리합니다.

배포 대상

대상URL타입명령어
aiscouncil.netCF Pages (정적)scripts/deploy.sh pages
스테이징aiscouncil.netCF Pages (정적)scripts/deploy.sh pages-staging
API Workerapi.aiscouncil.netCF Workerscripts/deploy.sh worker
Auth Workerauth.aiscouncil.netCF Workerscripts/deploy.sh worker-auth
앱 스토어store.aiscouncil.netCF Pages (정적)scripts/deploy.sh store
전체위의 모든 것모든 것scripts/deploy.sh all

환경 변수

~/.bashrc에서 내보내세요 (절대 커밋하지 마세요):

export CF_ACCOUNT_ID_AISCOUNCIL="your-cloudflare-account-id"
export CF_PAGES_TOKEN_AISCOUNCIL="your-pages-api-token"
export CF_WORKER_TOKEN_AISCOUNCIL="your-worker-api-token"

선택적 오버라이드:

export CF_PAGES_PROJECT_AISCOUNCIL="aiscouncil"              # 기본값
export CF_PAGES_PROJECT_AISCOUNCIL_STAGING="aiscouncil-staging" # 기본값
경고

이 토큰들은 Cloudflare 계정에 배포 접근 권한을 부여합니다. 저장소에 절대 커밋하지 마세요. 필수 변수가 누락되면 배포 스크립트가 에러와 함께 종료됩니다.

Pages 배포 (프로덕션)

단계별

  1. 소스에서 앱 조립:
./build.sh
  1. 프로덕션으로 배포:
scripts/deploy.sh pages

이 명령은:

  • 깨끗한 _deploy/ 디렉토리 생성
  • 개발 아티팩트를 제외하고 rsync로 정적 파일 복사
  • html-minifier-terserindex.html 축소 (~40% 크기 감소)
  • --branch=main으로 Cloudflare Pages에 배포
  • _deploy/ 정리
정보

프로덕션 배포는 항상 --branch=main을 사용합니다. 이것이 CF Pages가 프로덕션 도메인(aiscouncil.net)에서 서브하기 위해 필요합니다.

배포되는 것

rsync 단계는 브라우저面向 에셋이 아닌 모든 것을 제외합니다:

제외 디렉토리: src/, tools/, kernel/, serve/, worker/, worker-auth/, doc.aiscouncil.net/, node_modules/, .git/, .github/, .carl/, .claude/, modules/, scripts/, core-types/, bridge/, i18n/, dist/, build/

제외 파일 타입: *.py, *.zig, *.zon, *.md, *.sh, *.css, .env*

제외 설정 파일: package.json, package-lock.json, vitest.config.*, tsconfig.json, .cfignore, .gitignore

남는 것은 프로덕션 에셋입니다: index.html, sw.js, 아이콘, manifest.webmanifest, registry/ JSON 파일, sdk/, ads.json, sitemap.xml, 그리고 미니 프로그램 또는 앱 디렉토리.

축소

프로덕션 배포는 index.html을 다음 옵션으로 html-minifier-terser에 통과합니다:

  • 공백 축소
  • 주석 제거
  • 중복 속성 제거
  • 불리언 속성 축소
  • 인라인 CSS 축소
  • 인라인 JavaScript 축소

일반적인 크기 감소는 ~40%입니다 (예: 980 KB에서 ~580 KB로).

스테이징 배포

축소 없이 스테이징 환경에 배포합니다:

scripts/deploy.sh pages-staging

스테이징은 aiscouncil.net에서 서브됩니다. 앱은 런타임에 도메인을 자동 감지하고 그에 따라 API URL, 쿠키 도메인, 교차 출처 참조를 조정합니다.

스테이징을 프로덕션으로 승격

스테이징에서 검증한 후 동일한 빌드를 프로덕션으로 승격합니다:

scripts/deploy.sh promote

이것은 축소를 활성화하여 현재 코드를 프로덕션 Pages 프로젝트에 재배포합니다. 앱 코드는 동일합니다. 도메인만 변경됩니다.

Worker 배포

API Worker

scripts/deploy.sh worker

이것은 환경의 계정 ID와 Worker 토큰을 사용하여 worker/ 디렉토리 내에서 npx wrangler deploy를 실행합니다.

Auth Worker

scripts/deploy.sh worker-auth

worker-auth/ 디렉토리에도 동일한 프로세스.

Worker 시크릿

Worker는 코드 배포와 별도로 설정되는 시크릿이 필요합니다. Worker 디렉토리에서 wrangler secret put을 사용하세요:

cd worker
npx wrangler secret put JWT_SECRET
npx wrangler secret put STRIPE_SECRET_KEY
npx wrangler secret put STRIPE_WEBHOOK_SECRET
npx wrangler secret put WEBHOOK_PATH_SECRET
cd worker-auth
npx wrangler secret put JWT_SECRET
npx wrangler secret put GOOGLE_CLIENT_SECRET
npx wrangler secret put APPLE_CLIENT_SECRET
npx wrangler secret put GITHUB_CLIENT_SECRET

시크릿은 배포 간에 유지됩니다. 한 번만 설정하거나 자격 증명을 순환할 때 설정하면 됩니다.

Worker 설정

각 Worker는 다음을 정의하는 wrangler.toml을 가집니다:

  • Worker 이름과 라우트
  • KV 네임스페이스 바인딩
  • 환경 변수 참조
  • 호환성 설정

서비스 워커 캐시

클라이언트 측 서비스 워커(sw.js)는 버전이 있는 캐시를 사용합니다:

const CACHE = "ais-v1.0.0";

캐시 버전을 올려야 할 때:

  • 앱 셸의 호환성 깨는 변경 (HTML 구조, 중요 CSS)
  • 사전 캐시된 에셋 변경 (아이콘, 매니페스트)
  • 주요 버전 릴리스

버전을 올리면 서비스 워커가 다음을 수행합니다:

  1. 새 이름으로 새 캐시 생성
  2. 나열된 모든 에셋 사전 캐시
  3. 활성화 시 모든 오래된 캐시 삭제
경고

호환성 깨는 변경 후 캐시 버전을 올리는 것을 잊으면 사용자가 브라우저 캐시를 수동으로 지우거나 오래된 서비스 워커가 만료될 때까지 오래된 콘텐츠를 보게 됩니다.

모든 것 배포

순서대로 Pages 앱, API Worker, Auth Worker를 배포합니다:

scripts/deploy.sh all

배포 후 검증

배포 후 앱이 올바르게 서브되고 있는지 확인합니다:

# 프로덕션 확인
curl -s https://aiscouncil.net/ | head -5

# API 헬스 확인
curl -s https://api.aiscouncil.net/health

# 인증 헬스 확인
curl -s https://auth.aiscouncil.net/health
정보

Cloudflare Pages는 배포 시 CDN 캐시를 자동으로 무효화하지만 전 세계 전파에 1-2분이 걸릴 수 있습니다. 오래된 콘텐츠가 보이면 잠시 기다렸다가 다시 시도하세요.

도메인 아키텍처

앱은 프로덕션과 스테이징을 모두 지원하기 위해 런타임에 도메인 감지를 사용합니다:

도메인상수프로덕션스테이징
AIS.DOMAINaiscouncil.netaiscouncil.net
마케팅AIS.WWWwww.aiscouncil.netwww.aiscouncil.net
APIAPI_BASEhttps://api.aiscouncil.net/v1https://api.aiscouncil.net/v1
인증AUTH_BASEhttps://auth.aiscouncil.net/v1https://auth.aiscouncil.net/v1
문서AIS.DOC_BASEhttps://doc.aiscouncil.nethttps://doc.aiscouncil.net
스토어AIS.STORE_URLhttps://store.aiscouncil.nethttps://store.aiscouncil.net

API 기본 URL은 로컬 개발을 위해 localStorage를 통해 재정의할 수도 있습니다:

localStorage.setItem("ais-api-base", "http://localhost:8787/v1");
localStorage.setItem("ais-auth-base", "http://localhost:8788/v1");

로컬 개발

배포 없이 로컬 개발을 하려면:

  1. 앱 빌드: ./build.sh
  2. 모든 정적 파일 서버로 index.html 서브 (예: python3 -m http.server 8080)
  3. Wrangler로 로컬에서 Worker 실행:
cd worker && npx wrangler dev
cd worker-auth && npx wrangler dev --port 8788
  1. 브라우저 콘솔에서 API 기본 URL 재정의:
localStorage.setItem("ais-api-base", "http://localhost:8787/v1");
localStorage.setItem("ais-auth-base", "http://localhost:8788/v1");
location.reload();