사내 인하우스 서비스 기획 회의 중, 슬랙봇을 활용하면 별도의 회원가입이나 복잡한 절차 없이 간단히 서비스를 구축할 수 있다는 점을 알게 되었습니다. 특히, 슬랙봇이 제공하는 유려한 UI와 직관적인 사용자 경험에 관심이 생겨 간단한 서비스를 구현하게 되었습니다.
제가 하루에 “큰일”을 자주 본다고 했을 때 친구가 믿지 않았습니다. 그래서 실제로 증명하기 위해, 큰일을 볼 때는 카톡으로 ‘ㄸ’, 작은 일을 볼 때는 ‘ㅇ’을 친구에게 보냈습니다. 그 친구는 이 기록을 흥미롭게 여겨 주변 사람들의 배출 기록까지 모아 DB에 저장하기 시작했습니다. 이 과정이 저에게 영감을 주었고, 이를 기반으로 서비스를 만들어보고자 하였습니다.
NestJS 기반의 Slack 봇으로, Google Sheets와 연동하여 개인 활동 데이터를 추적하고 기록하는 애플리케이션입니다. Slack 슬래시 커맨드와 모달 인터페이스를 통해 데이터를 입력하고, Google Sheets에 실시간으로 저장됩니다.
/record 명령어를 통한 데이터 기록/history 명령어를 통한 기록 조회 및 통계Backend & Framework
API & 연동
개발 도구 & 품질 관리
src/
├── google-sheets/ # Google Sheets 관련 로직
│ ├── google-api.service.ts # Google API 인증 및 기본 설정
│ ├── google-sheets.service.ts # Sheets 데이터 CRUD 로직
│ └── google-sheets.module.ts # Google Sheets 모듈
├── slack/ # Slack 봇 관련 로직
│ ├── slack.service.ts # Slack 이벤트 처리 및 봇 로직
│ └── slack.module.ts # Slack 모듈
├── utils/ # 공통 유틸리티
│ └── date.utils.ts # KST 시간 처리 유틸리티
├── app.module.ts # 루트 모듈
└── main.ts # 애플리케이션 진입점
@Injectable 데코레이터를 통한 서비스 주입// Socket Mode를 통한 실시간 양방향 통신 설정
this.app = new App({
token: process.env.SLACK_BOT_TOKEN,
appToken: process.env.SLACK_APP_TOKEN,
socketMode: true,
});
구현 특징:
// Service Account 인증을 통한 Sheets API 접근
private async getSheetsApi() {
const auth = new google.auth.GoogleAuth({
keyFile: './service_account.json',
scopes: this.scopes,
});
return google.sheets({ version: 'v4', auth });
}
구현 특징:
// UTC를 KST로 변환하는 유틸리티
export const getKstString = (): string => {
const now = new Date();
const utc = now.getTime() + now.getTimezoneOffset() * 60000;
const kst = new Date(utc + 9 * 3600000);
return formatDate(kst);
};
구현 특징:
문제 상황: Modal 제출 시 동일한 요청이 여러 번 처리됨
시도한 해결책:
1. await ack() 호출 순서 변경
2. 이벤트 리스너 중복 등록 확인
최종 해결 방법:
// 즉시 응답 후 비동기 처리
this.app.view('record_modal', async ({ ack, body, view }) => {
await ack(); // 먼저 응답
// 그 다음 비즈니스 로직 처리
try {
await this.sheetsService.appendPoopRow(data, this.webhook);
} catch (error) {
// 에러 핸들링
}
});
문제 상황: 서버와 Google Sheets 간의 시간대 불일치
시도한 해결책:
1. moment.js 라이브러리 사용 고려
2. Google Sheets API의 시간대 설정 변경
최종 해결 방법: