Plan the trip. Keep it with you on the road.
An itinerary that follows your lead.
Planning a trip means changing your mind. Move a stop, add a day, drop in a booking: the plan has to reorganize itself without making you wait.
Instant on every change
Optimistic updates, batched persistence and cache invalidation make each edit feel immediate. Drag-over updates are throttled with requestAnimationFrame, and activation is tuned separately for touch and mouse.
- React
- TanStack React Query
- Zustand
A plan that stays consistent
Daily and overview modes, multi-day destinations, notes, bookings and budgets. Day assignment, global ordering and map markers are normalized after every move, so the itinerary never contradicts itself.
- Next.js
- React Native
- TypeScript
Maps that can switch providers
Google Maps, Mapbox and MapLibre/MapTiler sit behind one runtime provider abstraction, with markers synchronized to the itinerary. A Supabase Realtime feature flag switches provider without a redeploy or a refresh.
- MapLibre
- Mapbox
- Supabase Realtime
An assistant with real tools
Agentic AI through the Vercel AI SDK and Gateway, with authenticated multi-step tools that cover every planner feature.
- Vercel AI SDK
- Vercel AI Gateway
Connectivity is never a given.
A phone loses its signal in a valley, switches networks at the next town, or sleeps in a pocket for an hour. The mobile app handles each of these on purpose.
Data that stays on the device
An offline-first React Native architecture with an automatic MMKV storage layer under TanStack React Query caches and selected Zustand stores. The itinerary is there whether or not the network is.
- React Native
- Expo
- MMKV
Maps packed before departure
Selected map regions download to the device, with progress saved locally and interrupted downloads resumed when the app returns. The trip can keep its bearings beyond the network.
- Mapbox
- MMKV
Reconnecting on its own
Offline fallbacks, timeout detection, automatic network and authentication refresh, and Supabase Realtime reconnection after the app has been suspended or the network has changed.
- Supabase
- Supabase Realtime
Multiple platforms. Shared foundations.
Two brands, three platforms, one team. The monorepo keeps them aligned so a feature ships everywhere at once.
One codebase, aligned releases
Turborepo with shared TypeScript packages for services, API contracts, business logic, translations and brand-specific configuration, released together on web, iOS and Android.
- Turborepo
- Bun
- Expo EAS
Type-safe from database to screen
tRPC APIs validated with Zod, authentication through the Supabase SDK, and PostgreSQL through Drizzle ORM with triggers and stored functions. Itinerary access is role-based, with cached permissions invalidated properly.
- tRPC
- Zod
- Drizzle ORM
- PostgreSQL
Subscriptions on every platform
Stripe handles subscriptions on the web; RevenueCat handles them on iOS and Android.
- Stripe
- RevenueCat
What I delivered.
One travel planner, two brands, three platforms.
- Daily and overview planning with drag-and-drop
- Offline-first mobile apps that recover on their own
- Shared services, contracts and translations across brands
- Map providers that switch live, without a redeploy
- Subscriptions on web, iOS and Android
The sources do not provide adoption or commercial-impact metrics.
- Web and mobile applications
- Next.jsReact NativeExpo
- Shared logic and contracts
- TurborepoTypeScripttRPC
- Data, real-time updates and local storage
- SupabasePostgreSQLMMKV
- Mapping and subscriptions
- MapLibreStripeRevenueCat
Scope documented in Joel Tan’s CV, pages 2–3. Product and architecture illustrations informed by Itinego screenshots and implementation, September 2026.

