Changelog
Hand-curated list of user-visible changes. Mechanical commits (docs tweaks, dependency bumps, internal refactors) aren't listed here.
CSV exports + /stats/ coverage page
- New /api/cities.csv (4.5 KB) and /api/routes.csv (1.2 MB) for analytics use
- /stats/ shows live-computed coverage metrics (70 cities, 30 countries, 4,830 routes, per-mode availability counts)
- TypeScript type declarations published at /api/types.ts for consumers
Client-side /search/ + SearchAction JSON-LD
- New /search/ page with URL-shareable fuzzy filter across 70 cities
- Detects two city names in the query and offers a direct route link
- WebSite SearchAction JSON-LD on home — Google can show sitelinks search box
- Hreflang x-default declared site-wide
Live on first VPS — defense layers verified
- VPS provisioned, manually hardened (cloud-init was not applied at boot)
- Defense drill: 7 outbound abuse vectors blocked, scanning tools held by apt
- fail2ban active, UFW deny-out, root SSH disabled — all 13 layers green
- /health.txt endpoint refreshed each deploy, /security/today.txt updated daily
Articles section grown to 8 essays
- Night trains in Europe — where they actually go
- Why budget flights cost more than they used to
- Eurail pass: who it is actually worth it for
- Crossing the Channel: Eurostar vs flight vs ferry
- Why the station matters more than the city
Cities expanded 50 → 70 + per-country rankings + operator pages
- +20 cities across FR / DE / IT / ES / GB / AT / BE / NL, plus 3 new countries (SK, SI, LU)
- 4,830 city-pair routes (was 2,450 — 97% increase)
- Per-country /country/{slug}/rankings/ for all 30 countries
- Operator landing pages for Eurostar, FlixBus, Ryanair, ICE, TGV, AVE, Frecciarossa, Railjet, etc.
CO₂ footprint per mode + print stylesheet
- lib/co2.ts: EEA-cited per-km grams (train 14, bus 28, flight 156, car 170)
- RouteCard now shows ~X kg CO₂ per passenger
- Train-vs-flight savings comparison in deep-dive paragraphs
- Print stylesheet hides chrome, optimises B&W layout
Currency switcher (10 currencies)
- EUR / USD / GBP / CHF / SEK / NOK / DKK / PLN / CZK / HUF
- Server-rendered EUR + inline boot script converts via localStorage
- No hydration mismatch, no extra React framework cost
Country circuits + best-season widget
- Per-country auto-generated multi-city tour circuits via nearest-neighbour TSP
- Best-season-to-visit data for all 30 countries (peak / shoulder / avoid bands)
Project restart — static export architecture
- Three sites rebuilt with Next.js 15 output: export — no Node on the server
- cloud-init.yml hardens new VPS before SSH ever opens (preventing the 3 prior bans)
- Nginx-only serving, deploy.sh = rsync + reload
- 50 cities, 2,450 routes, 27 countries — all 3 sites built clean