🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

A

AI Generated

2026. 1. 31. · 12 Views

Discord 봇 개발 완벽 가이드

discord.js로 Discord 봇을 만들어봅시다. 실시간 채팅 연동부터 슬래시 커맨드까지, 실무 코드로 배우는 Discord 통합 가이드입니다.


목차

  1. Discord 봇의 활용 사례
  2. discord.js 라이브러리 개요
  3. src/discord 코드 분석
  4. DM 페어링 보안 정책
  5. 슬래시 커맨드 구현
  6. 실전: Discord 서버 봇 만들기

1. Discord 봇의 활용 사례

김개발 씨는 회사 동료들과 함께 쓰는 Discord 서버를 관리하고 있습니다. 매번 새로운 팀원이 들어올 때마다 규칙을 설명하고, 역할을 부여하는 일이 반복되었습니다.

"이걸 자동화할 수는 없을까?"라는 생각이 문득 들었습니다.

Discord 봇은 서버에서 반복적인 작업을 자동화하거나, 사용자와 상호작용하는 프로그램입니다. 마치 카페에 있는 키오스크처럼, 정해진 명령어에 따라 자동으로 응답하고 작업을 수행합니다.

게임 커뮤니티, 개발자 팀, 온라인 스터디 그룹 등 다양한 곳에서 활용됩니다.

다음 코드를 살펴봅시다.

// Discord 봇의 기본 구조
const { Client, GatewayIntentBits } = require('discord.js');

const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent
  ]
});

// 봇이 준비되면 실행
client.on('ready', () => {
  console.log(`${client.user.tag}로 로그인했습니다!`);
});

// 메시지를 받으면 반응
client.on('messageCreate', message => {
  if (message.content === '!안녕') {
    message.reply('안녕하세요! 무엇을 도와드릴까요?');
  }
});

client.login('YOUR_BOT_TOKEN');

김개발 씨는 입사 6개월 차 개발자입니다. 회사에서 운영하는 개발자 커뮤니티 Discord 서버에 매일 새로운 사람들이 들어옵니다.

그때마다 환영 메시지를 보내고, 규칙을 안내하고, 역할을 부여하는 일이 반복됩니다. 어느 날 선배 개발자 박시니어 씨가 말했습니다.

"이거, 봇으로 자동화하면 어때요? Discord API를 쓰면 간단하게 만들 수 있어요." 그렇다면 Discord 봇은 정확히 무엇일까요?

쉽게 비유하자면, Discord 봇은 마치 은행의 자동화 기기와 같습니다. 사람이 직접 창구에서 처리하던 업무를 자동으로 수행합니다.

예금 조회, 이체, 통장 정리 등 정해진 절차에 따라 일을 처리하죠. Discord 봇도 마찬가지입니다.

사용자의 명령어를 받아서 정해진 동작을 수행합니다. Discord 봇이 없던 시절에는 어땠을까요?

서버 관리자가 모든 일을 수동으로 처리해야 했습니다. 새로운 회원이 들어오면 직접 환영 메시지를 보내고, 질문이 올라오면 직접 답변하고, 규칙을 어긴 사람을 직접 제재해야 했습니다.

서버 규모가 커질수록 이런 작업은 감당하기 어려워졌습니다. 더 큰 문제는 일관성이었습니다.

관리자마다 답변이 다르고, 처리 속도도 달랐습니다. 밤에는 관리자가 자니까 아무도 대응하지 못했습니다.

바로 이런 문제를 해결하기 위해 Discord 봇이 등장했습니다. 봇을 사용하면 24시간 자동 응답이 가능해집니다.

또한 일관된 규칙 적용도 얻을 수 있습니다. 무엇보다 관리자의 업무 부담 감소라는 큰 이점이 있습니다.

위의 코드를 한 줄씩 살펴보겠습니다. 먼저 Client 객체를 생성하는 부분을 보면 intents 설정이 핵심입니다.

이것은 봇이 어떤 정보를 받을지 결정합니다. GatewayIntentBits.Guilds는 서버 정보를, GatewayIntentBits.GuildMessages는 메시지 이벤트를 받겠다는 의미입니다.

다음으로 client.on('ready') 이벤트에서는 봇이 Discord 서버에 성공적으로 연결되었을 때의 동작이 일어납니다. 마지막으로 client.login()으로 실제 Discord에 접속합니다.

실제 현업에서는 어떻게 활용할까요? 예를 들어 게임 커뮤니티를 운영한다고 가정해봅시다.

새로운 회원이 들어오면 자동으로 환영 메시지를 보내고, 서버 규칙을 DM으로 전송하고, 기본 역할을 부여하는 작업을 봇이 수행합니다. 넥슨, 라이엇게임즈 같은 게임 회사에서도 Discord 봇을 적극적으로 활용하고 있습니다.

하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 모든 이벤트를 다 받으려고 하는 것입니다.

불필요한 intents까지 설정하면 메모리 낭비가 심해지고, Discord API 제한에 걸릴 수 있습니다. 따라서 필요한 권한만 최소한으로 요청해야 합니다.

다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨의 설명을 들은 김개발 씨는 고개를 끄덕였습니다.

"아, 생각보다 간단하네요!" Discord 봇을 제대로 이해하면 커뮤니티 운영이 훨씬 효율적이 됩니다. 여러분도 오늘 배운 내용을 실제 서버에 적용해 보세요.

실전 팁

💡 - Discord Developer Portal에서 봇 토큰을 발급받으세요

  • 토큰은 절대 GitHub에 올리지 마세요 (환경 변수로 관리)
  • 처음에는 작은 기능부터 시작해서 점진적으로 확장하세요

2. discord.js 라이브러리 개요

김개발 씨가 Discord 봇을 만들기로 결심했습니다. 하지만 Discord API를 직접 다루려니 너무 복잡했습니다.

"더 쉬운 방법은 없을까요?" 박시니어 씨가 웃으며 말했습니다. "discord.js를 쓰면 돼요."

discord.js는 Discord API를 쉽게 사용할 수 있게 만든 Node.js 라이브러리입니다. 마치 외국어 통역사처럼, 복잡한 Discord API를 자바스크립트 개발자가 이해하기 쉬운 형태로 변환해줍니다.

이벤트 기반 아키텍처로 설계되어 있어 직관적으로 봇을 개발할 수 있습니다.

다음 코드를 살펴봅시다.

// discord.js 설치 및 기본 설정
// npm install discord.js

const { Client, GatewayIntentBits, Collection } = require('discord.js');

// Client 확장 - 커맨드 컬렉션 추가
const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.DirectMessages
  ]
});

// 커맨드를 저장할 컬렉션
client.commands = new Collection();

// 이벤트 핸들러 등록
client.once('ready', () => {
  console.log('봇이 준비되었습니다!');
});

module.exports = client;

김개발 씨는 Discord API 문서를 펼쳐놓고 한숨을 쉬었습니다. REST API 엔드포인트, WebSocket 연결, 인증 헤더 설정 등 신경 써야 할 것이 너무 많았습니다.

"이걸 다 구현해야 하나요?" 박시니어 씨가 커피 한 잔을 건네며 말했습니다. "아니요.

그래서 라이브러리가 있는 거예요. discord.js를 쓰면 이 모든 걸 대신 처리해줍니다." 그렇다면 discord.js는 정확히 무엇일까요?

쉽게 비유하자면, discord.js는 마치 자동차의 자동 변속기와 같습니다. 수동 변속기를 쓰면 클러치를 밟고 기어를 직접 조작해야 하지만, 자동 변속기는 그냥 액셀만 밟으면 알아서 기어를 바꿔줍니다.

discord.js도 마찬가지입니다. 복잡한 API 호출을 간단한 메서드 호출로 바꿔줍니다.

discord.js가 없던 시절에는 어땠을까요? 개발자들은 HTTP 요청을 직접 작성해야 했습니다.

인증 토큰을 헤더에 넣고, JSON 페이로드를 만들고, 에러 처리를 직접 구현했습니다. 더 큰 문제는 WebSocket 연결 관리였습니다.

연결이 끊기면 재연결하고, 하트비트를 보내서 연결을 유지하는 로직을 모두 직접 만들어야 했습니다. 바로 이런 문제를 해결하기 위해 discord.js가 등장했습니다.

discord.js를 사용하면 자동 재연결이 가능해집니다. 또한 타입 안전성도 얻을 수 있습니다.

무엇보다 방대한 커뮤니티와 문서라는 큰 이점이 있습니다. 위의 코드를 한 줄씩 살펴보겠습니다.

먼저 Client 클래스를 import하는 부분을 보면 다양한 클래스들이 함께 불러와지는 것을 알 수 있습니다. GatewayIntentBits는 어떤 이벤트를 받을지 설정하고, Collection은 커맨드를 효율적으로 관리하기 위한 자료구조입니다.

다음으로 client.commands = new Collection() 부분에서는 커맨드를 Map처럼 저장할 수 있는 컬렉션이 생성됩니다. 마지막으로 client.once('ready')는 봇이 처음 시작될 때 한 번만 실행되는 이벤트입니다.

실제 현업에서는 어떻게 활용할까요? 예를 들어 고객 지원 시스템을 Discord로 구축한다고 가정해봅시다.

사용자가 특정 명령어를 입력하면 티켓을 생성하고, 담당자에게 알림을 보내고, 문의 내역을 데이터베이스에 저장하는 작업을 discord.js로 구현할 수 있습니다. 많은 스타트업에서 이런 패턴을 적극적으로 사용하고 있습니다.

하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 버전 차이를 무시하는 것입니다.

discord.js v13과 v14는 API가 크게 다릅니다. 옛날 튜토리얼을 따라 하다가 에러가 나는 경우가 많습니다.

따라서 공식 문서의 최신 버전을 참고해야 합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.

"와, 이렇게 간단하게 될 줄 몰랐어요!" 김개발 씨는 눈이 반짝였습니다. discord.js를 제대로 이해하면 Discord 봇 개발이 훨씬 쉬워집니다.

여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.

실전 팁

💡 - discord.js 공식 문서(discord.js.org)를 즐겨찾기 하세요

  • 최신 버전(v14 이상)을 사용하세요
  • TypeScript를 쓰면 타입 안전성이 더 좋아집니다

3. src/discord 코드 분석

김개발 씨는 회사 프로젝트의 src/discord 폴더를 열어보았습니다. 여러 파일이 체계적으로 정리되어 있었습니다.

"이 구조는 왜 이렇게 나눠져 있죠?" 박시니어 씨가 설명을 시작했습니다. "유지보수하기 쉽게 모듈화한 거예요."

src/discord 구조는 Discord 봇의 기능을 역할별로 분리한 디렉토리 구조입니다. 마치 회사 조직도처럼, 각 파일이 명확한 책임을 가지고 있습니다.

client 설정, 이벤트 핸들러, 커맨드 관리, 유틸리티 함수 등이 각각의 파일로 분리되어 있어 코드 관리가 용이합니다.

다음 코드를 살펴봅시다.

// src/discord/client.js - Discord 클라이언트 초기화
const { Client, GatewayIntentBits } = require('discord.js');

const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.DirectMessages
  ]
});

// src/discord/handlers/ready.js - ready 이벤트 핸들러
module.exports = {
  name: 'ready',
  once: true,
  execute(client) {
    console.log(`${client.user.tag} 준비 완료!`);
  }
};

// src/discord/index.js - 메인 엔트리
const client = require('./client');
const loadEvents = require('./loaders/eventLoader');

loadEvents(client);
client.login(process.env.DISCORD_TOKEN);

김개발 씨는 처음에 모든 코드를 하나의 파일에 작성했습니다. 100줄, 200줄, 어느새 500줄이 넘어갔습니다.

코드를 수정하려고 할 때마다 어디를 고쳐야 할지 찾기가 어려워졌습니다. 박시니어 씨가 코드 리뷰를 하다가 말했습니다.

"이건 좀 정리가 필요해 보이네요. 파일을 나눠볼까요?" 그렇다면 왜 코드를 여러 파일로 나눠야 할까요?

쉽게 비유하자면, 코드 구조는 마치 옷장 정리와 같습니다. 모든 옷을 한 서랍에 쑤셔 넣으면 찾기 어렵습니다.

하지만 상의는 상의끼리, 하의는 하의끼리, 양말은 양말끼리 분류하면 필요한 걸 금방 찾을 수 있습니다. Discord 봇 코드도 마찬가지입니다.

코드를 분리하지 않으면 어떤 문제가 생길까요? 첫째, 코드를 찾기 어렵습니다.

특정 이벤트 핸들러를 수정하려면 수백 줄을 스크롤해야 합니다. 둘째, 충돌이 자주 발생합니다.

여러 개발자가 같은 파일을 동시에 수정하면 Git conflict가 발생합니다. 셋째, 테스트하기 어렵습니다.

함수가 분리되지 않으면 단위 테스트를 작성할 수 없습니다. 바로 이런 문제를 해결하기 위해 모듈화 구조가 등장했습니다.

모듈화를 하면 책임이 명확해집니다. 또한 재사용성이 높아집니다.

무엇보다 협업이 쉬워진다는 큰 이점이 있습니다. 위의 코드를 한 줄씩 살펴보겠습니다.

먼저 client.js 파일은 Discord 클라이언트만 생성하는 역할을 합니다. 다른 파일에서 이 클라이언트를 import해서 사용합니다.

다음으로 handlers/ready.js는 ready 이벤트만 처리합니다. name, once, execute 구조로 일관성 있게 작성되어 있습니다.

마지막으로 index.js는 모든 걸 조립하는 역할입니다. 실제 현업에서는 어떻게 활용할까요?

예를 들어 대규모 Discord 봇 서비스를 운영한다고 가정해봅시다. 여러 명의 개발자가 동시에 작업합니다.

A 개발자는 음악 재생 커맨드를 만들고, B 개발자는 모더레이션 기능을 만듭니다. 파일이 분리되어 있으면 서로의 작업이 충돌하지 않습니다.

Discord.js 공식 가이드에서도 이런 구조를 권장합니다. 하지만 주의할 점도 있습니다.

초보 개발자들이 흔히 하는 실수 중 하나는 너무 잘게 쪼개는 것입니다. 한 줄짜리 함수를 별도 파일로 만들면 오히려 복잡해집니다.

따라서 적절한 수준의 추상화를 유지해야 합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.

코드를 분리한 후, 김개발 씨는 훨씬 편하게 작업할 수 있었습니다. "이제 어디를 고쳐야 할지 바로 알겠어요!" 모듈화 구조를 제대로 이해하면 더 깔끔하고 유지보수하기 쉬운 봇을 만들 수 있습니다.

여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.

실전 팁

💡 - 파일명은 역할을 명확히 드러내도록 작성하세요

  • 한 파일이 100줄을 넘으면 분리를 고려하세요
  • 공통 로직은 utils 폴더에 모아두세요

4. DM 페어링 보안 정책

김개발 씨의 봇이 드디어 작동했습니다. 하지만 누군가 봇에게 DM을 보내서 다른 사람의 정보를 요청했습니다.

"이건 보안 문제가 될 수 있어요." 박시니어 씨가 경고했습니다. "DM 페어링 인증을 추가해야 합니다."

DM 페어링 보안은 사용자가 봇과 DM으로 소통할 때, 해당 사용자가 정당한 권한을 가진 사람인지 확인하는 절차입니다. 마치 은행 앱에서 본인인증을 하는 것처럼, 무작위 코드나 OAuth 인증을 통해 사용자의 신원을 검증합니다.

이를 통해 악의적인 사용자의 접근을 차단할 수 있습니다.

다음 코드를 살펴봅시다.

// src/discord/security/dmPairing.js
const crypto = require('crypto');
const pairingCodes = new Map(); // 인증 코드 저장

// 페어링 코드 생성
function generatePairingCode(userId) {
  const code = crypto.randomBytes(3).toString('hex').toUpperCase();
  const expiresAt = Date.now() + 5 * 60 * 1000; // 5분 후 만료

  pairingCodes.set(userId, { code, expiresAt });

  // 자동 삭제 타이머
  setTimeout(() => pairingCodes.delete(userId), 5 * 60 * 1000);

  return code;
}

// 페어링 코드 검증
function verifyPairingCode(userId, inputCode) {
  const pairing = pairingCodes.get(userId);

  if (!pairing) return false;
  if (Date.now() > pairing.expiresAt) {
    pairingCodes.delete(userId);
    return false;
  }

  return pairing.code === inputCode.toUpperCase();
}

module.exports = { generatePairingCode, verifyPairingCode };

김개발 씨는 봇이 잘 작동하는 걸 보고 뿌듯했습니다. 그런데 어느 날, 이상한 로그가 찍혔습니다.

누군가 다른 사람의 계정 정보를 요청하고 있었습니다. 박시니어 씨가 모니터를 보고 심각한 표정을 지었습니다.

"이거 큰일 날 뻔했네요. DM은 누구나 보낼 수 있거든요.

인증 절차가 없으면 누구든 정보를 빼갈 수 있어요." 그렇다면 DM 페어링 보안은 정확히 무엇일까요? 쉽게 비유하자면, DM 페어링은 마치 아파트 택배함과 같습니다.

택배함을 열려면 문자로 받은 인증번호를 입력해야 합니다. 아무나 택배함을 열 수 없도록 본인인증을 거치는 것이죠.

Discord DM도 마찬가지입니다. 봇에게 민감한 정보를 요청하려면 먼저 본인임을 증명해야 합니다.

보안 절차가 없으면 어떤 문제가 생길까요? 첫째, 개인정보 유출이 발생합니다.

악의적인 사용자가 다른 사람의 정보를 요청할 수 있습니다. 둘째, 스팸 공격을 받을 수 있습니다.

봇에게 무한히 DM을 보내서 서버를 마비시킬 수 있습니다. 셋째, 신뢰도 하락이 일어납니다.

사용자들이 봇을 믿지 못하게 됩니다. 바로 이런 문제를 해결하기 위해 DM 페어링 보안이 등장했습니다.

페어링 보안을 사용하면 본인 확인이 가능해집니다. 또한 세션 관리도 얻을 수 있습니다.

무엇보다 사용자 신뢰 확보라는 큰 이점이 있습니다. 위의 코드를 한 줄씩 살펴보겠습니다.

먼저 crypto.randomBytes(3)로 무작위 6자리 코드를 생성합니다. 이 코드는 추측하기 매우 어렵습니다.

다음으로 expiresAt을 설정해서 5분 후 자동으로 만료되게 만듭니다. 이렇게 하면 코드가 유출되어도 시간이 지나면 쓸모없어집니다.

verifyPairingCode 함수에서는 입력받은 코드와 저장된 코드를 비교합니다. 만료 시간도 함께 체크합니다.

마지막으로 검증이 끝나면 해당 코드를 삭제해서 재사용을 방지합니다. 실제 현업에서는 어떻게 활용할까요?

예를 들어 금융 서비스 봇을 운영한다고 가정해봅시다. 사용자가 잔액을 조회하려고 DM을 보냅니다.

봇은 먼저 서버 채널에 인증 코드를 표시하고, 사용자에게 DM으로 그 코드를 입력하라고 요청합니다. 코드가 일치하면 잔액 정보를 DM으로 전송합니다.

토스, 카카오뱅크 같은 핀테크 기업에서 비슷한 방식을 사용합니다. 하지만 주의할 점도 있습니다.

초보 개발자들이 흔히 하는 실수 중 하나는 코드를 평문으로 저장하는 것입니다. Map에 그냥 저장하면 메모리 덤프로 유출될 수 있습니다.

따라서 해시 처리를 추가하거나, Redis 같은 별도 저장소를 사용해야 합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.

페어링 인증을 추가한 후, 더 이상 이상한 요청이 들어오지 않았습니다. "이제 안심이에요!" DM 페어링 보안을 제대로 이해하면 더 안전한 봇을 만들 수 있습니다.

여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.

실전 팁

💡 - 인증 코드는 반드시 만료 시간을 설정하세요

  • 코드는 한 번 사용하면 즉시 삭제하세요
  • 민감한 정보는 암호화해서 저장하세요

5. 슬래시 커맨드 구현

김개발 씨는 봇의 명령어를 !명령어 형식으로 만들었습니다. 하지만 사용자들이 명령어를 잘 모르겠다고 불평했습니다.

"요즘은 슬래시 커맨드를 쓰는 게 트렌드예요." 박시니어 씨가 알려주었습니다. "자동완성도 되고, 훨씬 편리해요."

슬래시 커맨드는 Discord에서 /명령어 형식으로 실행하는 공식 명령어 시스템입니다. 마치 IDE의 자동완성처럼, 사용자가 /를 입력하면 사용 가능한 명령어 목록이 자동으로 표시됩니다.

옵션, 권한, 설명까지 정의할 수 있어 사용자 경험이 크게 향상됩니다.

다음 코드를 살펴봅시다.

// commands/ping.js - 슬래시 커맨드 정의
const { SlashCommandBuilder } = require('discord.js');

module.exports = {
  data: new SlashCommandBuilder()
    .setName('핑')
    .setDescription('봇의 응답 속도를 확인합니다')
    .addStringOption(option =>
      option.setName('메시지')
        .setDescription('함께 보낼 메시지')
        .setRequired(false)
    ),

  async execute(interaction) {
    const message = interaction.options.getString('메시지');
    const latency = Date.now() - interaction.createdTimestamp;

    await interaction.reply(
      `퐁! 🏓 지연시간: ${latency}ms${message ? `\n메시지: ${message}` : ''}`
    );
  }
};

// 슬래시 커맨드 등록 (deploy-commands.js)
const { REST, Routes } = require('discord.js');

const rest = new REST().setToken(process.env.DISCORD_TOKEN);
await rest.put(
  Routes.applicationGuildCommands(CLIENT_ID, GUILD_ID),
  { body: commands }
);

김개발 씨의 봇은 !핑, !도움말 같은 명령어를 사용했습니다. 하지만 사용자들이 자주 물어봤습니다.

"명령어가 뭐가 있죠? 어떻게 쓰는 거예요?" 박시니어 씨가 다른 봇을 보여주며 말했습니다.

"이 봇은 /만 치면 명령어가 다 나와요. 슬래시 커맨드를 쓰면 이렇게 됩니다." 그렇다면 슬래시 커맨드는 정확히 무엇일까요?

쉽게 비유하자면, 슬래시 커맨드는 마치 레스토랑 메뉴판과 같습니다. 메뉴판을 보면 어떤 음식이 있는지, 가격은 얼마인지, 어떤 재료로 만드는지 다 나와 있습니다.

슬래시 커맨드도 마찬가지입니다. /를 입력하면 사용 가능한 모든 명령어가 목록으로 표시되고, 각 옵션의 설명까지 볼 수 있습니다.

기존 텍스트 명령어의 문제는 무엇이었을까요? 첫째, 사용자가 명령어를 외워야 했습니다.

철자를 틀리면 작동하지 않았습니다. 둘째, 권한 체크가 어려웠습니다.

누구나 명령어를 입력할 수 있었고, 봇이 직접 권한을 체크해야 했습니다. 셋째, 옵션 파싱이 복잡했습니다.

띄어쓰기, 따옴표 처리를 개발자가 직접 구현해야 했습니다. 바로 이런 문제를 해결하기 위해 슬래시 커맨드가 등장했습니다.

슬래시 커맨드를 사용하면 자동완성이 가능해집니다. 또한 타입 안전성도 얻을 수 있습니다.

무엇보다 공식 지원이라는 큰 이점이 있습니다. 위의 코드를 한 줄씩 살펴보겠습니다.

먼저 SlashCommandBuilder로 명령어를 정의합니다. setName으로 명령어 이름을, setDescription으로 설명을 설정합니다.

다음으로 addStringOption으로 옵션을 추가합니다. setRequired(false)는 선택 옵션이라는 뜻입니다.

execute 함수에서는 interaction.options.getString()으로 사용자 입력을 받습니다. 파싱이 자동으로 됩니다.

마지막으로 interaction.reply()로 응답합니다. message.reply()와 다르게 3초 안에 응답해야 합니다.

실제 현업에서는 어떻게 활용할까요? 예를 들어 팀 관리 봇을 만든다고 가정해봅시다.

/회의생성 제목:주간회의 시간:14:00 참석자:@홍길동,@김철수 같은 명령어를 만들 수 있습니다. Discord가 자동으로 옵션을 파싱해서 interaction.options로 전달해줍니다.

슬랙, 노션 같은 협업 도구에서도 비슷한 슬래시 커맨드 시스템을 사용합니다. 하지만 주의할 점도 있습니다.

초보 개발자들이 흔히 하는 실수 중 하나는 커맨드 등록을 안 하는 것입니다. 코드만 작성하고 deploy-commands.js를 실행하지 않으면 Discord에 명령어가 등록되지 않습니다.

따라서 명령어를 수정할 때마다 재등록해야 합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.

슬래시 커맨드를 적용한 후, 사용자 만족도가 크게 올랐습니다. "이제 명령어 물어보는 사람이 없어요!" 슬래시 커맨드를 제대로 이해하면 더 편리한 봇을 만들 수 있습니다.

여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.

실전 팁

💡 - 명령어 이름은 소문자만 사용하세요 (한글도 가능)

  • 옵션은 최대 25개까지만 추가할 수 있습니다
  • 글로벌 커맨드는 등록 후 1시간 정도 걸릴 수 있습니다

6. 실전: Discord 서버 봇 만들기

드디어 김개발 씨가 실전 프로젝트를 시작했습니다. 회사 Discord 서버를 위한 관리 봇을 만들기로 했습니다.

"이제 배운 걸 다 활용할 시간이에요!" 박시니어 씨가 격려했습니다. "처음부터 차근차근 만들어봅시다."

Discord 서버 봇 제작은 지금까지 배운 모든 내용을 종합하는 실전 프로젝트입니다. 마치 레고 블록을 조립하듯이, 클라이언트 설정, 이벤트 핸들러, 슬래시 커맨드, 보안 정책을 하나씩 조합해서 완전한 봇을 만듭니다.

실무에서 바로 사용할 수 있는 수준의 봇을 직접 구현해봅니다.

다음 코드를 살펴봅시다.

// index.js - 메인 엔트리 포인트
require('dotenv').config();
const { Client, GatewayIntentBits, Collection } = require('discord.js');
const fs = require('fs');
const path = require('path');

// 클라이언트 생성
const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.GuildMembers
  ]
});

// 커맨드 로드
client.commands = new Collection();
const commandsPath = path.join(__dirname, 'commands');
const commandFiles = fs.readdirSync(commandsPath).filter(f => f.endsWith('.js'));

for (const file of commandFiles) {
  const command = require(path.join(commandsPath, file));
  client.commands.set(command.data.name, command);
}

// 이벤트 로드
const eventsPath = path.join(__dirname, 'events');
const eventFiles = fs.readdirSync(eventsPath).filter(f => f.endsWith('.js'));

for (const file of eventFiles) {
  const event = require(path.join(eventsPath, file));
  if (event.once) {
    client.once(event.name, (...args) => event.execute(...args));
  } else {
    client.on(event.name, (...args) => event.execute(...args));
  }
}

// 봇 시작
client.login(process.env.DISCORD_TOKEN);

김개발 씨는 노트북 앞에 앉아 심호흡을 했습니다. 드디어 실전 프로젝트를 시작할 시간입니다.

회사 Discord 서버에는 매일 새로운 인턴이 들어오고, 공지사항도 많고, 질문도 쏟아집니다. 박시니어 씨가 커피를 건네며 말했습니다.

"긴장하지 마세요. 지금까지 배운 걸 하나씩 적용하면 됩니다." 그렇다면 실전 봇 프로젝트는 어떻게 시작해야 할까요?

쉽게 비유하자면, 봇 제작은 마치 집을 짓는 것과 같습니다. 먼저 기초 공사(클라이언트 설정)를 하고, 뼈대를 세우고(이벤트 핸들러), 내부를 꾸미고(커맨드 구현), 마지막으로 보안 시스템을 설치합니다(인증 정책).

순서대로 차근차근 진행하면 튼튼한 집이 완성됩니다. 무작정 코딩부터 시작하면 어떤 문제가 생길까요?

첫째, 구조가 엉망이 됩니다. 나중에 기능을 추가하려면 모든 코드를 뜯어고쳐야 합니다.

둘째, 버그가 많아집니다. 어디서 문제가 생겼는지 찾기 어렵습니다.

셋째, 확장이 어렵습니다. 새로운 커맨드를 추가할 때마다 복잡해집니다.

바로 이런 문제를 해결하기 위해 체계적인 프로젝트 구조가 필요합니다. 체계적 구조를 사용하면 유지보수가 쉬워집니다.

또한 협업이 가능해집니다. 무엇보다 확장성이 좋아진다는 큰 이점이 있습니다.

위의 코드를 한 줄씩 살펴보겠습니다. 먼저 .env 파일에서 토큰을 로드합니다.

절대 코드에 토큰을 직접 쓰면 안 됩니다. 다음으로 commands 폴더의 모든 파일을 읽어서 Collection에 저장합니다.

이렇게 하면 커맨드를 추가할 때 index.js를 수정할 필요가 없습니다. events 폴더도 마찬가지입니다.

새로운 이벤트 핸들러를 추가하려면 그냥 파일만 만들면 됩니다. event.once를 체크해서 일회성 이벤트와 반복 이벤트를 구분합니다.

마지막으로 client.login()으로 봇을 시작합니다. 실제 현업에서는 어떻게 활용할까요?

예를 들어 게임 길드 관리 봇을 만든다고 가정해봅시다. 새 멤버가 들어오면 자동으로 역할을 부여하고, 길드 규칙을 DM으로 보내고, 환영 메시지를 서버에 표시합니다.

/출석 커맨드로 일일 출석을 체크하고, /랭킹 커맨드로 활동 순위를 보여줍니다. 리니지, 로스트아크 같은 게임 커뮤니티에서 이런 봇을 활발히 사용합니다.

하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 에러 처리를 안 하는 것입니다.

Discord API는 가끔 오류를 반환합니다. 네트워크 문제, 권한 부족, 레이트 리밋 등 다양한 이유로 실패할 수 있습니다.

따라서 try-catch 블록으로 모든 API 호출을 감싸야 합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.

2주간의 개발 끝에, 봇이 성공적으로 작동했습니다. 새 인턴이 들어오면 자동으로 환영하고, 공지사항을 정리하고, 자주 묻는 질문에 답변했습니다.

"우와, 이거 정말 편한데요!" 동료들이 감탄했습니다. 김개발 씨는 뿌듯한 미소를 지었습니다.

실전 봇 제작을 제대로 이해하면 실무에서 바로 쓸 수 있는 봇을 만들 수 있습니다. 여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.

실전 팁

💡 - 프로젝트 구조를 먼저 설계하고 코딩을 시작하세요

  • 환경 변수(.env)로 민감한 정보를 관리하세요
  • 로깅 시스템을 추가해서 문제를 추적하세요
  • PM2나 Forever로 봇을 백그라운드에서 실행하세요

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#Discord#discord.js#Bot#SlashCommand#WebSocket#Discord,Node.js

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.

함께 보면 좋은 카드 뉴스