Skip to content

Architecture

β€œMinjung edited this page Sep 26, 2026 · 3 revisions

Architecture

전체 데이터 νŒŒμ΄ν”„λΌμΈ

HackDigest의 핡심은 5단계 νŒŒμ΄ν”„λΌμΈμž…λ‹ˆλ‹€:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   1. FETCH  │────►│   2. RANK   │────►│ 3. SUMMARIZE│────►│  4. CACHE   │────►│  5. DELIVER β”‚
β”‚  (fetchers) β”‚     β”‚  (scoring)  β”‚     β”‚ (Groq LLM)  β”‚     β”‚ (JSON file) β”‚     β”‚ (Gmail SMTP)β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

상세 흐름

cronjob.io (맀일 KST 10:15)
  β”‚
  β–Ό workflow_dispatch
GitHub Actions Workflow (daily-digest.yml)
  β”‚
  β”œβ”€β”€ 1. λ³΄μ•ˆ μŠ€μΊ” (security-scan job)
  β”‚     └── ν•˜λ“œμ½”λ”©λœ μ‹œν¬λ¦Ώ 검사
  β”‚
  β”œβ”€β”€ 2. μΊμ‹œ 볡원 (GitHub Actions Cache)
  β”‚     └── data/cache/ 디렉토리
  β”‚
  └── 3. νŒŒμ΄ν”„λΌμΈ μ‹€ν–‰ (python -m src.main)
        β”‚
        β”œβ”€β”€ κ΅¬λ…μž λ‘œλ“œ (subscribers.json)
        β”‚
        β”œβ”€β”€ (topic, language) μ‘°ν•© 계산
        β”‚     예: (tech, ko), (stocks, en), (realestate, ko)
        β”‚
        β”œβ”€β”€ Fetch: 토픽별 기사 μˆ˜μ§‘
        β”‚   β”œβ”€β”€ tech:       Hacker News API β†’ μƒμœ„ 50개 필터링 β†’ Top 5
        β”‚   β”œβ”€β”€ stocks(en): Yahoo Finance RSS
        β”‚   β”œβ”€β”€ stocks(ko): Google News Korea RSS
        β”‚   β”œβ”€β”€ realestate(en): Zillow + HousingWire + CNBC RSS
        β”‚   └── realestate(ko): Google News Korea RSS
        β”‚
        β”œβ”€β”€ Summarize: μΊμ‹œ 미슀 κΈ°μ‚¬λ§Œ Groq API 호좜
        β”‚   β”œβ”€β”€ trafilatura둜 기사 λ³Έλ¬Έ μΆ”μΆœ
        β”‚   β”œβ”€β”€ 3000자 μ œν•œ β†’ Groq qwen/qwen3.8-27b
        β”‚   β”œβ”€β”€ 언어별 ν”„λ‘¬ν”„νŠΈ (ν•œκ΅­μ–΄: 캐주얼 λΈ”λ‘œκ±°, μ˜μ–΄: casual)
        β”‚   β”œβ”€β”€ Rate limit μ‹œ μ§€μˆ˜ λ°±μ˜€ν”„ μž¬μ‹œλ„ (μ΅œλŒ€ 3회)
        β”‚   └── μ‹€νŒ¨ μ‹œ Google Translate 폴백
        β”‚
        β”œβ”€β”€ Cache: 기사 + μš”μ•½ JSON μ €μž₯
        β”‚
        └── Deliver: κ΅¬λ…μžλ³„ 이메일 λ°œμ†‘
            β”œβ”€β”€ 단일 SMTP μ—°κ²°λ‘œ λͺ¨λ“  이메일 처리
            β”œβ”€β”€ HTML ν…œν”Œλ¦Ώ: λͺ¨λ°”일 μΉœν™”μ 
            β”œβ”€β”€ ꡬ독 ν•΄μ§€ 링크 포함
            └── μ‹€νŒ¨ μ‹œ λ‹€μŒ κ΅¬λ…μžλ‘œ 계속

ꡬ독 흐름

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  ꡬ독 νŽ˜μ΄μ§€          β”‚
β”‚  (GitHub Pages)      β”‚
β”‚  docs/index.html     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚ POST (이메일, μ–Έμ–΄, ν† ν”½)
           β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Cloudflare Worker   β”‚
β”‚  worker/src/index.js β”‚
β”‚                      β”‚
β”‚  ─ CORS 검증         β”‚
β”‚  ─ Rate limiting     β”‚
β”‚  ─ μž…λ ₯ 검증         β”‚
β”‚  ─ 이메일 길이 μ œν•œ   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚ repository_dispatch
           β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  GitHub Actions      β”‚
β”‚  subscribers.yml     β”‚
β”‚                      β”‚
β”‚  ─ subscribers.json  β”‚
β”‚    에 μΆ”κ°€/μ‚­μ œ       β”‚
β”‚  ─ ν™˜μ˜ 이메일 λ°œμ†‘   β”‚
β”‚  ─ 변경사항 컀밋+ν‘Έμ‹œ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

토픽별 데이터 μ†ŒμŠ€

Tech (μ–Έμ–΄ 독립적)

  • μ†ŒμŠ€: Hacker News API (hacker-news.firebaseio.com)
  • 방식: Top Stories β†’ μƒμœ„ 50개 fetch β†’ λΉ„κΈ°μˆ  필터링 β†’ 점수순 Top 5
  • 필터링: μ •μΉ˜, 슀포츠, λ‹€μ΄μ–΄νŠΈ, 유λͺ…인 λ“± λΉ„κΈ°μˆ  ν‚€μ›Œλ“œ μ œμ™Έ

Stocks (μ–Έμ–΄ 의쑴적)

  • μ˜μ–΄: Yahoo Finance RSS
  • ν•œκ΅­μ–΄: Google News Korea (주식+μ½”μŠ€ν”Ό+μ½”μŠ€λ‹₯, μ¦μ‹œ+μ£Όκ°€+상μž₯)
  • 필터링: 주식/μ‹œμž₯ κ΄€λ ¨ ν‚€μ›Œλ“œ λ§€μΉ­ (μ˜μ–΄/ν•œκ΅­μ–΄ 별도 νŒ¨ν„΄)

Real Estate (μ–Έμ–΄ 의쑴적)

  • μ˜μ–΄: Zillow Research + HousingWire + CNBC Real Estate RSS
  • ν•œκ΅­μ–΄: Google News Korea (뢀동산+μ•„νŒŒνŠΈ+λ§€λ§€, 뢀동산+μ „μ„Έ+λΆ„μ–‘)
  • 필터링: 뢀동산 κ΄€λ ¨ ν‚€μ›Œλ“œ λ§€μΉ­

캐싱 μ „λž΅

data/cache/
β”œβ”€β”€ articles_{topic}.json        # 기사 μΊμ‹œ (토픽별)
└── summaries_{language}.json    # μš”μ•½ μΊμ‹œ (언어별)
  • GitHub Actions Cacheλ₯Ό μ‚¬μš©ν•˜μ—¬ 일간 μΊμ‹œ
  • 같은 기사가 μ—¬λŸ¬ κ΅¬λ…μžμ—κ²Œ λ°œμ†‘λ  λ•Œ 쀑볡 API 호좜 λ°©μ§€
  • μš”μ•½μ€ μ–Έμ–΄λ³„λ‘œ μΊμ‹œ (ν•œκ΅­μ–΄ μš”μ•½κ³Ό μ˜μ–΄ μš”μ•½μ€ 별도)
  • μΊμ‹œ ν‚€: hackdigest-v2-{run_id} (μ‹€ν–‰λ§ˆλ‹€ μƒˆ μΊμ‹œ 생성, 이전 μΊμ‹œμ—μ„œ 볡원)

λ³΄μ•ˆ 섀계

λ ˆμ΄μ–΄ 보호
Cloudflare Worker CORS origin μ œν•œ, Rate limiting (λΆ„λ‹Ή 5건, μ‹œκ°„λ‹Ή 20건), ν•„λ“œ ν™”μ΄νŠΈλ¦¬μŠ€νŠΈ, Body 크기 μ œν•œ (1KB)
GitHub Actions ν•˜λ“œμ½”λ”© μ‹œν¬λ¦Ώ μŠ€μΊ”, Bandit 정적 뢄석
이메일 URL sanitization (http/https만), HTML escape
κ΅¬λ…μž 관리 μ΅œλŒ€ 500λͺ… μ œν•œ, 이메일 ν˜•μ‹ 검증