세팅 순서 (3단계)
1. Notion Integration 생성
1.
2.
API Key 복사
3.
Notion 업무일지 최상위 페이지 → ··· → Connections → Integration 연결
2. GitHub Secrets 등록
Settings → Secrets and variables → Actions → New repository secret
Secret 이름 | 설명 |
NOTION_API_KEY | 위에서 복사한 API Key |
NOTION_PARENT_PAGE_ID | 업무일지 최상위 페이지 URL 끝 32자리 |
NOTION_TEMPLATE_PAGE_ID | 복사 기준 날짜 페이지 ID (선택, 비우면 자동탐색) |
3. 파일 업로드 후 Push
bash 로 실행
git add notion_weekly_diary.py .github/workflows/notion_weekly_diary.yml
git commit -m "feat: Notion 주간 업무일지 자동 생성"
git push
Notion Integreation 생성
•
생성 후 화면
•
페이지 사용 권한 관리 세팅
Notion 주간 업무일지 자동 생성 자동화
개요
매주 금요일 오후 6시(KST) GitHub Actions가 자동으로 다음 주 업무일지를 Notion 데이터베이스에 생성한다.
구조
📄 2026년 4월 1주차 ← 데이터베이스 행 (주차 페이지)
📄 2026-03-30 ← 서브페이지 (월)
📄 2026-03-31 ← 서브페이지 (화)
📄 2026-04-01 ← 서브페이지 (수)
📄 2026-04-02 ← 서브페이지 (목) ← 주간보고 포함
📄 2026-04-03 ← 서브페이지 (금)
Plain Text
복사
날짜 서브페이지 양식
월/화/수/금
## 전날 To-do
☐ 1
☐ 2
☐ 3
## To-do (우선순위 반영)
☐ 1
☐ 2
☐ 3
Plain Text
복사
목요일 (주간보고 추가)
## 전날 To-do
☐ 1
☐ 2
☐ 3
## To-do (우선순위 반영)
☐ 1
☐ 2
☐ 3
## 주간보고
> (내용 입력)
Plain Text
복사
주차 페이지 속성
속성 | 값 |
아이콘 | |
날짜 | 해당 주 월요일 자동 입력 |
상태 | 시작 전 |
Place | 비워두기 |
파일 구조
레포지토리/
├── notion_weekly_diary.py
└── .github/
└── workflows/
└── notion_weekly_diary.yml
Plain Text
복사
세팅 방법
1단계 — Notion Integration 생성
1.
https://www.notion.so/my-integrations 접속
2.
+ New integration 클릭 후 생성
3.
API Key 복사
4.
Notion 업무일지 데이터베이스 열기 → ··· → Connections → Integration 연결
2단계 — 데이터베이스 ID 확인
업무일지 데이터베이스를 전체 페이지로 열기 (
버튼) → URL에서 추출
https://www.notion.so/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx?v=...
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
이 32자리가 DATABASE_ID
Plain Text
복사
3단계 — GitHub Repository Secrets 등록
Settings → Secrets and variables → Actions → New repository secret
Secret 이름 | 설명 |
NOTION_API_KEY | Notion Integration API Key |
NOTION_DATABASE_ID | 업무일지 데이터베이스 ID |
NOTION_TEMPLATE_PAGE_ID 는 등록 불필요 (양식이 코드에 내장됨)
4단계 — 파일 push
git add notion_weekly_diary.py .github/workflows/notion_weekly_diary.yml
git commit -m "feat: Notion 주간 업무일지 자동 생성"
git push
Bash
복사
5단계 — 수동 실행 테스트
GitHub → Actions 탭 → Notion 주간 업무일지 자동 생성 → Run workflow
스케줄
•
자동 실행: 매주 금요일 오후 6시 (KST)
•
수동 실행: Actions 탭 → Run workflow
주의사항
중복 방지
동일한 주차 페이지가 이미 존재하면 자동으로 종료된다.
수동 실행 후 스케줄링이 돌아도 중복 생성되지 않는다.
휴지통 주의
Notion에서 잘못 생성된 주차 페이지를 휴지통에 버리면,
API 조회 시 휴지통 항목도 포함되어 중복으로 인식할 수 있다.
→ 반드시 영구 삭제 처리할 것
속성명 주의
스크립트 내 속성명(날짜, 상태)이 Notion 데이터베이스의 실제 속성명과 일치해야 한다.
다를 경우 스크립트에서 해당 부분 수정 필요.
지원되지 않는 블록
Notion API는 일부 블록(linked database, embed 등)을 지원하지 않는다.
주차 계산 기준
•
해당 월의 첫 번째 월요일 = 1주차
•
월이 바뀌는 주(예: 3/30~4/3)는 월요일 날짜 기준 → 3월 5주차
트러블슈팅
증상 | 원인 | 해결 |
400 Bad Request | DATABASE_ID가 잘못됨 | URL에서 DB ID 재확인 |
페이지가 사이드바에 생성됨 | PARENT_PAGE_ID를 사용한 구버전 | NOTION_DATABASE_ID로 교체 |
생성은 됐는데 속성 오류 | 속성명 불일치 | 스크립트 내 속성명 수정 |
실행됐는데 생성 안 됨 | 휴지통에 동일 주차 페이지 존재 | 휴지통에서 영구 삭제 후 재실행 |
주차 계산 오류 (6주차 등) | 구버전 로직 | 최신 스크립트로 교체 |
구성 스크립트 및 yml 파일 정리
"""
Notion 업무일지 자동 생성 스크립트
- 다음 주 평일(월~금) 업무일지 페이지를 데이터베이스에 자동 생성
- 월/화/수/금: 전날 To-do + To-do (우선순위 반영)
- 목요일: 전날 To-do + To-do (우선순위 반영) + 주간보고
- GitHub Actions로 매주 금요일 자동 실행
"""
import os
import re
import json
import requests
from datetime import date, timedelta
# ── 환경변수 ────────────────────────────────────────────────
NOTION_API_KEY = os.environ["NOTION_API_KEY"]
DATABASE_ID = os.environ["NOTION_DATABASE_ID"]
HEADERS = {
"Authorization": f"Bearer {NOTION_API_KEY}",
"Content-Type": "application/json",
"Notion-Version": "2022-06-28",
}
# ── 문서 양식 ────────────────────────────────────────────────
def make_todo_block(text: str) -> dict:
"""체크박스(to_do) 블록 생성"""
return {
"object": "block",
"type": "to_do",
"to_do": {
"rich_text": [{"type": "text", "text": {"content": text}}],
"checked": False,
},
}
def make_heading2_block(text: str) -> dict:
"""heading_2 블록 생성"""
return {
"object": "block",
"type": "heading_2",
"heading_2": {
"rich_text": [{"type": "text", "text": {"content": text}}],
},
}
def make_paragraph_block(text: str = "") -> dict:
"""빈 줄(paragraph) 블록 생성"""
return {
"object": "block",
"type": "paragraph",
"paragraph": {
"rich_text": [{"type": "text", "text": {"content": text}}],
},
}
def make_quote_block(text: str = "") -> dict:
"""주간보고용 quote 블록 생성"""
return {
"object": "block",
"type": "quote",
"quote": {
"rich_text": [{"type": "text", "text": {"content": text}}],
},
}
def build_page_blocks(target_date: date) -> list[dict]:
"""
날짜에 따라 문서 양식 블록 리스트 반환
- 목요일(weekday==3): 주간보고 섹션 추가
- 그 외: 기본 양식
"""
blocks = [
# ── 전날 To-do ──
make_heading2_block("전날 To-do"),
make_todo_block("1"),
make_todo_block("2"),
make_todo_block("3"),
make_paragraph_block(),
# ── To-do (우선순위 반영) ──
make_heading2_block("To-do (우선순위 반영)"),
make_todo_block("1"),
make_todo_block("2"),
make_todo_block("3"),
make_paragraph_block(),
]
# 목요일에만 주간보고 섹션 추가
if target_date.weekday() == 3:
blocks += [
make_heading2_block("주간보고"),
make_quote_block(),
]
return blocks
# ── 주차 계산 ───────────────────────────────────────────────
def get_next_week_weekdays() -> list[date]:
"""다음 주 월~금 날짜 리스트 반환"""
today = date.today()
days_until_monday = (7 - today.weekday()) % 7 or 7
next_monday = today + timedelta(days=days_until_monday)
return [next_monday + timedelta(days=i) for i in range(5)]
def get_week_label(monday: date) -> str:
"""
월요일 날짜 기준으로 'YYYY년 M월 N주차' 레이블 생성
- 해당 월의 첫 번째 월요일 = 1주차
- 월이 바뀌는 주(예: 3/30~4/3)는 월요일(3/30) 기준 → '3월 5주차'
"""
year = monday.year
month = monday.month
first_of_month = date(year, month, 1)
first_weekday = first_of_month.weekday()
days_to_first_monday = (7 - first_weekday) % 7
first_monday = first_of_month + timedelta(days=days_to_first_monday)
if monday < first_monday:
prev_month = month - 1 if month > 1 else 12
prev_year = year if month > 1 else year - 1
first_of_prev = date(prev_year, prev_month, 1)
fw = first_of_prev.weekday()
d2fm = (7 - fw) % 7
fm_prev = first_of_prev + timedelta(days=d2fm)
wn = (monday - fm_prev).days // 7 + 1
return f"{prev_year}년 {prev_month}월 {wn}주차"
week_num = (monday - first_monday).days // 7 + 1
return f"{year}년 {month}월 {week_num}주차"
# ── Notion API 유틸 ─────────────────────────────────────────
def get_db_page_title(page: dict) -> str:
props = page.get("properties", {})
for key in ("title", "이름", "Name"):
if key in props:
title_list = props[key].get("title", [])
if title_list:
return title_list[0].get("plain_text", "")
return ""
def query_database(database_id: str) -> list[dict]:
url = f"https://api.notion.com/v1/databases/{database_id}/query"
res = requests.post(url, headers=HEADERS, data=json.dumps({}))
res.raise_for_status()
return res.json().get("results", [])
def create_db_page(database_id: str, title: str, monday: date) -> dict:
"""데이터베이스에 주차 페이지 생성 (날짜=월요일, 상태=시작 전)"""
payload = {
"parent": {"type": "database_id", "database_id": database_id},
"icon": {"type": "emoji", "emoji": "📄"},
"properties": {
"title": {
"title": [{"type": "text", "text": {"content": title}}]
},
"날짜": {
"date": {"start": monday.strftime("%Y-%m-%d")}
},
"상태": {
"status": {"name": "시작 전"}
},
},
}
res = requests.post(
"https://api.notion.com/v1/pages",
headers=HEADERS,
data=json.dumps(payload),
)
res.raise_for_status()
return res.json()
def create_sub_page(parent_page_id: str, title: str, blocks: list[dict]) -> dict:
"""날짜 서브페이지 생성 (📝 이모지 + 양식 블록 포함)"""
payload = {
"parent": {"type": "page_id", "page_id": parent_page_id},
"icon": {"type": "emoji", "emoji": "📄"},
"properties": {
"title": {
"title": [{"type": "text", "text": {"content": title}}]
}
},
"children": blocks,
}
res = requests.post(
"https://api.notion.com/v1/pages",
headers=HEADERS,
data=json.dumps(payload),
)
res.raise_for_status()
return res.json()
def week_page_exists(database_id: str, week_label: str) -> bool:
"""중복 방지: 동일 주차 페이지 존재 여부 확인"""
for page in query_database(database_id):
if get_db_page_title(page) == week_label:
return True
return False
# ── 메인 로직 ───────────────────────────────────────────────
DAY_NAMES = ["월", "화", "수", "목", "금"]
def main():
weekdays = get_next_week_weekdays()
monday = weekdays[0]
week_label = get_week_label(monday)
print(f"📅 생성 대상 주차: {week_label}")
print(f" 월요일: {monday.strftime('%Y-%m-%d')}")
print(f" 날짜: {[d.strftime('%Y-%m-%d') for d in weekdays]}")
# 중복 방지
if week_page_exists(DATABASE_ID, week_label):
print(f"\n⚠ '{week_label}' 페이지가 이미 존재합니다. 종료합니다.")
return
# 1. 데이터베이스에 주차 페이지 생성
print(f"\n📁 데이터베이스에 주차 페이지 생성: {week_label}")
week_page = create_db_page(DATABASE_ID, week_label, monday)
week_page_id = week_page["id"]
print(f" ✅ 생성 완료 (ID: {week_page_id})")
# 2. 날짜별 서브페이지 생성
print("\n📝 날짜별 서브페이지 생성 중...")
for d in weekdays:
title = d.strftime("%Y-%m-%d")
day_name = DAY_NAMES[d.weekday()]
is_thursday = d.weekday() == 3
blocks = build_page_blocks(d)
label = f"{title}({day_name})" + (" 📋 주간보고 포함" if is_thursday else "")
print(f" → {label} 생성 중...")
create_sub_page(week_page_id, title, blocks)
print(f" ✅ 완료")
print(f"\n🎉 {week_label} 업무일지 생성 완료! (총 {len(weekdays)}개 페이지)")
if __name__ == "__main__":
main()
Python
복사
•
workflow 파일
name: 📅 Notion 주간 업무일지 자동 생성
on:
# 매주 금요일 오후 6시 (KST) = UTC 09:00
schedule:
- cron: "0 9 * * 5"
# 수동 실행도 가능하도록
workflow_dispatch:
jobs:
create-weekly-diary:
runs-on: ubuntu-latest
steps:
- name: 📥 코드 체크아웃
uses: actions/checkout@v4
- name: 🐍 Python 세팅
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: 📦 의존성 설치
run: pip install requests
- name: 🚀 업무일지 생성 실행
env:
NOTION_API_KEY: ${{ secrets.NOTION_API_KEY }}
NOTION_DATABASE_ID: ${{ secrets.NOTION_DATABASE_ID }}
# NOTION_TEMPLATE_PAGE_ID: ${{ secrets.NOTION_TEMPLATE_PAGE_ID }} # 선택사항
run: python notion_weekly_diary.py
YAML
복사





