배경
매일 아침 Confluence에 일일 스크럼 페이지를 수동으로 만들고 있었다. 제목 복사, 팀원 목록 복사, 어제 “금일 예정 업무”를 오늘 “전일 업무”로 옮기기… 단순 반복인데 매일 5~10분씩 잡아먹는 작업이었다. 자동화하기로 했다.
무엇을 했나
TypeScript 기반 CLI 도구를 만들어 다음을 자동화했다:
- 스크럼 페이지 자동 생성 —
일일 스크럼 - yyyy-MM-dd제목으로 Confluence에 페이지 생성 - 전일 업무 자동 이관 — 이전 페이지의 “금일 예정 업무” HTML 블록을 통째로 파싱해서 새 페이지의 “전일 업무”로 세팅
- 첨부파일 복사 — 이전 페이지에 첨부된 이미지를 새 페이지로 자동 복사
- 공휴일/주말 스킵 —
date-holidays라이브러리로 한국 공휴일 체크 - 주간 아카이브 — 월요일 실행 시 지난주 페이지들을
2026년 7월 3주차 (07/14 ~ 07/18)같은 폴더로 이동
핵심 결정과 시행착오
1. HTML 파싱 — 텍스트만 뽑으면 안 된다
처음에는 이전 페이지에서 텍스트만 추출해서 새 페이지에 넣었다. 그런데 원본에는 중첩 리스트, Confluence 내부 링크(ac:link), 외부 링크, 이미지 매크로 등이 있었다. 텍스트만 뽑으면 구조가 다 깨진다.
결국 ”🎯 금일 예정 업무”와 ”❗ Blockers” 사이의 HTML 블록을 통째로 추출하는 방식으로 바꿨다.
// scrum/parser.ts (핵심 로직)
const todayMatch = section.match(
/🎯\s*금일 예정 업무<\/strong><\/p>([\s\S]*?)(?=<p[^>]*><strong>❗|$)/
);
const rawBlock = todayMatch[1].trim();
result.set(memberName, rawBlock);
이렇게 하니 중첩 리스트, 링크, 매크로 등 원본 구조가 그대로 보존됐다.
2. 첨부파일 — 이미지가 안 보이는 문제
페이지를 생성하고 보니 이전 페이지에 있던 이미지가 안 보였다. Confluence storage format에서 이미지는 ri:attachment로 참조되는데, 이건 해당 페이지의 첨부파일을 가리킨다. 새 페이지에는 첨부파일이 없으니 당연히 깨진다.
해결은 단순했다. 이전 페이지의 첨부파일을 다운로드해서 새 페이지에 업로드하는 과정을 추가했다.
// confluence/client.ts (요약)
export async function copyAttachments(sourcePageId: string, targetPageId: string) {
// 1. 원본 페이지 첨부파일 목록 조회
// 2. 각 첨부파일 다운로드
// 3. 새 페이지에 업로드
}
3. CQL 검색의 함정 — 인덱싱 딜레이와 제목 검색
Confluence CQL로 페이지를 검색할 때 두 가지 문제를 만났다.
첫 번째는 인덱싱 딜레이. 연속으로 여러 페이지를 생성하면 방금 만든 페이지가 CQL 검색에 바로 안 잡혔다. 실 운영에서는 하루에 하나만 만들기 때문에 문제가 안 되지만, 테스트할 때 헤맸다.
두 번째는 아카이브 검색. 처음에는 CQL title="일일 스크럼 - 2026-07-23" 같은 정확한 제목 검색을 썼는데, 특정 페이지가 검색에 안 잡히는 현상이 있었다. children API로 부모 폴더의 하위 페이지를 직접 조회한 뒤 제목으로 필터링하는 방식으로 바꿔서 해결했다.
4. 다음 업무일 계산
VPS에서 cron으로 평일 오후 5시에 실행하되, 다음 업무일 페이지를 생성해야 했다. 금요일이면 월요일, 공휴일 전날이면 공휴일 이후 첫 업무일을 계산해야 한다.
// utils/holiday.ts (요약)
export function getNextWorkday(from: Date): Date {
const next = new Date(from);
do {
next.setDate(next.getDate() + 1);
} while (!isWorkday(next));
return next;
}
--next-workday 플래그를 추가해서 cron에서는 이걸로 실행하도록 했다.
프로젝트 구조
설정 파일(scrum-config.json)로 팀 구성을 분리해서, 코드 수정 없이 다른 팀에서도 쓸 수 있게 만들었다.
src/
├── index.ts # 엔트리포인트
├── config.ts # 환경변수 로드
├── confluence/
│ ├── client.ts # Confluence REST API 클라이언트
│ └── archive.ts # 주간 아카이브
├── scrum/
│ ├── parser.ts # 이전 페이지 HTML 파서
│ └── template.ts # 스크럼 페이지 HTML 빌더
└── utils/
└── holiday.ts # 한국 공휴일 체크
회고
반복 작업은 두 번째 반복이 느껴질 때 자동화하는 게 맞다.
처음에는 “페이지 하나 만드는 건데 뭘” 했지만, 매일 하다 보니 생각보다 성가셨다. 특히 이전 페이지에서 금일 예정 업무를 복사해서 전일 업무로 옮기는 과정이 실수하기 쉬웠다. Confluence storage format의 HTML 구조가 생각보다 복잡해서 파싱에 시간이 좀 걸렸지만, 한번 만들어두니 아침마다 할 일이 하나 줄었다.