Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

🏃 런코스 — 취향으로 찾고, 직접 만드는 러닝 코스

매번 똑같은 코스가 지겹지만 새 코스를 짜기는 번거로운 러너를 위한 앱입니다. 따뜻한 에디토리얼 감성의 모바일 우선 UI에서 코스를 추천받고, 직접 만들고, 러너들과 공유할 수 있습니다.

무엇을 할 수 있나요

🛣️ 코스 만들기 — 첫 화면이자 핵심

앱을 열면 바로 지도가 뜹니다. 이 앱이 무엇을 하는 앱인지를 첫 화면이 그대로 보여줍니다: 원하는 거리·스타일로, 실제 뛸 수 있는 코스를 즉시 만들어 준다. 상단에 오늘의 러닝 컨디션(기온·미세먼지·적합도)이 한 줄로 붙어 뛸지 말지 바로 판단할 수 있습니다.

지도가 화면 전체를 차지하고, 입력·결과는 그 위에 떠 있는 카드로 올라갑니다.

  • 상단 떠 있는 입력 카드(모드 전환 · 출발/목표 행 · 데이터 소스 뱃지)
  • 지도 위 거리 슬라이더 pill, 우측 원형 버튼(내 위치 · 되돌리기)
  • 접히는 바텀시트 — 손잡이를 눌러 접으면 지도가 넓게 보임
  • 선택한 코스는 경사 색상 실선, 나머지 후보는 흐린 점선으로 함께 표시해 한눈에 비교
  • 결과는 문장형 헤드라인으로: “누적 상승 47m → 34m 로 줄였어요”
  • 비교 카드: 지도의 선 스타일과 1:1 대응하는 스와치 + 상승 뱃지 + 우측 매칭 점수

러너가 직접 코스를 짜는 두 가지 방식:

  1. 핀으로 만들기 — 지도에 가고 싶은 지점을 핀으로 찍고 러닝 스타일을 고르면, 여러 경로 후보를 생성해 스타일에 가장 맞는 코스를 추천. 시작점 복귀(순환) / 편도를 선택할 수 있습니다.
  2. 거리로 만들기 — 시작점(내 위치)과 목표 거리를 정하면 왕복 루프 또는 편도(네 방향 후보: 북/동/남/서쪽 방면)를 생성해 스타일 매칭이 높은 순으로 추천

두 모드 모두 사람이 실제로 걷고 뛸 수 있는 보행 경로를 따라갑니다. 경로는 보도·공원길· 산책로에 스냅되며, 구간별 경사(고도)를 계산해 경사 색상(급내리막·내리막·평지·오르막· 급오르막)으로 지도에 표시합니다. 러닝 스타일은 평지 / 완만 / 오르막내리막 / 경사 훈련 중 선택.

경로는 이 순서로 만들어집니다 — 키가 없어도 실제 보행로가 나옵니다.

우선순위 소스 키 내용
1 OpenRouteService 필요 도보 경로 + 왕복 생성 + 고도를 한 번에
2 OSRM foot (FOSSGIS 공개 서버) 불필요 실제 보행로 경로. 고도는 Open-Meteo Elevation 으로 조회
3 데모(직선) — 위 둘 다 실패할 때만. 실제 도로가 아니며 화면에 ⚠️ 로 명시

상단 뱃지가 지금 무엇으로 그렸는지 그대로 보여줍니다(🚶 실보행로 · OSM / 🛰 실경로 · ORS / ⚠️ 직선 데모). 거리 모드의 왕복 루프는 실제 도로로 이어 붙인 뒤 실측 거리로 반지름을 보정해 목표 거리에 수렴시킵니다.

베이스맵은 연회색 톤(CARTO Positron / Mapbox Light, 카카오맵은 타일 채도만 낮춤)을 써서 지도는 배경으로 물러나고 컬러 경로가 주인공이 되도록 했습니다.

🎽 실시간 러닝 기록

  • 브라우저 GPS(watchPosition)로 거리·시간·평균/현재 페이스를 실시간 기록
  • 라이브 트랙 지도(현재 위치를 따라가며 지나온 경로 표시), 일시정지/재개/종료
  • 뛰는 동안 화면 꺼짐 방지(Screen Wake Lock, 탭 복귀 시 자동 재획득)
  • 종료 후 요약(거리·시간·페이스·경사 고도)에서 바로 저장·공유·내보내기
  • GPS를 쓸 수 없는 환경(데스크톱 등)에서는 데모 재생으로 체험 가능
  • 홈의 "지금 바로 뛰기" 또는 만든 코스의 "이 코스로 뛰기"로 진입

📱 홈 화면에 설치 (PWA)

  • 배포 주소를 폰에서 열고 홈 화면에 추가하면 앱처럼 실행됩니다(주소창 없는 standalone)
  • Android/Chrome 은 설치 버튼, iOS Safari 는 공유 → "홈 화면에 추가" 안내 배너 제공
  • 서비스 워커가 앱 셸을 캐시해 오프라인에서도 실행(지도 타일·실시간 API는 네트워크 필요)

💾 코스 저장 · 🔗 공유

  • 만든 코스·기록한 러닝을 내 코스로 저장 → 저장 탭에서 다시 열기
  • 공유 링크: 경로를 polyline 으로 압축해 URL 로 공유(백엔드 불필요). 링크로 들어오면 코스가 그대로 열립니다. Web Share API / 클립보드 복사 지원

📤 GPX 내보내기 · Strava

  • 어떤 코스/기록이든 GPX 파일로 내보내기 → Strava·가민 커넥트 등에 업로드
  • "Strava에 올리기": 기본은 GPX 저장 + Strava 업로드 페이지 열기(연결 없이 바로 동작)
  • (선택) server/strava-worker 를 배포하고 주소를 넣으면 버튼 한 번에 자동 업로드 — OAuth 토큰 교환·업로드 중계를 Cloudflare Worker 가 처리 (아래 배포 문서 참고)

🔖 내 코스 & 👤 마이 — 전부 실제 기록

  • 러닝을 마치면 자동으로 내 코스에 저장되고, 마이의 모든 숫자가 여기서 계산됩니다 (이번 주 거리·요일 막대·누적·연속 일수·러닝 횟수·배지). 샘플 숫자 없음 — 기록이 없으면 정직한 빈 상태를 보여줍니다.
  • 주간 목표(± 조절), 러닝화 등록제 — 등록한 날 이후의 실제 기록 거리로 마일리지 누적
  • 페이스 계산기(5K·10K·하프 예상 기록) — 코스별 예상 시간에도 반영
  • 계정 동기화(이메일 로그인) — 기록·설정이 계정에 자동 백업, 기기를 바꿔도 유지
  • 파일 백업 — 로그인 없이 쓰는 안전망 (JSON 내보내기/가져오기)

러너 리서치 반영

국내외 러닝 앱/커뮤니티 자료를 분석해 자주 뛰는 러너가 실제로 원하는 요소를 담았습니다: 페이스·예상 시간, 구간 경사·고도, 날씨·미세먼지·복장 추천, 급수·화장실·야간 조명 안전, 노면, 코스 다양성, 러닝화 마일리지, 러닝 계산기, 크루·공유·함께 달리기 등.

외부 서비스 연동 (모두 선택 · 없어도 완전 동작)

모든 키는 선택 사항입니다. 키가 하나도 없어도 실제 보행 경로·실제 고도로 동작합니다 (OSRM foot + Open-Meteo, 둘 다 키 불필요). 키를 넣으면 더 정확한 소스로 전환됩니다. 연결 방법은 두 가지 — .env(.env.example 참고) 또는 앱 실행 후 마이 페이지 → 외부 서비스 연동에 붙여넣기.

서비스 역할 없을 때 발급
카카오맵 JS 키 기본 지도(한국) OpenStreetMap 폴백 developers.kakao.com
카카오맵 링크 길찾기·로드뷰 열기 — (키 불필요, 항상 동작) 없음
OpenRouteService 도보 경로·경사 (선택, 더 정확) OSRM 도보 경로로 자동 대체 openrouteservice.org
OSRM foot · Open-Meteo 실제 보행 경로 + 고도 — (키 불필요, 기본값) 없음
Mapbox 카카오 대신 쓸 지도(선택) 미사용 account.mapbox.com
Strava Worker 자동 업로드(선택) GPX 수동 업로드 server/strava-worker
  • 카카오맵을 기본 지도로 씁니다(국내 대상). 지도 계층은 스위처블 — 카카오 JS SDK 를 불러올 수 있으면 카카오맵, 아니면 자동으로 Leaflet/OSM(또는 Mapbox)으로 폴백합니다. 카카오는 자체 JS SDK 라 SDK 를 못 부르는 환경에서도 앱이 안 깨집니다. ⚠️ 카카오맵이 뜨려면 개발자 콘솔 → Web 플랫폼에 실행/배포 도메인을 등록해야 합니다 (http://localhost:5173, 배포 주소 등).
  • 도보 경로·고도는 카카오와 무관하게 OpenRouteService 또는 OSRM foot으로 계산하고, 그 좌표를 지도 위에 경사 색상 폴리라인으로 그립니다(카카오는 지도 표시 담당).
  • 카카오맵 링크(map.kakao.com/link/...)는 API 키가 필요 없습니다. 도메인 등록이나 키 상태와 무관하게 항상 동작하므로, 코스 상세·경로 시트에서 출발점까지 길찾기 · 지도 보기 · 로드뷰를 카카오맵 앱/웹으로 바로 넘겨줍니다 (실제 내비게이션은 카카오맵에 맡기는 편이 정확합니다).
  • Strava 자동 업로드는 client_secret 을 브라우저에 둘 수 없어 중계 서버가 필요합니다. 바로 배포할 수 있는 Cloudflare Worker 를 server/strava-worker 에 포함해 두었습니다(무료·단일 파일, 5분 배포). 배포 전에도 GPX 내보내기 → Strava 수동 업로드는 그대로 동작합니다.

배포 (GitHub Pages)

.github/workflows/deploy.yml 이 푸시 시 자동으로 빌드→Pages 배포합니다.

  1. 저장소 Settings → Pages → Build and deployment → Source: GitHub Actions 선택(최초 1회)
  2. 이 브랜치(또는 main)로 push → Actions 가 빌드/배포 → https://<owner>.github.io/<repo>/ 생성
  3. 그 주소를 카카오 개발자 콘솔 → Web 플랫폼 도메인에 등록하면 카카오맵이 표시됩니다 (예: https://won-topiaa.github.io)

vite.config.ts 의 base: './' 로 하위 경로에서도 에셋이 정상 로드됩니다. 별도 배포 비밀키는 필요 없습니다(지도 키는 도메인 제한 공개 키).

기술 스택

  • React 18 + TypeScript + Vite
  • Tailwind CSS (따뜻한 에디토리얼 디자인 시스템) + lucide-react 아이콘
  • 카카오맵 JS SDK(기본) ↔ Leaflet / react-leaflet(폴백, OSM·Mapbox 타일) 스위처블 지도
  • OpenRouteService(키 필요) ↔ OSRM foot(키 불필요) 도보 라우팅 + 데모 폴백
  • Open-Meteo (날씨 · 대기질 · 고도, 키 불필요)
  • Geolocation API 실시간 기록 · GPX 1.1 내보내기 · Encoded Polyline 공유 링크
  • 차트는 외부 의존성 없는 순수 SVG

실행 방법

npm install
npm run dev      # 개발 서버 (http://localhost:5173)
npm run build    # 타입체크 + 프로덕션 빌드
npm run preview  # 빌드 결과 미리보기

npm run check       # 로직 검증 3종 (GPS 필터 · 지역 기능 · 나가는 결과물)
npm run check:smoke    # 빌드된 dist 를 실제 브라우저로 열어 전 화면 클릭 (배포 직전)
npm run check:scenario # 다양한 실패 상황 연출 — 오프라인·위치거부·API차단·손상 저장소·공유링크 변조 등
npm run check:live  # 실제 ORS·Overpass 호출 검증 (느리고 외부 사정을 탄다)

프로젝트 구조

src/
├─ lib/                       # 도메인 로직 (UI와 무관)
│  ├─ types.ts                # 코스·선호·추천 타입
│  ├─ scoring.ts              # 취향 가중치 추천 엔진
│  ├─ geo.ts                  # 거리·방위·경로 생성 등 지오 계산
│  ├─ routing.ts              # ORS·OSRM(도보)·데모 provider, 구간 경사 계산
│  ├─ elevation.ts            # Open-Meteo 실제 고도 조회(샘플링 + 보간)
│  ├─ routeStyle.ts           # 러닝 스타일 점수화 + 경사 색상 밴드
│  ├─ courseBuilder.ts        # 후보 경로 생성 → 스타일/거리 랭킹
│  ├─ weather.ts              # 날씨·미세먼지·러닝 적합도
│  ├─ format.ts               # 페이스·시간·거리 포맷
│  ├─ config.ts               # 설정(키·페이스·위치) 지속
│  ├─ scene.ts                # 코스 → 감성 씬 매핑
│  ├─ polyline.ts             # Encoded Polyline + 공유 링크 코덱
│  ├─ savedRoutes.ts          # 만든/기록한 코스 저장 + 공유 복원
│  ├─ gpx.ts                  # GPX 1.1 생성/다운로드
│  ├─ strava.ts               # Strava OAuth authorize URL
│  ├─ useRunRecorder.ts       # 실시간 GPS 기록 훅(+데모 폴백)
│  ├─ kakaoLoader.ts          # 카카오맵 SDK 동적 로더
│  ├─ useKakao.ts             # 카카오 로드 상태 훅(폴백 신호)
│  ├─ routeColor.ts           # 경사 색상 폴리라인 그룹(지도 공용)
│  ├─ wakeLock.ts             # 러닝 중 화면 꺼짐 방지
│  └─ registerSW.ts           # 서비스 워커 등록(프로덕션)
├─ server/strava-worker/      # Strava 자동 업로드 Cloudflare Worker (선택 배포)
├─ server/supabase/           # 이메일 로그인 동기화 설정 가이드 (Supabase)
├─ public/                    # manifest·서비스워커·앱 아이콘(PWA)
├─ data/
│  └─ courses.ts              # 서울 실제 코스 큐레이션 (14곳)
├─ components/                # 지도 스위처(RouteMap/PathMap/LiveMap) + 카카오/Leaflet
│                             # 구현·차트·카드·시트(CourseDetail/RouteSheet)·기록·네비
├─ screens/                   # Build(홈) / Explore(추천) / Saved / My
└─ App.tsx                    # 화면 라우팅 · 전역 상태 · 공유 링크 수신

참고

  • 서울 코스의 GPS 경로 좌표는 실제 권역을 따라 단순화한 값이며, 6요소 속성/커뮤니티 피드/마이 페이지 통계는 큐레이션·샘플 데이터입니다. 실제 서비스에서는 지자체 DEM·POI, 실제 사용자 데이터로 대체됩니다.
  • 향후: 카카오/네이버 지도 연동, 실시간 GPS 기록, 스트라바 연동 취향 학습, 크루/챌린지.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages