Skip to content
Christian Andrey Reyes

Japan Itinerary Maker

Pick places, set your dates, and get a route-aware day-by-day plan with a map.

Music: Sascha Ende, ende.app (CC BY 4.0)
Role
Solo developer
Period
Jul – Oct 2026
Stack
Next.js 16, TypeScript, Leaflet, PostgreSQL, Nominatim, Vitest, React 19
Links
Live site (opens in a new tab)Repository (opens in a new tab)

The problem

Planning a trip across Japan means choosing places in several regions, then finding an order that does not double back and a daily load that fits. Most planners leave the routing to you. I wanted to pick places and dates and get a sensible plan to adjust, not a blank calendar.

What I built

  • A curated catalog of 152 places across 14 regions, with categories, visit durations and suggested activities.
  • Itinerary generation that orders regions along the travel corridor and packs places into days by their visit length.
  • Fixed-date pins, so a timed booking stays on its day while the free places are arranged around it.
  • A Leaflet map with day-numbered markers, and custom places added by search or a drag-and-drop pin.
  • Share links: trips stored in PostgreSQL under short unguessable codes, with a compact URL-safe encoding as a fallback.
  • A reservation and ticket assistant that lists what to book ahead, and accommodation suggestions based on the plan.
  • Geocoding through OpenStreetMap Nominatim behind a thin route handler, with the parsing kept pure and unit-tested.

How it works

  1. 01

    Choose places

    Browse the catalog by region and category, or add a custom place.

  2. 02

    Set dates

    A date range, with optional fixed dates for timed visits.

  3. 03

    Order regions

    Regions follow the travel corridor from the start city to the end city.

  4. 04

    Pack days

    Places fill days by visit length, about nine hours of sightseeing each.

  5. 05

    Map and plan

    Day-numbered markers, a timed day plan and a list of what to book.

  6. 06

    Share

    The trip's inputs are stored under a short code and rebuilt on open.

Decisions

Store the inputs, not the rendered plan

A shared trip stores place ids, dates and options, and the page rebuilds the itinerary with the same functions the planner uses. Storing the finished schedule was simpler to render, but every shared link would freeze an older version of the routing.

Route along a corridor

Regions follow a fixed north-to-south travel corridor, and the planner sweeps along it to avoid backtracking. A general shortest-route search over every place was the alternative; the corridor gives predictable plans that are easy to test.

Codes a person can read aloud

Share codes are eight characters from an alphabet without I, L, O, 0 or 1, so they survive being read off a screen or said aloud. Long random IDs were the alternative; they are awkward to share by voice, and eight characters already allow about 850 billion codes.

Evidence

33 commits, all mine
git shortlog -sn HEAD
152 places in the catalog
grep -c '{ id: "' src/data/places.ts
11 test files
git ls-files "*.test.ts"

Next

  • Weigh each leg by train travel time rather than distance.
  • Add a scheduled job that prunes old shared trips, which the table is already indexed for.