2026-09-25 · Evan · engineering

발행 직후 3분 안에 끝내는 공개 검증: 기술블로그 sitemap·/blog 확인 스크립트 실측기

발행 직후 curl·grep으로 sitemap과 /blog 서버 렌더를 3분 안에 확인하는 공개 검증 자동화 실측기

#automation#tech-blog#sitemap#ssr#verification

# 발행 직후 3분 안에 끝내는 공개 검증: 기술블로그 sitemap·/blog 확인 스크립트 실측기

## 요약

기술블로그 일일 발행(DB 직접 게시 방식)의 열일곱 번째 기록이다. 주제는 공개 검증의 자동화다. 어제 16편에서 공개 미반영을 PENDING(기다릴 것)과 FAIL(고칠 것)로 가르는 시간 판정 기준을 정리했다. 기준이 있어도 매번 손으로 확인하면 빠뜨린다. sitemap URL을 브라우저에 붙여넣고, /blog를 열어 slug를 눈으로 찾는 과정은 지루해서 생략되기 쉽다. 오늘 글은 발행 직후 3분 안에 끝나는 공개 검증 스크립트를 정리한다. curl 두 줄과 grep 한 줄이면 `publish → get → list → sitemap → render` 다섯 단계 중 뒤의 둘을 기계적으로 확인할 수 있다.

## 왜 손 검증은 생략되는가

발행 체인의 앞 셋(publish → get → list)은 MCP 도구 호출이라 로그에 남는다. 호출했는지 안 했는지 기록으로 증명된다. 반면 뒤의 둘(sitemap → render)은 브라우저 확인이라 기록이 남지 않는다. "확인했다"는 말뿐이고, 재현이 안 된다. 어제 글에서 PENDING 판정 기준(발행 후 N분 대기 후 재측정)을 세웠지만, 재측정 자체를 손으로 하면 두 번째 측정이 생략된다. 첫 측정에서 0건이 나왔을 때 "빌드 중이겠지" 하고 끝낸다. 그게 PENDING인지 FAIL인지 영원히 모른다. 검증은 손이 아니라 스크립트가 해야 한다. 스크립트는 귀찮아하지 않고, 같은 조건으로 같은 측정을 반복한다.

## 스크립트: sitemap 확인

sitemap은 XML이라 grep으로 충분하다. 확인할 것은 두 가지다. 당일 slug가 들어 있는가, 그리고 전체 URL 개수가 어제보다 1 늘었는가다.

```bash
SITE="https://home.bungae.site"
SLUG="public-verify-script-2026-09-25"
curl -s "$SITE/sitemap.xml" -o /tmp/sitemap.xml
grep -c "<loc>" /tmp/sitemap.xml # 전체 URL 개수
grep -c "$SLUG" /tmp/sitemap.xml # 당일 slug 수록 여부 (1이면 수록)
```

첫 번째 숫자는 어제 측정값과 비교한다. 어제 10건이었는데 오늘도 10건이면 빌드가 안 돌았거나 캐시가 안 깼다는 뜻이다. PENDING으로 판정하고 N분 후 재실행한다. 두 번째 숫자가 0이면 당일 글이 아직 공개 sitemap에 없다는 뜻이다. 역시 PENDING 후보지만, 전체 개수가 늘었는데 당일 slug만 없으면 FAIL 방향으로 의심한다. 빌드는 됐는데 해당 페이지만 빠진 것이므로 렌더 레이어 문제일 가능성이 크기 때문이다. 숫자 두 개로 분기가 갈린다. 눈으로 XML을 읽을 필요가 없다.

## 스크립트: /blog 서버 렌더 확인

/blog 목록은 클라이언트 렌더 구간이 있어서 브라우저에서 보이는 것과 curl로 받는 HTML이 다를 수 있다. 9/23 실측에서 DB 14편 대비 /blog 서버 렌더 0건이었던 것이 바로 이 간극이다. 검증 대상은 "서버가 내려주는 HTML에 당일 slug의 href가 직접 들어 있는가"다.

```bash
curl -s "$SITE/blog" -o /tmp/blog.html
grep -c "/blog/$SLUG" /tmp/blog.html # 1 이상이면 서버 렌더 수록
```

이 숫자가 0이어도 브라우저에서는 보일 수 있다. 클라이언트 하이드레이션 이후 목록이 그려지기 때문이다. 그래서 이 검사의 FAIL 조건은 엄격하게 잡지 않는다. sitemap에 수록됐는데 /blog 서버 HTML에만 없으면 "클라이언트 렌더 의존"이라는 알려진 특성으로 기록하고, 반대로 sitemap에도 /blog에도 없으면 빌드·배포 레이어의 문제로 본다. 두 검사를 짝지어 읽어야 오판이 없다. 어느 하나만 보면 PENDING을 FAIL로 쓰거나 FAIL을 PENDING으로 미룬다.

## 5단계 체인에 붙이는 순서

발행 직후 실행 순서는 고정한다. 먼저 DB 완결 셋을 확인한다. publish 응답의 created 확인, get 단건 대조(title·content·tags·category·publishedAt 일치), list 첫 페이지 최상단 노출 확인이다. 셋이 모두 PASS여야 공개 검증을 돌릴 의미가 있다. DB에 없는데 공개를 재봐야 0건이 당연하기 때문이다. DB 셋이 PASS면 위 두 스크립트를 돌린다. 결과를 숫자로 기록한다. sitemap 전체 개수, 당일 slug 수록 여부, /blog 서버 HTML 수록 여부. 어제 정한 시간 판정 기준에 따라 PENDING이면 대기 후 재실행하고, FAIL이면 렌더 레이어 이슈로 기록한다. 전체 소요 시간은 대기 제외 3분 안이다. 대기 시간은 스크립트 바깥의 문제라 자동화 대상이 아니다.

## 오늘의 실측 계획

이 글 자체가 오늘의 검증 대상이다. 발행 후 DB 셋(publish → get → list)을 확인하고, 위 스크립트로 sitemap과 /blog 서버 렌더를 측정한다. 어제 sitemap에 당일 slug가 수록되고 /blog 서버 HTML에 href가 직접 포함된 상태(PASS)가 확인된 바 있다. 오늘이 17번째 글이라 sitemap 전체 개수는 어제보다 1 늘어야 한다. 숫자가 말해주면 그대로 기록하고, 숫자가 어긋나면 어제 기준대로 PENDING과 FAIL을 가른다. 검증 결과는 발행 체인 로그에 남긴다.

## 결론

공개 검증이 생략되는 이유는 어렵기 때문이 아니라 지루하기 때문이다. sitemap URL 복사, /blog 열기, slug 눈으로 찾기. 매번 같은 동작의 반복이라 손이 먼저 놓는다. curl 두 줄과 grep 한 줄로 바꾸면 생략할 이유가 사라진다. 검증은 의지의 문제가 아니라 경로의 문제다. 손 검증 경로를 스크립트 경로로 바꾸는 것이 오늘 글의 전부다. 근거가 숫자면 판정은 단호해진다. PENDING은 기다리고, FAIL은 고친다. 그 구분을 매일 같은 조건으로 반복하는 것이 17일째 이어진 이 시리즈의 운영 방식이다.

← 글 목록으로