1편에서 소개한 Self-Tuning Loop 패턴을 실제로 운영하는 시스템의 전체 아키텍처. 데이터 수집(35개 소스), AI 큐레이션, Telegram 입력 파이프라인, 주간 자동 리뷰, Syncthing 기반 무배포 프롬프트 진화까지.
이전 편에서 Self-Tuning Loop의 개념을 소개했습니다. AI 초안과 사용자 최종본의 diff를 캡처하고, 패턴을 분석하여 프롬프트를 자동 진화시키는 4단계 순환.
이번 편에서는 이 루프를 실제로 6주째 운영하고 있는 시스템을 해부합니다. 이론이 아닌 프로덕션 환경의 이야기입니다.
시스템 개요: 하나의 대시보드, 다섯 개의 자동화
이 시스템은 개인의 반복 업무를 하나로 모아서 AI가 처리하고, 그 결과를 피드백 루프로 개선하는 구조입니다.
graph TD
subgraph 수집 ["Layer 1: 자동 수집 (04:00 KST)"]
RSS["RSS 19개"]
HN["Hacker News 8쿼리"]
WEB["GitHub Trending + HF Papers"]
RED["Reddit 2개"]
TAV["Tavily 검색 7개"]
STATS["GA4 + GitHub + Naver"]
end
subgraph 저장 ["Layer 2: Supabase"]
RAW["daily_news_raw"]
DN["daily_news (큐레이션 20개)"]
DS["daily_stats"]
LD["linkedin_drafts"]
TQ["task_queue"]
end
subgraph AI ["Layer 3: AI 처리"]
CURATE["뉴스 큐레이션 (06:30)"]
LINKEDIN["LinkedIn 드래프트 (10:00)"]
DISPATCH["태스크 디스패처 (매시)"]
end
subgraph 피드백 ["Layer 4: Self-Tuning Loop"]
FB["👍/👎 + 북마크 + 편집 diff"]
REVIEW["주간 자동 리뷰 (토 03:00)"]
EVOLVE["프롬프트 자동 패치"]
end
RSS & HN & WEB & RED & TAV --> RAW
STATS --> DS
RAW --> CURATE --> DN
DN --> FB --> REVIEW --> EVOLVE
EVOLVE -->|"다음 주 큐레이션 개선"| CURATE
다섯 가지 자동화가 돌아가고 있습니다.
| 자동화 | 주기 | 하는 일 |
|---|---|---|
| 뉴스 수집 | 매일 04:00 | 35개 소스에서 뉴스 수집 → dedup → 저장 |
| AI 큐레이션 | 매일 06:30 | 150개 → 20개 선별 + 요약 |
| LinkedIn 드래프트 | 매일 10:00 | 전일 뉴스 + 피드백 기반 포스트 2건 생성 |
| 태스크 디스패처 | 매시 정각 | Telegram 입력 처리 (블로그/리서치/아이디어) |
| 주간 리뷰 | 토요일 03:00 | 큐레이션 품질 분석 + 프롬프트 자동 패치 |
추가 비용: $0. 전체 스택이 무료 티어로 작동합니다.
이 시스템이 돌아가는 하드웨어
다른 프로젝트를 위해 구매했던 Mini PC가 있었습니다. Intel N100, 16GB RAM, Windows 11. 원래는 Slack 기반 AI 에이전트 프레임워크(OpenClaw, 이후 BoltShark로 전환)를 24/7 운영하려고 산 것이었는데, 프로젝트가 아카이브되면서 하드웨어만 남았습니다.
이 유휴 장비를 재활용했습니다.
| 컴포넌트 | 역할 | 실행 환경 |
|---|---|---|
| pm2 + node-cron | 뉴스/Stats 수집 크론 | WSL Ubuntu |
| Claude Desktop | AI 큐레이션, LinkedIn 드래프트, 태스크 디스패처 | Windows |
| Syncthing | Mac ↔ Mini PC 파일 동기화 | Windows + Mac |
WSL Ubuntu에서 Node.js 크론이 돌고, Windows의 Claude Desktop이 스케줄 태스크로 AI 작업을 처리합니다. 두 환경은 /mnt/c/ 경로로 연결됩니다.
Layer 1: 데이터 수집 — 35개 소스, 자동 dedup
매일 04:00 KST에 node-cron이 35개 소스에서 뉴스를 수집합니다.
| 카테고리 | 소스 | 수집 방식 |
|---|---|---|
| 공식 블로그 (Tier 1) | OpenAI, Google AI, DeepMind, HuggingFace, NVIDIA, Meta | RSS |
| 전문가 (Tier 2) | Simon Willison, Ahead of AI, One Useful Thing, Latent Space | RSS |
| 미디어 (Tier 3) | TechCrunch AI, VentureBeat AI, MIT Tech Review | RSS |
| 한국 (Tier 4) | AI Times, MIT Tech Review KR, GeekNews, PyTorch Korea | RSS |
| 커뮤니티 | Hacker News (8개 키워드), Reddit (r/ML, r/LocalLLaMA) | API + RSS |
| 검색 | Anthropic, BCG, Bain, Deloitte, Gartner, Stanford HAI | Tavily |
| 트렌드 | GitHub Trending Python, HuggingFace Papers | 스크래핑 |
수집 후 3단계 dedup이 적용됩니다.
1. URL 정규화 — 쿼리 파라미터, trailing slash 제거 후 비교 2. 제목 유사도 — 동일 뉴스가 다른 URL로 배포된 경우 필터링 3. 토픽 워드 매칭 — 3개 이상 키워드가 겹치면 중복 후보로 표시
결과: 매일 50~200개 항목이 daily_news_raw 테이블에 저장됩니다. 실패한 소스 목록도 함께 기록됩니다.
04:05 — Stats 수집
뉴스와 별도로 운영 지표도 수집합니다.
| 소스 | 데이터 |
|---|---|
| Google Analytics 4 | 3개 프로퍼티의 세션, 유저, 페이지뷰, 유입 소스 |
| GitHub API | 5개 레포의 스타, 트래픽, stale 감지 |
| Naver Blog | 4일간 방문자 + 일평균 |
Safety-net: 크론을 신뢰하지 않는다
WSL2 환경에서 node-cron이 조용히 실행을 건너뛰는 사건이 발생했습니다. pm2는 “online” 상태였지만, 04:05 스케줄의 로그 자체가 없었습니다. WSL2 VM이 idle 상태에서 일시 정지되면서, cron의 매 분 폴링 루프가 해당 시각을 건너뛴 것으로 추정됩니다.
이후 3중 방어를 구축했습니다.
1. 전역 crash handler — uncaughtException, unhandledRejection 캐치
2. Startup catch-up — 프로세스 재시작 시 오늘 데이터 누락이면 즉시 보충
3. 06:00 safety-net cron — 결과 행(row) 존재 여부로 재검증. 없으면 재실행
핵심 교훈: pm2 “online”은 CPU가 돌고 있다는 보장이 아닙니다. 크론을 신뢰하지 말고, 결과를 검증해야 합니다.
Layer 2: AI 큐레이션 — 150개 → 20개
매일 06:30 KST, Claude Desktop의 스케줄 태스크가 curate-daily-news.md 프롬프트를 읽고 실행합니다.
큐레이션 기준
AI가 150개 원본에서 20개를 선별할 때 적용하는 기준:
| 기준 | 설명 |
|---|---|
| 신선도 | 14일 이내 (60일이었다가 리뷰 후 축소) |
| 중복 제거 | 직전 2일 daily_news와 URL 비교 |
| Tier 가중치 | 공식 블로그 > 전문가 > 미디어 > 커뮤니티 |
| 카테고리 분산 | Model, Method, Tool, Product, Industry 골고루 |
| 컨설팅펌 우선 | BCG, Bain, Deloitte 등 14일 이내 → 자동 포함 |
결과는 3-tier로 분류됩니다.
Must-Read (빨강) — 놓치면 안 되는 핵심 뉴스 Notable (앰버) — 알아두면 좋은 것 FYI (기본) — 참고용
대시보드에서 보이는 것
웹 대시보드(Lovable + Supabase)에서 당일 큐레이션 결과를 확인합니다. 각 뉴스 카드에는:
- 카테고리 컬러 뱃지 (Model=보라, Tool=초록, Product=주황 등)
- 저장 토글 (북마크)
- 👍/👎 피드백 + 코멘트
- 실패 소스 경고 배너
이 피드백이 Layer 4의 Self-Tuning Loop으로 흘러갑니다.
Layer 3: Telegram 입력 파이프라인 — 폰에서 시스템으로
이 시스템에서 가장 독특한 부분입니다. Telegram Bot이 모바일 입력 레이어 역할을 합니다.
graph LR
PHONE["📱 Telegram"] -->|"사진 + 캡션"| WEBHOOK["Supabase Edge Function"]
WEBHOOK -->|"Vision + Tavily 전처리"| TQ["task_queue 테이블"]
TQ -->|"매시 정각"| DISPATCH["Claude Desktop 디스패처"]
DISPATCH -->|"타입별 라우팅"| RESULT["블로그/LinkedIn/리서치/아이디어"]
작동 방식
1. Telegram에서 사진과 캡션을 보냅니다. 키워드(/blog, /linkedin, /research, /idea)로 타입을 지정하거나, 한국어 키워드(블로그, 글감)도 인식합니다. 사진만 보내면 기본값 blog로 분류됩니다.
2. Supabase Edge Function(receive-telegram)이 웹훅으로 수신합니다.
- 앨범(사진 여러 장)은
media_group_id로 묶어서 1건으로 처리 - OpenAI Vision으로 사진 설명 생성
- Tavily + Naver 검색으로 관련 정보 전처리
- 결과를
task_queue테이블에pending으로 저장
3. Mini PC의 Claude Desktop이 매시 정각에 process-queue.md 프롬프트를 읽고, pending 태스크를 처리합니다.
blog→ 네이버 블로그 초안 (3,500~5,000자, 9섹션 구조, 사진 배치)linkedin→ LinkedIn 포스트 드래프트research→ secondbrain에 리서치 노트 저장idea/todo→ secondbrain에 저장
4. 완료 시 Telegram으로 알림이 옵니다.
핵심 가치: 이동 중에 사진 한 장 보내면 됩니다. 나머지는 시스템이 처리합니다.
Layer 4: Self-Tuning Loop — 실제 작동
여기가 1편에서 다룬 개념이 실제로 구현된 부분입니다.
뉴스 큐레이션의 자기 개선
graph TD
GEN["Generate: 큐레이션 프롬프트로 20개 선별"]
CAP["Capture: 👍/👎 + 북마크 + 코멘트"]
ANA["Analyze: 주간 리뷰 (토 03:00)"]
EVO["Evolve: 큐레이션 프롬프트 자동 패치"]
GEN --> CAP
CAP --> ANA
ANA --> EVO
EVO -->|"다음 주 큐레이션 개선"| GEN
Generate: 매일 06:30, curate-daily-news.md 프롬프트가 뉴스 20개를 선별합니다.
Capture: 대시보드에서 사용자가 피드백을 남깁니다.
- 👍 “이 뉴스는 좋았다” / 👎 “이건 필요 없었다”
- 북마크 “나중에 다시 볼 것”
- 코멘트 “이런 유형 더 보고 싶다”
- 뉴스 URL 직접 제출 “이 기사가 빠졌다”
Analyze: 매주 토요일 03:00, weekly-review.md 프롬프트가 자동 실행됩니다.
- 7일간의 피드백 데이터 조회
- 선별 패턴 분석 (어떤 카테고리를 선호하는지, 어떤 소스가 반복 저평가되는지)
- 사용자 제출 뉴스 분석 (큐레이션에서 빠진 것은 무엇이고 왜 빠졌는지)
Evolve: 분석 결과를 바탕으로 큐레이션 프롬프트를 자동 패치합니다.
- Safe 변경 (빈도 높은 스타일/우선순위 조정) → git commit + push로 자동 반영
- Risky 변경 (소스 추가/제거, 구조적 변경) → Telegram으로 제안만 전송
실제로 운영 초기(60일 신선도 필터)에서 주간 리뷰를 거쳐 14일 필터로 축소된 것이 자동 패치의 결과입니다.
LinkedIn 드래프트의 자기 개선
LinkedIn 쪽도 같은 루프가 돌고 있습니다.
Generate: 매일 10:00, daily-linkedin-draft.md가 2건의 드래프트를 생성합니다. 전일 뉴스에서 👍을 받거나 북마크된 항목을 우선 소재로 선정합니다.
Capture: 대시보드의 LinkedIn Studio에서 드래프트를 편집합니다. 톤, 해시태그, 구조를 수정하고 발행합니다. 원본 드래프트와 최종 발행본이 모두 linkedin_drafts 테이블에 저장됩니다.
Analyze + Evolve: 매주 토요일 03:15, weekly-linkedin.md가 발행된 포스트들의 편집 패턴을 분석하고, 톤 가이드를 자동 업데이트합니다.
프롬프트 진화의 배포: Syncthing
여기서 핵심적인 인프라 디테일이 있습니다. 프롬프트 파일의 업데이트에 별도 배포가 필요 없습니다.
Mac과 Mini PC 사이에 Syncthing이 4개 폴더를 실시간 양방향 동기화합니다.
| 폴더 | 내용 | 배포 |
|---|---|---|
memory/ | Claude Code의 메모리 파일 | 자동 싱크 |
claude-commands/ | 커스텀 슬래시 명령 | Mac → Mini PC (단방향) |
secondbrain/ | 리서치 노트, 아이디어 | 양방향 |
minbook-content/ | 블로그 콘텐츠 | 양방향 |
Claude Desktop의 스케줄 태스크는 매 실행 시 프롬프트 파일을 디스크에서 직접 읽습니다. 따라서:
1. Mac에서 daily-linkedin-draft.md의 톤 가이드를 수정합니다
2. Syncthing이 Mini PC로 자동 동기화합니다 (수 초 이내)
3. 다음 10:00 KST 실행 시 수정된 프롬프트가 바로 반영됩니다
pm2 재시작도 없고, git push도 없고, 배포 과정이 0입니다. 주간 리뷰가 프롬프트를 자동 패치하면, 그 파일이 Syncthing으로 싱크되고, 다음 실행부터 즉시 적용됩니다.
이것이 Self-Tuning Loop의 Evolve 단계가 실제로 마찰 없이 작동하는 이유입니다.
graph LR
REVIEW["주간 리뷰<br/>(토 03:00)"] -->|"프롬프트 패치"| FILE["prompts/*.md<br/>(Mini PC)"]
FILE -->|"Syncthing 싱크"| MAC["Mac에서도<br/>수정 가능"]
MAC -->|"Syncthing 싱크"| FILE
FILE -->|"다음 실행 시<br/>자동 반영"| CLAUDE["Claude Desktop<br/>스케줄 태스크"]
코드 변경은 git으로
프롬프트가 아닌 소스 코드(collect-news.ts, collect-stats.ts 등)를 수정할 때는 기존 방식을 따릅니다.
Mac에서 코드 수정 → git push → Mini PC에서 git pull → pm2 restart
하지만 Self-Tuning Loop에서 진화하는 것은 프롬프트 파일이지 소스 코드가 아닙니다. 프롬프트 진화에는 배포 과정이 없다는 것이 이 아키텍처의 핵심 장점입니다.
$0 비용 구조
| 컴포넌트 | 서비스 | 비용 |
|---|---|---|
| DB + Auth + Edge Function + Storage | Supabase (무료 티어) | $0 |
| 뉴스 검색 (월 1,000건) | Tavily (무료 티어) | $0 |
| AI 큐레이션 + 디스패처 + 리뷰 | Claude Desktop (Max 구독 포함) | $0 추가 |
| 웹 대시보드 | Lovable (무료 티어) | $0 |
| 파일 동기화 | Syncthing (오픈소스) | $0 |
| 24/7 서버 | Mini PC (기존 보유) | 전기세만 |
| 합계 | $0 추가 비용 |
Mini PC는 다른 프로젝트(Slack AI 에이전트)를 위해 이미 구매한 것이고, Claude Max 구독도 개발용으로 이미 사용 중이었습니다. 이 시스템을 위해 추가로 지출한 비용은 없습니다.
크론 스케줄 전체
| 시간 (KST) | 작업 | 실행 환경 | 비고 |
|---|---|---|---|
| 04:00 | 뉴스 수집 (35개 소스) | pm2 node-cron | |
| 04:05 | Stats 수집 (GA4 + GitHub + Naver) | pm2 node-cron | |
| 06:00 | Safety-net 재검증 | pm2 node-cron | 누락 시 재실행 |
| 06:30 | AI 뉴스 큐레이션 | Claude Desktop | |
| 09:30 | Minbook 메타데이터 동기화 | pm2 node-cron | GitHub API |
| 10:00 | LinkedIn 자동 드래프트 2건 | Claude Desktop | |
| 매시 :00 | Telegram 태스크 디스패처 | Claude Desktop | |
| 토 03:00 | 주간 뉴스 품질 리뷰 | Claude Desktop | Self-Tuning |
| 토 03:15 | 주간 LinkedIn 패턴 분석 | Claude Desktop | Self-Tuning |
모든 pm2 cron에 { timezone: 'Asia/Seoul' } 명시. WSL2 환경에서 호스트 시간대 드리프트를 방지합니다.
6주 운영 데이터
뉴스 큐레이션
| 지표 | 초기 (Week 1) | 현재 (Week 6) | 변화 |
|---|---|---|---|
| 일일 수집량 | 80~120개 | 130~200개 | 소스 최적화 후 증가 |
| 실패 소스 비율 | 15~20% | 5% 이내 | RSS URL 수정 + 폴백 |
| 신선도 필터 | 60일 | 14일 | 주간 리뷰 자동 조정 |
| cross-day 중복 | 미검사 | 직전 2일 검사 | 주간 리뷰 제안 → 구현 |
인시던트
| 날짜 | 사건 | 원인 | 대응 |
|---|---|---|---|
| 4/4 | GeekNews RSS 403 | URL 변경 | /rss/news로 수정 |
| 4/4 | Naver visitors 0 | 날짜 형식 불일치 | 전체 visitor 수집 후 최신값 |
| 4/8 | daily_stats 누락 | WSL2 cron silent miss | 3중 방어 구축 (Phase 4.2) |
| 4/12 | 블로그 태스크 17.5시간 | 파일 생성 시 퍼미션 팝업 블로킹 | 임시 파일 금지 규칙 + heredoc 패턴 |
자동 프롬프트 패치 이력
주간 리뷰가 실제로 패치한 것들:
- 신선도 필터: 60일 → 14일 (오래된 기사 반복 선별 문제)
- cross-day URL dedup 추가 (직전 2일
daily_newslookback) - 컨설팅펌 뉴스 우선순위 조건에 14일 이내 제한 추가
- LinkedIn 드래프트 톤: 6타입 템플릿 체계화
아키텍처 요약
graph TB
subgraph Mac ["💻 Mac (개발)"]
CODE["코드 수정"]
PROMPT_EDIT["프롬프트 수정"]
DASH["대시보드 (브라우저)"]
end
subgraph Sync ["🔄 Syncthing"]
S["실시간 양방향 동기화"]
end
subgraph MiniPC ["🖥 Mini PC (운영)"]
PM2["pm2 크론<br/>수집 + safety-net"]
CD["Claude Desktop<br/>큐레이션 + 디스패치 + 리뷰"]
PROMPTS["prompts/*.md"]
end
subgraph Cloud ["☁️ Cloud"]
SB["Supabase<br/>DB + Auth + Edge Function"]
TG["Telegram Bot<br/>입력 + 알림"]
LV["Lovable<br/>웹 대시보드"]
end
CODE -->|"git push/pull"| PM2
PROMPT_EDIT --> S --> PROMPTS
PM2 -->|"수집 데이터"| SB
CD -->|"읽기/쓰기"| SB
CD -->|"프롬프트 로드"| PROMPTS
TG -->|"webhook"| SB
SB --> LV
LV --> DASH
5개 레이어, $0 추가 비용, 24/7 자동 운영.
Mini PC가 없어도 구현 가능합니다. Mac이 24/7 켜져 있거나, 클라우드 VM을 쓰면 됩니다. 핵심은 크론 + AI 디스패처 + 피드백 DB + 파일 싱크라는 조합이지, 특정 하드웨어가 아닙니다.
다음 편 예고
이 시스템은 특정 개인의 워크플로우에 맞춰져 있습니다. 다음 편에서는 Self-Tuning Loop의 핵심 패턴을 누구든 적용할 수 있는 모듈로 추출하고, GitHub에 레퍼런스 구현을 공개합니다.
- 4단계 루프를 범용 모듈로 분리
- Supabase 스키마 + 분석/진화 프롬프트 전문 공개
- 이메일, 블로그 적용 예시
- Quick Start 가이드
참고 자료
- Supabase Documentation: https://supabase.com/docs
- Syncthing: https://syncthing.net
- Claude Desktop Scheduled Tasks: Anthropic Claude Max 기능
- node-cron: https://github.com/node-cron/node-cron
- pm2 Process Manager: https://pm2.keymetrics.io
관련 글

Self-Tuning Loop 직접 만들기 — 레퍼런스 구현 가이드
Self-Tuning Loop 4단계(Generate → Capture → Analyze → Evolve)를 범용 모듈로 추출. Supabase DDL, diff 캡처 유틸, 분석/진화 프롬프트 전문, 이메일/블로그 적용 예시, GitHub 레퍼런스 구현.

멀티엔진 아키텍처 — 3개 AI 엔진 병렬 수집 구조
AI 검색 엔진 간 응답 편차를 시그널로 활용하는 멀티엔진 아키텍처 설계 원칙과 병렬 수집 구조, 어댑터 패턴을 통한 확장성 확보 방법 분석

모니터링 없이 론칭하면 생기는 일
Sentry와 Betterstack을 활용해 $0로 구축하는 최소 모니터링 가이드와 론칭 전 80분 투자가 에러 대응 시간을 13시간에서 1시간으로 단축한 사례 분석