Let's talk ↗
← All projects

Full-Stack · Feb 2025 · Team project

The Next Horizon

A travel planner that keeps the day's stops, the map pins, and the drive between them in one place.

I was the frontend lead on Next Horizon, a travel planner for the stops in a day: the name, the place, the time, the note, and the drive between them.

The problem

A trip falls apart in the gap between the list and the map. The list says the museum is at 2, the list says dinner is at 7, and the map is a separate tab that does not know which one comes first. Someone planning the day ends up sorting by hand and guessing the drive. That is the frustration: two tools that each hold half of the plan.

It was worth putting them in one app because the order is the plan. If the stops are not in time order, the pins are just pins. If the drive is not the drive between those stops, the distance is a guess. The team built it as a React and Spring Boot app, and my side was the screen: the itinerary, the map, and the calls that keep them in step.

How I built it

A stop is a name, a place, a time, and a note. On the server that is a trip point: a PostGIS point in SRID 4326, a planned time, a date, a visit order, a planned duration, and the notes. PostgreSQL holds it. I did not want the order to be whatever the map felt like, so the list sorts by the time on the stop.

The map is Google Maps, through the React Google Maps wrapper. Each pin is labeled with its place in that sorted list, 1 then 2 then 3, so the number on the map is the number in the day. With two or more stops, a Directions request asks for driving time and distance. optimizeWaypoints is off. Google is not allowed to reorder the day. The route follows the times the person entered.

Finding the place is Google Places. The autocomplete is biased to about 50 kilometers around the trip’s location, so a search for a cafe prefers the city you are planning instead of a cafe with the same name on another continent. The suggestion becomes a latitude and a longitude, and that is what gets stored on the point.

Sign-in is JWT, with a filter in front of the trip API. Photos go to Google Cloud Storage: the upload is written as a public-read object and the row keeps the storage URL, not the file. The API is Spring Boot, packaged with Docker. Ant Design is the form, the modal, and the time picker on the itinerary, which is the part I was responsible for.

Challenges and what I learned

The bug I was guarding against is a clever route. If the directions call is allowed to optimize the waypoints, the map quietly reorders the day and the numbers on the pins stop matching the times. Leaving that off, and sorting by planned time before the route is requested, is why the pin labeled 2 is the second stop and not the one Google thought was convenient. The geometry lives in PostGIS so the map and the list are looking at the same point.

RECOMMENDED

More like The Next Horizon