공공데이터 4개 포털, 3번 막히고, KRIC은 포기했다 — 그렇게 교통약자 앱이 완성됐다
한 줄 요약
항목
내용
🎯 결과물
전국 운수시설 승강기 운행상태를 지도 위 🟢/🔴로 보여주는 시민용 PWA 앱
🧑💻 제작자
비개발자 + 30년 승강기 안전 전문가
🛠 도구
Claude (바이브 코딩) + 공공데이터포털 + 서울 열린데이터광장 + 카카오 API
⏱ 소요 시간
약 2주 (9단계 진행)
📍 시작 계기
사내 AI혁신팀 교통약자 불편해소 과제
이 글을 읽어야 할 사람
공공데이터를 실제로 써보고 싶은 Gpters 멤버
개발 지식 없이 실용 도구를 만들어보고 싶은 분
막혔을 때 포기하는 게 아니라 방향을 바꾸는 법을 고민하는 분
Before — 이 앱이 없을 때의 세상
휠체어를 쓰는 분이 외출을 준비한다. 지하철역까지 가려면 엘리베이터가 꼭 필요하다. 그런데 도착해보니 고장이다.
이 상황은 2026년 지금도 매일 벌어진다. 한국승강기안전공단(KOELSA) 내부에는 승강기 점검 기록이 있고, 서울교통공사는 실시간 가동상태 API를 공개하고 있다. 그 데이터는 존재한다. 다만 시민이 볼 수 있는 화면이 없을 뿐이었다.
AI혁신팀 과제가 내려왔다. 교통약자 대상 불편해소 방안. 나는 30년간 승강기를 봐왔다. 코드는 못 쓰지만, 무엇이 필요한지는 안다. Claude를 꺼냈다.
도구
도구
역할
Claude (바이브 코딩)
전체 코드 작성·수정·디버깅
Leaflet.js + OpenStreetMap
지도 (네이버 지도 인증 실패 후 우회)
서울 열린데이터광장 API
실시간 가동상태 (USE_YN 필드)
카카오 지오코딩 API
역명 → 위도·경도 변환
Python 프록시 서버
공공API CORS 우회 (로컬 실행)
Vercel Serverless
클라우드 배포, 키 서버 보관
작업 과정 — 3번 막히고 1번 돌아간 이야기
에피소드 1 : 지도 라이브러리부터 막혔다
계획은 단순했다. 네이버 지도 위에 마커를 찍으면 된다. Application 설정도 정상, 도메인도 등록했다. 그런데 인증이 계속 실패했다.
Claude에게 물었다. "Leaflet.js와 OpenStreetMap으로 대체합시다. 나중에 지도만 교체하면 되는 구조로 만들겠습니다."
여기서 첫 번째 원칙을 배웠다. 지도는 부품이다. 본질은 데이터와 UX다. 30분의 논쟁을 그만하고 Leaflet으로 갔다. 이후 클러스터링, 내 위치 버튼, 5km 반경 통계, 빨간 펄스 마커 — 모든 UX가 Leaflet 위에 올라갔다.
에피소드 2 : 공공API가 브라우저를 차단한다
서울교통공사 API 키를 발급받았다. 브라우저에서 호출했다. CORS 오류.
거의 모든 한국 공공API는 브라우저 직접 호출을 막는다. 이유는 보안이지만, 시민 도구를 만드는 입장에선 첫 번째 진입 장벽이다.
해결책은 로컬 중계 서버였다. Python 표준 라이브러리만으로 만든 프록시를 실행하면 localhost:8080이 API를 대신 불러다 준다. pip install 없이, Node.js 없이, 윈도우 배치파일 더블클릭 한 번으로.
공공데이터를 쓰고 싶다면 프록시 서버 하나는 기본 장비다. 이 사실을 모르면 첫날 포기하게 된다.
에피소드 3 : KRIC — 가장 아팠던 포기
5단계에서 야심찬 계획이 생겼다. 전국이다. 서울만이 아니라 부산, 대구, 인천, 전국 지하철역 857개를 커버하자. 레일포털(data.kric.go.kr)에 전국 도시철도 운영기관 데이터가 있었다. 22개 운영기관, 46개 노선.
API 키를 발급받고, 운영기관 코드를 매핑하고, 노선별 조합을 만들고, 테스트를 돌렸다. 모든 조합에서 0건.
명세서를 다시 읽었다. KRIC stationElevator API에는 위치 정보와 호기 정보가 있다. 그런데 USE_YN(가동상태) 필드가 없다. 어디 있는지는 알 수 있지만, 지금 켜져 있는지 꺼져 있는지는 알 수 없다.
"기술적으로 가능한 것과 본질적으로 필요한 것은 다르다."
전국 857개 역 마커를 지도에 찍을 수 있다. 그런데 색깔이 없으면 의미가 없다. 가동상태 없는 승강기 지도는 교통약자에게 쓸모없다.
포기했다. 서울교통공사로 돌아왔다.
이것이 이 프로젝트에서 가장 인상 깊었던 순간이다. 전국 데이터를 눈앞에 두고 "효용성 없다"고 판단한 그 5분이, 이후 2주의 방향을 결정했다.
에피소드 4 : 카카오 지오코딩 + 서울교통공사 = 작동하는 앱
서울교통공사 데이터에는 USE_YN이 있다. 그런데 좌표가 없다. 역명과 주소만 있다.
카카오 지오코딩 API가 해결사였다. 역명을 넣으면 위도·경도를 돌려준다. 처음엔 매번 API를 호출했는데, 역 위치는 바뀌지 않는다. localStorage에 영구 캐시를 만들었다. 처음 한 번만 조회하면 이후엔 캐시에서 꺼낸다.
결합하면 이렇다:
서울교통공사에서 USE_YN을 가져온다
카카오에서 좌표를 가져온다
Leaflet 위에 🟢/🔴 마커를 찍는다
이것이 앱의 핵심이다. 데이터 두 개를 연결하는 것, 그게 전부였다.
After — 만들어진 것들
산출물
내용
📱 PWA 웹앱
서울 실데이터 작동, 휴대폰 홈화면 설치 가능
📊 사업제안서
KOELSA_시민인터페이스_사업제안서.pptx — 13슬라이드, 임원 제출용
🎓 직원교육 자료
KOELSA_직원교육_개발사례.pptx — 16슬라이드, 의사결정 학습 사례
📄 시민 사용 가이드
PWA_설치사용가이드.docx — 1페이지, 누구나 이해하는 설치 안내
🌐 Vercel 배포 코드
Serverless Functions — API 키 서버 보관, CORS 해결
30년 안전 경력이 코 드에 새겨진 부분이 있다:
운행불가 클러스터의 빨간 펄스 애니메이션 — 관제실 비상 표시 패턴에서 가져왔다
새 고장 발생 시 시설명 노출 토스트 — "갱신됨"이 아니라 "어디서"
5km 반경 통계 — 골든타임 30분 출동 거리 개념
KOELSA EICP 어댑터 자리 비워둠 — 공식 협약 후 바로 꽂을 수 있게
코딩을 몰라도, 30년이 축적되면 설계가 달라진다.
실전 팁 3가지
1. 공공API는 CORS 차단이 기본이다
브라우저에서 직접 호출하면 무조건 막힌다. Python 프록시 or Vercel Serverless Functions 둘 중 하나를 먼저 준비하라. 이걸 모르면 첫날에 "API 작동 안 한다"로 끝난다.
2. 데이터셋 명세서를 먼저 읽어라
API 키 발급 전에 명세서부터. 내가 필요한 필드가 있는지 확인하는 게 먼저다. KRIC에 1주일 쓰기 전에 명세서 10분만 읽었다면 달랐을 것이다.
3. 지오코딩은 캐시와 함께
역명은 있는데 좌표가 없는 경우가 많다. 카카오/네이버 지오코딩 API가 해결사다. 한 번 변환한 좌표는 localStorage에 저장하면 이후 API 호출 비용도 없다.
이 방식으로 만들 수 있는 것들
복지관·의료기관 휠체어 접근 지도 — 동일 구조, 다른 데이터셋
학교 AED(자동심장충격기) 위치 지도 — 응급 장비 가동상태 실시간 확인
버스 저상버스 배차 현황 — 교통약자 대상 실시간 노선 정보
공공시설 임시 폐쇄 알림 — 시설 공지 API + 지도 결합
공공데이터는 이미 있다. 지도 위에 올리면 된다.
향후 계획
[현재] [다음]
✓ 서울권 작동 확인 → Vercel 배포 (1시간 작업)
✓ 사업제안서 완성 → KOELSA 본부 제출
✓ PWA 설치 가능 → 자체 도메인 구매 (연 2~3만원)
그리고 언젠가 KOELSA EICP 공식 API와 연결될 때, 이 프로토타입은 가장 강력한 사업 추진 근거가 된다.
재사용 프롬프트 3개
공공API CORS 우회 프록시 만들기
Python 표준 라이브러리만 써서 공공API 프록시 서버를 만들어줘.
- port 8080에서 실행
- /api/proxy?url=<인코딩된URL> 형태로 받아서 해당 URL에 GET 요청 후 응답 반환
- 사설망 IP 차단 (SSRF 방지)
- pip install 없이 동작
데이터셋 명세서 요약 요청
이 공공데이터 API 명세서를 보고 다음을 알려줘:
1. 내가 얻을 수 있는 필드 전체 목록
2. '가동상태' 혹은 '운행상태'에 해당하는 필드가 있는지
3. 위도·경도 좌표 필드가 있는지, 없으면 뭘로 위치를 알 수 있는지
[명세서 붙여넣기]
역명으로 지도 마커 찍기 전체 흐름