[나의 앱개발기] 비개발자가 AI로 노동조합 알림톡 자동화 시스템을 만든 이야기 (Google Apps Script + 뿌리오 API)
비개발자가 AI로 노동조합 알림톡 자동화 시스템을 만든 이야기
조합원이 가입 신청서를 내면, 누군가가 그 명단을 확인하고, 뿌리오에 접속하고, 전화번호를 복사하고, 템플릿을 골라서, 보내기 버튼을 누릅니다. 경조사 접수가 들어와도, 탈퇴 신청이 들어와도, 법률상담 요청이 들어와도 — 매번 같은 동작의 반복이거든요.
저는 코딩을 전혀 모르는 노동조합 임원입니다. 그런데 이 반복 업무가 너무 비효율적이라는 건 확실히 알았죠. "이걸 자동화할 수 없을까?"라는 생각이 시작이었고, Claude AI에게 물어보는 것이 첫 걸음이었습니다.
결과적으로 4분할 대시보드 + 로그인 + 발송기록 공유 + 일괄발송 + SMS 자유발송까지 갖춘 시스템을 만들었는데, 그 과정은 정말 우당탕탕 그 자체였습니다. 이건 그 좌충우돌 개발기입니다.
1. 왜 알림톡 자동화가 필요했나
2. 기술 스택 선택 — 왜 Google Apps Script였나
3. 4분할 대시보드 만들기 — 첫 번째 난관
4. 발송기록 공유 문제 — localStorage의 함정
5. 로그인과 일괄발송 — 점점 욕심이 커지다
6. SMS 자유발송 웹앱 — 별도 프로젝트로 독립
7. 삽질 모음 — 실제로 겪은 에러들
8. 마무리 정리
1. 왜 알림톡 자동화가 필요했나
* 2,000명 조합원, 4가지 업무, 매번 수동.
저희 노동조합에는 약 2천명 넘는 조합원이 있습니다. 신규 가입, 탈퇴, 경조사, 법률상담 — 이 네 가지 카테고리에서 매일 접수가 들어오고, 각각에 맞는 카카오 알림톡을 보내야 하거든요.
기존 프로세스는 이랬습니다. 구글 설문지로 접수가 들어오면 스프레드시트에 기록되고, 담당자가 그걸 확인한 다음 뿌리오 사이트에 직접 접속해서 하나하나 보내는 거죠. 하루에 몇 건 안 되면 괜찮은데, 가입 신청이 한꺼번에 10건, 20건 몰리는 날이면 정말 고역이었습니다.
"스프레드시트에 이미 이름이랑 전화번호가 다 있는데, 왜 이걸 또 복사해서 붙여넣어야 하지?" — 이 단순한 의문이 모든 것의 시작이었습니다.
2. 기술 스택 선택 — 왜 Google Apps Script였나
비개발자 입장에서 가장 중요한 건 "돈 안 들고, 복잡하지 않은 것"이었습니다. Next.js니 Vercel이니 하는 것도 해봤지만, 이 프로젝트에는 Google Apps Script(GAS)가 딱이었죠.
| 항목 | Google Apps Script | Next.js + Vercel |
|---|---|---|
| 서버 비용 | 무료 | 무료~유료 |
| 스프레드시트 연동 | 네이티브 지원 | API 별도 설정 |
| 배포 | 클릭 한 번 | Git Push |
| 웹앱 가능 여부 | 가능 (HTML Service) | 가능 |
| 학습 난이도 | 낮음 | 중~상 |
이미 조합원 명부, 경조사 접수, 법률상담 접수 등이 전부 구글 스프레드시트에 있었기 때문에, GAS를 쓰면 별도의 데이터베이스 설정 없이 바로 데이터를 읽을 수 있었거든요. 뿌리오 API도 HTTP 호출만 하면 되니까 GAS에서 충분했습니다.
3. 4분할 대시보드 만들기 — 첫 번째 난관
* 한 화면에 네 개의 카테고리를 동시에.
처음 구상은 단순했습니다. 신규가입, 탈퇴, 경조사, 법률상담 — 이 네 카테고리를 2×2 그리드로 한 화면에 배치하고, 각 카드에서 바로 알림톡을 보내는 거죠.
Claude에게 "4분할 대시보드를 만들어줘"라고 하니까 뚝딱 만들어주긴 했는데, 문제는 거기서부터였습니다.
1. 신규가입에는 버튼이 두 개 필요했다.
2. 발송 버튼의 칸 분리.
처음에는 한 칸에 두 버튼을 옆으로 나란히 놓았는데, 완료 표시가 되면 뱃지와 재발송 버튼이 같이 섞여서 도대체 뭐가 뭔지 모르겠더라고요. 결국 발송 열을 아예 두 개의 td로 쪼개고, 세로 구분선을 넣어서 시각적으로 분리했습니다. 이 과정만 세 번을 갈아엎었이죠.
3. 모바일 대응.
PC에서는 예뻤는데 모바일에서 열어보니 난리가 났습니다. 뱃지 크기를 줄이고, 패딩을 줄이고, 폰트 사이즈를 줄이고... 640px 이하 미디어쿼리를 세밀하게 잡는 데만 꽤 시간이 걸렸습니다.
4. 발송기록 공유 문제 — localStorage의 함정
* "나는 보냈는데, 옆 사람은 안 보낸 걸로 보여?"
초기 버전에서는 발송 완료 여부를 브라우저 localStorage에 저장했습니다. 간편하니까요. 그런데 치명적인 문제가 있었죠.
제가 알림톡을 보내고 "완료" 표시를 봤는데, 같은 링크로 접속한 다른 임원의 화면에서는 여전히 "미발송"으로 떠있는 겁니다. localStorage는 각 브라우저에만 저장되니까 당연한 거였죠.
해결책은 별도의 "발송기록 전용" 스프레드시트를 하나 만드는 것이었습니다.
카테고리 | 행번호 | 이름 | 전화번호 | 발송유형 | 발송일시 | 발송자
모든 발송 이력이 한 곳에, 모든 사용자가 실시간 공유
이렇게 하니까 A가 보낸 알림톡이 B의 화면에서도 "완료"로 뜨고, 누가 언제 보냈는지까지 기록이 남더라고요. 그리고 2월 21일 이전 기존 데이터는 자동으로 완료 처리하되, 이후 신규 데이터만 발송기록 시트에서 확인하도록 프론트엔드에서 날짜 분기를 넣었습니다.
근데 이것도 한 번에 안 됐습니다. 처음에는 발송유형이 한글이 아니라 "default"로 기록되는 바람에, 프론트에서 읽을 때 매칭이 안 되는 버그가 있었거든요. 프론트에서 보내는 sendType 파라미터와 서버에서 기록하는 로직 사이의 불일치 — 이런 사소한 것 때문에 반나절을 날렸습니다.
5. 로그인과 일괄발송 — 점점 욕심이 커지다
* "이왕 만드는 거, 제대로 만들자."
1. 로그인 시스템.
아무나 접근하면 안 되니까 간단한 로그인을 만들었습니다. 별도의 DB나 OAuth 같은 거창한 건 필요 없었고, 5명의 이름 + 생년월일 6자리를 Code.gs에 하드코딩해놓은 거죠. 우아하진 않지만 확실히 작동합니다.
로그인하면 발송기록의 G열에 "발송자"가 기록되니까, 누가 보냈는지 추적도 가능해졌습니다. 수동 완료처리를 하면 "정원희(수동)"처럼 표시되어 실제 발송과 구분이 되고요.
2. 수동 완료처리 버튼.
"이미 전화로 안내한 사람인데, 알림톡까지 또 보내야 하나?" — 이런 경우가 꽤 있었습니다. 그래서 각 발송 버튼 옆에 작은 "완료" 버튼을 추가했어요. 누르면 뿌리오로 발송하지 않고, 발송기록에만 기록하는 방식이죠.
3. 일괄발송 체크박스.
한 명 한 명 클릭하는 것도 귀찮아지더라고요. 체크박스로 여러 명 선택한 다음 한 번에 보내는 기능을 넣었습니다. 전체선택 체크박스까지. 그런데 신규가입과 경조사는 발송유형이 두 가지씩이니까, 각 유형별로 체크박스 열을 따로 만들어야 했습니다. 일괄발송 바에는 "일괄발송"과 "일괄완료" 두 버튼을 넣어서 선택의 여지를 줬고요.
제일 짜증났던 버그는 발송 후 자동 리프레시될 때 스크롤이 맨 위로 올라가는 현상이었습니다. 리스트를 한참 스크롤해서 내려가서 발송 버튼을 눌렀는데, 화면이 확 위로 올라가버리면 다시 내려가야 하잖아요. 스크롤 위치를 저장했다가 복원하는 코드를 넣어서 해결했습니다.
6. SMS 자유발송 웹앱 — 별도 프로젝트로 독립
* 알림톡 템플릿 외에 자유 메시지도 보내고 싶다.
"당첨 안내 같은 건 등록된 템플릿이 없는데, 그냥 문자로 보낼 수 없나?" — 이 요구사항 때문에 별도 웹앱을 만들게 됐습니다.
두 개의 탭으로 구성했어요. 📱 알림톡 탭은 등록된 뿌리오 템플릿을 선택해서 보내는 것이고, 💬 SMS/LMS 탭은 자유롭게 내용을 작성해서 보내는 것이죠.
여기서도 삽질이 있었습니다. 뿌리오 API로 템플릿 목록을 자동 조회하려고 했는데, 404 에러가 나더라고요. API 엔드포인트가 문서와 다른 건지, 접근 권한 문제인지 확인이 안 돼서 결국 템플릿 7개를 직접 하드코딩하는 방식으로 우회했습니다. 우아하진 않지만 작동합니다. (이 프로젝트에서 "우아하진 않지만 작동한다"는 말을 참 많이 했네요.)
SMS 발송에서는 [*이름*]을 각 수신자의 이름으로 자동 치환하는 기능도 넣었습니다. "안녕하세요, [*이름*]님" 이라고 쓰면 홍길동에게는 "안녕하세요, 홍길동님"으로 가는 거죠. 바이트 수도 실시간으로 계산해서 90바이트 이하면 SMS, 초과하면 LMS로 자동 판별합니다.
7. 삽질 모음 — 실제로 겪은 에러들
* 이게 진짜 개발 현실.
| 에러 | 원인 | 해결 |
|---|---|---|
| No HTML file named index | 파일명을 'Index.html'(대문자)로 생성 | doGet에서 'Index'로 호출하거나 소문자로 재생성 |
| 'from' must be phone number format | 발신번호 앞에 '00' 붙음 | 뿌리오 등록 번호와 정확히 일치하도록 수정 |
| 발송유형 'default' 매칭 실패 | 프론트에서 sendType을 null로 변환 | 원래 sendType을 별도 파라미터로 전달 |
| 기존 데이터 전부 미발송 표시 | 날짜 비교 로직 반대 | cutoff 날짜 기준 분기 수정 |
| 템플릿 조회 404 | 뿌리오 API 엔드포인트 불일치 | 템플릿 하드코딩으로 우회 |
| 알림톡 변수 비어있음 | target에 name 필드 누락 | target 객체에 name 추가 |
| SMS 성공인데 문자 안 옴 | 발신번호 미등록 | 뿌리오에 발신번호 사전 등록 |
솔직히 이 표에 있는 에러 하나하나가 최소 30분에서 2시간씩은 잡아먹었습니다. 특히 "SMS 발송 성공(응답코드 200)인데 실제로 문자가 안 온다"는 상황이 가장 답답했어요. 뿌리오가 200을 반환해놓고 실제로는 통신사에서 차단한 거였거든요. 발신번호를 뿌리오에 사전 등록하지 않으면 이렇게 됩니다.
그리고 Apps Script에서 파일명 대소문자 문제. 'index'와 'Index'가 다른 파일이라는 걸 몰랐다면 한참을 헤맸을 겁니다. HTML 파일을 추가할 때 자동으로 '.html'이 붙으니까, 이름 입력 시 'index.html'이라고 쓰면 실제로는 'index.html.html'이 되는 것도 처음에 한 번 당하더라고요.
8. 마무리 정리
* 마무리 정리.
결과적으로 만들어진 건 이렇습니다.
📊 4분할 알림톡 대시보드 (신규가입·탈퇴·경조사·법률상담)
🔐 5명 로그인 + 발송자 추적
📝 스프레드시트 기반 발송기록 공유
☑️ 체크박스 일괄발송 + 수동완료처리
✉️ SMS/LMS 자유발송 별도 웹앱
서버 비용 0원. 사용 기술은 Google Apps Script + HTML + 뿌리오 API. 코딩 경험 없는 사람이 AI의 도움으로 만든 결과물치고는 꽤 쓸만하다고 자부합니다.
물론 완벽하진 않습니다. 템플릿 목록이 하드코딩이라 새 템플릿이 추가되면 Code.gs를 직접 수정해야 하고, 로그인도 sessionStorage라 탭을 닫으면 다시 해야 하고, UI도 모바일에서 아직 좀 아쉬운 부분이 있죠.
그래도 이전에는 한 건 보내는 데 5분 걸리던 게, 지금은 체크박스 몇 개 클릭하고 버튼 한 번이면 끝나니까요. 비개발자도 AI와 함께라면 실무에 바로 쓸 수 있는 자동화 도구를 만들 수 있다 — 이건 직접 경험한 사실입니다.
다음에는 신규 접수가 들어오면 자동으로 알림톡을 보내는 트리거 기능을 붙여볼 생각입니다. 이 우당탕탕 여정은 아직 끝나지 않았거든요.