[{"content":" 오늘 작업은 개발일지 자동 생성과 티스토리 자동 발행 파이프라인의 연동 결함을 바로잡고, 프로젝트 단위 분리 발행 체계를 구축하는 데 집중했다. 총 11건의 커밋으로 1,086줄의 코드를 추가하고 115줄을 정리했다. 발행 성공을 실패로 오진하거나 에디터에 본문이 제대로 입력되지 않던 티스토리 연동 결함을 수정을 거쳐 정상화했다. 필자와 검토자가 서로 다른 데이터를 바라보며 자동 일지가 매일 반송되던 파이프라인 불일치 문제도 원인을 찾아 해결했다. 프로젝트별 2단계 분류 로직 연동과 자본시장법 금지 표현 검증 확대, 다이어그램 자동 이미지 변환 기능까지 통합을 마쳤다.\n성공한 발행을 실패로 리포트하던 티스토리 연동 교정 티스토리 발행 과정에서는 외부 응답이 정상적으로 수신되어 발행이 완료되었음에도 파이프라인 내부에서 이를 실패 상태로 잘못 판정하는 오진 문제가 존재했다. 추가로 웹 에디터 연동 과정에서 일반적인 DOM 셀렉터 지정 방식으로 입력할 경우 본문 영역에 글이 채워지지 않고 빈 상태로 발행되는 현상이 함께 발견되었다. 웹 에디터 내부의 CodeMirror API를 직접 호출하여 텍스트를 주입하도록 방식을 교정했다. 단순한 외부 조작 대신 에디터 인스턴스 내부 API에 직접 접근함으로써 입력 누락 현상을 원천 방지하고 발행 결과도 올바르게 반환받도록 바꿨다.\n외부 알림이 실제 전달되지 않았음에도 발송 성공으로 표시되던 메시지 리포트 오류도 함께 바로잡았다. 알림 실패 상황을 성공으로 잘못 알리면 운영자가 자동화 파이프라인의 이상 유무를 즉시 인지하지 못하고 적절한 조치 타이밍을 놓치게 된다. 외부 서비스와의 실제 연동 결과와 알림 메시지 상태를 정확히 일치시켜 거짓 성공 리포트를 완전히 없앴다. 예외 상황 발생 시 실패 기록을 명확하게 보여주도록 바꿔 운영 파이프라인의 투명성과 신뢰도를 동시에 확보했다.\n검토자와 필자의 시각 차이로 발생하던 일지 반송 해소 자동 작성된 개발일지가 검토선에서 매일 F항목으로 반송되던 문제를 추적한 결과, 검토 스크립트와 작성 스크립트가 서로 다른 재료 데이터를 들여다보고 있었다. 검토 모듈이 최종 렌더링을 거치기 전의 원본 본문 데이터를 기준으로 평가를 수행했기 때문에 필자가 다듬은 본문과 검토 기준 사이에 불일치가 발생한 것이다. 검증 보고서가 최종 렌더링된 본문을 기준으로 작동하도록 검증선 구조를 통일했다. 작성자와 검토자가 동일한 산출물을 공유하도록 만들어 불필요한 반송 재작업을 차단했다.\n단순히 커밋 내역이 존재한다는 이유만으로 무조건 일지 작성을 시작하던 기존 제어 조건도 개선했다. 최소한의 작업 재료 수량과 필수 캡처 이미지, 설정된 문턱 조건을 통과했을 때만 작성 단계로 진입하도록 조건을 강화했다. 이와 함께 품질 검사 모듈의 글자 수 임계값을 기존 2,000자에서 300자로 조정했다. 분량 기준을 채우기 위해 억지로 내용을 부풀리기보다는, 작업량이 적더라도 변경의 구체적인 이유와 판단 근거를 담은 실질적인 기록을 남기는 것이 파이프라인 운영 목적에 부합한다고 판단한 결과다.\n프로젝트별 2단계 분류 체계 도입과 출력 검증 강화 하나의 글에 모든 작업 내역을 한데 묶어 출간하던 방식을 벗어나, 프로젝트별로 일지를 분할하고 요약형 제목을 적용하는 구조 개편을 단행했다. 단일 글에 여러 개 맥락이 무작위로 섞이면 읽는 입장에서 원하는 기술 정보를 찾아내기 어렵다는 단점이 컸다. 새롭게 도입한 2단계 분류 체계를 일지 생성기와 티스토리 발행 모듈에 연결하여, 각 프로젝트 맥락에 맞춰 독립된 글이 발행되도록 시스템을 정비했다.\n자본시장법상 금지 표현을 검증하는 검사 로직의 적용 범위를 확장했다. 기존에는 기본 본문 텍스트만 검사했으나 이번 개편으로 통계 템플릿 출력 경로까지 검사 대상에 포함시켰다. 혹시라도 일지 생성 과정 중 예외적인 경로에서 부적합한 표현이 포함되어 배포되는 상황을 철저히 차단하기 위한 결정이다. 더불어 문맥을 시각적으로 전달하기 위해 mermaid 다이어그램 구문이 포함되면 발행 전 자동으로 PNG 이미지로 구워내는 변환 처리도 붙였다. 텍스트 위주의 설명에 시각적 도표 요소를 보완하여 전달력을 끌어올렸다.\n남은 과제 프로젝트별 분리 발행과 에디터 연동 오류 수정은 완료했으나, 새로 추가한 mermaid PNG 이미지 렌더링 과정에서 처리 시간이 늘어날 경우 전체 파이프라인의 타임아웃으로 이어지지 않는지 모니터링이 더 필요하다. 품질 검사 임계값을 300자로 낮춘 설정이 향후 다양한 작업량 변화 속에서 의도대로 작동하는지도 실제 발행 데이터를 쌓으며 계속 관찰할 계획이다.\n2026-08-08 · 개발일지 파이프라인 · 커밋 12건 (+1175/-141)\n이 글은 그날의 커밋 기록을 바탕으로 자동 생성·발행되었다.\n","permalink":"https://liquidation-man.github.io/posts/devlog-2026-08-08-devlog/","summary":"\u003c!--\n[사후 검수 체크리스트 — 발행 통지를 받으면 확인]\n- [ ] 고객 실명·주문번호·금액 등 민감정보 없음 (있으면 즉시 revert + denylist 등록)\n- [ ] 사업 전략·수익 목표 노출 없음\n자동 발행본 (PORTFOLIO §3-7 개발일지 예외). 문제 시 blog 리포에서 revert.\n--\u003e\n\u003cp\u003e오늘 작업은 개발일지 자동 생성과 티스토리 자동 발행 파이프라인의 연동 결함을 바로잡고, 프로젝트 단위 분리 발행 체계를 구축하는 데 집중했다. 총 11건의 커밋으로 1,086줄의 코드를 추가하고 115줄을 정리했다. 발행 성공을 실패로 오진하거나 에디터에 본문이 제대로 입력되지 않던 티스토리 연동 결함을 수정을 거쳐 정상화했다. 필자와 검토자가 서로 다른 데이터를 바라보며 자동 일지가 매일 반송되던 파이프라인 불일치 문제도 원인을 찾아 해결했다. 프로젝트별 2단계 분류 로직 연동과 자본시장법 금지 표현 검증 확대, 다이어그램 자동 이미지 변환 기능까지 통합을 마쳤다.\u003c/p\u003e","title":"개발일지 파이프라인 — 성공한 발행을 실패로 리포트하던 티스토리 연동 교정"},{"content":" 이 글은 2026-08-08(KST) 하루 동안 여러 저장소에 남긴 커밋을 GitHub Actions가 긁어모아 자동 발행한 개발일지다.\n트레이딩 봇 — 커밋 28건, +45844/-256 비공개 저장소라 작업 내역은 싣지 않는다. 이날 커밋 28건, 45844줄 추가 / 256줄 삭제.\n연금 리밸런싱 — 커밋 11건, +6267/-195 비공개 저장소라 작업 내역은 싣지 않는다. 이날 커밋 11건, 6267줄 추가 / 195줄 삭제.\n라이더 로그 — 커밋 4건, +1039/-23 비공개 저장소라 작업 내역은 싣지 않는다. 이날 커밋 4건, 1039줄 추가 / 23줄 삭제.\n기획 — 커밋 13건, +5167/-532 비공개 저장소라 작업 내역은 싣지 않는다. 이날 커밋 13건, 5167줄 추가 / 532줄 삭제.\n부업 자동화 — 커밋 9건, +2357/-108 비공개 저장소라 작업 내역은 싣지 않는다. 이날 커밋 9건, 2357줄 추가 / 108줄 삭제.\n운영·용역 — 커밋 16건, +6575/-3574 비공개 저장소라 작업 내역은 싣지 않는다. 이날 커밋 16건, 6575줄 추가 / 3574줄 삭제.\n블로그 — 커밋 7건, +432/-133 0ea071a 사람이 쓴 글 한 편 — 14초 만에 성공한 실행이 아무것도 안 했다 (+98/-0) 2147d56 GA4 측정 ID 를 넣는다 — 측정도 켜졌다 (+3/-1) ffc1623 서치콘솔 소유 확인 태그를 넣는다 — 색인이 0이던 직접 원인 (+5/-1) 5e79d77 ads.txt 가 있지도 않은 자동 생성을 약속하고 있었다 (+15/-4) cc614fb 분류를 2단계로 바꾼다 — 카테고리(큰 묶음) \u0026gt; 시리즈(프로젝트) (+126/-92) 0621458 없는 상품명을 광고하고 있었다 — 실물에 맞추고 검사 범위를 넓힌다 (+33/-10) 90ef106 글을 프로젝트별로 재배치하고 제목을 간결하게 고친다 (+152/-25) 이 글은 커밋 메타데이터만으로 자동 생성·발행되었다. 맥락 서술이 필요한 항목은 사후에 사람이 보강한다.\n","permalink":"https://liquidation-man.github.io/posts/devlog-2026-08-08-summary/","summary":"\u003c!--\n[사후 검수 체크리스트 — 발행 통지를 받으면 확인]\n- [ ] 고객 실명·주문번호·금액 등 민감정보 없음 (있으면 즉시 revert + denylist 등록)\n- [ ] 사업 전략·수익 목표 노출 없음\n자동 발행본 (PORTFOLIO §3-7 개발일지 예외). 문제 시 blog 리포에서 revert.\n--\u003e\n\u003cp\u003e이 글은 2026-08-08(KST) 하루 동안 여러 저장소에 남긴 커밋을 GitHub Actions가 긁어모아 자동 발행한 개발일지다.\u003c/p\u003e","title":"진행 요약 — 프로젝트 7곳, 커밋 88건"},{"content":"이 블로그는 밤에 사람 없이 글을 낸다. 여러 저장소의 그날 커밋을 긁어 서술로 바꾸고, 검수를 통과하면 발행한다. 며칠 껐다가 다시 켰고, 다음 날 아침에 확인했는데 새 글이 없었다.\n실패 알림은 안 왔다. 실행 기록을 열어 보니 초록색이었다. 소요 시간이 14초.\n처음엔 게이트를 의심했다 이 파이프라인은 검수 게이트가 여러 겹이라, 뭔가 걸려서 발행이 막혔겠거니 했다. 차단되면 알림이 오게 해 뒀지만 그 알림 경로가 죽었을 수도 있으니까. 게이트 로그부터 봤는데 아예 실행된 적이 없었다. 그 앞 단계에서 이미 끝나 있었다.\n로그를 위로 올리니 두 줄이었다.\n수집 대상: 2026-08-08 (KST) = 2026-08-07T15:00:00Z ~ 2026-08-08T15:00:00Z (UTC) 그날 커밋 없음 — 글은 만들지 않는다. 커밋이 없다니. 그날 작업을 한참 했는데.\n두 번째 헛다리를 여기서 짚었다. 저장소 접근 권한이 빠졌나 싶었다. 실제로 같은 로그에 저장소 하나가 404로 건너뛴 흔적이 있어서 한동안 그쪽을 팠다. 그건 맞는 문제였지만 이 문제는 아니었다.\n수집 대상 날짜를 다시 봤다. 8월 8일. 예약은 8월 7일 밤 11시 30분이다.\n하루가 26분밖에 안 지났다 예약 시각은 23시 30분인데, 실제로 실행이 시작된 시각은 자정을 26분 넘긴 뒤였다. 56분이 밀렸다. GitHub 은 예약 작업을 정시에 띄워 준다고 보장하지 않는다. 문서에도 그렇게 적혀 있고, 알고는 있었다.\n문제는 날짜를 실행 시각에서 가져오고 있었다는 것이다. 자정을 넘겼으니 대상이 어제가 아니라 시작한 지 26분 된 오늘이 됐다. 26분 동안 커밋이 없는 건 당연하고, 파이프라인은 규칙대로 \u0026ldquo;쓸 게 없으니 안 쓴다\u0026quot;고 판단했다.\n아무것도 고장나지 않았다. 코드는 시킨 대로 했다. 23시 30분에 돌 거라는 전제 하나만 틀렸고, 그 전제는 코드 어디에도 안 적혀 있었다.\n23시 30분 예약은 지연 여유가 30분이다. 한 번 밀린 게 아니라 앞으로도 밀릴 구조였다.\n두 곳을 같이 고쳤다. 예약을 새벽 1시로 옮기고, 대상을 이미 끝난 어제로 바꿨다. 이제 몇 시간이 밀려도 대상은 안 변한다. 하는 김에 23시 30분부터 자정 사이 커밋도 담기게 됐다 — 전에는 매일 그 30분이 통째로 빠지고 있었는데, 이건 이번에 알았다.\n고쳤더니 다음 게 나왔다 날짜를 고치니 글은 만들어지는데 매번 통계 표로 떨어졌다. 서술을 쓰는 모델은 멀쩡히 돌았고, 그걸 다른 모델이 검수한 뒤 반송하고 있었다. 사유가 늘 같았다.\n판정: REJECT - (F) \u0026#34;+278줄을 늘리고 -58줄을 줄였다\u0026#34; → 제공된 재료에서 찾을 수 없는 숫자임 지어낸 수치를 막는 항목이다. 자동 생성 글에서 제일 위험한 게 원본에 없는 숫자를 만들어 내는 일이라 넣어 둔 규칙이고, 이건 제 일을 한 것처럼 보였다. 모델이 또 헛소리를 하는구나 싶었다. 세 번째 헛다리다.\n필자 쪽 프롬프트를 열어 보니 그 숫자가 있었다. 커밋마다 - 메시지 (+278/-58) 형태로 들어가 있다. 모델은 받은 걸 그대로 썼다.\n검수 쪽 프롬프트에는 커밋 제목만 있었다. 숫자가 없다. 필자에게 준 재료를 검수자에게 안 준 것이다. 검수자 입장에서는 정말로 재료에 없는 숫자였고, 판정은 정확했다.\n그 함수 주석에 이렇게 적혀 있었다.\n판정 기준이 재료라면 재료를 다 보여줘야 한다.\n같은 사유의 반송이 그날만 세 번이었다. 세 번 다 이 한 줄 때문이었고, 원칙은 이미 문서에 적혀 있었는데 구현이 반만 따르고 있었다. 이런 게 제일 안 보인다. 규칙이 없어서 생긴 구멍은 규칙을 읽으면 보이는데, 규칙은 있고 구현이 반쪽인 건 양쪽을 나란히 놓고 봐야 보인다.\n아직 모르는 것 고치고 나서 며칠 돌려 봐야 안다. 지연이 몇 시간까지 나는지 실제 분포를 모른다. 한 번 56분을 봤을 뿐이고, 그게 평범한 편차인지 이상한 날이었는지 표본이 하나다. 지금 구조는 몇 시간이 밀려도 버티게 해 뒀지만, 그건 대응이지 이해가 아니다.\n날짜 때문에 하루를 통째로 건너뛴 게 이번이 처음인지도 모른다. 그전 기록을 뒤지면 알 수 있을 텐데 아직 안 봤다.\n지금은 종료 코드를 덜 믿는다. 이 두 건 다 exit 0 이었다. 실패 알림이 안 왔다는 건 성공했다는 뜻이 아니라 아무 일도 안 일어났다는 뜻일 수 있다는 걸 이번에 알았다. 그래서 요즘은 로그에서 뭐가 있는지보다 뭐가 없는지를 먼저 본다.\n","permalink":"https://liquidation-man.github.io/posts/green-but-failing/","summary":"\u003cp\u003e이 블로그는 밤에 사람 없이 글을 낸다. 여러 저장소의 그날 커밋을 긁어 서술로 바꾸고,\n검수를 통과하면 발행한다. 며칠 껐다가 다시 켰고, 다음 날 아침에 확인했는데 새 글이\n없었다.\u003c/p\u003e","title":"개발일지 파이프라인 — 14초 만에 성공한 실행이 아무것도 안 했다"},{"content":" 이 글은 2026-08-08(KST) 하루 동안 여러 저장소에 남긴 커밋을 GitHub Actions가 긁어모아 자동 발행한 개발일지다.\n트레이딩 봇 — 커밋 11건, +43391/-48 비공개 저장소라 작업 내역은 싣지 않는다. 이날 커밋 11건, 43391줄 추가 / 48줄 삭제.\n연금 리밸런싱 — 커밋 11건, +6267/-195 비공개 저장소라 작업 내역은 싣지 않는다. 이날 커밋 11건, 6267줄 추가 / 195줄 삭제.\n라이더 로그 — 커밋 1건, +56/-0 비공개 저장소라 작업 내역은 싣지 않는다. 이날 커밋 1건, 56줄 추가 / 0줄 삭제.\n기획 — 커밋 6건, +3788/-46 비공개 저장소라 작업 내역은 싣지 않는다. 이날 커밋 6건, 3788줄 추가 / 46줄 삭제.\n개발일지 파이프라인 — 커밋 3건, +255/-30 b44c49d 알림이 안 올라간 곳을 올라갔다고 말하고 있었다 (+47/-4) 60e351b feat(devlog): 자본시장법 금지 표현을 통계 템플릿 경로에서도 막는다 (+119/-0) 이 밖에 커밋 1건은 제목을 싣지 않는다. 부업 자동화 — 커밋 1건, +379/-13 비공개 저장소라 작업 내역은 싣지 않는다. 이날 커밋 1건, 379줄 추가 / 13줄 삭제.\n운영·용역 — 커밋 6건, +2242/-27 비공개 저장소라 작업 내역은 싣지 않는다. 이날 커밋 6건, 2242줄 추가 / 27줄 삭제.\n블로그 — 커밋 2건, +185/-35 0621458 없는 상품명을 광고하고 있었다 — 실물에 맞추고 검사 범위를 넓힌다 (+33/-10) 90ef106 글을 프로젝트별로 재배치하고 제목을 간결하게 고친다 (+152/-25) 이 글은 커밋 메타데이터만으로 자동 생성·발행되었다. 맥락 서술이 필요한 항목은 사후에 사람이 보강한다.\n","permalink":"https://liquidation-man.github.io/posts/devlog-2026-08-08/","summary":"\u003c!--\n[사후 검수 체크리스트 — 발행 통지를 받으면 확인]\n- [ ] 고객 실명·주문번호·금액 등 민감정보 없음 (있으면 즉시 revert + denylist 등록)\n- [ ] 사업 전략·수익 목표 노출 없음\n자동 발행본 (PORTFOLIO §3-7 개발일지 예외). 문제 시 blog 리포에서 revert.\n--\u003e\n\u003cp\u003e이 글은 2026-08-08(KST) 하루 동안 여러 저장소에 남긴 커밋을 GitHub Actions가 긁어모아 자동 발행한 개발일지다.\u003c/p\u003e","title":"개발일지 2026-08-08 — 커밋 41건, +56563/-394"},{"content":" 이 글은 2026-08-07(KST) 하루 동안 여러 저장소에 남긴 커밋을 GitHub Actions가 긁어모아 자동 발행한 개발일지다.\n자동 개발일지 파이프라인의 검토 오류를 수정하고 발행 전 차단 게이트를 강화하여 글이 잘못 출력되거나 불필요한 내용이 들어가지 않도록 자동화 흐름을 개편했다. 검토자가 판정 기준 예시를 실제 원고로 오인하거나 작성 주체 모델이 스스로 판정 표를 던지는 현상을 통제하는 한편, 글 하단 유료 안내 및 경로 연결 작업을 정비해 파이프라인의 입출력 제어를 마무리했다.\n검토 모델이 스스로를 심사하거나 예시 문장을 원고로 착각하던 문제를 고쳤다 자동 글쓰기 파이프라인에서 원고 작성에 참여한 모델이 검토 단계의 투표 후보로 들어가 스스로 작성한 글에 표를 던지는 구조적 결함이 있었다. 자기 평가가 개입되면 검토 객관성이 깨지기 때문에 작성에 관여한 모델을 검토 후보군에서 아예 배제하도록 바꿨다. 또한 검토자가 판정 가이드라인에 적힌 예시 문장을 실제 원고 내용으로 오해하여 정상 원고를 반송하는 일도 발생했다. 가이드라인 문맥과 원고 본문을 명확히 분리하고 검토자의 응답 상한 시간과 빈 응답 처리 기준을 다시 정립해 판정 실패율을 낮췄다.\n검토 후보에서 작성 모델을 제거하면 이용 가능한 검토 모델 수가 줄어들어 검토 병목이 발생할 수 있으나, 편향된 판정으로 잘못된 글이 통과되는 것보다는 검토 대기 시간을 약간 감수하는 편이 낫다고 판단했다. 2026-08-07 기준 네 번의 실행 표본 데이터를 기록하면서 모델 등급별 판정 동작을 확인했으며, 빈 응답이나 시간 초과가 발생했을 때 재검토 로직이 동작하도록 신뢰성을 보강했다. 결과적으로 판정 기준 예시 오인으로 인한 억울한 반송이 사라졌고 검토 단계의 판정 정확도가 올라갔다.\n발행 후 검사에 의존하던 방식을 발행 전 차단 구조로 바꿨다 이전에는 글이 발행된 이후에 사후 검사로 특정 내용의 포함 여부를 확인했으나, 이미 출력된 후에는 수습에 비용이 많이 들었다. 이를 개선하기 위해 전자책 내용이나 원고 제한 대상이 파이프라인을 거쳐 자동으로 출력되기 전에 사전에 검사하고 차단하는 게이트 세 곳을 새로 조였다. 개발일지 파이프라인과 블로그 출력 양쪽에 걸쳐 차단 로직을 구현했으며, 두 층의 검사 구조를 문서화하여 발행 단계에 진입하기 전 차단이 완결되도록 바꿨다.\n사전 차단 게이트를 촘촘하게 설정하면 검사 과정에서 정당한 개발 기록까지 과도하게 걸러질 위험이 존재한다. 그러나 불필요한 정보가 외부에 출력되는 위험을 감수하는 것보다는 일부 문장이 과차단되어 수정 요청으로 돌아오는 트레이드오프가 훨씬 안전하다. 사전 차단 게이트와 함께 스케줄러를 재가동하고 글 하단 안내 연결과 경로 및 훅 수정을 정비하여, 검증을 통과한 원고만 블로그 하단 안내와 함께 자동으로 처리되도록 전체 파이프라인의 동작을 조정했다.\n검토자의 판정 기준 오인 문제와 발행 전 사전 차단 게이트 구축은 완료했으나, 검토 후보 모델 수를 줄임에 따라 특정 시간대에 검토 대기가 길어지는 현상이 남아있다. 모델 등급별 시간 상한과 빈 응답 처리가 실전 데이터에서 안정적으로 작동하는지 추가 표본을 수집하여 검증할 예정이다.\n프로젝트별 진행 프로젝트 커밋 변경 트레이딩 봇 30건 +29240/-339 라이더 로그 4건 +3303/-181 기획 2건 +43/-11 개발일지 파이프라인 6건 +913/-72 부업 자동화 1건 +552/-0 운영·용역 1건 +146/-3 블로그 4건 +308/-13 이 글은 그날의 커밋 기록을 바탕으로 자동 생성·발행되었다.\n","permalink":"https://liquidation-man.github.io/posts/devlog-2026-08-07/","summary":"\u003c!--\n[사후 검수 체크리스트 — 발행 통지를 받으면 확인]\n- [ ] 고객 실명·주문번호·금액 등 민감정보 없음 (있으면 즉시 revert + denylist 등록)\n- [ ] 사업 전략·수익 목표 노출 없음\n자동 발행본 (PORTFOLIO §3-7 개발일지 예외). 문제 시 blog 리포에서 revert.\n--\u003e\n\u003cp\u003e이 글은 2026-08-07(KST) 하루 동안 여러 저장소에 남긴 커밋을 GitHub Actions가 긁어모아 자동 발행한 개발일지다.\u003c/p\u003e","title":"개발일지 2026-08-07 — 커밋 48건, +34505/-619"},{"content":"디버그 빌드에서는 홈, 입력, 통계, 백업까지 전부 정상이었다. 그런데 release AAB로 뽑아서 실제 기기에 올리자 스플래시 직후에 앱이 사라졌다. 코드 변경은 cargo-log/lib/core/app_config.dart에서 AdMob 테스트 광고 ID를 실제 ID로 바꾼 것(+17/-11)과 AndroidManifest.xml 두 줄(+2/-3)이 전부였다. 기능 커밋이 아니라 문자열 교체 커밋 하나에서 릴리스만 죽은 셈이다.\n오늘 하루 커밋은 44개, 변경량은 +35523/-1367줄이었다. 그중 마지막 커밋 1f5dbd7의 diff는 cargo-log/android/app/build.gradle.kts 한 파일, +4/-1줄이다. 네 줄을 찾는 데 걸린 시간이 앱 하나를 M1부터 M6까지 만드는 시간과 비슷했다.\nrelease 빌드만 죽은 이유 증상부터 정리하면 이렇다.\n구분 debug release 앱 실행 정상 스플래시 직후 종료 배너 광고 테스트 광고 표시 확인 불가(그 전에 종료) 코드 차이 없음 없음 빌드 파이프라인 차이 축소/난독화 없음 R8 축소 동작 코드가 같은데 결과가 다르면 범인은 코드가 아니라 빌드 파이프라인이다. Flutter 안드로이드 릴리스 빌드는 R8이 붙어서 참조되지 않아 보이는 클래스를 지운다. 문제는 google_mobile_ads와 androidx.work처럼 리플렉션이나 매니페스트 등록으로만 참조되는 클래스다. 정적 분석 입장에서는 아무도 안 부르는 코드라 지워도 되는 것처럼 보이고, 실제로 지워지면 런타임에 초기화 단계에서 바로 넘어진다.\n선택지는 두 가지였다. 하나는 keep 규칙을 하나씩 써서 필요한 클래스만 살리는 방법, 다른 하나는 축소 자체를 끄는 방법이다.\n// android/app/build.gradle.kts — release 블록 buildTypes { release { // R8이 google_mobile_ads / androidx.work 클래스를 스트립해서 // 릴리스에서만 죽는 문제. 우선 축소를 끈다. isMinifyEnabled = false isShrinkResources = false } } 이 네 줄을 넣자 release AAB가 정상 실행됐다. 대신 APK 크기 이득을 포기했다. 지금 단계에서는 \u0026ldquo;출시할 수 있는 앱\u0026quot;이 \u0026ldquo;작은 앱\u0026quot;보다 먼저라고 판단했다. proguard keep 규칙은 어떤 클래스가 왜 필요한지 정확히 알아야 최소한으로 쓸 수 있는데, 그걸 알아내려면 다시 릴리스 빌드를 반복해야 한다. 축소를 끄는 쪽이 원인과 결과가 명확하고 되돌리기도 쉽다.\n테스트 광고 ID에서 실제 ID로 바꾼 커밋이 방아쇠였다 크래시가 처음 보인 시점은 28f41b8, AdMob 실제 광고 ID를 넣은 직후다. 그래서 처음에는 광고 ID를 의심했다. 잘못된 앱 ID를 매니페스트에 넣으면 SDK 초기화에서 죽는 사례가 흔하기 때문이다.\n의심을 접은 근거는 debug 빌드였다. 같은 실제 ID로 debug를 돌리면 앱이 죽지 않았다. ID가 틀렸다면 빌드 타입과 무관하게 죽어야 한다. 그러니 ID 자체가 아니라 \u0026ldquo;실제 ID를 넣은 뒤 처음으로 release 빌드를 뽑아봤다\u0026quot;는 사실이 진짜 순서였다. 광고 ID 교체가 원인이 아니라, 그 커밋이 릴리스 빌드를 처음 실행하게 만든 계기였을 뿐이다.\n이 구분을 못 했으면 app_config.dart를 계속 들여다봤을 것이다. 증상이 나타난 커밋과 원인을 만든 커밋이 다르다는 건 자주 겪는 함정이다.\n화물기사 장부앱을 M1에서 M6까지 cargo-log는 오늘 처음 만들어진 프로젝트다. 커밋 순서대로 M1부터 M6까지 진행했다.\n각 단계에서 무엇을 먼저 세웠는지가 중요했다.\nM1 (c8b3068) 은 뼈대다. .gitignore(+45), analysis_options.yaml(+28), android/app/build.gradle.kts(+45), AndroidManifest.xml(+45)까지 프로젝트 설정과 화물 데이터모델, DB, 계산 로직을 한 번에 깔았다. 화면은 아직 없다.\nM2 (a8ab92a) 에서 홈과 운송·지출 입력을 붙였다. 커밋 메시지에 적어둔 판단이 이 앱의 성격을 결정한다. \u0026ldquo;GPS 없이 장부로 성립\u0026rdquo;. 즉 GPS 권한을 거부한 사용자도 앱을 그냥 장부로 쓸 수 있어야 한다는 뜻이다. lib/app.dart(+81), lib/app_providers.dart(+67), lib/core/theme.dart(+45), lib/data/repositories/client_repository.dart(+32)가 이때 들어갔다. 브랜드명도 여기서 \u0026ldquo;운행로그\u0026quot;로 정했다.\nM3 (0f05bbb) 에서 GPS를 얹었다. lib/data/models/trip.dart가 +140줄, lib/data/repositories/trip_repository.dart가 +119줄이다. 상차와 하차 지점을 경로로 잇고 타임라인에 표시하는데, 지도는 처음부터 OSM으로 갔다.\nM4 (a08b542) 는 통계와 종합소득세 경비 리포트다. lib/features/stats/stats_screen.dart(+237), stats_providers.dart(+95). 화물·용달 기사에게 필요한 건 \u0026ldquo;이번 달 얼마 벌었나\u0026quot;보다 \u0026ldquo;수수료랑 유류비 빼고 실제로 손에 남은 게 얼마고, 세금 낼 때 경비로 뭘 넣을 수 있나\u0026quot;다. 출처별 실수취를 따로 뽑는 이유가 그것이다.\nM5 (381f577) 에서 온보딩(onboarding_screen.dart +62), 설정(settings_screen.dart +219), 백업(backup_service.dart +128)을 붙여 앱 형태를 완성했다. test/ledger_csv_test.dart(+28)로 CSV 내보내기를 테스트로 묶었다.\nM6 (b6c10e0) 이 수익화 배선이다. lib/features/ads/banner_ad.dart(+63), lib/core/app_config.dart(+18), pubspec.lock(+40). 그리고 이 배선이 위에서 말한 R8 문제로 이어졌다.\nM1부터 M6까지 순서를 이렇게 잡은 이유는 하나다. 앱이 매 단계 끝에서 실행 가능한 상태로 남게 하려고 했다. M2가 끝난 시점에 이미 \u0026ldquo;GPS 없는 수동 장부앱\u0026quot;으로 쓸 수 있고, M4가 끝난 시점에 \u0026ldquo;통계까지 되는 장부앱\u0026quot;이 된다. 중간에 멈춰도 버릴 게 없다.\nGPS 코드를 앱 밖으로 뺀 이유 d74510c 커밋에서 packages/core_gps라는 별도 패키지를 만들었다. lib/src/trip_tracker.dart(+83), lib/src/geo.dart(+18), lib/core_gps.dart(+5), 그리고 test/core_gps_test.dart(+77)다. 테스트가 구현부보다 긴 구조다.\n동기는 단순하다. rider-log(배달 라이더)와 cargo-log(화물·용달)는 화면과 용어가 다르지만, \u0026ldquo;위치를 주기적으로 받아서 이동 거리를 누적한다\u0026quot;는 부분은 똑같다. 이 계산을 각 앱에 복사해 두면 좌표 필터링 기준을 한 번 바꿀 때마다 두 군데를 고쳐야 한다.\n거리 계산과 트립 누적은 부작용이 없는 순수 계산이라 테스트하기 쉽다. 그래서 이 부분만 떼어내면 앱 UI를 띄우지 않고도 검증할 수 있다. core_gps_test.dart가 +77줄이 된 게 그 결과다. 반대로 권한 요청이나 백그라운드 실행처럼 플랫폼에 붙는 부분은 앱 쪽에 남겼다. 그건 패키지로 빼도 테스트가 쉬워지지 않는다.\n유가 API가 죽어도 앱은 살아 있어야 한다 rider-log 쪽 오늘 작업 중 제일 손이 많이 간 건 유가 연동이다.\n3a929bd에서 오피넷 유가 자동 연동을 넣었다. lib/features/fuel/opinet_service.dart(+73), test/opinet_service_test.dart(+32), lib/core/app_config.dart(+7). 커밋 메시지에 \u0026ldquo;그레이스풀 폴백\u0026quot;이라고 적어둔 게 핵심이다. 외부 API는 언제든 응답이 없거나 형식이 바뀐다. 그때 앱이 예외를 던지고 죽으면 사용자는 유가와 아무 상관 없는 화면에서 앱이 종료되는 경험을 한다.\n그래서 3381a66에서 한 겹을 더 씌웠다. lib/features/fuel/fuel_price_updater.dart(+25)와 test/fuel_price_updater_test.dart(+62)를 추가하고, 갱신 실패 시 마지막으로 받아온 값을 그대로 유지하도록 했다. 갱신 시각도 함께 저장한다. 여기서도 테스트가 구현보다 길다. 실패 경로가 성공 경로보다 종류가 많기 때문이다.\n상황 처리 API 정상 응답 새 유가 저장 + 갱신 시각 갱신 네트워크 실패 마지막 값 유지, 화면 그대로 응답 형식 이상 마지막 값 유지 저장된 값도 없음 사용자가 설정에서 직접 입력 7ec6754에서는 앱 시작 시 유가를 fire-and-forget으로 갱신하게 했다. lib/main.dart +11/-1줄. 갱신 결과를 기다리지 않고 화면을 먼저 띄운다. 유가 하나 때문에 첫 화면이 늦게 뜨는 건 손해가 명백하다.\n에러 문구를 사람 말로 바꿨다 ad3d8f4는 \u0026ldquo;오류방지 감사\u0026quot;라는 이름을 붙인 커밋이다. lib/core/friendly_error.dart(+36)를 만들고, 입력 화면, 설정 화면, 통계 화면, 타임라인, 월 캘린더에 각각 한두 줄씩 연결했다.\n바꾼 건 두 가지다. 첫째, 예외 메시지를 그대로 토스트에 띄우던 자리를 사람이 읽을 수 있는 문장으로 교체했다. 둘째, 숫자 파싱을 하드닝했다. 사용자가 금액 칸에 쉼표나 공백을 섞어 넣는 건 예외 상황이 아니라 기본값에 가깝다.\n이 앱의 사용자는 배달과 화물 일을 하는 기사다. 화면에 알 수 없는 영문 예외가 뜨면 앱을 지운다. 앱이 죽지 않는 것과 사용자가 당황하지 않는 것은 다른 문제다. 전자는 try-catch로 끝나지만 후자는 문구까지 손봐야 한다.\nOCR 파서를 미션과 운행거리까지 f61a112에서 lib/features/ocr/receipt_parser.dart를 +71/-3줄 고치고 test/receipt_parser_test.dart(+27)를 늘렸다. 배달 앱 정산 화면 스크린샷에서 금액만 뽑던 것을, 미션 수행 여부와 플랫폼 종류, 운행거리까지 뽑도록 확장했다.\n플랫폼 감지가 들어간 이유는 그 다음 커밋을 보면 드러난다. 8e6e336에서 입력폼을 개편하면서(input_screen.dart +78/-11) 플랫폼을 자동 선택하고 자동 지출과 연동했다. 스크린샷 한 장을 넣으면 플랫폼, 금액, 거리, 미션이 자동으로 채워지고, 거리로부터 기름값이 자동 계산되는 흐름이다.\n자동 지출 계산은 d1733b0에 있다. lib/features/expense/auto_expense_service.dart(+69), test/auto_expense_test.dart(+95), lib/features/tax/tax_estimator.dart(+16/-3), lib/core/settings_store.dart(+30). 기름값과 식비를 자동으로 잡아 세금 추정까지 밀어 넣는다. 여기도 테스트가 구현보다 길다. 세금 계산은 틀렸을 때 사용자가 확인할 방법이 없어서 테스트로 고정해두는 편이 낫다.\n홈 화면을 순수익 하나로 정리 4118b44에서 홈 화면을 갈아엎었다. lib/app_providers.dart(+95)와 화면 파일(+166/-35)이 함께 움직였다. 바꾼 방향은 이렇다.\n헤드라인을 매출이 아니라 월 순수익으로 바꿨다. 기사에게 의미 있는 숫자는 들어온 돈이 아니라 남은 돈이다. 진도 배지를 넣었다. 이번 달 목표 대비 어디까지 왔는지를 숫자 대신 배지로 보여준다. 지난달 같은 시점과 비교를 붙였다. 절대값보다 방향이 더 빨리 읽힌다. 4e8a548에서는 월 캘린더에 수익 히트맵을 넣었다. lib/features/timeline/month_calendar.dart +14/-1줄. 많이 번 날일수록 셀 색이 진해진다. 14줄짜리 변경인데 화면 인상이 제일 크게 바뀐 작업이었다. 숫자를 읽지 않아도 이번 달 리듬이 보인다.\n10d406b에서 장부 CSV 내보내기를 붙였다(backup_service.dart +63, settings_screen.dart +7/-1, test/ledger_csv_test.dart +34). 세무 자료를 요구받았을 때 엑셀로 넘길 수 있어야 한다는 요구를 그대로 반영했다.\n7338838에서는 설정 화면에 자동입력과 목표 섹션을 추가했다(+160). 자동 계산이 늘어날수록 \u0026ldquo;무엇을 자동으로 할지\u0026rdquo; 끄고 켜는 자리가 필요해진다.\n지도를 OSM으로 바꾸고 릴리스 준비물을 만들었다 73d5353은 rider-log 쪽 큰 정리 커밋이다. 크래시 수정, 지도 OSM 전환, 미션 필드 추가와 DB 마이그레이션이 한 번에 들어갔다. android/app/build.gradle.kts(+13/-1), AndroidManifest.xml(+1/-5), 런처 아이콘 이미지 여러 해상도가 함께 바뀌었다.\n지도를 OSM으로 정한 이유는 비용과 키 관리다. 상용 지도 SDK는 API 키를 앱에 넣고 사용량에 따라 과금된다. 개인 부업 앱에서 사용량이 얼마나 튈지 모르는 상태로 과금 API를 넣는 건 위험이 크다. OSM은 키 없이 붙고, 나중에 타일 서버를 바꿔도 코드 구조가 그대로다.\n같은 커밋에 문서 두 개가 들어갔다. CLOSED-TESTING-GUIDE.md(+63)와 RELEASE-CHECKLIST.md(+66)다. 스토어 비공개 테스트를 돌리려면 매번 같은 절차를 밟아야 하는데, 그걸 머리로 기억하면 반드시 빠뜨린다. 릴리스 AAB 빌드 검증까지 마친 스냅샷을 d74510c에 남겼다.\n개발일지를 사람 없이 발행하는 파이프라인 df8a47a에서 dev-blog 프로젝트를 git에 편입했다. 이 글 자체를 만드는 파이프라인이다.\n주요 파일은 autoblog/collector.py(+408), autoblog/coordinator.py(+114), autoblog/config.py(+92), README.md(+164), CLAUDE.md(+45)다. assets/mermaid.min.js(+2024)도 함께 들어갔는데, 티스토리는 mermaid 코드블록을 렌더하지 못해서 다이어그램을 PNG로 미리 그려 넣어야 하기 때문이다.\n수집기가 가장 큰 이유는 입력이 지저분해서다. 여러 저장소의 커밋을 날짜로 모으고, 파일별 증감을 세고, 자동 커밋과 사람 커밋을 구분하고, diff에서 본문에 쓸 만한 조각만 남긴다. 여기서 한 번 잘못 걸러내면 뒤 단계가 전부 헛돈다.\n무인 발행에서 제일 무서운 건 개인정보다. 사람 검수가 없으니 마스킹이 뚫리면 그대로 공개된다. 그래서 발행 직전에 누출 검사를 두고, 한 건이라도 걸리면 push를 중단하는 fail-closed 구조로 잡았다. 통과해야 나가는 게 아니라, 확신이 없으면 멈추는 쪽이 기본값이다.\n정규식 마스킹의 한계도 그대로 인정했다. 라벨 없이 등장하는 한국어 실명은 패턴으로 못 잡는다. 그래서 실명 같은 항목은 설정의 차단 목록에 직접 넣어두는 방식으로 처리한다. 자동으로 잡히는 척하는 것보다, 못 잡는다고 적어두고 사람이 목록을 채우는 편이 안전하다.\n폰 버튼으로 승인하는 워커 5547ccd에서 원격 승인 파이프라인 2단계 워커를 만들었다. remote-approval/mailbox.py(+142), config.py(+56), actions.py(+47), integrity.py(+17), README.md(+59), 설계 문서 REMOTE-APPROVAL-DESIGN.md(+104), 그리고 승인 대기 원장 APPROVALS-PENDING.md(+63)다.\n문제 상황은 이랬다. 자동화가 밤에 돌다가 사람 승인이 필요한 지점에 걸리면, 아침까지 아무것도 진행되지 않는다. 그렇다고 폰에서 임의 명령을 실행할 수 있게 열어두면 승인 게이트를 만든 의미가 없어진다.\n절충안이 메일박스 구조다. 폰에서는 미리 정의된 승인 항목에 \u0026ldquo;예/아니오\u0026quot;만 남긴다. 실행은 로컬 워커가 한다. actions.py가 47줄로 짧은 게 핵심인데, 워커가 할 수 있는 행동을 좁게 고정해뒀기 때문이다. integrity.py는 17줄짜리 무결성 확인이다. 승인 응답이 중간에 바뀌지 않았는지만 본다.\nAPPROVALS-PENDING.md를 따로 둔 이유는 사각지대 때문이다. 대화 중에 \u0026ldquo;이건 나중에 결정하자\u0026quot;로 미룬 항목은 자동 점검 스크립트가 잡지 못한다. 미루는 순간 파일에 한 줄 적어두면, 아침 보고가 열린 항목을 다시 올려준다.\n자동화를 감시하는 자동화 b1341ef과 14d1f6c에서 운영 스크립트가 늘었다. scripts/backup_bundle.ps1(+235), scripts/automation_health.ps1(+206), scripts/RESTORE.md(+159), scripts/adsense_gate_check.ps1(+116), scripts/notify_telegram.ps1(+33), scripts/daily_report_run.ps1(+38/-17), scripts/content_harvest_run.ps1(+28)이다.\n백업은 폴더 원본을 클라우드에 그대로 올리는 방식을 쓰지 않는다. 저장소에는 설정 파일과 토큰 흔적이 섞여 있어서, 폴더 통째 동기화는 시크릿을 그대로 외부에 올리는 것과 같다. 대신 git 번들로 묶어서 올린다. 커밋 이력이 그대로 보존되고, 무엇이 들어가는지 목록이 명확하다.\nRESTORE.md가 159줄인 이유는 백업보다 복구가 어렵기 때문이다. 백업 스크립트는 매번 돌아가니 고장 나면 바로 안다. 복구 절차는 실제로 필요해지는 순간이 처음이라, 그때 문서가 부실하면 백업이 있어도 못 쓴다.\nautomation_health.ps1은 등록된 자동화가 실제로 돌았는지 확인한다. 스케줄러에 등록만 해두고 조용히 실패하는 상황이 제일 위험하다. 실패 알림이 없으면 성공한 것처럼 보인다.\n에이전트 정의를 매달 감사하기로 d25fef7에서 AGENT-AUDIT.md(+42)를 만들었다. 하위 프로젝트 전체에 흩어진 에이전트 정의가 약 45개, 스킬이 약 13개까지 늘어난 상태다.\n여기서 한 판단은 \u0026ldquo;상시 감시 자동화를 만들지 않는다\u0026quot;였다. 근거는 로그가 없다는 사실이다. 서브에이전트 호출을 기록하는 로그가 없으니 활동성을 실시간으로 측정할 방법이 없다. 측정할 수 없는 대상에 상시 자동화를 붙이면, 돌아가는 척만 하는 스크립트가 하나 더 늘어난다. 로스터가 월 단위로만 바뀌니 월 1회 점검이 적정하다고 봤다. 그리고 존폐 판단은 추천까지만 하고 삭제는 사람이 확정하도록 못 박았다.\n같은 날 0cf67ee에서 에이전트 이름 충돌을 정리했다. 카드뉴스 프로젝트의 에이전트 이름이 coin-card-designer에서 card-designer로 바뀌었다.\n--- -name: coin-card-designer +name: card-designer description: data/daily_data.json을 templates/*.html에 주입해 output/page1~4.png를 생성하는 에이전트. --- 이름 규칙은 이렇다. 상위 폴더의 정의는 하위 프로젝트가 자동으로 상속받고, 같은 이름이 여러 층에 있으면 작업 디렉토리에 가까운 정의가 이긴다. 그래서 프로젝트별로 동작을 다르게 하고 싶으면 이름을 같게 두고 가까운 곳에 덮어쓰면 되고, 전역에서 구분하고 싶으면 이름을 다르게 둬야 한다. 이번 변경은 프로젝트 폴더 안에서 같은 역할을 가리키므로 접두어를 뗐다.\n1367줄을 지운 쪽 오늘 삭제된 1367줄 중 상당 부분은 문서 정리다.\nrider-log/HANDOFF-FROM-TAXI-LOG.md(-78)와 HANDOFF-REPLY-TO-TAXI-LOG.md(-64): 폐기된 택시 앱 계획의 인수인계 문서다. 그 방향을 접었으니 문서도 지웠다. NEXT-SESSION-TODO.md(-53): 다음 세션 할 일을 적어두던 파일인데, 승인 대기 원장과 아침 보고로 역할이 옮겨가서 없앴다. rename_projects.ps1(-51): 폴더 이름 일괄 변경용 일회성 스크립트다. 한 번 쓰고 남겨두면 나중에 누군가 다시 돌린다. 죽은 문서를 남겨두면 다음에 읽는 사람이 그게 현행인지 확인하는 비용을 낸다. 확인 비용이 반복되는 문서는 지우는 게 맞다.\n나머지 트랙 한 줄씩만 남긴다.\nbitget-trading: a_momentum/a_momentum.py(+322)로 모멘텀 전략 코드가 들어왔고, 백테스트 캐시 파일들이 함께 커밋됐다. us-stock: backtest/forward_run.py(+56/-7). 페이퍼 포워드 테스트가 매일 NAV를 한 줄씩 쌓는 중이다. hell-train: index.html이 +1830/-468로 크게 움직였고, .claude/skills/ 아래 규칙 문서가 들어왔다. git-workflow(+716), tdd-workflow(+583), coding-standards(+551), error-handling(+377), verification-loop(+129). SPEC.md도 +279줄 늘었다. video-pipeline: assets/broll/hell-train/record_broll.py(+121)로 게임 플레이 영상을 자동 녹화하고, 개발일지 롱폼용 폰트와 클립을 모으는 중이다. insta-card-news: CLAUDE.md(+76), SCHEDULE-PLAN.md(+95), SETUP-TODO.md(+47). 발행은 아직 수동 고정이다. ai-influencer: HANDOFF.md(+84/-38), 캡션 로그와 포스팅 큐 정리. doc-maker: .claude/skills/doc-design-skill/SKILL.md(+124)와 docx 변환 실험 파일들. 오늘 남긴 세 가지 하나. 증상이 나온 커밋과 원인을 만든 커밋은 다르다. AdMob ID 교체 커밋에서 크래시가 보였지만 원인은 R8이었다. debug와 release를 비교해서 \u0026ldquo;코드가 같은데 결과가 다르다\u0026quot;를 확인한 게 방향을 바꿨다.\n둘. 실패 경로 코드는 성공 경로보다 테스트가 길어진다. 유가 갱신은 구현 25줄에 테스트 62줄, 자동 지출은 구현 69줄에 테스트 95줄이었다. 성공은 한 갈래인데 실패는 네트워크, 형식, 빈 데이터로 갈라진다.\n셋. 매 단계 끝에서 실행 가능한 앱으로 남겨야 한다. cargo-log를 M1부터 M6까지 밀 수 있었던 건 M2 시점에 이미 쓸 수 있는 장부앱이었기 때문이다. GPS도 광고도 그 위에 얹은 것이고, 마지막에 R8 문제로 M6이 막혔을 때도 앞 단계는 멀쩡했다.\n다음 할 일은 R8을 다시 켜는 것이다. 축소를 끈 건 임시 조치다. 어떤 클래스가 왜 필요한지 릴리스 로그에서 확인하고 keep 규칙을 최소로 쓰는 게 원래 자리다. 지금은 출시 가능한 상태를 먼저 확보했다.\n","permalink":"https://liquidation-man.github.io/posts/2026-07-27-flutter-%ED%99%94%EB%AC%BC-%EC%9E%A5%EB%B6%80%EC%95%B1-%ED%95%98%EB%A3%A8-%EB%A7%8C%EC%97%90-m1m6/","summary":"\u003cp\u003e디버그 빌드에서는 홈, 입력, 통계, 백업까지 전부 정상이었다. 그런데 release AAB로 뽑아서 실제 기기에 올리자 스플래시 직후에 앱이 사라졌다. 코드 변경은 \u003ccode\u003ecargo-log/lib/core/app_config.dart\u003c/code\u003e에서 AdMob 테스트 광고 ID를 실제 ID로 바꾼 것(+17/-11)과 \u003ccode\u003eAndroidManifest.xml\u003c/code\u003e 두 줄(+2/-3)이 전부였다. 기능 커밋이 아니라 문자열 교체 커밋 하나에서 릴리스만 죽은 셈이다.\u003c/p\u003e","title":"라이더 로그 — 릴리스 빌드만 죽던 앱을 살렸다"},{"content":"지금 읽는 이 글은 사람이 앉아서 쓴 글이 아니다. 어제 여러 저장소에 남긴 커밋과 그 작업을 진행한 Claude 세션 로그를 밤에 기계가 긁어모아, 한국어 개발일지로 다시 쓰고, 두 군데 블로그에 밀어 넣은 결과다. 발행 버튼을 누른 사람도 없다. 운영체제 스케줄러가 정해진 시각에 파이프라인을 깨워 수집부터 발행까지 한 번에 돌린다. 이 글은 그 파이프라인이 자기 자신을 소개하는, 조금 이상한 메타 성격의 글이다. 아래에서는 한 줄짜리 커밋 기록이 어떻게 읽을 만한 문단으로 바뀌고, 그 과정에서 사람 이름이나 주문번호 같은 게 어떻게 사라지는지를 실제 구성 그대로 따라간다.\n밤에 아무도 없을 때 안에서 벌어지는 일 파이프라인의 하루는 수집으로 시작한다. Collector가 대상 저장소들을 순회하며 지난 24시간 사이에 쌓인 커밋을 읽고, 같은 기간의 Claude Code 세션 로그도 함께 가져온다. 커밋 메시지만으로는 \u0026ldquo;무엇을 했는가\u0026quot;까지는 알아도 \u0026ldquo;왜 그렇게 했는가\u0026quot;가 비는 경우가 많은데, 세션 로그가 그 맥락을 메워준다. 어떤 버그를 어떤 판단으로 고쳤는지 같은 결정 과정이 로그에 남아 있어서, 글에 이야기의 살이 붙는다. 수집 단계에는 상한선이 걸려 있다. 커밋 수, 커밋당 파일 수, 파일당 diff 줄 수, 전체 diff 글자 수까지 모두 제한을 둔다. 하루치 작업이 폭발적으로 많은 날에도 후속 단계가 감당할 분량으로 잘라내기 위한 장치다.\n이 여덟 칸이 파이프라인의 등뼈다. 왼쪽 끝의 원시 커밋 로그가 오른쪽 끝의 발행된 글로 바뀌는 동안, 각 칸은 앞 칸의 결과만 받아 자기 일만 한다. 글생성 칸은 수집이 무엇을 걸렀는지 다시 따지지 않고, 발행 칸은 앞의 두 게이트가 통과시킨 원고만 신뢰한다. 이렇게 책임을 쪼개두면 결과가 이상한 날에 어느 칸에서 틀어졌는지 바로 짚을 수 있다. 커밋은 멀쩡한데 문단이 어색하면 글생성을, 멀쩡한 글이 안 올라갔으면 발행을 먼저 본다.\n사람 이름과 주문번호가 절대 새면 안 되는 이유 이 블로그가 다루는 소재에는 크몽 고객 응대나 문서 작업처럼 남의 개인정보가 스치는 작업이 섞여 있다. 사람이 매번 검수한다면 발행 직전에 눈으로 걸러낼 수 있지만, 이 파이프라인은 사람이 없다. 그래서 마스킹은 선택이 아니라 파이프라인이 성립하기 위한 전제다. 수집 직후 마스킹 단계가 이메일, 토큰처럼 생긴 문자열, API 키 패턴 같은 것을 정규식으로 지운다.\n문제는 정규식이 라벨 없는 한국어 실명을 못 잡는다는 데 있다. \u0026ldquo;박기효님께 회신\u0026rdquo; 같은 문장에서 이름 석 자는 어떤 일반 패턴으로도 안전하게 걸러지지 않는다. 그래서 두 번째 방어선으로 사람이 직접 채우는 차단 목록을 둔다. 크몽 고객 실명이나 주문번호처럼 반드시 지워야 하는 문자열을 설정 파일의 denylist에 미리 등록해두면, 그 저장소의 커밋이 수집되는 날 마스킹 단계가 해당 문자열을 통째로 가린다. 정규식이 넓게 훑고 denylist가 정규식이 놓치는 고유명사를 콕 집는 이중 구조다. 그래서 이 글 어디에도 실제 수치나 계정, 사람 이름이 나오지 않는다. 마스킹 원칙 자체가 이 글의 소재이면서, 동시에 이 글에 그런 정보가 없는 이유이기도 하다.\n커밋 로그 한 줄이 문단이 되는 순간 마스킹을 통과한 재료가 글생성 단계로 넘어간다. 여기서 claude -p 헤드리스 호출이 등장한다. 대화형 세션을 띄우지 않고 프롬프트 하나를 명령줄로 넘겨 결과만 받는 방식이다. 정리된 커밋 목록과 세션 맥락을 프롬프트에 실어 넣으면, \u0026ldquo;무엇을 왜 했는가\u0026quot;를 풀어 쓴 한국어 초안이 돌아온다. fix: leakguard 기본값 fail-closed로 변경 같은 한 줄이 그날 어떤 위험을 막으려 했는지를 설명하는 문단으로 펴지는 지점이 여기다.\n생성이 곧 발행은 아니다. 초안은 그대로 나가지 않고 두 개의 게이트를 차례로 통과해야 한다. 첫 번째가 품질 게이트다. 자동 생성 글에서 가장 위험한 건 원본에 없던 숫자를 지어내는 환각이다. 그래서 품질 게이트는 원고에 등장하는 수치가 수집된 실제 재료에 근거를 두는지 확인하고, 근거 없는 숫자가 튀어나오면 막는다. 제목 형식도 함께 검사한다. 제목이 종결어미로 끝나는 문장형이면 걸러내고 명사구로 다듬게 한다. 헤지 표현이나 상투적 마무리 문구처럼 글의 밀도를 떨어뜨리는 패턴도 이 단계의 점검 대상이다.\nfail-closed, 확신이 없으면 막는 쪽으로 기운다 두 번째 게이트는 누출 게이트다. 마스킹이 앞에서 한 번 훑었는데도 발행 직전에 leakguard가 완성된 원고 전체를 다시 스캔한다. 검사 대상이 재료가 아니라 최종 원고라는 점이 중요하다. 글생성 과정에서 모델이 맥락을 재구성하다가 마스킹된 조각을 우회해 되살릴 가능성까지 마지막에 한 번 더 잡기 위해서다.\n이 게이트의 핵심 설계는 fail-closed다. 스캔이 확실하게 \u0026ldquo;깨끗하다\u0026quot;고 판정하지 못하면, 애매한 경우를 통과가 아니라 차단으로 처리한다. 누출 후보가 하나라도 남으면 발행 자체를 멈춘다. 무인 시스템에서 판단이 흐릿할 때 어느 쪽으로 기울지를 미리 정해둔 것이다. 사람이 없으니 \u0026ldquo;일단 올리고 문제되면 내린다\u0026quot;가 성립하지 않는다. 한번 공개된 실명은 되돌려도 이미 새어 나간 뒤다. 그래서 의심스러우면 멈추는 쪽을 기본값으로 박아뒀다.\n이 두 게이트를 나눠 둔 이유는 걱정하는 대상이 다르기 때문이다. 품질 게이트는 \u0026ldquo;글이 틀렸는가\u0026quot;를, 누출 게이트는 \u0026ldquo;글이 위험한가\u0026quot;를 본다. 틀린 글은 창피한 정도로 끝나지만 위험한 글은 남에게 피해를 준다. 그래서 누출 쪽이 더 보수적으로, 조금이라도 걸리면 무조건 막는 방향으로 설계됐다.\n다이어그램이 저절로 그림 파일로 바뀌는 자리 두 게이트를 통과한 원고에는 종종 mermaid 코드 블록이 들어 있다. 파이프라인 흐름이나 구조를 설명하는 그림이다. 시각화 단계가 이 코드 블록을 실제 PNG 이미지로 렌더해 글에 붙인다. 텍스트로 남겨두면 티스토리 같은 일부 발행 대상에서 그대로 코드가 노출되기 때문에, 어디에 올리든 그림으로 보이도록 미리 이미지로 구워둔다.\n이 단계에서 실제로 데고 나서야 알게 된 함정이 하나 있었다. 초기에는 미래 날짜의 원고까지 렌더 대상에 들어가 아직 오지 않은 날의 글이 이미지와 함께 만들어지는 문제가 있었다. 예약 발행을 염두에 두고 날짜를 앞세워 작업하다 보면 오늘보다 뒤인 날짜의 초안이 파이프라인에 섞여 든다. 그래서 렌더 대상에서 미래 날짜를 제외하는 조건을 넣었다. 이런 함정은 설계도만 봐서는 안 보이고, 실제로 하루치를 돌려보고 이상한 결과가 나온 뒤에야 드러난다.\n한 번 쓴 글을 두 군데에 나눠 올릴 때 발행 대상은 하나가 아니다. GitHub Pages와 티스토리 두 곳에 같은 글을 올린다. 두 채널은 올리는 방식이 완전히 다르다. GitHub Pages 쪽은 마크다운 파일을 저장소에 커밋하고 push하면 GitHub Actions가 Hugo로 사이트를 빌드해 배포한다. 사람 손이 닿는 지점이 없는 순수 파일 기반 흐름이다. 티스토리 쪽은 공개 API로 글을 넣는 경로가 마땅치 않아 Playwright로 브라우저를 직접 몰아 로그인하고 글을 작성한다. 사람이 웹 관리 화면에서 하는 클릭을 코드가 대신하는 방식이다.\n방식이 이렇게 다른 두 채널을 한 파이프라인이 다루려면 공통의 약속이 필요하다. 그래서 Publisher라는 인터페이스로 발행 동작을 추상화했다. 상위 조율 코드는 \u0026ldquo;이 원고를 발행하라\u0026quot;고만 지시하고, GitHub용 구현과 티스토리용 구현이 각자의 방식으로 그 지시를 수행한다. 새 채널을 하나 더 붙이고 싶으면 같은 인터페이스를 만족하는 구현을 하나 추가하면 되고, 조율 코드는 손대지 않는다. 두 곳에 같은 글이 올라가면 검색엔진 입장에선 중복으로 보일 수 있어서, 티스토리 쪽을 원본으로 지정하는 canonical 표시를 걸어 어느 쪽이 정본인지 명시한다. 발행 성공 여부는 슬러그 단위로 상태 파일에 기록해서, 한 채널만 올라가고 다른 채널이 실패한 날에도 다음 실행 때 이미 올라간 글을 다시 올리지 않고 빠진 것만 채운다.\n매일 같은 시각에 사람 없이 도는 구조 마지막 칸은 스케줄이다. 지금까지의 모든 단계를 운영체제 스케줄러가 정해진 시각에 하루 한 번 깨운다. 여기서 순서 하나가 은근히 중요했다. 발행 시각이 그날의 자동 커밋 작업보다 앞서면, 정작 그날 마지막에 남긴 커밋이 아직 저장소에 반영되기 전이라 하루 밀린 내용으로 글이 만들어진다. 그래서 발행 시각을 자동 커밋이 끝난 뒤로 밀어, 오늘 작업이 온전히 담긴 상태에서 글이 생성되도록 순서를 맞췄다. 이런 시각 배치는 성능 문제가 아니라 순서 의존성 문제라서, 두 자동화가 서로를 모른 채 각자 시각만 보고 돌면 조용히 하루씩 어긋난다.\n전체를 떠받치는 기술은 단출하다. 수집과 마스킹, 게이트, 조율 로직은 Python 3.12로 짰다. 사이트는 Hugo에 PaperMod 테마를 얹어 빌드하고, 브라우저 자동화는 Playwright가, 배포는 GitHub Actions가 맡는다. 화려한 부품은 없다. 대신 각 부품이 자기 몫만 하고 다음 부품에 넘기도록 경계를 분명히 그어둔 게 이 파이프라인의 실제 무게중심이다. 사람이 지켜보지 않는 시스템에서는 각 단계가 무엇을 통과시키고 무엇을 막는지가 곧 신뢰의 전부이기 때문이다.\n이 블로그를 만드는 팀 이 파이프라인은 한 에이전트가 아니라 역할이 나뉜 팀이 함께 굴린다. 총괄 에이전트가 요청을 받아 라우팅과 조율을 맡고, research-team이 SEO와 수익화 방향을 조사하며, document-team이 글을 쓰고, docmaker-lead가 품질검증 게이트를 전수 점검하고, gatekeeper가 공개 발행을 승인한다.\n","permalink":"https://liquidation-man.github.io/posts/2026-07-25-%EB%A7%A4%EC%9D%BC-%EA%B0%9C%EB%B0%9C-%EC%9E%91%EC%97%85%EC%9D%84-%EC%82%AC%EB%9E%8C-%EC%97%86%EC%9D%B4-%EA%B8%80%EB%A1%9C/","summary":"\u003cp\u003e지금 읽는 이 글은 사람이 앉아서 쓴 글이 아니다. 어제 여러 저장소에 남긴 커밋과 그 작업을 진행한 Claude 세션 로그를 밤에 기계가 긁어모아, 한국어 개발일지로 다시 쓰고, 두 군데 블로그에 밀어 넣은 결과다. 발행 버튼을 누른 사람도 없다. 운영체제 스케줄러가 정해진 시각에 파이프라인을 깨워 수집부터 발행까지 한 번에 돌린다. 이 글은 그 파이프라인이 자기 자신을 소개하는, 조금 이상한 메타 성격의 글이다. 아래에서는 한 줄짜리 커밋 기록이 어떻게 읽을 만한 문단으로 바뀌고, 그 과정에서 사람 이름이나 주문번호 같은 게 어떻게 사라지는지를 실제 구성 그대로 따라간다.\u003c/p\u003e","title":"개발일지 파이프라인 — 사람 없이 매일 발행한다"},{"content":"증시 시황은 매일 갱신되고, 어제 만든 콘텐츠는 오늘 아침이면 낡는다. 그래서 시황을 다루는 콘텐츠는 하루도 빠짐없이 같은 시각에 새로 나와야 한다는 부담을 안고 시작한다. 이 부담을 사람이 매일 손으로 감당하려면 데이터를 찾고, 숫자를 옮겨 적고, 이미지를 만들고, 영상으로 합치고, 업로드하는 일을 하루도 거르지 않고 반복해야 한다. 이 글은 그 반복을 미국·국내·코인 세 시장에 대해 각각 하나씩, 모두 세 개의 파이프라인으로 묶어 한 유튜브 채널에 자동으로 발행하도록 만든 기록이다.\n매일 같은 시각에 시황을 정리해야 할 때 콘텐츠 하나가 나오기까지의 일은 늘 같은 순서를 밟는다. 먼저 그날의 시황 데이터를 수집하고, 그중 사람들이 볼 만한 핵심 종목과 지수를 골라내고, 그 내용을 카드 이미지 네다섯 장으로 그리고, 카드를 이어 붙여 영상으로 만들고, 배경 음악을 얹고, 마지막에 유튜브로 올린다. 이 여섯 단계는 시장이 미국이든 국내든 코인이든 뼈대가 같다. 달라지는 건 데이터의 출처와 발행 시각뿐이다.\n이 순서를 코드로 굳혀 두면, 매일 아침 사람이 개입하지 않아도 같은 품질의 콘텐츠가 같은 형식으로 나온다. 중요한 건 각 단계가 독립적으로 검증 가능하도록 나뉘어 있다는 점이다. 데이터 수집이 끝났는지, 카드가 다 그려졌는지, 영상이 정상적으로 합쳐졌는지를 단계마다 확인할 수 있어야, 어디서 문제가 났는지 추적할 수 있다. 한 덩어리로 뭉쳐 놓으면 실패했을 때 어느 지점이 무너졌는지 알 수 없다.\n세 시장이 서로 다른 시간에 열리고 닫힐 때 세 시장은 열고 닫는 시각이 다르다. 미국 증시는 한국 시간으로 새벽에 마감하고, 국내 증시는 오후 3시 30분에 닫히며, 코인 시장은 애초에 닫지 않는다. 그래서 세 콘텐츠를 하나의 스케줄에 묶을 수 없다. 미국 시황은 장 마감 직후의 데이터가 확정된 뒤에 만들어야 하고, 국내 시황은 국내 장 마감을 기다려야 하며, 코인은 하루 중 정해둔 기준 시각의 스냅숏으로 만든다. 세 파이프라인이 각기 다른 시각에 독립적으로 돌아가는 이유다.\n세 파이프라인은 발행 시각과 데이터 출처만 다를 뿐, 카드를 그리고 영상을 합치고 업로드하는 부분은 완전히 같은 코드를 공유한다. 시장별로 코드를 세 벌 복사해 두면 한 곳을 고칠 때 세 곳을 모두 고쳐야 하고, 그러다 한 곳을 빠뜨리면 시장마다 다른 결과가 나온다. 그래서 공통 부분은 한 벌로 유지하고, 시장별 차이는 설정값으로만 갈아 끼운다. 미국 파이프라인은 미국용 설정을 읽고, 국내 파이프라인은 국내용 설정을 읽는 식이다.\n숫자 하나가 틀리면 안 되는 콘텐츠를 자동으로 만들 때 시황 콘텐츠에서 가장 위험한 건 틀린 숫자다. 지수 등락률을 잘못 적거나, 어제 데이터를 오늘 것으로 착각해 올리면, 자동화는 편리한 도구가 아니라 매일 틀린 정보를 퍼뜨리는 장치가 된다. 사람이 만들면 마지막에 눈으로 한 번 더 확인하지만, 자동화에는 그 눈이 없다. 그래서 눈을 대신할 검산 게이트를 파이프라인 안에 넣었다.\n핵심 원칙은 fail-closed다. 데이터 수집이나 검산에서 하나라도 문제가 생기면, 어정쩡하게 만들어 올리는 대신 그날 발행을 통째로 건너뛴다. 예를 들어 그날이 거래일이 아니거나, 데이터 소스가 빈 값을 돌려주거나, 지수 값이 상식 범위를 벗어나면, 파이프라인은 거기서 멈추고 업로드 단계로 넘어가지 않는다. 틀린 콘텐츠를 올리는 것보다 그날 하루 콘텐츠가 없는 편이 낫다는 판단이다. 자동화의 기본값을 \u0026ldquo;의심스러우면 올린다\u0026quot;가 아니라 \u0026ldquo;의심스러우면 멈춘다\u0026quot;로 잡아 두는 것이 이 구조의 뼈대다.\n이 게이트는 실제 운영에서 여러 번 제 역할을 했다. 주말이나 공휴일처럼 장이 열리지 않은 날, 데이터 소스는 전날 값을 그대로 돌려주기도 한다. 거래일 게이트가 없으면 이 값을 오늘 시황으로 착각해 같은 내용을 반복 발행하게 된다. 그래서 콘텐츠를 만들기 전에 \u0026ldquo;오늘이 이 시장의 거래일이 맞는가\u0026quot;를 먼저 확인하고, 아니면 조용히 건너뛴다. 국내 장이 쉬는 날과 미국 장이 쉬는 날은 서로 다르기 때문에, 이 판단도 시장별로 따로 한다.\n카드 다섯 장을 손 안 대고 그리려면 선별된 시황 데이터는 이미지가 되어야 한다. 이 부분은 Pillow로 처리한다. 배경 판을 깔고, 그 위에 제목과 종목명과 등락률을 정해진 위치에 얹고, 색으로 오름과 내림을 구분해 카드 한 장을 완성한다. 이런 카드를 하루에 시장마다 네다섯 장씩 그린다. 첫 장은 그날의 요약, 다음 장들은 주요 지수와 종목, 마지막 장은 마무리 같은 식으로 구성이 정해져 있다.\n이미지를 코드로 그리는 방식의 장점은 일관성이다. 사람이 매일 디자인 도구로 카드를 만들면 위치와 글자 크기가 미세하게 흔들리지만, 코드는 매번 같은 좌표에 같은 크기로 글자를 얹는다. 폰트, 색, 여백을 한 번 정해 두면 그 규칙이 모든 카드에 그대로 적용된다. 등락을 나타내는 색 규칙 같은 것도 코드에 박아 두면, 오르는 종목은 언제나 같은 색, 내리는 종목은 언제나 다른 색으로 나온다. 보는 사람이 색만으로 방향을 읽을 수 있게 하는 규칙이 매일 깨지지 않고 유지된다.\n정지 이미지를 영상으로 바꾸고 소리를 입힐 때 카드는 정지 이미지지만 유튜브에 올라가는 건 영상이다. 그래서 완성된 카드 여러 장을 이어 붙여 각 장이 몇 초씩 화면에 머무는 슬라이드쇼 형태의 영상으로 합친다. 여기에 배경 음악을 얹으면 콘텐츠 한 편이 완성된다. 카드 장수와 각 장의 노출 시간이 정해져 있으니 영상 길이도 일정하게 나온다.\n음악은 콘텐츠 성격에 맞는 것을 미리 골라 둔 목록에서 가져온다. 매번 새로 고르지 않고 정해진 풀에서 순환시키면, 저작권을 신경 쓸 범위가 좁아지고 편마다 톤이 크게 튀지 않는다. 영상 합성 단계에서 챙겨야 하는 건 화면 비율과 해상도, 음량이 유튜브에서 어색하지 않게 나오는지 정도다. 이 값들도 한 번 맞춰 두면 매 편에 그대로 적용된다.\n사람 없이 유튜브에 올리려면 마지막 단계는 업로드다. 유튜브에 프로그램으로 영상을 올리려면 OAuth 인증을 거쳐 채널에 접근할 권한을 얻어야 한다. 한 번 사용자 동의를 받아 발급된 토큰으로 이후의 업로드를 자동으로 처리하는 구조다. 문제는 이 토큰이 영원하지 않다는 점이다. 액세스 토큰은 짧은 주기로 만료되고, 그때마다 리프레시 토큰으로 새 토큰을 발급받아야 한다. 이 갱신이 조용히 실패하면, 어느 날 아침 갑자기 업로드만 안 되는 상황이 생긴다.\n실제 운영에서 겪은 전형적인 문제도 이 지점이었다. 앞 단계는 모두 정상이라 카드와 영상까지 멀쩡하게 만들어졌는데, 업로드 단계에서 인증이 풀려 마지막에서 멈추는 경우다. 그래서 인증과 토큰 관리는 파이프라인 본체에서 떼어 내 한곳에서만 다루도록 분리했다. 세 파이프라인이 각자 인증을 처리하면 토큰이 세 벌로 흩어져 어느 것이 만료됐는지 파악하기 어렵지만, 인증을 한 곳으로 모으면 토큰 상태를 한 자리에서 관리할 수 있다. 업로드가 실패했을 때 그 원인이 인증인지 다른 것인지도 빨리 가려낼 수 있다.\n또 하나 조심하는 건 공개 범위다. 사람이 검수하지 않은 콘텐츠가 곧바로 전체 공개로 올라가면, fail-closed 게이트를 통과하지 못한 무언가가 새어 나갔을 때 되돌리기 어렵다. 그래서 무엇이 어떤 공개 상태로 올라가는지에 대한 판단은 자동화가 스스로 내리지 않고, 발행 정책을 정해 둔 규칙에 따르게 한다. 자동으로 도는 파이프라인이라도, 바깥에 공개되는 지점만큼은 통제 아래 두는 것이 이 구조의 마지막 안전장치다.\n세 파이프라인을 하나의 뼈대로 묶으면 세 시장의 파이프라인을 따로 만들었다면 각각의 개선이 서로 다른 곳에 흩어졌을 것이다. 하나의 뼈대로 묶어 두니, 카드 디자인을 한 번 고치면 세 시장에 동시에 반영되고, 검산 규칙을 하나 추가하면 세 파이프라인이 함께 안전해진다. 시장별로 갈리는 것은 데이터 출처와 발행 시각, 그리고 거래일 판단뿐이고 나머지는 공유 자산이 된다.\n자동화라고 부를 만한 부분은 화려한 무언가가 아니다. 매일 반복되던 수집과 선별과 렌더와 합성과 업로드를 코드로 굳히고, 그 사이사이에 \u0026ldquo;틀렸으면 멈춘다\u0026quot;는 게이트를 심어 둔 것이다. 이 구조가 자리를 잡으면 사람은 매일의 반복에서 벗어나, 무엇을 어떻게 보여줄지를 정하는 판단에만 집중할 수 있다. 콘텐츠의 질을 결정하는 건 결국 그 판단이고, 자동화는 그 판단이 매일 같은 품질로 세상에 나가도록 실어 나르는 역할을 한다.\n이 프로젝트를 만드는 팀 이 파이프라인은 시황 콘텐츠를 승인하고 수치를 검산하는 리드가 조율하고, 수집·디자인·합성·인프라·개선을 나눠 맡는 역할들이 그 아래에서 움직인다. jeungsi-briefing-lead가 시황 콘텐츠 승인과 수치 검산, 전체 조율을 맡고, data-analyst가 정형 데이터를 수집하고, card-designer가 카드 디자인을 담당하며, video-publisher가 영상 합성을 처리한다. 그 외 형태의 영상은 video-team이, OAuth와 업로드 인프라는 youtube-upload-team이 단일 관리하고, content-refiner가 가독성과 후킹을 지속적으로 개선한다.\n","permalink":"https://liquidation-man.github.io/posts/2026-07-25-%EB%A7%A4%EC%9D%BC-%EC%A6%9D%EC%8B%9C-%EC%8B%9C%ED%99%A9%EC%9D%84-%EC%B9%B4%EB%93%9C%EB%89%B4%EC%8A%A4-%EC%98%81%EC%83%81%EC%9C%BC%EB%A1%9C-%EB%A7%8C%EB%93%A4%EC%96%B4/","summary":"\u003cp\u003e증시 시황은 매일 갱신되고, 어제 만든 콘텐츠는 오늘 아침이면 낡는다. 그래서 시황을 다루는 콘텐츠는 하루도 빠짐없이 같은 시각에 새로 나와야 한다는 부담을 안고 시작한다. 이 부담을 사람이 매일 손으로 감당하려면 데이터를 찾고, 숫자를 옮겨 적고, 이미지를 만들고, 영상으로 합치고, 업로드하는 일을 하루도 거르지 않고 반복해야 한다. 이 글은 그 반복을 미국·국내·코인 세 시장에 대해 각각 하나씩, 모두 세 개의 파이프라인으로 묶어 한 유튜브 채널에 자동으로 발행하도록 만든 기록이다.\u003c/p\u003e","title":"증시 카드뉴스 — 시황을 영상으로 자동 발행한다"},{"content":"이 글에서 다루는 인물은 실존하지 않는다. 생성형 이미지 모델로 만든 AI 가상 인물이고, 이 글에 실린 모든 사진은 촬영본이 아니라 생성된 이미지다. 특정 연예인이나 실제 인물을 재현하려는 시도도 아니다. 목적은 하나다. 실제로 존재하지 않는 얼굴 하나를 정하고, 그 얼굴을 여러 장면에 걸쳐 흔들리지 않게 유지하면서 피드 이미지를 자동으로 찍어내는 과정을 기술적으로 정리하는 것이다.\n같은 인물인데 컷마다 얼굴이 달라졌다 가상 인플루언서를 만들겠다고 마음먹고 처음 이미지를 몇 장 뽑아봤을 때 바로 벽에 부딪혔다. 프롬프트에 나이대, 헤어스타일, 분위기를 아무리 자세히 적어도 생성할 때마다 다른 사람이 나왔다. 눈매가 바뀌고, 코 길이가 달라지고, 얼굴형이 넓어졌다 좁아졌다 했다. 한 장씩 따로 보면 그럴듯한데, 세 장을 나란히 놓으면 세 명이었다.\n피드는 한 장짜리 이미지가 아니다. 같은 사람이 어제는 카페에 있었고 오늘은 새 옷을 입었다는 연속성이 있어야 계정이 성립한다. 컷마다 얼굴이 미세하게 어긋나면 보는 사람은 설명하기 어려운 위화감을 느낀다. 그래서 이 프로젝트의 진짜 과제는 예쁜 이미지를 뽑는 게 아니라 같은 얼굴을 붙잡아 두는 것, 즉 얼굴 일관성(consistency)이었다.\n문제를 이렇게 다시 정의하고 나니 파이프라인의 뼈대가 잡혔다. 얼굴을 먼저 고정하고, 그다음에 장면만 바꾼다. 순서가 반대가 되면 매번 새 사람이 태어난다.\n얼굴 레퍼런스 한 장을 기준으로 잠갔다 첫 단계는 기준 얼굴을 정하는 일이었다. 여러 후보를 생성한 뒤 정면에 가깝고 조명이 고른 얼굴 한 장을 골라 레퍼런스로 지정했다. 이 한 장이 이후 모든 생성의 기준점이 된다. 표정이 과하거나 머리카락이 얼굴을 많이 가린 컷은 기준으로 쓰기 나쁘다. 이목구비가 또렷하게 드러나는, 담백한 정면 컷이 가장 잘 붙는다.\n레퍼런스를 잡는 방식은 크게 두 갈래다. 하나는 이미지-투-이미지 방식으로 기준 얼굴을 참조 이미지로 넣고 그 특징을 유지하도록 강제하는 것이고, 다른 하나는 시드(seed) 값을 고정해 생성기의 초기 상태를 재현하는 것이다. 이 둘은 배타적이지 않아서 함께 썼다. 레퍼런스 이미지로 얼굴 정체성을 잡고, 시드로 전반적인 톤과 질감의 흔들림을 줄이는 식이다.\n여기서 중요한 건 한 번 고른 레퍼런스를 함부로 바꾸지 않는 규율이다. 중간에 더 마음에 드는 얼굴이 나왔다고 기준을 갈아치우면 그 시점부터 계정의 인물이 다른 사람이 된다. 기준은 프로젝트 내내 하나로 유지했다.\n얼굴은 그대로 두고 포즈와 배경만 프롬프트로 바꿨다 얼굴을 잠갔으면 나머지는 장면 변수다. 프롬프트를 얼굴 파트와 장면 파트로 나눠서 관리했다. 얼굴 파트는 레퍼런스로 고정되어 있으니 프롬프트에서는 거의 건드리지 않고, 대신 포즈, 의상, 배경, 조명, 시간대 같은 장면 요소만 바꿨다.\n예를 들어 OOTD 컷은 전신이 보이도록 카메라를 멀리 두고 그날의 코디를 지정하고, 카페 컷은 상반신 위주로 자연광이 드는 창가를 배경으로 넣었다. 일상 컷은 조금 더 편한 포즈와 생활 공간을 배경으로 잡았다. 이렇게 장면 프롬프트를 몇 개의 틀로 만들어 두면 같은 인물을 서로 다른 상황에 반복적으로 배치할 수 있다.\n파이프라인 전체 흐름은 이렇게 정리된다.\n핵심은 검수에서 탈락한 컷이 버려지고 끝나는 게 아니라 장면 프롬프트 단계로 되돌아간다는 점이다. 얼굴이 어긋난 원인은 대개 얼굴 자체가 아니라 극단적인 각도나 과한 표정 같은 장면 설정에 있어서, 장면 조건을 조정하면 다음 생성에서 다시 얼굴이 맞아 들어오는 경우가 많았다.\n생성한 컷을 그냥 쓰지 않고 반드시 일관성을 검수했다 자동화라고 해서 뽑은 이미지를 무조건 피드에 올리는 건 아니다. 생성과 게시 사이에 검수 단계를 끼워 넣었다. 검수의 기준은 단순하다. 이 얼굴이 기준 얼굴과 같은 사람으로 보이는가.\n검수는 두 층으로 했다. 먼저 얼굴 임베딩을 뽑아 기준 얼굴과의 유사도를 수치로 재고, 미리 정한 임계값을 넘지 못한 컷은 자동으로 탈락시켰다. 이 자동 필터가 눈매가 크게 바뀌거나 얼굴형이 어긋난 명백한 실패를 걸러낸다. 그다음 임계값을 통과한 컷을 사람이 나란히 놓고 육안으로 확인했다. 수치로는 통과했는데 인상이 미묘하게 다른 경우가 남아 있기 때문이다.\n이 얼굴 일관성 유지 구조를 그림으로 보면 다음과 같다.\n승인된 컷만 모아 하나의 풀(pool)로 관리하니, 피드를 구성할 때는 이미 검증된 이미지 중에서 고르기만 하면 됐다. 실패한 컷이 계정에 올라가는 일이 구조적으로 막힌다.\n검수 임계값은 너무 높게 잡으면 멀쩡한 컷까지 떨어져 생성 낭비가 커지고, 너무 낮게 잡으면 얼굴이 흔들린 컷이 새어 나온다. 몇 차례 돌려보며 통과율과 실제 위화감 사이의 균형점을 찾아 임계값을 조정했다.\nOOTD, 카페, 일상 세 갈래로 피드를 채웠다 승인 컷 풀이 쌓이면 그걸로 피드를 조립한다. 콘텐츠 유형을 OOTD 룩북, 카페 일상, 생활 컷 세 갈래로 나눠 균형 있게 배치했다. 한 유형만 반복되면 피드가 단조로워지고, 반대로 장면이 무작위로 튀면 인물의 결이 흐려진다. 세 갈래를 번갈아 넣으면 같은 사람의 여러 하루처럼 읽힌다.\n생성 후 손이 가는 후처리도 있었다. 손가락 개수나 배경 소품처럼 생성 모델이 자주 틀리는 디테일을 다듬고, 컷마다 색감과 톤을 한 계정의 룩처럼 맞췄다. 색보정을 일관되게 걸면 얼굴이 조금 흔들려도 전체가 같은 사람의 앨범처럼 묶이는 효과가 있어서, 후처리 자체가 일관성을 보강하는 장치가 되기도 했다.\nAI가 만든 가상 인물임을 숨기지 않았다 기술적으로 얼굴을 아무리 정교하게 고정해도, 이 인물이 실제 사람인 것처럼 오해를 유도하면 그건 다른 문제가 된다. 그래서 이 프로젝트는 처음부터 투명성을 전제로 잡았다. 이 계정의 인물은 AI로 생성된 가상 인물이고, 게시물은 촬영이 아니라 생성된 이미지라는 사실을 감추지 않는다.\n투명성은 선언 한 줄로 끝나는 게 아니라 운영 방식에도 들어간다. 실존 인물을 특정해 닮게 만들지 않고, 실제 브랜드나 장소를 사실인 것처럼 꾸미지 않는다. 가상 인물이라는 정체성을 드러내는 것과 이미지의 완성도를 높이는 것은 상충하지 않는다. 오히려 만들어진 인물임을 분명히 해 두는 편이, 이 결과물을 어디까지 신뢰해야 하는지 보는 사람이 판단할 수 있게 한다.\nAI 가상 인물 제작 기술은 얼굴 하나를 붙잡아 여러 장면으로 확장하는 흥미로운 문제다. 그 흥미로움이 사람을 속이는 도구로 흘러가지 않도록, 만든 것을 만들었다고 밝히는 선을 유지하는 것이 이 파이프라인의 마지막 규칙이다.\n이 프로젝트를 만드는 팀 이 프로젝트는 전담 리드 없이 총괄 에이전트가 직접 조율하며, 생성형 이미지 모델과 힉스필드로 이미지를 만들고 content-refiner가 콘텐츠 품질을 다듬는 구성으로 움직인다.\n","permalink":"https://liquidation-man.github.io/posts/2026-07-25-%EA%B0%99%EC%9D%80-%EC%96%BC%EA%B5%B4%EC%9D%84-%EC%9C%A0%EC%A7%80%ED%95%98%EB%8A%94-ai-%EA%B0%80%EC%83%81-%EC%9D%B8%ED%94%8C%EB%A3%A8%EC%96%B8%EC%84%9C/","summary":"\u003cp\u003e이 글에서 다루는 인물은 실존하지 않는다. 생성형 이미지 모델로 만든 AI 가상 인물이고, 이 글에 실린 모든 사진은 촬영본이 아니라 생성된 이미지다. 특정 연예인이나 실제 인물을 재현하려는 시도도 아니다. 목적은 하나다. 실제로 존재하지 않는 얼굴 하나를 정하고, 그 얼굴을 여러 장면에 걸쳐 흔들리지 않게 유지하면서 피드 이미지를 자동으로 찍어내는 과정을 기술적으로 정리하는 것이다.\u003c/p\u003e","title":"AI 인플루언서 — 같은 얼굴로 피드를 자동 생성한다"},{"content":"먼저 분명히 해둘 것이 있다. 이 글은 수익을 자랑하는 글이 아니고, 어떤 종목이나 코인을 사라는 이야기는 더더욱 아니다. 자동매매 전략이 \u0026lsquo;진짜로 되는가\u0026rsquo;를 실거래 없이 걸러내려고 만든 검증 파이프라인의 개발·실험 기록이다. 실제 돈은 한 푼도 들어가지 않았고, 모든 실행은 백테스트와 페이퍼(모의) 포워드테스트로만 이뤄졌다. 등장하는 판정도 \u0026lsquo;이 전략은 벌어준다\u0026rsquo;가 아니라 \u0026lsquo;이 전략은 벤치마크를 이기지 못해서 보류했다\u0026rsquo; 쪽이 훨씬 많다. 투자 조언이 아니라 개발과 검증의 기록으로 읽어달라.\n백테스트 그래프가 예뻐도 못 믿는 이유 전략 검증을 시작하면 누구나 같은 함정에 빠진다. 과거 데이터에 전략을 돌려보면 우상향하는 자산곡선이 나오고, 그걸 보는 순간 \u0026lsquo;이거 되네\u0026rsquo; 하는 확신이 든다. 문제는 그 곡선의 상당 부분이 실전에서는 존재하지 않는 이득이라는 데 있다.\n가장 흔한 세 가지 누수가 있다. 첫째는 미래참조(lookahead)다. 그날 종가로 판단해서 그날 종가에 체결했다고 계산하면, 실전에서는 알 수 없는 정보로 매매한 셈이 된다. 둘째는 슬리피지다. 화면에 찍힌 호가에 그대로 체결된다고 가정하지만, 실제로는 주문이 시장을 밀어내면서 불리한 가격에 잡힌다. 셋째는 수수료와 세금이다. 회전율이 높은 전략일수록 이 마찰비용이 수익을 통째로 갉아먹는다. 백테스트에서 화려하게 빛나던 전략이 이 세 가지를 제대로 반영하는 순간 평범해지거나, 아예 마이너스로 돌아서는 일이 흔하다.\n그래서 이 프로젝트의 목표를 처음부터 \u0026lsquo;돈 버는 봇 만들기\u0026rsquo;가 아니라 \u0026lsquo;가짜 수익을 걸러내는 체\u0026rsquo;로 잡았다. 좋아 보이는 전략을 통과시키는 파이프라인이 아니라, 어지간한 전략은 다 떨어뜨리는 파이프라인을 원한 것이다.\n데이터 수집부터 판정까지, 한 방향으로 흐르게 파이프라인은 단계마다 전략을 한 번씩 더 의심하도록 설계했다. 각 단계는 앞 단계를 통과한 전략만 다음으로 넘긴다.\n데이터는 전부 무료 소스에서 읽기전용으로만 가져온다. 주문을 넣는 권한은 파이프라인 어디에도 연결하지 않았다. 크립토는 비트겟 공개 시세, 주식은 한국·미국 시장의 무료 일봉 데이터를 쓴다. 유료 고빈도 데이터나 대체 데이터에 손을 대지 않은 것은 비용 문제도 있지만, 개인이 재현할 수 없는 데이터 위에 세운 전략은 검증의 의미가 옅어지기 때문이다.\n전략 구현 단계에서는 규칙을 코드로 못 박는다. \u0026lsquo;저평가됐을 때 산다\u0026rsquo; 같은 애매한 문장은 검증할 수 없다. 어떤 신호가 뜨면 얼마를 어떤 조건으로 사고, 언제 판다는 것까지 전부 결정적인 규칙으로 적어야 백테스트에 올릴 수 있다.\n백테스트는 앞서 말한 세 가지 누수를 방어하는 데 초점을 맞췄다. 판단에 쓰는 정보는 반드시 체결 시점 이전 것으로 제한하고, 체결가에는 슬리피지를 얹고, 매매마다 수수료를 뗀다. 이 단계에서 이미 상당수 전략이 \u0026lsquo;백테스트만 예쁜\u0026rsquo; 정체를 드러낸다.\n백테스트를 통과해도 페이퍼로 한 번 더 백테스트는 결국 과거를 두 번 보는 일이다. 아무리 규칙을 엄격하게 짜도, 과거 데이터에 맞춰 전략을 고르는 과정 자체에 편향이 스며든다. 그래서 백테스트를 통과한 전략은 곧장 실투입으로 가지 않고, 페이퍼 포워드테스트로 넘긴다.\n포워드테스트는 실시간으로 들어오는 새 데이터에 전략을 돌리되, 주문은 모의로만 체결한다. 아직 아무도 보지 못한 미래 구간에서 전략이 어떻게 행동하는지를 관찰하는 것이다. 백테스트에서 좋았던 전략이 포워드 구간에 들어서자마자 흔들린다면, 그건 과거에 과최적화됐다는 강한 신호다. 실제 돈을 넣지 않았으니 이 실패는 비용 없는 실패다. 이 프로젝트에서 페이퍼 포워드테스트는 \u0026lsquo;실전 직전의 안전지대\u0026rsquo; 역할을 한다.\n여기에 성과귀인 저널을 붙였다. 전략이 벌거나 잃을 때마다 \u0026lsquo;왜\u0026rsquo;를 기록하는 장치다. 이 수익이 전략의 논리에서 나온 것인지, 아니면 그냥 시장 전체가 올라서 묻어간 것인지, 특정 며칠의 운에 몰려 있는지를 구분한다. 중요한 점은 이 저널이 전략을 자동으로 고치지 않는다는 것이다. 사람이 다시 들여다볼 필요가 있는지를 알려주는 트리거 역할만 한다. 자동으로 파라미터를 바꿔가며 성적을 맞추기 시작하면 그 순간 또 다른 과최적화가 된다는 걸 알기 때문이다.\n여러 전략을 돌려봤고, 대부분 떨어뜨렸다 실제로 이 파이프라인에 능동 전략 여러 개를 통과시켜봤다. 결과부터 말하면 대부분 보류였다. 이건 파이프라인이 고장 난 게 아니라, 오히려 의도대로 작동한 증거다.\n주식 쪽에서는 미국 시장을 대상으로 한 몇 가지 능동 전략을 검증했다. 실적 발표 이후의 흐름을 노리는 전략, 단기 되돌림을 노리는 전략 같은 것들이었다. 백테스트 수치만 보면 그럴듯했지만, 마찰비용을 반영하고 포워드 구간까지 밀어보면 시장 전체를 그냥 사서 들고 있는 것보다 나은 게 없었다. 특히 하락을 노리는 매도 포지션을 섞은 변형은 오히려 성적을 갉아먹었고, 회전율이 지나치게 높아 마찰비용에 취약한 전략도 있었다. 벤치마크를 이기지 못하는 전략은 아무리 자산곡선이 우상향해도 통과시키지 않았다.\n크립토 쪽도 접근은 같다. 비트겟을 대상으로 단일 통합 전략을 페이퍼로만 검증하며, 실거래 연결은 하지 않는다. 화려한 여러 전략을 동시에 굴리는 대신 하나를 제대로 검증하는 쪽을 택했다. \u0026lsquo;많이 벌었다\u0026rsquo;가 아니라 \u0026lsquo;이 규칙이 우연이 아니라고 말할 수 있는가\u0026rsquo;가 판정 기준이다.\n이 실패들을 지우지 않고 남겨두는 데는 이유가 있다. 어떤 전략이 왜 떨어졌는지를 기록해두면, 나중에 비슷한 아이디어가 다시 떠올랐을 때 같은 검증을 반복하지 않는다. 정직한 실패 노트는 그 자체로 재산이다.\n그래도 살아남은 소수는 어떻게 다른가 전부 떨어진 것은 아니다. 조건부로 살아남아 페이퍼 운영을 이어가는 전략도 있다. 공통점은 능동적으로 시장을 이기려 들기보다, 위험을 줄이는 쪽에 무게를 둔다는 것이다.\n낙폭 방어형과 저변동성 계열이 그렇다. 크게 벌려고 달려드는 대신 크게 잃지 않는 데 초점을 맞추는 전략들이다. 미국 시장에서 저변동성 롱온리 방식은 조건부로 검증을 통과해 지금도 페이퍼 포워드로 관찰 중이다. 다만 이것도 \u0026lsquo;확정된 승자\u0026rsquo;가 아니라 \u0026lsquo;아직 무너지지 않은 후보\u0026rsquo;로 다룬다. 정해둔 재평가 시점이 오면 다시 판정대에 올린다. 한국 시장의 같은 계열은 구간에 따라 성적이 들쭉날쭉해서 승격 근거가 부족하다고 보고 보류했다.\n여기서 얻은 감각은 분명하다. 검증을 빡빡하게 걸수록 \u0026lsquo;시장을 이기는 화려한 전략\u0026rsquo;은 대부분 걸러지고, 남는 것은 \u0026lsquo;위험을 다스리는 수수한 전략\u0026rsquo;에 가깝다는 것이다. 이건 개인적인 편향이 아니라 파이프라인이 반복해서 내놓은 결과다.\n실투입은 왜 아직도 하지 않는가 가장 자주 받을 법한 질문이다. 조건부로 살아남은 전략이 있는데 왜 실제 돈을 넣지 않는가. 답은 실투입을 이 시스템의 최상위 안전게이트로 두었기 때문이다.\n페이퍼에서 좋아 보인다는 것과 실전에 넣어도 된다는 것은 전혀 다른 문제다. 페이퍼는 잃어도 되는 돈으로 하는 연습이고, 그래서 심리적 압박도, 진짜 슬리피지도, 유동성 제약도 온전히 담기지 않는다. 실투입 기준은 의도적으로 높게 잡았다. 짧은 관찰 기간만으로는 부족하고, 시장이 실제로 무너지는 하락 국면을 페이퍼 상태로 최소 한 번은 통과해봐야 한다. 상승장에서 잘 버는 전략은 널렸지만, 하락장에서 덜 잃는지는 하락장을 겪어봐야만 알 수 있다.\n그리고 실자금을 연결하는 결정만큼은 자동화나 위임의 대상으로 두지 않았다. 다른 사소한 결정은 파이프라인이 알아서 처리하더라도, 진짜 돈을 시장에 붙이는 스위치는 사람이 직접 올리도록 남겨뒀다. 되돌리기 어려운 결정일수록 자동화의 편리함보다 사람의 확인을 앞에 두는 편이 안전하다.\n이 기록에서 남길 한 가지 이 파이프라인이 지금까지 내놓은 가장 값진 산출물은 수익이 아니라 \u0026lsquo;아니오\u0026rsquo;라고 말하는 능력이다. 좋아 보이는 전략에 돈을 넣기 전에 페이퍼 단계에서 걸러내는 것, 벤치마크를 이기지 못하는 전략을 미련 없이 보류하는 것, 자동으로 성적을 맞추려는 유혹을 참는 것. 이 세 가지가 실거래 없이도 계속 실험을 이어갈 수 있게 해주는 뼈대다.\n다시 강조하지만 이 글은 투자 권유가 아니고, 특정 종목이나 코인을 사라는 신호도 아니다. 자동매매 전략이 정말 되는지를 돈을 걸지 않고 확인하려는 개발·검증 기록일 뿐이다. 그리고 지금까지의 결론은 겸손하다. 대부분의 전략은 생각만큼 되지 않으며, 그걸 실투입 전에 알아내는 것만으로도 파이프라인은 제 값을 한다.\n이 프로젝트를 만드는 팀 크립토 매매 판단과 주식 전략 검증을 각각의 리드가 맡고, 두 갈래 모두 공용 리서치팀의 시장·전략 조사에 기대어 후보를 발굴한다.\n","permalink":"https://liquidation-man.github.io/posts/2026-07-25-%EC%95%94%ED%98%B8%ED%99%94%ED%8F%90%EC%A3%BC%EC%8B%9D-%EC%9E%90%EB%8F%99%EB%A7%A4%EB%A7%A4-%EC%A0%84%EB%9E%B5%EC%9D%84-%ED%8E%98%EC%9D%B4%ED%8D%BC%EB%A1%9C-%EA%B2%80%EC%A6%9D%ED%95%98%EB%8A%94-%EB%B0%B1%ED%85%8C%EC%8A%A4%ED%8A%B8/","summary":"\u003cp\u003e먼저 분명히 해둘 것이 있다. 이 글은 수익을 자랑하는 글이 아니고, 어떤 종목이나 코인을 사라는 이야기는 더더욱 아니다. 자동매매 전략이 \u0026lsquo;진짜로 되는가\u0026rsquo;를 실거래 없이 걸러내려고 만든 검증 파이프라인의 개발·실험 기록이다. 실제 돈은 한 푼도 들어가지 않았고, 모든 실행은 백테스트와 페이퍼(모의) 포워드테스트로만 이뤄졌다. 등장하는 판정도 \u0026lsquo;이 전략은 벌어준다\u0026rsquo;가 아니라 \u0026lsquo;이 전략은 벤치마크를 이기지 못해서 보류했다\u0026rsquo; 쪽이 훨씬 많다. 투자 조언이 아니라 개발과 검증의 기록으로 읽어달라.\u003c/p\u003e","title":"트레이딩 봇 — 전략을 페이퍼로 검증했다"},{"content":"프로젝트가 하나일 땐 에이전트 하나로 충분했다. 자동매매 봇, 콘텐츠 자동화, 게임, 문서 제작, AI 생성까지 늘어나자 그 하나가 무너졌다. 한 세션에서 매매 전략을 판단하다가 다음 순간 문서 조판을 고민하면, 어느 쪽도 깊게 못 판다. 그래서 한 명의 만능 에이전트를 버리고, 역할을 나눈 조직으로 재설계했다.\n왜 만능 에이전트가 한계였나 만능 에이전트의 문제는 능력이 아니라 맥락 오염이었다. 크립토 매매의 리스크 감각과 전자책 문체 교정은 완전히 다른 판단 회로다. 한 컨텍스트에 둘을 섞으면 프롬프트가 길어지고, 도메인 지식이 서로를 밀어낸다. \u0026ldquo;이 전략이 우리 리스크 한도에 맞나\u0026quot;를 묻는 순간과 \u0026ldquo;이 표현이 자연스러운가\u0026quot;를 묻는 순간이 같은 머리에서 나오면 둘 다 얕아진다.\n해법은 분업이었다. 다만 사람 조직처럼, 누가 무엇을 최종 판단하는지 경계를 코드로 못 박는 것이 핵심이었다.\n총괄은 판단하지 않는다 맨 위에 총괄 에이전트를 뒀지만, 총괄은 도메인 판단을 하지 않는다. 순수 라우터다. 요청이 오면 \u0026ldquo;이건 어느 프로젝트 리드 소관인가\u0026quot;만 정해서 위임하고, 여러 프로젝트에 걸친 요청은 관련 리드에게 나눠 시킨 뒤 결과만 취합해 보고한다.\n총괄이 매매 승인이나 고객 응대 문구를 직접 정하지 않는 이유는 명확하다. 총괄이 모든 도메인 지식을 다 아는 건 비효율이고, 한 곳에서 다 판단하면 처음의 맥락 오염으로 되돌아간다. 총괄의 유일한 전문성은 분류와 취합이다.\n프로젝트 리드: 도메인 최종 판단권자 각 프로젝트에는 리드가 있다. 자동매매, 주식 검증, 증시 콘텐츠, 프리랜서 업무, 문서 제작, 게임 개발이 각자의 리드를 가진다. 리드는 그 도메인의 최종 판단권자다. 매매를 실행할지, 콘텐츠를 승인할지, 게임의 \u0026lsquo;재미\u0026rsquo;를 어떻게 조율할지는 전부 해당 리드가 정한다.\n리드는 자기 밑의 팀원(또는 공유팀)을 호출해 일을 시킨다. 여기서 중요한 기술적 결정이 하나 있었다. 서브에이전트의 중첩 위임이다.\n공유 기능팀: 재사용되는 역량 프로젝트마다 겹치는 일이 있다. 시장 리서치, 영상 제작, 업로드 인프라, 문서 작성 같은 것들이다. 이걸 프로젝트마다 새로 만들면 정의가 여러 곳으로 흩어진다. 그래서 공유 기능팀을 한 곳에만 정의하고, 여러 리드가 재사용한다.\n경계는 신경 써서 그었다. 예를 들어 \u0026ldquo;정해진 스키마를 채우는 정형 수집\u0026quot;과 \u0026ldquo;답이 정해지지 않은 리서치\u0026quot;는 겉보기엔 같은 조사처럼 보이지만 다른 팀이다. 매일 도는 정형 작업은 프로젝트 고유 역할이, 일회성 탐색은 공유 리서치팀이 맡는다. 이 경계가 흐려지면 같은 일을 두 곳에서 하게 된다.\ngatekeeper: 외부로 나가는 모든 것의 단일 관문 가장 중요한 노드는 gatekeeper다. 스케줄 등록, 배포, 외부 공개 업로드 — 되돌리기 어려운 모든 행위는 총괄이든 리드든 스스로 판단해서 진행할 수 없다. 반드시 gatekeeper에게 계획을 보여주고 승인받은 뒤에만 실행한다.\n이 관문을 둔 이유는 사고 경험 때문이다. 검수 없이 자동 공개된 산출물이 문제가 된 적이 있었고, 그 뒤로 \u0026ldquo;외부로 나가는 것\u0026quot;과 \u0026ldquo;실제 돈이 오가는 것\u0026quot;은 반드시 별도 승인을 거치게 했다. gatekeeper는 승인만 하는 게 아니라, 각 에이전트가 자기 역할대로 실제로 일했는지 감사도 한다.\n중첩 위임과 상속을 어떻게 켰나 이 조직이 실제로 돌려면 두 가지 기술 결정이 필요했다.\n첫째, 중첩 위임이다. 총괄이 리드를 부르고, 리드가 다시 팀원을 부르는 2계층 위임은 기본적으로 꺼져 있다. 서브에이전트가 또 서브에이전트를 부르는 걸 막아두는 게 기본값이기 때문이다. 이걸 환경변수로 켜서 총괄→리드→팀원의 2계층을 허용했다. 이 값을 지우면 리드가 팀원을 못 부르고 혼자 처리하게 되므로, 조직이 조직으로 작동하려면 이 설정이 살아 있어야 한다.\n둘째, 정의의 상속이다. 공유 기능팀을 프로젝트마다 복사하지 않는다. 상위 폴더 한 곳에 에이전트 정의를 두면, 하위의 모든 프로젝트가 경로를 거슬러 올라가며 그 정의를 자동으로 상속한다. 같은 이름을 하위에 다시 두면 작업 디렉토리에 가장 가까운 정의가 이긴다 — 특정 프로젝트에서만 공유팀 동작을 바꾸고 싶으면 그 프로젝트 폴더에 같은 이름으로 덮어쓰면 된다. 그래서 이름은 트리 전체에서 유일하게 유지한다. 심볼릭 링크도, 동기화 스크립트도 필요 없다.\n이 두 가지가 없으면 조직도는 그림일 뿐이고, 실제로는 총괄 혼자 다 하는 원점으로 돌아간다.\n완료를 어떻게 판정하나 분업만큼 중요한 게 판정이었다. 각 프로젝트는 \u0026ldquo;고쳐줘\u0026quot;라는 요청을 **\u0026ldquo;무엇이 참이면 고쳐진 것인가\u0026rdquo;**라는 검증 기준으로 바꾼 뒤, 그게 실제로 참이 될 때까지 반복한다. \u0026ldquo;아마 될 겁니다\u0026quot;로 끝내지 않는다. 검증에 실패했으면 실패했다고 그대로 보고한다. 추측으로 빈 값을 그럴듯하게 채우지 않고, 못 구한 건 \u0026ldquo;못 구했다\u0026quot;고 멈춘다. 이 규칙이 없으면 자동화는 조용히 틀린 결과를 쌓는다.\n이 구조가 준 것 세 가지가 달라졌다. 첫째, 각 판단이 깊어졌다. 도메인 리드가 자기 영역만 보니 프롬프트가 짧고 정확해졌다. 둘째, 되돌리기 어려운 사고가 줄었다. gatekeeper라는 단일 관문이 공개·배포를 전부 걸러낸다. 셋째, 역량이 재사용됐다. 공유팀을 한 번 만들면 모든 프로젝트가 상속받는다.\n무엇보다, 사람은 총괄하고만 대화하면 된다. 나머지 분업은 조직 안에서 알아서 흐른다. 이 블로그의 글도 그 조직의 산출물이다.\n이 조직의 전체 구조 ","permalink":"https://liquidation-man.github.io/posts/2026-07-25-%EB%B6%80%EC%97%85-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EB%A5%BC-%EB%A9%80%ED%8B%B0-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EC%A1%B0%EC%A7%81%EC%9C%BC%EB%A1%9C-%EA%B5%B4%EB%A6%AC%EB%8A%94/","summary":"\u003cp\u003e프로젝트가 하나일 땐 에이전트 하나로 충분했다. 자동매매 봇, 콘텐츠 자동화, 게임, 문서 제작, AI 생성까지 늘어나자 그 하나가 무너졌다. 한 세션에서 매매 전략을 판단하다가 다음 순간 문서 조판을 고민하면, 어느 쪽도 깊게 못 판다. 그래서 \u003cstrong\u003e한 명의 만능 에이전트를 버리고, 역할을 나눈 조직으로 재설계\u003c/strong\u003e했다.\u003c/p\u003e","title":"개발 인프라 — 멀티 에이전트 조직으로 운영한다"},{"content":"세 줄 요약 매일 작업 내역을 수집해 글로 만들고 자동 발행하는 블로그 파이프라인을 플랫폼 선정부터 계정 인증까지 정의했다. 발행 채널은 GitHub Pages(Hugo + PaperMod)로 확정. 어제 여러 세션에서 각각 수정한 내용이 충돌해 전부 날아간 사고 때문에, 자동 커밋과 자동 발행의 실행 순서를 다시 짰다. 커밋 23:30 → 발행 00시. 이 글의 수집 데이터에는 커밋이 0건, 변경 라인이 +0/-0, 프로젝트 집계가 \u0026ldquo;없음\u0026quot;으로 잡혔다. 파이프라인이 자기 자신을 만드는 첫 회차라서 그렇다. 1. 개발일지 블로그를 \u0026ldquo;완전 무인\u0026quot;으로 정의했다 오늘의 본 작업은 코드가 아니라 정의였다. 요구사항은 명확했다. 매일 여러 프로젝트를 오가며 작업하는데, 그날 무엇을 했는지가 자동으로 글이 되고, 정해진 시간에 자동으로 올라가야 한다. 사람이 붙는 구간이 하나라도 상시로 남으면 그건 무인이 아니라 그냥 반자동이다. 최종 목표는 방문자 유입을 통한 광고 수익화다.\n플랫폼은 GitHub Pages 정적 블로그로 못 박았다. 테마는 PaperMod. 선정 근거는 취향이 아니라 자동화 가능성 한 줄이다.\ngit push 하나로 배포가 끝난다. 로그인 폼도, 캡차도, 세션 만료도 없다.\n워드프레스나 티스토리 같은 호스팅형 플랫폼은 글을 올리는 순간이 곧 브라우저 자동화 구간이 된다. 로그인 세션이 만료되면 파이프라인은 조용히 멈추고, 그 사실을 며칠 뒤에 알게 된다. 정적 사이트 + git push 조합은 실패해도 exit code로 튀어나온다. 무인 운영에서 \u0026ldquo;조용히 실패하지 않는 것\u0026quot;은 \u0026ldquo;빠른 것\u0026quot;보다 훨씬 중요하다.\nGitHub 계정은 liquidation-man으로 잡았고, 여기서 파생된 원칙이 하나 더 붙었다. 개인정보는 전부 가린다. 금액, 계정 식별자, API 키, 고객 정보는 수집 단계에서 마스킹 토큰으로 치환된 상태로 글 생성기에 들어온다. 생성기는 원문을 볼 수 없고, 복원할 방법도 없다. 참고로 오늘 넘어온 데이터에는 마스킹 토큰이 하나도 등장하지 않았다. 오늘 다룬 소재 자체에 민감정보가 없었다는 뜻이다.\n2. 진짜 문제는 시각이 아니라 순서였다 어제 사고가 있었다. 여러 세션에서 같은 저장소를 동시에 건드렸고, 자동 커밋이 돌 때 충돌이 나면서 수정 사항이 통째로 유실됐다. 그래서 오늘 먼저 한 일이 \u0026ldquo;오늘 자동 커밋 되기 전에 충돌이 없는지 판단\u0026quot;이었다. 커밋을 실행하는 게 아니라, 커밋이 안전한 상태인지를 선행 점검하는 단계를 앞에 세운 것이다.\n그다음이 순서 재배치다. 블로그 자동화를 매일 23시에 돌리기로 했었는데, 이 상태에는 구조적 결함이 있다.\n23:00 — 오늘 작업을 요약해 글을 쓴다 23:xx — 자동 커밋이 오늘 작업을 저장소에 반영한다 글이 먼저 나가고 커밋이 나중에 붙으면, 글은 항상 오늘의 마지막 작업을 놓친다. 수집기가 보는 것은 커밋 로그인데, 아직 커밋되지 않은 작업은 존재하지 않는 것과 같다. 그래서 순서를 뒤집었다. 커밋 23:30, 발행 00시. 하루 치 작업이 전부 저장소에 들어간 뒤에 그걸 읽어서 글을 만든다.\n여기서 정직하게 남겨둘 것이 하나 있다. \u0026ldquo;자동 커밋은 며칠 주기 몇 시로 스케줄링돼 있는지\u0026rdquo; 현재 등록값을 확인하는 작업을 요청했지만, 그 조회 결과는 오늘 수집 데이터에 남아 있지 않다. 실제 스케줄러 등록이 커밋 23:30 / 발행 00시로 반영 완료됐는지는 이 글 시점에서 확인 못 함. 그리고 이 글 자체의 타임스탬프는 2026-07-25T23:30:00+09:00이다. 목표한 00시가 아니라 커밋과 같은 시각이다. 즉 순서 역전 위험이 아직 남아 있고, 내일 첫 항목으로 검증해야 한다.\nWindows 작업 스케줄러에 파이썬 스크립트를 등록해 자동 실행하는 구성에서 사람들이 대개 신경 쓰는 건 트리거 시각과 반복 주기다. 하지만 여러 자동화가 같은 저장소를 공유하는 순간 진짜 변수는 작업 간 선후 관계가 된다. 두 작업이 30분 간격으로 등록돼 있어도, 앞 작업이 40분 걸리면 순서는 그냥 뒤집힌다. 시각으로 순서를 흉내 내는 대신, 뒤 작업이 앞 작업의 산출물(커밋 해시)을 확인하고 시작하게 만드는 편이 안전하다.\n3. 무인 파이프라인에 딱 하나 남은 사람 개입 구간 gh auth login. GitHub CLI 인증은 브라우저를 띄워 사람이 승인해야 한다. 자동화로 우회할 수 있는 성격이 아니고, 우회해서도 안 되는 구간이다.\n그래서 오늘 진행 방식은 \u0026ldquo;순서대로 하되, 인증 단계에서는 브라우저를 띄우고 사람이 직접 승인\u0026quot;이었다. 이 지점을 없애려 애쓰는 대신 최초 1회로 몰아넣고 명시하는 쪽을 택했다. 한 번 인증하면 이후 push는 저장된 자격증명으로 돌아간다. 무인 자동화라는 말은 사람이 0번 개입한다는 뜻이 아니라, 정상 동작 중에는 0번이라는 뜻이다.\n4. 게임 프로젝트는 원점으로 되돌렸다 병렬로 진행 중인 로그라이크 게임 쪽에서는 정반대 방향의 결정이 나왔다. \u0026ldquo;뭐 하는 게임인지 모르겠다, 목표가 뭔지, 위험요소가 뭔지, 재미 요소도 그렇고\u0026rdquo; — 기획을 다시 하기로 했다.\n만들다 만 것을 이어 붙이는 것보다, 한 줄 정의가 안 나오는 상태에서 코드를 더 쌓는 게 훨씬 비싸다. 플레이어가 무엇을 원하고, 무엇이 그걸 막고, 실패하면 무엇을 잃는지가 정리되지 않으면 밸런싱 수치는 근거 없는 숫자일 뿐이다. 오늘은 재기획 착수까지이고, 산출된 기획 문서는 아직 데이터에 없다.\n막혔던 것들 문제 대응 세션 간 동시 수정 → 커밋 충돌로 작업 유실 커밋 전 충돌 선행 점검 단계 추가 발행이 커밋보다 먼저 돌아 마지막 작업 누락 커밋 23:30 → 발행 00시로 순서 재배치 gh auth login은 비대화형 실행 불가 최초 1회 수동 인증으로 격리, 이후 토큰 사용 수집 결과가 커밋 0건 / 프로젝트 없음 원인 미확인 — 내일 수집기 커버리지 점검 오늘 배운 것 하나. 무인 자동화가 깨지는 지점은 대부분 각 작업이 잘못 동작해서가 아니라, 서로의 순서를 잘못 가정해서다. 어제의 유실 사고도, 오늘의 커밋 0건도 전부 순서 문제였다.\n둘. 파이프라인이 자기 자신을 관측 대상에 포함하면 첫 회차는 반드시 비어 보인다. 오늘 총계가 커밋 0개 · +0/-0 라인으로 찍힌 건 아무 일도 안 해서가 아니라, 오늘 한 일이 \u0026ldquo;그 일을 기록하는 장치\u0026quot;였기 때문이다. 이럴 때 빈 데이터를 그럴듯한 수치로 채우면 그 순간부터 이 블로그의 모든 숫자는 신뢰를 잃는다. 없으면 없다고 쓰는 게 유일하게 지속 가능한 선택이다.\n셋. 사람이 반드시 필요한 구간은 제거 대상이 아니라 격리 대상이다.\n내일 할 일 Windows 작업 스케줄러 실제 등록값 조회 — 커밋 23:30, 발행 00시가 맞게 들어갔는지 확인. 오늘 미확인 상태. 수집기 커버리지 점검 — 프로젝트 집계가 \u0026ldquo;없음\u0026quot;으로 나온 원인 파악. 커밋이 없어서인지, 수집 경로가 좁아서인지 구분. 첫 자동 발행 실검증 — 사람 개입 없이 글 생성부터 git push, GitHub Pages 빌드까지 통과하는지. 게임 프로젝트 한 줄 정의 작성 — 목표 / 위험요소 / 재미 요소 세 항목부터. ","permalink":"https://liquidation-man.github.io/posts/2026-07-25-%EC%9E%90%EB%8F%99-%EC%BB%A4%EB%B0%8B-2330-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EB%B0%9C%ED%96%89-00%EC%8B%9C/","summary":"\u003ch2 id=\"세-줄-요약\"\u003e세 줄 요약\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e매일 작업 내역을 수집해 글로 만들고 자동 발행하는 블로그 파이프라인을 플랫폼 선정부터 계정 인증까지 정의했다. 발행 채널은 GitHub Pages(Hugo + PaperMod)로 확정.\u003c/li\u003e\n\u003cli\u003e어제 여러 세션에서 각각 수정한 내용이 충돌해 전부 날아간 사고 때문에, 자동 커밋과 자동 발행의 \u003cstrong\u003e실행 순서\u003c/strong\u003e를 다시 짰다. 커밋 23:30 → 발행 00시.\u003c/li\u003e\n\u003cli\u003e이 글의 수집 데이터에는 커밋이 0건, 변경 라인이 +0/-0, 프로젝트 집계가 \u0026ldquo;없음\u0026quot;으로 잡혔다. 파이프라인이 자기 자신을 만드는 첫 회차라서 그렇다.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"1-개발일지-블로그를-완전-무인으로-정의했다\"\u003e1. 개발일지 블로그를 \u0026ldquo;완전 무인\u0026quot;으로 정의했다\u003c/h2\u003e\n\u003cp\u003e오늘의 본 작업은 코드가 아니라 정의였다. 요구사항은 명확했다. 매일 여러 프로젝트를 오가며 작업하는데, 그날 무엇을 했는지가 \u003cstrong\u003e자동으로\u003c/strong\u003e 글이 되고, \u003cstrong\u003e정해진 시간에 자동으로\u003c/strong\u003e 올라가야 한다. 사람이 붙는 구간이 하나라도 상시로 남으면 그건 무인이 아니라 그냥 반자동이다. 최종 목표는 방문자 유입을 통한 광고 수익화다.\u003c/p\u003e","title":"개발일지 파이프라인 — 발행 순서를 재배치했다"},{"content":"지하철 문이 열리는 순간, 등 뒤에서 밀려드는 인파가 하나의 물결처럼 느껴진 적이 있다면 이 게임의 출발점을 이미 아는 셈이다. \u0026lsquo;지옥철\u0026rsquo;은 서울 출근길을 뱀서라이크(Vampire Survivors류) 실시간 생존 장르로 풍자하는 브라우저 로그라이크다. 플레이어의 목표는 단 하나, 몰려오는 인파를 헤치고 오전 9시까지 회사에 도착하는 것이다. 무기는 총도 칼도 아닌 \u0026lsquo;헛기침\u0026rsquo;이고, 체력바 대신 멘탈 게이지가 바닥나면 그 자리에서 무너진다.\n왜 카드 덱빌딩을 버리고 뱀서라이크로 갈아탔나 처음 기획서에 적혀 있던 \u0026lsquo;지옥철\u0026rsquo;은 지금과 완전히 다른 게임이었다. 턴제 카드 덱빌딩, 그러니까 한 턴에 손패를 내고 다음 칸으로 이동하는 슬레이 더 스파이어 계열이었다. 출근이라는 소재와 카드의 \u0026lsquo;선택과 자원 관리\u0026rsquo;가 잘 붙을 거라는 가설이었지만, 초기 플레이테스트에서 치명적인 위화감이 드러났다. 출근길의 핵심 감각은 \u0026lsquo;차분히 손패를 고르는 것\u0026rsquo;이 아니라 \u0026lsquo;숨 돌릴 틈 없이 밀려나는 것\u0026rsquo;이었다. 턴이 끊기는 순간 그 압박감이 통째로 증발했다.\n그래서 카드 시스템을 통째로 폐기했다. 대신 화면 사방에서 인파가 실시간으로 쏟아지고, 플레이어는 멈추지 않고 움직이며 자동으로 나가는 헛기침으로 길을 여는 뱀서라이크 실시간 액션으로 피벗했다. 결정을 내리는 단위가 \u0026lsquo;턴\u0026rsquo;에서 \u0026lsquo;초\u0026rsquo;로 바뀌자, 소재가 요구하던 압박감이 비로소 게임 메커닉과 맞아떨어졌다. 기획에서 \u0026lsquo;재미\u0026rsquo;의 최종 판단은 언제나 이 지점에서 갈린다. 문서상 그럴듯한 조합보다, 손으로 만져봤을 때 소재의 감각이 살아나는지가 기준이다.\nGodot 프로젝트를 index.html 한 장으로 갈아엎은 이유 기술 스택도 한 번 크게 뒤집혔다. 원래는 Godot 4와 GDScript로 시작했다. 그런데 이 게임은 외부 이미지 에셋이 사실상 필요 없는 구조였다. 캐릭터도, 인파도, 아이템도 전부 이모지 스프라이트와 캔버스 연출로 표현하기로 했기 때문이다. 외부 이미지 에셋은 결국 0개였다. 무거운 엔진 런타임과 에디터, 익스포트 파이프라인을 짊어질 이유가 옅어진 것이다.\n결론은 순수 index.html 한 장, vanilla JS, Canvas 2D로의 전면 전환이었다. 지금 게임 전체가 1,691줄의 코드 한 뭉치로 돌아간다. 빌드 단계가 없으니 파일을 브라우저에 던지면 그대로 실행되고, 배포는 정적 호스팅에 파일 하나 올리는 것으로 끝난다. 로그라이크 코어 루프에 필요한 것은 화려한 엔진 기능이 아니라 매 프레임 안정적으로 도는 게임 루프와 렌더 한 줄이었고, Canvas 2D는 그 요구에 정확히 맞았다.\n아트 방향도 이 전환과 한 몸이다. 플레이어는 넥타이 이모지, 몰려드는 인파는 사람 이모지, 헛기침은 물방울 이모지처럼, 화면 위 모든 개체가 유니코드 문자 하나에서 출발한다. 여기에 흔들림, 밀려남, 잔상 같은 캔버스 연출을 얹어 \u0026lsquo;살아 움직이는\u0026rsquo; 느낌을 만든다. 이미지 파일을 그리지 않으니 다운로드할 것도, 로딩 스피너도 없다. 브라우저 탭을 여는 즉시 게임이 손에 잡히는 것, 그 즉시성이 애초에 이 스택을 고른 이유이기도 하다.\n아래는 M1에서 완성한 코어 루프의 뼈대다. 이 순환이 매 프레임 반복되면서 인파가 몰려오고, 헛기침이 나가고, 경험치가 쌓인다.\n밀려드는 인파 속에서 60fps는 어떻게 지켰나 뱀서라이크의 생명은 화면을 가득 채우는 적의 물량이다. 그런데 브라우저에서 수십 개의 개체를 매 프레임 그리면서 60fps를 유지하는 것은 만만치 않다. 여기서 세 가지 최적화가 결정적이었다.\n첫째, 이모지 렌더링이다. 캔버스에서 이모지를 그릴 때 가장 흔한 실수가 매 프레임 fillText를 호출하는 것이다. 텍스트 렌더링은 생각보다 비싸서, 개체가 늘어나면 프레임이 뚝뚝 떨어진다. 그래서 각 이모지를 게임 시작 시 오프스크린 캔버스에 딱 한 번 그려 스프라이트로 캐싱해 두고, 이후에는 drawImage로 그 비트맵을 복사만 한다. 매 프레임 폰트 래스터라이저를 부르는 대신, 이미 구워둔 그림을 옮기는 셈이다.\n둘째, 오브젝트 풀링이다. 인파와 헛기침 투사체는 끊임없이 생성되고 사라진다. 이걸 매번 new로 만들고 버리면 가비지 컬렉터가 주기적으로 개입해 프레임을 갉아먹는 GC 스파이크가 생긴다. 그래서 개체를 미리 만들어 풀에 담아두고, 필요할 때 꺼내 쓰고 죽으면 반납하는 방식으로 바꿨다. 할당과 해제가 사라지자 프레임 그래프의 톱니 모양 스파이크도 함께 사라졌다.\n셋째, 충돌 판정이다. 모든 인파와 모든 투사체를 짝지어 검사하면 개체 수의 제곱, 즉 O(n²)로 비용이 폭증한다. 대신 화면을 격자 셀로 나누는 스페이셜 해시를 도입해, 한 개체는 자기가 속한 셀과 근접 셀만 검사한다. 화면 반대편에 있는 인파와는 애초에 비교조차 하지 않는다. 이 세 가지를 합친 결과가 동시 개체 15기 기준 60fps, 콘솔 에러 0이라는 검증 수치다.\n9시까지 도착, 시계를 밸런스의 축으로 삼다 M1이 \u0026lsquo;손맛 나는 코어\u0026rsquo;였다면, 지금 진행 중인 M2는 그 위에 \u0026lsquo;출근\u0026rsquo;이라는 서사를 얹는 런 구조 단계다. 스테이지는 6개 구간으로 나뉘고, 게임 내 시계가 오전 7시 30분에서 9시를 향해 흐른다. 이 시계가 단순한 장식이 아니라 밸런스의 중심축이라는 점이 이 게임의 특징이다.\n플레이어에게는 급행과 완행이라는 선택지가 주어진다. 시계는 코드 상수로 설계했는데, 완행만 타면 9시 4분에 도착해 지각하고, 급행을 두 번 타면 8시 52분에 도착해 세이프하다. 즉 \u0026lsquo;빠른 경로는 더 위험하고 붐비지만 시간을 번다\u0026rsquo;는 리스크와 보상의 축이 시계 하나로 성립한다. 여기에 우산이나 노이즈 캔슬링 헤드폰 같은 환경 아이템, 급행과 완행에 따라 다른 혼잡도를 얹으면서 매 판이 다른 출근길이 되도록 만드는 중이다. 상단 HUD에는 현재 시각과 남은 구간, 멘탈 상태가 한눈에 들어온다.\n레벨업 설계도 뱀서라이크 문법을 따른다. 경험치가 차면 3개의 강화 옵션 중 하나를 고르는 3택 방식이다. 헛기침의 범위를 넓힐지, 이동 속도를 올릴지, 멘탈 회복을 챙길지를 매번 선택하면서 한 판 안에서 캐릭터가 성장한다. M3부터 M5까지는 아직 착수 전이라, 지금 공개하는 건 코어가 확실히 돌아가는 뼈대와 그 위에 얹히기 시작한 런 구조까지다.\n환경 아이템도 시계와 짝을 이룬다. 우산은 비 오는 구간에서 시야와 이동을 지켜주는 방패 역할이고, 노이즈 캔슬링 헤드폰은 멘탈이 깎이는 속도를 늦춰준다. 급행이 붐비는 대신 시간을 벌어주는 것처럼, 아이템 하나하나가 \u0026lsquo;무엇을 포기하고 무엇을 얻을지\u0026rsquo;라는 선택을 만든다. 이 선택들이 겹치면서 완행 위주의 안전한 지각 회피 빌드와 급행 돌파형 고위험 빌드가 갈리고, 같은 6구간이라도 매 판의 출근길이 달라진다.\n무엇을 넣지 않기로 했는가 풍자 게임에서 가장 조심해야 하는 건 웃음의 방향이다. 출근길이라는 소재는 자칫 사회적 약자를 조롱의 대상으로 삼기 쉽다. \u0026lsquo;지옥철\u0026rsquo;은 여기서 분명한 선을 그었다. 임산부, 휠체어 이용자, 노숙인 같은 존재는 절대 적이나 조롱의 대상이 되지 않는다.\n대신 이들은 상황과 환경 요소로만 등장한다. 예를 들어 임산부석은 잠깐 멘탈을 회복할 수 있는 회복존으로 작동한다. 게임이 겨냥하는 풍자의 표적은 \u0026lsquo;사람\u0026rsquo;이 아니라 \u0026lsquo;지옥 같은 출근 시스템 그 자체\u0026rsquo;다. 무엇을 넣느냐만큼 무엇을 넣지 않기로 했는가를 밝히는 것이, 이런 소재를 다루는 팀이 스스로에게 지우는 최소한의 책임이라고 본다.\n패배 조건도 이 원칙 위에 서 있다. 지는 방법은 두 가지다. 하나는 밀려드는 압박을 견디지 못해 멘탈이 붕괴하는 것, 다른 하나는 시계가 9시를 넘겨 지각하는 것이다. 둘 다 \u0026lsquo;출근에 실패했다\u0026rsquo;는 하나의 감정으로 수렴한다. 그리고 패배 화면은 좌절로 끝나지 않고 \u0026lsquo;다시 출근하기\u0026rsquo; 버튼으로 곧장 재도전을 유도한다. 로그라이크의 본질은 실패를 통해 다음 판을 준비하는 리듬에 있다.\n두 패배 조건이 나뉘어 있다는 점도 의도된 설계다. 멘탈 붕괴는 \u0026lsquo;너무 무리하게 인파를 뚫었다\u0026rsquo;는 신호이고, 지각은 \u0026lsquo;너무 몸을 사려 시간을 못 벌었다\u0026rsquo;는 신호다. 한쪽으로 치우친 플레이는 각기 다른 방식으로 벌을 받는다. 그래서 잘 죽은 판일수록 다음 판에서 무엇을 바꿔야 할지가 선명해지고, 플레이어는 \u0026lsquo;조금만 더 빨리 탈걸\u0026rsquo; 하며 자연스럽게 재도전 버튼으로 손이 간다.\n다음 정거장은 어디인가 지금까지의 좌표를 정리하면 이렇다. 장르는 카드 덱빌딩에서 뱀서라이크로, 스택은 Godot 4에서 순수 브라우저 코드로, 두 번의 큰 방향 전환을 거쳐 지금의 형태에 도달했다. 코어를 담당한 M1은 게임 루프, 이동, 인파 스폰과 추적, 헛기침 오토 어택, 3택 레벨업, 멘탈 HP, 그리고 무엇보다 손맛까지 완성한 상태다. 런 구조를 담당하는 M2는 6구간과 게임 내 시계, 급행과 완행, HUD, 우산과 노이즈 캔슬링 같은 요소를 얹는 중이다.\n앞으로 남은 M3에서 M5까지는 콘텐츠 확장과 메타 진행, 다듬기의 영역이다. 브라우저에서 열자마자 30초 안에 \u0026lsquo;아, 이거 딱 내 출근길이네\u0026rsquo; 하고 웃게 만드는 것이 이 게임의 완성 기준이다. 그 웃음이 조롱이 아니라 공감에서 나오도록, 시계와 인파와 헛기침이라는 세 축을 계속 다듬어 나갈 예정이다.\n이 프로젝트를 만드는 팀 game-lead — 기획과 규칙 최종 결정, \u0026lsquo;재미\u0026rsquo;의 최종 판단. game-design-team — 규칙과 밸런스, 절차생성 스펙 설계. game-code-team — Godot 및 vanilla JS 구현. game-code-reviewer — 독립 코드 리뷰로 스펙과 구현을 교차검증. game-asset-team — 그래픽과 사운드 에셋 제작. game-playtest-team — 클리어타임과 사망률 등 수치 완료조건 자동테스트. ","permalink":"https://liquidation-man.github.io/posts/2026-07-25-%EC%B6%9C%EA%B7%BC%EA%B8%B8-%EC%83%9D%EC%A1%B4%EC%9D%84-%EB%B1%80%EC%84%9C%EB%9D%BC%EC%9D%B4%ED%81%AC%EB%A1%9C-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EB%A1%9C%EA%B7%B8%EB%9D%BC%EC%9D%B4%ED%81%AC-%EC%A7%80%EC%98%A5%EC%B2%A0/","summary":"\u003cp\u003e지하철 문이 열리는 순간, 등 뒤에서 밀려드는 인파가 하나의 물결처럼 느껴진 적이 있다면 이 게임의 출발점을 이미 아는 셈이다. \u0026lsquo;지옥철\u0026rsquo;은 서울 출근길을 뱀서라이크(Vampire Survivors류) 실시간 생존 장르로 풍자하는 브라우저 로그라이크다. 플레이어의 목표는 단 하나, 몰려오는 인파를 헤치고 오전 9시까지 회사에 도착하는 것이다. 무기는 총도 칼도 아닌 \u0026lsquo;헛기침\u0026rsquo;이고, 체력바 대신 멘탈 게이지가 바닥나면 그 자리에서 무너진다.\u003c/p\u003e","title":"지옥철 — 출근길을 뱀서라이크로 만들었다"},{"content":"발표 자료를 외주로 받아본 사람은 비슷한 경험이 있다. 파일을 열어 오타 하나를 고치려는데 슬라이드 전체가 한 장의 PNG로 박혀 있어서 글자를 클릭할 수 없다. 결국 발주자가 캡션 위에 텍스트 상자를 덧대거나, 다시 수정을 요청하는 왕복이 시작된다. doc-maker는 이 왕복을 없애는 것을 첫 번째 설계 목표로 잡았다. 주제 한 줄을 입력하면 자료조사와 구성, 슬라이드 디자인을 거쳐 파워포인트와 워드에서 글자를 직접 고칠 수 있는 산출물이 나온다. 아래는 그 과정과 품질 게이트를 실제 빌드물 기준으로 정리한 글이다.\n주제 한 줄만 던졌을 때 안에서 벌어지는 일 입력은 \u0026ldquo;2분기 신규 구독 지표 요약 20장\u0026rdquo; 같은 한 줄이면 충분하다. 이 한 줄이 들어오면 파이프라인은 곧장 슬라이드를 그리지 않는다. 먼저 주제를 자료조사 단계로 넘겨 근거가 될 항목을 모으고, 그다음 구성 단계에서 20장을 어떤 논점 순서로 배치할지 뼈대를 짠다. 표지 1장, 핵심 요약 1장, 지표 상세 여러 장, 마무리 1장 같은 흐름이 이 단계에서 결정된다. 구성이 확정된 뒤에야 디자인 단계가 각 장의 레이아웃을 채운다. 순서를 이렇게 고정한 이유는 단순하다. 논점 배치가 흔들린 상태에서 예쁜 슬라이드를 먼저 만들면, 나중에 순서를 바꿀 때 디자인을 통째로 다시 손봐야 하기 때문이다.\n이 다섯 칸이 파이프라인의 등뼈다. 왼쪽 끝의 한 줄짜리 주제가 오른쪽 끝의 검증된 파일로 바뀌는 동안, 각 칸은 앞 칸의 결과만 신뢰하고 자기 일만 한다. 구성 단계는 자료조사가 모은 항목이 사실인지 다시 따지지 않고, 디자인 단계는 구성이 정한 순서를 임의로 바꾸지 않는다. 이렇게 책임을 나눠두면 결과가 이상할 때 어느 칸에서 틀어졌는지 바로 짚을 수 있다.\n파일을 열어 글자를 클릭했을 때 실제로 수정되는가 doc-maker의 가장 큰 차별점은 산출물이 이미지 박제가 아니라는 데 있다. 표지의 제목, 데이터 슬라이드의 숫자, 본문 문단까지 전부 파워포인트와 워드 안에서 커서를 올리고 직접 타이핑해 고칠 수 있다. 발주자가 회사명을 바꾸거나 수치를 최신값으로 갱신할 때 새로 의뢰할 필요가 없다는 뜻이다.\n이 성질을 말로만 보장하지 않고 기계로 검증한다. pptx는 내부적으로 여러 XML 조각을 압축한 묶음인데, 슬라이드의 실제 글자는 \u0026lt;a:t\u0026gt; 태그 안에 들어간다. verify_pptx는 빌드된 파일을 풀어 이 \u0026lt;a:t\u0026gt; 태그에서 실제 텍스트가 나오는지 확인하고, 동시에 ppt/media 폴더에 이미지가 박혀 있지 않은지 검사한다. 글자가 이미지로 구워졌다면 \u0026lt;a:t\u0026gt;에는 아무 텍스트도 없고 ppt/media에 PNG만 잔뜩 쌓인다. 그래서 이 두 조건을 함께 보면 \u0026ldquo;편집 가능한 텍스트로 만들어졌는가\u0026quot;를 정확히 판정할 수 있다. 워드 쪽도 같은 원리로, verify_docx가 본문 글자가 담기는 \u0026lt;w:t\u0026gt; 태그의 실제 텍스트와 word/media의 부재를 확인한다.\n급하게 렌더만 하고 넘겼다가 사고가 나는 지점 \u0026ldquo;렌더했다\u0026quot;와 \u0026ldquo;검수했다\u0026quot;는 다른 말이다. 브라우저에서 슬라이드가 그럴듯하게 보였다고 해서 pptx로 변환된 파일도 멀쩡하다는 보장은 없다. 특히 자주 터지는 사고가 슬라이드 재줄바꿈이다. HTML에서는 한 줄에 들어가던 긴 제목이 pptx 폰트 메트릭에서는 폭을 넘겨 두 줄이 되고, 그 바람에 아래 요소를 밀어내 레이아웃이 깨진다. 캡션이 슬라이드 밖으로 삐져나가거나 데이터 표가 다음 장을 침범하는 식이다.\ndoc-maker는 이런 조판 사고를 막기 위해 빌드 뒤에 실제 파일을 열어 육안과 자동 검사를 함께 돌린다. 텍스트가 지정한 박스를 벗어나지 않았는지, 제목이 의도치 않게 재줄바꿈되지 않았는지 같은 항목이 품질 게이트를 이룬다. 게이트를 통과하지 못하면 그 슬라이드는 폰트 크기나 줄바꿈 지점을 조정해 다시 빌드한다. 렌더 결과를 그대로 납품하지 않고 빌드물을 직접 검수한다는 원칙이 이 단계에 박혀 있다.\n글자가 많아 촘촘한 화면에서 가독성이 갈리는 이유 발표 자료와 문서에서 인상을 좌우하는 건 색이 아니라 타이포그래피다. doc-maker는 본문과 제목에 Pretendard를 기본으로 쓴다. 한글과 숫자, 라틴 문자의 굵기와 자간이 한 서체 안에서 일관되게 정렬되기 때문에, 지표가 촘촘한 데이터 슬라이드에서도 숫자 열이 흐트러지지 않고 읽힌다. 폰트 하나를 잘 고르는 것만으로 \u0026ldquo;어디서 만든 티가 나는\u0026rdquo; 자료와 그렇지 않은 자료가 갈린다.\n레이아웃은 표준 CSS로 짜서 Chromium PDF 엔진으로 렌더한다. 별도의 그리기 엔진을 쓰지 않고 브라우저가 실제로 웹 페이지를 그리는 방식 그대로 조판하기 때문에, 여백과 정렬이 화면에서 본 것과 PDF에서 본 것 사이에 어긋나지 않는다. CSS 기반이라 슬라이드 한 장의 간격을 바꾸고 싶을 때 규칙 한 줄만 고치면 전체에 일관되게 반영된다는 실무적 이점도 있다.\n발표 자료가 아니라 긴 문서를 만들어야 할 때 doc-maker는 슬라이드만 다루지 않는다. 전자책 원고나 여러 쪽짜리 보고서처럼 장문 본문이 이어지는 문서는 docx로 빌드한다. 이때도 편집 가능성 원칙은 동일하게 적용돼서, 목차와 소제목, 본문 문단이 전부 워드에서 손댈 수 있는 텍스트로 들어간다. 발주자가 챕터 하나를 통째로 다시 쓰거나 문단 순서를 바꿀 때 원본 그대로 편집하면 된다.\n문서는 슬라이드와 조판 관심사가 다르다. 슬라이드가 한 장 안에 정보를 배치하는 문제라면, 문서는 쪽을 넘어가며 흐름이 끊기지 않게 하는 문제다. 소제목이 페이지 맨 아래에 혼자 남고 본문이 다음 쪽에서 시작되는 어색한 분리, 표가 페이지 경계에서 잘리는 문제 같은 것이 문서 쪽 품질 게이트의 검사 대상이다. verify_docx는 이 흐름을 확인한 뒤, 앞서 말한 \u0026lt;w:t\u0026gt; 실제 텍스트 검증까지 함께 통과해야 산출물을 내보낸다.\n이 파이프라인을 실제 의뢰에 붙였을 때 정리하면 doc-maker는 세 가지를 동시에 보장하려 한다. 첫째, 산출물은 이미지가 아니라 파워포인트와 워드에서 직접 고칠 수 있는 텍스트다. 둘째, Pretendard와 표준 CSS 조판으로 어디서 만든 티가 나지 않는 타이포그래피 품질을 맞춘다. 셋째, 렌더 결과를 그대로 믿지 않고 빌드된 파일을 열어 편집 가능성과 조판, 수치를 검증한 뒤에야 끝낸다. 이 글에 실린 이미지는 전부 SAMPLE 뱃지를 각인한 가상 예시이며 실제 의뢰물이 아니다. 실제 작업에서는 이 세 게이트를 통과한 파일만 발주자에게 전달된다.\n이 프로젝트를 만드는 팀 doc-maker는 한 명의 에이전트가 아니라 역할이 나뉜 팀이 함께 만든다. 주제를 받아 자료조사·구성·슬라이드 조율의 최종 판단을 docmaker-lead가 맡고, 장문 텍스트와 전자책 작성은 document-team이, 내부에서 구성·논점 설계는 planner가, 슬라이드 디자인은 designer가, 편집 가능성과 수치 검증은 verify가 담당한다.\n","permalink":"https://liquidation-man.github.io/posts/2026-07-25-%EC%A3%BC%EC%A0%9C%EB%A7%8C-%EC%A3%BC%EB%A9%B4-%ED%8E%B8%EC%A7%91-%EA%B0%80%EB%8A%A5%ED%95%9C-pptxdocx%EA%B0%80-%EB%82%98%EC%98%A4%EB%8A%94/","summary":"\u003cp\u003e발표 자료를 외주로 받아본 사람은 비슷한 경험이 있다. 파일을 열어 오타 하나를 고치려는데 슬라이드 전체가 한 장의 PNG로 박혀 있어서 글자를 클릭할 수 없다. 결국 발주자가 캡션 위에 텍스트 상자를 덧대거나, 다시 수정을 요청하는 왕복이 시작된다. doc-maker는 이 왕복을 없애는 것을 첫 번째 설계 목표로 잡았다. 주제 한 줄을 입력하면 자료조사와 구성, 슬라이드 디자인을 거쳐 파워포인트와 워드에서 글자를 직접 고칠 수 있는 산출물이 나온다. 아래는 그 과정과 품질 게이트를 실제 빌드물 기준으로 정리한 글이다.\u003c/p\u003e","title":"문서 자동생성 — 주제 한 줄로 PPTX 까지 만든다"},{"content":"크몽에서 서비스 하나를 등록하고 첫 문의가 들어오면, 그때부터 반복되는 작업의 목록이 눈에 보이기 시작한다. 제목과 상세페이지를 다듬고, 고객이 무엇을 원하는지 물어보고, 받은 답을 정리해 작업으로 옮기고, 완성물을 납품하고, 수정 요청을 받는다. 이 흐름은 서비스가 전자책이든 챗봇이든 홈페이지든 뼈대가 거의 같다. 그래서 세 종류의 서비스를 한꺼번에 굴리면서 공통 부분을 양식과 체크리스트로 묶어두는 작업을 계속해왔다. 이 글은 그 운영을 어떻게 체계화했는지에 대한 기록이다.\n전자책, 챗봇, 홈페이지를 한 판에 올려두면 생기는 일 현재 운영하는 서비스는 세 종류다. 첫째는 전자책이다. AI를 처음 접하는 사람을 위한 입문 가이드, 그리고 유튜브 무인 채널을 파이프라인으로 굴리는 방법을 정리한 실무형 원고 두 갈래가 중심이다. 둘째는 GPT와 Claude 기반 챗봇 제작이다. 자주 묻는 질문에 자동으로 답하는 FAQ 봇, 여러 채널에 동시에 붙이는 다채널 봇, 대화 내용을 요약해 리포트로 뽑아주는 봇까지 목적별로 나뉜다. 셋째는 반응형 원페이지 홈페이지 제작이다. PC와 모바일에서 모두 깨지지 않고, 간단한 관리자 화면으로 문구와 이미지를 직접 고칠 수 있는 형태다.\n이 세 가지는 결과물의 성격이 완전히 다르다. 전자책은 글이고, 챗봇은 대화 로직이며, 홈페이지는 화면이다. 그런데도 한 판에 올려두는 이유는, 앞단의 운영 흐름이 겹치기 때문이다. 문의를 받아 요구사항을 확인하고, 작업 범위와 가격을 맞추고, 중간 확인을 거쳐 납품하고, 수정 라운드를 도는 리듬은 세 서비스가 똑같다. 결과물을 만드는 손은 다르지만, 그 손에게 일을 넘겨주기까지의 준비 과정은 하나로 묶을 수 있다는 뜻이다.\n등록 버튼을 누르기 전에 반드시 거치는 검수 크몽에서 gig 하나가 반려되는 가장 흔한 이유는 증빙 없는 표현이다. \u0026ldquo;국내 최고\u0026rdquo;, \u0026ldquo;100% 만족 보장\u0026rdquo;, \u0026ldquo;무제한 수정\u0026rdquo; 같은 문구는 근거를 댈 수 없으면 심사에서 걸린다. 그래서 상세페이지 초안이 나오면 등록 버튼을 누르기 전에 문장을 한 줄씩 스캔하는 단계를 반드시 거친다. 걸릴 만한 표현을 찾아내고, 같은 의미를 증빙 가능한 형태로 바꾼 대체안을 함께 준비한다. 예를 들어 \u0026ldquo;무제한 수정\u0026quot;은 \u0026ldquo;기본 2회 수정 포함, 추가 수정 협의\u0026quot;처럼 범위가 분명한 문장으로 고친다.\n이 검수는 사람의 감이 아니라 목록으로 돌아간다. 과거에 걸렸던 표현, 크몽 정책상 조심해야 하는 카테고리, 서비스별로 오해를 부르기 쉬운 문구를 정리해두고 매번 그 목록에 비춰본다. 새 gig를 만들 때마다 처음부터 고민하는 대신, 이미 검증된 체크리스트 위에서 다른 부분만 새로 판단하면 된다. 등록 전 준비를 담당하는 단계와 실제로 사이트를 조작하는 단계를 분리해둔 것도 같은 이유다. 준비와 검수가 끝난 상태에서만 실제 등록으로 넘어가야, 걸릴 걸 뻔히 알면서 올렸다가 반려당하는 왕복을 줄일 수 있다.\n고객 요구사항을 매번 처음부터 묻지 않으려면 프리랜서 작업에서 가장 많은 시간이 새는 지점은 요구사항 수집이다. 문의가 들어왔을 때 \u0026ldquo;어떤 걸 원하세요?\u0026ldquo;라고 열린 질문을 던지면, 고객도 무엇을 말해야 할지 몰라 대화가 몇 번씩 오간다. 그래서 서비스마다 입력 요청 양식을 정본 포맷으로 만들어두고, 문의가 오면 그 양식을 먼저 건넨다.\n챗봇 제작이면 봇이 답해야 할 질문 목록, 답변의 톤, 붙일 채널, 넘겨줄 기존 자료를 항목으로 묻는다. 홈페이지 제작이면 담을 섹션, 참고 사이트, 로고와 이미지 보유 여부, 관리자 수정이 필요한 범위를 묻는다. 전자책이면 대상 독자, 분량, 목차 방향, 원고 보유 여부를 묻는다. 이렇게 항목이 정해져 있으면 고객은 빈칸을 채우기만 하면 되고, 작업자는 첫 답변만으로 견적과 일정을 낼 수 있다. 요구사항 양식을 정본으로 관리한다는 건, 매 주문마다 대화를 새로 설계하지 않는다는 뜻이다.\n아래는 gig 등록부터 납품까지의 공통 흐름이다. 서비스 세 종류가 이 뼈대를 공유한다.\n코딩 서비스는 납품 기준이 글과 다르다 챗봇과 홈페이지 같은 코딩 서비스는 전자책과 결이 다른 지점이 있다. 글은 읽어보면 완성 여부가 드러나지만, 코드는 \u0026ldquo;동작한다\u0026quot;는 걸 눈으로 확인해야 한다. 그래서 이쪽은 납품 전에 검증 단계를 따로 둔다. 홈페이지라면 PC와 모바일 양쪽에서 레이아웃이 깨지지 않는지, 관리자 화면에서 문구 수정이 실제로 반영되는지를 확인한다. 챗봇이라면 요구사항 양식에서 받은 질문들을 실제로 던져보고, 의도한 답이 나오는지 대화 흐름을 짚는다.\n납품물의 형태도 서비스에 맞춰 나뉜다. 챗봇은 붙일 채널에 연결된 상태로 넘기거나, 고객이 직접 붙일 수 있도록 설정 방법을 정리해 함께 전달한다. 홈페이지는 배포된 주소와 관리자 접근 방법, 그리고 이후 고객이 스스로 문구를 고칠 때 참고할 간단한 안내를 묶어서 넘긴다. 코딩 서비스의 수정 라운드는 대개 \u0026ldquo;이 버튼이 안 눌려요\u0026rdquo; 같은 구체적 증상으로 들어오기 때문에, 증상을 재현하고 고친 뒤 같은 조건에서 다시 확인하는 순서를 지킨다. 고쳤다고 말하기 전에 실제로 그 화면에서 눌러보는 것이 이 서비스의 최소 기준이다.\n전자책은 재고가 없는 대신 신뢰가 재고다 전자책은 세 서비스 중 성격이 가장 독특하다. 한 번 만들어두면 같은 원고를 여러 고객에게 반복 판매할 수 있어서, 주문마다 새로 만드는 챗봇이나 홈페이지와 원가 구조가 다르다. 대신 재고가 없다는 건 품질에 대한 신뢰가 곧 재고라는 뜻이기도 하다. 목차가 허술하거나 내용이 얕으면 환불과 낮은 평점으로 곧장 돌아온다.\n그래서 전자책은 기획 단계에 시간을 더 쓴다. AI 입문 가이드라면 처음 접하는 사람이 어디서 막히는지를 기준으로 목차를 짜고, 유튜브 무인 채널 파이프라인이라면 실제로 채널 하나를 굴리는 순서대로 장을 배치한다. 상세페이지에서 약속한 내용과 실제 원고가 어긋나지 않는 것도 중요하다. \u0026ldquo;이것까지 다룬다\u0026quot;고 써놓고 원고에 없으면 그것 역시 증빙 없는 표현과 같은 문제가 된다. 그래서 상세페이지 문구와 원고 목차를 나란히 놓고 서로 맞는지 대조하는 과정을 넣어두었다. 글을 쓰는 일과 그 글을 파는 문구를 만드는 일을 같은 기준으로 검수하는 셈이다.\n세 서비스를 묶어두니 보이는 것 세 종류의 서비스를 각각 따로 굴렸다면, 각자의 운영 노하우가 서로 다른 곳에 흩어졌을 것이다. 한 판에 올려두니 공통 부분이 선명해졌다. 등록 전 검수 목록, 요구사항 수집 양식, 납품 전 확인 절차는 서비스가 달라도 형식만 갈아끼우면 그대로 쓸 수 있는 자산이 됐다. 새 서비스를 추가할 때도 이 세 가지 틀을 먼저 채우는 것으로 시작한다.\n동시에 각 서비스가 어디서 갈라지는지도 분명해졌다. 전자책은 기획과 신뢰가 핵심이고, 코딩 서비스는 동작 검증이 핵심이며, 세 서비스 모두 앞단의 문의 대응과 요구사항 정리에서 시간이 갈린다. 자동화라고 부를 만한 부분은 화려한 무언가가 아니라, 매번 반복되던 판단을 목록과 양식으로 바꿔 다음 주문에서 다시 고민하지 않게 만든 것이다. 그 목록이 쌓일수록 새 문의에 답하는 속도가 붙고, 남는 시간을 결과물의 질에 다시 쓸 수 있게 된다.\n이런 작업이 필요하다면 블로그에서 소개한 챗봇·홈페이지 제작은 크몽에서 직접 의뢰할 수 있습니다.\n🤖 GPT·Claude FAQ 챗봇 제작 의뢰하기 🌐 반응형 원페이지 홈페이지 제작 의뢰하기 이 프로젝트를 만드는 팀 크몽 운영에는 판단과 실무를 나눠 맡는 다섯 역할이 참여한다.\nkmong-lead — gig 구성, 가격, 고객 대응의 최종 판단. kmong-ops-team — 등록·수정·고객 메시지 실무 처리. kmong-gig-prep — 등록 전 준비와 검수, 요구사항 수집 양식 관리. kmong-dev-delivery — 챗봇과 홈페이지 등 코딩 서비스 납품. document-team — 전자책과 문서 원고 작성. ","permalink":"https://liquidation-man.github.io/posts/2026-07-25-%ED%81%AC%EB%AA%BD-%ED%94%84%EB%A6%AC%EB%9E%9C%EC%84%9C-%EC%9A%B4%EC%98%81%EC%9D%84-%EC%9E%90%EB%8F%99%ED%99%94%ED%95%9C-%EA%B8%B0%EB%A1%9D-%EC%A0%84%EC%9E%90%EC%B1%85%EC%B1%97%EB%B4%87%ED%99%88%ED%8E%98%EC%9D%B4%EC%A7%80/","summary":"\u003cp\u003e크몽에서 서비스 하나를 등록하고 첫 문의가 들어오면, 그때부터 반복되는 작업의 목록이 눈에 보이기 시작한다. 제목과 상세페이지를 다듬고, 고객이 무엇을 원하는지 물어보고, 받은 답을 정리해 작업으로 옮기고, 완성물을 납품하고, 수정 요청을 받는다. 이 흐름은 서비스가 전자책이든 챗봇이든 홈페이지든 뼈대가 거의 같다. 그래서 세 종류의 서비스를 한꺼번에 굴리면서 공통 부분을 양식과 체크리스트로 묶어두는 작업을 계속해왔다. 이 글은 그 운영을 어떻게 체계화했는지에 대한 기록이다.\u003c/p\u003e","title":"프리랜싱 — 크몽 운영을 자동화했다"},{"content":"오늘 한 일 3줄 그동안 폴더별로 따로 놀던 부업 프로젝트들을 C:\\Projects 아래 단일 git 저장소로 묶었다. 첫 통합 커밋이 f24b126. 매번 손으로 커밋하지 않으려고 프로젝트 단위로 변동을 감지해 묶어 커밋하는 auto_commit.ps1(+82줄)을 붙였다. 이게 오늘의 핵심인 git 커밋 자동 수집 장치다. 통합하면서 튀어나온 진짜 위험 하나 — 토큰 파일이 저장소에 딸려 들어갈 뻔한 것 — 을 .gitignore 방어로 막고 실제로 차단되는지 눈으로 확인했다. 하루 총계는 커밋 16개, +9200/-93 라인. 대부분이 신규 파일 추가라 삭제가 93줄밖에 안 된다. 처음으로 이력에 넣는 파일들이 그만큼 많았다는 뜻이다.\n왜 지금 통합했나 지금까지는 프로젝트마다 폴더가 따로 있고, 어떤 건 git이 걸려 있고 어떤 건 아니었다. 비트겟 매매 로직, doc-maker 문서 파이프라인, 증시 카드뉴스, 새로 시작한 ai-influencer까지 늘어나니까 \u0026ldquo;어제 뭘 바꿨더라\u0026quot;를 폴더 뒤지면서 되짚는 게 한계에 왔다.\n그래서 방침을 정했다. 기존에 어중간하게 올라가 있던 git 흔적은 걷어내고, C:\\Projects 아래 지금 존재하는 모든 프로젝트를 하나의 이력으로 다시 넣는다. 대신 파일 하나 고칠 때마다 커밋하지는 않는다. 변동이 있는 프로젝트만, 일 단위 혹은 며칠 단위로 묶어서 반영한다. 개인 부업 저장소에 커밋 노이즈를 쌓아봐야 나중에 이력을 읽을 때 방해만 된다.\n첫 통합 스냅샷 f24b126은 조직 정의부터 넣었다. gatekeeper.md(+100/-0)를 필두로 각 프로젝트 리드 정의 — bitget-lead.md(+34), docmaker-lead.md(+27), kmong-lead.md(+32) — 와 공유팀 정의들이 한꺼번에 이력에 올라갔다. 코드보다 \u0026ldquo;누가 뭘 담당하는가\u0026quot;를 먼저 버전관리 대상으로 삼은 셈이다. 에이전트 구성 자체가 자주 바뀌는 살아있는 문서라, 여기가 흔들리면 나머지가 다 흔들린다.\nauto_commit.ps1: 프로젝트 단위로 묶어 커밋 자동 수집 e785bfd에서 추가한 scripts/auto_commit.ps1(+82/-0)이 오늘의 주인공이다. 하는 일은 단순하다. 저장소 안의 각 프로젝트 디렉토리를 훑어서, 변동이 있는 프로젝트만 골라 그 프로젝트 이름을 커밋 메시지 앞에 붙여 따로 커밋한다.\n그래서 오늘 이력을 보면 커밋 메시지가 이렇게 프로젝트 태그로 갈린다.\n[ORG-STRUCTURE.md] 3d281aa auto: 루트 문서/설정 변동사항 반영 (2026-07-24) [scripts] e785bfd auto: scripts 변동사항 반영 (2026-07-24) [doc-maker] dc28647 auto: doc-maker 변동사항 반영 (2026-07-24) [bitget-trading] b5a67a7 auto: bitget-trading 변동사항 반영 (2026-07-24) [ai-influencer] 12b3049 auto: ai-influencer 변동사항 반영 (2026-07-24) 한 번에 뭉텅이로 \u0026ldquo;update\u0026quot;를 날리지 않고 프로젝트별로 쪼갠 이유는 나중에 되짚을 때다. git log에서 [bitget-trading]만 훑으면 매매 로직이 어떻게 바뀌어 왔는지 그 프로젝트 이력만 선명하게 읽힌다. 한 커밋에 다섯 프로젝트가 뒤섞여 있으면 그게 안 된다.\nPC는 어차피 24시간 켜둔다. OAuth 토큰 만료를 막으려고 그렇게 하기로 이미 정해뒀으니, 그 켜져 있는 시간에 이 수집 스크립트가 하루 단위로 돌면 손으로 커밋하는 습관 자체가 필요 없어진다. 다만 실제 스케줄러 등록은 아직 안 걸었다. 스케줄에 올리는 건 별도 승인 절차를 거쳐야 해서, 오늘은 스크립트를 이력에 넣고 수동으로 한 번 돌려본 데까지만 했다.\n비밀키가 커밋에 딸려 들어갈 뻔한 지점 통합에서 제일 아찔했던 건 여기다. 유튜브 업로드용 token.json 같은 인증 파일들이 프로젝트 폴더 안에 그냥 있다. 저장소를 통째로 다시 넣는 작업이니, 방심하면 refresh 토큰이 커밋 이력에 박제된다. 한 번 커밋되면 git rm으로 지워도 이력에는 남는다.\n그래서 통합 전에 .gitignore부터 손봤고, 실제로 차단되는지를 커밋 시도로 검증했다. 확인 로그가 이렇게 나왔다.\nus-card-news: scripts/token.json [차단됨(OK)] kr-card-news: scripts/token.json [차단됨(OK)] 경로가 \u0026ldquo;차단됨\u0026quot;으로 찍히면 그 파일은 커밋 후보에서 빠졌다는 뜻이다. 같은 세션에서 한 유튜브 채널의 새 refresh_token이 production 상태로 재발급되면서 7일 만료가 풀린 것도 확인했는데, 그 실제 토큰 값은 비공개다. 중요한 건 값이 아니라 \u0026ldquo;저 파일이 저장소 밖에 머문다\u0026quot;는 사실이고, 그건 검증됐다.\n같은 날 병행으로 굴러간 작업들 통합이 메인이었지만 프로젝트별 실제 작업도 같이 이력에 올라갔다.\ndoc-maker 쪽은 문서 파이프라인을 한 단계 정식화했다. 0fa315f에서 scripts/build_doc.js(+268/-0)와 scripts/verify_doc.js(+125/-0)를 넣어 \u0026ldquo;장문 원고 → 표준 HTML → Chromium PDF\u0026quot;를 주력 엔진으로 굳혔다. 이전 커밋에서 LibreOffice 임포트용으로 넣었던 우회 CSS — 문단마다 margin-right를 박고 word-break를 떼는 땜빵 — 를 Chromium 경로에서는 걷어냈다. Chromium은 CSS를 1:1로 해석하니 표준 CSS를 그냥 쓰면 된다. 엔진을 바꾸니 우회가 통째로 필요 없어진 케이스다.\n비트겟은 b5a67a7에서 공포탐욕지수 기반 실험 코드 btc_feargreed.py(+310/-0)와 README(+30)를 처음 이력에 넣었다. 매매 로직은 아직 고칠 게 많아서 이건 확정본이 아니라 작업 중 스냅샷이다.\nai-influencer는 12b3049에서 운영 문서들이 들어왔다. FOLLOW-PLAN.md(+56)는 초기 팔로잉 대상 30명(피어 18 + 로컬 12)을 채우는 수동 실행용 시트인데, 표 칸은 아직 비어 있는 뼈대 상태다. 자동팔로우 앱은 계정 정지 트리거라 처음부터 배제하고 수동 전용으로 설계했다.\n막혔던 점 가장 손이 많이 간 건 \u0026ldquo;무엇을 이력에 넣지 않을 것인가\u0026quot;였다. git 통합은 파일을 추가하는 것보다 빼는 규칙을 먼저 정확히 세우는 일이 본체다. 토큰·빌드 산출물(decks/*/output/, output-chromium/)·node_modules 같은 것들을 .gitignore에서 하나씩 확정하고, 확정할 때마다 실제 커밋 후보 목록을 뽑아 눈으로 대조했다. \u0026ldquo;아마 무시되겠지\u0026quot;로 넘기면 딱 그 하나가 새서 사고가 난다.\n배운 점 통합 저장소의 첫 커밋은 코드가 아니라 규칙이어야 한다. 오늘 f24b126에 조직 정의부터 넣은 게 맞았다. 담당 경계와 .gitignore 규칙이 이력의 바닥에 깔려 있어야 이후 자동 커밋이 안전하게 쌓인다. 커밋 자동화의 값어치는 \u0026ldquo;언제 커밋하느냐\u0026quot;가 아니라 \u0026ldquo;어떻게 쪼개느냐\u0026quot;에 있다. 프로젝트 태그로 커밋을 가르니 로그 가독성이 통째 커밋과 비교가 안 된다. 비밀 파일 차단은 선언만으로 끝내면 안 된다. [차단됨(OK)]처럼 실제 후보 목록에서 빠지는 걸 확인해야 검증이다. 내일 할 일 auto_commit.ps1을 스케줄에 올릴지 결정하고, 올린다면 승인 절차부터 밟는다. 지금은 수동 실행 상태다. 비트겟 btc_feargreed.py는 스냅샷일 뿐이라 로직을 이어서 손본다. doc-maker의 docx 조판 후처리와 Chromium PDF 경로가 같은 원고에서 화질이 어떻게 갈리는지 실렌더로 비교를 마무리한다. ","permalink":"https://liquidation-man.github.io/posts/2026-07-24-%ED%9D%A9%EC%96%B4%EC%A7%84-%EB%B6%80%EC%97%85-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-7%EA%B0%9C%EB%A5%BC-git-%EC%A0%80%EC%9E%A5%EC%86%8C/","summary":"\u003ch2 id=\"오늘-한-일-3줄\"\u003e오늘 한 일 3줄\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e그동안 폴더별로 따로 놀던 부업 프로젝트들을 \u003ccode\u003eC:\\Projects\u003c/code\u003e 아래 \u003cstrong\u003e단일 git 저장소\u003c/strong\u003e로 묶었다. 첫 통합 커밋이 \u003ccode\u003ef24b126\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003e매번 손으로 커밋하지 않으려고 \u003cstrong\u003e프로젝트 단위로 변동을 감지해 묶어 커밋하는\u003c/strong\u003e \u003ccode\u003eauto_commit.ps1\u003c/code\u003e(+82줄)을 붙였다. 이게 오늘의 핵심인 git 커밋 자동 수집 장치다.\u003c/li\u003e\n\u003cli\u003e통합하면서 튀어나온 진짜 위험 하나 — 토큰 파일이 저장소에 딸려 들어갈 뻔한 것 — 을 \u003ccode\u003e.gitignore\u003c/code\u003e 방어로 막고 실제로 차단되는지 눈으로 확인했다.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e하루 총계는 커밋 16개, +9200/-93 라인. 대부분이 신규 파일 추가라 삭제가 93줄밖에 안 된다. 처음으로 이력에 넣는 파일들이 그만큼 많았다는 뜻이다.\u003c/p\u003e","title":"개발 인프라 — 프로젝트 7개를 저장소 하나로 합쳤다"},{"content":"본 방침은 부업 자동화 개발일지(이하 \u0026ldquo;본 사이트\u0026rdquo;)가 방문자의 개인정보를 어떻게 취급하는지를 설명합니다. 최종 개정일: 2026년 7월 25일.\n1. 수집하는 개인정보 본 사이트는 정적 블로그로, 방문자로부터 이름·이메일 등 개인정보를 직접 입력받거나 저장하지 않습니다. 회원가입, 댓글, 문의 폼이 없습니다.\n다만 아래 제3자 서비스가 방문 통계 및 광고 제공을 위해 일부 정보를 수집할 수 있습니다.\n2. 쿠키 및 제3자 서비스 Google AdSense (광고) 본 사이트는 향후 Google AdSense를 통해 광고를 게재할 수 있습니다. Google을 포함한 제3자 광고 사업자는 쿠키를 사용하여 방문자의 이전 방문 기록을 바탕으로 맞춤형 광고를 제공할 수 있습니다.\nGoogle의 광고 쿠키 사용을 통해 Google과 그 파트너는 본 사이트 및 다른 사이트 방문 기록에 기반한 광고를 게재합니다. 방문자는 Google 광고 설정에서 맞춤 광고를 비활성화할 수 있습니다. 제3자 공급업체의 쿠키 사용을 원치 않을 경우 www.aboutads.info에서 선택 해제할 수 있습니다. 접속 통계 GitHub Pages 호스팅 및 분석 도구를 통해 접속 IP, 브라우저 종류, 방문 페이지 등 비식별 통계 정보가 수집될 수 있습니다. 이는 사이트 개선 목적에만 사용됩니다.\n제휴 마케팅 고지 본 사이트의 일부 글에는 제휴(어필리에이트) 링크가 포함될 수 있습니다. 방문자가 해당 링크를 통해 상품을 구매하면 본 사이트는 판매자로부터 일정액의 수수료를 제공받을 수 있으며, 이는 구매 가격에 영향을 주지 않습니다. 제휴 링크에는 \u0026ldquo;(제휴 링크)\u0026rdquo; 표기를 함께 제공합니다. (쿠팡 파트너스 활동 시: 본 사이트는 쿠팡 파트너스 활동의 일환으로 이에 따른 일정액의 수수료를 제공받습니다.)\n3. 개인정보의 제3자 제공 본 사이트는 방문자의 개인정보를 제3자에게 판매·대여·제공하지 않습니다.\n4. 게시 콘텐츠와 민감정보 보호 본 사이트의 글은 자동화 파이프라인이 생성합니다. 발행 전 단계에서 API 키·토큰·비밀번호·이메일 주소·개인 파일 경로·실계좌 금액 등 민감 정보를 자동으로 제거·마스킹하며, 특정 비공개 프로젝트는 아예 수집 대상에서 제외합니다.\n5. 이용자의 권리 방문자는 브라우저 설정을 통해 쿠키 저장을 거부할 수 있습니다. 쿠키를 거부해도 사이트 이용에는 제한이 없으나 일부 맞춤 기능이 제한될 수 있습니다.\n6. 방침의 변경 본 방침은 관련 법령 또는 서비스 변경에 따라 개정될 수 있으며, 변경 시 본 페이지를 통해 공지합니다.\n7. 문의 개인정보 관련 문의는 GitHub을 통해 접수합니다.\n","permalink":"https://liquidation-man.github.io/privacy/","summary":"개인정보처리방침 및 쿠키·광고 안내","title":"개인정보처리방침"},{"content":"이 블로그는 무엇인가요 부업 자동화 개발일지는 여러 사이드 프로젝트를 매일 조금씩 넓혀가는 과정을 자동으로 기록하는 개발 일지입니다.\n자동매매 봇, 유튜브 콘텐츠 자동화, 로그라이크 게임, AI 인플루언서 등 서로 다른 프로젝트를 오가며 무엇을, 왜, 어떻게 했는지를 남깁니다. 잘 풀린 날뿐 아니라 막혔던 지점과 그걸 해결한 과정까지 솔직하게 기록하는 걸 목표로 합니다.\n어떻게 쓰여지나요 이 블로그의 글은 사람이 직접 타이핑하지 않습니다. 매일 정해진 시각에 파이프라인이 그날의 작업 내역(git 커밋, 작업 세션 기록)을 수집·요약해 자동으로 글을 생성하고 발행합니다. 즉, 자동화를 기록하는 과정 자체가 자동화되어 있습니다.\n민감한 정보(계정 정보, API 키, 개인 식별 정보, 실계좌 수치 등)는 발행 전에 자동으로 제거·마스킹됩니다. 자세한 내용은 개인정보처리방침을 참고하세요.\n다루는 주제 파이썬 기반 데이터 수집·자동화 파이프라인 정적 사이트(Hugo)와 GitHub Actions를 이용한 무인 배포 트레이딩 전략의 백테스트·포워드테스트 유튜브/숏폼 콘텐츠 생성 자동화 게임 개발(Godot) 생성형 AI 활용 문의나 제안은 GitHub을 통해 남겨주세요.\n","permalink":"https://liquidation-man.github.io/about/","summary":"부업 자동화 개발일지 소개","title":"소개"},{"content":"이 블로그는 개인이 운영하는 개발 자동화 기록 공간입니다. 문의·제안·오류 신고는 아래 채널로 받습니다.\n이메일: [YOUR_EMAIL] — 문의·제안·광고/제휴 관련 연락은 이 주소로 보내주세요. (평일 기준 확인 후 회신드립니다.) GitHub: github.com/liquidation-man — 이슈나 프로필을 통해 남겨주세요. 참고: 위 이메일 주소의 [YOUR_EMAIL] 자리는 운영자가 실제 주소로 교체해 발행합니다.\n글의 내용 중 사실관계 정정이 필요하거나, 민감정보가 의도치 않게 노출된 경우 알려주시면 신속히 조치하겠습니다. 자세한 데이터 처리 방침은 개인정보처리방침을 참고하세요.\n","permalink":"https://liquidation-man.github.io/contact/","summary":"문의 및 연락 방법","title":"연락처"},{"content":"","permalink":"https://liquidation-man.github.io/projects/","summary":"프로젝트별 진행내역","title":"프로젝트"}]