Treader
Collaborative trip planner. Every stop on one live map, with the plan checked against opening hours, daylight and holidays.

- automated tests in CI, on every pull request and on staging
- 3,000+
- API endpoints behind one typed client
- 95
- Postgres tables with row-level security
- 51 of 51
Features

Scout, the AI assistant
Scout reads the whole trip, so you can ask things like "what is day 2 missing?" and get an answer based on your actual plan. Suggestions can be added straight to a day. It runs on Vertex AI, server-side, with limits per plan.

Trip hub and trip check
Days, budget, fuel and who owes who in one place. The trip check flags stops outside opening hours or daylight, holidays on your dates, and bookings you still need to make.

Travel time between stops
Walk, drive, train and ferry legs are timed between each stop. Here a Shinkansen leg sits between walks in Tokyo and Kyoto. Moving a stop updates the rest of the day.

Places in view
Lists everything inside the current map view with ratings, so you can add a stop in one tap.
Mobile

Planner map with the Itinerary, Map and Scout switch.

Scout answering the same day 2 question.

Trip hub, with the trip check below.

The Tokyo to Kyoto train leg.
Engineering
Plan limits enforced in Postgres
Every table has row-level security, and the free and paid plan limits are checked in the database, not just the UI. A client talking to Supabase directly still can't go past its plan.
One API client, keys stay server-side
Every browser request goes through a single typed API client. Keys for Google, Stripe and Vertex can only be read on the server.
Fallbacks for every provider
If the Google key is missing, search and routing fall back to OpenStreetMap. If Stripe isn't set up, billing is hidden. A health endpoint reports what each deployment has.
Import from other tools
Paste an itinerary from ChatGPT, Claude or Gemini and it gets put on the map and checked. GPX and KML hikes import the same way.
MCP server for Claude
An MCP server with OAuth 2.1 lets Claude read and build trips with the user's permission.
Automated screenshots
A Playwright script signs in, opens real trips and retakes every product screenshot after a UI change. The screenshots on this page came from it.
Why I built it
Every group trip I've planned started the same way: a shared doc, a pile of browser tabs, and one person doing most of the work. The apps out there are either a calendar with a map added on, or a booking site trying to sell you something.
I wanted something in between, where a group can add places, sort out the order together, and end up with a day-by-day route without anyone putting it together by hand.

How it's built
SvelteKit and Svelte 5 on the front end, Supabase and Postgres behind it, deployed on Vercel. Paid features are gated in the database, not the UI.
Live co-editing runs on Supabase Realtime, so edits show up for everyone without me running a socket server. Stripe handles subscriptions in CAD, with monthly, annual and lifetime plans.

Keeping API costs down
Google Places, Routes and Vertex all charge per call, and an interactive map makes a lot of calls. Everything billable is cached, rate limited and capped by a daily budget. When the budget runs out the map switches to OpenStreetMap instead of going blank.
How Scout works
Scout gets the trip as structured data instead of a block of text in a prompt. It knows what each day looks like, so it can point out a gap in the afternoon and suggest something to fill it, with Add to trip and Undo.
It runs server-side and is limited by plan, which keeps the API key private and the cost predictable.
What I'd do differently
I stored itineraries as a flat list of stops for too long. Days are a real concept in the product, and changing that later cost a migration and a week of merge bugs.
I'd also build plan limits into the database from the start. Adding them after the UI was already handling it meant checking every write twice.
