Reflective — Notion MCP와 Claude로 만든 AI 저널링 동반자
I’m happy to translate the article for you, but I’ll need the text you’d like translated. Could you please paste the content (or the portion you want translated) here? I’ll keep the source line and all formatting exactly as you specify.
What I Built
Reflective는 Chrome 확장 프로그램 + Node.js 백엔드로, Notion에서 글을 쓸 때 브라우저 사이드바에 AI 일기 동반자를 추가합니다.
대부분의 일기 도구는 쓰기 전용입니다. 생각을 쏟아 넣으면 그곳에 머무르죠. Reflective는 Notion 일기를 양방향 대화로 바꿔줍니다 — 페이지를 떠나지 않아도 됩니다.
How it works
You write in Notion
↓
Click "Analyze this entry" in the sidebar
↓
Claude reads your entry + your journal history from Notion
↓
Opens a conversation grounded in what you actually wrote
↓
Click "Mark session complete"
↓
Mood score, tags, themes, and AI summary written back to Notion
Key behaviors
- Notion 옆에 Chrome 사이드 패널에 자리 잡아 새 탭이 열리지 않음.
- 컨텍스트 인식: 데이터베이스 뷰에서는 최근 50 개의 항목을 로드하고, 단일 항목에서는 해당 페이지만 읽음.
- 시간 인식: 오래된 항목을 읽고 있다면 Claude가 이를 알고 과거를 되돌아보는 식으로 응답을 구성함.
- 전체 세션 동안 하나의 대화 흐름을 유지 — 새 항목으로 이동하면
— now reading: [title] —구분자를 붙여 채팅에 추가됨. - 분석은 항상 사용자가 직접 시작하며, 확장 프로그램은 탐색 시 API 호출을 전혀 하지 않음.
- 감정 스파크라인은 Notion 데이터베이스에서 실시간으로 가져온 최근 14 일간의 데이터를 표시함.
One‑click workspace setup
첫 실행 시 확장 프로그램이 다음을 생성합니다:
- Journal Entries 데이터베이스,
- Mood Log 데이터베이스,
- Weekly Summaries 데이터베이스,
- 초기 샘플 항목, 그리고
- 대시보드 페이지.
통합 토큰을 붙여넣으면 설정이 약 10 초 안에 완료됩니다.
코드를 보여 주세요
레포:
스택
- Chrome 확장 프로그램 (Manifest V3, React + TypeScript, Vite, Tailwind)
- Node.js + Express 백엔드 (TypeScript)
- Anthropic Claude (
claude-sonnet-4-5) - Notion API (
@notionhq/clientv2) - 확장 프로그램에 진행 상황을 스트리밍하기 위한 Server‑Sent Events
- pnpm workspaces
Notion MCP를 사용한 방법
Notion은 사용자가 데이터를 읽고 쓰는 장소이며, 전체 데이터 모델이기도 합니다. 모든 상태는 @notionhq/client를 통해 접근되는 그곳에 존재합니다.
읽기: Claude를 위한 컨텍스트 구축
“Analyze this entry”(이 항목 분석) 버튼을 클릭하면 백엔드가 병렬로 다음을 가져옵니다:
const [rawHistory, recentMoods] = await Promise.all([
fetchJournalEntries(journalDbId, 50, notionToken), // 최근 50개 항목
queryMoodHistory(moodLogDbId, 14, notionToken), // 14일 스파크라인
]);
그 다음 현재 페이지 블록을 직접 읽습니다:
const [pageObj, blocks] = await Promise.all([
notion.pages.retrieve({ page_id: pageId }),
notion.blocks.children.list({ block_id: pageId, page_size: 100 }),
]);
블록 내용은 저널 히스토리와 함께 Claude에 전달되는 원시 텍스트가 됩니다. 히스토리는 현재 보고 있는 항목을 기준으로 “해당 날짜 이전”과 “해당 날짜 이후”로 나뉘어 Claude에게 정확한 시간적 프레임을 제공합니다.
쓰기: 분석 결과를 Notion에 다시 저장
세션을 완료로 표시하면 다음과 같이 업데이트됩니다:
await notion.pages.update({
page_id: pageId,
properties: {
'Mood Score': { number: result.moodScore },
'Mood Tags': { multi_select: result.moodTags.map(name => ({ name })) },
'Themes': { multi_select: result.themes.map(name => ({ name })) },
'AI Summary': { rich_text: [{ text: { content: result.aiSummary } }] },
'Word Count': { number: wordCount },
'Session Complete': { checkbox: true },
},
});
시간이 지남에 따라 Notion 데이터베이스가 점점 풍부해집니다. 이후 분석에서는 AI Summary가 이미 있는 항목은 바로 사용되어 빠르게 처리되고, 요약이 없는 항목은 블록을 다시 가져와야 하므로 로딩 진행 표시줄에 느리게 표시됩니다. 첫 번째 로드에서는 저널을 초기화하고, 이후 로드는 즉시 완료됩니다.
로딩 경험
첫 번째에 50개의 항목을 초기화하는 데는 시간이 걸립니다. /api/init 엔드포인트는 Server‑Sent Events를 통해 진행 상황을 스트리밍합니다:
data: {"type":"journal_count","total":47}
data: {"type":"hydrating","index":1,"total":47,"title":"March reflections"}
data: {"type":"hydrating","index":2,"total":47,"title":"A hard week"}
...
data: {"type":"done","entryContent":"...","openingMessage":"..."}
확장 프로그램은 fetch + ReadableStream(확장 컨텍스트에서 EventSource보다 더 안정적)으로 이를 소비하고 UI를 업데이트합니다. 예: Reading your journal — 3/47 — A hard week.
Notion이 일반 데이터베이스에서는 얻을 수 없는 것
Mood Tags와Themes에 대한 다중 선택 속성을 사용하면 Notion 내에서 기분이나 테마별로 전체 저널을 필터링, 정렬 및 그룹화할 수 있습니다 — 별도의 맞춤형 쿼리 인터페이스가 필요 없습니다.- AI가 이러한 속성을 채워 넣으며, Notion의 내장 뷰가 나머지를 처리합니다.
- 기분 스파크라인은 별도의 Mood Log 데이터베이스에서 가져오며, 이 데이터베이스는 저널 항목과 독립적으로 일일 기분을 추적합니다. 글을 쓰지 않는 날에도 기분을 기록할 수 있으며, 차트에 반영됩니다.
이 구조—다중 연결 데이터베이스와 풍부한 속성 유형—는 Notion에서 자연스럽게 지원되며, 다른 곳에서는 명시적인 스키마 설계가 필요합니다. AI가 속성을 채우고, Notion의 기본 뷰가 추가 대시보드나 맞춤형 쿼리 레이어 없이도 시간이 지남에 따라 저널을 더 똑똑하게 만듭니다.