시작하며
코코무 팀에서는 격일로 디스코드에 스크럼 알림을 보내고, 그 메시지에 팀원들이 스레드로 스크럼을 작성하는 방식으로 협업을 이어가고 있었다.
이 알림은 팀원 한 분이 수동으로 직접 작성하고 있었는데, 매번 직접 시간을 맞춰 알림을 올리는 게 번거롭고 귀찮을 뿐만 아니라, 때로는 바쁜 일정 때문에 잊어버리는 일도 종종 생겼다.
그래서 자연스럽게, “이걸 왜 사람이 직접 하지?”라는 생각이 들었고, 그 수고를 덜어줄 자동 알림 봇을 직접 만들게 되었다.
초기 세팅하기
디스코드 봇을 만들고 실행하기 위해서는, 이 봇이 누구의 소유인지를 디스코드 측에 등록하는 과정이 필요하다.
이를 위해 디스코드 개발자 포털에서 봇의 Token(토큰)을 발급받아 코드에 입력해야 한다.
먼저 아래 링크에 접속해 개발자 포털로 이동하자.
https://discord.com/developers/applications
Discord Developer Portal — API Docs for Bots and Developers
Integrate your service with Discord — whether it's a bot or a game or whatever your wildest imagination can come up with.
discord.com
오른쪽 상단에 있는 New Application 버튼을 클릭한다.
버튼을 누르면 애플리케이션 이름을 입력할 수 있는 창이 뜨는데, 여기에 원하는 이름을 입력하고 Create 버튼을 눌러 애플리케이션을 생성한다.
Reset Token 버튼을 클릭해 봇의 토큰을 새로 발급받는다.
발급된 토큰은 복사해서 안전한 곳에 보관해두자! 이 토큰은 추후 봇을 실행할 때 사용된다.
필요한 기능 구현하기
- /반복알림, /알림끄기 슬래시 커맨드 지원
- ${날짜}, ${시간}, ${요일} 같은 템플릿 치환 가능
- 10m, 2h, 1d, 3d처럼 다양한 간격 설정 가능
- 서버 초대 시 슬래시 커맨드 자동 등록
- 서버 재시작 시 기존 알림 복원
1. 슬래시 커맨드 등록
서버 초대 시 자동으로 명령어를 등록하도록 GuildCreate 이벤트에서 처리했다.
client.on(Events.GuildCreate, async guild => {
await registerCommandsToGuild(client.user.id, guild.id, token);
});
명령어 정의는 아래처럼 구성했다.
new SlashCommandBuilder()
.setName('반복알림')
.setDescription('반복 알림을 설정합니다')
.addStringOption(opt =>
opt.setName('시작시간').setDescription('시작 시간 (예: 2025-04-04T10:00)').setRequired(true)
)
.addStringOption(opt =>
opt.setName('반복간격').setDescription('간격 (예: 10m, 2h, 1d)').setRequired(true)
)
.addStringOption(opt =>
opt.setName('메시지').setDescription('알림 메시지').setRequired(true)
)
2. 반복 알림 등록 로직
reminderManager.js에서 실제 알림을 예약한다.
setTimeout으로 시작 시간을 맞춘 뒤, 이후 반복은 node-cron으로 처리한다.
const scheduleTask = () => {
const cronExpr = convertMsToCron(intervalMs);
const task = cron.schedule(cronExpr, sendMessage, { timezone: 'Asia/Seoul' });
activeReminders.set(key, task);
};
if (delay > 0) {
setTimeout(() => {
sendMessage();
scheduleTask();
}, delay);
} else {
sendMessage();
scheduleTask();
}
3. 메시지 템플릿 치환
${날짜}, ${시간}, ${요일}을 자동으로 현재 시각 기준으로 바꿔준다.
function formatTemplate(template) {
const now = dayjs().tz('Asia/Seoul');
const yyyy = now.year();
const mm = String(now.month() + 1).padStart(2, '0');
const dd = String(now.date()).padStart(2, '0');
const hh = String(now.hour()).padStart(2, '0');
const min = String(now.minute()).padStart(2, '0');
const days = ['일', '월', '화', '수', '목', '금', '토'];
const day = days[now.day()];
return template
.replace('${날짜}', `${yyyy}-${mm}-${dd}`)
.replace('${요일}', day)
.replace('${시간}', `${hh}:${min}`);
}
예를 들어,
/반복알림 ... 메시지:오늘은 ${날짜} (${요일}) ${시간} 스크럼!
→ 실제 메시지는 2025-04-06 (일) 09:00 스크럼! 형태로 전송됨.
4. 알림 유지 & 복원
등록된 알림은 reminders.json 파일에 저장하고, 봇이 다시 시작되면 자동으로 불러와 복원한다.
function loadReminders(client) {
const list = JSON.parse(fs.readFileSync(remindersPath, 'utf-8'));
for (const r of list) {
const channel = client.channels.cache.get(r.channelId);
if (channel) {
scheduleReminder(r.userId, channel, r.startStr, r.intervalStr, r.rawMessage, false);
}
}
}
이 방식은 간단하고 빠르게 구현할 수 있다는 장점이 있지만, Railway 같은 호스팅 환경에서는 재배포 시 .json 파일이 초기화될 수 있기 때문에 알림 데이터가 사라지는 문제가 있다.
예를 들어, 환경변수를 수정하거나 코드가 push되어 새로 배포되면 파일이 초기화되면서 기존 알림이 날아갈 수 있다.
🔧 향후 개선 계획
이런 한계를 보완하기 위해 이후 외부 DB를 연동해 알림 데이터를 영구적으로 저장하고 관리할 수 있도록 확장해 볼 예정이다.
5. 반복 간격 파싱
알림 간격은 문자열로 입력받아 밀리초로 변환된다. 예: 1d → 86400000ms
function parseInterval(str) {
const match = str.match(/^(\d+)([smhd])$/); // s초, m분, h시간, d일
const value = parseInt(match[1], 10);
const unitToMs = { s: 1000, m: 60000, h: 3600000, d: 86400000 };
return value * unitToMs[match[2]];
}
배포하기
스크럼 알림용으로만 사용할 디스코드 봇이기 때문에, 거창한 인프라보다는 가볍고 빠르게 배포할 수 있는 플랫폼이 필요했다.
그래서 GitHub 연동만으로 바로 배포가 가능한 Railway를 선택하게 되었다.
실행 결과 확인하기
정상적으로 반복 알림이 동작하는지 확인하기 위해, 1분 간격으로 알림을 설정해 테스트해보았다.
설정한 메시지가 매 분마다 정확하게 도착하는 것을 확인할 수 있었다!
개발과 배포를 마친 후, 실제로 디스코드 서버에 봇을 초대하고 알림을 등록해봤다!
슬래시 커맨드도 잘 등록되었다!
아래는 /반복알림 명령어를 사용해 알림을 설정하고, 설정한 시간에 맞춰 메시지가 정상적으로 전송된 화면이다.
아래 링크에서 코드를 확인하실 수 있습니다!
https://github.com/Seio924/Discord-Reminder-Bot
GitHub - Seio924/Discord-Reminder-Bot
Contribute to Seio924/Discord-Reminder-Bot development by creating an account on GitHub.
github.com