개발일지WhoAmI — 공부 기록을 발행 가능한 형태로 좁힌 파이프라인 →
형식이 틀린 글은 배포가 아니라 빌드에서 멈추게 했다
카테고리 오타 하나가 목록에서 조용히 빠지는 글을 만든다. 콘텐츠 스키마와 교차 파일 검증으로 어긋난 값을 배포 전에 막고, 개발일지의 카테고리 예외와 오류·경고의 현재 경계를 다시 정리한 기록.
목차 3
2026-08-09 정정 — 현재는 개발일지만
category를 비우며, 프로젝트 관계를 함께 읽는 검증기가 아티클·개발일지 규칙을 강제한다. 본문 H1, 남은 Obsidian 문법, 공개 대표글 중복의 검사 등급도 실제 구현에 맞게 바로잡았다.
글을 옮기다 보면 frontmatter 에서 틀린다. 카테고리를 Cloud · Devsecops 로 적거나, 날짜를 2026.07.22 로 쓰거나, 설명을 비워 둔다. 이 장치를 넣기 전에는 이런 값이 틀려도 아무 일도 일어나지 않았다. 사이트는 정상적으로 빌드되고, 그 글만 카테고리 목록에서 조용히 빠졌다. 며칠 뒤 「그 글이 왜 안 보이지」 하고 찾게 됐다.
배포된 뒤에 알게 되는 오류와 빌드에서 걸리는 오류는 고치는 비용이 다르다. 앞의 것은 언제 생겼는지부터 찾아야 하고, 뒤의 것은 방금 고친 파일을 보면 된다.
값의 목록을 한 곳에 두고 스키마가 그것을 읽게 했다
카테고리 이름은 src/data/categories.ts 하나에만 있다. 처음 이 장치를 만들었을 때 콘텐츠 스키마는 그 배열을 필수 z.enum()으로 읽었다. 이후 개발일지를 아티클 목록에서 분리하면서 예외가 하나 생겼다. 현재 스키마는 다음과 같다.
category: z.enum(CATEGORY_NAMES).optional(),.optional()은 아무 글이나 카테고리를 비워도 된다는 뜻이 아니다. 스키마는 글 한 편만 보므로 그 글이 프로젝트의 개발일지인지 알 수 없다. scripts/validate-content.mjs가 프로젝트 파일의 devlog 목록과 글을 함께 읽어, 아티클에는 카테고리가 있어야 하고 개발일지에는 있으면 안 된다는 두 방향을 오류로 검사한다. 목록에 없는 이름을 적으면 Astro 스키마가 막고, 관계에 맞지 않게 비우거나 채우면 저장소 검증기가 막는다. Astro Content Collections 문서가 설명하듯 스키마는 각 항목의 형태를 보장하고, 프로젝트와 글 사이의 관계는 이 저장소의 별도 검증이 맡는다.
카테고리를 추가하는 일은 여전히 파일 하나를 고치는 일이다. 스키마와 라우트와 필터는 같은 목록에서 파생된다.
같은 방식을 다른 칸에도 걸었다. 설명은 z.string().min(1) 로 비어 있는 것만 막고, 날짜는 z.coerce.date() 로 파싱되지 않으면 실패한다. 프로젝트 쪽은 더 강하게 걸었다. 사용 기술은 src/data/skills.ts 의 이름과 정확히 일치해야 하고, 없는 이름을 적으면 프로젝트 페이지 빌드가 실패한다. 자유 문자열로 두면 Terraform 과 terraform 이 갈라져 두 개의 다른 기술이 된다.
설명 길이 제한은 걸었다가 뺐다
처음에는 설명에 z.string().min(60).max(170) 을 걸었다. 검색 결과 스니펫에 알맞은 길이라는 이유였는데, 쓰다 보니 이 규칙이 글을 방해했다. 짧게 끝나는 게 맞는 설명을 60자까지 늘리려고 문장을 덧붙이게 된다. 늘린 문장은 대개 아무 정보도 없다.
그래서 제한을 없애고 비어 있는 것만 막는 쪽으로 바꿨다. 지금은 관리자 화면이 글자 수를 실시간으로 보여 주기만 하고 판단은 사람이 한다.
어디까지를 기계가 막을지가 이 편의 실제 판단이다. 값의 형식이 틀린 것은 기계가 확실히 안다 — 목록에 없는 카테고리, 파싱되지 않는 날짜, 빈 설명. 반면 「이 설명이 좋은 설명인가」는 기계가 모른다. 모르는 것을 규칙으로 만들면 규칙을 피하는 요령만 생긴다.
그래서 검증을 두 층으로 나눴다. Astro 스키마는 frontmatter 한 편의 형식과 타입을 보고, 그 위의 validate-content.mjs는 파일 사이의 관계와 본문 구조를 본다. 현재 본문 H1, 변환되지 않은 Obsidian 임베드·위키링크·주석·콜아웃, 공개 글의 featured: true 중복은 모두 오류다. 개발일지와 카테고리의 양방향 규칙도 여기에 속한다.
경고로 남긴 것은 태그가 없거나 공백을 포함한 경우, 이미지 대체 텍스트가 빈 경우, 공개 대표글이 하나도 없는 경우처럼 사람이 맥락을 보고 고를 항목이다. npm run validate에서는 경고를 보여 주고 성공하지만, npm run check는 --strict로 같은 검증기를 실행한다. npm run release가 이 명령을 거치므로 배포 전에는 경고도 확인하지 않은 채 지나갈 수 없다.
이 방식이 통하는 조건
스키마가 게이트 역할을 하려면 어긴 파일이 초안이어도 멈춰야 한다. 실제로 그렇다. 설명이 빈 글이 하나라도 있으면 초안이든 아니든 개발 서버와 빌드가 통째로 멈춘다. 처음에는 이게 과하다고 생각했는데, 며칠 지나고 보니 이 성질 덕분에 게이트가 우회되지 않았다. 「일단 초안으로 넣어 두고 나중에」가 불가능하기 때문이다.
대신 대가가 있다. 손으로 만든 파일 하나 때문에 사이트 전체가 안 뜨는 상황이 생긴다. 오류 메시지에 파일 경로가 나오고 관리자는 계속 열려 있어서 그 글을 고치면 바로 복구되지만, 처음 겪으면 사이트가 망가진 것처럼 보인다. 그래서 이 증상을 관리자 문서의 「잘 안 될 때」 표 맨 위에 적어 두었다.
지금 경계는 단순히 「오류는 막고 경고는 통과」가 아니다. 구조 계약을 어긴 값은 언제나 오류이고, 글의 질처럼 맥락이 필요한 항목은 작성 중에는 경고로 보여 주되 릴리스에서는 strict 모드로 다시 확인한다. 경계를 옮길 때마다 그 규칙이 정말 기계가 아는 것인지 다시 묻는다.
함께 보면 좋은 글
이 기록과 태그가 겹치는 아티클입니다.