우테코 크루가 자주 이용하는 정류장과 버스를 Slack 명령어로 조회하고, 설정한 시간대에 버스가 곧 도착하면 Slack DM으로 알려주는 퇴근 보조 서비스입니다.
/조회 [정류장]/조회 [정류장] [버스번호]/알림 [정류장] [버스번호] [몇 분 전] [시작시간] [종료시간]/알림 초기화/알림목록/알림삭제 [정류장] [버스번호]- 정류장 별칭 허용
- 조회 결과는 도착 시간 순으로 정렬
/도움말/상태/조회결과는 Block Kit으로 렌더링/알림목록은 Block Kit으로 렌더링/알림목록에서 삭제 버튼 제공- 삭제 버튼을 누르면 기존 목록 메시지를 삭제 완료 메시지와 갱신된 알림목록으로 교체
/알림을 인자 없이 입력하면 Modal로 등록 (정류장 선택, 시간 선택)- Modal 등록 성공 시 사용자에게 등록 완료 DM 발송
- 알림 DM에는 현재 시각과 "탑승 완료" 버튼 표시
- 알림 DM의 "탑승 완료" 버튼을 누르면 오늘 더 이상 모든 알림 발송 안 함
/알림 초기화로 탑승 완료 이후 오늘 중지된 알림을 다시 울리도록 초기화- 1분 주기 알림 스케줄링
- 같은 알림 10분 내 중복 발송 방지
- 같은 사용자, 정류장, 버스번호 조합의 중복 등록 시 기존 알림 업데이트
- Java 21
- Spring Boot 4
- Spring Web MVC
- Spring Data JPA
- H2 file mode
- Slack Slash Command
- Slack
chat.postMessage - Slack
views.open - Slack Block Kit Interactivity
- 경기버스 API
- Gradle
필수 환경변수:
export SLACK_BOT_TOKEN="<slack-bot-token>"
export SLACK_SIGNING_SECRET="..."
export GBIS_SERVICE_KEY="..."주의:
- Slack bot token, signing secret, 경기버스 API key는 커밋하지 않습니다.
- 노출된 Slack token은 Slack App 설정에서 즉시 폐기하고 새로 발급합니다.
- 로컬 데모에서는 ngrok URL을 Slack Slash Command Request URL로 연결합니다.
로컬 설정 파일을 생성합니다.
cp src/main/resources/application-example.properties src/main/resources/application.propertiessrc/main/resources/application.properties에는 로컬 실행용 기본값이 들어 있습니다.
Slack token, signing secret, 경기버스 API key는 환경변수로만 주입합니다.
./gradlew bootRun기본 설정:
- 서버 timezone:
Asia/Seoul - DB:
jdbc:h2:file:./data/bus-alert - H2 Console:
/h2-console - 알림 쿨타임: 10분
- 알림 체크 주기: 60초
./gradlew test테스트는 src/test/resources/application.properties의 H2 in-memory 설정을 사용합니다.
실행 중 생성되는 file mode DB와 분리되어 있습니다.
Slack App에서 아래 Slash Command를 생성하고, Request URL을 ngrok 또는 배포 주소와 연결합니다.
| Slack 명령어 | Request URL |
|---|---|
/조회 |
POST /slack/commands/search |
/알림 |
POST /slack/commands/alert |
/알림목록 |
POST /slack/commands/alert-list |
/알림삭제 |
POST /slack/commands/alert-delete |
/도움말 |
POST /slack/commands/help |
/상태 |
POST /slack/commands/status |
예시:
https://{ngrok-domain}/slack/commands/search
https://{ngrok-domain}/slack/commands/alert
https://{ngrok-domain}/slack/commands/alert-list
https://{ngrok-domain}/slack/commands/alert-delete
https://{ngrok-domain}/slack/commands/help
https://{ngrok-domain}/slack/commands/status
Interactivity & Shortcuts 설정에서 Interactivity를 켜고, Request URL을 아래처럼 연결합니다.
https://{ngrok-domain}/slack/actions
/slack/actions는 아래 Slack 인터랙션을 처리합니다.
/알림Modal 제출/알림목록의삭제버튼- 알림 DM의
탑승 완료버튼
현재 Modal의 정류장 선택은 static_select를 사용하므로 Options Load URL은 비워둡니다.
Bot Token Scopes에는 최소한 아래 권한이 필요합니다.
chat:writecommands
/조회, /알림목록, /알림 초기화, 명령어 기반 알림 등록 응답은 본인에게만 보이는 ephemeral 응답으로 반환됩니다.
알림 발송과 Modal 등록 성공 메시지는 chat.postMessage로 사용자 DM에 전송됩니다.
정류장 도착 정보 조회:
/조회 텔레칩스
특정 버스 도착 정보 조회:
/조회 텔레칩스 310
알림 등록:
/알림 텔레칩스 310 5 17:45 23:30
Modal로 알림 등록:
/알림
오늘 중지된 알림 다시 울리기:
/알림 초기화
알림 목록 조회:
/알림목록
알림 삭제:
/알림삭제 텔레칩스 310
도움말:
/도움말
시스템 상태 (GBIS API 호출 통계):
/상태
MVP에서는 정류장 이름 중복을 피하기 위해 아래 정류장만 지원합니다.
- 텔레칩스
- 벤처타운(북문)
벤처타워(북문), 벤처타워 북문 같은 별칭도 벤처타운(북문)으로 해석합니다.
지원 정류장과 노선 매핑은 DB에서 관리합니다. 앱 시작 시 정류장 기본 데이터와 해당 정류장의 경유 노선을 경기버스 API에서 읽어 자동으로 저장합니다.
| 정류장 | stationId | mobileNo | 지역 |
|---|---|---|---|
| 텔레칩스 | 204000158 |
05341 |
성남 |
| 벤처타운(북문) | 204000159 |
05342 |
성남 |
실행 후 bus_routes 테이블에 경유 노선이 채워집니다. |
알림은 아래 조건을 모두 만족할 때 발송됩니다.
- 현재 시간이 알림 시작 시간 이상입니다.
- 현재 시간이 알림 종료 시간 이하입니다.
- 등록된 정류장과 버스번호 매핑이 존재합니다.
- 첫 번째 버스 도착 예정 시간이
notifyBeforeMinutes이하입니다. - 같은 사용자, 정류장, 버스번호 조합의 알림이 최근 10분 이내 발송되지 않았습니다.
MVP에서는 자정을 넘기는 알림 시간을 지원하지 않습니다.
예를 들어 23:00 01:00은 등록할 수 없습니다.
알림 DM의 탑승 완료 버튼을 누르면 해당 사용자의 모든 알림이 오늘은 더 이상 울리지 않습니다.
다음 날에는 다시 알림이 울립니다.
당일에 다시 알림을 받고 싶으면 /알림 초기화를 입력합니다.
정류장:
- 지원 정류장만 허용합니다.
버스번호:
- 정류장별로 설정된 버스번호만 허용합니다.
알림 기준 시간:
- 1분 이상 30분 이하만 허용합니다.
시간:
HH:mm형식만 허용합니다.- 예:
09:05,17:45,23:30 - 비허용:
5:45,17,24:00
시작/종료 시간:
- 종료 시간은 시작 시간보다 늦어야 합니다.
- 자정을 넘기는 시간대는 지원하지 않습니다.
도메인 우선 패키지 구조를 사용합니다.
com.woowa.bus
├── alert
│ ├── application
│ ├── domain
│ └── infrastructure
├── arrival
│ ├── domain
│ └── infrastructure
├── route
│ ├── domain
│ └── infrastructure
├── search
│ └── application
├── slack
│ ├── application
│ ├── infrastructure
│ └── presentation
└── global
└── config
레이어 책임:
presentation: HTTP 요청/응답과 Slack command text 변환application: 유스케이스 흐름 조율domain: 핵심 규칙과 저장소 포트infrastructure: JPA, 경기버스 API, Slack API 구현
src/main/resources/application-example.properties: 로컬 실행 설정 예시src/main/resources/application.properties: 로컬 실행 설정src/test/resources/application.properties: 테스트 실행 설정build.gradle: 의존성과 Java 버전
- Slack App 생성
- Slash Command 6개 생성
- 각 Slash Command Request URL을 ngrok 또는 배포 URL로 연결
- Interactivity & Shortcuts 켜기
- Interactivity Request URL을
/slack/actions로 연결 -
SLACK_BOT_TOKEN설정 -
SLACK_SIGNING_SECRET설정 -
GBIS_SERVICE_KEY설정 - 텔레칩스
stationId확보 - 벤처타운(북문)
stationId확보 -
bus_routes테이블 자동 동기화 확인 -
/조회 텔레칩스응답 확인 -
/조회 텔레칩스 310Block Kit 응답 확인 -
/알림 텔레칩스 310 5 17:45 23:30등록 확인 -
/알림Modal 등록 확인 -
/알림목록확인 -
/알림목록삭제 버튼 확인 - Slack DM 알림 발송 확인
- 알림 DM의
탑승 완료버튼 확인 -
/알림 초기화후 알림 재발송 가능 여부 확인