배포
AISCouncil는 Cloudflare Pages의 정적 파일로 배포되며 API 로직은 Cloudflare Workers에서 실행됩니다. 통합 배포 스크립트가 모든 대상을 처리합니다.
배포 대상
| 대상 | URL | 타입 | 명령어 |
|---|---|---|---|
| 앱 | aiscouncil.net | CF Pages (정적) | scripts/deploy.sh pages |
| 스테이징 | aiscouncil.net | CF Pages (정적) | scripts/deploy.sh pages-staging |
| API Worker | api.aiscouncil.net | CF Worker | scripts/deploy.sh worker |
| Auth Worker | auth.aiscouncil.net | CF Worker | scripts/deploy.sh worker-auth |
| 앱 스토어 | store.aiscouncil.net | CF 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 배포 (프로덕션)
단계별
- 소스에서 앱 조립:
./build.sh
- 프로덕션으로 배포:
scripts/deploy.sh pages
이 명령은:
- 깨끗한
_deploy/디렉토리 생성 - 개발 아티팩트를 제외하고
rsync로 정적 파일 복사 html-minifier-terser로index.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)
- 사전 캐시된 에셋 변경 (아이콘, 매니페스트)
- 주요 버전 릴리스
버전을 올리면 서비스 워커가 다음을 수행합니다:
- 새 이름으로 새 캐시 생성
- 나열된 모든 에셋 사전 캐시
- 활성화 시 모든 오래된 캐시 삭제
호환성 깨는 변경 후 캐시 버전을 올리는 것을 잊으면 사용자가 브라우저 캐시를 수동으로 지우거나 오래된 서비스 워커가 만료될 때까지 오래된 콘텐츠를 보게 됩니다.
모든 것 배포
순서대로 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.DOMAIN | aiscouncil.net | aiscouncil.net |
| 마케팅 | AIS.WWW | www.aiscouncil.net | www.aiscouncil.net |
| API | API_BASE | https://api.aiscouncil.net/v1 | https://api.aiscouncil.net/v1 |
| 인증 | AUTH_BASE | https://auth.aiscouncil.net/v1 | https://auth.aiscouncil.net/v1 |
| 문서 | AIS.DOC_BASE | https://doc.aiscouncil.net | https://doc.aiscouncil.net |
| 스토어 | AIS.STORE_URL | https://store.aiscouncil.net | https://store.aiscouncil.net |
API 기본 URL은 로컬 개발을 위해 localStorage를 통해 재정의할 수도 있습니다:
localStorage.setItem("ais-api-base", "http://localhost:8787/v1");
localStorage.setItem("ais-auth-base", "http://localhost:8788/v1");
로컬 개발
배포 없이 로컬 개발을 하려면:
- 앱 빌드:
./build.sh - 모든 정적 파일 서버로
index.html서브 (예:python3 -m http.server 8080) - Wrangler로 로컬에서 Worker 실행:
cd worker && npx wrangler dev
cd worker-auth && npx wrangler dev --port 8788
- 브라우저 콘솔에서 API 기본 URL 재정의:
localStorage.setItem("ais-api-base", "http://localhost:8787/v1");
localStorage.setItem("ais-auth-base", "http://localhost:8788/v1");
location.reload();