스프린트 회고 액션 아이템 자동 트래킹 봇 만들기: 누락 없는 리마인드 운영 가이드
스프린트 회고에서 나온 액션 아이템이 사라지는 문제를 해결하는 방법을 정리합니다. TypeScript·Node.js·PostgreSQL·Slack Web API로 담당자 지정, 상태 추적, 기한 알림, 에스컬레이션을 자동화하고 팀 운영에 맞는 리마인드 정책을 설계합니다.

핵심 요약
스프린트 회고 액션 아이템이 누락되는 가장 큰 이유는 회고 기록과 실행 업무가 분리되고 담당자·기한·상태가 구조화되지 않기 때문입니다. 액션 아이템을 고유 ID와 담당자, 기한, 상태로 저장한 뒤 스케줄러가 다음 알림 시각을 계산하도록 만들면 진행 상황을 자동으로 추적할 수 있습니다.
TypeScript 5.x와 Node.js 20 LTS로 봇을 구현하고 PostgreSQL에 액션 아이템을 저장한 다음 Slack Web API의 chat.postMessage를 이용해 담당자에게 리마인드를 보낼 수 있습니다. 핵심은 알림을 많이 보내는 것이 아니라 명확한 완료 조건과 예외 처리 정책을 운영하는 데 있습니다.
스프린트 회고 액션 아이템은 왜 자주 사라지는가?
회고에서 나온 개선 의견은 대개 다음 스프린트의 실행 업무로 연결되어야 합니다. 하지만 회고 보드나 문서에 제목만 남기면 실제 업무 시스템에서 추적하기 어렵습니다.
| 누락 원인 | 운영상 문제 | 자동화로 보완할 데이터 |
|---|---|---|
| 담당자가 정해지지 않음 | 아무도 실행하지 않음 | ownerUserId |
| 완료 기준이 모호함 | 진행 중인지 판단하기 어려움 | definitionOfDone |
| 기한이 없음 | 우선순위가 계속 밀림 | dueAt |
| 상태가 문서에만 있음 | 회고 때마다 수동 확인 | status |
| 알림 기록이 없음 | 같은 알림이 반복되거나 누락됨 | lastNotifiedAt, reminderCount |
| 막힘 상태가 표현되지 않음 | 담당자에게 불필요한 압박이 발생함 | blockedReason |
액션 아이템을 단순한 메모가 아니라 추적 가능한 업무 객체로 취급해야 합니다. 특히 담당자와 기한만 지정하는 것보다 무엇이 완료된 상태인지 함께 정의하는 것이 중요합니다.
자동 트래킹 및 리마인드 봇은 어떤 원리로 동작하는가?
봇은 다음 네 가지 역할을 수행합니다.
- 회고에서 액션 아이템을 수집합니다.
- 입력값을 검증하고 고유 ID를 발급합니다.
- 데이터베이스의 상태와 기한을 주기적으로 확인합니다.
- 알림 정책에 따라 담당자와 관련 채널에 메시지를 보냅니다.
flowchart TD
A["회고 입력<br/>제목·담당자·기한"] --> B["입력 검증 및 ID 발급"]
B --> C["PostgreSQL 저장"]
C --> D["스케줄러가 미완료 항목 조회"]
D --> E{"알림 조건 충족?"}
E -->|아니오| F["다음 실행 시각 계산"]
E -->|예| G["Slack DM 또는 채널 알림"]
G --> H["알림 이력 및 다음 알림 시각 저장"]
H --> F
C --> I["담당자 상태 업데이트"]
I --> J{"완료 또는 보류?"}
J -->|완료| K["알림 종료"]
J -->|보류| L["차단 사유 기록 및 재계획"]
알림을 보내기 전에 반드시 중복 발송을 막아야 합니다. 이를 위해 액션 아이템 ID와 알림 유형을 조합한 멱등성 키를 사용합니다. 예를 들어 RETRO-2026-W34-03:due-soon이 이미 처리됐다면 같은 알림을 다시 보내지 않습니다.
액션 아이템 데이터 모델은 어떻게 설계할까?
처음부터 복잡한 프로젝트 관리 도구 전체를 만들 필요는 없습니다. 다음 필드만으로도 담당자 지정, 상태 추적, 기한 알림을 구현할 수 있습니다.
type ActionStatus = "todo" | "in_progress" | "blocked" | "done";
type RetroActionItem = {
id: string;
sprintKey: string;
title: string;
definitionOfDone: string;
ownerUserId: string;
createdByUserId: string;
dueAt: string; // ISO-8601, 예: 2026-08-28T18:00:00+09:00
status: ActionStatus;
blockedReason?: string;
sourceMessageTs?: string;
nextReminderAt: string | null;
lastNotifiedAt: string | null;
reminderCount: number;
completedAt: string | null;
};
고유 ID는 스프린트와 순번을 포함하면 검색과 회고 연결에 유리합니다. 예를 들어 RETRO-2026-W34-03은 2026년 34주차 스프린트 회고의 세 번째 액션 아이템을 의미합니다.
PostgreSQL에서는 다음처럼 저장할 수 있습니다.
CREATE TABLE retro_action_items (
id TEXT PRIMARY KEY,
sprint_key TEXT NOT NULL,
title TEXT NOT NULL,
definition_of_done TEXT NOT NULL,
owner_user_id TEXT NOT NULL,
due_at TIMESTAMPTZ NOT NULL,
status TEXT NOT NULL CHECK (status IN ('todo', 'in_progress', 'blocked', 'done')),
blocked_reason TEXT,
next_reminder_at TIMESTAMPTZ,
last_notified_at TIMESTAMPTZ,
reminder_count INTEGER NOT NULL DEFAULT 0,
completed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_retro_action_reminder
ON retro_action_items (next_reminder_at)
WHERE status <> 'done';
TIMESTAMPTZ를 사용하면 서버와 팀원의 시간대가 달라도 일관된 시각을 저장할 수 있습니다. 화면에 표시할 때만 팀의 기본 시간대인 Asia/Seoul로 변환하는 방식을 권장합니다.

리마인드 정책은 어떻게 정해야 하는가?
리마인드 봇은 알림 빈도보다 정책의 예측 가능성이 중요합니다. 팀이 합의한 규칙을 문서화하고 모든 액션 아이템에 동일하게 적용해야 합니다.
| 시점 | 대상 | 메시지 목적 | 기본 채널 |
|---|---|---|---|
| 기한 2영업일 전 | 담당자 | 기한과 완료 조건 확인 | DM |
| 기한 당일 오전 | 담당자 | 오늘 처리할 업무임을 안내 | DM |
| 기한 초과 1영업일 | 담당자 | 상태 업데이트 요청 | DM |
| 기한 초과 3영업일 | 담당자와 리드 | 지연 사유와 재계획 요청 | 비공개 채널 |
| 매주 회고 전 | 팀 전체 | 미완료 액션 아이템 요약 | 회고 채널 |
다음 원칙을 함께 적용하면 알림 피로를 줄일 수 있습니다.
- 근무 시간인 오전 9시부터 오후 6시 사이에만 발송합니다.
- 같은 액션 아이템에는 하루 최대 한 번만 자동 알림을 보냅니다.
blocked상태에서는 담당자에게 반복 알림을 보내지 않고 차단 사유를 리드에게 전달합니다.done상태가 되면 예약된 알림을 취소합니다.- 기한 연장은 담당자가 직접 수정하고 변경 이력을 남기도록 합니다.
- 에스컬레이션은 개인의 성과 평가가 아니라 의사결정과 지원 요청으로 표현합니다.
리마인드 봇을 어떻게 구현할까?
1단계: 회고 템플릿을 구조화한다
회고 문서나 Slack 메시지에서 다음 항목을 필수 입력으로 둡니다.
[액션 아이템]
제목: 빌드 실패 원인 분석 문서 작성
완료 조건: CI 실패 원인과 재발 방지 절차를 README에 반영
담당자: @developer
기한: 2026-08-28 18:00 KST
입력 단계에서 담당자와 기한을 받지 않으면 봇이 나중에 추론해야 하므로 자동화의 신뢰도가 떨어집니다. 제목과 완료 조건을 분리하면 상태 업데이트를 확인하기도 쉽습니다.
2단계: 입력값을 검증하고 액션 아이템을 저장한다
검증 규칙은 간단하고 명확해야 합니다.
- 제목은 10자 이상 120자 이하입니다.
- 담당자는 실제 Slack 사용자 ID와 매칭되어야 합니다.
- 기한은 현재 시각보다 이후여야 합니다.
- 완료 조건은 관찰 가능한 결과로 작성해야 합니다.
- 같은 스프린트에서 동일한 제목이 이미 존재하면 중복 여부를 확인합니다.
담당자 이름 대신 Slack 사용자 ID를 저장하면 이름 변경이나 표시명 중복의 영향을 줄일 수 있습니다. 원본 메시지의 ts와 채널 ID도 함께 저장하면 액션 아이템이 만들어진 맥락을 다시 확인할 수 있습니다.
3단계: 스케줄러가 미완료 항목을 조회한다
운영 규모가 작다면 Node.js 프로세스의 node-cron으로 10분마다 실행할 수 있습니다. 여러 인스턴스를 운영한다면 PostgreSQL의 행 잠금이나 Redis 기반 분산 락을 사용해 같은 알림이 중복 발송되지 않도록 해야 합니다.
const REMINDER_INTERVAL_MINUTES = 10;
async function findDueItems(now: Date) {
return db.query(
`
SELECT *
FROM retro_action_items
WHERE status <> 'done'
AND next_reminder_at IS NOT NULL
AND next_reminder_at <= $1
AND reminder_count < 5
ORDER BY next_reminder_at ASC
LIMIT 100
`,
[now],
);
}
조회한 뒤에는 발송 전에 다시 상태를 확인해야 합니다. 담당자가 알림 조회 직전에 완료 처리했을 수 있기 때문입니다. 발송과 이력 저장의 순서도 정해야 합니다.
권장 순서는 다음과 같습니다.
- 대상 행을
FOR UPDATE SKIP LOCKED로 잠급니다. - 현재 상태와 알림 조건을 다시 확인합니다.
- 멱등성 키가 이미 처리됐는지 조회합니다.
- Slack Web API로 메시지를 보냅니다.
lastNotifiedAt,nextReminderAt,reminderCount를 갱신합니다.- 성공과 실패 결과를 로그에 저장합니다.
4단계: Slack 메시지에 상태 변경 링크를 제공한다
알림에는 긴 설명보다 바로 실행할 수 있는 버튼이나 명령을 넣는 편이 좋습니다. Slack Block Kit을 사용하면 진행 중, 차단됨, 완료와 같은 상태 변경 버튼을 만들 수 있습니다.
메시지에는 다음 정보를 포함합니다.
RETRO-2026-W34-03 · 기한 임박
빌드 실패 원인 분석 문서 작성
완료 조건: CI 실패 원인과 재발 방지 절차를 README에 반영
기한: 2026-08-28 18:00 KST
현재 상태: TODO
[진행 중으로 변경] [차단됨] [완료]
버튼 클릭을 처리하는 엔드포인트는 Slack의 서명 검증을 수행해야 합니다. Signing Secret을 서버 환경 변수로 보관하고 요청의 X-Slack-Signature와 X-Slack-Request-Timestamp를 검증한 뒤 상태를 변경합니다.
5단계: 다음 알림 시각을 계산한다
기본 규칙은 기한 전 알림, 기한 당일 알림, 기한 후 에스컬레이션으로 나눌 수 있습니다. 주말과 공휴일을 제외하려면 회사 캘린더나 별도의 영업일 라이브러리를 사용합니다.
function calculateNextReminder(item: RetroActionItem, now: Date): Date | null {
if (item.status === "done") return null;
const dueAt = new Date(item.dueAt);
const overdue = dueAt.getTime() < now.getTime();
if (!overdue) {
return addBusinessDays(dueAt, -2);
}
if (item.status === "blocked") {
return addBusinessDays(now, 3);
}
return addBusinessDays(now, 1);
}
실제 운영에서는 계산 결과가 이미 지난 시각인지 확인해야 합니다. 봇이 중단됐다가 다시 실행되면 과거의 여러 알림을 한꺼번에 보내지 말고 현재 시각 기준으로 한 건만 처리하는 것이 안전합니다.
운영 중 어떤 지표를 확인해야 하는가?
봇의 성공 여부를 발송 건수로 판단하면 안 됩니다. 다음 지표를 주간 단위로 확인하는 것이 더 유용합니다.
| 지표 | 계산 방법 | 해석 |
|---|---|---|
| 액션 아이템 완료율 | 완료 항목 수 ÷ 전체 항목 수 | 회고 개선 과제가 실제로 실행되는지 확인 |
| 기한 내 완료율 | 기한 내 완료 항목 수 ÷ 완료 항목 수 | 일정 예측 가능성 확인 |
| 평균 지연 일수 | 지연 일수의 평균 | 스코프와 담당자 용량 점검 |
| 첫 알림 후 상태 변경률 | 알림 후 24시간 내 변경 항목 수 ÷ 알림 수 | 알림이 실제 행동으로 이어지는지 확인 |
| 차단 상태 비율 | blocked 항목 수 ÷ 미완료 항목 수 | 의사결정이나 외부 의존성 확인 |
| 중복 발송률 | 중복 메시지 수 ÷ 전체 메시지 수 | 멱등성 처리 품질 확인 |
예를 들어 완료율이 낮은데 차단 상태 비율도 높다면 알림 횟수를 늘릴 문제가 아닐 수 있습니다. 담당자에게 권한이 부족하거나 액션 아이템의 범위가 너무 큰지 먼저 확인해야 합니다.
실패하기 쉬운 운영 패턴은 무엇인가?
모든 미완료 항목을 공개 채널에서 압박한다
공개 채널의 반복 알림은 투명성을 높이는 대신 개인을 압박하는 방식으로 받아들여질 수 있습니다. 기본 알림은 담당자 DM으로 보내고 팀 채널에는 주간 요약만 게시하는 편이 안전합니다.
회고가 끝난 뒤 봇이 내용을 추출하게 한다
자연어에서 담당자와 기한을 추출하는 기능은 편리하지만 필수 입력을 대체하면 안 됩니다. 자동 추출 결과는 확인 단계에서 수정할 수 있어야 하며 최종 저장 전에 담당자가 승인하도록 구성해야 합니다.
기한이 지났다는 사실만 알린다
좋은 리마인드는 지연 사실과 함께 다음 행동을 제시합니다. 예를 들어 완료 예상일을 다시 입력하거나 blockedReason을 작성하거나 범위를 줄이는 선택지를 제공해야 합니다.
알림 실패를 조용히 무시한다
Slack API 오류, 잘못된 사용자 ID, 권한 만료는 언제든 발생할 수 있습니다. 발송 실패를 재시도 큐에 넣고 재시도 횟수를 제한하며 최종 실패는 운영 채널에 알려야 합니다.
팀 규모별 권장 구성
| 팀 규모 | 권장 구성 | 주의점 |
|---|---|---|
| 3~8명 | Node.js 20 LTS + SQLite + node-cron | 단일 프로세스와 백업 정책 필요 |
| 8~30명 | TypeScript + PostgreSQL 15+ + Slack Web API | 멱등성 키와 권한 관리 필요 |
| 30명 이상 | 워커 큐 + PostgreSQL + Redis 락 + 관측 도구 | 재시도, 레이트 리밋, 감사 로그 필요 |
핵심은 팀 규모보다 현재 사용하는 협업 도구와 운영 복잡도에 맞추는 것입니다. 이미 Jira나 Linear를 사용하고 있다면 별도 데이터베이스를 만들기보다 해당 도구의 이슈와 상태를 원본으로 삼고 봇은 수집과 알림만 담당하게 할 수 있습니다.
자주 묻는 질문 FAQ
Q. 회고 액션 아이템마다 반드시 담당자를 한 명만 지정해야 하나요?
기본 담당자는 한 명으로 지정하는 것이 좋습니다. 협업자가 필요하면 보조 참여자를 추가하되 완료 책임과 상태 변경 권한은 한 명에게 두어야 추적이 명확합니다.
Q. 리마인드 봇은 얼마나 자주 메시지를 보내야 하나요?
기본값은 하루 최대 한 번입니다. 기한 2영업일 전, 기한 당일, 기한 초과 1영업일 후를 시작점으로 삼고 팀의 응답률과 알림 피로도를 보며 조정하세요.
Q. 자동 알림을 도입했는데도 완료율이 낮으면 어떻게 해야 하나요?
알림 빈도를 늘리기 전에 완료 조건, 액션 아이템의 크기, 담당자의 권한, 외부 의존성을 점검해야 합니다. 한 스프린트 안에 완료하기 어려운 항목은 더 작은 작업으로 나누거나 다음 스프린트의 정식 작업으로 전환하는 것이 좋습니다.
정리
스프린트 회고 액션 아이템 자동 트래킹의 핵심은 봇 자체가 아니라 운영 데이터의 구조화입니다. ownerUserId, dueAt, definitionOfDone, status, nextReminderAt를 필수 데이터로 관리하고 Slack 알림과 상태 변경을 연결하면 회고 결과를 실제 개선 활동으로 이어갈 수 있습니다.
처음에는 회고 템플릿과 단순한 기한 알림만 도입하고 이후 멱등성 처리, 차단 상태, 에스컬레이션, 완료율 지표를 단계적으로 추가하는 방식이 현실적입니다. 자동화의 목표는 팀원을 감시하는 것이 아니라 약속한 개선 과제가 잊히지 않도록 실행의 맥락과 다음 행동을 제공하는 데 있습니다.



