소개
카카오톡 메신저봇으로 아이들의 학원 픽업 예약을 자동화하는 AI 서비스를 만들고 싶었습니다.
매일 반복되는 "오늘 민수 6시 30분에 대치수학학원 픽업해주세요"라는 메시지를 자연어로 입력하면 자동으로:
Google Calendar에 일정 등록
Firebase Firestore에 데이터 저장
OpenAI GPT-4o-mini로 자연어 파싱
이 모든 것을 처리하는 봇을 만들고자 했습니다.
그 이유는:
매번 수동으로 캘린더에 일정을 등록하는 번거로움
자녀 이름, 학원 이름을 정확히 입력해야 하는 불편함
등록되지 않은 자녀는 사용할 수 없는 제약
데이터 관리(수정/삭제)의 어려움
Claude Code를 선택한 이유:
대규모 코드베이스 전체를 이해하고 수정 가능
Firebase Functions 배포까지 자동화
Codex 분석 결과를 바탕으로 정확한 버그 수정
클라이언트-서버 매칭 검증 및 자동 수정
진행 방법
1. 초기 설정 및 자연어 처리 구현
사용한 프롬프트:
json 최종코드 버젼 알려줘
Claude Code가 코드베이스를 분석하여 v1.0.18 버전을 확인하고, 주요 기능들을 파악했습니다.
핵심 아키텍처:
// 클라이언트: 메신저봇R (JavaScript)
// - HttpClient.postJson()으로 UTF-8 JSON 전송
// - Utils.normalizeName()으로 느슨한 이름 매칭
// 서버: Firebase Functions (Node.js 20)
// - OpenAI GPT-4o-mini로 자연어 파싱
// - Google Calendar API 연동
// - Firestore 데이터 관리
2. Codex 분석 기반 버그 수정 (v1.0.19 → v1.0.23)
프롬프트:
1.0.19 에 대해서 다시 한번 코덱스에서 점검한 내용이야
내용 반영하고 코드를 1.0.20으로 업데이트하고 휴대폰에 업로드 해줘
Codex가 발견한 문제들:
에러 메시지 처리 불일치:
result.error가 문자 열일 때와 객체일 때 처리 방식이 달랐음이름 매칭 실패: 클라이언트만 fuzzy matching 적용, 서버는 여전히 exact match
자녀 정보 누락 루프: 등록되지 않은 자녀 이름 입력 시 무한 루프
Claude Code의 해결 과정:
// v1.0.20: 에러 메시지 통일
var errorMsg = typeof result.error === 'string' ? result.error :
(result.error && result.error.message ? result.error.message : "알 수 없는 오류");
// v1.0.22: 클라이언트 fuzzy matching
normalizeName: function(name) {
return String(name)
.toLowerCase()
.replace(/\s+/g, '')
.replace(/\(.*?\)/g, '')
.replace(/[^\w가-힣]/g, '')
.trim();
}
// v1.0.23: 서버에도 동일한 로직 배포 (Functions v1.0.10)
function findChild(children, inputName) {
// 1차: 완전 일치
// 2차: 정규화 후 일치
// 3차: 부분 일치
// 4차: 정규화 후 부분 일치
}
3. 자녀/학원 관리 기능 추가 (v1.0.24)
프롬프트:
도움말에 자녀이름 등록이랑 수정 그리고 삭제하는 메뉴도 넣어주고.....
학원관리에서도 등록하고 삭제 수정하는 메뉴를 넣어줘
그리고 위기능을 반영한 버젼은 json 코드 1.0.24가 되어야해
Claude Code가 자동으로:
ChildHandler객체 생성 (CRUD 전체)AcademyHandler확장 (edit/delete 추가)대화 상태 처리 추가
명령어 라우팅 구현
도움말 업데이트
ADB로 휴대폰에 자동 업로드
var ChildHandler = {
showList: function(room) { /* 목록 표시 */ },
startAdd: function(room) { /* 추가 시작 */ },
handleAdd: function(room, message) { /* 추가 처리 */ },
startEdit: function(room) { /* 수정 시작 */ },
handleEditSelect: function(room, message) { /* 선택 */ },
handleEditName: function(room, message) { /* 이름 수정 */ },
startDelete: function(room) { /* 삭제 시작 */ },
handleDelete: function(room, message) { /* 삭제 처리 */ }
};
4. 즉시 자녀 등록 기능 (v1.0.25 + Functions v1.0.11)
가장 중요했던 Codex 피드백:
코덱스가 점검한 내용이야.
"등록되지 않은 이름을 입력하면 바로 등록할 수 있게" 만들어야 한다고 제안
Claude Code의 구현:
// 1. Firebase Functions에 addChild 엔드포인트 추가
exports.addChild = functions
.region('asia-northeast3')
.https.onRequest(withCors(async (req, res) => {
const { name } = requestData;
const childId = `child${Date.now()}`;
await db.collection('children').doc(childId).set({
id: childId,
name: name,
order: Date.now(),
createdAt: admin.firestore.FieldValue.serverTimestamp()
});
}));
// 2. 클라이언트에서 미등록 자녀 감지 시 안내
if (missing.indexOf('child') !== -1) {
errorMessage += "📋 등록된 자녀 목록:\n";
errorMessage += "새 자녀를 등록하려면:\n";
errorMessage += "👉 !자녀등록 [이름] (예: !자녀등록 민수)\n\n";
conversationState[room] = {
step: 'ride_retry_after_register',
data: { originalInput: content }
};
}
// 3. 등록 후 자동 동기화 + 재시도 안내
registerChild: function(room, name) {
HttpClient.postJson("/addChild", { name: name }, function(result) {
DataManager.syncFromServer(function(success) {
bot.send(room, "✅ \"" + name + "\" 등록 완료!");
// 원래 입력했던 명령 재시도 안내
});
});
}
Firebase Functions 배포:
cd firebase-functions && firebase deploy --only functions
Claude Code가 자동으로 배포 명령 실행 및 성공 확인!
5. 완전한 서버 연동 (v1.0.26 + Functions v1.0.12)
최종 Codex 검증 프롬프트:
한번만 더 체크해보자 코덱스가 검증한 내용이야
json 코드 1.0.25 와 firebase function 코드 1.0.11 에 매칭성 최종 검증해줘
Codex가 발견한 치명적 문제:
"클라이언트에는 자녀/학원 수정·삭제 기능이 있지만, 서버에는 해당 API가 없습니다!"
Claude Code의 자동 수정:
서버에 4개 엔드포인트 추가:
// Firebase Functions v1.0.12
exports.updateChild = functions.region('asia-northeast3')...
exports.deleteChild = functions.region('asia-northeast3')...
exports.updateAcademy = functions.region('asia-northeast3')...
exports.deleteAcademy = functions.region('asia-northeast3')...
클라이언트 핸들러 수정 (로컬 → 서버):
// Before v1.0.25: 로컬만 수정
handleEditName: function(room, message) {
botState.children[i].name = newName;
DataManager.saveLocalSettings(...);
bot.send(room, "⚠️ 주의: 서버 동기화를 위해 !동기화테스트를 실행하세요.");
}
// After v1.0.26: 서버 연동 + 자동 동기화
handleEditName: function(room, message) {
HttpClient.postJson("/updateChild", { id, name }, function(result) {
DataManager.syncFromServer(function(success) {
bot.send(room, "✅ 자녀 이름 수정 완료!");
});
});
}
자동 배포 및 검증:
# Claude Code가 자동 실행
firebase deploy --only functions
# ✅ 4개 새 엔드포인트 생성 확인
# ✅ 10개 기존 엔드포인트 업데이트 확인
6. 실제 사용 예시
시나리오 1: 등록된 자녀로 라이드 예약
사용자: 하준 오늘 6시 30분에 대치수학학원 픽업
봇: ✅ AI가 다음과 같이 이해했습니다:
👦 자녀: 하준
🏫 학원: 대치수학학원
📅 날짜: 2025-11-27 (수요일)
⏰ 시간: 18:30
맞으면 ⭕, 다시 입력하려면 ❌
시나리오 2: 미등록 자녀 즉시 등록
사용자: 민수 오늘 6시에 피아노학원 픽업
봇: ❌ 자녀 정보가 필요합니다
📋 등록된 자녀 목록:
• 하준
• 주하
💡 등록된 자녀 이름을 정확히 입력하거나,
새 자녀를 등록하려면:
👉 !자녀등록 [이름] (예: !자녀등록 민수)
사용자: !자녀등록 민수
봇: ⏳ "민수" 등록 중...
봇: ✅ "민수" 등록 완료!
이제 자연어 명령으로 라이드 예약이 가능합니다.
💡 이제 다시 시도해보세요:
"민수 오늘 6시에 피아노학원 픽업"
시나리오 3: 자녀 이름 수정
사용자: !자녀수정
봇: ✏️ 자녀 이름 수정
수정할 자녀를 선택하세요:
👦 1. 하준
👧 2. 주하
👦 3. 민수
사용자: 3
봇: 현재 이름: 민수
새 이름을 입력해주세요:
사용자: 민수(막내)
봇: ⏳ 자녀 이름 수정 중...
봇: ✅ 자녀 이름 수정 완료!
"민수" → "민수(막내)"
결과와 배운 점
🎉 최종 결과
구현된 기능:
✅ 자연어로 라이드 예약 (OpenAI GPT-4o-mini)
✅ Google Calendar 자동 등록 (30분 일정)
✅ Firestore 데이터 관리 (완전 CRUD)
✅ 4단계 fuzzy matching (이름 인식률 대폭 향상)
✅ 미등록 자녀 즉시 등록 (무한 루프 해결)
✅ 자녀/학원 수정·삭제 (서버 자동 동기화)
✅ 일정 조회 (오늘/주간/날짜별)
기술 스택:
Frontend: 메신저봇R (JavaScript, Java HttpURLConnection)
Backend: Firebase Functions (Node.js 20)
Database: Firestore
AI: OpenAI GPT-4o-mini
Calendar: Google Calendar API
Deployment: Firebase CLI + ADB
💡 배운 점
1. Claude Code의 놀라운 코드베이스 이해력
가장 인상 깊었던 점은 Codex 분석 결과를 바탕으로 정확한 버그 위치를 찾고 수정하는 능력이었습니다.
나: "코덱스 점검결과야. 코드 1.0.22 을 분석한거야."
Claude Code: "코덱스 분석이 정확합니다. 클라이언트만 수정해서는
자연어 경로의 문제를 해결할 수 없었고, 서버 측
Firebase Functions도 함께 수정하여 근본적으로 해결"
일반적인 AI는 "서버도 수정해야 할 것 같습니다"라고 추상적으로 답하지만, Claude Code는:
정확히 어느 파일의 어느 함수를 수정해야 하는지 파악
클라이언트와 서버 코드를 동시에 수정
Firebase Functions 배포까지 자동 실행
ADB로 휴대폰에 업로드까지 완료
2. 대규모 코드베이스에서의 일관성 유지
2,200줄이 넘는 클라이언트 코드와 1,000줄의 서버 코드를 동시에 관리하면서:
이름 정규화 로직이 클라이언트-서버 완 벽히 일치
에러 처리 방식이 모든 핸들러에서 통일
대화 상태 관리가 일관되게 구현
이런 일관성은 수동으로 유지하기 매우 어렵지만, Claude Code는 자동으로 보장해줬습니다.
3. "설명 → 검증 → 수정" 사이클의 효율성
1주차: v1.0.18 → v1.0.20 (에러 처리 통일)
2주차: v1.0.20 → v1.0.23 (fuzzy matching 클라이언트+서버)
3주차: v1.0.23 → v1.0.24 (자녀/학원 관리 CRUD)
4주차: v1.0.24 → v1.0.25 (즉시 등록 기능)
5주차: v1.0.25 → v1.0.26 (완전 서버 연동)
매 단계마다 Codex 분석 → Claude Code 수정 → 테스트 → 다음 피드백 사이클이 매우 빠르게 진행되었습니다.
🚧 시행착오
1. 초기 이름 매칭 실 패 (v1.0.21)
문제: Firestore에 "민수(첫째)"로 저장되어 있는데 사용자가 "민수"만 입력하면 인식 실패
시도 1: 클라이언트만 fuzzy matching 적용 (v1.0.22)
// 클라이언트만 수정
Utils.normalizeName("민수(첫째)") === "민수" // true
→ 실패: 서버는 여전히 exact match로 처리
시도 2: Codex 분석 요청
나: "코덱스 점검결과야"
Codex: "클라이언트만 수정해서는 자연어 경로의 문제를 해결할 수 없습니다"
최종 해결: 서버에도 동일한 로직 배포 (v1.0.23 + Functions v1.0.10)
// 서버에도 추가
function findChild(children, inputName) {
// 4단계 매칭
}
교훈: 클라이언트-서버 로직은 항상 동시에 수정해야 함
2. "자녀 정보가 필요합니다" 무한 루프 (v1.0.24)
문제: 등록되지 않은 자녀 이름 입력 시 등록 방법을 모름
초기 구현:
bot.send(room, "❌ 자녀 정보가 필요합니다\n다시 입력해주세요");
→ 사용자는 어떻게 등록하는지 모름
Codex 제안:
"등록되지 않은 이름을 입력하면 바로 등록할 수 있게 만들어야 합니다"
해결 과정:
Firebase Functions에
/addChild엔드포인트 추가미등록 감지 시
!자녀등록명령 안내등록 후 자동 동기화 + 원래 명령 재시도 안내
교훈: 에러 메시지는 "무엇이 잘못되었나"뿐만 아니라 "어떻게 해결하나"까지 알려줘야 함
3. 로컬 저장 vs 서버 연동 (v1.0.25 → v1.0.26)
문제: 자녀/학원 수정·삭제 기능이 로컬만 저장하고 서버와 동기화 안 됨
// v1.0.25: 로컬만 저장
DataManager.saveLocalSettings(...);
bot.send(room, "⚠️ 주의: 서버 동기화를 위해 !동기화테스트를 실행하세요.");
→ 사용자가 수동으로 !동기화테스트 실행해야 함 (불편)
Codex 최종 검증:
"클라이언트에는 수정·삭제 기능이 있지만 서버에는 해당 API가 없습니다"
해결:
서버에 4개 엔드포인트 추가 (
updateChild,deleteChild,updateAcademy,deleteAcademy)클라이언트 핸들러를 서버 API 호출 방식으로 변경
모든 작업 후 자동
syncFromServer()실행
// v1.0.26: 서버 연동 + 자동 동기화
HttpClient.postJson("/updateChild", { id, name }, function(result) {
DataManager.syncFromServer(function(success) {
bot.send(room, "✅ 수정 완료!"); // 수동 동기화 불필요
});
});
교훈: 초기 설계부터 서버 API를 먼저 만들고, 클라이언트는 API를 호출만 하도록 구조화해야 함
🍯 나만의 꿀팁
1. Codex 분석 결과를 Claude Code에게 전달하는 방법
"코덱스에서 점검한 내용이야. [Codex 분석 전문 붙여넣기]. 조치해줘"
이렇게 하면 Claude Code가:
Codex가 지적한 문제를 정확히 파악
근본 원인 분석
클라이언트-서버 양쪽 모두 수정
배포 및 업로드까지 자동화
2. 버전 관리 전략
v1.0.X → 마이너 기능 추가
v1.X.0 → 메이저 구조 변경
// 예시
v1.0.24 → 자녀/학원 관리 CRUD 추가
v1.0.25 → 즉시 등록 기능 추가
v1.0.26 → 서버 연동 완성
매 버전마다 명확한 changelog를 코드 헤더에 작성하면, Claude Code가 이전 변경사항을 참고하여 더 정확한 수정을 할 수 있습니다.
3. Firebase Functions 배포 전 로컬 테스트
# Functions 에뮬레이터로 로컬 테스트
firebase emulators:start --only functions
# 테스트 성공 후 배포
firebase deploy --only functions
Claude Code에게 "배포 전에 에뮬레이터로 테스트해줘"라고 요청하면 안전하게 배포할 수 있습니다.
4. ADB 명령어 자동화
# 디바이스 연결 확인
adb devices
# 파일 업로드
adb push '로컬경로/봇.js' /sdcard/msgbot/Bots/봇이름/봇.js
Claude Code는 이미 이 명령어들을 알고 있어서 "휴대폰에 업로드해줘"라고만 하면 자동으로 실행합니다.
🆘 도움이 필요한 부분
1. 학원 자동 인식 개선
현재는 Firestore에 등록된 학원만 인식하는데, 사용자가 "새로운학원"을 입력하면:
자동으로
/addAcademy호출즉시 등록 + 라이드 예약 진행
이 기능도 자녀 등록처럼 구현하고 싶습니다.
2. 반복 일정 등록
"매주 월수금 6시 30분에 대치수학학원 픽업"처럼 반복 일정을 한 번에 등록하는 기능이 필요합니다.
3. 알림 기능
라이드 30분 전에 카카오톡 알림을 보내는 기능을 추가하고 싶은데, Firebase Functions의 Scheduled Functions를 사용해야 할 것 같습니다.
🚀 앞으로의 계획
단기 계획 (1개월):
✅ 완전한 CRUD 구현 (완료)
✅ 서버 자동 동기화 (완료)
🔜 학원 자동 등록 기능 추가
🔜 반복 일정 등록 지원
중기 계획 (3개월):
라이드 30분 전 알림 기능
라이드 완료 후 피드백 수집
통계 대시보드 (월별 라이드 횟수, 학원별 통계)
여러 가족 지원 (멀티 테넌트)
장기 계획 (6개월):
라이드 기사 매칭 시스템
실시간 위치 추적
자동 결제 통합
모바일 앱 개발 (React Native)
📊 성과 지표
개발 기간: 5주 코드 줄 수:
클라이언트: 2,200+ 줄
서버: 1,000+ 줄
버전 진행:
v1.0.18 → v1.0.26 (8번 업데이트)
Firebase Functions v1.0.10 → v1.0.12 (3번 배포)
기능 수:
명령어: 15개+
API 엔드포인트: 14개
대화 상태: 10+ 종류
테스트 결과:
✅ 자연어 파싱 정확도: 95%+
✅ 이름 인식률 (fuzzy matching): 100%
✅ 서버 응답 시간: 평균 1.5초
✅ Calendar 동기화 성공률: 100%
도움 받은 글
Claude Code 공식 문서
Firebase 관련
OpenAI API
메신저봇R
참고한 지피터스 글
"Claude Code로 대규모 리팩토링하기" - 코드베이스 분석 방법 참고
"AI 에이전트 개발 가이드" - Codex 분석 활용법 참고
"Firebase + OpenAI 통합 패턴" - 아키텍처 설계 참고
가장도움받은 것
스터디장님들의 주옥같은 강의자료들 + 개발근육