완성 기준을 “글 한 편이 검색에 잡히는 것”으로 잡았습니다
만들기 전에 정한 완료 조건은 기능 목록이 아니었습니다. 글을 하나 쓰면 그 글이 고유 주소를 갖고, 목록과 사이트맵과 RSS에 자동으로 들어가고, 명령 한 줄로 내 도메인에 올라가는 것. 이 문장 하나가 이후 모든 선택을 정리해 줬습니다. 댓글, 로그인, 검색창, 다크모드 토글은 전부 뺐습니다. 없어도 완료 조건이 충족되기 때문입니다.
2026년 9월 17일 기준으로 이 저장소에는 글 본문 디렉터리가 55개, 목록에 등록된 글이 58편 있습니다. 홈·주제·소개·문의·편집원칙 같은 고정 페이지와 robots.ts, sitemap.ts, rss.xml이 붙어 있고, 애드센스 스크립트가 들어가 있습니다. 데이터베이스는 한 개도 쓰지 않습니다.

프레임워크는 AI가 잘 아는 것, 호스팅은 요금이 0에 가까운 것
스택은 두 가지 기준으로만 골랐습니다. 첫째, 학습 데이터가 두꺼워서 AI가 실수를 덜 하는 것. 둘째, 글만 있는 사이트라 비용이 거의 들지 않는 것. 실제로 설치된 버전은 package.json에 그대로 남아 있습니다.
| 역할 | 선택 | 버전 |
|---|---|---|
| 프레임워크 | Next.js (App Router) | 16.2.6 |
| UI 라이브러리 | React | 19.2.6 |
| 빌드·런타임 어댑터 | vinext + Vite | 1.0.0-beta.3 / 8.0.13 |
| 스타일 | Tailwind CSS | 4.2.1 |
| 호스팅·배포 | Cloudflare Workers (wrangler) | 4.92.0 |
| 실행 환경 | Node.js | 22.13 이상 |
여기서 하나가 기준에서 벗어납니다. vinext는 버전 번호가 1.0.0-beta.3인 베타 패키지입니다. Next.js 앱을 Vite로 빌드해 Cloudflare Workers에 얹기 위해 쓰는데, 베타라서 AI 모델이 이 패키지를 거의 모릅니다. 실제로 겪은 증상은 명확합니다. 에이전트가 자신 있게 제안한 설정 옵션이 존재하지 않는 옵션이었습니다. Next.js의 일반적인 관례를 기억해서 그대로 갖다 붙인 것이고, 빌드는 조용히 그 옵션을 무시했습니다.
그래서 규칙을 하나 만들었습니다. 버전이 1.0 미만인 패키지의 설정은 AI 답변을 그대로 믿지 않고 해당 패키지의 node_modules 안 타입 정의 파일을 직접 열어 확인합니다. 문서보다 타입 정의가 정확하고, 무엇보다 지금 설치된 버전의 진실이기 때문입니다. 유명한 라이브러리를 쓸 때는 필요 없는 절차인데, 최신 도구를 쓰는 순간 바이브코딩의 품질이 여기서 갈립니다.
글을 데이터베이스가 아니라 파일에 둔 것이 가장 큰 결정이었습니다
블로그를 만든다고 하면 보통 관리자 화면과 글 테이블부터 떠올립니다. 이 사이트에는 둘 다 없습니다. 글 목록은 app/posts.tsx 파일 하나에 배열로 들어 있고, 길이는 159줄입니다. 한 줄이 글 한 편이라고 보면 됩니다.
{ slug: "vibe-coding-blog-build", title: "...", seoTitle: "...",
description: "...", excerpt: "...", category: "AI 코딩",
datePublished: "2026-09-17", dateModified: "2026-09-17" }
본문은 app/guides/<슬러그>/page.tsx에 있습니다. 즉 글 한 편을 늘리는 일은 폴더 하나 만들고 배열에 한 줄 추가하는 것이고, 목록·사이트맵·RSS·JSON-LD는 그 배열을 읽어 알아서 갱신됩니다.
이렇게 한 이유는 취향이 아닙니다. AI 에이전트에게 작업을 맡길 생각이라면 데이터가 파일이어야 합니다. 데이터베이스에 글이 들어 있으면 에이전트는 관리자 화면에 로그인하거나 API를 호출해야 하고, 무엇을 바꿨는지 확인하려면 다시 조회해야 합니다. 파일이면 전혀 다릅니다. 무엇이 바뀌었는지 git diff 한 번으로 전부 보이고, 잘못되면 되돌리는 것도 한 줄입니다. 실제로 사고가 났을 때 저를 구한 것도 이 구조였습니다.
글이 수백 편이 되면 배열 파일이 길어져 병합 충돌이 늘어납니다. 여러 사람이 동시에 글을 쓰는 팀이라면 이 구조는 맞지 않습니다. 1인 운영이고 글쓴이가 저장소에 접근할 수 있을 때만 성립하는 선택입니다.
배포 코드는 20줄, 빌드는 한 자릿수 초입니다
바이브코딩 글에서 잘 다루지 않는 구간이 배포입니다. 만드는 것보다 올리는 데서 막히는 경우가 훨씬 많은데도 그렇습니다. 이 사이트의 배포는 package.json의 스크립트 한 줄에 전부 들어 있습니다.
"deploy": "vinext build && node scripts/prepare-deploy.mjs
&& wrangler deploy -c dist/server/wrangler.deploy.json"
가운데 끼어 있는 prepare-deploy.mjs가 직접 쓴 유일한 배포 코드이고, 20여 줄입니다. 하는 일은 두 가지뿐입니다. 빌드 도구가 생성한 Cloudflare 설정 파일을 읽어 워커 이름과 커스텀 도메인 경로를 입히고, 정적 자산 응답에 하루짜리 캐시 헤더를 덧붙입니다.
const cfg = JSON.parse(readFileSync(SRC, 'utf8'));
cfg.name = 'techworklog';
cfg.routes = [{ pattern: 'techworklog.com', custom_domain: true }];
writeFileSync(OUT, JSON.stringify(cfg, null, 1));
왜 설정 파일을 직접 고치느냐면, 빌드 도구가 만드는 설정에는 도메인 정보가 없기 때문입니다. 손으로 매번 고치면 빌드할 때마다 덮어써집니다. 이런 20줄짜리 접착제 코드가 바이브코딩에서 AI가 가장 잘하는 종류의 작업입니다. 요구사항이 명확하고, 결과가 즉시 참이거나 거짓으로 판정되니까요.
실제 빌드 시간은 이렇게 나옵니다. 글 58편 규모에서 연속해서 네 번 돌려 보니 전체 소요 시간은 4초에서 12초 사이였고, 아래는 그중 한 번의 출력입니다.
[1/5] analyze client references... ✓ 290 modules transformed (677ms)
[2/5] analyze server references... ✓ 126 modules (251ms)
[3/5] build rsc environment... ✓ 288 modules (987ms)
[4/5] build client environment... ✓ 133 modules (1.22s)
[5/5] build ssr environment... ✓ 128 modules (974ms)
real 0m6.325s

길어야 열두 초입니다. 이 숫자가 중요한 이유는 속도 자랑이 아니라 검증 습관의 비용이기 때문입니다. 빌드가 5분 걸리면 “일단 올리고 확인하자”는 유혹이 생기지만, 이 정도면 글을 고칠 때마다 빌드를 돌리게 됩니다. AI가 만든 코드를 자주 검증하는 구조를 만들고 싶다면, 검증 자체가 싸야 합니다.
AI에게 맡겼다가 실제로 난 사고는 코드 사고가 아니었습니다
여기가 이 글의 핵심입니다. 몇 달 운영하면서 겪은 사고를 정리해 보니 “코드가 안 돌아가는” 문제는 거의 없었습니다. 문제는 전부 멀쩡히 돌아가는데 내용이 틀렸거나, 조용히 사라졌거나, 겉보기에만 정상인 쪽에서 나왔습니다.
① 사실이 틀린 글이 모든 검사를 통과했습니다같은 파이프라인으로 운영하는 다른 사이트에서, 세법 개편안을 다룬 초안이 발표된 적 없는 한도 숫자를 표로 만들어 넣은 적이 있습니다. 문법도 맞고 빌드도 성공하고 링크도 전부 열렸습니다. 기계가 잡을 수 있는 오류가 하나도 없었던 겁니다. 발행 직전 사람이 원문 기사를 대조하다 발견했습니다. 자동 검사는 ‘형식’만 봅니다.
② 병렬로 돌린 작업들이 같은 파일을 덮어썼습니다글 여러 편을 동시에 쓰게 했더니, 각 작업이 모두 글 목록 배열 파일을 수정하려 했습니다. 결과는 항목 중복과 항목 삭제였습니다. 본문 파일은 각자 폴더라 안전했는데, 공유 파일 하나가 병목이었습니다. 지금은 본문은 병렬로 쓰되 목록 등록은 마지막에 한 번만 순차로 처리합니다.
③ 한글이 조용히 깨졌습니다터미널을 거쳐 본문을 파일에 쓰는 과정에서 한 글자가 유니코드 대체 문자로 바뀐 적이 있습니다. 화면에서는 검은 마름모 하나라 눈에 잘 띄지 않고, 빌드도 통과합니다. 지금은 발행 전에 대체 문자를 전수 검색합니다.
한 가지 더 있습니다. 이미지 태그는 멀쩡한데 그 이미지 파일이 실제로는 폴더에 없던 경우가 있었습니다. 작업 중 정리 과정에서 지워진 것인데, 빌드는 이미지 존재 여부를 확인하지 않으므로 아무 경고도 나오지 않습니다. 배포한 다음 브라우저에서 깨진 아이콘을 보고서야 압니다.
바이브코딩의 위험은 “AI가 코드를 못 짜는 것”이 아니라 “틀린 결과가 성공처럼 보이는 것”입니다. 컴파일러는 사실 확인을 해주지 않고, 링크 검사기는 이미지가 의미 있는지 봐주지 않습니다. 그래서 검사 목록이 필요합니다.
발행 전에 돌리는 검사는 다섯 줄입니다
위 사고들을 겪은 뒤 고정한 순서입니다. 사람이 판단할 것과 기계가 확인할 것을 나누는 게 목적입니다.
| 확인 항목 | 방법 | 누가 |
|---|---|---|
| 타입 오류 | npx tsc --noEmit | 기계 |
| 빌드 성공 | npm run build | 기계 |
| 한글 깨짐 | grep -c $'\xef\xbf\xbd' 파일 | 기계 |
| 이미지 실존·크기 | 본문이 참조하는 경로 전수 대조 | 기계 |
| 의도한 파일만 변경 | git status | 기계 |
| 숫자·날짜·출처 | 원문을 열어 한 줄씩 대조 | 사람 |
맨 아래 한 줄이 나머지 다섯 줄보다 오래 걸립니다. 그리고 그 한 줄을 건너뛰면 앞의 다섯 줄이 전부 통과해도 틀린 글이 나갑니다. git status가 목록에 있는 이유도 같습니다. 에이전트에게 글 한 편을 맡겼는데 전혀 다른 파일이 같이 바뀌어 있는 경우가 생기고, 배포 명령이 커밋이 아니라 현재 작업 폴더를 그대로 올리는 구조라면 그 변경이 같이 올라갑니다.
같은 걸 만들어 볼 생각이라면
처음부터 사이트 전체를 한 번에 요구하지 않는 편이 결과가 좋습니다. 이 사이트도 다음 순서로 늘렸습니다.
1단계 · 글 한 편이 보이는 주소목록도 스타일도 없이, 특정 주소로 들어가면 글 하나가 뜨는 것까지만 만듭니다. 여기서 프레임워크의 라우팅 방식을 이해하게 됩니다.
2단계 · 목록을 데이터에서 생성배열 하나를 만들고 홈이 그 배열을 읽게 합니다. 글을 추가할 때 손댈 곳이 한 군데로 줄어듭니다.
3단계 · 배포스타일을 다듬기 전에 먼저 올립니다. 배포가 막히는 지점은 대개 도메인과 설정 파일이라, 글이 적을 때 뚫어두는 편이 낫습니다.
4단계 · 사이트맵·RSS·메타데이터검색엔진에 필요한 것들입니다. 배열 기반이면 이 단계가 가장 쉽습니다.
5단계 · 검사 목록 고정사고가 한 번 나고 나서 만드는 게 보통이지만, 위 표를 그대로 가져다 쓰면 한 번은 건너뛸 수 있습니다.
도구는 터미널에서 돌아가는 코딩 에이전트를 썼습니다. 브라우저 안에서 앱을 만들어주는 생성형 서비스는 첫 화면까지는 훨씬 빠르지만, 이 사이트처럼 배포 설정 파일을 직접 고쳐야 하는 작업에서는 내 저장소 안의 파일을 그대로 다루는 쪽이 편합니다. 도구별 차이는 바이브코딩 툴 비교에, 프롬프트와 검증 루프를 짜는 기본기는 바이브코딩 입문에 정리했습니다. 작업을 여러 개 동시에 돌릴 계획이라면 ②번 사고를 피하기 위해 git worktree를 먼저 보시는 것을 권합니다.
자주 묻는 질문
코딩을 전혀 모르면 이 정도까지 만들 수 있나요?
배포와 도메인 연결 단계에서 한 번은 막힙니다. 코드를 짜는 능력보다 “지금 어디까지 됐고 무엇이 안 되는지”를 설명하는 능력이 더 필요합니다. 에러 메시지를 그대로 붙여넣는 것만으로도 대부분 풀립니다.
운영 비용은 얼마나 드나요?
이 사이트 기준으로 고정비는 도메인 값뿐입니다. 글만 있는 정적 사이트라 Cloudflare Workers의 무료 범위 안에서 돌아가고, 이미지도 같이 배포되므로 별도 저장소를 쓰지 않습니다. 트래픽이 커지면 달라집니다.
글도 AI가 쓰나요?
초안 작성과 자료 정리에 사용합니다. 다만 숫자·날짜·출처는 사람이 원문과 대조한 뒤에만 발행합니다. 기준은 편집·정정 원칙에 적어 두었습니다.
버전·줄 수·파일 구조는 2026년 9월 17일 이 사이트의 저장소에서 직접 확인했습니다. 빌드 시간은 같은 날 npm run build를 네 번 연속 실행해 측정한 값(4–12초)이며, 기기와 캐시 상태에 따라 달라집니다. 사고 사례는 운영 중 실제로 발생해 기록해 둔 내용입니다. 스택 구성과 배포 방식을 그대로 따라해 보려면 각 도구의 공식 문서를 함께 보셔도 좋습니다.
Next.js App Router 공식 문서 ↗ · Cloudflare Workers 공식 문서 ↗ · wrangler 명령 레퍼런스 ↗