프로젝트 / 웹앱·대시보드
웹앱·대시보드실시간 데이터공공 API엣지 컴퓨팅지도 시각화시계열 적재
«서울 지금» 실시간 도시 상황 지도
명소 121곳 혼잡도와 교통·날씨·CCTV를 한 화면에 모으고 «지금 나가기 좋은가»를 근거와 함께 판정
- 기간
- 2026.08
- 형태
- 사이드 프로젝트
- 상태
- 배포·운영 중
- 역할
- 기획·설계·풀스택 개발·배포
121곳실시간 혼잡도를 보여주는 명소
1콜121곳 개요 조회(22KB, 공개 API 경로는 121콜)
34,848행/일5분 단위 혼잡도 시계열 적재량
3개요청당 상류 동시 호출 상한
문제
도시의 실시간 정보는 혼잡도·도로 소통·지하철·주차·공유자전거·날씨·미세먼지·CCTV가 각각 다른 서비스에 흩어져 있습니다. 공개 API는 한 번에 한 장소만 주고 http 전용이라 HTTPS 페이지에서 직접 부를 수 없으며, 과거 추이나 요일별 패턴은 제공되지 않습니다.
그 결과 사용자는 여러 화면을 오가며 «지금 나가기 좋은가»를 스스로 종합해야 했습니다. 데이터가 없는 것과 호출이 실패한 것이 같은 빈 화면으로 보이는 문제도 있었습니다.
접근
- 브라우저 대신 Cloudflare Worker가 상류 API를 중계·캐시(TTL 150~240초)하도록 해 mixed content·키 노출 문제를 함께 해결했습니다.
- 121곳을 한 번에 주는 일괄 조회 경로를 주 경로로, 공개 API 키 경로를 이중화 경로로 두었습니다.
- 상류에 동시에 많이 던질수록 오히려 느려지는 현상을 실측하고 요청당 동시 호출을 3개로 제한했습니다.
- 5분 Cron으로 D1에 실측 시계열만 쌓고 예측값은 저장하지 않아 원장을 깨끗하게 유지했습니다.
- 판정 로직은 클라이언트 순수 함수로 두고, 확인하지 못한 축은 «모름»으로 표시하도록 설계했습니다.
구조
수집Worker가 일괄 조회·상세·특보 API를 병렬 제한 하에 호출합니다.
캐시엣지 Cache API가 150~240초 단위로 부하를 흡수합니다.
적재5분 Cron이 혼잡도와 시간대별 인구를 D1 시계열로 쌓습니다.
합성클라이언트가 특보·체감온도·강수·초미세먼지·혼잡도를 합쳐 판정합니다.
표시지도·하단 시트·24시간 추이 차트에 등급과 근거를 함께 보여줍니다.
주요 기능
«지금 나가기 좋은가» 판정등급과 근거를 같이 내고, 보지 못한 축은 못 봤다고 밝힙니다. 특보를 확인하지 못하면 등급 상한을 «보통»으로 제한합니다.
24시간 추이 + 예보 겹치기혼잡도 막대 위에 기온 선과 강수확률 띠를 같은 시간축으로 얹고, 예측 구간에서 가장 한산한 시각을 문장으로 알려줍니다.
기상특보 전역 배너장소를 고르기 전에 보이도록 헤더 아래에 배치했습니다.
CCTV 라이브HTTPS 네이티브 소스로 직결하고 버퍼를 10초 세그먼트 3개 분량으로 맞춰 끊김을 줄였습니다.
상권·연령 구성·사고 통제«사람은 많은데 가게는 한산한 곳», 연령·성별 구성, 도로 통제 원인을 혼잡도와 다른 축으로 보여줍니다.
주소 검색·내 주변·모바일 시트주소나 장소명 기준 거리순 정렬과, 지도를 덮지 않는 접이식 하단 시트를 제공합니다.
결과
- 로그인·API 키 없이 쓰는 공개 웹 지도로 배포했습니다.
- 121곳 개요를 1콜·22KB로 받아 장소별 121콜 구조의 N+1 문제를 없앴습니다.
- 시계열 적재량을 하루 약 3.5만 행(121곳 × 5분 간격 288회)으로 설계해 D1 무료 한도(10만 행/일) 안에 여유 있게 들어가게 했습니다.
- 타임존 혼용·문자열 불리언·자정 표기 불일치 등 상류 데이터와 도구의 함정 27건을 실측 기록으로 남겼습니다.
포인트
가장 크게 배운 점은 «모든 요청을 동시에 던지는 게 가장 빠르다»는 직관이 틀릴 수 있다는 것입니다. 단독으로 2~5초 걸리던 호출이 11개 동시 호출에서는 40초를 넘겨 타임아웃으로 실패했고, 이를 근거로 요청당 동시 호출을 3개로 제한했습니다.
판정 화면에서는 «확인 못 함»과 «확인했고 문제없음»을 분리하는 것이 신뢰의 핵심이었습니다. 아무것도 못 본 상태를 «좋음»으로 표시하던 결함을 테스트로 잡은 뒤, 근거와 못 본 축을 함께 보여주는 원칙을 세웠습니다.
기술
Cloudflare WorkersCloudflare D1Cron TriggersCache APITypeScriptViteMapLibre GLOpenFreeMapHLS
상단 영상은 실제 화면을 녹화한 것입니다.