한 문단 요약
이 시스템은 한 사람이 만들고 유지한다 — 그런데 규모는 64개 쇼핑몰, 추적 소스 ~9만 줄, 4개월간 463개 커밋, 유닛 테스트 1,082개다. 쇼핑몰마다 HTML 구조가 다르고 수시로 바뀌어서, 하나를 고치면 다른 하나가 조용히 깨진다. 사람 한 명의 눈으로는 이걸 다 못 본다. 그래서 코드를 직접 다 짜는 대신, AI 를 "스태프 엔지니어처럼" 부리는 워크플로를 만들었다 — 규약을 문서로 못박고, 검증을 여러 AI 에이전트에게 병렬로 시키고, 만든 것을 스스로 반박하게 하고, 배운 것을 기억에 쌓고, 감사 도구로 회귀를 막는다. 이 글은 그 다섯 개의 축과, 이 글을 쓰는 과정 자체가 코드 버그를 잡아 같은 날 고친(PR #66) 실사례다.
1. 문제 — 1인 개발자의 네 가지 한계
혼자 이 규모를 운영하면 네 곳에서 막힌다.
- 컨텍스트 — 64개 샵 × 12개 플랫폼(cafe24·makeshop·godo·shopify·yes24 …)의 세부를 한 머리에 다 담을 수 없다. 어제 고친 걸 오늘 잊는다.
- 회귀 — 공통 파서를 한 줄 고치면 그 게이트를 지나는 수십 개 샵이 영향받는다. "고쳤는데 다른 게 깨진" 걸 사람 눈으로 전수 확인하기 어렵다.
- 품질 — 리뷰어가 없다. 내가 만든 걸 내가 승인하면 같은 맹점을 못 본다(케이스 스터디 ③의 "자기 검증의 함정"과 같은 문제).
- 기억 — 세션이 끝나면 맥락이 사라진다. "이 샵은 왜 이렇게 처리했더라"가 매번 리셋된다.
각 한계에 하나씩 대응하는 다섯 개의 축을 세웠다.
2. 다섯 개의 축
축 ① 규약을 코드처럼 — CLAUDE.md
AI 에게 매번 같은 원칙을 말로 반복하는 대신, 프로젝트 규약을 파일로 못박아 세션마다 자동 주입한다(CLAUDE.md, repo 루트). 규약은 추상적 선언이 아니라 집행 가능한 규칙이다:
- 샵별 vs 공통 편집 경계 — "특정 사이트를 고치라면 그 샵 모듈(
main/shops/<id>.js)만. 공통으로 확장하지 말 것. 애매하면 물어봐." → 한 샵 수정이 64개로 번지는 사고를 구조적으로 차단. - Git 위생 — 미커밋 변경 누적 임계값, 기본 브랜치 보호, merge commit(잔디·이력 보존, squash 금지) 규약.
- 실행 중 프로세스 보호 — "사용자가 결과를 확인 중일 수 있으니 dev 프로세스를 임의로 죽이지 말 것." → 검증을 이유로 운영을 끊는 실수 방지.
- 자기 개선 루프 — 교정받으면
tasks/lessons.md에 패턴을 적어 재발을 막는다.
규약을 문서로 두니, 같은 실수를 두 번 하지 않는 재현 가능한 작업 표준이 된다.
축 ② 서브에이전트·워크플로 오케스트레이션 — 병렬 팬아웃 검증
한 개의 긴 대화로 다 하지 않는다. 독립적인 하위 작업은 여러 AI 에이전트에게 병렬로 팬아웃하고 결과만 취합한다. 컨텍스트를 깨끗이 유지하면서 검증의 폭을 넓히는 방식이다.
실사례(이 케이스 스터디 시리즈): 각 편을 쓰기 전, 4개의 검증 에이전트를 병렬로 띄워 커밋·코드·수치를 각자 다른 각도에서 대조하게 했다(예: ②편은 CDP 캡처 / cafe24 안티봇 / 에스컬레이션 / 커버리지 카운트를 각 에이전트가 담당, 구조화 스키마로 근거를 강제). 이 글의 "혼자 못 본다"를 실제로 여러 눈으로 본다.
이 방식은 정확성 감사(케이스 스터디 ③)에서도 썼다 — 독립 판독 에이전트 11개가 화면을 직독해 스크래퍼의 셀렉터와 다른 눈으로 대조했다.
축 ③ 적대적 리뷰 — 만들고, 스스로 반박한다
만든 결과를 그대로 믿지 않는다. 일부러 반박하는 리뷰를 붙여, 그럴듯하지만 틀린 것을 걸러낸다.
실사례: STEP 1b(하네스 결함 수정)는 적대적 리뷰 3렌즈(blocker/major 0, minor 3건 반영)를 거쳤고, 라이브 스냅샷 1,347건 전수 A/B 스윕으로 "변경 54건이 전부 의도된 것, 의도 외 부수효과 0건"을 증명했다. STEP 2(구글폼 에이전트)는 적대적 diff 리뷰로 결함 3건(URL 쿼리 오매칭·토큰 한도 조용한 실패·동의문 매칭)을 머지 전에 잡아 고쳤다.
"만든 사람"과 "검증하는 사람"을 분리하는 것 — 혼자여도 그 구조를 AI 로 만든다.
축 ④ 메모리 — 세션을 건너 배운 것을 쌓는다
세션이 끝나도 사라지지 않게, 배운 것을 파일 기반 메모리(현재 66개)에 쌓는다. 한 파일에 사실 하나, 프론트매터로 분류(사용자·피드백·프로젝트·참조)하고, MEMORY.md 색인이 매 세션 주입돼 관련 기억을 불러온다.
실사례(이 세션): ②편을 쓰며 "자동 로그인 25개 샵"이라는 기존 메모가 코드와 안 맞음을 발견 — 실제 LOGIN_SPECS 는 23개였다. 케이스 스터디를 바로잡는 데 그치지 않고, stale 카운트가 재발하지 않도록 관련 메모리 파일의 수치를 현행으로 교정했다(다음 세션의 오류를 미리 막음).
메모리는 "기억"이자 자기 교정 장치다 — 틀린 것으로 드러난 기억은 지우거나 고친다.
축 ⑤ 감사 루프 — 회귀를 도구로 막는다
마지막 축은 케이스 스터디 ③의 주제와 같다: 일회성 감사를 상시 평가 하네스로 승격해 (npm run eval:golden, 골든셋 112케이스), 누가 파서를 건드리면 "무엇이 새로 깨졌는지"를 즉시 말하게 했다. AI 가 만든 변경도 이 결정적 회귀 가드를 통과해야 한다 — AI 는 판단에, 결론은 재현 가능한 규칙에 둔다.
3. 하루의 실사례 — 2026-08-05, 그리고 문서가 잡은 버그
이 워크플로가 실제로 어떻게 도는지는, 하루치 로그가 가장 잘 보여준다. 2026-08-05 하루에:
2026-08-05 (모두 워크트리 분기 → PR → main merge commit)
PR #63 Eval 하네스 (골든셋 112케이스) b23937a
PR #64 하네스 발견 결함 5건 수정 95.5% → 100% 6875fbe
PR #65 구글폼 초안 생성 에이전트 (Gemini tool-use) e77ef03
+ 케이스 스터디 ①②③ 초고 (각 편 4-에이전트 병렬 검증)
PR #66 ← 아래 참조 4837b2f
문서 작성이 코드 버그를 잡았다 (PR #66)
케이스 스터디 ①(sleep-guard)을 쓰며, 서사에 인용할 모든 코드를 검증 에이전트로 재확인하던 중 한 줄이 걸렸다:
// main/sleep-guard.js (수정 전)
powerSaveBlocker.start('prevent_app_suspension'); // ← 언더스코어
Electron 의 유효 상수는 하이픈 'prevent-app-suspension' 이다. 언더스코어 표기를 실제 Electron 에서 구동해 보니 throw(conversion failure) 가 났고, 그걸 try/catch 가 삼켜 _blockerId=null — 즉 "사이클 중 잠들기 방지(1층 예방)"가 도입 이래 조용히 no-op 였다. (2층인 하트비트 갭 감지 → SLEEP_INTERRUPTED 재라벨은 독립적으로 정상 동작해, 케이스 ①이 다룬 오탐 방어 자체엔 영향이 없었다 — 그래서 아무도 눈치채지 못했다.)
같은 날 확인·수정해 PR #66 으로 머지했다(merge commit 4837b2f, 2026-08-05 KST, +14/−1): 유효 상수로 교체 + PSB_TYPE 상수화(주석에 실측 근거) + 오타 회귀 방지 핀 테스트 1개 (sleep-guard 유닛 6 → 7). 검증은 코드 읽기가 아니라 실제 Electron 구동 실측(blocker 활성 true / 비활성 true)으로 했다.
이게 이 워크플로의 핵심을 압축한다 — 문서화(축②의 검증)가 감사(축⑤)를 강제했고, 감사가 도입 이래 숨어 있던 결함을 드러냈고, 적대적 확인(실 Electron 실측)으로 진짜임을 증명한 뒤, 규약(축①의 워크트리→PR→merge)대로 회귀 테스트까지 붙여 같은 날 닫았다. 다섯 축이 한 사건에서 모두 돌았다.
4. 결과 — 혼자, 그러나 혼자가 아니게
| 지표 | 값 | 근거 |
|---|---|---|
| 추적 소스 | ~9만 줄 (앱 코드 main+src ≈ 5.7만, +스크립트 1.3만·테스트 1.2만) | git ls-files + wc -l = 90,026 |
| 지원 쇼핑몰 | 77개 모듈 (활성 ~64) | main/shops/*.js |
| 커밋 · 기간 | 463 커밋 · ~4개월 (2026-04-09 → 08-05) | git log (main) |
| 유닛 테스트 | 1,082개 그린 (PR #66 후 1,083) | npx vitest run |
| 축적 메모리 | 66개 파일 | memory/*.md |
| 추적 파일 | 584개 | git ls-files |
숫자의 요점은 "많다"가 아니라, 한 사람이 이 규모를 회귀 없이 유지한다는 것이다. 그걸 가능하게 한 건 손이 빠른 게 아니라 — 규약을 코드로, 검증을 병렬로, 리뷰를 적대적으로, 기억을 파일로, 감사를 상시로 만든 워크플로다.
5. 배운 것
- AI-native 는 "AI 가 코드를 대신 짜는 것"이 아니다. 핵심은 검증을 확장하는 것이다 — 병렬 에이전트, 적대적 리뷰, 상시 감사로 "혼자 못 보는 것"을 보게 만든다. 생산이 아니라 신뢰가 병목이었다.
- 규약을 문서로 못박으면 실수가 재현되지 않는다.
CLAUDE.md의 샵별/공통 경계, git 위생, 프로세스 보호는 매번 같은 판단을 강제하는 집행 가능한 표준이 됐다. - 문서화가 최고의 감사다. 케이스 스터디를 쓰려고 코드를 인용 단위로 재검증하다 도입 이래 죽어 있던 버그(PR #66)를 잡았다. "설명할 수 있게 다시 보는 것"이 코드 리뷰보다 촘촘했다.
- 기억은 자산이자 부채다. 66개 메모리가 세션을 잇지만, 틀린 기억("25개 샵")은 오류를 전파한다 — 그래서 기억도 검증·교정 대상으로 다룬다(발견 즉시 현행 수치로 갱신).
- 혼자여도 "만든 사람 ≠ 검증하는 사람" 구조를 만들 수 있다. 그 분리를 AI 로 구현한 것이 이 1인 운영의 실체다. 그리고 그 구조가 흔들리면(축 하나라도 빠지면) 조용한 회귀가 돌아온다.
근거 (repo 대조)
| 주장 | 근거 | |
|---|---|---|
| 규모 9만 줄 / 77샵 / 463커밋 / 1,082테스트 / 66메모리 | `git ls-files\ | wc -l=90,026, main/shops/*.js=77, git log=463(2026-04-09~08-05), npx vitest run=1,082, memory/*.md`=66 |
| 규약을 코드로 | CLAUDE.md(샵별/공통 경계·git 위생·프로세스 보호·자기개선 루프), tasks/lessons.md | |
| 하루 4 STEP 머지 (2026-08-05) | PR #63 b23937a(하네스), #64 6875fbe(결함수정 95.5→100%), #65 e77ef03(에이전트) | |
| 적대적 리뷰 실사례 | STEP 1b 3렌즈(blocker/major 0·minor 3)·A/B 스윕 1,347건 의도 외 0; STEP 2 diff 리뷰 결함 3건 | |
| 문서 작성 중 버그 발견 → 당일 수정 | PR #66 merge 4837b2f(2026-08-05 KST, +14/−1); main/sleep-guard.js prevent_app_suspension→prevent-app-suspension, 회귀 테스트 6→7, 실 Electron 실측 | |
| 상시 감사 루프 | npm run eval:golden(골든셋 112) — 케이스 스터디 ③ | |
| 병렬 검증 오케스트레이션 | 이 시리즈 각 편 4-에이전트 병렬 repo 검증; 감사 독립 판독 에이전트 11개 |
초고 · 2026-08-05 KST. 공개 게시 전 개인정보·API 키 없음 확인.