Build Log
자동화에서 가장 중요한 건 ‘만드는 것’이 아니라 ‘잘못 올리지 않는 것’이었다
N-Layer Build Log 네 번째 기록. 초안과 이미지의 공개 차단, lint·타입 검사·테스트·빌드와 기존 페이지 회귀 확인을 살펴봤다. 빠르게 만드는 흐름에 게시를 멈추는 기준이 왜 필요한지 정리한다.
3편 — AI에게 글쓰기를 맡기면 블로그가 자동화될까?에서는 사람이 할 일과 AI에게 맡길 일을 나눴다. 반복되는 파일 형식과 초안 정리는 도움을 받을 수 있지만, 사실과 경험, 공개 여부를 판단하는 일은 사람에게 남겨야 했다.
그다음에는 반대쪽 질문이 생겼다.
AI와 자동화가 글을 빠르게 만들 수 있다면, 잘못된 글도 빠르게 만들 수 있지 않을까?
아직 검토하지 않은 초안이 공개되거나, 다른 글의 이미지가 붙거나, 링크가 엉뚱한 페이지를 가리킬 수 있다. 글 파일의 문법이 틀려 빌드가 실패할 수도 있다. 새 글은 잘 보이는데 기존 홈페이지가 깨지는 경우도 생각해야 한다.
이것들은 이번 시리즈에서 실제로 일어났다는 사고 기록이 아니다. 자동화에 맡기기 전에 막아야 할 가능한 실패를 나열한 것이다.
사람이 직접 게시할 때도 실수는 생긴다. 다만 단계마다 확인할 기회가 있다. 여러 단계를 자동으로 이어 놓으면 잘못된 입력 하나가 다음 작업으로 빠르게 넘어가고, 같은 실수가 반복될 수 있다.
그래서 ‘얼마나 빨리 만드는가’ 옆에 ‘어디에서 멈추는가’를 놓아야 했다. 자동화가 강해질수록 ‘만드는 기능’보다 ‘멈추는 기능’이 중요해졌다.
이번 글은 ‘블로그 자동화 만들기’의 네 번째 기록이다. 추상적인 안전 원칙보다, N-Layer에서 실제로 사용한 검사와 공개 경계를 살펴보려 한다.
Draft는 단순한 임시 저장이 아니었다
초안은 보통 나중에 이어 쓰려고 저장해 둔 글이다. 이번 블로그에서는 거기에 한 가지 역할을 더 붙였다. 작성 중인 글을 공개용 결과물에서 분리하는 것이다.
글 파일 앞의 published: false가 그 구분이다. 파일은 작업 폴더에 있고, 검수 대상에도 들어간다. 빌드는 초안의 제목 정보와 본문도 읽고 검사한다. 잘못된 초안이 있어도 무조건 건너뛰는 방식은 아니다.
하지만 공개용 빌드에는 그 글의 HTML 페이지를 만들지 않는다. 목록, RSS와 sitemap에도 넣지 않는다. RSS는 새 글 소식을 모아 주는 목록이고, sitemap은 검색엔진에 페이지 주소를 알려 주는 목록이다. 직접 들어가는 주소뿐 아니라 이런 목록에서도 초안을 빼야 했다.
이미지도 같은 기준을 따른다. public/blog/ 아래 글 이름과 같은 폴더가 있어도, 현재 빌드는 공개 대상 글의 이미지 폴더만 결과물로 복사한다. 초안 글의 폴더는 공개용 결과물에 없다. 그래서 그 결과물을 제공하면 글 주소와 이미지 주소 모두 404가 된다.
이건 로그인이나 암호로 숨기는 기능이 아니다. 공개할 파일을 애초에 결과물에 넣지 않는 방식이다. 로컬 초안 미리보기는 별도 폴더에 만들고 검색 제외 표시를 붙인다. 검색 제외 표시 자체가 접근 차단은 아니므로, 미리보기 결과물을 외부에 올리면 안 된다. 현재 스크립트는 Vercel이나 CI 환경에서 초안 빌드를 실행하려 하면 거부하도록 되어 있다.
자동화에서 draft는 저장 상태가 아니라 첫 번째 안전장치였다. 적어도 지금 구조에서는 ‘파일이 있다’와 ‘독자가 볼 수 있다’를 분리해 준다.
다만 이 보호에도 범위가 있다. 초안 이미지를 공개 글의 폴더에 따로 복사하면 그 파일은 보호 대상 초안 폴더 밖에 있다. 이미 배포한 글을 나중에 draft로 바꿔도 운영 사이트가 즉시 바뀌지는 않는다. 새 결과물을 배포해야 한다. 공개 상태와 저장 위치, 배포 범위를 함께 지켜야 하는 이유다.
오류는 게시 전에 잡아야 한다
글을 넘기기 전에 맞춤법을 보고, 사진이 빠지지 않았는지 확인하듯 코드와 웹페이지에도 여러 종류의 검사가 필요했다. 하나가 통과했다고 나머지까지 확인된 것은 아니었다.
Lint는 코드의 기본 규칙을 확인하는 교정 작업에 가깝다. 우리 프로젝트의 npm run lint는 빌드·서버 스크립트와 테스트, 검사 설정을 살펴본다. 글의 한국어 맞춤법이나 사실관계를 교정하는 명령은 아니다.
Typecheck는 부품의 연결 규격을 확인하는 일에 가깝다. 숫자가 필요한 자리에 다른 종류의 값이 들어가거나, 필요한 값의 연결이 잘못됐는지 코드에서 확인한다. 현재 npm run typecheck의 대상은 TypeScript로 작성한 블로그 스크립트다. MDX 본문의 문법과 모든 JavaScript 파일까지 이 명령 하나로 검사하는 것은 아니다.
Test는 정해 둔 동작을 실제로 해 보는 점검이다. 공개 글이 목록에 나오는지, 초안 주소와 이미지가 막히는지, 글의 표와 이미지가 출력되는지 확인한다. 잘못된 날짜, 중복 주소와 허용하지 않은 본문 코드가 거부되는지도 검사한다. 사람이 정한 질문에 답하는 방식이라, 테스트로 만들지 않은 문제는 놓칠 수 있다.
Build는 재료를 실제로 내놓을 결과물로 만드는 작업이다. 글 파일을 읽어 HTML로 바꾸고, 공개할 이미지와 기존 페이지를 준비한다. 제목 정보가 규칙에 맞지 않거나 본문을 읽을 수 없으면 실패한다. 이미지 파일의 존재와 글별 경로, 설명의 필수 여부도 검사한다.
이미지가 있다는 확인은 그 사진이 내용에 맞는다는 확인과 다르다. 링크도 허용된 주소 형식인지는 검사하지만, 모든 외부 링크의 목적지와 내용을 자동 확인하지는 않는다. 이런 차이를 알고 결과를 읽어야 한다.
| 검증 | 무엇을 확인하는가 | 실패하면 |
|---|---|---|
| Lint | 스크립트·테스트 코드의 기본 규칙 | 수정 후 재검사 |
| Typecheck | 블로그 TypeScript 코드의 값·연결 규칙 | 연결을 수정하고 재검사 |
| Tests | 공개·초안·이미지·페이지 등 정해 둔 동작 | 다음 게시 단계 중단, 원인 확인 |
| Build | 메타데이터·MDX·이미지 검사와 HTML 결과물 생성 | 실패한 결과물을 배포하지 않음 |
| 회귀 확인 | 홈·프로젝트·목록·이전 글의 동작과 화면 | 변경 원인을 찾아 수정·재확인 |
이것들은 현재 프로젝트에서 각각 실행하는 명령과 확인 작업이다. npm test 안에는 빌드가 먼저 실행되고, 그다음 테스트가 실행된다. lint와 타입 검사는 별도다. 아래에서 말하는 검증 게이트는 이 검사들을 통과해야 게시를 진행한다는 절차를 뜻한다. 모든 명령과 승인을 한 버튼으로 강제하는 게시 시스템이 이미 완성된 것은 아니다.
새 글 하나 때문에 기존 사이트가 깨질 수도 있다
새 글이 잘 보이면 작업이 끝난 것처럼 느껴질 수 있다. 그런데 블로그에는 새 글만 있는 것이 아니다. 홈페이지와 프로젝트 소개, 앞서 쓴 글과 초안을 숨기는 규칙도 함께 있다.
공통 스타일을 수정하면 다른 글의 표가 밀릴 수 있다. 빌드에서 이미지를 복사하는 범위를 넓히면 초안 이미지가 따라 나올 수 있다. 목록을 바꾸다가 이전 글 링크가 빠질 수도 있다. 이런 가능성을 새 글 화면 하나로는 확인하기 어렵다.
이미 잘 되던 기능이 변경 뒤에도 그대로 동작하는지 다시 보는 것을 회귀 확인이라고 부른다. 새 가구를 들인 뒤 문이 여전히 열리고, 다른 가구를 쓸 수 있는지 확인하는 것과 비슷하다.
이번 시리즈에서도 새 글 외에 같은 곳을 반복해서 살폈다.
- 홈이 열리고 기존 소개가 유지되는가?
/take-a-look프로젝트 페이지에 직접 접근할 수 있는가?/blog목록에서 글과 상세 링크를 찾을 수 있는가?- 이전 Build Log 글의 본문, 이미지와 표가 그대로 표시되는가?
- 기존 draft 글과 이미지 주소는 여전히 404인가?
- 작은 화면에서 표와 도표 때문에 페이지가 가로로 밀리지 않는가?
테스트는 주소 응답과 정해 둔 출력 내용을 확인한다. 브라우저에서는 실제 모양과 읽기 흐름을 살핀다. 앞선 글의 원문·이미지·생성 HTML을 변경 전후 파일 해시로 비교한 것도 같은 이유다. 파일 내용이 같은지 확인하는 보조 수단이며, 그것만으로 모든 화면 동작이 증명되는 것은 아니다.
새 기능이 잘 되는 것만 확인하면 충분하지 않았다. 이미 잘 되던 것도 계속 잘 되는지 확인해야 했다.
도표의 PASS는 확인할 조건을 통과했다는 뜻이다. 사람이 글의 의도와 공개 여부를 승인하는 일은 검사 프로그램의 PASS와 다르다. 초안 단계의 확인 뒤 공개 준비 상태로 바꿨다면, 공개용 결과물에서도 검사와 회귀 확인을 다시 마쳐야 한다.
자동화는 실패할 권한보다 멈출 권한이 중요하다
오류를 발견해도 다음 단계로 계속 넘어가면 검사는 기록만 남기고 끝난다. 게시를 멈출 기준과 함께 있어야 의미가 있다.
현재 검사 명령은 실패하면 오류를 내고 종료한다. 그때 작업 흐름에서도 배포를 진행하지 않고, 원인을 확인하고 수정한 뒤 필요한 검사를 다시 해야 한다. 아직은 이 규칙을 사람이 지키며 작업한다. 명령이 오류를 냈다는 사실만으로 별도로 실행한 배포까지 자동 차단되는 것은 아니다.
필요한 행동은 네 가지로 정리할 수 있었다. 실패를 알아차리고, 게시를 멈추고, 어느 파일이나 검사에서 문제가 났는지 보고하고, 수정된 결과가 확인되기 전까지 운영 사이트를 바꾸지 않는 것이다.
여기서 ‘기존 상태 유지’도 정확히 말해야 한다. 배포하지 않으면 운영 사이트는 그대로지만, 로컬 빌드는 결과물 폴더를 새로 만들면서 진행한다. 실패 때 이전 로컬 결과물을 자동 복원하는 기능은 현재 없다. 실패한 폴더를 게시 가능한 결과로 취급하지 않고, 수정 후 성공한 빌드를 다시 준비해야 한다.
멈췄다는 결과는 자동화가 실패했다는 뜻만은 아니다. 잘못된 결과가 외부로 넘어가기 전에 발견했다는 뜻이기도 하다. 원인 보고에는 확인된 오류와 아직 확인하지 못한 부분을 함께 남겨야 다음 수정도 정확해진다.
사람이 마지막에 남는 이유
형식이 맞고 빌드가 성공해도 글의 의도가 달라질 수 있다. 실제로 하지 않은 일을 경험처럼 표현하거나, 공개하지 않을 맥락을 자연스럽게 문장에 넣을 수도 있다. 이런 글은 기술 검사만으로 걸러지지 않을 수 있다.
자동 검증은 정해진 파일 규칙과 변환 오류, 반복되는 동작 확인을 맡는다. AI는 그 검사를 실행하고 결과를 정리하는 데 도움을 줄 수 있다. 사람은 무엇을 말하려 했는지, 맥락이 빠지지 않았는지, 실제 경험과 어긋나지 않는지, 공개해도 되는 내용을 판단한다.
published: true는 이 판단을 기록하는 승인 문서가 아니다. 공개용 빌드에 넣으라는 값일 뿐이다. 누가 어떤 내용을 검토했는지와 배포 범위를 확인하는 절차는 따로 필요하다.
이번 4편도 게시 준비와 검증, 커밋까지 진행한다. 공개용 파일을 준비하는 것과 운영 사이트에 올리는 것을 구분하고, push와 production 재배포는 이번 범위에 포함하지 않는다.
검증 자동화는 사람을 없애기 위한 것이 아니라, 사람이 더 중요한 판단에 집중하게 하기 위한 것이었다. 반복되는 오류를 검사할수록 사람은 글의 내용과 공개할 맥락을 더 자세히 살필 수 있다.
이제는 하나의 흐름으로 연결할 차례다
지금까지 남긴 기록은 서로 다른 질문에서 시작했다.
- 1편 — 시작 이유: 왜 기록 공간을 직접 만들려 했는가.
- 2편 — 글 구조: 글 파일은 어떻게 웹페이지가 되는가.
- 3편 — 사람과 AI 역할: 무엇을 맡기고 무엇을 사람이 결정할 것인가.
- 4편 — 검증과 안전장치: 어떤 결과를 막고 어디에서 멈출 것인가.
이제 마지막 질문이 남았다.
이 모든 단계를 하나의 흐름으로 연결하면 실제 블로그 자동화 시스템은 어떤 모습이 되는가?
검사 명령과 초안 보호는 있다. 하지만 주제 결정부터 게시 승인까지 모두 연결한 버튼은 아직 없다. 다음에는 지금 있는 장치와 앞으로 연결할 작업을 구분하며 그 흐름을 살펴보려 한다.
이전 글: 3편 — AI에게 글쓰기를 맡기면 블로그가 자동화될까?
다음 글: 5편 — 버튼 하나로 글이 올라갈 때까지 — N-Layer Blog 자동화 완성기
만들고, 검사하고, 멈추고, 다시 확인하는 과정이 연결되면서, 비로소 하나의 자동화 시스템이 보이기 시작했다.