이 글에서 다루는 것
bblog 검색·AI 크롤러 노출을 키우고 ko/en/ja를 마크다운 → SQLite → 검색 → SEO까지 한 축으로 맞춘 하루다. 이어서 /en·/ja에서 링크가 /ko로 튀는 버그를 고치고, Knowledge 상세에 BFS 로컬 그래프를 붙였다. 마지막으로 vault TIL·wiki/cs·bblog knowledge를 정리해 publish했다.
각 작업은 배경지식 → 어떤 상황 → 핵심 작업 → 교훈 순서로 묶는다.
하루 요약
| 작업 | 무엇을 하고 싶었나 | 한 일 | 결과 |
|---|---|---|---|
| 1. JSON-LD + 3국어 | 검색·AI 노출 + locale별 콘텐츠 | JSON-LD 리치화, .{locale}.md 파이프라인, 67문서 en/ja 번역 | DB·검색 id locale 인지, 빌드·테스트 green |
| 2. i18n 라우팅 | /en에서 클릭 시 /ko로 튐 | next-intl Link 일괄 교체, redirect 공통 헬퍼 | prod SSR bare href 0건 |
| 3. 로컬 문서 그래프 | related·wikilink를 지도처럼 | BFS getLocalGraph + force-graph canvas | Vitest + Playwright e2e |
| 4. 지식 정리 | 학습 기록과 공개 교과서 분리 | vault TIL + knowledge 4 slug × ko/en/ja publish | 역할 분리·slug 동기화 |
1. JSON-LD + 3개국어 콘텐츠
배경지식 (개념)
- JSON-LD: 검색엔진·AI 크롤러가 읽는 구조화 데이터. Article·TechArticle에 author·image·wordCount를 넣으면 rich result 후보가 된다.
- Locale suffix: 파일명
.{locale}.md로 같은 slug의 언어별 문서를 구분한다. suffix 없으면 기본ko. - hreflang: sitemap·canonical·
og:locale과 함께 움직여야 한다.
어떤 상황이었나
[locale]/라우팅은 있었지만 content 파이프라인은 단일 언어 가정이었다.- 검색 인덱스 id와 DB id 포맷이 어긋나면 MiniSearch duplicate-ID throw가 난다.
핵심 작업
siteConfig+buildArticleJsonLd확장(WebSite/Organization, TechArticle, mentions/citation).- 로더·schema·
content.dbid=type:slug:locale, list/detail·검색·sitemap hreflang locale 인지형 확장. - 67문서 en/ja 기계번역(
translated: machine),/llms.txt·AI 크롤러 robots 허용. - search-index id 불일치 수정 +
SearchScope.locale정렬.
교훈
- 다국어는 번역뿐 아니라 식별자 포맷 전 구간 grep이 필수다.
- PK/id 변경 시 검색 hydration 소비처를 같은 커밋에서 맞춘다.
→ multilingual-content-locale-suffix · json-ld-structured-data · single-source-of-truth-content-metadata
2. i18n 라우팅·네비게이션 버그 수정
배경지식 (개념)
- next-intl: App Router i18n. locale 프리픽스 URL과 메시지 번역을 담당한다.
localePrefix: "always": bare/til을 미들웨어가/ko/til로 301한다.- locale-aware
Link(@/i18n/navigation): 현재 locale을 href에 자동 붙인다.
어떤 상황이었나
- 3국어 도입 후
/en·/ja에서 리스트·헤더 클릭 시/ko로 튀는 버그. - detail 4곳에 미번역→ko redirect 로직이 복붙돼 있었다.
핵심 작업
getLocalizedDocumentOrRedirect헬퍼 + 4케이스 테스트.- 언어 선택기 Radix Dropdown(ko/en/ja).
- content-nav 12개 plain
next/link→ next-intlLink; load-more·relations 활성 locale 스코프.
교훈
localePrefix:"always"에서 내부 이동은 예외 없이 i18nLink/router.- SSR HTML href 샘플링이 로케일 유실 회귀를 잡는다.
3. TIL·Knowledge 로컬 문서 그래프
배경지식 (개념)
- BFS(너비 우선 탐색): 루트에서 가까운 이웃부터 차례로 방문하는 그래프 탐색.
- force-directed graph: 노드 간 물리 시뮬레이션 레이아웃. 무거워
dynamic({ ssr: false })로 분리한다.
어떤 상황이었나
- TIL·Knowledge 상세의
related·wikilink 관계를 지도처럼 보고 싶었다.
핵심 작업
getLocalGraph: RelationIndex BFS, depth 1~3, published/public만, 엣지 dedupe.DocumentGraphView+ force-graph canvas, reduced-motion·depth UI.- observatory 톤(별·궤도) UI polish.
교훈
- 순수 BFS 함수 + dynamic canvas로 서버 번들을 지킨다.
- depth UI 없으면 허브 문서에서 노드 폭발한다.
→ bfs-document-relation-graph · 제작기 document-graph-view
4. (재정리) 7/11 가상 리스트 스크롤 복원
배경지식 (개념)
- 가상 리스트(window virtualizer): 보이는 행만 DOM에 두는 기법.
- 스크롤 authority: scroll 위치를 최종 결정하는 주체. 여러 주체가 동시에
scrollTo하면 떨림이 난다.
어떤 상황이었나
- 7/11 작업에서 리스트 새로고침 번쩍임·드르륵 떨림·깊은 위치 클램프를 고쳤는데, vault TIL에는 홈 모션 위주로만 남아 있었다.
핵심 작업 (7/11, 오늘 문서화)
- 4개 scroll authority → 단일 corrective scroll 통합.
- throttle save 리스너 재구독 버그 →
[]deps + latest-ref. - 측정 높이 sessionStorage seed로 deep reload 클램프 제거.
교훈
- 복원 e2e는 sessionStorage 저장을 gate한다(네이티브 restoration false-green).
- 이벤트 리스너 deps에 매 렌더 새 콜백을 넣지 않는다.
→ virtual-list-scroll-restore-authority · list-virtualization-windowing