본문으로 건너뛰기

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-Studio
  • projectName: tech-writing-harness

저장소 이름이 변경되면 docusaurus.config.ts 의 세 곳을 동시에 갱신해야 한다.

글 링크 체계 — M코드 공식 링크 + 한글 링크 호환 (v1.6.1)

한글 slug URL은 공유 시 percent-encoding 으로 길고 깨지기 쉬워, 글마다 짧은 M코드를 공식 링크로 쓴다.

역할
공식 링크/articles/M011frontmatter code 에서 생성 — 공유·클릭 이동의 정본
한글 링크/articles/110-자비스-라운드테이블기존 공유분 호환 — 정적 리다이렉트 스텁이 M코드로 보냄

동작 구조:

  1. 원고 frontmatter 의 code: MNNN ([[manuscript-conventions]] §frontmatter) 이 단일 출처
  2. copy-from-manuscript.mjscode 를 Docusaurus slug/id 로 주입하고, 한글 파일명 slug → M코드의 링크 호환 맵src/data/article-redirects.json 으로 생성 (gitignored)
  3. @docusaurus/plugin-client-redirects 가 맵을 읽어 구 한글 경로마다 정적 HTML 스텁(meta refresh + canonical + JS, query/hash 보존)을 빌드에 심는다 — GitHub Pages 는 서버 리다이렉트가 없으므로 이것이 정적 호스팅의 권장 방식
  4. 본문 상호 링크는 파일 상대 형식(./NNN-슬러그.md)으로 쓰면 빌드가 M코드 URL 로 자동 재작성한다 — URL 상대 형식(../NNN-슬러그)은 금지 (030/040/050 에서 일괄 정정된 전력)

새 글 추가 시 code 누락이면 copy 스크립트가 경고를 내고 한글 slug 로 발행된다 — lint 대상.

빌드 흐름

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 동작

  1. manuscript/ walk → .md 파일 수집
  2. frontmatter 파싱 → status 가 필터값에 포함되어야 통과
  3. 파일명에서 slug 추출 → frontmatter 에 id / slug 명시 주입 (Docusaurus 가 prefix 010- 을 자동 제거하는 동작 차단)
  4. ordersidebar_position 매핑
  5. 상대경로 이미지: manuscript/ 바깥이면 docs-docusaurus/docs/_assets/<parent>/ 로 복사 + 경로 재작성
  6. {{변수}} → 백틱 inline code (MDX JS 평가 회피)

환경변수

변수기본효과
MANUSCRIPT_STATUS_FILTERpublished콤마 구분. 예: draft,review,published

CI는 기본값 그대로. 로컬 미리보기 시 작성자가 토글.

GitHub Pages 활성화 (저장소 처음 셋업 시)

  1. GitHub repo → Settings → Pages
  2. Source: GitHub Actions 선택 (Deploy from a branch 가 아님!)
  3. Pages visibility: 저장소가 internal / private 인 경우 별도로 Public 선택 (GitHub Enterprise Cloud 기능 — 코드는 비공개 유지하면서 Pages만 공개 게시)
  4. 첫 워크플로우 실행: Actions 탭 → Deploy · Docusaurus → GitHub Pages → Run workflow
  5. 성공 후 환경 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: '22' 과 로컬 일치
copy-from-manuscript.mjs 가 0개 복사status 필터 mismatchMANUSCRIPT_STATUS_FILTER 환경변수 확인. manuscript 에 status: published 글이 실제로 있는지
Broken link warn내부 링크의 상대경로 오류같은 articles/ 의 다른 글로 가는 링크는 ./<slug> 형태. onBrokenLinks: 'warn' 이라 빌드는 통과하나 사이트에서 404
Broken markdown image warnmanuscript의 이미지 src 가 존재하지 않음copy 스크립트의 [copy] WARN image not found 로그에서 누락 파일 식별
MDX 파서 오류 (Unexpected token)본문에 <...> 또는 {...} 형태 텍스트.md 만 사용 + {{변수}} 는 자동 escape 됨. 그래도 깨지면 백틱으로 명시 escape

워크플로우 등록/파싱 단계 (v1.0.0 사이클에서 학습)

증상진단조치
워크플로우가 gh run listname: .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 rulesenvironment 의 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 mismatchbaseUrl: '/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

노션 북 채널 — 제2 출판 채널 (2026-08-09 개설)

GitHub Pages 와 별개로, 사내 노션 워크스페이스(happytalk)에 시리즈 전편을 북 형태로 출판한다.

항목
루트 페이지"블룸 정원의 하네스" (3b7c0b11-04dd-80ea-9aed-ffd8f7426138)
파이프라인docs-notion/publish-notion-book.mjs (Node 18+, 의존성 0)
상태 파일docs-notion/notion-book.state.json — 편별 pageId·해시·내비 블록 id (커밋 대상)
시크릿.secret/notion.json — internal-doc-tools 와 공유 (integration "쌤전용")
API 버전2022-06-28 (file_upload·cover·inline DB 프로브 검증: 2026-08-09)

구조

블룸 정원의 하네스 (루트)
├── 📚 시리즈 목차 — 인라인 DB "하네스 테크라이팅 시리즈"
│ 속성: 제목("NN · 제목") / 순번 / 게시일 / 카테고리 / 코드 / 요약 / 상태
│ 각 행 = 편 페이지: 커버(히어로) + 아이콘 🌿 + TOC + 본문(이미지 인라인 업로드)
│ + 하단 내비(← 이전편 | 📖 목차 | 다음편 →)
└── 🕘 업데이트 이력 — 인라인 DB (최초출판/추가/수정, 일시·상세)

실행 (증분 sync)

node docs-notion/publish-notion-book.mjs sync [--dry-run] [--limit N] [--status published,review]
  • 기본은 status: published 원고만 대상 — review 편은 승급 후 다음 sync 에서 자동 등재
  • --status published,review 로 검수 전 편도 선출판 가능 — 이 경우 시리즈 DB 상태가 검수중으로 표기되고, 이후 원고가 published 로 승급되면 frontmatter 변경이 해시를 바꿔 다음 기본 sync 에서 자동 재출판 + 상태 '게시' 갱신 (2026-08-09 19편 선출판이 첫 사례)
  • 해시 동일 → skip / 신규 → 행 생성 / 변경 → 본문 블록 전량 교체 + 속성·커버 갱신
  • 내비는 매 sync 재계산 — 새 편이 붙으면 직전 편의 "다음편" 링크가 자동 갱신됨
  • 이력 DB 에 최초출판/추가/수정 행 자동 기록

변환 규칙 (Docusaurus 채널과의 차이)

원고 요소노션 처리
H1 (제목)제거 — 페이지 제목이 대신
히어로 이미지 (hero.png)본문에서 빼고 페이지 커버로 승격 (갤러리 카드 미리보기)
"3줄 요약" 인용💡 파란 콜아웃으로 승격
절 이미지Notion File Upload API 로 직접 업로드 + alt → 캡션
내부 상호 링크 (./NNN-*.md)노션 편 페이지 URL 로 재작성 (미등재 편이면 링크 제거, 텍스트 유지)
GFM 표 / 코드펜스 / 인용Notion table / code / quote 블록

수동 1회 설정 (API 미지원 영역)

  • 시리즈 DB 의 뷰를 갤러리로 전환 + 카드 미리보기 = "페이지 커버", 정렬 = 순번 오름차순 — Notion API 는 뷰 생성/변경을 지원하지 않아 최초 1회 사람이 전환
  • 제목의 NN · 접두어 덕에 기본 정렬로도 출판순이 유지된다

주의

  • 통합 토큰은 워크스페이스 단위 + 페이지별 공유 — 루트 페이지에 integration 이 연결되어 있어야 하위 전체 접근 가능
  • 파일 업로드 id 는 발급 후 1시간 내 attach 필요 — 파이프라인이 업로드 직후 attach 하므로 정상 흐름에선 문제 없음
  • 재출판(변경) 은 기존 블록을 전량 삭제 후 재적재 — 블록 수 × ~300ms 소요, 대량 개정 시 시간 감안
  • GitHub Pages 채널과 이 채널은 독립 — 사이트 태그 배포와 노션 sync 는 서로를 트리거하지 않는다