diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml new file mode 100644 index 0000000..942e619 --- /dev/null +++ b/.github/workflows/pr-build.yml @@ -0,0 +1,37 @@ +name: PR Build Check + +# main·develop 으로 향하는 모든 PR에서 프로덕션 빌드를 강제한다. +# onBrokenLinks: 'throw' 이므로 깨진 내부 링크·MDX 오류가 여기서 차단된다. +# (배포는 하지 않는다 — 배포는 main push 시 deploy.yml 이 담당) +# +# ⚠️ 이 파일만으로는 머지 게이트가 되지 않는다. GitHub +# Settings → Branches → Branch protection rules 에서 main·develop 에 +# "Require status checks to pass" 로 이 체크를 required 로 추가해야 강제된다. +on: + pull_request: + branches: [main, develop] + +# 같은 PR에 새 푸시가 오면 진행 중인 빌드는 취소하고 최신 1개만 유지 +concurrency: + group: pr-build-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: Build (all locales) + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Build (production, all locales) + run: npm run build diff --git a/.github/workflows/sync-develop.yml b/.github/workflows/sync-develop.yml new file mode 100644 index 0000000..d94e214 --- /dev/null +++ b/.github/workflows/sync-develop.yml @@ -0,0 +1,33 @@ +name: Sync main → develop + +# 서버 crontab(2분 주기 Notion 동기화)이 main 에 쌓는 콘텐츠 +# (docs/ · docs_en/ · static/img/)를 develop 으로 정기 흡수한다. +# develop 이 오래된 문서를 들고 있지 않도록 유지하는 역방향 흐름. +# +# 충돌이 나면 job 이 실패한다 = 알림. 자동 우회(-X ours/theirs 등)는 +# 쓰지 않는다 — 콘텐츠 손실을 막기 위해 수동 개입을 강제한다. +on: + schedule: + - cron: '0 18 * * *' # 매일 UTC 18:00 = KST 03:00 + workflow_dispatch: + +permissions: + contents: write + +jobs: + sync: + runs-on: ubuntu-latest + steps: + - name: Checkout develop (full history) + uses: actions/checkout@v4 + with: + ref: develop + fetch-depth: 0 + + - name: Merge main into develop + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git fetch origin main + git merge origin/main --no-edit + git push origin develop diff --git a/CLAUDE.md b/CLAUDE.md index 3180659..df5c30d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,197 +1,60 @@ -앞으로 branch 는 main 만 쓰도록 해 +# CLAUDE.md — docs-web 작업 가이드 (허브) -# CLAUDE.md — docs-web 작업 가이드 - -SceneMakerAI 기술 문서 사이트의 작업 가이드. 코드 개발 저장소가 아닌 **콘텐츠 사이트**다. 작업의 대부분은 Markdown 추가·수정과 EN 번역이다. +SceneMakerAI 기술 문서 사이트의 작업 가이드이자 **문서 인덱스**다. 작업 대부분은 콘텐츠(Markdown)·EN 번역이지만, 사이트 코드(`src/`·`scripts/`·설정)의 유지보수·기능개선도 포함한다. **콘텐츠는 Notion에서 `main`으로 자동 동기화**되고, **코드 작업은 [브랜치 전략](#-브랜치-전략-요약)(main/develop)**을 따른다. --- -## 프로젝트 개요 - -**SceneMakerAI**는 오픈소스 AI(멀티모달 LLM)로 방송 콘텐츠(드라마·예능·다큐멘터리)를 재가공하는 **솔박스(Solbox Inc.) 사내 프로젝트**다. 2026 NIPA 오픈소스 AI·SW 지원사업으로 진행 중이며, 4대 서비스(모아보기·리믹스·광고·Batch)와 오픈소스 기여 30+건을 목표로 한다. - -- 운영 URL: `https://doc.scenemaker.solbox.com` -- GitHub: `https://github.com/SceneMakerAI/docs-web` -- 기술 스택: **Docusaurus 3.10.1** (React 19, TypeScript 6) -- 기본 언어: 한국어(KR), 번역: 영어(EN) -- 콘텐츠 원본: **Notion DB** → GitHub Actions로 자동 동기화 - ---- +## 📚 문서 맵 -## 디렉토리 구조 +| 무엇을 찾나 | 문서 | +|------------|------| +| 외부 첫인상 · 빠른 시작 · 포인터 | [README.md](./README.md) | +| 기여 룰 · **브랜치 전략(상세·다이어그램)** · 릴리즈 룰 | [CONTRIBUTING.md](./CONTRIBUTING.md) | +| 디렉토리 구조 · slug 시스템 · 빌드 게이트 · 사이드바 · 콘텐츠 추가 | [dev-docs/codebase.md](./dev-docs/codebase.md) | +| i18n 메커니즘 (symlink · DeepL · EN 파일 규칙) | [dev-docs/i18n.md](./dev-docs/i18n.md) | +| Notion 동기화 (서버 crontab · DB 매핑 · 내부 로직) | [dev-docs/notion-sync.md](./dev-docs/notion-sync.md) | +| 디자인 토큰 (Revolut 스타일) | [.aidocs/design.md](./.aidocs/design.md) | -``` -docs-web/ -├── docs/ # KR 원본 문서 (Notion 자동 동기화 대상) -│ ├── about/ # 프로젝트 소개 -│ ├── architecture/ # 아키텍처 설계 -│ ├── blog/ # 블로그 (docs 섹션으로 운영, blog 플러그인 비활성) -│ ├── contribute/ # 오픈소스 기여 가이드 -│ ├── guide/ # 시작하기 / 문서 인덱스 -│ ├── install/ # 설치 가이드 (Qwen, LLM 등) -│ ├── poc/ # PoC 기획안 및 벤치마크 -│ └── release-notes/ # 릴리즈 노트 -│ -├── docs_en/ # EN 번역 문서 (개발자 편집 위치) -│ └── (docs/ 와 동일한 서브디렉토리 구조) -│ -├── i18n/ -│ └── en/ -│ ├── docusaurus-plugin-content-docs/ -│ │ └── current -> ../../../docs_en ← symlink (docs_en/ 가리킴) -│ ├── docusaurus-theme-classic/ -│ │ ├── navbar.json # EN 네비바 라벨 -│ │ └── footer.json # EN 푸터 라벨 -│ └── code.json # EN 컴포넌트 UI 문자열 -│ -├── src/ -│ ├── pages/index.tsx # 홈페이지 (Hero + Features + KPI) -│ ├── components/ -│ │ ├── HomepageFeatures/ # 기능 소개 카드 -│ │ └── HomepageKPI/ # KPI 지표 섹션 -│ └── css/custom.css # 전역 CSS 토큰 -│ -├── static/ -│ ├── img/ # 정적 이미지 (섹션별 하위 폴더) -│ └── CNAME # doc.scenemaker.solbox.com -│ -├── scripts/ -│ ├── notion_to_docs_generic.py # Notion DB → docs/ 범용 동기화 (계층 구조 지원) -│ ├── translate_to_en.py # 변경된 docs/ → DeepL 번역 → docs_en/ 저장 -│ ├── notion_to_blog.py # 블로그 전용 동기화 (레거시) -│ └── notion_to_contribute.py # 기여 전용 동기화 (레거시) -│ -├── .github/workflows/ -│ ├── deploy.yml # main push 시 GH Pages 자동 배포 -│ └── notion-sync.yml # workflow_dispatch 수동 실행 (DAILY/ALL 선택) -│ -├── docusaurus.config.ts # 사이트 설정 (i18n, navbar, footer, webpack) -├── sidebars.ts # 8개 사이드바 정의 (autogenerated) -└── .aidocs/design.md # 미래 리디자인용 토큰 참조 (Revolut 스타일, 현재 미적용) -``` +> 이 파일(CLAUDE.md)은 **허브**다 — 프로젝트 컨텍스트 + 핵심 함정 + 자주 쓰는 것만 담고, 상세는 위 문서로 위임한다. --- -## i18n 구조 핵심 - -**한국어가 원본, 영어는 번역본.** - -| 경로 | 역할 | -|------|------| -| `docs/` | KR 원본. Notion 자동 동기화 대상. | -| `docs_en/` | EN 번역본 편집 위치. **실제 파일이 여기 있다.** | -| `i18n/en/.../current` | `docs_en/`을 가리키는 심볼릭 링크. Docusaurus가 읽는 경로. | - -### 주의: symlink 방향 - -``` -i18n/en/docusaurus-plugin-content-docs/current → ../../../docs_en -``` - -- `docs_en/` = 실제 파일 -- `i18n/.../current` = symlink +## 환경 -**반대로 하면 안 된다.** webpack이 symlink를 real path로 resolve해서 Docusaurus SSG 라우팅과 불일치 → DocItem `content` props undefined 오류 발생. `docusaurus.config.ts`의 `resolve.symlinks: false` 플러그인이 이 문제를 해결한다 (방향이 맞더라도 적용 중). +프로젝트가 무엇을 하는지(4대 서비스·KPI 등)는 [README](./README.md) 참조. 여기엔 작업에 필요한 사실만 둔다. -### EN 파일 추가 규칙 - -1. `docs/section/filename.md`에 KR 파일이 있으면 → `docs_en/section/filename.md` 에 EN 번역 추가 -2. EN 파일 frontmatter에 `slug: "N"` 반드시 포함 (KR과 동일한 값) -3. EN 파일에 `id:` 필드는 넣지 않는다 — `translate_to_en.py`가 자동으로 제거하며, Docusaurus가 파일 경로로 KR/EN 매칭 -4. `sidebar_position:` 은 KR과 동일하게 -5. **`docs_en/` 파일명은 KR 파일명과 반드시 동일해야 한다** — Docusaurus가 파일 경로 기준으로 KR/EN 페이지를 매칭하므로 이름이 다르면 로케일 스위처가 깨짐 - - KR: `docs/poc/poc-기획안-멀티모달-llm.md` → EN: `docs_en/poc/poc-기획안-멀티모달-llm.md` (동일 파일명 필수) - - Notion 동기화로 KR 파일명이 변경되면 EN 파일명도 반드시 함께 변경할 것 - - `translate_to_en.py`가 자동으로 처리하지만, 수동으로 EN 파일 생성 시에도 동일하게 적용 +- 운영 URL: `https://doc.scenemaker.solbox.com` +- GitHub: `https://github.com/SceneMakerAI/docs-web` +- 기술 스택: **Docusaurus 3.10.1** (React 19, TypeScript 6) +- 기본 언어: 한국어(KR), 번역: 영어(EN) +- 콘텐츠 원본: **Notion DB** → 서버 crontab(2분 주기)이 `main`으로 자동 동기화 (GitHub Actions `notion-sync.yml`은 수동 백업) --- -## URL 구조 (slug 시스템) - -Notion 동기화 파일은 `slug: "N"` frontmatter로 숫자 URL을 갖는다. - -``` -docs/architecture/아키텍처-설계.md (slug: "1") → /docs/architecture/1 -docs/install/qwen-3x-설치.md (slug: "1") → /docs/install/1 -docs/install/llm-설치.md (slug: "2") → /docs/install/2 -``` +## ⚠️ 핵심 함정 (작업 전 반드시) -**계층 구조 페이지 (Notion 하위 항목이 있는 경우):** +작업 중 가장 자주 부딪히는 메커니즘. 상세는 각 dev-docs 참조. -``` -docs/poc/vision-bench/index.md (slug: "/") → /docs/poc/vision-bench/ -docs/poc/vision-bench/child.md (slug: "1") → /docs/poc/vision-bench/1 -``` - -- 부모 `index.md`는 `slug: "/"` (디렉토리 루트 URL), `id:` 필드 없음 -- 자식 파일은 `slug: "{child-order}"` (부모 디렉토리 기준 상대 슬러그) -- **slug는 섹션 내 상대경로**. `"architecture/1"` 같은 전체 경로 쓰면 안 된다. -- 새 파일은 섹션 내에서 `sidebar_position` 순서에 맞춰 다음 번호를 부여한다. -- **Notion 동기화 파일**: `scripts/notion_to_docs_generic.py`가 `slug` 자동 생성. 수동 추가 파일만 직접 slug를 넣어야 한다. +- **symlink 방향** — `i18n/.../current → docs_en` (반대로 만들면 빌드 라우팅 깨짐). → [i18n.md](./dev-docs/i18n.md) +- **한글 파일명은 정상** — `notion_to_docs_generic.py` slugify가 한글 제목을 보존하고, URL은 `slug: "숫자"`로 따로 잡힌다. 수동 파일만 kebab-case. → [codebase.md](./dev-docs/codebase.md) +- **`onBrokenLinks: 'throw'`** — 깨진 내부 링크 = 빌드 실패. PR 전 `npm run build` 필수. +- **서버 crontab 2분 push** — main에 콘텐츠가 2분마다 자동 commit/push된다. main 관련 작업 직전 `git pull --rebase origin main`. → [notion-sync.md](./dev-docs/notion-sync.md) +- **`_category_.json`** — 서브디렉토리는 sync가 자동 생성(수동 수정은 다음 sync에 덮어씌워짐). 부모 `index.md`에 `id:` 추가 금지(파일 경로 기반 ID와 충돌). +- **수동 `git mv`로 KR 파일명 변경 시** — 대응 EN 파일도 함께 옮길 것. (Notion sync를 통한 rename은 old 삭제를 `git diff -D`가 잡아 EN까지 자동 처리되지만, 사람이 직접 `git mv`하면 자동 감지 밖이라 stale EN이 남는다.) --- -## Notion 동기화 - -### 실제 운영 방식 — 서버 crontab - -GitHub Actions가 아닌 **서버에서 직접 crontab으로 2분마다** 실행한다. - -``` -*/2 * * * * /root/docs-web/scripts/server-sync.sh >> /var/log/notion-sync.log 2>&1 -``` - -**`scripts/server-sync.sh` 흐름:** - -1. `git pull --rebase origin main` — 원격 최신 코드 반영 -2. 8개 Notion DB 병렬 동기화 (`notion_to_docs_generic.py`, `FETCH_MODE=ALL`) -3. `translate_to_en.py` — 변경된 KR 파일 DeepL 번역 → `docs_en/` 저장 -4. 변경사항 있으면 `git commit + push` → `deploy.yml` 트리거 → GH Pages 배포 +## 🌿 브랜치 전략 (요약) -환경변수는 `/root/docs-web/.env` 파일에서 로드한다 (레포에 포함되지 않음). +콘텐츠(Notion 자동 동기화)와 코드 작업을 **main/develop 2개 브랜치**로 분리한다. -로그 확인: -```bash -tail -f /var/log/notion-sync.log -``` +- **main** — 배포 + 서버 crontab 콘텐츠 자동 commit/push. **사람이 직접 작업하지 않는다.** +- **develop** — 상시 통합 브랜치. 모든 기능개선·버그픽스가 모인다. 배포되지 않으므로 검증은 로컬 `npm run build && npm run serve`. +- `feature/*` → PR → **develop** → PR → **main** → 배포 +- `hotfix/*`는 develop을 거치지 않고 **main에 직접 PR** 후 develop으로 백머지(미완성 기능 동반 배포 방지). +- 모든 PR은 `pr-build.yml`(빌드)을 통과해야 머지(브랜치 보호 규칙으로 강제). -> **GitHub Actions `notion-sync.yml`** 은 수동 실행용 백업 (`workflow_dispatch`). 평소에는 서버 crontab이 실제 운영을 담당한다. - ---- - -### DB ↔ 디렉토리 매핑 - -| `.env` 변수 | 저장 경로 | -|------------|-----------| -| `NOTION_ABOUT` | `docs/about/` | -| `NOTION_ARCHITECTURE` | `docs/architecture/` | -| `NOTION_BLOG` | `docs/blog/` | -| `NOTION_CONTRIBUTE` | `docs/contribute/` | -| `NOTION_DOCS` | `docs/guide/` | -| `NOTION_INSTALL` | `docs/install/` | -| `NOTION_POC` | `docs/poc/` | -| `NOTION_RELEASE` | `docs/release-notes/` | -| `NOTION_TOKEN` | API 인증 토큰 | -| `DEEPL_API_KEY` | DeepL 번역 API 키 | - -### 동기화 내부 로직 (`notion_to_docs_generic.py`) - -Notion "하위 항목" relation을 읽어 자동으로 계층 구조를 결정한다. - -- 하위 항목 없는 페이지 → `docs/{section}/{slug}.md` (평면) -- 하위 항목 있는 부모 → `docs/{section}/{slug}/index.md` + `_category_.json` 자동 생성 -- 자식 페이지 → `docs/{section}/{parent-slug}/{child-slug}.md` - -| 환경변수 | 기본값 | 설명 | -|---------|--------|------| -| `NOTION_PROPERTY_SUBITEM` | `하위 항목` | Sub-items relation 속성명 | -| `NOTION_PROPERTY_PARENT` | `상위 항목` | Parent item relation 속성명 | - -### 수동 동기화 (단일 섹션) - -```bash -NOTION_TOKEN=... NOTION_DATABASE_ID=... SAVE_DIR=docs/guide python3 scripts/notion_to_docs_generic.py -``` +> **다이어그램·머지 전략·역방향 흡수 등 상세는 [CONTRIBUTING.md §7](./CONTRIBUTING.md#7-코드사이트-기여-github-develop-플로우)**. --- @@ -209,59 +72,11 @@ NOTION_TOKEN=... NOTION_DATABASE_ID=... SAVE_DIR=docs/guide python3 scripts/noti --- -## 빌드 게이트 - -### CI에서 실패하는 것 -- **깨진 내부 링크** — `onBrokenLinks: 'throw'` 설정. PR 전 `npm run build` 통과 필수. -- **MDX 컴파일 오류** — 프론트매터·JSX 문법 오류. - -### 로컬에서만 확인 -- `npm run typecheck` — `strict: true`지만 빌드와 무관. IDE 보조용. - ---- - -## 콘텐츠 추가 워크플로우 - -### 새 Notion 섹션 추가 시 - -1. `secrets.NOTION_XXX` 시크릿 등록 -2. `.github/workflows/notion-sync.yml`에 새 DB 환경변수 및 실행 블록 추가 -3. `docs/new-section/` 디렉토리 및 `_category_.json` 생성 -4. `sidebars.ts`에 새 사이드바 항목 추가 -5. `docusaurus.config.ts` navbar에 `{type: 'docSidebar', ...}` 추가 - -### 수동으로 새 문서 추가 시 - -1. `docs/section/filename.md` 생성 (slug, id, sidebar_position, title 포함) -2. `docs_en/section/filename.md` 생성 (동일 frontmatter + 영어 내용) -3. `npm run build` 통과 확인 후 main에 push - ---- - -## 사이드바 목록 - -| 사이드바 ID | 네비바 라벨 | `docs/` 디렉토리 | -|------------|------------|-----------------| -| `aboutSidebar` | 프로젝트 소개 | `about/` | -| `architectureSidebar` | 아키텍처 | `architecture/` | -| `installSidebar` | 설치 | `install/` | -| `pocSidebar` | PoC | `poc/` | -| `docsSidebar` | 문서 | `guide/` | -| `blogSidebar` | 블로그 | `blog/` | -| `contributeSidebar` | 오픈소스 기여 | `contribute/` | -| `releaseNotesSidebar` | 릴리즈 노트 | `release-notes/` | - ---- - -## 하지 말 것 +## 🚫 하지 말 것 - `docusaurus.config.ts`의 `url` / `baseUrl` / `organizationName` / `projectName` 임의 변경 금지 (GH Pages 배포와 RSS 절대 URL에 직접 영향) - `onBrokenLinks: 'throw'`를 `'warn'`으로 낮추지 말 것 - EN 번역 만든다고 KR 원본(`docs/`)을 영어로 덮어쓰지 말 것 -- `i18n/en/.../current` 를 real directory로 바꾸지 말 것 (symlink여야 함) +- `i18n/en/.../current` 를 real directory로 바꾸지 말 것 (symlink여야 함 — [i18n.md](./dev-docs/i18n.md)) - `.docusaurus/`, `build/`, `node_modules/` 커밋 금지 -- **`_category_.json` 수동 편집 시 주의**: - - **섹션 루트** (`docs/{section}/_category_.json`): 수동 관리. `link.type: "doc"` 사용 시 실제 존재하는 doc ID인지 반드시 확인 (`npm run build` 로컬 통과 필수) - - **서브디렉토리** (`docs/{section}/{subdir}/_category_.json`): `notion_to_docs_generic.py`가 자동 생성·관리. 직접 수정하면 다음 sync에 덮어씌워짐 - - 부모 `index.md`에 `id:` 필드 추가 금지 — `_category_.json`의 `link.id`가 파일 경로 기반 ID(`{section}/{slug}/index`)로 고정되어 있어 충돌 발생 -- **KR 파일이 이동(rename)된 경우** 대응하는 stale EN 파일을 수동 삭제해야 함 — `translate_to_en.py`는 git diff 삭제 감지만 하므로 rename은 자동 처리 안 됨 +- `_category_.json` 서브디렉토리 수동 편집 금지(sync가 덮어씀), 부모 `index.md`에 `id:` 금지 — [codebase.md](./dev-docs/codebase.md) · 위 핵심 함정 참조 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7c4661d..f9ba5fa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,64 +1,154 @@ # SceneMakerAI · docs-web 기여 가이드 -이 문서는 **"무엇을 어디에 어떻게 올리는가"의 결정 룰과 수용 기준**을 정의합니다. -설치·실행·번역 추가 절차 등 *how-to*는 [README.md](./README.md)를 참조하세요. +이 문서는 **"무엇을 어디에 어떻게 올리는가"의 결정 룰과 수용 기준**을 정의합니다. 설치·실행 등 *how-to*는 [README.md](./README.md), 디렉토리·메커니즘 상세는 [CLAUDE.md](./CLAUDE.md)와 [dev-docs/](./dev-docs/)를 참조하세요. 원칙은 단 한 줄입니다. > **"링크가 안 깨지고 빌드가 통과하면, 메인테이너 셀프 리뷰 후 머지한다."** -`docusaurus.config.ts`에 `onBrokenLinks: 'throw'`가 걸려 있어 깨진 내부 링크는 빌드 자체를 실패시킵니다. 이것이 사실상 자동 강제되는 유일한 룰이며, 아래의 모든 규칙은 이를 떠받치기 위한 결정 기준입니다. +`docusaurus.config.ts`에 `onBrokenLinks: 'throw'`가 걸려 있어 깨진 내부 링크는 빌드 자체를 실패시킵니다. 이것이 사실상 자동 강제되는 유일한 룰이며, 아래 규칙은 이를 떠받치기 위한 결정 기준입니다. --- -## 1. 콘텐츠 라우팅 — 이 글은 어디에 가는가? +## 1. 두 가지 기여 경로 -작성하려는 글이 다음 중 어디에 해당하는지 먼저 정합니다. 헷갈리면 위에서부터 매칭되는 첫 번째 항목을 따릅니다. +기여는 **콘텐츠**냐 **코드**냐에 따라 경로가 완전히 다릅니다. 먼저 이걸 구분하세요. -| 글의 성격 | 위치 | 예시 | +| 기여 종류 | 어디서 작업 | 어떻게 반영되나 | | --- | --- | --- | -| **시점이 있는 회고/실험/공지** (날짜에 의미가 있다) | `blog/` | "Qwen3.5 VLM 방송 도메인 적용기", "1Q 리뷰" | -| **변하지 않는 사용/운영 방법** | `docs/guide/` | "SceneMakerAI 시작하기", "장애 대응 매뉴얼" | -| **시스템 설계·데이터 흐름·기술 의사결정** | `docs/architecture/` | "vLLM 클러스터 토폴로지", "LangGraph 워크플로우" | -| **외부 OSS 기여 인덱스·관련 저장소 링크** | `docs/contribute/` | Qwen에 올린 PR 링크, 데이터셋 공개 | -| **릴리즈 노트** (4대 서비스 버전 단위 변경) | `docs/release-notes/` | `v0.1.0.md`, `v0.2.0-aurora.md` | -| **사이트 자체 페이지** (정보 구조의 일부, 사이드바 밖) | `src/pages/` | `/about`, `/` 랜딩 | +| **콘텐츠** (문서·블로그·기여 로그·릴리즈 노트) | **Notion DB** | 서버 crontab이 2분마다 `docs/`로 동기화 → DeepL이 `docs_en/`로 번역 → `main` push → 자동 배포 | +| **코드·사이트** (`src/`·`scripts/`·`sidebars.ts`·`docusaurus.config.ts`·`static/`·디자인) | **GitHub** | `feature/*` → `develop` → `main` PR 플로우 (§7) | -판단이 안 서면 **`blog/`** 가 기본값입니다. 가치 있는 글이 docs에 안 가는 것보다, blog에 올라가서 발견되는 편이 낫습니다. 시간이 지나 "이건 docs로 옮기는 게 맞다"고 판단되면 그때 이관합니다. +- **콘텐츠는 GitHub의 `docs/`를 직접 편집하지 않습니다** — Notion에 쓰면 sync가 가져옵니다 (§2). 예외는 수동 구조 파일뿐 (§2.3). +- **코드는 Notion과 무관**하게 `develop` 브랜치에서 작업합니다 (§7). +- 콘텐츠와 코드 변경은 **PR(또는 작업 단위)을 분리**합니다. --- -## 2. 문서(`docs/`) 룰 +## 2. 콘텐츠 기여 — Notion에 작성 -### 파일 위치 · 명명 -- `docs/{guide,architecture,contribute}/` 중 하나의 하위에 `.md` 또는 `.mdx`로 둡니다. -- 파일명은 **kebab-case** (`vllm-cluster.md`), 한글 파일명 금지. -- 한 폴더가 5개를 넘으면 하위 카테고리(`docs/architecture/inference/...`)로 분리하고 `_category_.json`을 추가합니다. +모든 문서는 Notion DB가 원본입니다. `scripts/notion_to_docs_generic.py`가 페이지 제목을 파일명으로, 본문을 Markdown으로 변환하고 frontmatter를 자동 생성합니다. + +### 2.1 어느 DB에 쓰는가 + +작성하려는 글의 성격에 따라 해당 Notion DB에 페이지를 만듭니다. 헷갈리면 위에서부터 매칭되는 첫 항목을 따릅니다. + +| 글의 성격 | Notion DB → 동기화 경로 | 예시 | +| --- | --- | --- | +| **시점이 있는 회고/실험/공지** (날짜에 의미) | `NOTION_BLOG` → `docs/blog/` | "Qwen VLM 방송 도메인 적용기" | +| **변하지 않는 사용/운영 방법** | `NOTION_DOCS` → `docs/guide/` | "SceneMakerAI 시작하기", "장애 대응" | +| **시스템 설계·데이터 흐름·기술 의사결정** | `NOTION_ARCHITECTURE` → `docs/architecture/` | "vLLM 클러스터 토폴로지" | +| **설치 가이드** | `NOTION_INSTALL` → `docs/install/` | "Qwen 설치", "LLM 설치" | +| **PoC 기획·벤치마크** | `NOTION_POC` → `docs/poc/` | "Vision 벤치마크" | +| **프로젝트 소개** | `NOTION_ABOUT` → `docs/about/` | "SceneMakerAI 소개" | +| **외부 OSS 기여 인덱스** | `NOTION_CONTRIBUTE` → `docs/contribute/` | Qwen PR 링크 (§4) | +| **릴리즈 노트** | `NOTION_RELEASE` → `docs/release-notes/` | `v0.1.0` (§5) | + +> DB ↔ 경로 매핑 상세는 [dev-docs/notion-sync.md](./dev-docs/notion-sync.md). + +판단이 안 서면 **blog DB**가 기본값입니다. 가치 있는 글이 안 올라가는 것보다, blog에 올라가 발견되는 편이 낫습니다. 나중에 "docs로 옮기는 게 맞다" 싶으면 그때 Notion에서 이관합니다. + +### 2.2 Notion 작성 → 자동 반영 + +sync가 처리하므로 아래는 **알아두면 되는 것**이지 손으로 할 일이 아닙니다. + +- **파일명·slug 자동**: slugify가 한글 제목을 보존해 한글 파일명을 만들고(정상), URL은 `slug: "숫자"`로 따로 잡힙니다. → [CLAUDE.md 핵심 함정](./CLAUDE.md) +- **계층 구조 자동**: Notion "하위 항목" relation을 걸면 sync가 서브디렉토리 + `_category_.json`을 자동 생성합니다(부모 `index.md`는 `slug: "/"`). +- **frontmatter 자동 생성**: + - 평면·자식 페이지 → `id`, `title`, `sidebar_position`, `slug` (4개) + - 부모 `index.md` → `title`, `sidebar_position`, `slug` (`id`는 생략 — 파일경로 기반 ID와 충돌 방지) + - `description`·`date`는 **자동 생성되지 않습니다**(필요하면 SEO상 권장이나 강제 아님). +- **정렬 자동**: 섹션 내 `sidebar_position`은 Notion 페이지 `created_time` 오름차순으로 배정됩니다. +- **이미지 자동**: 본문 이미지는 `static/img/<섹션>//`로 내려받아집니다. + +### 2.3 수동 문서 추가 (예외) + +sync는 `.notion-sync.json`에 추적된 *자기가 만든 파일만* 삭제하므로(`remove_orphans`), 사람이 만든 파일은 보존됩니다. 다만 **콘텐츠의 기본은 Notion**이고, 수동 추가는 빌드용 구조 파일 등 예외로 최소화합니다. + +- 파일명은 **kebab-case**(`vllm-cluster.md`), frontmatter 4개(`id`/`title`/`sidebar_position`/`slug`)를 직접 채웁니다. +- `slug`는 **섹션 내 상대 경로**입니다. `/<섹션>/...` 전체경로는 금지. +- 같은 섹션의 Notion 파일과 `sidebar_position`이 겹치지 않게 합니다. +- 본문에 H1(`#`)을 따로 쓰지 않습니다(frontmatter `title`이 H1 생성). +- 내부 링크는 같은 폴더 상대 경로 또는 `/docs/<섹션>/` 형식. +- `_category_.json`은 **섹션 루트만** 수동 관리 대상이며, 하위 서브디렉토리는 sync가 덮어씁니다 — 부모 `index.md`에 `id:`를 넣지 마세요. + +--- + +## 3. i18n (자동 번역) + +EN 번역본 실파일은 **`docs_en/`**에 있고, `i18n/en/docusaurus-plugin-content-docs/current`가 그곳을 가리키는 **symlink**입니다. `scripts/translate_to_en.py`가 변경된 KR 문서를 DeepL로 자동 번역합니다. 상세는 [dev-docs/i18n.md](./dev-docs/i18n.md). + +- **한국어가 원본**입니다. 번역이 없는 콘텐츠는 자동으로 한국어로 fallback됩니다. +- 콘텐츠 번역은 sync 파이프라인이 처리하므로 **별도 작업이 필요 없습니다**. +- 네비·푸터·컴포넌트 UI 라벨은 `i18n/en/`의 JSON으로 번역합니다 — 이건 콘텐츠가 아니라 **코드 기여(§7)** 영역입니다. -### 필수 frontmatter -```yaml --- -id: <파일명과 동일한 슬러그> -title: <한국어 문서 제목> -sidebar_position: <폴더 내 정렬, 1부터> -slug: /<섹션>/ # 예: /architecture/vllm-cluster -description: <한 줄 SEO 설명> + +## 4. 외부 오픈소스 기여 로깅 (KPI 직결) + +과제 목표는 **누적 30건 이상의 외부 OSS 기여**입니다. 모든 외부 기여는 사이트에 흔적을 남깁니다. + +- 외부 **PR / Issue / Discussion / 데이터셋 공개**가 머지·공개되는 즉시, **Notion contribute DB**(`NOTION_CONTRIBUTE` → `docs/contribute/`)에 **한 줄 항목**을 추가합니다. +- 한 줄 형식 예: + ```markdown + - [vLLM] `flash-attn` MoE 라우팅 버그 수정 PR — [vllm-project/vllm#12345](https://github.com/vllm-project/vllm/pull/12345) (2026-06-12, merged) + ``` +- 포함 항목: **업스트림 프로젝트명**, **요약**, **링크**, **날짜**, **상태**(open / merged / closed / released). +- 별도 회고가 필요하면 blog 글을 함께 쓰고, 인덱스 항목에서 블로그를 링크합니다. + +이 룰은 강제됩니다 — 외부 기여를 했는데 contribute DB에 항목이 없다면 **이 사이트의 KPI 카운트에 포함되지 않은 것으로 간주**합니다. + --- -``` -### 새 카테고리 추가 -- 폴더 생성 시 `_category_.json`을 함께 둡니다 (`docs/architecture/_category_.json` 참고). -- `link.type`은 `generated-index`를 기본으로 합니다. 별도 인덱스 페이지가 필요하면 `doc`으로 바꾸고 해당 문서를 작성합니다. +## 5. 릴리즈 노트 (Notion release DB) + +릴리즈 노트는 **SceneMakerAI 프로젝트(4대 서비스: 모아보기·리믹스·광고·Batch)** 의 버전 단위 공식 발표 기록입니다. docs-web 사이트 자체의 변경은 대상이 아니며 — [GitHub Release](https://github.com/SceneMakerAI/docs-web/releases) 또는 `git log`로 갈음합니다. + +**Notion release DB**(`NOTION_RELEASE` → `docs/release-notes/`)에 버전별 페이지를 작성하면 sync가 반영합니다. 파일명·slug·정렬은 sync가 자동 처리하므로(§2.2), 아래는 **Notion 페이지에 담을 내용 규칙**입니다. + +### 버전 명명 +- **SemVer**(`vMAJOR.MINOR.PATCH`)를 따릅니다. + - MAJOR: 호환성 깨지는 변경 / MINOR: 호환되는 기능 추가 / PATCH: 호환되는 버그 수정. +- 4대 서비스는 **통합 버전**으로 운영합니다(서비스별 분리가 필요해지는 시점에 재정의). +- 코드명을 붙이려면 페이지 제목에: `v0.1.0 — Aurora`. + +### 본문 구조 (Keep a Changelog) +다음 섹션을 **순서대로** 쓰며, 해당 항목이 없으면 섹션 자체를 생략합니다. + +```markdown +## 요약 (1~3줄) + +## 호환성 +- 마이그레이션 필요 여부 · 영향 받는 API/설정 · 다운그레이드 안전성 +- 변경 없으면 "변경 없음" 한 줄로 명시 + +## 서비스별 변경 +### 모아보기 +### 리믹스 +### 광고 +### Batch + +## 의존성 변경 +- Qwen ... / vLLM ... / LangGraph ... / faster-whisper ... 등 + +## 알려진 이슈 + +## 기여자 +- @, ... +``` ### 수용 기준 -- [ ] frontmatter 5개 항목(`id`, `title`, `sidebar_position`, `slug`, `description`) 모두 채워짐 -- [ ] 본문에 H1(`#`)을 별도로 쓰지 않음 (frontmatter `title`이 H1을 생성) -- [ ] 내부 링크는 `/docs/<섹션>/` 절대 경로 또는 같은 폴더 내 상대 경로 -- [ ] `npm run build`가 통과 (= 깨진 링크 없음) +- [ ] 페이지 제목이 SemVer(`vMAJOR.MINOR.PATCH`) 형식 +- [ ] 본문에 "호환성" 섹션 존재 (해당 없으면 "변경 없음" 명시) +- [ ] 릴리즈에 포함된 외부 OSS 기여가 contribute DB에 누락되지 않음 (§4) + +> **정렬 주의**: sync는 `created_time` 오름차순으로 `sidebar_position`을 배정합니다(오래된 릴리즈가 위). 최신 릴리즈를 위에 고정하려면 sync 정렬 정책 조정이 필요하므로, 표시 순서가 문제가 되는 시점에 별도로 다룹니다. --- -## 3. 블로그(`blog/`) 룰 +## 6. 블로그 작성 규칙 (참고용 · 현재 비활성) + +> **현행**: 블로그는 별도 blog 플러그인이 아니라 **`docs/blog/` 섹션(docs 플러그인)**으로 운영됩니다(`docusaurus.config.ts`의 `blog: false`). 글은 Notion blog DB에서 자동 동기화되며 **일반 콘텐츠 규칙(§2)을 따릅니다.** 따라서 아래의 `authors.yml`·`tags.yml`·``·`onInlineAuthors/Tags` 게이트는 **현재 비활성**입니다(향후 blog 플러그인으로 전환할 경우의 참고용으로 남겨둡니다). ### 게시 주기 (KPI 직결) - 과제 목표: **블로그 누적 20+건**, **월 2건 이상**. 최소 격주 게시를 권장합니다. @@ -70,7 +160,7 @@ blog/YYYY-MM-DD-kebab-case-slug.mdx ``` 예: `blog/2026-06-15-qwen-vlm-broadcast.mdx` -날짜는 게시 예정일을 기준으로 합니다. 같은 날 여러 글을 올릴 일은 거의 없지만, 발생 시 슬러그로 구분합니다. +날짜는 게시 예정일 기준입니다. 같은 날 여러 글은 슬러그로 구분합니다. ### 필수 frontmatter ```yaml @@ -86,17 +176,17 @@ description: <한 줄 요약, 미리보기·OG·RSS 공통 사용> ### 본문 구조 - 본문 상단에 미리보기에 노출할 1–3문단의 리드를 작성합니다. -- 리드 끝에 **반드시** `` 마커를 넣습니다 (블로그 목록에서 노출되는 분량의 컷). +- 리드 끝에 **반드시** `` 마커를 넣습니다(블로그 목록에서 노출되는 분량의 컷). - 마커가 없으면 빌드 시 경고(`onUntruncatedBlogPosts: 'warn'`)가 떨어집니다. ### 저자(`blog/authors.yml`) - 글을 올리기 전, 본인 키가 `authors.yml`에 없으면 추가합니다. -- 신규 저자 항목 최소 필드: `name`, `title`, `url`, `image_url`, `page: true`, `socials.github`. -- 인라인 저자(`authors: [{name: ..., title: ...}]`)는 사용하지 않습니다 (`onInlineAuthors: 'warn'` 정책). +- 신규 저자 최소 필드: `name`, `title`, `url`, `image_url`, `page: true`, `socials.github`. +- 인라인 저자(`authors: [{name: ..., title: ...}]`)는 사용하지 않습니다(`onInlineAuthors: 'warn'` 정책). ### 태그 - 태그는 `tags.yml`에서 관리되는 항목만 사용합니다. 새 태그가 필요하면 `blog/tags.yml`에 정의를 추가한 뒤 사용합니다. -- 인라인 태그(`tags: ['처음쓰는태그']`)는 사용하지 않습니다 (`onInlineTags: 'warn'` 정책). +- 인라인 태그(`tags: ['처음쓰는태그']`)는 사용하지 않습니다(`onInlineTags: 'warn'` 정책). - 태그는 **주제**(qwen, vllm, langgraph, dataset) 또는 **활동 유형**(retro, experiment, contribution) 중 하나로 작명. 너무 일반적인 태그(`ai`, `ml`)는 지양. ### 수용 기준 @@ -108,46 +198,28 @@ description: <한 줄 요약, 미리보기·OG·RSS 공통 사용> --- -## 4. i18n 룰 - -기본 정책은 README의 i18n 섹션에 정리되어 있습니다 — 룰 측면에서의 결정 사항만 정리합니다. - -- **한국어가 원본**입니다. 한국어를 먼저 쓰고, 영어는 뒤따라옵니다. -- **영어 번역은 선택적**입니다. 번역이 없는 콘텐츠는 자동으로 한국어 원본으로 fallback됩니다. -- 영어 번역 우선순위: - 1. `docusaurus.config.ts`의 네비/푸터 라벨 (사이트 전역 노출) - 2. `intro.mdx`, `about.mdx`, 각 섹션 `overview.md` (entry point) - 3. KPI에 직결되는 핵심 블로그 글 (오픈소스 커뮤니티에 외부 인용될 가능성이 있는 글) - 4. 나머지 -- 영어 번역을 추가했다면 PR 설명에 *"i18n: ko 추가/수정에 대응하는 en 번역 포함"* 또는 *"i18n: en 번역 보류(추후 일괄)"* 중 하나를 명시합니다. 빠뜨림과 의도적 미작성을 구분하기 위함입니다. - -명령어·디렉토리 구조는 [README — i18n 워크플로우](./README.md#-i18n-워크플로우) 참조. +## 7. 코드·사이트 기여 (GitHub develop 플로우) ---- +콘텐츠가 아닌 모든 것 — `src/`·`scripts/`·`sidebars.ts`·`docusaurus.config.ts`·`static/`·`i18n/`의 JSON·디자인 — 은 GitHub에서 작업합니다. -## 5. 외부 오픈소스 기여 로깅 룰 (KPI 직결) +### 브랜치 전략 (main / develop) +코드 작업과 콘텐츠 자동 동기화를 분리합니다. -과제 목표는 **누적 30건 이상의 외부 OSS 기여**입니다. 모든 외부 기여는 사이트에 반드시 흔적을 남깁니다. +- **main** — 배포 브랜치. `deploy.yml`이 push마다 배포하고, **서버 crontab이 2분마다 콘텐츠(`docs/`·`docs_en/`·`static/img/`)를 자동 commit/push**합니다. 사람이 직접 작업하지 않습니다. +- **develop** — 상시 통합 브랜치. 모든 기능개선·버그픽스가 모입니다. 배포되지 않으므로 검증은 로컬 `npm run build && npm run serve`. -- **외부 PR / Issue / Discussion / 데이터셋 공개**가 머지/공개되는 즉시, `docs/contribute/overview.md`(또는 카테고리 인덱스)에 **한 줄 항목**을 추가합니다. -- 한 줄 형식 예: - ```markdown - - [vLLM] `flash-attn` MoE 라우팅 버그 수정 PR — [vllm-project/vllm#12345](https://github.com/vllm-project/vllm/pull/12345) (2026-06-12, merged) - ``` -- 항목에는 다음을 포함합니다: **업스트림 프로젝트명**, **요약**, **링크**, **날짜**, **상태**(open / merged / closed / released). -- 기여에 별도 회고가 필요하면 blog 글을 함께 작성하고, 인덱스 항목에서 블로그를 링크합니다. - -이 룰은 강제됩니다 — 외부 기여 PR을 머지했는데 `docs/contribute/`에 항목이 없다면, **이 사이트의 KPI 카운트에 포함되지 않은 것으로 간주**합니다. - ---- - -## 6. 브랜치 · 커밋 · PR 룰 +``` +[기능] feature/* ──PR+CI(squash)──▶ develop ──PR+CI(merge)──▶ main ──▶ 배포 +[핫픽스] hotfix/* ──────PR+CI───────────────────────────────▶ main ──▶ 배포 + └─(백머지)─▶ develop +[흡수] main ──(sync-develop.yml 매일)──▶ develop +``` -### 브랜치 -- `main` 외 모든 작업은 별도 브랜치에서 진행합니다. -- 명명: **`type/short-kebab-desc`** - - `feat/blog-qwen-vlm`, `docs/architecture-vllm-cluster`, `chore/template-cleanup`, `fix/broken-intro-link` -- type은 커밋 컨벤션과 동일한 prefix를 씁니다. +- **명명**: `feature/`, `hotfix/`, `chore/` (커밋 type prefix와 동일) +- **머지 전략**: `feature→develop` = Squash, `develop→main` = Merge commit, `hotfix→main` = Squash(작으면) +- **hotfix는 develop을 거치지 않습니다** — develop의 미완성 기능이 동반 배포되는 것을 막기 위해 main에 직접 PR하고, 머지 후 develop으로 백머지합니다. +- 모든 PR은 `pr-build.yml`(`npm run build`)을 통과해야 머지합니다. **GitHub Settings → Branches에서 main·develop에 "Require status checks(pr-build) 통과 필수" 보호 규칙을 켜야** 강제됩니다. main 머지 직전엔 `git pull --rebase origin main`(서버 자동 push 레이스 방지). +- main의 최신 콘텐츠를 develop에 즉시 흡수하려면 `scripts/sync-develop.sh`(수동) 또는 `sync-develop.yml`(매일 자동). ### 커밋 메시지 (Conventional Commits, 한국어) 현재 리포의 관행을 룰화합니다. @@ -157,11 +229,11 @@ description: <한 줄 요약, 미리보기·OG·RSS 공통 사용> ``` - `type`: `feat`, `fix`, `docs`, `chore`, `refactor`, `ci`, `style`, `perf` 중 하나 -- `scope`: 영향 범위 (`blog`, `docs`, `intro`, `i18n`, `ci`, `infra` 등). 없으면 생략 가능. +- `scope`: 영향 범위 (`home`, `brand`, `blog`, `docs`, `i18n`, `ci`, `infra` 등). 없으면 생략 가능. - 본문은 한국어, 명령형(`~한다` / `~추가`). -- 예시 (기존 커밋 패턴): - - `docs(intro): Docusaurus 튜토리얼 본문을 SceneMakerAI 임시 소개로 교체` - - `chore(blog): Docusaurus 기본 템플릿 잔재 제거 및 임시 저자 교체` +- 예시 (실제 커밋 패턴): + - `feat(brand): 로고·파비콘·OG 이미지 적용` + - `feat(home): 홈페이지 Hero·KPI·서비스 카드 리디자인` - `feat: 커스텀 도메인(doc.scenemaker.solbox.com) 설정` ### PR @@ -176,11 +248,11 @@ description: <한 줄 요약, 미리보기·OG·RSS 공통 사용> ## 관련 ``` - WIP 단계는 **Draft PR** 로 둡니다. -- 단일 PR 크기 가이드: 문서 1편 또는 같은 맥락의 변경만. 콘텐츠와 인프라 변경은 분리합니다. +- 단일 PR 크기 가이드: 같은 맥락의 변경만. 콘텐츠와 인프라(코드) 변경은 분리합니다. --- -## 7. 리뷰 · 머지 · 검증 +## 8. 리뷰 · 머지 · 검증 ### 단일 메인테이너 정책 (현 단계) - 현재 단일 메인테이너 운영입니다. 외부 리뷰어가 없으므로 **셀프 리뷰 체크리스트 + CI 통과**가 머지 조건입니다. @@ -188,100 +260,28 @@ description: <한 줄 요약, 미리보기·OG·RSS 공통 사용> ### 셀프 리뷰 체크리스트 (머지 전 본인이 확인) - [ ] `npm run typecheck` 통과 (코드 변경이 포함된 경우) -- [ ] `npm run build` 통과 — 깨진 내부 링크 없음, `onUntruncatedBlogPosts` / `onInlineAuthors` / `onInlineTags` 경고 없음 -- [ ] 라우팅 룰(§1)에 맞는 위치에 콘텐츠가 있는가 -- [ ] frontmatter 필수 항목이 모두 있는가 (§2 또는 §3) -- [ ] 외부 OSS 기여 PR이라면 `docs/contribute/`에 항목을 추가했는가 (§5) -- [ ] 신규 저자/태그라면 `authors.yml` / `tags.yml`에 등록했는가 +- [ ] `npm run build` 통과 — 깨진 내부 링크 없음 +- [ ] 변경이 올바른 경로에 있는가 (코드=GitHub / 콘텐츠=Notion, §1) +- [ ] 수동 추가 문서라면 frontmatter 필수 항목이 모두 있는가 (§2.3) +- [ ] 외부 OSS 기여라면 Notion contribute DB에 항목을 추가했는가 (§4) - [ ] PR 본문의 4개 섹션이 채워졌는가 +- [ ] README/CLAUDE 등 **루트 `.md`의 내부 링크**는 빌드가 잡지 않으니 직접 확인했는가 ### CI -- `.github/workflows/`의 GitHub Actions가 `main` push 시 자동 빌드·배포합니다. -- **빌드가 실패하면 사이트는 갱신되지 않습니다.** 이전 배포가 그대로 유지되므로 운영 중단은 아니지만, 의도한 변경은 반영되지 않습니다. CI 빨간불 = 즉시 처리. - ---- - -## 8. 릴리즈 노트 룰 - -릴리즈 노트는 **SceneMakerAI 프로젝트(4대 서비스: 모아보기·리믹스·광고·Batch)** 의 버전 단위 공식 발표 기록입니다. docs-web 사이트 자체의 변경은 대상이 아니며 — [GitHub Release](https://github.com/SceneMakerAI/docs-web/releases) 또는 `git log`로 갈음합니다. - -### 버전 명명 -- **SemVer**(`vMAJOR.MINOR.PATCH`)를 따릅니다. - - MAJOR: 호환성 깨지는 변경 / MINOR: 호환되는 기능 추가 / PATCH: 호환되는 버그 수정. -- 4대 서비스는 **통합 버전**으로 운영합니다 (서비스별 분리 운영이 필요해지는 시점에 본 룰 재정의). -- 코드명을 붙이려면 hyphen suffix: `v0.1.0-aurora.md`. - -### 파일 위치 · 명명 -- `docs/release-notes/<버전>.md` — 예: `docs/release-notes/v0.1.0.md` -- 파일명 = frontmatter `id` = slug 마지막 세그먼트. 셋 모두 일치시킵니다. - -### 정렬 (사이드바) -Docusaurus 사이드바는 알파벳 정렬이라 `v0.10.0` < `v0.9.0` 문제가 발생합니다. **반드시 `sidebar_position`을 명시**하여 최신 릴리즈가 위에 오게 합니다. -- `overview.md` = `sidebar_position: 0` (고정) -- 가장 최신 릴리즈 = `sidebar_position: 1` -- 새 릴리즈를 추가할 때 기존 릴리즈들의 `sidebar_position`을 모두 +1 갱신 - -### 필수 frontmatter -```yaml ---- -id: v0.1.0 -title: v0.1.0 — <한 줄 요약 또는 코드명> -sidebar_position: 1 -slug: /release-notes/v0.1.0 -description: <한 줄 SEO 설명> -date: YYYY-MM-DD ---- -``` - -### 본문 구조 (Keep a Changelog 적용) -다음 섹션을 **순서대로** 사용하며, 해당 항목이 없으면 섹션 자체를 생략합니다. - -```markdown -## 요약 (1~3줄) - -## 호환성 -- 마이그레이션 필요 여부 · 영향 받는 API/설정 · 다운그레이드 안전성 -- 변경 없으면 "변경 없음" 한 줄로 명시 - -## 서비스별 변경 -### 모아보기 -- ... -### 리믹스 -- ... -### 광고 -- ... -### Batch -- ... - -## 의존성 변경 -- Qwen ... / vLLM ... / LangGraph ... / faster-whisper ... 등 - -## 알려진 이슈 - -## 기여자 -- @, ... -``` - -### 머지 · 게시 시점 -- 릴리즈 노트 PR은 **해당 버전의 릴리즈 태그가 찍히는 시점에 함께 머지**합니다 (별도 PR이어도 같은 날). -- 사후 보강은 PATCH 릴리즈(`v0.1.1`)로 분리하거나, 본문 끝에 `## 갱신 이력` 섹션을 추가합니다 — 이미 발표된 본문을 무성의하게 덮어쓰지 않습니다. - -### 수용 기준 -- [ ] 최신 릴리즈의 `sidebar_position: 1` 보장 (기존 릴리즈 모두 +1 갱신) -- [ ] `slug`가 `/release-notes/<버전>` 형식 -- [ ] 본문에 "호환성" 섹션 존재 (해당 없음이면 "변경 없음" 명시) -- [ ] 릴리즈에 포함된 외부 OSS 기여가 `docs/contribute/` 인덱스에 누락되지 않음 (§5) -- [ ] `npm run build` 통과 +- **PR 게이트**: `pr-build.yml`이 main·develop 대상 PR에서 `npm run build`를 돌립니다. 통과해야 머지(브랜치 보호 규칙으로 강제). +- **배포**: `deploy.yml`이 `main` push 시 자동 빌드·배포합니다. +- **콘텐츠 흡수**: `sync-develop.yml`이 매일 main→develop을 머지합니다. +- **빌드가 실패하면 사이트는 갱신되지 않습니다.** 이전 배포가 유지되므로 운영 중단은 아니지만, 의도한 변경은 반영되지 않습니다. CI 빨간불 = 즉시 처리. --- ## 9. 자주 헷갈리는 1줄 룰 -- **디자인 토큰의 단일 출처**는 `.aidocs/design.md` 입니다. 본격 적용·세부 룰은 별도 PR에서 확정합니다 — 지금은 컬러/타이포 변경 시 이 파일을 먼저 갱신한다는 것만 기억하면 됩니다. +- **디자인 토큰의 단일 출처**는 `.aidocs/design.md`입니다(Revolut 스타일). 디자인 토큰과 홈페이지엔 적용됐고 전체 리디자인은 진행 중 — 컬러/타이포 변경 시 이 파일을 먼저 갱신합니다. - **배포**: `main` push = 자동 배포. 다른 트리거는 없습니다. -- **정적 자산**(`static/img/`): 출처가 외부인 이미지는 파일과 같은 폴더의 `CREDITS.md`에 출처·라이선스를 1줄 명기. 출처가 불명확한 자산은 커밋하지 않습니다. +- **정적 자산**(`static/img/`): 출처가 외부인 이미지는 같은 폴더의 `CREDITS.md`에 출처·라이선스를 1줄 명기. 출처가 불명확한 자산은 커밋하지 않습니다. - **`.docusaurus/`, `build/`, `node_modules/`** 는 커밋하지 않습니다 (`.gitignore` 적용 중). -- **`docusaurus.config.ts`의 `url` / `baseUrl` / `organizationName` / `projectName`** 변경은 배포 도메인에 직접 영향. 변경 PR은 본인 외에 한 명 더 확인하거나, 변경 후 즉시 프로덕션 확인. +- **`docusaurus.config.ts`의 `url` / `baseUrl` / `organizationName` / `projectName`** 변경은 배포 도메인·RSS 절대 URL에 직접 영향. 변경 후 즉시 프로덕션을 확인합니다. --- diff --git a/README.md b/README.md index d764591..74a8e80 100644 --- a/README.md +++ b/README.md @@ -6,40 +6,38 @@ [![License](https://img.shields.io/badge/License-TBD-lightgrey.svg)]() [![Node](https://img.shields.io/badge/Node-%E2%89%A520-339933?logo=node.js&logoColor=white)]() +운영 사이트: **https://doc.scenemaker.solbox.com** + --- ## 📖 소개 -본 저장소는 **솔박스(Solbox Inc.)** 가 수행하는 *2026년 오픈소스 AI·SW 개발·활용 지원사업* -국책과제의 **공개 기술 블로그 및 문서 사이트**입니다. +본 저장소는 **솔박스(Solbox Inc.)**가 수행하는 *2026년 오픈소스 AI·SW 개발·활용 지원사업*(NIPA) 국책과제 **SceneMakerAI**의 **공개 기술 블로그 및 문서 사이트**입니다. -본 과제(**SceneMakerAI**)는 오픈소스 기반 모델 위에 4 가지 방송 도메인 AI -서비스를 제공합니다. +오픈소스 멀티모달 LLM 위에 4가지 방송 도메인 AI 서비스를 제공합니다. | 서비스 | 목적 | -| ------ | ---- | +| --- | --- | | **모아보기** | 방송 전체에서 핵심 구간 자동 선별 | -| **리믹스** | 자동 하이라이트 탐지를 통한 숏폼 생성 | +| **리믹스** | 자동 하이라이트 탐지로 숏폼 생성 | | **광고** | 맥락 기반 광고 매칭 | | **Batch** | 대규모 배치 분석 파이프라인 | -본 사이트는 과제 산출물 중 다음 두 가지를 공개합니다. - -- **기술 블로그** — 격주 정기 게시 (목표 **20건 이상**) -- **문서** — 아키텍처, 운영 가이드, 오픈소스 기여 인덱스 (목표 **30건 이상의 업스트림 기여** 링크) +공개 산출물: **기술 블로그**(목표 20+건) · **문서**(아키텍처 / 운영 가이드 / 오픈소스 기여 인덱스, 업스트림 기여 30+건 목표). --- ## 🧱 기술 스택 -| 구분 | 도구 | 비고 | -| ---- | ---- | ---- | -| 정적 사이트 생성기 | **Docusaurus 3** (TS) | 문서/블로그/i18n/MDX 일급 지원 | -| 프론트엔드 런타임 | React 19 | — | -| 언어 | **한국어(기본)** + **English** (i18n) | 국내 + 글로벌 커뮤니티 동시 어필 | -| 호스팅 (예정) | GitHub Pages | 무료, GitHub 워크플로우와 자연스럽게 연동 | -| CI/CD (예정) | GitHub Actions | `main` push 시 자동 빌드·배포 | -| 검색 (예정) | Algolia DocSearch (오픈소스 플랜) | 오픈소스 문서에 무료 | +| 구분 | 도구 | +| --- | --- | +| 정적 사이트 생성기 | **Docusaurus 3.10.1** (TypeScript) | +| 런타임 | React 19 | +| 언어 | **한국어(원본)** + English (i18n, DeepL 자동 번역) | +| 콘텐츠 소스 | **Notion DB** → 서버 crontab 자동 동기화 | +| 호스팅 | GitHub Pages (커스텀 도메인 `doc.scenemaker.solbox.com`) | +| CI/CD | GitHub Actions (`main` push 시 자동 빌드·배포) | +| 검색 | Algolia DocSearch (적용 예정) | --- @@ -47,246 +45,99 @@ ``` docs-web/ -├── blog/ # 📝 기술 블로그 글 (한국어 원본) -│ ├── 2019-05-28-first-blog-post.mdx # (Docusaurus 샘플 — 추후 제거) -│ ├── authors.yml -│ └── tags.yml -│ -├── docs/ # 📘 문서 (한국어 원본) -│ ├── intro.mdx # 문서 첫 페이지 -│ ├── guide/ # 사용/운영 가이드 -│ │ └── overview.md -│ ├── architecture/ # 시스템 아키텍처 -│ │ ├── _category_.json -│ │ └── overview.md -│ ├── contribute/ # 오픈소스 기여 인덱스 -│ │ ├── _category_.json -│ │ └── overview.md -│ └── tutorial-basics/, tutorial-extras/ # (Docusaurus 샘플 — 추후 제거) -│ +├── docs/ # KR 원본 문서 (Notion 자동 동기화) +│ ├── about/ architecture/ blog/ contribute/ +│ └── guide/ install/ poc/ release-notes/ +├── docs_en/ # EN 번역본 (실파일 위치, DeepL 자동 번역) +├── i18n/en/ +│ ├── docusaurus-plugin-content-docs/current → ../../../docs_en (symlink) +│ ├── docusaurus-theme-classic/{navbar,footer}.json +│ └── code.json ├── src/ -│ ├── pages/ # 🧩 자유 React/MDX 페이지 -│ │ ├── index.tsx # 사이트 랜딩 페이지 (/) -│ │ ├── about.mdx # /about — 프로젝트 소개 -│ │ └── markdown-page.mdx # (샘플) -│ ├── components/ # 커스텀 React 컴포넌트 (차트 등) -│ └── css/custom.css # 전역 스타일 -│ -├── static/ # 🖼 정적 자원 (그대로 서빙) -│ └── img/ -│ -├── i18n/ # 🌐 번역 -│ └── en/ # English 로케일 -│ ├── code.json # UI 문구 (82개) -│ ├── docusaurus-theme-classic/ # 네비/푸터 번역 -│ │ ├── navbar.json -│ │ └── footer.json -│ ├── docusaurus-plugin-content-docs/ -│ │ ├── current.json # 사이드바 카테고리 라벨 -│ │ └── current/ # 영어 .md 문서 (docs/ 미러) -│ ├── docusaurus-plugin-content-blog/ # 영어 블로그 글 -│ │ └── options.json -│ └── docusaurus-plugin-content-pages/ # 영어 자유 페이지 -│ -├── docusaurus.config.ts # ⚙️ 사이트 전체 설정 -├── sidebars.ts # 📑 사이드바 정의 (3개 사이드바) -├── package.json -├── tsconfig.json -└── README.md # 👈 현재 파일 +│ ├── pages/index.tsx # 홈페이지 (Hero · Features · KPI) +│ ├── components/ # HomepageFeatures, HomepageKPI +│ └── css/custom.css # 디자인 토큰 +├── static/ # 정적 자원 (img/, CNAME) +├── scripts/ # Notion 동기화 · DeepL 번역 파이프라인 +│ ├── notion_to_docs_generic.py +│ ├── translate_to_en.py +│ └── server-sync.sh # 서버 crontab 진입점 (실 운영) +├── .github/workflows/ # deploy · pr-build · sync-develop · notion-sync +├── docusaurus.config.ts +└── sidebars.ts # 8개 사이드바 ``` -### 내비게이션 맵 - -``` -좌측 메뉴 우측 메뉴 -├─ 블로그 → /blog ├─ 🌐 언어 드롭다운 -├─ 문서 → docsSidebar └─ GitHub -├─ 아키텍처 → architectureSidebar -├─ 오픈소스 기여 → contributeSidebar -└─ 프로젝트 소개 → /about -``` +상세 구조·운영 노트는 [CLAUDE.md](./CLAUDE.md), 기여 룰은 [CONTRIBUTING.md](./CONTRIBUTING.md) 참조. --- ## 🚀 빠른 시작 -### 사전 요구사항 - -- **Node.js ≥ 20** (현재 v22 사용) -- **npm ≥ 10** - -### 설치 +요구: **Node.js ≥ 20** ```bash -git clone https://github.com/SceneMakerAI/docs-web.git -cd docs-web npm install +npm start # KR dev 서버 → http://localhost:3000 +npm run start:en # EN dev 서버 → http://localhost:3002/en/ +npm run build # 프로덕션 빌드 (양쪽 로케일) +npm run serve # build/ 결과 로컬 서빙 (한 서버에서 양쪽 확인) ``` -### 로컬 개발 - -```bash -# 한국어 dev 서버 (기본 로케일) -npm start -# → http://localhost:3000 - -# 영어 dev 서버 (별도 포트) -npm run start:en -# → http://localhost:3002/en/ -``` - -> ⚠️ Docusaurus dev 서버는 **한 번에 한 로케일만** 띄울 수 있습니다 (HMR 제약). -> 두 로케일을 동시에 보려면 두 터미널에서 각각 실행하거나, -> 아래 [빌드 & 미리보기](#-빌드--미리보기)로 한 서버에서 모두 확인하세요. - -### 빌드 & 미리보기 - -```bash -# 양쪽 로케일을 ./build/ 에 빌드 -npm run build - -# 빌드 결과를 로컬에서 서빙 (한 서버에서 양쪽 모두 접근 가능) -npm run serve -# → http://localhost:3000 (한국어) -# → http://localhost:3000/en/ (English) -``` - -### 자주 쓰는 명령어 - -| 명령어 | 설명 | -| ------ | ---- | -| `npm start` | 한국어 dev 서버 시작 | -| `npm run start:en` | 영어 dev 서버 시작 (포트 3002) | -| `npm run build` | 프로덕션 빌드 (모든 로케일) | -| `npm run serve` | `build/` 결과를 로컬에서 서빙 | -| `npm run typecheck` | TypeScript 타입 체크 (빌드 X) | -| `npm run write-translations:en` | 영어 번역 JSON 파일 재생성 | -| `npm run clear` | Docusaurus 캐시 정리 | +> Docusaurus dev 서버는 한 번에 한 로케일만 띄웁니다(HMR 제약). 양쪽을 한 서버에서 보려면 `npm run build && npm run serve`. --- -## 🌐 i18n 워크플로우 - -### 동작 원리 - -1. **한국어가 원본**입니다. 원본 `.md` / `.mdx` 파일은 `docs/`, `blog/`, `src/pages/` 에 위치합니다. -2. **영어 번역**은 `i18n/en/docusaurus-plugin-content-*/` 아래에 같은 구조로 미러링합니다. -3. **영어 번역이 없는 콘텐츠는 한국어 원본으로 자동 fallback**됩니다. 따라서 번역은 점진적으로 추가해도 됩니다. - -### 영어 번역 추가하기 - -```bash -# 1) 한국어 원본을 추가/수정한 뒤 영어 JSON 골격을 다시 생성 -npm run write-translations:en +## 🌐 i18n -# 2) 새로 추가된 문자열을 영어로 번역: -# i18n/en/code.json -# i18n/en/docusaurus-theme-classic/{navbar,footer}.json -# i18n/en/docusaurus-plugin-content-docs/current.json - -# 3) 문서 전체를 번역할 때는 경로를 그대로 미러: -# docs/architecture/overview.md -# → i18n/en/docusaurus-plugin-content-docs/current/architecture/overview.md -``` - -### URL 레이아웃 - -| 로케일 | URL 프리픽스 | -| ------ | ------------ | -| 한국어 (기본) | `/` | -| English | `/en/` | +- **한국어가 원본**, 영어는 번역본입니다. 번역이 없으면 KR로 자동 fallback. +- EN 실파일은 **`docs_en/`**에 있고, `i18n/en/.../current`가 이를 가리키는 **symlink**입니다 (방향 주의 — [dev-docs/i18n.md](./dev-docs/i18n.md)). +- `scripts/translate_to_en.py`가 변경된 KR 문서를 DeepL로 자동 번역합니다. +- 네비/푸터/UI 라벨은 `i18n/en/`의 JSON으로 번역합니다. --- -## ✍️ 콘텐츠 추가 +## 📥 콘텐츠 동기화 (Notion) -### 새 블로그 글 +콘텐츠 원본은 **Notion DB**이며, 서버 crontab이 2분 주기로 동기화합니다. -```bash -# blog/ 에 날짜 패턴으로 새 MDX 파일 생성 -touch blog/2026-06-15-qwen-vlm-broadcast.mdx ``` - -```mdx ---- -slug: qwen-vlm-broadcast -title: Qwen3.5 VLM 방송 도메인 적용기 -authors: [minsung] -tags: [qwen, vlm, broadcast] -date: 2026-06-15 ---- - -본문은 truncate 마커 위까지 목록에 노출됩니다. - - - -여기서부터는 상세 페이지에서만 보입니다. +Notion DB ──(notion_to_docs_generic.py)──▶ docs/ ──(translate_to_en.py · DeepL)──▶ docs_en/ ──▶ main push ──▶ 배포 ``` -### 새 문서 페이지 - -1. 적절한 폴더(`docs/guide/`, `docs/architecture/`, `docs/contribute/`)에 `.md` 또는 `.mdx` 파일 생성 -2. 프론트매터 작성 - ```yaml - --- - id: my-page - title: 페이지 제목 - sidebar_position: 2 - --- - ``` -3. 사이드바에 자동으로 노출됩니다. +- 실 운영: `scripts/server-sync.sh` (서버 crontab 2분 주기) +- 수동 백업: `.github/workflows/notion-sync.yml` (`workflow_dispatch`) +- 상세: [dev-docs/notion-sync.md](./dev-docs/notion-sync.md) --- -## 🛠 배포 (예정) +## 🌿 브랜치 전략 -### 타겟 +- **main** — 배포 + Notion 자동 동기화 (사람이 직접 작업하지 않음) +- **develop** — 상시 통합 브랜치. `feature/*` → develop → main 순으로 PR하며, `pr-build` 빌드를 통과해야 머지합니다. develop은 로컬 빌드로 검증합니다. -`main` 브랜치 push 시 **GitHub Actions** 가 자동으로 **GitHub Pages** 에 배포. - -### URL 전략 - -- 초기: `https://scenemakerai.github.io/docs-web/` -- 최종(예정): `https://tech.solbox.com` 등 커스텀 도메인 - -### 활성화 단계 (구현 예정) - -1. `.github/workflows/deploy.yml` 추가 (GitHub Actions 워크플로우) -2. 저장소 Settings → **Pages** 에서 source 를 "GitHub Actions" 로 설정 -3. `docusaurus.config.ts` 의 `url` / `baseUrl` 을 실제 배포 URL 에 맞춤 -4. (선택) 커스텀 도메인용 `CNAME` 추가 +**다이어그램·hotfix 경로·머지 전략 등 상세는 [CONTRIBUTING.md §7](./CONTRIBUTING.md#7-코드사이트-기여-github-develop-플로우)**. --- -## 🎯 과제 목표 (마일스톤 기반) +## 🎯 과제 목표 -| 지표 | 목표치 | -| ---- | ------ | -| 오픈소스 생태계 기여 | **누적 30건 이상** (PR, Issue, 데이터셋) | -| 기술 블로그 게시 | **누적 20건 이상** (월 2건 이상 정기 게시) | -| 추론 처리 성능 | 1 시간 방송 → **20분 이하** | -| 장면 분류 F1 | ≥ 0.70 (40–60분) / ≥ 0.65 (60–120분) | +| 지표 | 목표 | +| --- | --- | +| 오픈소스 기여 | 누적 **30건+** (PR · Issue · 데이터셋) | +| 기술 블로그 | 누적 **20건+** (월 2건+) | +| 추론 처리 성능 | 1시간 방송 → **20분 이하** | +| 장면 분류 F1 | **≥ 0.70** (40–60분) | --- -## 🤝 기여 - -현재는 단일 메인테이너 운영입니다. 초기 구조가 안정화된 뒤 PR/Issue/Discussion 을 환영합니다. - -문의: **minsung7336 [at] solbox.com** +## 🤝 기여 · 라이선스 ---- - -## 📄 라이선스 - -확정 예정입니다. 사이트 콘텐츠는 **CC BY 4.0**, 코드 샘플 및 레퍼런스 구현은 **Apache 2.0** 으로 계획되어 있습니다. - ---- +- 기여 룰: [CONTRIBUTING.md](./CONTRIBUTING.md) +- 라이선스: 콘텐츠 **CC BY 4.0** / 코드 **Apache 2.0** (확정 예정) +- 문의: **minsung7336@solbox.com** -## 🔗 관련 링크 +## 🔗 링크 -- 사업: 2026년 오픈소스 AI·SW 개발·활용 지원사업 -- 주관 조직: [Solbox Inc.](https://solbox.com) -- 기반 모델: [Qwen3.5 (Hugging Face)](https://huggingface.co/Qwen) -- 워크플로우: [LangGraph](https://langchain-ai.github.io/langgraph/) -- 사이트 프레임워크: [Docusaurus](https://docusaurus.io/) +- 주관: [Solbox Inc.](https://solbox.com) +- 기반 모델: [Qwen (Hugging Face)](https://huggingface.co/Qwen) +- 프레임워크: [Docusaurus](https://docusaurus.io/) diff --git a/dev-docs/codebase.md b/dev-docs/codebase.md new file mode 100644 index 0000000..ad11822 --- /dev/null +++ b/dev-docs/codebase.md @@ -0,0 +1,134 @@ +# 코드베이스 구조 + +> [CLAUDE.md](../CLAUDE.md) 허브에서 분리한 상세 문서. 디렉토리 구조 · URL(slug) 시스템 · 빌드 게이트 · 사이드바 · 콘텐츠 추가 절차. + +## 디렉토리 구조 + +``` +docs-web/ +├── docs/ # KR 원본 문서 (Notion 자동 동기화 대상) +│ ├── about/ # 프로젝트 소개 +│ ├── architecture/ # 아키텍처 설계 +│ ├── blog/ # 블로그 (docs 섹션으로 운영, blog 플러그인 비활성) +│ ├── contribute/ # 오픈소스 기여 가이드 +│ ├── guide/ # 시작하기 / 문서 인덱스 +│ ├── install/ # 설치 가이드 (Qwen, LLM 등) +│ ├── poc/ # PoC 기획안 및 벤치마크 +│ └── release-notes/ # 릴리즈 노트 +│ +├── docs_en/ # EN 번역 문서 (개발자 편집 위치) +│ └── (docs/ 와 동일한 서브디렉토리 구조) +│ +├── i18n/ +│ └── en/ +│ ├── docusaurus-plugin-content-docs/ +│ │ └── current -> ../../../docs_en ← symlink (docs_en/ 가리킴) +│ ├── docusaurus-theme-classic/ +│ │ ├── navbar.json # EN 네비바 라벨 +│ │ └── footer.json # EN 푸터 라벨 +│ └── code.json # EN 컴포넌트 UI 문자열 +│ +├── src/ +│ ├── pages/index.tsx # 홈페이지 (Hero + Features + KPI) +│ ├── components/ +│ │ ├── HomepageFeatures/ # 기능 소개 카드 +│ │ └── HomepageKPI/ # KPI 지표 섹션 +│ └── css/custom.css # 전역 CSS 토큰 +│ +├── static/ +│ ├── img/ # 정적 이미지 (섹션별 하위 폴더) +│ └── CNAME # doc.scenemaker.solbox.com +│ +├── scripts/ +│ ├── notion_to_docs_generic.py # Notion DB → docs/ 범용 동기화 (계층 구조 지원) +│ ├── translate_to_en.py # 변경된 docs/ → DeepL 번역 → docs_en/ 저장 +│ ├── server-sync.sh # 실 운영: 서버 crontab 2분 주기 (pull→sync→translate→commit→push) +│ ├── sync-local.sh # 로컬 수동 전체 동기화 (generic 스크립트) +│ ├── sync-develop.sh # 로컬 수동: main → develop 콘텐츠 흡수 (sync-develop.yml 의 수동판) +│ ├── deploy.sh # notion-sync.yml 수동 트리거 헬퍼 +│ ├── notion_to_blog.py # (레거시) 구 blog/ 구조 전용 — 현행 운영 미사용 +│ ├── notion_to_contribute.py # (레거시) 구 기여 전용 — 현행 운영 미사용 +│ └── sync.sh # (레거시) notion_to_blog/contribute 호출 +│ +├── .github/workflows/ +│ ├── deploy.yml # main push 시 GH Pages 자동 배포 +│ ├── pr-build.yml # main·develop PR 빌드 게이트 (npm run build) +│ ├── sync-develop.yml # main→develop 콘텐츠 흡수 (매일 cron) +│ └── notion-sync.yml # workflow_dispatch 수동 실행 (DAILY/ALL 선택) +│ +├── dev-docs/ # 내부 개발 문서 (codebase · i18n · notion-sync) +├── docusaurus.config.ts # 사이트 설정 (i18n, navbar, footer, webpack) +├── sidebars.ts # 8개 사이드바 정의 (autogenerated) +└── .aidocs/design.md # 디자인 토큰 단일 출처 (Revolut 스타일). 토큰·홈페이지엔 적용됨, 전체 리디자인은 미완 +``` + +--- + +## URL 구조 (slug 시스템) + +Notion 동기화 파일은 `slug: "N"` frontmatter로 숫자 URL을 갖는다. + +``` +docs/architecture/아키텍처-설계.md (slug: "1") → /docs/architecture/1 +docs/install/qwen-3x-설치.md (slug: "1") → /docs/install/1 +docs/install/llm-설치.md (slug: "2") → /docs/install/2 +``` + +**계층 구조 페이지 (Notion 하위 항목이 있는 경우):** + +``` +docs/poc/vision-bench/index.md (slug: "/") → /docs/poc/vision-bench/ +docs/poc/vision-bench/child.md (slug: "1") → /docs/poc/vision-bench/1 +``` + +- 부모 `index.md`는 `slug: "/"` (디렉토리 루트 URL), `id:` 필드 없음 +- 자식 파일은 `slug: "{child-order}"` (부모 디렉토리 기준 상대 슬러그) +- **slug는 섹션 내 상대경로**. `"architecture/1"` 같은 전체 경로 쓰면 안 된다. +- 새 파일은 섹션 내에서 `sidebar_position` 순서에 맞춰 다음 번호를 부여한다. +- **Notion 동기화 파일**: `scripts/notion_to_docs_generic.py`가 `slug` 자동 생성. 수동 추가 파일만 직접 slug를 넣어야 한다. + +--- + +## 빌드 게이트 + +### CI에서 실패하는 것 +- **깨진 내부 링크** — `onBrokenLinks: 'throw'` 설정. PR 전 `npm run build` 통과 필수. +- **MDX 컴파일 오류** — 프론트매터·JSX 문법 오류. + +> PR 단위 자동 검증은 `.github/workflows/pr-build.yml`(main·develop 대상)이 담당한다. 배포는 `deploy.yml`(main push). + +### 로컬에서만 확인 +- `npm run typecheck` — `strict: true`지만 빌드와 무관. IDE 보조용. + +--- + +## 사이드바 목록 + +| 사이드바 ID | 네비바 라벨 | `docs/` 디렉토리 | +|------------|------------|-----------------| +| `aboutSidebar` | 프로젝트 소개 | `about/` | +| `architectureSidebar` | 아키텍처 | `architecture/` | +| `installSidebar` | 설치 | `install/` | +| `pocSidebar` | PoC | `poc/` | +| `docsSidebar` | 문서 | `guide/` | +| `blogSidebar` | 블로그 | `blog/` | +| `contributeSidebar` | 오픈소스 기여 | `contribute/` | +| `releaseNotesSidebar` | 릴리즈 노트 | `release-notes/` | + +--- + +## 콘텐츠 추가 워크플로우 + +### 새 Notion 섹션 추가 시 + +1. `secrets.NOTION_XXX` 시크릿 등록 +2. `.github/workflows/notion-sync.yml`에 새 DB 환경변수 및 실행 블록 추가 +3. `docs/new-section/` 디렉토리 및 `_category_.json` 생성 +4. `sidebars.ts`에 새 사이드바 항목 추가 +5. `docusaurus.config.ts` navbar에 `{type: 'docSidebar', ...}` 추가 + +### 수동으로 새 문서 추가 시 + +1. `docs/section/filename.md` 생성 (slug, id, sidebar_position, title 포함) +2. `docs_en/section/filename.md` 생성 (동일 frontmatter + 영어 내용) +3. `npm run build` 통과 확인 후 `feature/*` 브랜치 → `develop` PR ([CONTRIBUTING.md](../CONTRIBUTING.md) §7 브랜치 전략 참조) diff --git a/dev-docs/i18n.md b/dev-docs/i18n.md new file mode 100644 index 0000000..2ffb38b --- /dev/null +++ b/dev-docs/i18n.md @@ -0,0 +1,35 @@ +# i18n 구조 + +> [CLAUDE.md](../CLAUDE.md) 허브에서 분리한 상세 문서. 한국어 원본 / 영어 번역 구조, symlink 방향, EN 파일 추가 규칙. + +**한국어가 원본, 영어는 번역본.** + +| 경로 | 역할 | +|------|------| +| `docs/` | KR 원본. Notion 자동 동기화 대상. | +| `docs_en/` | EN 번역본 편집 위치. **실제 파일이 여기 있다.** | +| `i18n/en/.../current` | `docs_en/`을 가리키는 심볼릭 링크. Docusaurus가 읽는 경로. | + +## 주의: symlink 방향 + +``` +i18n/en/docusaurus-plugin-content-docs/current → ../../../docs_en +``` + +- `docs_en/` = 실제 파일 +- `i18n/.../current` = symlink + +**반대로 하면 안 된다.** webpack이 symlink를 real path로 resolve해서 Docusaurus SSG 라우팅과 불일치 → DocItem `content` props undefined 오류 발생. `docusaurus.config.ts`의 `resolve.symlinks: false` 플러그인이 이 문제를 해결한다 (방향이 맞더라도 적용 중). + +## EN 파일 추가 규칙 + +1. `docs/section/filename.md`에 KR 파일이 있으면 → `docs_en/section/filename.md` 에 EN 번역 추가 +2. EN 파일 frontmatter에 `slug: "N"` 반드시 포함 (KR과 동일한 값) +3. EN 파일에 `id:` 필드는 넣지 않는다 — `translate_to_en.py`가 자동으로 제거하며, Docusaurus가 파일 경로로 KR/EN 매칭 +4. `sidebar_position:` 은 KR과 동일하게 +5. **`docs_en/` 파일명은 KR 파일명과 반드시 동일해야 한다** — Docusaurus가 파일 경로 기준으로 KR/EN 페이지를 매칭하므로 이름이 다르면 로케일 스위처가 깨짐 + - KR: `docs/poc/poc-기획안-멀티모달-llm.md` → EN: `docs_en/poc/poc-기획안-멀티모달-llm.md` (동일 파일명 필수) + - Notion 동기화로 KR 파일명이 변경되면 EN 파일명도 반드시 함께 변경할 것 + - `translate_to_en.py`가 자동으로 처리하지만, 수동으로 EN 파일 생성 시에도 동일하게 적용 + +> UI 라벨(네비/푸터/사이드바 카테고리)은 `i18n/en/`의 JSON으로 따로 번역한다. KR 원본 라벨 변경 후엔 `npm run write-translations:en`으로 골격을 갱신한다. diff --git a/dev-docs/notion-sync.md b/dev-docs/notion-sync.md new file mode 100644 index 0000000..0573dd7 --- /dev/null +++ b/dev-docs/notion-sync.md @@ -0,0 +1,63 @@ +# Notion 동기화 + +> [CLAUDE.md](../CLAUDE.md) 허브에서 분리한 상세 문서. 서버 crontab 운영 방식 · DB 매핑 · 동기화 내부 로직. + +## 실제 운영 방식 — 서버 crontab + +GitHub Actions가 아닌 **서버에서 직접 crontab으로 2분마다** 실행한다. + +``` +*/2 * * * * /root/docs-web/scripts/server-sync.sh >> /var/log/notion-sync.log 2>&1 +``` + +**`scripts/server-sync.sh` 흐름:** + +1. `git pull --rebase origin main` — 원격 최신 코드 반영 +2. 8개 Notion DB 병렬 동기화 (`notion_to_docs_generic.py`, `FETCH_MODE=ALL`) +3. `translate_to_en.py` — 변경된 KR 파일 DeepL 번역 → `docs_en/` 저장 +4. 변경사항 있으면 `git commit + push` → `deploy.yml` 트리거 → GH Pages 배포 + +환경변수는 `/root/docs-web/.env` 파일에서 로드한다 (레포에 포함되지 않음). + +로그 확인: +```bash +tail -f /var/log/notion-sync.log +``` + +> **GitHub Actions `notion-sync.yml`** 은 수동 실행용 백업 (`workflow_dispatch`). 평소에는 서버 crontab이 실제 운영을 담당한다. + +--- + +## DB ↔ 디렉토리 매핑 + +| `.env` 변수 | 저장 경로 | +|------------|-----------| +| `NOTION_ABOUT` | `docs/about/` | +| `NOTION_ARCHITECTURE` | `docs/architecture/` | +| `NOTION_BLOG` | `docs/blog/` | +| `NOTION_CONTRIBUTE` | `docs/contribute/` | +| `NOTION_DOCS` | `docs/guide/` | +| `NOTION_INSTALL` | `docs/install/` | +| `NOTION_POC` | `docs/poc/` | +| `NOTION_RELEASE` | `docs/release-notes/` | +| `NOTION_TOKEN` | API 인증 토큰 | +| `DEEPL_API_KEY` | DeepL 번역 API 키 | + +## 동기화 내부 로직 (`notion_to_docs_generic.py`) + +Notion "하위 항목" relation을 읽어 자동으로 계층 구조를 결정한다. + +- 하위 항목 없는 페이지 → `docs/{section}/{slug}.md` (평면) +- 하위 항목 있는 부모 → `docs/{section}/{slug}/index.md` + `_category_.json` 자동 생성 +- 자식 페이지 → `docs/{section}/{parent-slug}/{child-slug}.md` + +| 환경변수 | 기본값 | 설명 | +|---------|--------|------| +| `NOTION_PROPERTY_SUBITEM` | `하위 항목` | Sub-items relation 속성명 | +| `NOTION_PROPERTY_PARENT` | `상위 항목` | Parent item relation 속성명 | + +## 수동 동기화 (단일 섹션) + +```bash +NOTION_TOKEN=... NOTION_DATABASE_ID=... SAVE_DIR=docs/guide python3 scripts/notion_to_docs_generic.py +``` diff --git a/scripts/sync-develop.sh b/scripts/sync-develop.sh new file mode 100755 index 0000000..091624f --- /dev/null +++ b/scripts/sync-develop.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# main 의 최신 콘텐츠(서버 crontab 이 쌓은 docs/·docs_en/·static/img/)를 +# develop 으로 즉시 흡수하는 로컬 수동 헬퍼. +# +# 정기 자동 흡수는 .github/workflows/sync-develop.yml 이 매일(KST 03:00) 수행한다. +# 이 스크립트는 develop 에서 작업하기 직전 "지금 당장" 최신화하고 싶을 때 쓴다. +# 충돌이 나면 머지가 중단된다(set -e) — 수동 해결 후 다시 실행하면 된다. +set -euo pipefail + +cd "$(dirname "$0")/.." + +echo ">> main → develop 흡수 시작" +git fetch origin + +git checkout develop +git merge --ff-only origin/develop # 로컬 develop 을 origin 최신으로 (로컬이 앞서 있으면 중단) +git merge origin/main --no-edit # main 콘텐츠 흡수 (충돌 시 중단) +git push origin develop + +echo ">> 완료: develop 이 main 의 최신 콘텐츠를 포함합니다"