관점을 비교하는 법
숙지빈 폴더에서 superpowers 워크플로로 설계하고 Phase 단위로 빌드합니다. 2시간 트랙이라 키 발급이 없고(4개 매체 공개 RSS), 마감은 CloudFront 실배포입니다. 소스는 영문 3개 + 한국어 1개지만, 화면의 토픽과 비교 브리핑은 전부 한국어입니다(원문 제목 병기).
| 레이어 | 구성 | 핵심 원칙 |
|---|---|---|
| 수집 | BBC / Guardian / NHK World / 연합뉴스 RSS를 120초 폴링 | 소스별 실패 격리, 피드 하나가 죽어도 뉴스룸은 산다 |
| 저장 | 기사 link 멱등 딕셔너리(소스별 50건) | 본문은 저장하지 않는다, 헤드라인 + 요약 + 링크만 |
| 렌즈 | 공통 토픽 클러스터 + 매체별 프레임을 JSON 계약으로 | LLM 출력이 곧 화면 데이터, 계약이 무너지면 화면도 무너진다 |
| 개장 | CDK로 CF → prefix SG → ALB → Fargate | Bearer는 Secrets 기동 주입, 이미지에 비밀 없음 |
1. 뉴스룸 (기본 뷰)
| 기능 | 설명 |
|---|---|
| 4열 그리드 | 매체별 최신 헤드라인 카드, 원문 링크 새 탭, 상대 시각("12분 전") |
| 소스 상태 바 | 매체별 마지막 수집 시각과 건수, 실패 시 경고 배지 |
| 듀얼 테마 | 시스템 기본 + 토글 + localStorage |
2. 렌즈 (이 캡스톤의 심장)
| 기능 | 설명 |
|---|---|
| 토픽 클러스터 | 2개 이상 매체가 다룬 공통 토픽 3~5개, 공통 사실 요약 |
| 프레임 비교 | 토픽마다 4개 매체의 프레임을 나란히, 미보도는 회색 - 침묵도 관점이다 |
| 근거 링크 | 모든 프레임 칩에 원문 기사 링크, 출처 없는 주장 없음 |
| 렌즈 캐시 | 같은 10분 버킷 동안 재사용 |
이 캡스톤을 마치면 다음 네 가지를 설명할 수 있고, 다시 만들 수 있습니다.
| 목표 | 검증되는 순간 |
|---|---|
| 이질적 소스를 하나의 스키마로 정규화하는 법 | M2에서 4개 피드가 같은 모양의 JSON으로 나란히 설 때 |
| LLM 출력에 JSON 계약을 거는 법 | M4에서 클러스터 응답이 파싱 한 번에 화면 데이터가 될 때 |
| 요약을 넘어 관점 비교를 시키는 프롬프트 설계 | 같은 토픽의 매체별 프레임이 실제로 다르게 읽힐 때 |
| 컨테이너 앱을 CF → ALB → Fargate로 개장하는 법 | 내 CloudFront URL이 다른 사람 브라우저에서 열릴 때 |
| Ch1 설치부터 Headless까지 | M0~전체: 세션 운용, 지시 → 실행 → 검증 루프 |
| Ch2 Subagents | M2~M3: 수집기 리뷰를 code-reviewer에게, 그리드와 상태 바 병행 |
| Ch3 Admin Setup | M4: Bearer 자격과 Secrets 주입이 도는 통제선의 배경 |
| Ch4 Settings, 훅과 스킬 | OPT: 하네스 성숙화, 훅과 스킬의 프로젝트 자산화 |
| Ch5 CLI Reference | 확장 방향: 아침 렌즈를 헤드리스로 뽑아 Slack에 배달하는 파이프라인 |
| Ch6 Agent SDK | 확장 방향: 렌즈 생성을 코드에서 부르는 상주 미디어 데스크 |
구현 청사진
참고M1 설계가 이 구조로 수렴하도록 방향을 잡아 주는 구현 지도입니다.
[수집 루프] 120초마다, 소스별 격리
Scheduler ──> Collector: BBC / Guardian / NHK / 연합 RSS ──> 정규화(source, title, link, published, summary)
│ (한 피드 실패는 그 피드만) │
+── 소스 상태 기록 Store <── link 멱등 upsert ──+
[조회 경로] 브라우저가 당길 때
Browser ── fetch ──> FastAPI: /api/articles ──> 4열 그리드 + 소스 상태 바
[렌즈 경로] 버튼 눌렀을 때만, 이 캡스톤의 심장
FastAPI ── 4소스 헤드라인 묶음 ──> httpx POST converse(Bearer) ──> JSON만:
clusters[{topic, summary, frames{bbc/guardian/nhk/yna}, sources}] + overview
│
+── 10분 버킷 캐시 ──> 클러스터 뷰(프레임 나란히, 미보도 회색, 근거 링크)
| 매체 | 언어 | 피드 | 비고 |
|---|---|---|---|
| BBC World | 영어 | feeds.bbci.co.uk의 world 편 RSS | 공식 제공, 안정 |
| The Guardian World | 영어 | theguardian.com/world/rss | 섹션 URL + /rss 관례, 공식 |
| NHK World | 영어 | www3.nhk.or.jp 영문 뉴스 RSS | 일본 관점의 영문 발신 |
| 연합뉴스 국제 | 한국어 | yna.co.kr 국제 섹션 RSS | 유일한 한국어 소스 |
참고: Reuters는 공식 RSS를 2020년에 중단해 소스에서 제외했습니다. 피드 URL은 변할 수 있는 값이라 구현 시 각 사 RSS 허브에서 확인해 config에 확인일과 함께 기록하는 것이 M2의 첫 작업입니다 - 상류 계약을 문서화하는 습관 자체가 학습입니다.
{
"clusters": [
{
"topic": "한국어 토픽명",
"summary": "매체들이 공통으로 전하는 사실, 2문장",
"frames": {
"bbc": "이 매체가 무엇을 앞세우는지 1문장",
"guardian": "...", "nhk": "...", "yna": "미보도"
},
"sources": { "bbc": [0, 3], "guardian": [1], "nhk": [2], "yna": [] }
}
],
"overview": "오늘의 미디어 지형, 3문장"
}
| 선택 | 이유 |
|---|---|
| link 멱등 + 본문 미저장 | 중복 없는 스토어와 출처 존중을 한 번에, 우리는 렌즈지 아카이브가 아니다 |
| 소스별 실패 격리 | RSS는 언제든 한 곳이 느려진다, 4분의 1의 장애가 4분의 4가 되면 안 된다 |
| JSON 전용 LLM 계약 | 자유 산문은 사람용, 화면용 출력은 스키마 - 파싱 가능성이 곧 신뢰성 |
| CF → ALB → Fargate 개장 형식 | prefix list SG와 X-Origin-Verify 이중 방어를 갖춘, 공개 URL까지 가는 최단 경로 |
사전 준비
5분이 트랙은 외부 키 발급이 없습니다. Bedrock Bearer와 AWS 자격만 확인하면 출발입니다.
mkdir -p ~/capstone/capstone-6 && cd ~/capstone/capstone-6
set -a; source ~/capstone/.env; set +a
python3 -c "import os; print('Bearer:', 'OK' if os.environ.get('AWS_BEARER_TOKEN_BEDROCK') else 'MISSING')"
aws sts get-caller-identity --query Account --output text
설계, 브레인스토밍
15분소스 4개, 정규화, JSON 렌즈 계약, 배포까지 요구 9조항으로 넘깁니다.
이 미션의 바탕 학습: Ch1의 세션 운용과 Capstone Setup의 superpowers 워크플로.
claude
/superpowers:brainstorming 다음 요구사항으로 "Newsroom Lens", 4개 매체의 관점 비교 뉴스룸을 설계하자.
1) 구조: backend/(Python 3.11+ FastAPI, app/collector 수집, app/store, app/api, app/llm, config.py)
+ frontend/index.html(빌드 없는 정적 SPA 한 장). FastAPI가 정적 파일을 함께 서빙해 :8000 완결.
Dockerfile 한 장
2) 소스 4개(전부 공개 RSS, 키 불요), config.py 상수로:
BBC World, The Guardian World, NHK World(영문), 연합뉴스 국제 - 각 항목은 {id, 이름, 언어, rss_url}.
피드 URL은 구현 시점에 각 사 공식 RSS 허브에서 확인해 채운다(하드코딩하되 주석으로 확인일 기록)
3) 수집기: feedparser로 4개 피드를 120초 주기 수집, 소스별 최신 15건을
{source, title, link, published(UTC ISO), summary(HTML 태그 제거, 300자 절단)}로 정규화.
피드 하나가 실패해도 나머지는 계속(소스별 실패 격리), 마지막 성공 시각을 소스별로 기록
4) 스토어: link를 멱등 키로 하는 인메모리 딕셔너리(소스별 최대 50건). 같은 기사는 published만 갱신
5) API 계약: GET /healthz, GET /api/articles(소스별 최신 목록 + 소스 상태),
POST /api/lens (아래 6, 같은 10분 버킷 캐시)
6) 렌즈(LLM, 이 캡스톤의 심장): Bedrock Converse를 SDK 없이 httpx 직접 REST로.
POST https://bedrock-runtime.ap-northeast-2.amazonaws.com/model/global.anthropic.claude-sonnet-4-6/converse
Authorization: Bearer(환경변수 AWS_BEARER_TOKEN_BEDROCK), maxTokens 1500.
입력은 4개 소스의 최신 헤드라인+요약 묶음. 출력은 반드시 JSON만:
{"clusters":[{"topic":"한국어 토픽명","summary":"공통 사실 2문장",
"frames":{"bbc":"이 매체의 프레임 1문장","guardian":"...","nhk":"...","yna":"..."},
"sources":{"bbc":[기사 인덱스],...}}], "overview":"오늘의 미디어 지형 3문장"}
클러스터는 2개 이상 매체가 다룬 공통 토픽만 3~5개. 다루지 않은 매체의 frame은 "미보도".
모든 생성 텍스트는 한국어, 기사 제목 원문은 화면에서 병기
7) 화면(텍스트 스펙): 라이트/다크 듀얼 테마. 상단 소스 상태 바(4개 매체, 마지막 수집, 건수).
기본 뷰는 4열 카드 그리드(매체별 최신 헤드라인, 원문 링크 새 탭, 상대 시각).
"렌즈" 버튼 → 클러스터 뷰: 토픽 카드마다 공통 요약 + 4개 매체 프레임을 나란히,
미보도는 회색 처리, 근거 기사 링크 칩. 뷰 전환 토글
8) 키와 윤리: Bearer는 환경변수로만. 기사 본문을 저장하지 않는다(헤드라인+요약+링크만),
화면 모든 카드에 원문 출처 링크 필수
9) 배포와 순서: CDK로 CloudFront → (prefix list SG + X-Origin-Verify) ALB → Fargate 를 구성,
Secrets 기동 주입. Phase 1(수집 + 스토어 + /api/articles) → Phase 2(4열 그리드)
→ Phase 3(렌즈 JSON + 클러스터 뷰) → Phase 4(cdk deploy 개장). 2시간 제약: 테스트 생략,
curl과 브라우저로 검증. 결정이 필요하면 이 범위 안에서 최소한으로만 물어봐.
auto mode on을 선언해 두면 superpowers가
brainstorming → write-plan → execute-plan의 단계 전환과 승인 대기를 자동으로 이어 갑니다.
시간이 빠듯할 때 유용합니다. 되돌리려면 auto mode off입니다.
/superpowers:write-plan으로 Phase 4개 계획을 승인하고, 위 구현 청사진과 대조하세요.
Phase 1, 수집기와 스토어
30분4개 피드가 같은 모양으로 정규화되어 쌓이고, 한 피드가 죽어도 나머지가 살면 끝입니다.
이 미션의 바탕 학습: Ch1의 지시 → 실행 → 검증 루프. 여유가 있다면 Ch2의 code-reviewer에게 정규화 로직 리뷰를 맡겨 보세요.
cdk deploy는 첫 회 12~15분이 걸립니다. Phase 1을 시작하자마자
별도 터미널에서 인프라 배포를 먼저 걸어 두세요. 빌드와 배포 대기가 겹치면
M4는 이미지 푸시와 서비스 갱신만 남아 10분 안에 개장합니다.
cd ~/capstone/capstone-6 && npx aws-cdk@2 deploy --require-approval never # Claude가 infra를 만든 직후 실행
/superpowers:execute-plan Phase 1만 구현하고 멈춰줘. 시작 전에 4개 피드 URL을 각 사 공식 RSS 허브에서 확인해 config.py에 확인일 주석과 함께 기록. backend venv + requirements(fastapi, uvicorn, httpx, feedparser, apscheduler), 소스별 격리 수집기(120초), link 멱등 스토어(소스별 50건), /api/articles(목록 + 소스 상태)와 /healthz, Dockerfile과 infra 골격까지. uvicorn과 curl 검증 방법 포함.
cd backend && .venv/bin/uvicorn app.main:app --port 8000 &
sleep 8
curl -s localhost:8000/api/articles | head -c 500; echo
Phase 2, 뉴스룸 그리드
30분4열 그리드에 세계의 지금이 나란히 뜨면, 비교의 무대가 완성됩니다.
이 미션의 바탕 학습: Ch2의 병렬 감각. 그리드를 만드는 동안 소스 상태 바를 서브에이전트로 병행할 수 있습니다.
/superpowers:execute-plan Phase 2를 구현해줘. frontend/index.html 정적 SPA 한 장: 요구 7의 기본 뷰(듀얼 테마, 소스 상태 바, 4열 카드 그리드 - 매체명 헤더, 헤드라인, 상대 시각, 원문 새 탭 링크). 모바일에서는 2열로 접히게. FastAPI 정적 서빙 mount까지.
# 브라우저에서 /proxy/8000/ 열기, 4개 매체의 지금이 나란히 선다
Phase 3 + 4, 렌즈와 개장
40분LLM의 JSON이 그대로 화면이 되고, 내 CloudFront URL이 열리면 미션 완료입니다.
이 미션의 바탕 학습: Ch3에서 본 Bedrock 자격과 Secrets 주입의 배경, 그 위에서 도는 REST 계약.
/superpowers:execute-plan Phase 3(렌즈)을 구현해줘. llm 모듈: httpx POST converse(Bearer, maxTokens 1500, 타임아웃 504/파싱 502), 시스템 프롬프트에 요구 6의 JSON 스키마와 "JSON 외 출력 금지, 코드펜스 금지"를 명시, 응답은 json.loads 전에 백틱/여백 방어적 제거. POST /api/lens(10분 버킷 캐시). 화면 렌즈 뷰: 토픽 카드에 공통 요약 + 4개 프레임 나란히, 미보도 회색, sources 인덱스로 근거 기사 링크 칩, 뷰 전환 토글.
curl -s -X POST localhost:8000/api/lens | head -c 400; echo
/superpowers:execute-plan Phase 4(개장)를 진행해줘. 선배포한 인프라에 앱 이미지를 빌드/푸시하고 서비스 갱신, CloudFront 도메인 출력. X-Origin-Verify와 Secrets 주입 확인 절차 포함.
렌즈 퀄리티 강화 라운드, 시선을 벼려라
+α 자유렌즈가 열렸다면 이제 렌즈를 내 것으로 만드는 시간입니다. 강화 카드 중 끌리는 것을 골라 하나씩 주문하세요. 요령은 같습니다: 한 번에 하나, 화면으로 확인하고, 마음에 들면 커밋과 재배포.
Al Jazeera English를 다섯 번째 소스로 추가하자. config에 피드를 등록하면
수집기, 스토어, 그리드(5열), 렌즈 프롬프트와 frames 스키마까지 자동으로 확장되는지가
이 카드의 진짜 시험이다. 하드코딩이 남아 있으면 이 기회에 소스 목록 주도로 리팩터.
추가 소스 후보 메뉴판 (한국 / 미국, 2026.08 기준 - NPR와 NYT는 웹 확인, 나머지는 등록 시 각 사 허브에서 피드 URL을 확인해 config에 확인일을 남기세요)
| 국가 | 매체 | 피드 허브 | 비고 |
|---|---|---|---|
| 한국 | KBS 뉴스 | news.kbs.co.kr RSS | 공영 기준선, 안정 |
| 한국 | 한겨레 | hani.co.kr RSS | 공식 제공 오래 유지 |
| 한국 | 경향신문 | khan.co.kr RSS | 섹션별 제공 |
| 한국 | 조선일보 | chosun.com RSS | 섹션별 제공 |
| 한국 | SBS 뉴스 | news.sbs.co.kr RSS | 방송사 중 충실 |
| 한국 | 매일경제 / 한국경제 | mk.co.kr, hankyung.com RSS | 경제 섹션 렌즈용 |
| 미국 | NPR | feeds.npr.org | 미국 매체 중 RSS 지원 최상급 |
| 미국 | NYT | rss.nytimes.com | 헤드라인 + 요약 무료, 렌즈는 본문 미저장이라 충분 |
| 미국 | Fox News | feeds.foxnews.com | 공식 제공 |
| 미국 | Washington Post | feeds.washingtonpost.com | 제공, 개편 잦은 편 |
참고: AP는 공식 RSS 미제공, CNN 피드는 레거시라 후순위입니다. 렌즈는 프레이밍 비교가 심장이므로 관점의 거리가 있는 짝(예: NPR + Fox, 국내라면 KBS + 한겨레 + 조선)일수록 화면이 살아납니다.
관심 키워드 추적을 추가하자. 헤더의 입력창에 키워드(예: AI, 반도체)를 핀하면
그리드에서 매칭 헤드라인이 하이라이트되고, "이 키워드만" 필터 토글이 생긴다.
핀 목록은 localStorage에, 매칭은 대소문자 무시.
렌즈 응답에 어조 온도를 더하자. 각 프레임에 tone 필드(-2 차분 ~ +2 격앙)를 JSON 계약에 추가하고,
화면은 프레임 옆에 작은 온도 바로 표시. 같은 사건에 대한 온도 차가 한눈에 보이면
프레이밍이라는 개념이 몸에 들어온다. 프롬프트에 "근거 문구 없이 극단값 금지"를 명시.
렌즈를 텍스트로 내보내자. "복사용 브리핑" 버튼 → overview와 클러스터를
Slack에 붙여넣기 좋은 플레인 텍스트(토픽별 3줄 + 링크)로 만들어 클립보드에 복사.
매일 아침 팀 채널에 배달하는 내 미디어 브리핑의 원형이다.
여기부터는 정해진 카드가 없습니다. 당신이 편집장입니다. 뉴스룸을 보며 궁금했던 것 하나를 골라, 위 카드들처럼 직접 요구사항을 써서 주문하세요. 아이디어가 필요하면: 테크 섹션 전용 렌즈, 시간대별 헤드라인 변화, 매체별 다룬 지역 지도, 토픽 히스토리(오전 vs 오후), 읽음 표시, DynamoDB로 스토어 승격(재배포와 다중 태스크에도 기사 이력이 유지되고, 토픽 히스토리 카드의 토대가 됩니다).
내 렌즈에 [내가 원하는 기능]을 추가하자. 규칙:
1) 데이터: [필요한 필드, 새 소스라면 공식 RSS 확인]
2) 화면: [어디에 어떻게 보이는지]
3) 계약: 본문 미저장과 원문 링크 필수 원칙, JSON 스키마 호환은 깨지 않는다
4) 배포: 완성되면 재배포까지
구현 전에 이 규칙을 네 계획으로 다시 말해주고, 승인하면 진행해.
하네스 엔지니어링
+15분완주한 프로젝트를 표준 하네스로 성숙시킵니다 (project-init으로 구조를 잡고 harness-eval로 6개 차원 등급을 받습니다).
이 미션의 바탕 학습: Ch4의 훅과 스킬을 팀 자산으로 승격하는 감각, 그리고 Reference 3의 플러그인 생태계.
/project-init:init-project .
/harness-eval:quick
등급표에서 낮은 차원 하나를 골라 /add-adr 또는 /add-runbook으로 보강하고 재평가해 보세요.
미션 종료
소스는 정규화로 나란히, 출력은 JSON 계약으로, 침묵은 미보도로. 요약을 넘어 관점을 읽었습니다.
| 가져가는 것 | 내용 |
|---|---|
| 정규화의 힘 | 이질적 소스 통합의 8할은 한 가지 모양으로 다듬는 일이다 |
| LLM JSON 계약 | 화면용 출력은 스키마로 계약한다, 파싱 가능성이 곧 신뢰성 |
| 프레이밍 프롬프트 | 비교 지시, 침묵의 처리, 근거 링크 - LLM 고유 화면의 설계 문법 |