블로그 설계 & 운영 가이드
이 블로그를 어떻게 만들었고, 글이 늘어나면 어떻게 관리·확장할지를 한곳에 정리한 문서입니다. 새 글을 쓰기 전, 구조를 바꾸기 전에 여기부터 봅니다.
0. 대전략
README의 원칙을 그대로 따릅니다.
- "표현"과 "내용"의 완전한 분리 (= 독립적 진화)
- 표현: 어떻게 보여줄지 — 폰트, 테마, 레이아웃, 카테고리/사이드바 구성
- 내용: 글 자체 —
docs/contents/의 마크다운 파일
- 글을 쓸 때는 표현을 신경 쓰지 않고, 표현을 바꿀 때는 글을 건드리지 않는다.
- 그래서 글은 순수 마크다운 + frontmatter로만 두고, 노출 방식(홈·사이드바·검색)은 스크립트가 frontmatter를 읽어 자동으로 조립합니다.
1. 현재 구조
기술 스택
- VitePress
2.x— 마크다운 → 정적 사이트 생성기 - GitHub Pages — 호스팅 (
/blog/하위 경로로 배포) - GitHub Actions —
main푸시 시 자동 빌드·배포 - Makefile + Node 스크립트 — frontmatter 기반으로 메인/사이드바/태그통계 자동 생성
디렉토리
blog/
├─ Makefile # ⭐ 운영 명령어 (make landing / category / tag-stats)
├─ scripts/ # 자동화 스크립트
│ ├─ lib/posts.mjs # frontmatter 파싱 공용 모듈
│ ├─ landing.mjs # 최근 글 21개 → recent.json
│ ├─ category.mjs # category 기준 → sidebar.json
│ └─ tag-stats.mjs # 태그 통계 → 콘솔 + tag-stats.md
├─ docs/
│ ├─ index.md # 홈(hero + <RecentPosts/>)
│ ├─ contents/ # ⭐ 모든 글이 여기에
│ ├─ public/fonts/ # 정적 자원(폰트)
│ └─ .vitepress/
│ ├─ config.mts # 표현 설정(네비·검색). 사이드바는 generated에서 읽음
│ ├─ generated/ # 스크립트 산출물(커밋 대상): recent.json, sidebar.json
│ └─ theme/ # 커스텀 테마(style.css, RecentPosts.vue)
└─ .github/workflows/deploy.yml # 자동 배포배포 흐름
글 작성/수정 → make gen(=landing+category) → git push (main) → GitHub Actions
→ npm ci → npm run docs:build → dist 업로드 → Pages 반영- 로컬 dev/preview는 루트(
/), Actions 빌드만base = /blog/. (config.mts가GITHUB_ACTIONS환경변수로 분기) generated/(recent.json, sidebar.json)는 빌드에 필요하므로 커밋합니다. 푸시 전에make gen을 돌려 최신화하세요.
2. 새 글 추가하는 법
① 파일 생성 — 네이밍 컨벤션
docs/contents/ 아래에 만듭니다. 파일명은 YYMMDD-slug.md 규칙을 씁니다.
docs/contents/260702-vitepress-search.md
docs/contents/260715-kafka-consumer-lag.md- 날짜 프리픽스 → 목록이 자연스럽게 최신순 정렬됨 (
landing/category가 이 날짜로 정렬) - slug는 영문·하이픈으로 (URL이 깔끔:
/contents/260702-vitepress-search) - 한글 파일명은 URL 인코딩되어 지저분해지므로 피합니다. 제목은 frontmatter로 한글을 씁니다.
② frontmatter 작성 — 모든 자동화의 근거
모든 글 맨 위에 붙입니다. 이 값들로 홈 최근글·사이드바·태그통계가 자동 생성됩니다.
---
title: VitePress 로컬 검색 붙이기
description: 한 줄 요약(홈 카드/검색 결과에 노출)
date: 2026-07-02
category: 서비스개발 # 대분류 1개 (MECE, 5~7개로 고정)
tag: #서비스운영 #아키텍처 # 세부 태그 여러 개 (M:N)
editLink: true
---category: 글당 정확히 하나. 없으면미분류로 모입니다.tag:#해시태그를 공백으로 나열합니다. (tags: [a, b]리스트 형식도 지원)date: 생략하면 파일명YYMMDD프리픽스에서 자동 추론합니다.
⚠️ YAML에서
#는 원래 주석 기호입니다.tag: #...는 우리 스크립트가 원문을 직접 파싱하므로 정상 동작하지만, VitePress의useData()로frontmatter.tag를 읽으면null이 됩니다. 태그는 스크립트(사이드바/통계)용으로만 쓰고, 페이지 안에서 직접 읽어야 하면tags: [a, b]형식을 쓰세요.
③ 반영 → 배포
글 파일만 만들면 끝이 아니라, 메타데이터를 홈/사이드바에 반영해야 합니다. make가 대신 해줍니다.
make gen # landing + category 재생성 (홈·사이드바 갱신)
make dev # 로컬 확인 (http://localhost:5173) ※ gen 자동 실행
git add . && git commit -m "post: vitepress 검색" && git push푸시하면 Actions가 알아서 배포합니다.
3. 컨텐츠가 늘어나면 — 관리·분리 전략
지금은 docs/contents/에 파일을 평평하게(flat) 쌓고 있습니다. 사이드바는 이미 category 기준으로 자동 그룹화되므로(§5), 물리적 폴더 분리는 필수가 아닙니다. 다만 글이 수십 개를 넘어가면 다음을 검토합니다.
주제별 폴더로 분리 (선택)
파일이 아주 많아지면 카테고리 = 폴더로 나눠 파일 탐색을 쉽게 합니다. posts.mjs가 하위 폴더까지 재귀 스캔하므로 자동화는 그대로 동작합니다.
docs/contents/
├─ service-dev/260702-vitepress-search.md
├─ backend/260715-kafka-consumer-lag.md
└─ til/260702.md- 이동 시 URL이 바뀌므로(
/contents/x→/contents/service-dev/x) 옮기려면 초기에 하는 게 비용이 쌉니다.
인덱스 페이지 (선택)
카테고리별 진입점이 필요하면 docs/contents/<cat>/index.md를 두거나, VitePress 데이터 로더로 태그 페이지를 자동 생성할 수 있습니다.
4. 카테고리 & 태그 설계 철학
이 블로그의 분류는 2축입니다. 하나는 뼈대, 하나는 혈관입니다.
카테고리(MECE) = 블로그의 '뼈대' (책의 목차)
- 독자가 처음 들어왔을 때 "이 블로그는 주로 무슨 주제를 다루는구나"를 직관적으로 보여주는 대문 역할.
- 하나의 글은 무조건 하나의 카테고리에만 속하므로, URL을 깔끔하게 뽑거나(예:
/category/service-dev/post-1) 대분류별 통계를 내기 좋습니다.
태그(M:N) = 콘텐츠의 '혈관' (그물망)
- 카테고리라는 딱딱한 벽을 깨고 글과 글 사이를 유연하게 연결합니다.
- 예:
서비스개발이 아니라비즈니스카테고리에#서비스운영태그를 가진 글이 올라오면, 독자는 카테고리를 넘나들며 '운영'에 대한 글만 모아 볼 수 있습니다.
이렇게 설계했을 때의 이점
- 탐색 경험(UX) 극대화
- 목차형 독자: "이 블로그의 '서비스개발' 글을 정주행하겠어!" → 카테고리
- 파도타기형 독자: "'아키텍처' 관련 다른 글도 재밌겠는데?" → 태그 클릭
- SEO에 유리 — 태그의 M:N 연결이 자연스러운 내부 링크(Internal Link) 네트워크를 형성해 검색엔진 점수를 높입니다.
- 글 쓸 때 결정장애 해결 — 큰 틀(카테고리) 하나만 툭 정하고, 세부 속성은 태그로 다 때려 넣으면 되니 글쓰기 부담이 줍니다.
운영 가이드라인 (이것만 지키면 완벽)
- 카테고리는 굳이 늘리지 않기 — MECE 유지를 위해 5~7개 이내로 고정. 웬만한 새 주제는 카테고리 신설 대신 기존 카테고리 + 새 태그로 해결합니다.
- 태그 파편화 방지 — M:N의 유일한 단점은 관리 안 하면 태그가 난장판이 된다는 것.
#서비스운영/#서비스-운영/#운영처럼 제각각이면 연결이 깨집니다. 나만의 '태그 사전'을 두고 일관되게 입력하세요. →make tag-stats로 주기적으로 점검합니다.
결론: "카테고리로 내비게이션(길 찾기)을 제공하고, 태그로 콘텍스트(맥락 탐색)를 제공한다." 이 방향 그대로 밀고 나갑니다.
구현 연결
- 카테고리 →
make category가categoryfrontmatter를 읽어 사이드바를 자동 그룹핑 (§5). - 태그 →
make tag-stats가 태그 사용 빈도를 집계해 파편화를 점검 (§5).
5. 자동화 명령어 (Makefile)
frontmatter만 성실히 채우면 나머지는 명령어가 처리합니다. make help로 목록을 볼 수 있습니다.
make landing — 메인페이지 최근 글
- 최신 글 21개(3열 × 7행)를 골라
docs/.vitepress/generated/recent.json으로 저장. - 홈(
docs/index.md)의<RecentPosts />컴포넌트가 이 JSON을 읽어 카드 그리드로 렌더링(제목·카테고리·날짜·태그). - 정렬 기준:
datefrontmatter → 없으면 파일명YYMMDD.
make category — 사이드바 자동 생성
- 모든 글의
category를 읽어 카테고리별로 묶은generated/sidebar.json생성. config.mts가 이 파일을 읽어themeConfig.sidebar로 사용 → 글에category만 적으면 사이드바가 자동 갱신.미분류카테고리는 항상 맨 뒤로 정렬됩니다. (사이드바를 손으로 고치던 방식은 폐기)
make tag-stats — 태그 통계 (파편화 점검)
- 태그별 사용 횟수, 카테고리 분포를 콘솔에 막대그래프로 출력.
- 리포트를
tag-stats.md로도 저장. 이 파일은 로컬 점검용이라.gitignore에 등록되어 커밋되지 않습니다. - 뜻이 같은데 표기가 다른 태그를 찾아 '태그 사전'대로 통일하는 데 씁니다.
묶음 명령어
make gen=landing+category(푸시 전에 실행)make dev/make build=gen후 개발 서버 / 빌드make preview= 빌드 결과 미리보기
6. 검색
현재 — VitePress 로컬 검색 (활성화됨)
config.mts에 아래가 설정되어 상단 검색창이 동작합니다. 빌드 시 클라이언트 인덱스(MiniSearch)를 만드는 내장 기능으로 외부 서비스·비용이 없고 GitHub Pages 정적 배포와 완벽히 호환됩니다.
// docs/.vitepress/config.mts → themeConfig
search: { provider: 'local' }한글 검색 유의점
- 로컬 검색의 기본 토크나이저는 공백 기준이라 한국어 형태소 분리가 약합니다(부분 단어 매칭이 아쉬울 수 있음).
- 개선책:
search.options.miniSearch로 커스텀 토크나이저 지정, 또는 글에 영문 키워드/태그를 병기해 적중률을 높입니다.
search: {
provider: 'local',
options: {
miniSearch: { /* tokenize, searchOptions ... 한글 부분매칭 튜닝 지점 */ }
}
}장기 개선 — Algolia DocSearch
글이 수백 개 규모가 되거나 더 정교한 랭킹·오타 보정이 필요하면 검토합니다.
search: {
provider: 'algolia',
options: { appId: '...', apiKey: '...', indexName: '...' }
}- 장점: 강력한 검색 품질, 오타 보정, 분석 / 단점: 외부 가입·크롤러 설정 필요, 한국어도 별도 튜닝 필요.
- 결론: 로컬 검색으로 시작 → 규모가 커지면 Algolia로 승격.
7. 로드맵 / 체크리스트
완료
- [x] 로컬 검색 켜기 (
search: { provider: 'local' }) - [x]
config.mts정리 —222222·중복 링크·placeholder 제거, 사이드바 자동화로 전환 - [x] 홈 메인에 최근 글 21개 그리드(
make landing+<RecentPosts/>) - [x] category 기반 사이드바 자동 생성(
make category) - [x] 태그 통계/파편화 점검(
make tag-stats)
진행/예정
- [ ] 네이밍 컨벤션 확정 및 통일(
YYMMDD-slug, 하이픈) - [ ] 글이 늘면
contents/주제별 폴더 분리 - [ ] frontmatter
tag기반 태그 페이지(데이터 로더) - [ ] 한글 검색 토크나이저 튜닝 / 필요 시 Algolia 전환