노션에서 작성한 문서를 GitHub에 자동으로 백업하고 싶은데 어떻게 해야 할지 막막하신가요. 페이지를 수정할 때마다 수동으로 내보내기하는 것도 번거롭고, 버전 관리도 제대로 되지 않아 고민이에요. 이런 문제를 해결하기 위해 노션 웹훅과 GitHub Actions를 연동하는 자동화 시스템을 만들어볼게요.
노션 웹훅 설정하기 - 변경 감지의 첫걸음
노션의 자동화(Automation) 기능을 사용하면 데이터베이스에서 변경이 일어날 때 웹훅을 트리거할 수 있어요. 다만 현재 노션 웹훅은 데이터베이스 단위로만 작동하고, 개별 페이지 본문 전체를 직접 전달하지는 않아요.
// 웹훅 리스너 서버 예제 (Node.js + Express)
const express = require('express');
const app = express();
app.use(express.json());
app.post('/webhook/notion', async (req, res) => {
// 노션에서 보낸 페이로드 확인
console.log('Notion webhook received:', req.body);
const pageId = req.body.pageId;
// 페이지 ID로 노션 API 호출해서 전체 내용 가져오기
await fetchNotionPageContent(pageId);
res.status(200).send('Webhook processed');
});
app.listen(3000, () => {
console.log('Webhook listener running on port 3000');
});
노션 웹훅의 한계를 보완하려면 웹훅 수신 후 별도로 Notion API를 호출해 페이지 내용을 가져와야 해요. 이때 주의할 점은 웹훅이 HTTP POST 요청만 지원하고, 한 자동화당 최대 5개의 웹훅 액션만 등록할 수 있다는 거예요.
notion-to-md 라이브러리로 마크다운 변환하기
노션 콘텐츠를 마크다운으로 변환하는 가장 효율적인 방법은 notion-to-md 패키지를 사용하는 거예요. 중첩된 블록 구조도 깔끔하게 처리해주고, GitHub Actions와의 연동도 쉬워요.
// notion-to-md 사용 예제
const { Client } = require('@notionhq/client');
const { NotionToMarkdown } = require('notion-to-md');
const notion = new Client({
auth: process.env.NOTION_TOKEN,
});
const n2m = new NotionToMarkdown({ notionClient: notion });
async function convertPageToMarkdown(pageId) {
// 노션 페이지를 마크다운 블록으로 변환
const mdblocks = await n2m.pageToMarkdown(pageId);
// 마크다운 문자열로 변환
const mdString = n2m.toMarkdownString(mdblocks);
console.log('Converted markdown:', mdString);
return mdString;
}
// 실제 사용 시
convertPageToMarkdown('your-page-id-here');
Python을 선호한다면 notion2markdown 라이브러리도 좋은 선택이에요. YAML 형식으로 프로퍼티를 포함할 수 있어서 문서 메타데이터 관리에 유용해요.
GitHub Actions 워크플로우 구성하기
이제 변환된 마크다운 파일을 GitHub에 자동으로 커밋하는 워크플로우를 만들어볼게요. GitHub Actions를 사용하면 서버 없이도 자동화를 구현할 수 있어요.
# .github/workflows/notion-backup.yml
name: Notion to GitHub Backup
on:
schedule:
# 매일 자정에 실행 (필요에 따라 조정)
- cron: '0 0 * * *'
workflow_dispatch: # 수동 실행 가능
jobs:
backup:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '16'
- name: Install dependencies
run: |
npm install @notionhq/client
npm install notion-to-md
- name: Convert Notion to Markdown
env:
NOTION_TOKEN: ${{ secrets.NOTION_TOKEN }}
NOTION_DATABASE_ID: ${{ secrets.NOTION_DATABASE_ID }}
run: |
node scripts/notion-to-markdown.js
- name: Commit and Push
uses: EndBug/add-and-commit@v9
with:
message: 'Auto backup from Notion'
add: 'content/*.md'
secrets에 NOTION_TOKEN과 DATABASE_ID를 저장해두면 안전하게 API 키를 관리할 수 있어요. 스케줄러를 사용하면 정기적으로 백업이 실행되고, workflow_dispatch를 추가하면 필요할 때 수동으로도 실행할 수 있어요.
실시간 감지를 위한 하이브리드 방식 구현
노션 웹훅만으로는 모든 변경사항을 실시간으로 감지하기 어려워요. 페이지 본문 전체가 웹훅 페이로드에 포함되지 않기 때문이에요. 이를 해결하기 위해 웹훅과 폴링을 병행하는 하이브리드 방식을 추천해요.
// 하이브리드 감지 시스템
const cron = require('node-cron');
// 웹훅으로 즉시 감지
app.post('/webhook/notion', async (req, res) => {
// 변경 이벤트 즉시 처리
await processNotionChange(req.body.pageId);
res.status(200).send('OK');
});
// 5분마다 폴링으로 놓친 변경사항 확인
cron.schedule('*/5 * * * *', async () => {
console.log('Checking for missed changes...');
// 최근 수정된 페이지 목록 가져오기
const recentPages = await getRecentlyModifiedPages();
for (const page of recentPages) {
// 변경사항 확인 및 처리
await checkAndProcessChanges(page.id);
}
});
async function processNotionChange(pageId) {
// 1. 노션 API로 페이지 내용 가져오기
const pageContent = await notion.pages.retrieve({ page_id: pageId });
// 2. 마크다운으로 변환
const markdown = await convertToMarkdown(pageContent);
// 3. GitHub에 커밋
await commitToGitHub(markdown, pageId);
}
macOS에서 로컬 개발 환경 설정하기
맥에서 이 시스템을 테스트하려면 ngrok을 사용해 로컬 서버를 외부에서 접근 가능하게 만들어야 해요.
# ngrok 설치 (Homebrew 사용)
brew install ngrok
# Node.js 프로젝트 초기화
mkdir notion-github-sync
cd notion-github-sync
npm init -y
# 필요한 패키지 설치
npm install express @notionhq/client notion-to-md
npm install -D nodemon # 개발용
# 서버 실행
node server.js
# 다른 터미널에서 ngrok 실행
ngrok http 3000
ngrok이 생성한 URL을 노션 자동화 설정의 웹훅 URL로 입력하면 로컬에서도 웹훅을 받을 수 있어요. 개발 중에는 nodemon을 사용하면 코드 변경 시 자동으로 서버가 재시작되어 편리해요.
보안과 에러 처리 고려사항
웹훅 수신 서버는 별도의 인증 없이 POST 요청을 받기 때문에 보안 검증을 직접 구현해야 해요. 시크릿 토큰을 사용한 검증 로직을 추가하는 것이 좋아요.
// 웹훅 보안 검증 예제
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const hash = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
return hash === signature;
}
app.post('/webhook/notion', (req, res) => {
// 시그니처 검증
const signature = req.headers['x-webhook-signature'];
const isValid = verifyWebhookSignature(
req.body,
signature,
process.env.WEBHOOK_SECRET
);
if (!isValid) {
return res.status(401).send('Unauthorized');
}
// 검증 통과 후 처리
processWebhook(req.body);
});
웹훅 액션이 실패하면 노션 자동화가 일시 중지되므로, try-catch 블록으로 에러를 처리하고 적절한 로깅을 추가해야 해요. 실패한 작업을 재시도하는 큐 시스템을 구현하면 더욱 안정적인 백업 시스템을 만들 수 있어요.
노션과 GitHub을 연동하는 자동 백업 시스템은 초기 설정이 조금 복잡하지만, 한 번 구축해두면 모든 작업 히스토리가 자동으로 보존되어 매우 유용해요. 특히 팀 프로젝트나 기술 문서 관리에서 버전 관리의 장점을 최대한 활용할 수 있어요.