IT 시행착오·

relatedSlugs가 ‘있는데 안 보일’ 때…스키마는 통과하고 UI만 비는 구멍

Astro 컬렉션은 relatedSlugs 길이만 검사한다. RelatedPosts는 없는 슬러그를 조용히 걸러 빌드가 성공해도 관련 글이 사라진다. 실측으로 확인한 운영 메모.

해커톤에서 노트북으로 코딩하는 장면 — 프론트매터·링크 검증 운영 맥락 (cc by-sa 2.0, openverse:flickr)

증상은 빌드 로그에 없었다. npm run build는 초록이고, 카테고리 페이지에도 새 글이 올라왔다. 그런데 본문 하단 ‘관련 글’이 비어 있거나, 기대보다 한 칸이 줄었다. 프론트매터에는 relatedSlugs가 분명히 있었다. 배포는 성공했는데 연결만 사라진 상태였다.

사실: 스키마가 보는 것과 컴포넌트가 하는 일

src/content.config.ts의 Zod 스키마는 relatedSlugsz.array(z.string()).min(2).max(3)로만 둔다. 길이 2~3이면 통과다. 대상 슬러그가 실제로 존재하는지는 검사하지 않는다. 오타·삭제된 글·카테고리 이동으로 사라진 id를 넣어도 Astro 빌드는 멈추지 않는다.

렌더 쪽은 더 관대하다. RelatedPosts.astro는 컬렉션 전체를 읽은 뒤 slugs.map(...).filter(Boolean)으로 없는 항목을 버린다. 매칭이 0개면 관련 글 <aside> 자체를 그리지 않는다. 즉 검증 실패가 아니라 표시 생략이다. 운영자 눈에는 “관련 글 기능이 꺼진 것 같다”로만 보인다.

이 레포에서 전 포스트의 relatedSlugs를 파싱해 존재 여부를 대조해 보니(열람: 2026-08-01), 깨진 참조는 0건이었다. 지금 당장 장애는 아니다. 다만 구조상 내일 오타 하나면 같은 침묵이 재현된다. 스키마가 막아 주지 않기 때문이다.

이유: ‘배열 길이’와 ‘그래프 무결성’을 같은 층에 두지 않았다

콘텐츠 컬렉션 스키마는 YAML 형태를 빠르게 맞추는 데 강하다. 반면 관련 글은 문서 간 외래키에 가깝다. 길이 검사만 두면 CI는 초록을 유지하고, UI는 부분 결손을 흡수한다. 정적 사이트에서는 그 조합이 특히 위험하다. 런타임 404 모니터링이 관련 글 칸까지 잘 안 보기 때문이다.

시니어 IT 실무자 시각으로 정리하면, 이 구멍은 “버그”라기보다 의도된 관대함의 부작용이다. 관련 글이 하나라도 있으면 섹션을 살리고, 없으면 숨기는 편이 UX상 깔끔하다. 문제는 그 관대함이 작성자 피드백 루프를 끊는다는 점이다. 배포 직후 HTML만 훑으면 “문제 없음”으로 끝난다.

평가: 어디에 쓰고, 어디에 안 쓰는지

쓰는 읽기: 멀티 카테고리 동시 발행·자동화 글쓰기처럼 relatedSlugs를 자주 손대는 워크플로. 안 쓰는 읽기: “스키마만 통과하면 SEO·내부링크가 자동으로 건강하다”는 가정. Zod min(2)작성 형식이지 링크 그래프 검증이 아니다.

실무 체크는 단순하다. 빌드 전에 슬러그 집합을 만들고, 각 글의 relatedSlugs가 그 집합의 부분집합인지 확인한다. 실패하면 배포를 멈춘다. 컴포넌트의 filter(Boolean)은 남겨 두되, 침묵을 CI 단계에서 소리 나게 바꾸는 쪽이 안전하다.

한 가지 더. 관련 글은 같은 카테고리를 우선하라는 글쓰기 기준과도 맞물린다. 존재하지 않는 슬러그를 넣으면 카테고리 교차 실수보다 먼저 빈 칸이 된다. 각도·유사도 게이트를 통과한 글을 올려도, 독자 동선은 관련 글에서 끊길 수 있다.

부연하면, 이번에 확인한 0건 깨짐은 “지금은 깨끗하다”는 스냅샷일 뿐이다. 글이 늘어날수록 오타 확률은 올라간다. 배포 파이프라인이 Actions든 Wrangler든, 콘텐츠 그래프 검증은 빌드 앞단에 두는 편이 낫다.

실측을 한 줄로 더 남긴다. 컬렉션 id는 파일 stem과 같아야 RelatedPostsp.id === slug 비교가 산다. 확장자·경로를 섞어 쓰면 파일이 있어도 매칭이 실패한다. 자동화로 글을 대량 추가할수록, “길이 2 이상”만 보는 스키마와 “없으면 숨김” UI의 조합을 전제로 한 사전 존재 검증이 배포 체크리스트의 고정칸이 돼야 한다. 빌드가 초록인 날일수록, 관련 글 HTML을 한 번 열어보는 습관이 싸게 먹힌다.

배포 직후 스모크 테스트 목록에 /posts/<slug>/ HTML에서 ‘관련 글’ 헤딩 존재 여부를 넣으면, Actions 침묵·Wrangler 수동 배포 날에도 같은 체크가 산다. 콘텐츠 파이프라인은 빌드 성공만으로 끝내지 않는다.

출처

  • 내부 실측: src/content.config.ts relatedSlugs Zod 규칙, src/components/RelatedPosts.astro의 map→filter(Boolean) 동작, 전 포스트 relatedSlugs 존재 대조(깨짐 0건, 2026-08-01)
  • Notion 시드: «리뷰올 오프아이스 구성 설명» — 운영/로컬 환경 분리·검증 누락을 공개 가능한 교훈으로만 재구성 (비밀·제품 실명 제외)