롱 폴링과 SQLite로 Max.ru MVP 피드백 봇 만들기
Max.ru는 개발자에게 인터랙티브 도구를 만들 수 있도록 봇 API를 제공합니다. 이번 MVP 피드백 봇에서는 Node.js와 @maxhub/max-bot-api 라이브러리, 그리고 SQLite를 사용합니다. 롱 폴링 기술을 통해 웹훅, 서버, HTTPS 없이도 로컬 환경에서 개발할 수 있습니다.
핵심 과제는 관리자가 응답했을 때 해당 요청을 보낸 클라이언트를 식별하는 것입니다. 관리자의 답변 메시지에는 원본 메시지의 mid를 포함한 링크가 포함되어 있어, 데이터베이스를 통해 응답을 사용자에게 정확히 전달할 수 있습니다.
기술 스택 선택 및 프로젝트 설정
@maxhub/max-bot-api 라이브러리는 기본적으로 롱 폴링을 지원하므로, 개발 중 ngrok이나 Cloudflare Tunnel을 사용할 필요가 없습니다.
SQLite는 MVP에 이상적인 선택입니다. 파일 기반 데이터베이스로 별도의 서버가 필요 없으며, 지연 시간이 낮고 요청 처리가 일관적입니다.
의존성 설치:
npm init -y
npm install @maxhub/max-bot-api sqlite sqlite3 dotenv
.env 파일 생성:
BOT_TOKEN=your_token_here
OWNER_ID=12345678
토큰은 business.max.ru에서 발급받으며, OWNER_ID는 본인의 Max 사용자 ID입니다.
SQLite 초기화 및 데이터베이스 구조 설정
비동기 연결을 사용하고, 응답 매핑을 위한 reply_map 테이블을 생성합니다:
import { open } from 'sqlite';
import sqlite3 from 'sqlite3';
let db;
(async () => {
db = await open({ filename: './database.sqlite', driver: sqlite3.Database });
await db.exec(`
CREATE TABLE IF NOT EXISTS reply_map (
owner_msg_mid TEXT PRIMARY KEY,
client_user_id INTEGER
)
`);
console.log('Database ready');
})();
이 테이블은 owner_msg_mid를 client_user_id로 매핑하여 저장합니다.
클라이언트로부터의 메시지 처리
message_created 이벤트는 발신자를 확인합니다. 클라이언트 메시지는 마크다운 형식으로 관리자에게 포워딩됩니다:
const ownerId = Number(process.env.OWNER_ID);
bot.on('message_created', async (ctx) => {
const msg = ctx.message;
const senderId = msg.sender.user_id;
const text = msg.body.text;
if (senderId !== ownerId) {
const forwardText = `📩 **${msg.sender.first_name}님의 메시지** (ID: ${senderId}) :
${text}`;
const sentMsg = await bot.api.sendMessageToUser(ownerId, forwardText, { format: 'markdown' });
if (sentMsg && sentMsg.body && sentMsg.body.mid) {
await db.run('INSERT OR REPLACE INTO reply_map (owner_msg_mid, client_user_id) VALUES (?, ?)',
[sentMsg.body.mid, senderId]);
}
return;
}
// 응답 로직
});
전송된 메시지의 mid는 이후 경로 전달을 위해 reply_map에 저장됩니다.
관리자 응답 로직
응답 메시지는 link.type = 'reply'와 link.message.mid — 즉 원본 메시지의 ID — 를 포함합니다. 클라이언트를 찾기 위해:
link.type === 'reply'인 경우,repliedMsgMid를 추출하고 데이터베이스에서 조회합니다.client_user_id를 이용해 클라이언트에게 응답을 전송합니다.- 관리자에게 수신 확인을 전달합니다.
샘플 응답 JSON 구조:
{
"body": { "text": "answer", ... },
"sender": { ... },
"link": {
"type": "reply",
"message": {
"mid": "mid.original_message..."
}
}
}
이 아키텍처의 장점
- 로컬 개발 가능:
npm start로 바로 실행 가능하며, 포트 설정이나 SSL 구성 없이도 작동합니다. - 간편한 응답 인터페이스: 관리자는 표준 응답 기능을 자연스럽게 사용할 수 있습니다.
- 단순한 데이터베이스: 백업이 쉬운 하나의 파일(
database.sqlite)로 운영됩니다. - 확장성: 트래픽 증가 시 PostgreSQL으로 쉽게 마이그레이션 가능합니다.
핵심 요약
- 롱 폴링은 웹훅 없이도 MVP 개발을 간소화합니다.
- SQLite의
reply_map는 정확한 응답 경로 전달을 보장합니다. - 포워딩 메시지에 마크다운을 사용하면 클라이언트 이름과 ID 등 추가 정보가 명확해집니다.
- 관리자 응답의 백업 전략: 매칭되는 클라이언트가 없을 경우 최근 활성화된 클라이언트를 사용합니다.
— Editorial Team
아직 댓글이 없습니다.