Gildle — 반려견 산책 경로 추천

OSM 보행 그래프에 가로수(나무 그늘)·결빙 위험·반려견 친화도 3축 환경 점수를 매긴 뒤, A* 알고리즘으로 시즌별 최적 경로를 계산하는 산책 경로 추천 서비스.


주요 기능

기능 설명
보행 그래프 시각화 osmnx로 추출한 영등포구 도보 네트워크 1,600+ 엣지를 Leaflet 지도에 인터랙티브 시각화.
환경 점수 산정 서울 열린데이터(가로수·결빙)와 반려견 친화도를 3축으로 매핑. 엣지별 배치 점수 산정.
경로 추천 출발/도착 클릭 → A* 알고리즘으로 환경 점수 가중 최적 경로 계산.
시즌 모드 봄/가을(그늘 우선)·겨울(결빙 회피) 모드에 따라 가중치 자동 전환.
구간별 시각화 경로를 선택한 레이어(나무/결빙/반려견) 점수별 색상으로 구간 표시.
경로 요약 총 거리·도보 시간 + 나무·결빙·반려견 평균 점수 요약 패널.
레이어 토글 나무 그늘·결빙 위험·반려견 친화도 3개 점수 레이어 전환.

기능 요구 사항

ID 기능 설명 우선순위
G-001 보행 그래프 osmnx로 OSM 도보 네트워크 추출, PostgreSQL 저장 필수
G-002 환경 점수 가로수·결빙·반려견 3축 점수 배치 산정 (서울 열린데이터) 필수
G-003 경로 추천 A* 알고리즘 기반 최적 경로 계산 필수
G-004 시즌 모드 봄가을(그늘 우선)/겨울(결빙 회피) 가중치 전환 필수
G-005 구간 시각화 점수별 색상 코딩 + 평균 점수 요약 패널 필수
G-006 지도 UI Leaflet 인터랙티브 지도, 클릭 출발/도착, 레이어 토글 필수
G-007 지역 확장 영등포구 → 서울 전역 (백로그) 선택

데이터 파이프라인

OSM 보행 그래프 구축

OpenStreetMap (영등포구)
    │
    ▼
osmnx.graph_from_place("영등포구", network_type="walk")
    │
    ▼
NetworkX 그래프 → 엣지 리스트 추출
    │
    ▼
PostgreSQL route_edges 테이블

환경 점수 배치 산정

서울 열린데이터
    ├─ 가로수 현황 CSV (cp949) ──→ 위치별 나무 밀도 ──→ tree_score (0~1)
    └─ 도로결빙 취약지점 CSV    ──→ 위치별 결빙 위험 ──→ hazard_score (0~1)

반려견 기본 점수 ──→ 도로 유형·폭원 기반 ──→ dog_friendly_score (0~1)

    │
    ▼
EdgeScoreCalculator: 엣지 midpoint ↔ 데이터 위치 매칭 (반경 검색)
    │
    ▼
scored_edges.json (1,616 엣지 × 3축 점수)

경로 최적화

출발 노드 + 도착 노드 + 시즌 모드
    │
    ▼
A* 알고리즘
    │
    ├─ 봄/가을: cost = distance × (1 - tree_score × 0.3)
    └─ 겨울:    cost = distance × (1 + hazard_score × 0.5)
    │
    ▼
최적 경로 (노드 리스트 + 좌표)
    │
    ▼
프론트: 구간별 점수 색상 Polyline + 요약 패널

점수 분포 (영등포구 실측)

점수 엣지 수 비율 범위 평균
나무 그늘 (tree) 107 / 1,616 6.6% 0.12 ~ 0.84 0.75
결빙 위험 (hazard) 101 / 1,616 6.3% 0.01 ~ 0.97 0.35
반려견 친화 (dog) 1,616 / 1,616 100% 0.30 ~ 0.89 0.34

기술 스택

구분 기술
백엔드 Python 3.12 · FastAPI · PostgreSQL · Clean Architecture + DDD
프론트엔드 Next.js 16 · TypeScript · Leaflet · react-leaflet
데이터 OpenStreetMap · osmnx · 서울 열린데이터 (가로수·결빙)
알고리즘 A* (가중 최단 경로) · NetworkX
테스트 pytest (170+ 테스트, 레이어별 단위·통합)

아키텍처 (Clean Architecture + DDD)

adapter/
├── inbound/api/v1/route_router.py     ← FastAPI Router
└── outbound/
    ├── graph/sample_walk_graph_source.py  ← OSM 그래프 로더
    └── repositories/                      ← PostgreSQL 저장소
app/
├── ports/input/calculate_route_use_case.py   ← ABC
├── ports/output/                              ← Repository ABC
└── use_cases/                                 ← Interactor
domain/
└── value_objects/
    ├── route_edge.py      ← 엣지 (from/to/점수/거리)
    ├── coordinate.py      ← 위경도
    └── season_mode.py     ← 시즌 모드 (spring_autumn/winter_safety)

트러블슈팅

CSV 인코딩 통합 (cp949)

  • 상황: 서울 열린데이터 CSV가 cp949 인코딩, Python 기본 utf-8로 읽으면 깨짐
  • 원인: 공공데이터 포털이 Excel 호환 인코딩(EUC-KR 계열)으로 제공
  • 해결: encoding="cp949" 명시, 통합 테스트에서 실제 CSV 파일로 검증
  • 결과: 가로수·결빙 데이터 정상 파싱, 영등포구 전체 매칭 완료

OSM 데이터 EC2 호환

  • 상황: osmnx가 EC2에 미설치 상태에서 import 시 기동 실패
  • 원인: osmnx + 의존성(GDAL 등)이 무거워 EC2 이미지에 미포함
  • 해결: osmnx lazy import로 전환, 미설치 환경에서도 기동 가능
  • 결과: EC2 배포 시 Gildle 외 서비스 영향 없음

스크린샷

Gildle 보행 그래프 지도 — 구간별 점수 시각화
Gildle 보행 그래프 지도 — 구간별 점수 시각화
Gildle 경로 추천 — 시즌 모드 + 색상 코딩
Gildle 경로 추천 — 시즌 모드 + 색상 코딩