반응형
# 들어가며
"매일 아침 9시에 팀원들에게 데일리 스크럼 알림 보내기", "매주 금요일 주간보고 리마인더" — 이런 반복 알림, 어떻게 처리하고 계신가요?
별도 서버 없이, **내 PC에서 직접 돌리는 Telegram 알림 스케줄러**를 만들어 보았습니다. 클라우드 비용 0원, DB 서버 설치 0건. Node.js와 SQLite만으로 충분합니다.
---
## 이런 걸 만들었습니다
| 기능 | 설명 |
|------|------|
| 알림 CRUD | 등록 / 수정 / 삭제 / 테스트 발송 |
| 반복 유형 | 1회, 매시, 매일, 매주, 매월, 매년 |
| 캘린더 뷰 | 주간 / 월간 / 연간 시각화 |
| 실행 로그 | 발송 성공/실패 이력 조회 |
| 자동 복원 | 앱 재시작 시 활성 스케줄 자동 등록 |
| 다수 수신자 | Chat ID 콤마 구분으로 다중 전송 |
| 보안 헤더 | XSS, Clickjacking 등 기본 방어 적용 |
---
## 기술 스택
```
Frontend : React 19 + Vite
Backend : Node.js + Express
Database : SQLite (better-sqlite3)
Scheduler: node-cron
API 통신 : axios
```
> SQLite를 선택한 이유 — MySQL이나 PostgreSQL 같은 외부 DB 없이 `.db` 파일 하나로 끝. 로컬 용도에는 이게 최고입니다.
---
## 프로젝트 구조
```
telegram-schedule/
├── server/
│ ├── index.js # 서버 진입점
│ ├── controllers/ # 요청 처리 (유효성 검증)
│ ├── routes/ # REST API 라우팅
│ ├── services/
│ │ ├── telegramReminderService.js # DB CRUD
│ │ └── telegramService.js # Telegram API 연동
│ ├── scheduler/
│ │ └── telegramReminderScheduler.js # cron 기반 스케줄링
│ ├── db/sqlite.js # SQLite 연결 & 테이블 초기화
│ └── lib/ # 보안, 로깅, 에러코드 유틸
├── client/
│ ├── src/
│ │ ├── pages/
│ │ │ └── TelegramReminderAdminPage.jsx # 메인 관리 화면
│ │ └── components/
│ │ ├── TelegramReminderForm.jsx # 등록/수정 폼
│ │ ├── TelegramReminderList.jsx # 목록 테이블
│ │ ├── CalendarView.jsx # 캘린더 시각화
│ │ ├── LogModal.jsx # 실행 로그 모달
│ │ └── Toast.jsx # 알림 토스트
│ └── dist/ # 프로덕션 빌드
├── db/telegram_reminders.db # SQLite DB 파일 (자동 생성)
├── logs/ # 일별 로그 파일
└── .env # Bot Token 설정
```
---
## 핵심 설계 포인트
### 1. Cron 표현식 자동 생성
반복 유형에 따라 cron 표현식을 동적으로 빌드합니다.
```javascript
function buildCronExpression(reminder) {
const [hour, minute] = reminder.time_value.split(':').map(Number);
switch (reminder.repeat_type) {
case 'hourly':
// 매시 정각 ~ 지정 시간대까지
return `${minute} ${startHour}-${endHour} * * *`;
case 'daily':
return `${minute} ${hour} * * *`;
case 'weekly':
return `${minute} ${hour} * * ${weekday}`;
case 'monthly':
return `${minute} ${hour} ${day} * *`;
case 'yearly':
return `${minute} ${hour} ${day} ${month} *`;
case 'once':
// 매일 체크하되, 날짜 일치 시에만 실행
return `${minute} ${hour} * * *`;
}
}
```
`once`(1회) 타입이 재미있는데요 — cron 자체는 매일 해당 시각에 트리거되지만, 실행 시점에 날짜를 비교해서 해당일에만 발송하고 자동 비활성화합니다.
### 2. 실패 시 지수 백오프 재시도
네트워크 불안정에 대비해 최대 3회 재시도하며, 대기 시간을 1초 → 2초 → 4초로 늘려갑니다.
```javascript
for (let attempt = 1; attempt <= maxRetries; attempt++) {
const result = await sendTelegramMessage(chatId, formattedMsg);
if (result.success) break;
// 지수 백오프: 2^(attempt-1) * 1000ms
const delayMs = Math.pow(2, attempt - 1) * 1000;
await new Promise(resolve => setTimeout(resolve, delayMs));
}
```
### 3. 중복 실행 방지
`executingJobs` Set으로 동일 알림이 동시에 두 번 실행되는 것을 방지합니다. cron이 1분 간격이라 거의 발생하지 않지만, 전송 지연 시 다음 트리거와 겹칠 수 있어 방어 코드를 넣었습니다.
### 4. 앱 재시작 시 자동 복원
서버가 시작되면 DB에서 활성 상태인 알림을 모두 읽어와 cron job을 재등록합니다. 만료된 1회성 알림은 자동으로 비활성화 처리합니다.
```javascript
function restoreAllJobs() {
const activeReminders = reminderService.getActiveReminders();
for (const reminder of activeReminders) {
if (reminder.repeat_type === 'once' && reminder.date_value < today) {
reminderService.deactivateReminder(reminder.id);
continue;
}
registerJob(reminder);
}
}
```
---
## API 설계
RESTful하게 구성했습니다.
| Method | Endpoint | 설명 |
|--------|----------|------|
| GET | `/api/telegram-reminders` | 전체 목록 조회 |
| POST | `/api/telegram-reminders` | 알림 등록 |
| GET | `/api/telegram-reminders/:id` | 단건 조회 |
| PUT | `/api/telegram-reminders/:id` | 수정 |
| DELETE | `/api/telegram-reminders/:id` | 삭제 |
| PATCH | `/api/telegram-reminders/:id/active` | 활성/비활성 토글 |
| POST | `/api/telegram-reminders/test-send` | 테스트 발송 |
| GET | `/api/telegram-reminders/:id/logs` | 실행 로그 조회 |
---
## 실행 방법
### 사전 준비
- **Node.js 18+** 설치
### 설치 & 실행
```bash
# 1. 의존성 설치 (서버 + 클라이언트 한 번에)
npm run setup
# 2. 환경 설정
# .env 파일에 Bot Token 입력
TELEGRAM_BOT_TOKEN=your_bot_token_here
PORT=3001
# 3-A. 프로덕션 모드
npm run build
npm start
# → http://localhost:3001
# 3-B. 개발 모드 (핫 리로드)
npm run dev
# → http://localhost:5173
```
---
## Google 캘린더에서 영감을 받다
반복 유형 설계 시 Google 캘린더의 일정 반복 옵션을 참고했습니다.
> 1회 / 매시 / 매일 / 매주 / 매월 / 매년 — 실무에서 쓰이는 대부분의 반복 패턴을 커버합니다.
캘린더 뷰도 주간·월간·연간 모드를 제공해서, 등록된 알림을 시각적으로 확인할 수 있습니다.
---
## 주의사항
- **로컬 전용**입니다. PC가 켜져 있고 앱이 실행 중일 때만 알림이 발송됩니다.
- PC 종료 시 알림이 밀리지만, 재시작하면 활성 스케줄이 자동 복원됩니다.
- 보안상 `.env` 파일의 Bot Token은 절대 외부에 노출하지 마세요.
---
## 마치며
"서버 없이 내 PC에서 Telegram 알림을 자동화하고 싶다"는 단순한 니즈에서 시작한 프로젝트입니다. SQLite 덕분에 별도 DB 설치가 필요 없고, `npm run setup` 한 줄이면 바로 사용할 수 있습니다.
개인 리마인더, 팀 알림, 정기 보고 리마인더 등 다양하게 활용해 보세요.
소스 코드는 GitHub에서 확인할 수 있습니다.
반응형
'Programing' 카테고리의 다른 글
| [framework]Express vs NestJS 비교 정리 (0) | 2026.03.11 |
|---|---|
| [IT 지식] Express.js란 무엇일까? 웹 개발의 핵심 구조 이해하기 (0) | 2026.03.09 |
| [날짜]공공데이터포털 API 키 발급 방법 (한국천문연구원 특일 정보) (0) | 2026.03.09 |
| [Claude]실무에서 자주 보는 TypeScript 코드 작성 기준 정리 (0) | 2026.03.03 |
| [Python]파이썬 설치 (0) | 2026.02.20 |