재난문자가 오면 5분 안에 쇼츠로: 재난문자 API에서 인스타·텔레그램·카카오톡·웹까지 자동 배포한 11단계
이 글과 연결된 글 보기
드래그로 이동 · 휠/두 손가락으로 확대 · 방향키로 글 선택 · 0으로 맞춤. 실선: 본문 링크, 점선: 시리즈·주제의 대표 연결.표시된 글 10편 목록
재난문자가 발송되면 몇 분 안에 그 문자를 지도·음성·원문이 들어간 세로 영상으로 만들어 인스타그램 @disaster.hanjang에 올리고, 같은 지역을 구독한 사람에게 텔레그램으로 보내고, 지역별 웹 페이지 disaster.datapopcorn.ai를 갱신하는 자동화를 만들었습니다. 상시 감시로 바꾼 뒤 정상 처리된 실제 문자 기준으로 발송 후 2.1~4.6분 안에 게시와 첫 댓글 확인까지 끝났습니다. 이 글은 그 과정을 처음부터 같은 순서로 따라 할 수 있게 11단계로 정리한 것입니다.

이 글은 이런 분께 필요합니다
- 공공 API에서 실시간 이벤트(재난문자, 공지, 가격 변동 등)를 받아 사람 손 없이 영상·알림으로 내보내고 싶은 분
- 인스타그램에 공식 API로 릴스를 자동 게시하려는데, 영상 파일을 어떻게 공개 URL로 넘겨야 할지 막힌 분
- 텔레그램이나 카카오톡으로 "내 지역만" 골라 받는 구독 봇을 만들고 싶은 분
- 자동화가 "올렸나"만 확인하고 "제대로 올렸나"를 놓쳐 사실 오류를 낸 경험이 있는 분
준비물은 다음과 같습니다.
| 항목 | 이 글에서 쓴 것 |
|---|---|
| 상시 켜 둘 컴퓨터 | 맥 1대 (launchd로 상시 실행) |
| 재난문자 API | 재난안전데이터공유플랫폼 행정안전부_긴급재난문자 (무료, IP 등록 필요) |
| 음성 | Typecast API (영상 1편에 약 105크레딧) |
| 지도 | OpenStreetMap 타일과 Nominatim 행정경계 (출처 표기) |
| 일러스트 | 이랴스토야(いらすとや) 이미지, 영상 1편에 4장 이내 |
| 게시 | Instagram API with Instagram Login, 텔레그램 Bot API, 카카오 챗봇 관리자센터 |
| 웹 공개 | Cloudflare Tunnel (자기 도메인의 하위 도메인) |
언어는 파이썬 표준 라이브러리와 Pillow, NumPy만 썼고, 영상 합성은 ffmpeg로 했습니다.
Step 1. 재난문자 API 키를 받고, 상시 켜 둘 컴퓨터의 IP를 등록합니다
재난안전데이터공유플랫폼(safetydata.go.kr)에서 행정안전부_긴급재난문자를 활용 신청하면 서비스 키가 나옵니다. 이 API는 신청서에 적은 IP 1개에서만 호출됩니다. 다른 IP에서 부르면 이렇게 거절됩니다.
{"header":{"resultMsg":"UNREGISTERED IP ERROR","resultCode":"32","errorMsg":"등록되지 않은 IP"},"body":null}
처음에는 노트북 IP로 신청했다가, 노트북을 들고 다니면 IP가 바뀌어 감시가 멈춘다는 문제가 생겼습니다. 그래서 마이페이지 → 데이터 이용 내역 → 수정에서 유저 IP를 24시간 켜 두는 Mac의 공인 IP로 바꿨습니다. IP 변경은 바로 반영됐고, 같은 키로 새 IP에서 NORMAL SERVICE가 돌아오는 것을 확인했습니다.
- 공인 IP 확인: 그 컴퓨터에서
curl -s https://api.ipify.org - 하루 호출 한도 기본값은 1,000회입니다. 30초 간격으로 확인하려면 하루 약 2,900회가 필요해 같은 화면에서 5,000회로 변경 신청을 했고, 이 글을 쓰는 시점에는 승인 대기입니다. 변경 신청 중에도 기존 키는 그대로 동작했습니다.
- 그날 문자만 받으려면
crtDt=YYYYMMDD파라미터를 붙입니다. 전체를 받지 않아도 돼서 호출 한 번이 0.1초 남짓이었습니다.
https://www.safetydata.go.kr/V2/api/DSSP-IF-00247?serviceKey=<키>&pageNo=1&numOfRows=200&returnType=json&crtDt=20261021
응답의 주요 필드는 SN(일련번호), CRT_DT(발송 시각), MSG_CN(원문), RCPTN_RGN_NM(수신 지역, 쉼표로 여러 개), DST_SE_NM(재난 유형), EMRG_STEP_NM(안전안내·긴급재난·위급재난)입니다.
Step 2. 어떤 문자를 영상으로 만들지 거르는 규칙을 정합니다
하루 재난문자는 60건 안팎이고, 그중 상당수는 실종자 찾기, 집회 안내, 보이스피싱 주의처럼 기타 유형입니다. 2023년 9월~12월 3,000건을 세어 보니 기타가 1,492건으로 절반이었습니다. 그래서 다음 규칙으로 걸렀습니다.
- 핵심 재난 유형만: 호우·홍수·태풍·강풍·대설·한파·폭염·지진·지진해일·화재·산불·산사태·붕괴·폭발·정전 등. 긴급재난·위급재난 단계는 유형과 관계없이 포함
- 같은 유형 + 같은 시군구 + 같은 날은 영상 1편: 같은 날 다시 보낸 문자는 영상 없이 원문만 전달
- 발송 후 6시간이 지난 문자는 건너뜀: 감시가 잠깐 멈췄다 다시 켜졌을 때 오래된 문자가 한꺼번에 올라가지 않게
- 하루 상한: 인스타그램 API는 24시간에 100편이 한도라 80편에서 멈춤
처리한 문자는 state.json에 SN 단위로 기록해 두고, 이미 처리한 SN은 다시 보지 않습니다.
Step 3. 문자 한 통을 화면에 넣을 칸으로 나눕니다 (원문 그대로)
영상에는 "무엇 / 어디 / 언제"와 행동 요령이 들어갑니다. 처음에는 Gemini로 문자에서 제목·장소·행동 문구를 뽑았는데, 두 가지 이유로 지금은 규칙만으로 뽑습니다.
- 무료 한도: 빌려 쓰던 키가 무료 요금제였고, 운영 첫날 오후 2시쯤
429 RESOURCE_EXHAUSTED가 났습니다. 응답에generate_content_free_tier_requests, limit: 20이라고 적혀 있었습니다. 하루 20회를 넘는 날에는 영상 만들기 첫 단계에서 멈췄고, 그 사이 6편이 밀렸습니다. - 사실 보존: 재난문자는 바꿔 쓰면 안 되는 글입니다. 뽑은 문구가 원문에 그대로 있는지 어차피 코드로 다시 확인해야 했습니다.
규칙은 단순합니다.
ACT_RE = re.compile(r'(바랍니다|하세요|하십시오|자제|유의|대피|주의|우회|삼가|금지|확인)')
PLACE_RE = re.compile(r'[가-힣A-Za-z0-9]+(?:\s*입구)?\s*(?:사거리|삼거리|교차로)'
r'|[가-힣A-Za-z0-9]+(?:IC|JC|나들목|터널|대교|지하차도)'
r'|[가-힣0-9]+(?<!지)역(?![가-힣])'
r'|[가-힣]+(?:동|리|읍|면|가)\s*\d+(?:-\d+)?')
- 행동 문구: 원문을
▲와 문장 단위로 나눈 뒤, 위 단어가 들어간 문장을 그대로 씁니다. - 장소: 첫 문장에서
예단포 입구 사거리,역삼동 830-71,수원역같은 구절만 지도 핀으로 씁니다. "연평도지역"이 "역"으로 잡히지 않도록(?<!지)역을 넣었습니다. - 제목: 원문에 그대로 있는 16자 이내 구절만 씁니다. 문장이 길면
21시부로 한파주의보가 발령처럼 "○○주의보(가) 발령/발효/해제" 구절을 찾고, 없으면강풍 재난문자처럼 유형 이름을 씁니다.
Step 4. 첫 화면을 "무엇 / 어디 / 문자 발송"으로 꽉 차게 만듭니다
릴스는 첫 1초에 넘길지 말지가 정해집니다. 첫 프레임에서 바로 무엇이, 어디서, 언제 났는지 읽히도록 세 줄을 화면 폭에 맞춰 키웠습니다.
- 글꼴은 굵은 제목용 글꼴(Black Han Sans)을 쓰고, 화면 폭 940px에 들어가는 가장 큰 크기를 자동으로 고릅니다. 두 줄에 안 들어가면 자르지 않고 크기를 줄입니다.
- 인스타 프로필 격자에는 가운데 3:4만 보여서, 중요한 글자는 세로 260~1650px 안에 둡니다.
- 일러스트는 오른쪽 아래 귀퉁이에 작게 두어 글자를 가리지 않게 했습니다.
운영 첫날 검수에서 이 화면에서만 세 번 실수가 나왔습니다(Step 10). 그래서 지금은 세 번째 칸 이름이 "언제"가 아니라 **"문자 발송"**입니다.

Step 5. 지도, 음성, 효과음을 붙여 20초 안팎 영상으로 만듭니다
| 장면 | 내용 | 만드는 법 |
|---|---|---|
| 1. 첫 화면 | 무엇·어디·문자 발송 | Pillow로 그림 |
| 2. 지도 | 시군구 경계를 붉은 선으로, 주변은 흑백 | OSM 타일 + Nominatim 경계 폴리곤 |
| 3. 행동 요령 | 원문 행동 문장 | 원문 그대로 |
| 4. 원문 카드 | 문자 전문과 출처 | 원문 그대로 |
- 음성: Typecast API로 문장별로 합성합니다. 처음에는 문장을 차례로 합성해 6초가 걸렸는데, 앞뒤 문맥(
previous_text,next_text)은 그대로 넘기고 문장별로 동시에 요청하도록 바꿨습니다. - 효과음: 실제 재난문자 경보음은 쓰지 않았습니다. 실제 경보로 착각할 수 있어서, 비프·휘익 같은 소리를 파이썬으로 직접 합성했습니다.
- 지도 경계: Nominatim은 1초에 1번만 부를 수 있습니다. 과거 문자에 나온 시도·시군구 316곳의 경계를 미리 받아 두니, 처음 나오는 지역의 제작 시간이 93초에서 49초로 줄었습니다.
- 일러스트 라이선스: 이랴스토야는 상업 이용 시 한 작품에 20장 이내라 영상 1편에 4장 이내로 씁니다. 일본어 글자가 들어간 그림은 쓰지 않습니다.
Step 6. 상시 감시 데몬으로 돌립니다 (launchd KeepAlive)
처음에는 2분마다 스크립트를 새로 실행했는데, 영상 한 편을 다 만들 때까지 다음 문자를 못 봐서 같은 시각 여러 지역 문자가 오면 뒤 순서가 15분 넘게 밀렸습니다. 그래서 항상 떠 있는 프로세스로 바꾸고, 새 문자마다 작업 스레드를 띄워 최대 4편을 동시에 만듭니다.
<key>KeepAlive</key><true/>
<key>RunAtLoad</key><true/>
<key>ThrottleInterval</key><integer>30</integer>
- 확인 간격은 하루 호출 한도에서 계산합니다. 실제 코드는
max(30, 86400 / max(100, 한도 - 100))초입니다. 한도 1,000회면 96초이고, 5,000회면 계산값은 17.6초지만 30초 하한에 걸려 30초입니다. 100회는 대시보드 갱신 몫으로 남겨 둡니다. - 멈추고 싶을 때는 프로세스를 내리지 않고
state/PAUSE파일을 만듭니다. 실제로 코드를 배포하다launchctl bootout으로 내린 뒤 다시 등록하지 못해 9분 동안 감시가 꺼진 적이 있습니다.
Step 7. 인스타그램 공식 API로 바로 올립니다
브라우저로 올리면 같은 브라우저를 쓰는 다른 계정 작업과 섞입니다. 그래서 계정별 토큰을 쓰는 Instagram API with Instagram Login(graph.instagram.com)으로 올립니다.
- 크리에이터 계정으로 전환: 개인 계정은 API로 게시할 수 없습니다. 인스타그램 웹 설정 → 프로페셔널 계정에서 크리에이터를 고르고, 카테고리는 "뉴스 및 미디어 웹사이트"로 하되 프로필에는 표시하지 않았습니다.
- Meta 앱에 Instagram 테스터로 추가: 앱 대시보드 앱 역할 → 사람 추가 → Instagram 테스터에서 계정을 초대하고, 인스타그램 설정 → 앱 및 웹사이트 → 테스터 초대에서 수락합니다.
- 토큰 생성: API 설정의 "액세스 토큰 생성"에서 그 계정의 토큰 생성을 누르고 로그인합니다. 동의 화면에서 메시지 권한은 끄고, 게시·댓글·인사이트만 남겼습니다. 토큰은 60일짜리라 서버에서 주기적으로 갱신합니다.
- 영상은 공개 URL로 넘깁니다: 이 API는 파일 직접 업로드를 받지 않고
video_url만 받습니다. 로컬 파일 서버를cloudflared tunnel --url(빠른 터널)로 잠깐 공개해 넘깁니다.
POST /{user-id}/media media_type=REELS, video_url=..., caption=...
GET /{container-id}?fields=status_code → FINISHED가 될 때까지
POST /{user-id}/media_publish creation_id=...
시간을 재 보니 터널을 매번 새로 여는 데 25~35초가 걸렸습니다(주소가 외부에서 열릴 때까지 기다리는 시간). 그래서 터널을 계속 띄워 두고 5분마다 예열하게 바꿨더니 업로드 URL 준비가 0.1초가 됐습니다. 인스타그램 쪽 처리(FINISHED까지)는 약 27초였고, 상태 확인 간격도 5초에서 2초로 줄였습니다.
중복 게시를 막는 규칙도 넣었습니다. media_publish를 호출한 뒤 생긴 실패는 다시 시도하지 않습니다. 응답을 못 받았을 뿐 실제로는 올라갔을 수 있어서입니다.

Step 8. 인스타그램은 긴급·위급만, 나머지는 하루 요약으로
모든 지역 문자를 올리니 팔로워 입장에서는 남의 동네 강풍주의보가 피드를 채웠습니다. 인스타그램은 팔로워마다 다른 게시물을 보여 줄 수 없어서, 역할을 나눴습니다.
- 인스타그램 즉시 게시: 긴급재난·위급재난 단계 문자만 (하루 0~1편)
- 인스타그램 하루 요약: 매일 07:30에 전날 문자를 유형별·시도별로 센 이미지 1장. 숫자는 API 원자료에서 바로 셉니다.
- 나머지 지역 문자: 텔레그램 구독자와 웹 페이지로만 보냅니다 (Step 9~11)

음성 비용을 줄이려고, 긴급·위급도 아니고 그 지역을 구독한 사람도 없는 문자는 영상을 만들지 않고 웹에 원문만 올립니다.
Step 9. 텔레그램 지역 구독 봇을 만듭니다
- 텔레그램에서 @BotFather(사용자 수와 파란 체크로 공식 계정인지 확인)에게
/newbot을 보내고, 이름과_bot으로 끝나는 아이디를 정하면 토큰이 나옵니다. - 봇은 서버에서
getUpdates(롱 폴링)로 메시지를 받습니다. 웹훅용 공개 주소가 없어도 됩니다. /start에 시도 버튼(인라인 키보드)을 보여 주고, 시도를 누르면 시군구 버튼으로 바꿉니다. 고른 지역은 대화방 번호와 함께 저장합니다.- 문자가 오면 수신 지역이 구독 지역과 겹치는 사람에게
sendVideo로 보냅니다. 첫 사람에게 파일을 올린 뒤 응답의file_id를 받아 두면, 다음 사람부터는 파일을 다시 올리지 않고file_id로 보냅니다.
def matches(alert, sub):
for rg in alert['RCPTN_RGN_NM'].split(','):
sido, sgg = canon(rg) # '전라남도' → '전남광주통합특별시' 같은 이름 변경도 여기서 맞춥니다
if sido != sub['sido']: continue
if not sub.get('sgg') or not sgg or sgg == sub['sgg']:
return True # 시도 전체 구독, 또는 시도 전체에 보낸 문자
return False
- 웹 페이지에서
https://t.me/<봇>?start=r1_21같은 딥링크를 누르면 그 지역이 바로 구독되게 했습니다. - 사용자가 봇을 차단하면 전송이 403으로 실패하므로, 이때 구독을 지우도록 코드에 넣었습니다(아직 실제로 발생한 적은 없습니다).

Step 10. 운영 첫날 검수에서 걸린 실수 3가지를 막습니다
게시 후 검수에서 세 가지가 걸렸습니다. 모두 원문에는 맞게 있는데 화면이 다르게 보이게 만든 실수였습니다.
| 사례 | 무엇이 틀렸나 | 고친 방법 |
|---|---|---|
| 계룡 한파 | 첫 화면 "언제 오전 10:25"가 주의보 발효 시각처럼 보임 (원문은 21시 발효, 10:25는 발송 시각) | 칸 이름을 "문자 발송"으로 변경 |
| 옹진 강풍 | 원문은 연평면에만 보낸 문자인데 "옹진군 전체에 발송"으로 표기 | 수신 지역을 그대로 "연평면에 발송", 여러 곳이면 "○○ 외 N곳" |
| 대전 한파 | 원문 문장을 통째로 제목으로 써서 두 줄째에서 잘림 | 16자 이내 원문 구절만 제목으로, 넘치면 글자 축소 |
이후 영상을 만들기 전에 사실 대조를 자동으로 돌립니다. 하나라도 걸리면 그 문자는 올리지 않습니다.
# 실제 코드를 줄인 것입니다 (h12, mm은 발송 시각의 시·분)
def fact_gate(spec, alert):
msg, rgn = alert['MSG_CN'], alert['RCPTN_RGN_NM']; bad = []
if nz(spec['event']) not in nz(msg) and spec['event'] != f"{alert['DST_SE_NM']} 재난문자": bad.append('event')
for act in spec['actions']:
if nz(act) not in nz(msg): bad.append('action') # 행동 문구는 원문에 그대로 있어야 함
if len(rgn.split(',')[0].split()) > 2 and '전체에 발송' in spec['where']: bad.append('scope')
if not spec['when'].endswith(f'{h12}:{mm:02d}'): bad.append('when') # 발송 시각과 같아야 함
return bad
이미 올라간 세 편에는 "[정정]"으로 시작하는 댓글을 API로 달았습니다. 아래는 게시 후 기록용으로 남기는 화면 검사 시트입니다(첫 화면·중간·끝 프레임과 기준 예시).

Step 11. 지역별 웹 페이지와 SEO·GEO, 카카오톡 챗봇을 붙입니다
웹 페이지 251개
disaster.datapopcorn.ai는 원격 Mac의 작은 파이썬 서버를 Cloudflare Tunnel로 공개한 것입니다. 처음에는 cloudflared tunnel route dns가 Authentication error로 실패했습니다. 로컬 cert.pem이 도메인과 다른 Cloudflare 계정 것이었기 때문입니다. 도메인이 있는 계정에서 원격 관리형 터널을 만들고, 그 터널의 토큰으로 cloudflared tunnel run --token-file ...을 실행해 해결했습니다.
- 시도 16개와 시군구별로
/r/경기도/오산시/같은 정적 페이지를 만들어, 사람들이 실제로 검색하는 "오산시 재난문자" 같은 말에 걸리게 했습니다. - 본문(최근 7일 문자 목록, 자주 묻는 질문)을 HTML에 미리 넣어 JS 없이도 읽히게 하고, 새 문자가 오면 몇 초 안에 해당 페이지를 다시 만듭니다.
- 영상에는 Range 요청을 지원해야 사파리에서 재생됩니다. 파이썬 기본
SimpleHTTPRequestHandler는 지원하지 않아 직접 구현했습니다.

SEO와 GEO 설정
| 항목 | 한 일 |
|---|---|
| 메타 | 지역별 제목·설명·canonical, og:image 1200×630 지역별 자동 생성 |
| 구조화 데이터 | WebPage, BreadcrumbList, FAQPage, ItemList, VideoObject JSON-LD |
| 크롤러 | robots.txt에서 GPTBot·ClaudeBot·PerplexityBot·Google-Extended 등 명시 허용, Cloudflare AI 봇 차단 꺼짐 확인 |
| AI 안내 | llms.txt에 서비스 설명, 데이터 주소, 인용 시 주의점 |
| 검색엔진 | 구글 서치콘솔 사이트맵 제출(251페이지 발견), 네이버 서치어드바이저 등록·사이트맵 제출, 페이지가 바뀌면 IndexNow로 빙·네이버에 알림 |

텔레그램 거부감을 줄이는 첫 방문 안내
한국에서는 텔레그램에 대한 인식이 좋지 않아 "텔레그램으로 받기" 버튼만으로는 누르기 어렵습니다. 그래서 첫 방문 때 30초 안내를 띄우고, 사실만 적었습니다. 봇은 전화번호·연락처·다른 대화를 볼 수 없고, 저장하는 것은 대화방 번호와 고른 지역뿐이며, /stop 한 번으로 그만 받을 수 있다는 점입니다. 텔레그램이 내키지 않는 사람에게는 카카오톡 채널을 안내합니다.

카카오톡 채널 챗봇
카카오톡 채널 재난 한 장에 지역 이름을 보내면 그 지역 최근 문자를 답합니다.
- 카카오비즈니스 파트너센터에서 새 비즈니스 만들기 → 기본 채널형으로 채널을 만들고, 대시보드에서 공개·검색 허용·채팅 사용을 켭니다. 검색용 아이디는 한 번 정하면 바꿀 수 없어서
재난한장으로 정했습니다.

- 챗봇 관리자센터에서 채널 챗봇 만들기 → 카카오톡 챗봇을 만들고, 왼쪽 스킬 → 스킬 목록 → 생성에 스킬 서버 주소를 넣습니다. 외부에서 아무나 부르지 못하게 헤더에 비밀 키를 넣고, 서버에서 키가 다르면 403을 돌려줍니다. 같은 화면의 "스킬서버로 전송"을 누르면 "올바른 스킬 서버 응답입니다"가 떠야 합니다.

- 폴백 블록과 웰컴 블록의 파라미터 설정에서 그 스킬을 고르고, 봇 응답을 "스킬데이터"로 바꿔 저장합니다. 그러면 사용자가 무엇을 보내든 스킬 서버가 답합니다. 웰컴 블록은 처음에 꺼져 있어서 켜야 합니다.

- 설정 → 운영 채널 연결에서 채널을 고르고 저장한 뒤, 배포에서 배포합니다. 배포가 끝나면 봇 상태가 "준비"에서 "실행"으로 바뀝니다.


- 오른쪽 위 봇테스트에 "오산시"를 보내 실제 답이 오는지 확인합니다. 파트너센터 챗봇 연결 메뉴에도 봇이 연결된 채널로 보여야 합니다.


- 봇이 답하는 채널이라 사람 상담용 설정은 정리했습니다. 채팅 → 채팅 설정에서 채팅 시간을 매일 00시~00시로 저장하면 "매일 24시간"이 됩니다(종료 시각 목록에 24시가 없어서 00시를 고릅니다). 첫인사 메시지는 "보내지 않기"로 두고, 채널홈 기본 정보에는 웹사이트만 넣었습니다.

스킬 서버는 5초 안에 답해야 해서 외부 호출 없이 로컬 파일만 읽습니다. "중구"처럼 여러 시도에 있는 이름이 오면 "서울 중구 / 인천 중구 / ..." 바로가기 버튼으로 되묻습니다.

카카오톡으로 먼저 알리려면: 비즈니스 심사
카카오톡에서 봇이 먼저 메시지를 보내려면 Event API가 필요하고, 메시지 1건당 15원(VAT 별도)이 과금됩니다. 비즈니스 인증을 받은 채널과 비즈니스 인증을 받은 앱을 연결하고, 월렛을 충전해야 합니다. 사업자등록번호가 없는 "개인 개발자 비즈 앱"은 비즈니스 채널과 연결할 수 없어서, 사업자 정보로 진행했습니다.
- 채널 → 비즈니스 심사 → 채널 심사 신청하기를 누르면 단계별 신청 창이 열립니다.
- 매장 여부("아니오, 매장이 없어요") → 사업자등록번호 입력 → "대표자예요"를 고릅니다. 사업자등록번호 칸은 값을 한 번에 채우는 자동 입력이 들어가지 않아, 숫자를 한 글자씩 입력했습니다(하이픈은 자동으로 붙습니다).
- 대표자 확인은 카카오톡 전자증명서로 합니다. "전자증명서 제출"을 누르면 팝업이 열리고, "카카오톡으로 메시지 받기"를 누르면 대표자 휴대폰 카카오톡으로 정부24 사업자등록증 제출 요청이 옵니다(24시간 유효). 휴대폰에서 제출한 뒤 팝업의 "완료"를 눌러야 다음 단계로 넘어갑니다. 팝업을 닫았다면 "전자증명서 제출"을 다시 누르면 기다리던 화면으로 돌아옵니다.
- 채널 이름("재난 한 장")이 사업자등록증 업체명(데이터팝콘)과 다르면 다른 이유를 적어야 합니다. 사유 칸은 한글·영문·숫자와
( ) & . , - ~ /만 받아서, 작은따옴표나@를 넣으면 오류가 납니다. 같은 사업자가 운영한다는 근거로 웹 주소를 링크 칸에 넣었습니다.

- 사업자등록증 종목에 "강사"가 있어서 학원 인허가 서류를 물었습니다. 이 채널은 해당이 없어 "해당 업종으로 운영할 계획이 없어요"를 고르고, 마지막 동의 후 접수했습니다.

심사는 영업일 기준 3~5일 걸리고, 결과는 관리자센터 알림으로 옵니다. 이 글을 쓰는 시점에는 심사 진행 중이라, 카카오톡은 "물어보면 답하기"(무료)만 열려 있습니다. 통과하면 같은 사업자 정보로 비즈 앱을 만들어 채널과 연결하고, 긴급·위급 문자만 먼저 알리도록 붙일 예정입니다.
운영 첫날 숫자
| 항목 | 값 |
|---|---|
문자 발송(CRT_DT)부터 처리 완료까지 (정상 처리) | 2.1~4.6분 (완도 화재 2.1분, 예천 한파 2.5분, 대전 한파 3.5분, 옹진 강풍 4.0분, 광주 강풍 4.6분) |
| 위 지표의 끝 지점 | 인스타 게시 후 게시 시각 조회와 첫 댓글 확인까지 마치고 데몬이 기록한 시각. 인스타 게시 시각 기준으로는 약 0.1분 짧음 (완도 2.0분, 예천 2.4분, 대전 3.4분) |
| 예외 | Gemini 한도에 막혔던 6편은 다시 처리해 8.6분~2시간 뒤 게시 |
| 영상 1편 제작 | 약 20~50초 (경계 캐시가 있으면 20초대) |
| 인스타 컨테이너 처리 | 약 27초 |
| 음성 비용 | 영상 1편에 약 105 Typecast 크레딧 |
| 웹 페이지 | 251개, 다시 만드는 데 1~2초 |
자주 막히는 지점
| 증상 | 원인 | 해결 |
|---|---|---|
| 카카오 심사 사유 입력 오류 | 사유 칸이 작은따옴표·@ 같은 특수문자를 받지 않음 | 한글·영문·숫자와 ( ) & . , - ~ /만 사용 |
| 카카오 전자증명 "완료"가 안 넘어감 | 휴대폰 카카오톡에서 제출 전, 또는 팝업을 닫음 | 휴대폰에서 제출 후 "전자증명서 제출"을 다시 눌러 팝업의 "완료" |
UNREGISTERED IP ERROR | 신청서의 IP와 호출한 컴퓨터 IP가 다름 | 마이페이지에서 유저 IP 수정, 상시 켜 두는 컴퓨터 IP로 |
HTTP 429 RESOURCE_EXHAUSTED | Gemini 무료 요금제 하루 20회 초과 | 외부 AI 없이 규칙으로 추출하거나, 실패 시 규칙으로 넘어가는 대비책 |
| 인스타 컨테이너가 안 만들어짐 | video_url이 외부에서 열리지 않음(터널 DNS 전파 전) | 터널을 상시 띄우고 예열, URL이 200인지 먼저 확인 |
| 같은 문자가 두 번 게시될 위험 | media_publish 뒤 응답 유실 후 재시도 | 게시 호출 이후 실패는 재시도하지 않음 |
cloudflared tunnel route dns 인증 오류 | cert.pem이 다른 Cloudflare 계정 것 | 도메인 계정에서 원격 관리형 터널을 만들고 토큰으로 실행 |
| 새 하위 도메인이 내 컴퓨터에서만 안 열림 | 레코드를 만들기 전에 조회해 '없음'이 캐시됨 | 공용 DNS로 확인, 30분 안팎이면 풀림 |
| 감시 프로세스가 사라짐 | 배포 중 bootout 뒤 재등록 실패 | 멈출 때는 PAUSE 파일, 재시작은 kickstart -k만 사용 |
| 첫 화면 사실 오류 | 발송 시각·수신 범위·제목을 화면용으로 바꿔 씀 | 원문 대조 게이트를 통과해야만 영상 제작 |
재난문자 데이터 자체를 분석한 글은 폭염 재난문자, 정말 더워서 늘었을까?에 있습니다.
출처: 행정안전부 긴급재난문자(재난안전데이터공유플랫폼). 지도 © OpenStreetMap contributors. 일러스트 いらすとや. 영상과 웹 페이지의 문자는 발송 시점 원문이며, 실제 상황에서는 지자체·관계기관 안내를 따르세요.