TravelSync
A full-stack travel planning platform handling trip organisation, itinerary management and booking workflows — deployed with modern session-based auth.
- Auth
- Auth.js / NextAuth v5
- Database
- MongoDB Atlas
- Deployed
- Render
Overview
TravelSync is a travel planning platform designed and deployed to Render, using Auth.js (NextAuth v5) for authentication and handling trip organisation, itinerary management and booking workflows.
Problem
Planning a trip is a data-modelling problem disguised as a to-do list. Dates, destinations, bookings and day-by-day plans are all related, all editable, and all private to one traveller. Most planning tools fail in one of two ways: they’re a flat list that can’t express 'day three, two bookings, one moved', or they’re a spreadsheet with no notion of who owns what.
Solution
Model trips, itinerary items and bookings as related documents scoped to an authenticated owner, then build the interface around editing that structure. Next.js handles routing and rendering, MongoDB Atlas provides the managed datastore, and Auth.js (NextAuth v5) owns sessions — so every query is filtered by the session user rather than trusting a client-supplied id. Deployed to Render as a long-running service.
Architecture
A conventional stack chosen deliberately. The engineering effort went into the ownership model and the itinerary data shape, not into novelty.
- Layer 01
Application
Next.js app
Trips, itinerary, bookings
Server actions / route handlers
Validated mutations
- Layer 02
Identity
Auth.js (NextAuth v5)
Session strategy + callbacks
Route protection
Session checked server-side
- Layer 03
Domain
Trip
Dates, destination, owner
Itinerary item
Ordered, belongs to a trip day
Booking
Attached to trip or item
- Layer 04
Infrastructure
MongoDB Atlas
Managed cluster, IP allowlist
Render
Environment config, build + deploy
Tech Stack
Screenshots
Screenshot slot 1
Screenshot slot 2
Interface captures for TravelSync aren’t published here yet — the architecture and decisions above are the substance. Available on request, or in the repository.
Challenges
- 01
NextAuth v5 during its rewrite
Auth.js v5 changed the configuration surface substantially, and most tutorials still described v4. Getting sessions working meant reading the actual migration docs rather than copying patterns — restructuring config, handlers and callbacks, and understanding what the session object contains server-side versus client-side.
- 02
Ownership on every single query
The moment two users exist, every read and write becomes an authorisation question. I stopped accepting resource ids as sufficient input and made the session user part of every query filter, so a valid id belonging to someone else returns nothing rather than someone else’s trip.
- 03
An itinerary that survives editing
Itineraries get reordered, moved between days, and deleted mid-plan. A naive array index breaks immediately. Getting the ordering and day-association model right — so a move doesn’t corrupt the rest of the trip — took more iterations than any other part of the build.
- 04
Local to deployed
Working locally and working on Render are different problems: environment variables, auth callback URLs that must match the deployed origin exactly, and Atlas network access rules. Deployment surfaced configuration assumptions the local build had quietly hidden.
Lessons Learned
- 01
Authorisation belongs in the query, not in a check beside it. Scope by session user and the whole class of leaks disappears.
- 02
When a library is mid-major-version, read the migration guide first. Copied v4 patterns cost more time than the docs would have.
- 03
Ordering and hierarchy are the hard part of any planning tool. Get the data shape right before styling anything.
- 04
Deploying early exposes configuration bugs while they’re still cheap to fix.
Live Demo & Repository
Live demo
Not publicly hosted. Happy to walk through it live or share a recording.
Source code
View on GitHub
Want the deeper version of this?
I’m happy to walk through the code, the trade-offs, or the parts that didn’t make the write-up.