designpaca/docs/DEPLOYMENT_PLAN.md
Yun Chan 63a3860f4b
All checks were successful
ci / build (push) Successful in 35s
사이트를 Cloudflare Pages 에 배포하고 실전 기록을 남긴다
배포됨: https://designpaca.pages.dev
커스텀 도메인 designpaca.chanpaca.net 은 Pages 에 등록했고 CNAME 대기 중이다
(토큰에 Zone DNS Edit 가 없어 레코드를 못 만든다).

Cloudflare 403 의 원인은 토큰 권한이 아니라 .env 의 CF_ACCOUNT_ID 가
토큰이 볼 수 없는 계정을 가리킨 것이었다. /accounts 목록으로 실제 접근
가능한 계정을 찾아 교정했다.

DEPLOYMENT_PLAN.md 에 8절을 추가했다 — git push 가 도메인으로 안 되는 이유,
CI 가 네 번 실패한 서로 다른 원인, Cloudflare 진단법.
2026-08-20 17:47:18 +09:00

8.4 KiB

designpaca 배포 운영 계획

이 문서는 designpaca를 git.chanpaca.net(Forgejo)에서 빌드·배포·릴리스하기 위한 전제와 절차를 적는다. 한 번 읽고 그대로 따라 하면 첫 릴리스까지 갈 수 있어야 한다.

0. 전제 — 러너 환경

CI는 self-hosted linux-builder 러너(host 모드)에서 돈다. host 모드라 러너 머신에 있는 것만 쓸 수 있다.

필요 확인 없을 때
Node 20 이상 node -v fnm install 22 && fnm default 22 후 러너 재시작
pnpm 10 pnpm -v corepack enable && corepack prepare pnpm@10.5.2 --activate
git, curl, tar, python3 command -v 배포판 패키지로 설치

build/ci/verify-node.sh가 매 잡 첫 스텝에서 이걸 검사하고, 없으면 명확한 메시지로 즉시 실패시킨다. nvm/fnm/volta의 흔한 설치 경로는 자동으로 PATH에 올려본다.

host 러너에는 Node가 없을 수 있으므로 워크플로에서 uses: 액션을 쓰지 않는다. 체크아웃도 run: 스텝의 git 명령으로 처리한다 (videodownloader 파이프라인과 동일한 패턴).

1. 저장소

git.chanpaca.net/<owner>/designpaca
  • 소스 공개 여부는 자유. 단 npm 배포는 npmjs 공개 레지스트리이므로 코드는 어차피 tarball로 공개된다
  • 기본 브랜치: main
  • 태그 규칙: v<semver> (예: v0.1.0) — 태그 푸시가 릴리스 트리거

2. 시크릿 등록

저장소 → Settings → Actions → Secrets 에 등록한다.

이름 용도 발급처
NPM_TOKEN npmjs 배포 npmjs.com → Access Tokens → Automation 타입
FORGEJO_NPM_TOKEN 사설 레지스트리 미러 Forgejo → 설정 → 애플리케이션 → 액세스 토큰 (write:package 권한)
RELEASE_TOKEN 릴리스 생성·자산 업로드 Forgejo 액세스 토큰 (write:repository)
CF_API_TOKEN Cloudflare Pages 배포 Cloudflare → API Tokens → Edit Cloudflare Workers 템플릿
CF_ACCOUNT_ID Cloudflare 계정 식별 Cloudflare 대시보드 우측 하단 Account ID

변수(Variables)에 선택적으로:

이름 기본값 설명
FORGEJO_NPM_OWNER yunchan 사설 npm 패키지 소유자

시크릿이 없어도 파이프라인은 죽지 않는다. publish-npm.shFORGEJO_NPM_TOKEN이 없으면 미러를 건너뛰고, 릴리스 스텝은 CF_API_TOKEN이 없으면 페이지 배포를 건너뛴다. 하나씩 붙여가며 굴릴 수 있다.

3. 릴리스 절차

3.1 변경 기록

pnpm changeset            # 무엇이 바뀌었는지, patch/minor/major 중 무엇인지 기록
git add .changeset && git commit -m "changeset: <요약>"

3.2 버전 확정

pnpm version              # changeset version + lockfile 갱신
# packages/*/package.json 과 CHANGELOG.md 가 갱신된다
git add -A && git commit -m "release: v<새 버전>"

designpaca · @designpaca/core · @designpaca/skill은 changesets의 fixed 그룹이라 항상 같은 버전으로 움직인다. 스킬 내용과 CLI 버전이 어긋나면 업그레이드 판정(.designpaca_version 비교)이 깨지기 때문이다.

3.3 태그 푸시 = 릴리스 발동

git tag v0.1.0 && git push origin main --tags

파이프라인이 순서대로 수행한다:

  1. verify-node.sh → 의존성 설치
  2. 태그와 packages/cli/package.json 버전 일치 확인 (다르면 즉시 실패)
  3. 스킬 문서 검사 → 타입 검사 → 테스트 → 빌드 → 배포물 점검
  4. npm publish (npmjs) → Forgejo 레지스트리 미러. 이미 배포된 버전이면 조용히 건너뛴다(재실행 안전)
  5. Forgejo draft 릴리스 생성 + tarball 첨부
  6. Cloudflare Pages 배포

3.4 승격

draft 릴리스를 확인하고 수동으로 Publish한다. draft는 익명에게 보이지 않으므로 QA 시간을 벌 수 있다.

3.5 리허설

태그 없이 돌려볼 수 있다. Actions → release → Run workflow. ci-rehearsal prerelease 릴리스로 전 과정을 검증하되 npm 배포는 건너뛴다(DO_PUBLISH=0).

4. 사용자 설치 경로

npx designpaca                 # 온보딩 TUI
npx designpaca install -t claude-code,codex -s user -y

사설 레지스트리에서 직접 받으려면:

npx --registry=https://git.chanpaca.net/api/packages/<owner>/npm/ designpaca

5. 소개 페이지

  • 배포 대상: Cloudflare Pages 프로젝트 designpaca
  • 도메인: designpaca.chanpaca.net (Cloudflare DNS에 CNAME → Pages)
  • 최초 1회만 수동: Cloudflare 대시보드에서 Pages 프로젝트 생성(빈 프로젝트) → 커스텀 도메인 연결. 이후에는 릴리스 워크플로의 wrangler pages deploy가 알아서 올린다

6. 장애 대응

증상 원인 조치
Node 를 찾을 수 없다 host 러너에 Node 미설치 러너 머신에 fnm으로 Node 22 설치 후 러너 재시작
태그와 package.json 이 다르다 pnpm version 없이 태그를 밀었다 태그 삭제 → 3.2부터 다시
npm publish 403 토큰 만료 / 이름 선점 NPM_TOKEN 재발급, npm view designpaca 로 소유 확인
Forgejo 미러 401 토큰에 write:package 없음 토큰 권한 재발급
릴리스 자산 업로드 실패 RELEASE_TOKEN 권한 부족 write:repository 부여
Pages 배포 스킵 CF_API_TOKEN 미등록 시크릿 등록 (없어도 나머지는 성공한다)

7. 롤백

npm은 배포 취소가 사실상 불가능하다(72시간 이내 unpublish만 가능, 같은 버전 재사용 금지). 따라서 되돌리기가 아니라 앞으로 감는다:

# 문제 버전을 latest 에서 내린다
npm dist-tag add designpaca@<직전 정상 버전> latest
# 수정 후 새 패치 릴리스

사용자 쪽 복구는 npx designpaca@<정상버전> update --force.


8. 실제 배포에서 걸린 것 (2026-08-20)

문서대로 되지 않은 지점들이다. 다음 사람이 같은 데서 막히지 않게 남긴다.

git push 는 도메인으로 못 한다

git.chanpaca.net 은 Cloudflare 뒤에 있어(104.21.x) 22·2222 포트가 둘 다 막혀 있다. 오리진을 감추는 정상 구성이다. push 는 Tailscale 주소로 한다.

ssh://git@100.116.83.60:2222/yunchan/designpaca.git

SSH 키는 이미 Forgejo 에 등록돼 있어(encep-win) 토큰도 비밀번호도 필요 없다.

CI 가 네 번 실패했고 전부 다른 이유였다

# 증상 원인
1 exit 126 / 허가 거부 Windows 에서 만든 .sh 가 mode 100644 로 커밋됐다. git update-index --chmod=+x + 워크플로에서 bash script 로 호출
2 Node 20 이상이 필요하다 (현재 v18) 러너에 Node 18 뿐. fnm 으로 22 설치. 그리고 verify-node.sh 가 Node 가 없을 때만 대체 경로를 훑고 있었다 — 낡았을 때도 찾도록 고침
3 ERR_MODULE_NOT_FOUND: picocolors tarball 을 풀어 node dist/index.js 를 직접 불렀다. 그건 npx 경로가 아니다. 임시 프로젝트에 npm i 후 실행하도록 교체
4 초록불인데 # pass 0 빌드보다 테스트가 먼저라 CLI 테스트 6개가 전부 SKIP. 순서를 바꾸고 SKIP 이 있으면 실패시키는 단계를 넣었다

4번이 가장 위험했다. 통과한 게 아니라 건너뛴 것이었고, 그래도 초록이었다.

Cloudflare 는 계정 ID 가 문제였다

403 Authentication error 가 계속 났다. 토큰 권한을 의심했지만 실제로는 .envCF_ACCOUNT_ID 가 토큰이 볼 수 없는 계정을 가리키고 있었다.

진단법: /accounts 목록을 부르면 토큰이 실제로 접근 가능한 계정이 나온다. 그 id 로 /accounts/{id}/pages/projects 를 부르면 권한 유무가 갈린다.

  • /accounts 목록이 200 인 것은 권한 증거가 아니다. 유효한 토큰이면 누구나 200 이다
  • /user/tokens/verifyUser 토큰 전용이다. 계정 소유 토큰(cfat…)은 여기서 거부당한다. 그걸 보고 "토큰이 잘못됐다"고 판단하면 틀린다 — wrangler whoami 로 교차 확인해라

아직 남은 것

  • NPM_TOKEN — 이름 선점이라 사람 승인 후에만 태그를 민다
  • designpaca.chanpaca.net CNAME — 토큰에 Zone · DNS · Edit 가 없어 수동으로 넣어야 한다