Flights
Flights are TravStats’ first-class entity. There are four ways to get one into the database, ranked by how much typing they save:
| Method | Time per flight | Best for |
|---|---|---|
| Forward a confirmation email | ~5 s | Future flights (booking → trip prep) |
| Scan a boarding pass | ~10 s | At the gate or right after landing |
| Bulk import (XLSX/CSV/JSON) | seconds for thousands | Backfilling years of past flights |
| Manual entry | ~30 s | Old flights, no email/pass available |
Adding a flight manually
Section titled “Adding a flight manually”Flights → Add Flight opens a step-by-step form:
- Departure / arrival airports — type IATA (
FRA), ICAO (EDDF), or city (Munich); the autocomplete searches all ~9000 airports seeded on first boot. - Date and times — local times in each airport’s timezone (TravStats stores everything as canonical UTC behind the scenes; v1.2.0 fixed a long-running bug where reminder emails fired 1–2 h off because of mixed conventions).
- Airline — IATA (
LH) or ICAO (DLH) plus the operator name. Auto-fills if the IATA matches a known airline. - Aircraft — IATA-T type code (
32Afor A320neo,744for 747-400) or freeform. - Flight number — normalised to
LH123style automatically; case and whitespace don’t matter. - Optional fields — booking reference (PNR), seat, cabin class, tags. All searchable later.
Distance is computed from the airport coordinates; you don’t enter it yourself.
Parsing a confirmation email
Section titled “Parsing a confirmation email”The fastest path for booked-but-not-yet-flown flights.
Flights → Import → Email — paste the email body or upload an
.eml / .msg file. The parser pipeline (Ollama-first when
configured — strongly recommended):
- Clean the email body and detect the sender / subject for routing.
- User template if you’ve recorded one with confidence ≥ 80 % — runs first.
- Ollama LLM (recommended primary parser) — your local LLM, default
gemma3:12b, runs as a sidecar container next to TravStats. Handles multi-flight bookings (round trips, connections, group itineraries) reliably across any airline. Benchmark accuracy: ~95–100 %. - Built-in regex templates as the fallback for these eight European carriers when Ollama is unavailable: Lufthansa (
LH, plus the older “Buchungsdetails” format), Swiss (LX), Austrian (OS), Brussels (SN), Ryanair (FR), easyJet (U2), Eurowings (EW), Wizz Air (W6). Single-leg bookings on these carriers parse fine without Ollama. Multi-flight emails are the regex layer’s weak spot — if you fly multi-leg itineraries, run Ollama. - Generic regex extractor as last resort.
- Review screen before anything is saved. You can edit any field, delete suggestions you don’t want, or hit Save all.
For airlines you fly often that aren’t on the built-in list and where you’d rather not depend on Ollama, you can record a user template — paste an example email, mark which lines contain which fields, and TravStats will reuse the rules on future emails from the same sender.
When the parse is incomplete
Section titled “When the parse is incomplete”Common cases and what to do:
| Symptom | Cause | Fix |
|---|---|---|
| Aircraft type missing | Airline doesn’t include it in the email | Manually edit, or enable AirLabs/Aviationstack enrichment for auto-fill on next save |
| Wrong departure date | Email has multiple legs, parser picked the first | Review screen lets you delete the unwanted ones before saving |
| Codeshare flight number | Operator vs. marketing carrier mismatch | The flight-lookup API resolves codeshares — set an AirLabs/Aviationstack key in Admin → Settings |
| All fields blank | Email is OCR’d from a forwarded photo, or HTML is heavily styled | Try uploading the original .eml file instead of pasting body text |
Scanning a boarding pass
Section titled “Scanning a boarding pass”Flights → Import → Boarding Pass takes a photo or uploaded image.
Three vision parsers are tried in order, falling back if the previous one isn’t configured or fails:
- Ollama with a vision-capable model (default), running locally
- OpenAI / Claude if you’ve set an API key in Admin → Settings
- Tesseract OCR as last resort — pure-CPU, slower, less accurate
Whichever extracts a usable flight number first, wins. If nothing works you’ll get a manual-entry form pre-filled with whatever text the OCR could read.
The PDF417 / Aztec barcode on the pass is decoded too — once we have the flight number and date, the flight-lookup API fills in the aircraft, distance, scheduled times, and operating carrier.
Editing flights
Section titled “Editing flights”Edit any field after the fact: click a flight in the list, change, save. Distance recomputes when you change either airport. The audit trail in Admin → Logs tracks who changed what, when, and what the previous value was.
Bulk edits — Flights → Filter, select rows, Bulk edit. Useful for one-time corrections like:
- Renaming an airline (merger or rebrand: “Air Berlin” → “AB”)
- Replacing an aircraft type (typo:
744→74H) - Adding a tag to all flights of a trip
- Deleting test flights from a demo run
Re-importing without duplicates
Section titled “Re-importing without duplicates”If you re-import a boarding pass for a flight you’ve already entered, TravStats fills in missing fields on the existing row instead of creating a duplicate. Same flight number + same calendar day + matching airports = match. The dashboard surfaces a flightMerged toast that reports how many fields were filled in.
To force a merge explicitly via the API:
curl -X POST https://travstats.example.com/api/v1/flights?merge=true \ -H "Authorization: Bearer ts_pat_…" \ -H "Content-Type: application/json" \ -d '{ "flightNumber":"LH401", "departure": …, "arrival": … }'The merge respects manual edits — fields you’ve curated never get
overwritten. Only blank fields are filled. See the
OpenAPI docs at /api/v1/docs
for the full request/response schema.
Viewing flights
Section titled “Viewing flights”The dashboard has six map modes for the same data:
- Routes — great-circle arcs on a 2D world map
- Heatmap — density by airport
- Hexagon — H3 hex bins for clustered analysis
- 3D Columns — column heights = flight counts
- Trips — animated playback of routes through time
- 3D Globe — three.js spinning globe with arc traces
Plus statistics across the lot: total distance (”× around Earth”), total time, countries visited, top airlines, top aircraft, top airports.
Tagging and filtering
Section titled “Tagging and filtering”Add free-form tags (business, family, solo, expat-life, 2026)
on any flight. The filter sidebar lets you mix tags, airlines,
aircraft, year and country to narrow the dataset for both the map and
the statistics — handy for “all family trips in 2026” kind of slices.
Achievements
Section titled “Achievements”Every save kicks off the achievement engine. Distance milestones, country counts, route patterns, equator/antimeridian crossings, all 58 awards are checked on every flight create / update / delete and unlocked retroactively. You’ll see a toast on the dashboard when a new one fires.