Docusaurus + GitHub Pages 출판 가이드
출판 스택 결정 (현행)
| 영역 | 도구 |
|---|---|
| 정적 사이트 생성기 | Docusaurus 3.10.x (classic preset, docs only) |
| 배포 | GitHub Pages (workflow: .github/workflows/deploy-docusaurus.yml) |
| 배포 트리거 | 태그 push (v* 패턴) — main push 로는 배포되지 않음 |
| 단일 출처 | manuscript/articles/*.md |
| 빌드 변환 | docs-docusaurus/scripts/copy-from-manuscript.mjs |
영입 원본: book-happtalk 의 multi-tool hub 패턴. 이 프로젝트는 단일 도구만 사용해 hub 패턴을 생략했다 — Docusaurus 산출물이 곧 사이트.
URL 구조
https://blumnai-studio.github.io/tech-writing-harness/
└─ baseUrl
url:https://blumnai-studio.github.io— GitHub organization Pages 도메인baseUrl:/tech-writing-harness/— 저장소명 그대로organizationName:BlumnAI-StudioprojectName:tech-writing-harness
저장소 이름이 변경되면 docusaurus.config.ts 의 세 곳을 동시에 갱신해야 한다.
빌드 흐름
manuscript/articles/*.md ← 사람이 작성
│
│ npm run copy:manuscript
│ (MANUSCRIPT_STATUS_FILTER=published 가 CI 기본)
▼
docs-docusaurus/docs/articles/ ← 자동 생성 (gitignored)
│
│ npm run build (docusaurus build)
▼
docs-docusaurus/build/ ← 정적 사이트 산출물 (gitignored)
│
│ actions/upload-pages-artifact → actions/deploy-pages
│ (트리거: git tag v* push)
▼
GitHub Pages
출판 트리거 — 태그 기반
main 브랜치 push 만으로는 사이트가 배포되지 않는다.
v* 패턴의 git tag 가 push 되어야 배포가 일어난다 — 사이트 게시를 명시적 결정으로 끌어올린 의도.
태그 컨벤션 (semver)
| 자리 | 언제 올리는가 |
|---|---|
| MAJOR (v1.0.0 → v2.0.0) | 사이트 구조 전면 개편, 도구 교체 (Docusaurus → 다른 SSG) |
| MINOR (v1.0.0 → v1.1.0) | 새 글 published, 사이드바 구조 변경 |
| PATCH (v1.0.0 → v1.0.1) | 오탈자 수정, 이미지 교체, 표기 통일 같은 작은 보정 |
본 프로젝트 내부 하네스 버전(
harness/docs/vX.Y.Z.md)과 사이트 태그(vX.Y.Z)는 별도 축으로 흘러간다. 하네스는 정원이 자라는 속도, 사이트 태그는 발행물의 누적 속도.
출판 절차
# 1) 원고 작업 + 검수 + manuscript-architect 가 status: published 로 승급
# (publication-pipeline 의 Stage 1~4)
# 2) main 으로 commit + push (배포 미발동 — 작업 백업만)
git push origin main
# 3) 사이트 발행 결정 — 새 태그 생성
git tag v1.0.0 -m "첫 글 게시 — 010-문서시스템-하네스도입"
git push origin v1.0.0
# → GitHub Actions deploy-docusaurus.yml 가 발동
# 4) 워크플로우 상태 확인
gh run list --workflow=deploy-docusaurus.yml --limit 3
# 5) 성공 후 사이트 URL 확인 (run summary 또는 repo Settings → Pages)
긴급 수동 배포
태그 없이 즉시 배포해야 할 때 (예: 핫픽스 검증):
gh workflow run deploy-docusaurus.yml --ref main
workflow_dispatch 트리거가 발동된다. 단, 정상 출판 흐름은 태그를 통하는 것이 원칙.
copy-from-manuscript.mjs 동작
manuscript/walk →.md파일 수집- frontmatter 파싱 →
status가 필터값에 포함되어야 통과 - 파일명에서 slug 추출 → frontmatter 에
id/slug명시 주입 (Docusaurus 가 prefix010-을 자동 제거하는 동작 차단) order→sidebar_position매핑- 상대경로 이미지: manuscript/ 바깥이면
docs-docusaurus/docs/_assets/<parent>/로 복사 + 경로 재작성 {{변수}}→ 백틱 inline code (MDX JS 평가 회피)
환경변수
| 변수 | 기본 | 효과 |
|---|---|---|
MANUSCRIPT_STATUS_FILTER | published | 콤마 구분. 예: draft,review,published |
CI는 기본값 그대로. 로컬 미리보기 시 작성자가 토글.
GitHub Pages 활성화 (저장소 처음 셋업 시)
- GitHub repo → Settings → Pages
- Source:
GitHub Actions선택 (Deploy from a branch 가 아님!) - Pages visibility: 저장소가
internal/private인 경우 별도로Public선택 (GitHub Enterprise Cloud 기능 — 코드는 비공개 유지하면서 Pages만 공개 게시) - 첫 워크플로우 실행: Actions 탭 →
Deploy · Docusaurus → GitHub Pages→ Run workflow - 성공 후 환경 URL 확인 (workflow summary 의 deployment URL)
본 프로젝트(
BlumnAI-Studio/tech-writing-harness)는internal가시성으로 운영하면서 Pages 만Public으로 게시한다. 소스는 조직 내부에서만 보이고, 발행물은 누구나 읽을 수 있다.
권한
워크플로우의 permissions 블록이 필수:
permissions:
contents: read
pages: write
id-token: write
조직 정책에서 Actions Pages 배포가 차단되어 있으면 organization → Settings → Actions → General 에서 허용.
트러블슈팅
빌드 단계
| 증상 | 진단 | 조치 |
|---|---|---|
npm install 의존성 해석 실패 | Node 버전 확인 | setup-node 의 node-version: '20' 과 로컬 일치 |
copy-from-manuscript.mjs 가 0개 복사 | status 필터 mismatch | MANUSCRIPT_STATUS_FILTER 환경변수 확인. manuscript 에 status: published 글이 실제로 있는지 |
Broken link warn | 내부 링크의 상대경로 오류 | 같은 articles/ 의 다른 글로 가는 링크는 ./<slug> 형태. onBrokenLinks: 'warn' 이라 빌드는 통과하나 사이트에서 404 |
Broken markdown image warn | manuscript의 이미지 src 가 존재하지 않음 | copy 스크립트의 [copy] WARN image not found 로그에서 누락 파일 식별 |
MDX 파서 오류 (Unexpected token) | 본문에 <...> 또는 {...} 형태 텍스트 | .md 만 사용 + {{변수}} 는 자동 escape 됨. 그래도 깨지면 백틱으로 명시 escape |
워크플로우 등록/파싱 단계 (v1.0.0 사이클에서 학습)
| 증상 | 진단 | 조치 |
|---|---|---|
워크플로우가 gh run list 에 name: .github/workflows/<>.yml (파일 경로) 으로 표시 | YAML 파싱 실패 — GitHub Actions 가 name: 필드를 읽지 못함 | 로컬 python -c "import yaml; yaml.safe_load(open(...))" 로 정확한 줄·열 식별 |
step name: 에 (status filter: published) 같이 콜론+공백이 들어가면 즉시 실패 | YAML 매핑 키:값으로 잘못 파싱 | step name 을 큰따옴표로 감싼다: name: "Copy manuscript to docs (status filter: published)" |
워크플로우는 등록됐는데 job 이 0초만에 실패, annotation 에 is not allowed to deploy to <environment> due to environment protection rules | environment 의 deployment branch policy 가 태그를 허용하지 않음 | gh api -X POST repos/<owner>/<repo>/environments/<env>/deployment-branch-policies -f name='v*' -f type='tag' |
gh api .../pages 가 "public": false 인데 발행물을 공개하고 싶다 | internal/private repo 의 Pages 기본 가시성 | gh api -X PUT repos/<owner>/<repo>/pages -f public=true — Enterprise Cloud 기능 |
배포 단계
| 증상 | 진단 | 조치 |
|---|---|---|
| 401/403 deploy 실패 | Pages 권한 누락 | repo Settings → Pages → Source: GitHub Actions |
| 페이지 404 (URL은 맞는데) | baseUrl mismatch | baseUrl: '/tech-writing-harness/' 와 실제 저장소명 일치 확인 |
| asset 404 (이미지 깨짐) | _assets/ 복사 실패 또는 경로 깨짐 | 빌드 산출물의 build/articles/<slug>/_assets/ 존재 확인 |
| 사이트가 옛 버전 그대로 | 캐시 또는 워크플로우 실패 | Actions 탭에서 최근 실행 상태 확인. concurrency 그룹 pages 가 cancel 되었는지 |
Pages 환경 (cosmetic)
| 증상 | 조치 |
|---|---|
| 다크모드가 시스템 설정 무시 | themeConfig.colorMode.respectPrefersColorScheme: true 확인 |
| 한국어 검색 불가 | 기본 검색만 제공. Algolia DocSearch 도입 검토 |
| 사이드바가 어색 | sidebars.ts 의 카테고리 라벨 및 dirName 수정 |
채택 의사결정 기록
| 결정 | 이유 |
|---|---|
| Docusaurus만 사용 (multi-tool hub 안 함) | 단일 사이트로 충분. hub 패턴은 도구가 2개 이상일 때만 가치 |
버전 디렉터리 없음 (docs-docusaurus/v1/ 가 아님) | 아직 다중 버전 필요 없음. 필요해지면 그때 docs-docusaurus/v2/ 추가하고 hub 패턴 검토 |
| docs preset (블로그 X) | manuscript-architect 의 frontmatter/status/order 흐름이 docs 와 잘 맞음. 글이 시간순 정렬이 본질이면 blog preset 으로 전환 검토 |
routeBasePath: '/' | 사이트의 root 가 곧 문서. /docs/ 접두사 없음 |
전환을 검토할 신호:
- 글의 발견이 시간순이 더 자연스러워질 때 → blog preset
- 다국어/다중 버전 도입 → hub 패턴 영입
- 검색 만족도가 낮을 때 → Algolia DocSearch