Expo · React Native · OpenAI · Express

Jurnee
AI 추천을 실제 일정으로 연결하는 여행 플래너

목적지 추천부터 일정·지도·예산·체크리스트·멤버 초대까지 하나의 여행 흐름에서 관리하는 React Native 모바일 앱입니다. 모바일 앱, API 서버, 운영 도구까지 직접 설계하고 구현했습니다.

35
모바일 화면
12
API 모듈
93
API 핸들러
Jurnee 내 여행 홈
Scope

출시까지 맡은 엔지니어링 범위

Jurnee는 모바일 앱, API 서버, 운영자 콘솔, 다국어 랜딩·가이드 사이트, 배포·운영 흐름까지 함께 설계한 서비스 단위 프로젝트입니다.

Role

Mobile · Backend · Operations

모바일 앱, API 서버, 운영 도구, 배포 흐름까지 담당

Product

Published Mobile App

iOS · Android 스토어에 배포한 여행 계획 앱

System

App · API · Admin · Landing

Expo 앱, Express API, 운영자 콘솔, 다국어 랜딩·가이드와 약관 페이지 분리

Quality

Typed · Validated · Observable

TypeScript strict, zod 검증, Sentry, Jest 회귀 테스트

Engineering Evidence

운영까지 고려해 나눈 구현 경계

AI 비용, Places 프록시, API 모듈화, 랜딩 SEO와 배포 운영 흐름을 실제 구현 기준으로 소개합니다.

AI 비용과 어뷰징 제어

이메일 인증 계정만 AI 호출을 허용하고, 성공한 호출을 user_events에 기록해 플랜별 일일 한도를 서버에서 판정합니다.

Places 프록시와 비용 방어

details, nearby, explore, autocomplete, by-id, photo를 서버에서 처리하고 캐시와 field mask로 호출 비용을 제어합니다.

여행 도메인 API

모바일 client API를 auth·trips·ai·user 등으로 분리하고, 서버는 routes·validation·repository 경계로 책임을 나눴습니다.

출시·랜딩 운영 경로

EAS OTA, Fly.io 서버 운영에 더해 Vercel 정적 랜딩, hreflang, sitemap, 여행 가이드 페이지까지 운영 흐름에 반영했습니다.

About

프로젝트 개요

여행지는 AI로 추천받아도, 일정·지도·예산·체크리스트로 옮기는 과정은 여전히 여러 앱에 흩어져 있습니다.Jurnee는 추천부터 실행까지를 하나의 흐름으로 묶었습니다.

AI 통합

OpenAI Responses API와 Google Places를 결합해, 장소 데이터 기반 여행 코스를 단계별 입력으로 생성합니다.

실행 흐름 · 코드 구조

AI 결과를 여행 데이터로 저장하는 흐름에 더해 클라이언트 API, 여행 상세 데이터 훅, 공유 유틸을 분리해 유지보수성을 높였습니다.

공간 컨텍스트

도시 추천 · 일자별 동선 · 장소 상세 · 실시간 좌표 검색까지 지도를 일관된 컨텍스트로 사용해 탐색과 실행을 잇습니다.

서비스 운영

멤버 초대·푸시 리마인더·구독·4개국어·운영자 콘솔까지 포함해 출시 이후 운영 흐름을 함께 설계했습니다.

Features

주요 기능

탐색과 대화형 추천에서 일정 생성, 예산·체크리스트·멤버 관리까지 하나의 여행 데이터 안에서 이어지도록 설계했습니다

AI 일정 생성

목적지·기간·동행자·취향·밀도 5단계 입력으로 장소 데이터 기반 코스를 만들고, 결과를 편집 가능한 여행으로 저장합니다.

OpenAIPlaces5-Step

일정 타임라인

항공·숙소·식사·관광·교통 카테고리와 일자/카테고리 필터, 일정별 예상 비용과 예산 합계를 함께 관리합니다.

5 CategoryFilterBudget

지도 기반 동선

도시별 추천 장소, 일자별 동선, 이동 거리, 장소 순서를 react-native-maps로 시각화하고 좌표 검색·역지오코딩을 지원합니다.

react-native-mapsGeocodingRoute

예산 관리

여행별 예산·사용 금액·통화·카테고리별 비용을 추적하고, 일정별 예상 비용과 지출 내역을 연결합니다.

Multi-currencyTrackingSync

준비물 체크리스트

여행 안에서 준비물을 추가하고, 일괄 추가와 완료 항목 정리로 출국 전 점검 흐름을 단순하게 만듭니다.

Batch AddCleanup

멤버 초대 & 권한

이메일/닉네임 초대, 역할 관리, 초대 수락/거절 흐름을 제공하고 owner/editor/viewer 권한을 나눕니다.

InviteRolesRealtime

리마인더 & 푸시

출발·일정·사용자 지정 리마인더를 여행 단위로 관리하고, Expo Notifications로 푸시 알림을 보냅니다.

Expo PushSchedule

Jurni AI 채팅

대화형 어시스턴트가 여행지 후보와 추천 이유, 테마를 제안하고 채팅 결과를 일정 생성 흐름으로 연결합니다.

ChatThemesBridge

다국어 지원

앱 UI·내장 데이터·AI 프롬프트에 더해 랜딩 페이지와 여행 가이드도 한국어·영어·중국어·일본어 정적 URL과 hreflang으로 제공합니다.

4 LocaleshreflangSEO

소셜 로그인

Google·Kakao·Apple 소셜 로그인과 이메일 인증·비밀번호 재설정을 제공하고, 발급한 JWT는 SecureStore에 안전하게 저장합니다.

GoogleKakaoApple
Architecture

아키텍처

모바일 앱 · API 서버 · 운영자 콘솔 · 랜딩/가이드 정적 사이트를 역할별로 분리하고, 민감한 키와 데이터 처리는 서버 경계에 모았습니다

레이어 구조

Mobile App (Expo)

L1
React Native 0.83.6React Navigation 7Expo SDK 55

여행·탐색·AI 플래너·마이페이지 탭에 소셜 로그인, 4개국어, 딥링크, 푸시 알림을 통합

State & Storage

L2
Context APIAsyncStorageExpo SecureStore (JWT)

토큰은 SecureStore, 사용자 데이터는 AsyncStorage + 도메인별 API 클라이언트로 관리

API Server

L3
Express 5.1better-sqlite3zod · helmet · rate-limit

JWT 인증, 요청 검증, 보안 헤더, 12개 API 모듈과 93개 핸들러, repository 계층으로 도메인 분리

External Integrations

L4
OpenAIGoogle PlacesResend · R2 · RevenueCat · Sentry

키는 서버 환경 변수로 관리하고 모바일 번들에는 공개 가능한 값만 노출

모노레포 구조

📁Jurnee/
📄App.tsxProvider · Sentry · Splash
📄app.json / app.config.jsExpo 설정
📁src/
📁screens/35 화면 · tripDetail 훅/공유 유틸 분리
📁api/auth·trips·ai·user client modules
📁components/지도·입력·카드·모달
📁navigation/React Navigation · DeepLink
📁contexts/Auth · Theme · Notification
📁i18n/ko·en·ja·zh 4개국어
📁utils/보안 · themed styles · telemetry
📁server/
📁routes/12 modules · 93 handlers
📁repositories/user data import/export
📁validation/30+ zod schemas · 입력 검증
📁admin-site/Vite + React 운영자 콘솔
📁legal-site/랜딩 · 가이드 · 약관 · SEO

예외 상황 대응

AI 응답 실패재시도 + 캐시된 추천 fallback
오프라인로컬 상태로 화면 유지
Places quota서버 프록시 + 결과 캐싱
푸시 실패Sentry 이벤트 기록 + 토큰 갱신
Tech Stack

기술 스택

각 기술의 선택 이유와 프로젝트에서의 역할

📱

Expo

SDK 55

React Native 개발 플랫폼

선택 이유

EAS Build/Update로 OTA 핫픽스, 네이티브 모듈 관리 효율화

Framework
⚛️

React Native

0.83.6

크로스플랫폼 모바일 프레임워크

선택 이유

iOS/Android 단일 코드베이스로 빠른 반복 개발

Framework
📘

TypeScript

5.9.2

정적 타입 시스템 (strict)

선택 이유

여행 DTO와 도메인별 API client 모듈의 타입 안전성 확보

Language
🚀

Express

5.1

Node.js HTTP 서버

선택 이유

라우트·validation·repository 계층 분리와 미들웨어 조합

Backend
💾

SQLite

better-sqlite3

임베디드 데이터베이스

선택 이유

Fly.io 단일 인스턴스 운영에 적합, 동기 쿼리로 단순한 코드

Database
🧠

OpenAI

Responses API

AI 추천/일정 생성

선택 이유

여행 도메인 프롬프트와 구조화된 응답을 한 번에 처리

AI
📍

Google Places

장소 검색/상세/사진 proxy

선택 이유

details/nearby/explore/photo 등 서버 프록시로 키 노출과 호출 비용 제어

AI
🛡️

zod

런타임 스키마 검증

선택 이유

30개 이상의 API 입력 스키마로 라우트와 repository 진입 전 검증

Backend
🔍

Sentry

에러/이벤트 추적

선택 이유

앱과 서버 오류를 같은 릴리스 컨텍스트로 추적

Observability
💳

RevenueCat

구독 결제 관리

선택 이유

iOS/Android IAP 영수증 검증과 webhook을 한 번에 처리

Payments
🗄️

Cloudflare R2

이미지 객체 스토리지

선택 이유

S3 호환 + egress 비용 없음, 프로필/여행 이미지 호스팅

Storage
🛫

Fly.io

API 서버 호스팅

선택 이유

SQLite 영구 볼륨과 graceful shutdown을 고려한 API 서버 운영

DevOps
🌐

Vercel Static Site

랜딩·가이드·약관 정적 호스팅

선택 이유

clean URLs, hreflang, sitemap, QR 다운로드 CTA로 앱 유입 경로 운영

DevOps
Quality

구현 근거 & 품질

데이터 모델, 보안·입력 경계, 운영 대응, 회귀 테스트, 타입·코드 품질을 실제 구현 단위로 확인할 수 있게 구성했습니다

0
모바일 화면
0
API 모듈
0
API 핸들러
0
통과 테스트

도메인 모델

여행·활동·지출·지출 참여자·체크리스트·멤버·리마인더·이벤트·감사 로그를 SQLite 스키마와 인덱스로 분리했습니다.

보안 · 입력 경계

Helmet, CORS whitelist, rate limit, JWT revocation, SecureStore 토큰 저장에 더해 여행 날짜 순서·텍스트 길이 제한 같은 입력 검증으로 요청 경계를 지킵니다.

운영 · 데이터 복구

관리자 쓰기 액션은 감사 로그에 남기고, 데이터 export/import는 userDataRepository로 분리해 라우트와 복구 로직의 책임을 나눴습니다.

테스트 범위

Jest 멀티프로젝트(ts-jest 유닛 + jest-expo 컴포넌트)로 예산 계산, 보안 유틸, 좌표 변환, geo 로직과 RNTL 컴포넌트까지 113개 테스트로 검증합니다.

타입 · 코드 품질

AI 응답 DTO, 도메인별 src/api 모듈, TripDetail 데이터 훅·공유 유틸, themed styles 훅으로 대형 파일의 변경 범위를 줄였습니다.

Screenshots

스크린샷

실제 시뮬레이터 화면 19장 — 카테고리로 필터링하거나 클릭해 라이트박스로 확대해서 볼 수 있습니다

내 여행 홈

내 여행 홈

진행 중인 여행, 검색, 상태 필터, D-Day를 한 화면에서 확인

일정 타임라인

일정 타임라인

일자·카테고리 필터와 예산 합계를 함께 보는 여행 상세

일정 날짜 선택

일정 날짜 선택

생성된 일정의 출발일을 캘린더 모달에서 조정

오사카 일정

오사카 일정

항공·숙소·관광·식사·쇼핑이 섞인 실제 타임라인

여행 관리 요약

여행 관리 요약

썸네일, 일정 수, 예산, 체크리스트, 멤버 관리 요약

AI 일정 결과

AI 일정 결과

목적지·취향 기반의 3일 코스 미리보기

일정 밀도 선택

일정 밀도 선택

하루 일정 수로 여행 리듬 조절

여행 스타일

여행 스타일

힐링·미식·문화·쇼핑 등 취향 조합

동행자 선택

동행자 선택

혼자·커플·친구·가족별 일정 톤 조정

기간 선택

기간 선택

2-14일 범위의 여행 기간 선택

목적지 선택

목적지 선택

국가·도시 카드로 시작점 선택

실시간 장소 지도

실시간 장소 지도

도시별 명소·맛집·카페·자연 스팟

지도 동선

지도 동선

일자별 경로·이동 거리·장소 순서

여행 지도 탭

여행 지도 탭

여행 상세 안의 날짜별 장소 지도

추천 코스 상세

추천 코스 상세

지도·장소·평점·코멘트 포함 즉시 생성

탐색 홈

탐색 홈

AI 추천·지도 탐색·테마 추천 진입점

Jurni 채팅 시작

Jurni 채팅 시작

추천 질문과 입력창이 있는 AI 홈

Jurni 추천 답변

Jurni 추천 답변

여행지 후보와 이유를 대화로 제안

멤버 관리

멤버 관리

이메일/닉네임 초대와 역할 선택