|
1 | 1 | # Docus Upstream Changes — Applicability Survey |
2 | 2 |
|
3 | | -> 조사 시점: 2026-05-28 |
| 3 | +> Surveyed: 2026-05-28 |
4 | 4 | > Pinned: `ref/docus` @ `0eafdaaa` (v5.4.1+2) |
5 | | -> Upstream: `origin/main` (v5.11.0 이후 164 commits 앞섬) |
| 5 | +> Upstream: `origin/main` (164 commits ahead, past v5.11.0) |
6 | 6 |
|
7 | | -## 배경 |
| 7 | +## Background |
8 | 8 |
|
9 | | -`ref/docus` 서브모듈을 v5.4.1 → v5.11.0+main까지 비교했다. docus는 **`@nuxt/ui v3`**, 우리 `packages/layer`는 **`shadcn-vue` + `Tailwind v4`** 스택이라 컴포넌트 단의 변경은 대부분 이식 불가하지만, **서버 라우트 / 모듈 / 유틸 / 컴포저블 단의 변경은 거의 그대로 적용 가능**하다. |
| 9 | +The `ref/docus` submodule was compared from v5.4.1 to v5.11.0+main. Docus uses **`@nuxt/ui v3`**, while our `packages/layer` is built on **`shadcn-vue` + `Tailwind v4`**, so most UI-component changes are not portable. However, **changes at the server route, module, util, and composable layer are largely portable as-is**. |
10 | 10 |
|
11 | | -## 적용 가능 변경 |
| 11 | +## Applicable Changes |
12 | 12 |
|
13 | | -### 🟢 즉시 적용 가능 (높은 ROI, 저위험) |
| 13 | +### 🟢 Apply now (high ROI, low risk) |
14 | 14 |
|
15 | | -#### 1. `inferSiteURL` 보강 |
| 15 | +#### 1. Expand `inferSiteURL` |
16 | 16 |
|
17 | | -- **파일**: `packages/layer/utils/meta.ts:5-13` |
18 | | -- **상류 commit**: 일반 유틸 개선 (시간 경과 누적) |
19 | | -- **변경 내용**: |
20 | | - - 감지하는 env vars 확장: `NUXT_PUBLIC_SITE_URL`, `VERCEL_PROJECT_PRODUCTION_URL`, `VERCEL_BRANCH_URL`, `VERCEL_URL` 추가 |
21 | | - - `ufo.withHttps`로 정규화 |
22 | | -- **현재 우리 상태**: `NUXT_SITE_URL`, `NEXT_PUBLIC_VERCEL_URL`, `URL`, `CI_PAGES_URL`, `CF_PAGES_URL`만 감지 |
| 17 | +- **File**: `packages/layer/utils/meta.ts:5-13` |
| 18 | +- **Upstream commit**: general util improvements accumulated over time |
| 19 | +- **Change**: |
| 20 | + - Detect more env vars: add `NUXT_PUBLIC_SITE_URL`, `VERCEL_PROJECT_PRODUCTION_URL`, `VERCEL_BRANCH_URL`, `VERCEL_URL` |
| 21 | + - Normalize with `ufo.withHttps` |
| 22 | +- **Current state**: only detects `NUXT_SITE_URL`, `NEXT_PUBLIC_VERCEL_URL`, `URL`, `CI_PAGES_URL`, `CF_PAGES_URL` |
23 | 23 |
|
24 | | -#### 2. raw markdown 경로 prerender 등록 |
| 24 | +#### 2. Prerender raw markdown paths |
25 | 25 |
|
26 | | -- **파일**: `packages/layer/app/pages/[...slug].vue` |
27 | | -- **상류 commit**: `9ceafe6f` — `feat(llms): add docs page redirection to raw markdown for agents (#1264)` |
28 | | -- **변경 내용**: 문서 페이지 setup script 끝에 `addPrerenderPath(\`/raw${route.path}.md\`)` 한 줄 추가 |
29 | | -- **효과**: 정적 생성 시 `/raw/*.md`가 함께 생성되어 AI 에이전트가 곧바로 fetch 가능 |
| 26 | +- **File**: `packages/layer/app/pages/[...slug].vue` |
| 27 | +- **Upstream commit**: `9ceafe6f` — `feat(llms): add docs page redirection to raw markdown for agents (#1264)` |
| 28 | +- **Change**: add `addPrerenderPath(\`/raw${route.path}.md\`)` at the end of the page's setup script |
| 29 | +- **Effect**: `/raw/*.md` files are generated during static build, ready for AI agents to fetch directly |
30 | 30 |
|
31 | | -#### 3. baseURL 인식 raw 링크 |
| 31 | +#### 3. baseURL-aware raw link |
32 | 32 |
|
33 | | -- **상류 commit**: `16f5e353` — `fix(links): handle app.baseURL in Markdown generated link (#1221)` |
34 | | -- **변경 내용**: `${origin}/raw${path}.md` → `${origin}${appBaseURL}raw${path}.md` |
35 | | -- **적용 시점**: `DocsPageHeader.vue`에 "Copy markdown link" 버튼을 추가할 때 같이 적용. 현재 우리 헤더는 비어 있어서 단독으로는 효과 없음. |
| 33 | +- **Upstream commit**: `16f5e353` — `fix(links): handle app.baseURL in Markdown generated link (#1221)` |
| 34 | +- **Change**: `${origin}/raw${path}.md` → `${origin}${appBaseURL}raw${path}.md` |
| 35 | +- **When to apply**: alongside adding a "Copy markdown link" button to `DocsPageHeader.vue`. Our header is currently empty, so this isn't useful in isolation. |
36 | 36 |
|
37 | | -#### 4. `content.config.ts` 자동 감지 |
| 37 | +#### 4. Auto-detection in `content.config.ts` |
38 | 38 |
|
39 | | -- **파일**: `packages/layer/content.config.ts`, 신규 `packages/layer/utils/pages.ts` |
40 | | -- **상류 commit**: `f9e999d8` (root docs prefix), `99c78508` (handle docs prefix & folder) |
41 | | -- **변경 내용**: |
42 | | - - `app/pages/index.vue` 존재 시 `landing` 컬렉션 정의 생략 → 사용자가 자체 랜딩 페이지를 가질 수 있음 |
43 | | - - `content/docs/` 폴더 존재 시 자동으로 `/docs` prefix |
44 | | - - i18n locales 존재 시 collection을 `docs_<lang>` 단위로 자동 분기 (현재는 i18n 비활성이므로 이 부분은 보류해도 됨) |
45 | | -- **신규 헬퍼**: |
| 39 | +- **Files**: `packages/layer/content.config.ts`, new `packages/layer/utils/pages.ts` |
| 40 | +- **Upstream commits**: `f9e999d8` (root docs prefix), `99c78508` (handle docs prefix & folder) |
| 41 | +- **Change**: |
| 42 | + - If `app/pages/index.vue` exists, skip defining the `landing` collection — users can ship their own landing page |
| 43 | + - If `content/docs/` exists, automatically prefix the collection with `/docs` |
| 44 | + - When i18n locales are configured, split collections into `docs_<lang>` (can defer until i18n is wired up) |
| 45 | +- **New helpers**: |
46 | 46 |
|
47 | 47 | ```ts |
48 | 48 | // packages/layer/utils/pages.ts |
49 | 49 | export function landingPageExists(rootDir: string): boolean |
50 | 50 | export function docsFolderExists(rootDir: string, locale?: string): boolean |
51 | 51 | ``` |
52 | 52 |
|
53 | | -#### 5. 네비게이션 유틸 보강 |
| 53 | +#### 5. Expand navigation utils |
54 | 54 |
|
55 | | -- **파일**: `packages/layer/app/utils/navigation.ts` |
56 | | -- **현재**: `flattenNavigation` 한 개만 존재 |
57 | | -- **추가**: |
| 55 | +- **File**: `packages/layer/app/utils/navigation.ts` |
| 56 | +- **Current**: only `flattenNavigation` |
| 57 | +- **Add**: |
58 | 58 |
|
59 | 59 | ```ts |
60 | 60 | export interface BreadcrumbItem { title: string, path: string } |
61 | 61 | export function transformNavigation(data, isI18nEnabled, locale?): ContentNavigationItem[] |
62 | 62 | export function findPageBreadcrumbs(navigation, path, currentPath?): BreadcrumbItem[] | undefined |
63 | 63 | ``` |
64 | 64 |
|
65 | | -- **용도**: i18n/`docs/` prefix 자동 스트립, breadcrumb 렌더링, JSON-LD 스키마 |
| 65 | +- **Use cases**: strip i18n / `docs` prefix levels, render breadcrumbs, feed JSON-LD schemas |
66 | 66 |
|
67 | 67 | --- |
68 | 68 |
|
69 | | -### 🟡 중간 노력 (신규 파일이지만 stack-agnostic) |
| 69 | +### 🟡 Moderate effort (new files but stack-agnostic) |
70 | 70 |
|
71 | | -#### 6. `sitemap.xml` 라우트 |
| 71 | +#### 6. `sitemap.xml` route |
72 | 72 |
|
73 | | -- **파일**: 신규 `packages/layer/server/routes/sitemap.xml.ts` |
74 | | -- **상류 commit**: `45bffbc5` (initial), `cd2c62e4` (exclude navigation) |
75 | | -- **변경 내용**: `queryCollection`으로 docs/landing 컬렉션 순회, `frontmatter.sitemap: false` 및 `.navigation` 경로 제외, `<lastmod>` 포함 |
76 | | -- **현재 우리 상태**: `nuxt-og-image`는 있지만 sitemap.xml 라우트 없음. `@nuxtjs/sitemap`을 추가하는 대안도 있으나 docus는 의도적으로 자체 라우트로 처리. |
| 73 | +- **File**: new `packages/layer/server/routes/sitemap.xml.ts` |
| 74 | +- **Upstream commits**: `45bffbc5` (initial), `cd2c62e4` (exclude navigation) |
| 75 | +- **Change**: iterate docs/landing collections via `queryCollection`, skip pages with `frontmatter.sitemap: false` and `.navigation` paths, include `<lastmod>` |
| 76 | +- **Current state**: we have `nuxt-og-image` but no sitemap route. Adding `@nuxtjs/sitemap` is an alternative; docus deliberately rolls its own route. |
77 | 77 |
|
78 | | -#### 7. Skills 모듈 (`.well-known/skills`) |
| 78 | +#### 7. Skills module (`.well-known/skills`) |
79 | 79 |
|
80 | | -- **파일**: 신규 `packages/layer/modules/skills/index.ts` + `runtime/server/routes/` |
81 | | -- **상류 commit**: `2f7861bd` (initial), `764329f5` (configurable dir) |
82 | | -- **변경 내용**: |
83 | | - - 루트 `skills/<name>/SKILL.md`(frontmatter `name`, `description`) 스캔 |
84 | | - - `/.well-known/skills/index.json` + 파일별 라우트 노출 |
85 | | - - Anthropic Agent Skills 네이밍 스펙 검증 (`^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$`, 64자 이내) |
86 | | -- **prerender**: 모든 스킬 파일 경로를 사전 등록 |
| 80 | +- **Files**: new `packages/layer/modules/skills/index.ts` + `runtime/server/routes/` |
| 81 | +- **Upstream commits**: `2f7861bd` (initial), `764329f5` (configurable dir) |
| 82 | +- **Change**: |
| 83 | + - Scan `skills/<name>/SKILL.md` (frontmatter `name`, `description`) at project root |
| 84 | + - Expose `/.well-known/skills/index.json` plus per-file routes |
| 85 | + - Validate against the Anthropic Agent Skills naming spec (`^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$`, max 64 chars) |
| 86 | +- **Prerender**: register every skill file path up-front |
87 | 87 |
|
88 | | -#### 8. MCP 서버 도구 |
| 88 | +#### 8. MCP server tools |
89 | 89 |
|
90 | | -- **파일**: 신규 `packages/layer/server/mcp/tools/{list-pages,get-page}.ts` |
91 | | -- **상류 commit**: `ec3b468c` (initial), `3eb54da4` (exclude .navigation), `f7e42ebf` (baseURL fix), `6043beb1` (derive URLs from request origin) |
92 | | -- **선행 작업**: |
93 | | - - `@nuxtjs/mcp-toolkit` 의존성 추가 + `nuxt.config.ts` modules에 등록 |
94 | | - - `packages/layer/server/utils/content.ts` 신규 (`getAvailableLocales`, `getCollectionsToQuery`, `isNavigationPath`, `getCollectionFromPath`) |
95 | | -- **도구**: |
96 | | - - `list-pages`: 컬렉션의 페이지 메타 전체 반환 (locale 필터) |
97 | | - - `get-page`: 경로로 한 페이지 + `$fetch('/raw{path}.md')`로 본문까지 반환 |
98 | | -- **효과**: Claude/MCP 클라이언트가 문서를 도구로 직접 조회 가능 |
| 90 | +- **Files**: new `packages/layer/server/mcp/tools/{list-pages,get-page}.ts` |
| 91 | +- **Upstream commits**: `ec3b468c` (initial), `3eb54da4` (exclude .navigation), `f7e42ebf` (baseURL fix), `6043beb1` (derive URLs from request origin) |
| 92 | +- **Prereqs**: |
| 93 | + - Add `@nuxtjs/mcp-toolkit` dependency and register it in `nuxt.config.ts` modules |
| 94 | + - New `packages/layer/server/utils/content.ts` (`getAvailableLocales`, `getCollectionsToQuery`, `isNavigationPath`, `getCollectionFromPath`) |
| 95 | +- **Tools**: |
| 96 | + - `list-pages`: return all collection page metadata (with optional locale filter) |
| 97 | + - `get-page`: return a single page by path, body fetched via `$fetch('/raw{path}.md')` |
| 98 | +- **Effect**: Claude / MCP clients can query docs directly as tools |
99 | 99 |
|
100 | | -#### 9. Vercel `markdown-rewrite` 모듈 |
| 100 | +#### 9. Vercel `markdown-rewrite` module |
101 | 101 |
|
102 | | -- **파일**: 신규 `packages/layer/modules/markdown-rewrite.ts` |
103 | | -- **상류 commit**: `6fd8686b` (homepage → llms.txt), `9ceafe6f` (docs pages → raw) |
104 | | -- **변경 내용**: Vercel preset 빌드 후 `config.json`에 rewrite 규칙 주입 |
105 | | - - `Accept: text/markdown` 또는 `User-Agent: curl/*` 일 때 |
| 102 | +- **File**: new `packages/layer/modules/markdown-rewrite.ts` |
| 103 | +- **Upstream commits**: `6fd8686b` (homepage → llms.txt), `9ceafe6f` (docs pages → raw) |
| 104 | +- **Change**: after the Vercel preset build, inject rewrite rules into `config.json` |
| 105 | + - When `Accept: text/markdown` or `User-Agent: curl/*`: |
106 | 106 | - `/` → `/llms.txt` |
107 | 107 | - `/{locale}` → `/llms.txt` |
108 | | - - 문서 페이지 → `/raw/{path}.md` |
109 | | -- **제약**: Vercel preset 전용 (다른 호스팅엔 무영향). 현재 `nuxt-llms`만 있고 호스팅 단 리라이트는 없음. |
| 108 | + - any docs page → `/raw/{path}.md` |
| 109 | +- **Constraint**: Vercel-preset only (no-op on other hosting). We have `nuxt-llms` but no host-level rewrites today. |
110 | 110 |
|
111 | 111 | --- |
112 | 112 |
|
113 | | -### 🔴 부분 적용 / 검토 필요 |
| 113 | +### 🔴 Partial / needs review |
114 | 114 |
|
115 | 115 | #### 10. `useSeo` composable |
116 | 116 |
|
117 | | -- **파일**: 신규 `packages/layer/app/composables/useSeo.ts` |
118 | | -- **상류 commit**: `d283f9aa` — `feat(layer): add more seo optimization (#1267)` |
119 | | -- **변경 내용**: |
120 | | - - Article / WebSite / BreadcrumbList JSON-LD 자동 생성 |
| 117 | +- **File**: new `packages/layer/app/composables/useSeo.ts` |
| 118 | +- **Upstream commit**: `d283f9aa` — `feat(layer): add more seo optimization (#1267)` |
| 119 | +- **Change**: |
| 120 | + - Auto-generate Article / WebSite / BreadcrumbList JSON-LD |
121 | 121 | - canonical link, OG/twitter meta |
122 | | - - hreflang 태그 (i18n 활성 시) |
123 | | -- **제약**: hreflang 부분은 `@nuxtjs/i18n` 의존. i18n 도입 전에는 해당 분기 skip하거나 주석 처리해서 도입 가능. |
| 122 | + - hreflang tags (when i18n is enabled) |
| 123 | +- **Constraint**: hreflang depends on `@nuxtjs/i18n`. Before i18n lands, skip that branch or stub it out. |
124 | 124 |
|
125 | | -#### 11. `d` 단축키로 컬러모드 토글 |
| 125 | +#### 11. `d` shortcut to toggle color mode |
126 | 126 |
|
127 | | -- **파일**: 신규 `packages/layer/app/composables/useDocusShortcuts.ts` (이름은 조정) |
128 | | -- **상류 commit**: `61c36d03` — `feat(layer): add d shortcut to toggle color mode (#1377)` |
129 | | -- **제약**: docus는 `@nuxt/ui`의 `defineShortcuts` 사용. 우리는 `@vueuse/core`의 `useMagicKeys` 또는 `onKeyStroke`로 대체 구현 필요. |
| 127 | +- **File**: new `packages/layer/app/composables/useDocusShortcuts.ts` (name TBD) |
| 128 | +- **Upstream commit**: `61c36d03` — `feat(layer): add d shortcut to toggle color mode (#1377)` |
| 129 | +- **Constraint**: docus uses `@nuxt/ui`'s `defineShortcuts`. We need to reimplement using `@vueuse/core`'s `useMagicKeys` or `onKeyStroke`. |
130 | 130 |
|
131 | | -#### 12. GitHub edit 링크 가드 |
| 131 | +#### 12. Guard the GitHub edit link |
132 | 132 |
|
133 | | -- **상류 commit**: `d056a2c9` (do not display edit page if github url missing), `bd2455ca` (do not show separator if github is disabled) |
134 | | -- **적용 시점**: `DocsPageHeader`에 edit/markdown 액션 버튼을 추가할 때 같이. |
| 133 | +- **Upstream commits**: `d056a2c9` (do not display edit page if github url missing), `bd2455ca` (do not show separator if github is disabled) |
| 134 | +- **When to apply**: when adding edit / markdown action buttons to `DocsPageHeader`. |
135 | 135 |
|
136 | 136 | --- |
137 | 137 |
|
138 | | -### ⛔ 적용 보류 (스택 의존, 큰 리팩토링 필요) |
| 138 | +### ⛔ Defer (stack-dependent, large refactor) |
139 | 139 |
|
140 | | -| 항목 | 상류 commit | 보류 이유 | |
| 140 | +| Item | Upstream commit | Reason for deferral | |
141 | 141 | | --- | --- | --- | |
142 | | -| AppHeaderLeft / CTA / Bottom 분할 | `313ef59e`, `72205f9f` | `@nuxt/ui` 컴포넌트 조립 패턴 | |
143 | | -| Assistant 모듈 전체 | `1ff28292` 외 다수 | `USidebar` 등 `@nuxt/ui` 의존 | |
144 | | -| ContentTOC `circuit` variant | `7d90d20c` | TOC 컴포넌트 구조 자체가 다름 | |
145 | | -| `defaultVariants` 포워딩 | `8abf0d4a` | `@nuxt/ui` 전용 | |
146 | | -| LanguageSelect | — | `@nuxtjs/i18n` 의존 | |
147 | | -| `useDocusI18n` 전체 | `dd4a5267`, `7032533e` | i18n 모듈 도입 후 검토 | |
148 | | -| 컬러모드 강제 middleware | `8d8b0a71` | `@nuxt/ui`의 `forced` 컬러모드 API 의존 | |
| 142 | +| AppHeaderLeft / CTA / Bottom split | `313ef59e`, `72205f9f` | `@nuxt/ui` component composition pattern | |
| 143 | +| Assistant module | `1ff28292` + others | Relies on `USidebar` etc. from `@nuxt/ui` | |
| 144 | +| ContentTOC `circuit` variant | `7d90d20c` | TOC component structure differs entirely | |
| 145 | +| `defaultVariants` forwarding | `8abf0d4a` | `@nuxt/ui` specific | |
| 146 | +| LanguageSelect | — | Requires `@nuxtjs/i18n` | |
| 147 | +| `useDocusI18n` (full) | `dd4a5267`, `7032533e` | Revisit after the i18n module is introduced | |
| 148 | +| Forced color mode middleware | `8d8b0a71` | Relies on `@nuxt/ui`'s `forced` color mode API | |
149 | 149 |
|
150 | 150 | --- |
151 | 151 |
|
152 | | -## 추천 1차 PR 묶음 |
| 152 | +## Recommended first PR bundle |
153 | 153 |
|
154 | | -다음 5개를 하나의 PR로 묶으면 응집도 좋고 사이즈도 적절함: |
| 154 | +These five fit nicely into a single PR — cohesive scope, manageable size: |
155 | 155 |
|
156 | | -1. **#1** `inferSiteURL` Vercel/withHttps 보강 |
157 | | -2. **#2** raw `.md` prerender 등록 |
158 | | -3. **#4** `content.config.ts` 자동 감지 + `utils/pages.ts` |
159 | | -4. **#5** `app/utils/navigation.ts` 보강 (`transformNavigation`, `findPageBreadcrumbs`) |
160 | | -5. **#6** `sitemap.xml` 라우트 |
| 156 | +1. **#1** Expand `inferSiteURL` (Vercel envs, `withHttps`) |
| 157 | +2. **#2** Register raw `.md` prerender path |
| 158 | +3. **#4** `content.config.ts` auto-detection + `utils/pages.ts` |
| 159 | +4. **#5** Expand `app/utils/navigation.ts` (`transformNavigation`, `findPageBreadcrumbs`) |
| 160 | +5. **#6** `sitemap.xml` route |
161 | 161 |
|
162 | | -**후속 PR (선택)**: |
163 | | -- **#7 + #8 + #9**: Skills + MCP + markdown-rewrite (AI/에이전트 통합 묶음, `@nuxtjs/mcp-toolkit` 의존성 추가 동반) |
164 | | -- **#10**: `useSeo` (단, hreflang는 i18n 도입 시점까지 보류 또는 noop) |
165 | | -- **#11 + #12**: 컬러모드 단축키 + GitHub edit 가드 (헤더 액션 버튼 추가와 함께) |
| 162 | +**Follow-up PRs (optional)**: |
| 163 | +- **#7 + #8 + #9**: Skills + MCP + markdown-rewrite (AI / agent integration bundle; pulls in `@nuxtjs/mcp-toolkit`) |
| 164 | +- **#10**: `useSeo` (defer hreflang or no-op it until i18n lands) |
| 165 | +- **#11 + #12**: color-mode shortcut + GitHub edit guard (paired with header action buttons) |
166 | 166 |
|
167 | | -## 참고 commit 인덱스 |
| 167 | +## Commit index for reference |
168 | 168 |
|
169 | 169 | ``` |
170 | 170 | 9ceafe6f feat(llms): add docs page redirection to raw markdown for agents |
|
0 commit comments