트립게더
세종대 창업캠프 대상롯데 청년기업가대상 본선
SNS 게시물을 공유하면 장소 정보를 정리하는 AI 여행 가이드
배경
인스타그램 릴스나 유튜브에서 가 보고 싶은 장소를 봐도, 저장하려면 지도 앱에서 다시 검색해야 했습니다. 트립게더는 SNS 앱의 공유 버튼으로 링크를 보내면 서버가 콘텐츠를 분석해 장소를 정리해 주는 AI 기반 여행 가이드 앱입니다.
팀 프로젝트였고, 저는 Flutter 앱을 맡았습니다. 분석 서버는 별도로 개발됐고, iOS·Android 배포 자동화는 팀원이 맡았습니다. 네이티브 공유 수신과 소셜 로그인은 제게 처음 시도한 기술이었습니다.
맡은 역할
- 공유 수신 — iOS Share Extension(Swift)과 Android MethodChannel(Kotlin)
- 로그인과 토큰 관리 — Google 로그인, Dio 인터셉터로 JWT 자동 주입·갱신
- 화면 구현 — 온보딩, 홈, 콘텐츠 상세, 지도, 코스 마켓, 마이페이지
- 지도 — 영업 상태를 보여 주는 커스텀 마커와 장소 바텀시트
- 푸시 알림과 다국어 — FCM 연동, 한국어·영어 지원
- 디자인 시스템 — 디자인 값을 테마로 통일,
textTheme사용처 76곳 이전
과정
처음 시도한 기술 ①은 네이티브 공유 수신이었습니다. 공유 수신 패키지는 iOS 빌드 문제로 빼고, Swift와 Kotlin 코드를 직접 작성했습니다. 이틀 동안 "체크포인트1~6" 커밋으로 되돌아갈 지점을 남기며 iOS부터 완성하고 Android까지 붙였습니다.
공유 화면은 여러 번 만들고 되돌렸습니다. 개발 환경에서 보이던 바텀 시트가 TestFlight 빌드에서는 바로 사라졌습니다. 진단용 빌드까지 올려 본 뒤, 바텀 시트 없이 즉시 저장하고 닫는 구조로 정리했습니다.
처음 시도한 기술 ②는 소셜 로그인이었습니다. 로그인을 취소하면 앱이 멈추는 오류와, 앱과 서버의 필드명이 달라 로그인이 실패하던 문제를 고쳤습니다. 코드에 있던 OAuth Client ID는 빌드 시점에 .env에서 주입하도록 바꿨습니다.
마지막 한 달은 백엔드 API를 붙이는 데 썼습니다. Mock 데이터로 화면을 먼저 만들고, 환경 변수로 실제 API와 전환하며 맞춰 갔습니다. 온보딩·관심사, 콘텐츠, 장소 저장, 지도 마커 API를 차례로 연결했습니다.
기술적 결정
Share Extension은 저장만 하고, 처리는 앱이 맡기
- 상황Share Extension은 Flutter 밖의 별도 프로세스이고, 안에 UI를 넣으면 동작이 불안정했습니다.
- 결정Extension은 공유 URL을 App Group 큐에 저장하고 바로 종료하며, 앱이 열릴 때 큐를 처리합니다.
- 결과공유를 연달아 해도 큐에 쌓였다가 앱에서 한 번에 처리됩니다.
토큰 재발급은 인터셉터 한곳에서
- 상황여러 API를 동시에 호출하다 토큰이 만료되면, 요청마다 재발급을 시도할 수 있었습니다.
- 결정Dio 인터셉터에서 첫 요청만 재발급하고, 나머지는 Completer로 기다렸다가 새 토큰으로 재시도합니다.
생년월일 입력을 칸 8개에서 입력창 1개로
- 상황숫자 한 칸씩 입력창 8개로 받았더니, 연속 백스페이스가 제대로 동작하지 않았습니다.
- 결정입력창 하나에서
YYYY / MM / DD로 자동 포맷팅하고, 커서는 항상 끝으로 보내게 했습니다. - 결과입력창 8개·FocusNode 16개가 각각 1개로, 커서 로직은 40줄에서 5줄로 줄었습니다.
결과
- 세종대 창업캠프 대상
- 롯데 청년기업가대상 본선 진출
- iOS·Android 공유 수신부터 Google 로그인, 6단계 온보딩, 지도, FCM 푸시 알림, 한국어·영어 지원까지 앱 전반을 구현했습니다.
배운 점
- 개발 환경에서 되는 것과 배포 빌드에서 되는 것은 다릅니다. 공유 화면 문제는 TestFlight 빌드에서만 드러나, 진단용 빌드를 따로 올려야 했습니다.
- 복잡한 로직을 다듬기보다 규칙을 단순하게 바꾸는 편이 나을 때가 있습니다. 커서 계산과 공유 화면 모두, 마지막에 남은 것은 더 단순한 쪽이었습니다.