Skip to content

TravStats v1.0.0

Choose a tag to compare

@Abrechen2 Abrechen2 released this 17 Apr 16:59

TravStats v1.0.0 — the first public release ✈️

Six months of daily use, 22 resolved pentest findings, a full switch to DB-backed config and a thousand tiny UX tweaks later, TravStats goes stable. One container, one environment variable, the setup wizard handles the rest. No telemetry, no account on anyone else's server, no ads — your flights stay on your own machine.

"I just wanted to know where I've been — without handing that to a company."
That's the whole thesis. TravStats is for 1–10 users who want their travel history to outlive a startup's pivot.


What you can actually do with it

✈️ Track flights the way that fits you

  • Manual entry with categories, tags, up to 50 travel companions, cost + currency
  • Boarding-pass scanner — QR, PDF417 and OCR fallback with automatic airline/airport resolution
  • Email & PDF import — plain text, HTML, Outlook .msg, .eml, with optional local LLM parsing via Ollama (gemma3:12b benchmarks 100% accuracy on our test corpus)
  • Five flight states — flown · scheduled · cancelled · historical · duplicated, each with its own form, validation and stats treatment
  • Duplicate detection with a confirmed "save anyway" escape hatch when you actually did fly the same number twice in a day

🗺️ Six map modes on one canvas

Routes · Heatmap · Hexagon (3D) · 3D Columns · animated Trips · 3D Globe. Built on deck.gl 9 and MapLibre 5 through a shared WebGL context, so switching visualisations doesn't flash. Scheduled flights render as cyan arcs and are excluded from stats until they're flown.

📊 Statistics that actually tell a story

Year-over-year comparison, seat/class distribution, top routes, cost tracking, airline loyalty breakdown. Export a PDF year report for your own records, or download a vintage-passport-style PNG certificate with your totals to share.

🏆 58 achievements across 5 categories

Explorer · Distance · Collector · Elite · Special — plus Planner and Survivor tiers for travellers who cancel nothing, and those who survive them. Thresholds are tuned so v1 users don't unlock everything in the first week.

🤖 Automation that never leaves your LAN

  • Automatic flight-data lookup via AirLabs (primary), OpenSky OAuth and Aviationstack fallback — with live gate, terminal and actual-times while the flight is in the air
  • Pending-update inbox — nothing changes without your approval, and every suggestion shows its statistics impact before you accept it
  • Historical enrichment scheduler backfills gate/terminal/aircraft data for past flights
  • 24 h / 2 h pre-departure reminders via SMTP (off by default)
  • Automated database backups with retention + optional WebDAV sync to Nextcloud, HiDrive or any WebDAV endpoint
  • Runtime auto-update checker that pings GHCR for a newer image and lets an admin redeploy with one click

🔐 Security you can audit yourself

  • JWT stored in an HttpOnly, SameSite=Strict cookie — no Bearer fallback, no localStorage
  • 15 rate limiters on auth, external-API-backed routes and admin exports (LAN traffic is skipped so the admin dashboard doesn't throttle itself)
  • Zod validation on every input endpoint, Prisma-parameterised queries, Helmet CSP, server_tokens off
  • 22 pentest findings (2 CRITICAL, 5 HIGH, 8 MEDIUM, 7 LOW) surfaced and mitigated across the beta — reproducible verification commands in SECURITY.md
  • JWT + encryption keys auto-generated on first boot and persisted inside the data volume at /app/data/secrets/ — no secret in your .env

🐛 Friction-free bug reports

One button in the top nav copies an anonymised diagnostic bundle (log tails, flight-state aggregates, settings sans credentials) to your clipboard and opens a pre-filled GitHub Issue Form with your version populated. Two clicks from "something's weird" to "here's a useful report".


Installation

Docker Compose (bundled Postgres):

curl -O https://raw.githubusercontent.com/Abrechen2/TravStats/main/docker-compose.prod.yml
echo "DB_PASSWORD=$(openssl rand -base64 32)" > .env
docker compose -f docker-compose.prod.yml up -d
open http://localhost:3000/setup

Unraid: Community Apps templates live at Abrechen2/docker-templates — install travstats-db first, then TravStats, set the password, open /setup.

Images: ghcr.io/abrechen2/travstats:1.0.0 · docker.io/abrechen2/travstats:1.0.0

Full install guide with screenshots: README.md · Unraid step-by-step: docs/unraid/README.md


Zero-config is the default now

For a default Docker install, the only thing you set in a file is DB_PASSWORD. Instance name, public URL, user cap, registration mode, API keys, Ollama endpoint + model, backup schedule, WebDAV — everything is captured by the first-run setup wizard or configured from the admin UI afterwards. The setup form itself is just username + password + confirm; sensible defaults are applied silently and are editable anytime.

This was the single biggest change going into 1.0: nine new admin_settings columns took the place of nine environment variables, and the runtime reads from there first. Pre-1.0 installs keep working — the old env vars are honoured as a one-time fallback until an admin saves from the UI.


Breaking changes from 0.x

  • Docker registry: images still live on GHCR (ghcr.io/abrechen2/travstats) as the primary target. Starting with 1.0, X.Y.0 releases are also mirrored bit-identically to Docker Hub (abrechen2/travstats) for discovery. Pre-release candidates and patches stay on GHCR only.
  • Default LLM model is now gemma3:12b (was qwen2.5:7b). Change it in Admin → Parser after login.
  • Parser-feedback collection removed. The /admin/parser-feedback/* endpoints and the FeedbackAnalytics admin tab are gone. The separate ParseTrainingLog-backed hit-rate dashboard is unchanged.
  • Install footprint: one volume now covers the app data, backups and auto-generated secrets (previously a dedicated /app/secrets mount). Pre-1.0 installs are auto-migrated at container boot.
  • Instance-level ENV vars are now optional. INSTANCE_NAME, MAX_USERS, ALLOW_REGISTRATION, FRONTEND_URL, WEBDAV_* are still read once as a fallback, then superseded by the DB value the first time an admin saves from the UI.

What's next

The v1.x roadmap in ROADMAP.md is driven by real-world use:

  • v1.1 Cruises module — track cruise segments alongside flights, same interactive map
  • v1.2 Trip planner — draft upcoming travel with budget and gear checklists
  • v1.3 CO₂ footprint tracking + compensation suggestions
  • v1.4 Social sharing — optional opt-in "my travel year" cards
  • v1.7 PWA — installable web app, offline flight entry sync

Priority shifts with feedback. Open an issue or discussion — we read all of them.


About this release

TravStats was built solo over six months — as a personal travel-history tool first, hardened through daily use on a homelab, and carried through a full black-box pentest before going public. v1.0.0 is the first release you're seeing because it's the first one I'd hand to someone else without caveats.

If it ends up useful to you, the nicest ways to say thanks are:

  • ⭐ Star the repo on GitHub — helps other self-hosters find it
  • Tell the community — post on your favourite homelab/self-hosted subreddit or Mastodon instance
  • Open a pull request with the airline template you wish TravStats already shipped
  • A small donation via PayPal keeps the AirLabs quota topped up for community users who share the key

Safe travels.

— Dennis