블로그 개발기 - 공개, 전체 문서 데이터 소스 비대칭
개요
홈 화면(/)의 좌측 태그 패널과, 개별 문서 페이지의 좌측 Tags 패널이 서로 다른 태그 목록을 보여줬다.
- 홈:
블로그 117,지식 79,it 77… 공개 태그만 - 문서 페이지:
일지 403,work 296,커리어 84,MKGPFPJT-…같은 비공개 업무 태그까지 노출 - 게다가 공유 태그 카운트도 부풀려짐 —
지식 289(홈은 79),it 108(홈은 77)
처음엔 "공개 콘텐츠 유출"처럼 보였지만, 확인해 보니 관리자로 로그인한 상태에서만 나타났다.
비로그인 방문자에겐 정상적으로 공개 태그만 보였다. 즉 외부 유출이 아니라 관리자 화면의 표시 불일치였다.
원인
데이터 소스의 비대칭이 핵심이었다. 포스트 인덱스는 두 종류를 제공한다.
| 함수 | 반환 | 내용 |
|---|---|---|
getAllPosts() → index.posts |
BlogPost[] |
공개 전용 |
getAllIndexedPosts() → index.allPosts |
IndexedPost[] |
비공개 포함 전체 |
- 홈 페이지는
getAllPosts()를 쓰므로 태그 트리가 항상 공개 전용. - 문서 페이지는
getAllIndexedPosts()(전체)를 가져온 뒤, 사이드바를 이렇게 빌드했다:
const visiblePosts = isAdmin ? posts : posts.filter(isPubliclyVisible);관리자면 전체 문서 기준으로 사이드바를 만들기 때문에 비공개 태그가 그대로 흘러들어왔다.
게다가 사이드바의 태그 링크는 /?tag=X(공개 전용 홈)로 이동하므로, 관리자가 비공개 태그를 클릭해도 0건이 나오는 죽은 링크였다 — 관리자에게조차 쓸모없는 동작이었다.
해결
사이드바를 홈과 동일하게 항상 공개 전용으로 통일했다.
// 좌측 Tags 사이드바는 홈(getAllPosts=공개 전용)과 동일하게 항상 공개 문서만으로 빌드한다.
const visiblePosts = posts.filter(isPubliclyVisible);단, 현재 보고 있는 글 자기 자신의 태그(본문 하단·primaryTag)는 기존처럼 canExposeTags = isAdmin || isPubliclyVisible(post)로 처리해, 관리자가 비공개 글의 태그는 계속 볼 수 있도록 유지했다.
(사이드바 = 전역 내비게이션 → 공개 전용 / 글 자체 태그 = 컨텍스트 → admin 노출 허용)
회귀 테스트도 추가했다 — "관리자 뷰어여도 사이드바에서 비공개 태그를 제외한다".
교훈
- "공개 전용 목록"과 "전체 목록"을 구분해 제공하는 API가 있으면, 소비하는 쪽이 어느 것을 쓰는지가 곧 보안·일관성 경계가 된다. 같은 UI 요소(태그 트리)가 페이지마다 다른 소스를 쓰면 반드시 어긋난다.
- "admin이니까 다 보여준다"는 분기는, 그 화면 너머의 동작(여기선 공개 전용 홈으로 가는 링크)과 맞물려야 의미가 있다. 맞물리지 않으면 노출만 늘고 기능은 죽는다.
- 비슷한 비대칭으로 과거 Vercel fallback에서 공개 문서가 적게 집계된 사례도 있었다 — 인덱스의 공개/전체 구분은 이 프로젝트의 단골 함정 포인트다.
댓글
첫 번째 댓글을 남겨보세요.