자동화 slecs

새벽 6시간, SEO 파이프라인과 블로그 자동화를 전면 손질한 날

목차

자정 넘어 시작한 작업이 해 뜨기 전까지 이어졌다. 처음엔 단순한 SEO 점검으로 시작했는데, 하나 손대면 옆이 보이고, 옆을 손대면 또 다른 구멍이 보이는 특유의 연쇄가 새벽 내내 이어졌다. 크게 세 덩어리로 정리된다. 사이트맵 위생 전수점검, 블로그 발행 파이프라인 대수술, 그리고 Indexing API 핑 자동화와 안드로이드 배포 마무리.


sitemap 위생 - GSC 전수점검이 터뜨린 숙제

새벽 첫 작업은 Google Search Console 전수점검이었다. 결과가 생각보다 좋지 않았다. noindex가 걸린 상세 페이지들이 sitemap에 버젓이 올라가 있었고, /privacy/terms 같은 법적 고지 페이지도 섞여 있었다. 크롤 버짓 낭비 수준이 아니라 GSC가 신호를 혼동할 수 있는 구조였다.

문제는 여러 사이트에 동시에 걸려 있었다. 한 사이트는 astro.config.mjs에서 제외 처리, 다른 사이트는 sitemap-content.xml.ts에서 필터링, 또 다른 사이트는 DB 레벨의 blindbox-db.ts까지 건드려야 했다. 같은 문제인데 사이트마다 sitemap 구조가 달라서 고치는 방식이 전부 달랐다. 그러다 보니 커밋이 사이트별로 여러 개 쌓였다.

핵심 룰은 세 가지로 정리됐다.

  • noindex 페이지는 sitemap에서 반드시 제외
  • redirect(301) 대상 URL 제외
  • canonical과 sitemap URL 일치 확인

이걸 docs/NEW-SITE-ONBOARDING.md에 "신규 사이트 온보딩 3종 필수 체크"로 박아뒀고, docs/seo-infra.md에도 2026-07-04 GSC 점검 결과로 사유를 달았다. 다음에 사이트 추가할 때 같은 실수를 반복하지 않으려면 문서화가 먼저다. 코드로 막는 것도 중요하지만, 온보딩 때 아예 체크리스트로 강제하는 게 더 확실하다.

Event JSON-LD description 누락이 matchPage에 있던 것도 이때 같이 잡았다. sitemap 점검하다 보면 구조화 데이터 쪽도 눈에 들어오는데, 뒤로 미루면 또 잊어버리니까 그 자리에서 처리했다.


블로그 발행 파이프라인 - 이미지 품질, 카테고리 오류, 비용 절감을 한꺼번에

새벽 2~4시 사이가 제일 바빴다. lib_publish.js 커밋이 가장 많이 쌓인 구간인데, 이미지 생성 쪽 문제가 연달아 터졌기 때문이다.

이미지 생성 엔진 교체와 품질 조정

제일 큰 변경은 이미지 생성을 Gemini에서 OpenAI(gpt-image-1, 폴백은 dall-e-3)로 바꾼 것이었다. 추상 벡터 스타일로 나오던 이미지를 실사 에디토리얼 사진 스타일로 전환하려는 시도였는데, Gemini 쪽 결과물이 매번 너무 AI티가 났다. 매거진급 스튜디오 사진처럼 뽑히는 게 처음엔 좋아 보였는데, 막상 블로그에 올리면 글이랑 너무 겉돌았다. 독자 입장에서 "이거 AI가 썼네"가 바로 보이는 구도였다.

그래서 톤을 완전히 뒤집었다. 매거진/스튜디오 톤을 버리고 평범한 일상 스냅샷 느낌으로 프롬프트를 재설계했다. 프롬프트에 사람 완전 차단, 서류·문서는 백지 처리 지침도 박았다. 이전에 주제와 무관한 책이나 잡지 소품이 자꾸 끼어드는 문제도 있었는데, 그것도 프롬프트 레벨에서 명시적으로 금지했다. AI가 "분위기 있어 보이는" 소품을 알아서 갖다 붙이는 습관이 있는데, 이게 생활정보 블로그에선 오히려 어색하다.

kfoodlab에서 이미 검증한 비전 검증 루프도 이식했다. 이미지 생성 후 자동으로 검증을 돌리고, 문제가 있으면 재생성하는 루프다. 한 번 만들어진 이미지를 사람이 일일이 확인하는 게 자동화 파이프라인에선 현실적이지 않으니까, 검증 자체를 코드로 넣는 게 맞다.

비용 쪽도 건드렸다. 이미지를 글당 8장에서 4장으로 줄이고(MAX_AUTO_IMG), 품질도 medium에서 low로 내렸다. 이미지 품질이 글의 인덱싱이나 체류시간에 직접적인 영향을 주는지 아직 데이터가 없는 상황에서, 비용을 절반 이하로 줄이는 게 합리적인 판단이었다. 거기다 sharp로 생성 이미지를 폭 1200px로 리사이즈하고 JPEG 압축까지 적용했더니 파일 하나가 2MB에서 200KB대로 떨어졌다. 이미지 용량이 페이지 로드에 미치는 영향을 생각하면 이게 더 중요한 최적화였을 수도 있다.

카테고리 버그와 글감 구조 개편

이미지 작업 중간에 카테고리 버그를 잡았다. 어느 순간부터 발행되는 글이 전부 "일상, 생활정보" 기본값으로만 나가고 있었다. lib_publish.js의 카테고리 분기 로직이 제대로 동작하지 않은 것이었다. 동시에 gen_ideas.py에서 카테고리명이 "자기계발·생산성"으로 되어 있어서 네이버 블로그 실제 카테고리명인 "자기계발"과 불일치하는 문제도 있었다. 발행 자동화에서 카테고리명이 하나라도 안 맞으면 매핑이 깨지는데, 이런 타이포 수준의 실수가 실제로 꽤 오래 묻혀 있었다.

UI 쪽도 정리했다. server.jsui.html의 카테고리 드롭다운이 실제 운영 카테고리 5개(일상 위주)를 반영하지 않고 있었다. 글감 생성도 하루 3개에서 5개로 늘리면서, 5개 카테고리에서 각 1개씩 균등하게 뽑도록 구조를 바꿨다. 특정 카테고리가 편향되게 많이 나오는 문제를 구조로 해결한 셈이다.


Indexing API 핑 자동화와 thin post 보강

sitemap 정리를 마친 다음 자연스럽게 이어진 작업이 Indexing API 핑이었다. 이미 다른 사이트에서 coway 패턴으로 검증된 방식을 slecsblog.com에 그대로 이식했다. scripts/slecsblog_indexing_ping.py 스크립트 하나로 일별 자동 핑을 돌리는 구조다. 패턴이 같으니까 새로 설계할 게 없어서 빠르게 붙였다.

noindex 기준도 이번에 손봤다. 기존 800자 기준이 너무 낮아서 실제로 읽을 만한 글도 noindex 처리되는 경우가 있었다. 2000자로 올리는 게 맞다고 판단했고, 동시에 scripts/enrich_thin_posts.py 배치 스크립트로 기존 thin 글들을 자동 보강하는 루틴도 만들었다. 기준을 올리기만 하면 기존 noindex 글들이 갑자기 인덱싱 대상이 되는데, 그냥 올리는 것보다 콘텐츠를 먼저 보강하고 올리는 순서가 맞다. 이 판단 흐름과 운영 시 주의사항은 CLAUDE.md에 기록해뒀다.


안드로이드 배포 마무리 - AGP9 R8 크래시

새벽 작업의 마지막 퍼즐은 Android 쪽이었다. vc5 빌드에서 첫 실행 때 크래시가 나는 문제였다. R8 minify가 WorkDatabase_Impl 생성자를 스트립해버리는 AGP9 이슈였다. 해결책은 간단했는데 찾는 데 시간이 걸렸다. android/app/build.gradle.kts에서 minify를 OFF로 내리는 것으로 해결했다. 크래시 재현 조건이 "첫 실행"이라 로컬 테스트에서 놓치기 쉬운 케이스였다.

nyangle 업데이트 스크립트도 이 타이밍에 정리됐다. 기기가 6GB 용량 제한이 있는 상황에서 구글 앱 정리로 공간을 확보하고, 파란 버튼 픽셀 탐지 로직을 화면별 좌표 차이에 대응하도록 수정했다. CDN 전파 가드도 추가했다. intonaire 반영 건에서 겪었던 adb 인증 콜드부팅 이슈, pt07 6GB 용량 한계 등도 CLAUDE.md에 기록해두는 것으로 마무리했다. 이런 기기별 특이사항은 기록해두지 않으면 3개월 후에 같은 삽질을 반복하게 된다.


새벽 6시간 동안 커밋이 30개 가까이 쌓였다. 단일 기능을 깊게 판 게 아니라, 여러 사이트와 파이프라인을 가로질러 쌓여있던 숙제들을 한 번에 치운 시간이었다. 특히 sitemap 위생 룰을 문서화하고 온보딩 체크리스트에 박은 게 이날 작업 중 장기적으로 가장 가치 있는 부분이라고 생각한다. 코드 수정은 해당 사이트에만 적용되지만, 온보딩 문서는 다음에 추가되는 모든 사이트에 자동으로 적용되니까.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.