LogoSEO Jing
  • All Posts
  • SEO Jing
  • okayJing
  • KD Team
  • CLAB Coreteam
  • Study

Contact Me

© 2026 SEOJing. All rights reserved.

SEOJingImage GenerationCoverAutomationDevLog

대표 이미지 자동화 실험 — 검색과 Codex 생성이 같은 경로로 붙었다

2026년 6월 21일·9분 읽기

사진이 없는 글은 진입 장벽이 된다

블로그 목록을 텍스트만으로 보면 글이 많아질수록 어디부터 눌러야 할지 흐려진다. 특히 SEOJing처럼 학습 기록, 기능 개발기, OkayJing 운영 기록이 섞여 있으면 제목만으로 분위기를 구분하기 어렵다. 그래서 최근에 블로그 목록을 대표 이미지 중심의 카드 그리드로 바꾸고, 이미지가 없는 글은 코드로 만든 fallback 카드를 보여주도록 했다.

여기서 바로 다음 문제가 생긴다. fallback 카드는 빈칸을 막아주지만, 모든 글이 fallback이면 결국 비슷한 카드가 반복된다. 글마다 사진이나 시각 요소가 있으면 글의 성격을 훨씬 빨리 파악할 수 있다. 그래서 이번에는 실제로 대표 이미지 자동 삽입을 돌려봤다.


구조는 네 층으로 나눴다

이번 기능은 한 번에 “AI가 예쁜 사진을 알아서 넣는다”로 잡지 않았다. 실패할 수 있는 지점을 나눠야 운영할 수 있기 때문이다.

층역할현재 상태
cover.src글 frontmatter에 실제 대표 이미지 경로를 저장한다구현됨
검색 기반 삽입

Post Q&A

오케이징에게 물어보기

대표 이미지 자동화 실험 — 검색과 Codex 생성이 같은 경로로 붙었다 전체를 기준으로 질문과 피드백을 받아요.답을 본 뒤에는 이 내용을 댓글로 달아서 서징에게도 물어볼 수 있어요. 작성자가 직접 볼 수 있어요!

0/500

포스트 목록

/SEOJing
파일 13개, 폴더 1개
Cloudflare Workers에서 fs 모듈이 안 되는 이유와 해결법대표 이미지 자동화 실험 — 검색과 Codex 생성이 같은 경로로 붙었다모바일 웹에서 가로 모드를 강제하는 5가지 방법 — iOS Safari에서도 동작하는 코드 뷰어 만들기블로그 글을 PPT로 만들기 — DOM 클로닝 기반 프레젠테이션 모드100vh가 100%가 아닌 이유 — 모바일 뷰포트 단위 완전 정리Context로 퀴즈 컴포넌트를 만들다 막혀서 React.Children을 공부하게 된 이야기대표 이미지를 글마다 다시 붙이는 방식 — 사진 검색에서 리소그래프 배경까지localStorage 읽기에서 하이드레이션 에러가 터지는 이유 useSyncExternalStore로 해결useEffect cleanup과 의존성 배열 — 실전 버그 사례로 이해하는 생애주기vinext + GitHub Actions로 Cloudflare Workers 배포하기vinext 오픈소스 기여기: 한국어 slug가 RSC에서 이슈를 일으킨 이유RSC 환경에서 WebAssembly가 차단되는 이유 — Shiki에서 rehype-prism-plus로vinext는 왜 빠를까? — SSR, Vite, Edge, 그리고 Web Vitals까지

같은 섹션의 대표 이미지

37 posts · latest first
대표 이미지 자동화 실험 — 검색과 Codex 생성이 같은 경로로 붙었다 글의 리소그래프 스타일 대표 이미지 배경
SEO Jing26. 06. 21.

대표 이미지 자동화 실험 — 검색과 Codex 생성이 같은.

SEOJing 블로그에 대표 이미지를 자동으로 붙이는 실험을 실제로 돌려봤다. 검색 기반 cover 삽입과 Codex CLI 기반 정적 SVG 생성이 같은 frontmatter 경로로 연결됐다.

SEOJing
대표 이미지를 글마다 다시 붙이는 방식 글의 리소그래프 스타일 대표 이미지 배경
Wikimedia Commons에서 이미지를 찾아 로컬 public asset으로 복사한다
동작 확인
생성 기반 삽입구독 기반 이미지 생성 도구로 이미지를 만들고 같은 cover 구조로 넣는다도구 연결 필요
fallback 카드cover가 없을 때 제목/카테고리/날짜/패턴으로 카드 렌더링구현됨

이 구조의 장점은 검색과 생성을 같은 렌더링 경로로 다룬다는 점이다. 이미지가 어디서 왔든 최종적으로는 apps/web/public/images/content/** 아래 파일이 되고, MDX에는 cover.src, cover.alt, cover.caption, cover.kind만 남는다. 렌더러는 출처를 신경 쓰지 않고 cover.src가 있으면 이미지를 쓰고, 없으면 fallback 카드를 그린다.


검색 기반 삽입은 실제로 됐다

먼저 Wikimedia 검색 기반 흐름을 테스트했다. cover:auto 스크립트는 기본적으로 dry-run이고, --write를 붙였을 때만 파일과 MDX를 수정한다. 넓은 범위의 글을 한 번에 바꾸지 않도록 --path, --limit, --force, --query도 따로 받는다.

bash
pnpm --filter @app/web run cover:auto -- \
  --provider wikimedia \
  --path apps/web/content/okayJing/technical-map.mdx \
  --limit 1 \
  --write

이 테스트에서는 okayJing/technical-map.mdx에 대표 이미지가 들어갔다. 이미지 파일은 apps/web/public/images/content/okayjing/technical-map/cover-02.jpg로 저장됐고, MDX frontmatter에는 출처와 라이선스가 caption으로 남았다. 이후 content-tree를 다시 생성해보니 frontmatter.cover도 사라지지 않고 들어갔다.

중간에 작은 함정도 있었다. SEOJing의 가벼운 frontmatter 파서는 원래 scalar 값과 배열만 읽고, cover:처럼 중첩된 YAML 객체는 제대로 읽지 못했다. 그래서 이미지를 넣었는데도 카드 렌더러가 계속 fallback을 보여주는 상태가 됐다. 해결은 카드가 아니라 parser 쪽이었다. 중첩 객체 파싱을 추가하고 frontmatter.test.ts에 케이스를 넣은 뒤에야 그리드 카드에 실제 이미지가 보였다.


생성 기반 삽입은 API key 경로가 기본값이면 안 맞았다

처음 구현은 OPENAI_API_KEY가 있으면 이미지 생성 API를 호출하는 fallback까지 열어뒀다. 하지만 이건 SEOJing 운영 방향과 맞지 않았다. API key 방식은 별도 과금과 별도 쿼터가 붙는다. 진짜 원하는 건 “내가 이미 쓰는 Codex/Hermes 구독 사용량 안에서 생성하고, 그 결과만 블로그 자산으로 가져오는 흐름”이었다.

그래서 auto 모드에서 OpenAI API fallback은 뺐다. 지금 cover:auto의 기본 자동화는 검색만 수행한다. API 기반 생성은 --provider openai를 명시했을 때만 쓰는 선택지로 내려놨다. 기본 운영 경로는 다음처럼 잡는 게 맞다.

text
검색 이미지가 어울리는 글
→ cover:auto --provider wikimedia --write

추상적이거나 OkayJing 정체성이 필요한 글
→ Hermes/Codex 구독 기반 이미지 생성
→ 생성 파일을 public/images/content/** 로 저장
→ 같은 cover frontmatter를 삽입
→ asset check / content generation / browser 검증

Codex CLI 생성도 같은 cover 경로로 연결했다

이후 Codex CLI 로그인을 마치고 --provider codex-svg 경로를 추가했다. 이 모드는 Codex에게 1200×630 정적 SVG를 만들게 하고, 결과를 바로 쓰지 않는다. 먼저 SVG 안에 script, foreignObject, 외부 URL, href, 이벤트 핸들러, data: URL, <image> 태그가 없는지 검사한다. 검사를 통과한 파일만 apps/web/public/images/content/** 아래로 복사하고, MDX의 cover metadata를 kind: "generated"로 교체한다.

bash
pnpm --filter @app/web run cover:auto -- \
  --provider codex-svg \
  --path apps/web/content/SEOJing/cover-automation-codex-test.mdx \
  --limit 1 \
  --force \
  --write

이 실험의 첫 결과는 Wikimedia 검색 이미지에서 Codex가 만든 정적 SVG였고, 이후 같은 파이프라인에 리소그래프 PNG 변환을 얹었다. 중요한 점은 “생성”이 렌더러의 별도 예외가 아니라는 것이다. 검색 이미지든 Codex 생성물이든 최종적으로는 같은 cover.src, cover.alt, cover.caption, cover.kind 구조로 들어간다.

다만 이건 Codex CLI가 직접 PNG를 뱉은 것이 아니라, Codex가 코드형 시각 자료를 만든 경로다. OpenAI 문서에 나온 gpt-image-1.5 기반 이미지 반복 기능이 Codex 제품 안에 열려 있더라도, 지금 CLI 자동화에서 확인된 안정 경로는 “Codex로 안전한 SVG/HTML 시각 자산을 만들고 블로그 cover 파이프라인에 넣는 방식”이다.


이 실험에서 정리된 기준

이번 실험 뒤에 대표 이미지 자동화의 기준은 조금 더 명확해졌다.

  • 검색 이미지는 빠르고 출처를 남기기 쉽다. 다만 추상적인 OkayJing 글에는 종종 generic하게 보인다.
  • 생성 이미지는 글의 분위기를 맞추기 좋다. 대신 별도 API key가 아니라 구독 기반 Hermes/Codex 도구로 실행해야 한다.
  • cover:auto는 기본적으로 dry-run이어야 한다. 이미지 자동화는 한 번에 많은 글을 바꿀 수 있어서 실수 비용이 크다.
  • cover.caption에는 검색 이미지의 출처와 라이선스를 남긴다. 생성 이미지는 어떤 생성 경로였는지 남긴다.
  • 렌더러보다 parser와 asset check가 더 중요할 수 있다. frontmatter가 content-tree에 남지 않으면 아무리 좋은 카드 컴포넌트도 이미지를 못 본다.

그래서 지금 SEOJing의 상태는 “검색 기반 대표 이미지 자동 삽입은 바로 쓸 수 있고, Codex 기반 정적 생성도 같은 파이프라인에 얹을 수 있다”에 가깝다. 다만 photorealistic 이미지 생성이나 PNG 직접 생성까지 검증한 것은 아니다. 당장 안정적으로 운영할 수 있는 생성 경로는 Codex가 만든 안전한 SVG 시각 자료를 cover asset으로 가져오는 방식이다.


참고문헌

  • Wikimedia Commons API — https://www.mediawiki.org/wiki/API:Imageinfo
  • Wikimedia Commons licensing guide — https://commons.wikimedia.org/wiki/Commons:Licensing
  • OpenAI Codex 소개 — https://openai.com/ko-KR/index/codex-for-almost-everything/
  • SEOJing 로컬 구현 파일: apps/web/scripts/generate-content-covers.mjs, apps/web/scripts/check-content-assets.mjs, apps/web/src/widgets/post-grid/PostCoverCard.tsx, packages/utils/src/frontmatter.ts
SEO Jing26. 06. 21.

대표 이미지를 글마다 다시 붙이는 방식 — 사진 검색에서.

SEOJing 포스트 목록을 파일 탐색기처럼만 두지 않고, 최신 글부터 실제 사진 기반 리소그래프 배경을 붙이는 실험을 정리합니다. 이미지는 배경만 만들고, 제목과 아이콘은 블로그 UI가 맡는 쪽으로 방향을 바꿨습니다.

SEOJing
SEO Jing26. 04. 01.

Day 12 - 테스트 커버리지 개선, 모바일 프레젠테이션 버그 2건.

SEO Jing 개발 열두째 날. code-block 테스트 14개 추가로 커버리지 대폭 개선, 모바일 프레젠테이션에서 FullscreenView 방향 전환 문제와 스크롤 멈춤 버그 수정.

SEOJing
SEO Jing26. 04. 01.

useEffect cleanup과 의존성 배열 — 실전 버그.

useEffect 의존성 배열에 불필요한 값이 포함되면 cleanup과 재실행이 뒤엉켜 DOM 상태가 꼬일 수 있다. 프레젠테이션 모드에서 발생한 모바일 스크롤 고착 버그를 통해 원인과 해결 패턴을 정리한다.

SEOJing
SEO Jing26. 03. 25.

Day 11 - 프레젠테이션 확대 기능,.

SEO Jing 개발 열한째 날. PC 프레젠테이션 확대/축소 컨트롤 추가, 모바일 orientation 판단 로직 개선, FullscreenView를 독립 컴포넌트로 분리 및 PC 대응.

SEOJing
SEO Jing26. 03. 25.

vinext 오픈소스 기여기: 한국어 slug가 RSC에서.

한국어 MDX 블로그를 만들다 vinext 프레임워크의 ByteString 버그를 발견하고, 이슈를 작성하고, PR을 올리기까지의 과정

SEOJing
SEO Jing26. 03. 25.

vinext는 왜 빠를까? — SSR, Vite, Edge,.

vinext가 빠른 이유를 이해하기 위해, SSR부터 Hydration, 빌드 도구, Edge Runtime, Web Vitals, RSC, CDN 캐싱, ISR, PPR까지 웹 렌더링 성능의 전체 그림을 정리한다

SEOJing
SEO Jing26. 03. 24.

100vh가 100%가 아닌 이유 — 모바일 뷰포트 단위 완전 정리.

모바일 Safari에서 100vh가 화면을 넘치는 이유, vh/svh/lvh/dvh의 차이, JavaScript에서 실제 뷰포트를 구하는 방법, 그리고 전체화면 UI를 만들 때 알아야 할 CSS zoom과 모바일 판정 패턴까지 정리한다.

SEOJing
SEO Jing26. 03. 23.

Day 10 - 프레젠테이션 모드 안정화.

SEO Jing 개발 열째 날. 프레젠테이션 모드의 모바일 UX 문제들을 전면 수정. 퀴즈·코드블록·이미지·포스트목록 처리 개선, 롱프레스 UX 및 하단 바 레이아웃 안정화. 모바일 뷰포트·리스트 분할 문제 수정, 채움 비율 보수적으로 조정, 포스트 탐색기 자연 정렬 적용.

SEOJing
SEO Jing26. 03. 22.

Day 9 - 프레젠테이션 모드, 코드블럭 개선, 테스팅.

SEO Jing 개발 아홉째 날. 프레젠테이션 기능 추가, 퀴즈 구조 변경, 모바일 반응형, 코드블럭 사용성, 테스팅 도입.

SEOJing
SEO Jing26. 03. 22.

모바일 웹에서 가로 모드를 강제하는 5가지 방법 — iOS.

모바일 웹에서 코드 블록을 가로로 넓게 보여주고 싶었다. screen.orientation.lock()은 iOS에서 안 되고, PWA manifest는 브라우저에서 무시된다. 결국 CSS transform으로 가짜 회전을 만들었고, 그 과정에서 엄지 접근성까지 고민하게 됐다.

SEOJing
SEO Jing26. 03. 22.

블로그 글을 PPT로 만들기 — DOM 클로닝 기반.

MDX 파일을 수정하지 않고, 렌더된 DOM을 h2 기준으로 자르고 화면 높이에 맞춰 자동 페이지네이션하는 프레젠테이션 모드를 만들었다. 리스트 높이 측정이 왜 틀리는지 디버깅한 과정과, ul/ol을 li 단위로 분할하는 해결책을 정리한다.

SEOJing
SEO Jing26. 03. 21.

Day 8 - 아티클 퀴즈와 스터디 자료.

SEO Jing 개발 여덟째 날. 아티클 퀴즈 디자인시스템 구현과 스터디 대면 자료 작성.

SEOJing
SEO Jing26. 03. 21.

Context로 퀴즈 컴포넌트를 만들다 막혀서.

MDX 블로그에 퀴즈 컴포넌트를 만들면서, Context 기반 Compound Component로 시작했다가 index 문제에 막혀 React.Children API를 채택하게 된 과정을 정리한다.

SEOJing
SEO Jing26. 03. 20.

Day 7 - Front Matter CMS와 관련 게시물.

SEO Jing 개발 일곱째 날. Front Matter CMS 설치와 관련 게시물 이동 탐색기 구현.

SEOJing
SEO Jing26. 03. 18.

Day 6 - 스터디 자료 작성과 데스크탑 비율 수정.

SEO Jing 개발 여섯째 날. 데스크탑 비율 수정과 씨랩 스터디 사전 진단 자료 작성.

SEOJing
SEO Jing26. 03. 17.

Day 5 - shiki 제거, MDX 모듈화, 그리고.

SEO Jing 개발 다섯째 날. shiki를 rehype-prism-plus로 교체하고, gray-matter 직접 구현, MDX 모듈화, 페이지 내 검색, 테이블 디자인시스템까지.

SEOJing
SEO Jing26. 03. 16.

Day 4 - 배포와 CI/CD.

SEO Jing 개발 넷째 날. lint, codecov, Cloudflare 배포, fs 런타임 이슈.

SEOJing
SEO Jing26. 03. 16.

Cloudflare Workers에서 fs 모듈이 안 되는 이유와.

배포 후 블로그 포스트가 404를 반환하던 문제부터, gray-matter eval 차단, next-mdx-remote eval 차단까지 — 세 겹으로 터진 이슈를 하나씩 해결한 기록

SEOJing
SEO Jing26. 03. 16.

localStorage 읽기에서 하이드레이션 에러가 터지는 이유.

localStorage를 읽는 컴포넌트에서 하이드레이션 불일치가 발생하는 원인과, useState+useEffect가 아닌 useSyncExternalStore가 정답인 이유를 정리한다.

SEOJing
SEO Jing26. 03. 16.

vinext + GitHub Actions로.

vinext 프로젝트를 GitHub Actions로 Cloudflare Workers에 자동 배포하는 방법과 실제 겪은 트러블슈팅 기록

SEOJing
SEO Jing26. 03. 16.

RSC 환경에서 WebAssembly가 차단되는 이유 —.

코드 하이라이팅에 Shiki를 쓰면 왜 RSC에서 WebAssembly.instantiate() 에러가 터지는지, 그리고 빌드 타임 하이라이팅으로 어떻게 해결했는지 정리한다.

SEOJing
SEO Jing26. 03. 15.

엄청난 피드백.

CLI 코드 리뷰에서 받은 피드백과 전체 코드 수정 계획을 정리했다.

SEOJing
SEO Jing26. 03. 15.

생각보다 어려웠던 댓글, 완독 로컬스토리지.

localStorage만으로 글 읽기 추적, 스크롤 진행률, 댓글 감지를 구현한 과정을 정리했다.

SEOJing
SEO Jing26. 03. 15.

MDX 관련 이슈 노트.

블로그 디테일 페이지에서 MDX를 렌더링하기 위해 검토한 라이브러리들과 최종 선택 과정.

SEOJing
SEO Jing26. 03. 15.

Day 3 - MDX 이슈, 반응형, 다크모드.

SEO Jing 개발 셋째 날. MDX 라이브러리 이슈, 반응형, 코드블럭, 댓글, 다크모드, 코드 리뷰.

SEOJing
SEO Jing26. 03. 14.

디자인 시스템을 구축할 때 주의할 점.

디자인 시스템 구현 시 파일 구조, 디자인 토큰, 유의 사항을 정리했다.

SEOJing
SEO Jing26. 03. 14.

폰트는 왜 메인 페이지에서만 적용이 안되고 있었을까?.

Tailwind v4 환경에서 폰트가 메인 페이지에서만 적용되지 않던 원인과 Hydration Mismatch 이슈를 정리했다.

SEOJing
SEO Jing26. 03. 14.

MDX DOM 트리 파싱하기.

MDX 파일의 경로 탐색 로직과 콘텐츠 트리 생성 과정을 정리했다.

SEOJing
SEO Jing26. 03. 14.

결국 Node.js 까지 와버렸다.

MDX 파일 구조를 JSON으로 변환하기 위해 Node.js의 fs 모듈을 배워봤다.

SEOJing
SEO Jing26. 03. 14.

Day 2 - 블로그 스켈레톤과 MDX 파싱.

SEO Jing 개발 둘째 날. 디자인 시스템 확장, 블로그 스켈레톤, 폰트 이슈 해결.

SEOJing
SEO Jing26. 03. 13.

전체적인 플로우.

SEO Jing 프로젝트의 기술 스택 선정과 전체적인 개발 플로우 정리.

SEOJing
SEO Jing26. 03. 13.

Storybook으로 디자인 시스템 테스팅하기.

Storybook의 사용법과 디자인 시스템 개발에서의 장점을 정리했다.

SEOJing
SEO Jing26. 03. 13.

MDX가 뭘까?.

MDX의 개념과 블로그에서 활용하는 이유를 정리했다.

SEOJing
SEO Jing26. 03. 13.

Day 1 - 디자인 컨셉과 디자인 시스템.

SEO Jing 개발 첫째 날. 디자인 컨셉 설정과 디자인 시스템 구축을 시작했다.

SEOJing
SEO Jing26. 03. 13.

기술 블로그를 직접 제작하게 된 이유.

SEO Jing을 개발하게 된 이유입니다.

SEOJing
SEO Jing26. 03. 13.

왜 자꾸 프로젝트가 중단되는지.

프로젝트가 중단되는 이유에 대한 자기 회고입니다.

SEOJing