Skip to content

TravStats 2.7.0

Latest

Choose a tag to compare

@Abrechen2 Abrechen2 released this 29 Oct 09:22
· 462 commits to main since this release

Images: ghcr.io/abrechen2/travstats:2.7.0 (also :latest, :stable, for amd64 and arm64) and the Docker Hub mirror abrechen2/travstats:2.7.0.

TravStats 2.7.0 is the largest release since lodging became a domain. Web and
app now share one look; every figure in the statistics can show the entries it
is made of; documents and receipts live on the entry they belong to; forms
suggest what you entered before; places, photos and the passport grew up; rail, bus,
rental cars and ferries are their own domains; and TravPlan, which plans a
trip ahead, and TravTrack, your own location history on your server, wait
behind the beta switch together with roadtrips and tours. The forty audit
fixes first written for the never-promoted 2.6.3-rc.1 ship here too, further
down this entry.

Before upgrading: take a backup. Coming from 2.6.3, the first start runs
166 migrations, one of which rewrites stored cruise statuses from flown to
completed; it also recalculates stored cruise legs along the sea route and
re-routes stored straight ferry crossings once in the background, which can
take a minute on a large logbook. A database restored from before the update
is the way back; the previous image alone does not know the new columns.
From 2.7.0-rc.27 nothing changes: 2.7.0 is that release candidate, retagged.

Added

  • A shared trip's dates sync to every member; its name does not. Moving a shared trip's period moves it for everyone on the trip, each member gets an inbox notice they can undo, and each member keeps their own name for the trip.

  • TravPlan is switched on and off per account, beside the domains in your settings, like any other area. Accounts that already plan with it keep it on.

  • Country and continent badges count ground contact. A bus or ferry end, a service area or a fuel station places you in a country and on a continent, each piece of evidence on its own continent; a service area or fuel station counts as ground contact only, never as a visit.

  • Both odometer readings prove a finished roadtrip driven.

  • TravTrack shows as soon as an admin switches it on, and says how data comes in.

  • The "what's new" dialog ends with a note from the developer after the 2.7 highlights.

  • TravTrack (beta): your own location history on your server. The Companion records into it; a map of days and ranges, explored areas, monthly values, stays, a flight panel with the altitude profile and the photos taken on board, imports from GPX and a Dawarich copy, privacy zones that delete and never draw what lies inside them. Behind its own instance switch and the beta key.

  • Inbox questions from TravTrack show their stretch of track: a small map, from–to, duration, distance and why the question was asked.

  • Duplicates are merged from the inbox, with undo. Keep both, merge into one (refused with a reason when the copies carry different recordings or trips), and a ferry crossing inside a trip is offered to that trip. Dismiss, keep and link can be undone for ten minutes.

  • Statistics for one year. Every statistics endpoint the Companion reads takes a year and says which year it answered for; the passport counts a country in every year with evidence for it.

  • Tram and U-Bahn rides run on their own tracks. OpenRailRouting is asked with a tram or subway profile instead of the mainline one, so a U2 ride no longer detours over S-Bahn tracks; without such a profile the ride keeps a straight line with a reason. Rides can be routed again, one by one or all at once by an admin. Setup: docs/features/rail-routing.md.

  • The calendar subscription shows local times. Flights and rides carry the departure and arrival time zone and the local time in the title ("✈ Jeju 12:05 → Gimpo 13:10 · KE1206"); the link prefers a host name over an IP and warns when Google cannot reach it; the Companion can add it to the phone's calendar.

  • A setup checklist for server-to-server sharing in Admin → Instance, and the trip's share menu says why sharing with another server is not available yet.

  • TravPlan has its own switch in Admin → Instance (still beta).

  • A place's visits, redesigned: planned visits first, past ones by year, undated last, dates in your format, trip, photos, documents and rating on the row.

  • A rail ride knows whether it was a train, an U-Bahn, a tram or a bus. The mode is shown and can be changed on the ride, and the rail statistics count trains only. Every ride stored before this version is a train.

  • A bahn.de connection's U-Bahn, tram and bus legs are reviewed in place. The import dialog names each leg's mode; U-Bahn and tram legs can be kept as rail rides of that mode or skipped, bus legs can be saved as bus rides or skipped. Settings → Daten remembers the choice for each kind ("skip" until changed).

  • bahn.de stops are resolved from bahn.de's own station data, so a stop named the way bahn.de prints it finds its catalogue station.

  • Settings → Mitreisende. One page for everyone you travel with: how
    often each person appears per area, rename (the name changes on every
    entry), merge two spellings of the same person after a preview of what
    moves, and delete people nobody is attached to. Merging is refused when
    both are linked to different accounts.

  • "Mit wem unterwegs" on the statistics overview: days, entries and
    countries shared with each companion across all switched-on areas, stays
    included, each figure with the entries behind it. A shared day counts
    once; paying an expense alone does not count as travelling together.

  • Server connections exchange keys by file. Admin → Server-Verbindungen
    hands out a connection file (a ZIP with this server's address, public key,
    fingerprint and a short DE/EN guide) and reads the other server's file
    into the form. An imported server is marked "Noch nicht überprüft" until
    its address and fingerprint have been compared with the other admin over
    a second channel, and nothing is stored before "Server hinterlegen"; a
    known server arriving with a different key is flagged. The manual fields
    stay, folded away under "Von Hand eingeben".

  • Replacing the server key asks first. When a key is already stored,
    "Schlüssel erzeugen" explains that servers holding the old key refuse
    this server until their admins check and store the new one.

  • Ferry crossings have a route map, the trip's photos taken during the
    crossing and a chapter in the year in review.
    The map draws the stored sea route, or a faint
    straight line between the ports where there is none.

  • Bus rides have a route map and the trip's photos taken during the ride.

  • Ferry and bus departure reminders. The existing 24-hour and 2-hour
    reminder switches now also mail before a ferry crossing or a bus ride,
    in the port's or terminal's local time — for a domain the account has
    switched on (both are still behind the beta switch), and only for a
    departure with a time of day.

  • Lodging enrichment from OpenStreetMap shows what it found before it
    writes:
    the matched house with its OSM link and distance, and per field
    what would be filled and what stays. Nothing changes until "Übernehmen";
    if OpenStreetMap names a different house by then, nothing is written. The
    match is stored on the lodging unless it already carries a reference.

  • Flight track upload reads FlightAware and Flightradar24 KML exports, KMZ
    and Flightradar24's CSV,
    reads their altitudes in the right unit, and
    says why a file gives no track (still behind the beta switch).

  • Rentals appear on the statistics overview as their own card and count
    as an experience; they add no travel days and no countries.

  • Rail is out of beta. It shows whenever an account has the rail domain
    switched on, independent of the instance's beta switch.

  • Deutsche Bahn share links. A bookmarklet (Settings → Data → Import →
    Rail) takes a connection shared from bahn.de or DB Navigator
    (bahn.de/buchung/start?vbid=…) into the rail review dialog. bahn.de is
    asked from the browser on bahn.de itself, and the connection reaches
    TravStats in the address fragment rather than in a request to bahn.de's
    or anyone else's server; no ride is saved before review.

  • Settings closer to the agreed prototype: tabs, breadcrumb, domain
    colour dots, expert notes, search that switches to the expert level when a
    hit lives there, one-open-at-a-time service accordions, larger switches for
    touch, and a page for a switched-off domain that says how to switch it on.
    Admin geocoder settings moved to External services → Maps & place search.

  • New account settings: a default colour for new trips (automatic colours
    now rotate the same way however a trip is created), whether sea days count
    as cruise days, a "Live-Verfolgung" switch for the Companion's in-flight
    recording, and seat statistics on or off.

  • WebDAV sync per account (expert): the account's export goes to the
    user's own WebDAV share (e.g. Nextcloud) daily, weekly or on "sync now",
    gzipped, with a chosen number of kept versions; clean-up only ever deletes
    exports this account uploaded. The last result is shown with its reason;
    a run that uploaded but could not clean up says "partial". Ordinary
    accounts may use public https servers only; administrators may also use a
    share on their own network.

  • Admin → Hotel chains (expert): search, create, rename, edit loyalty
    programme name and brand colour, merge (every link moves along), and delete
    only when nothing hangs on the chain; a deleted chain does not come back
    with the next seed.

  • Normal accounts can see whether keyless instance services are switched on.

  • Map cards for every ground domain. Rail, bus, ferry and rental routes
    open a card with their own statistics — first and last journey, average
    duration with fastest and slowest, average delay, total distance with what
    it measures (air line, along the track, estimated sea route) — and, where
    one exists, a picture of the train, ship or car model with its credit.
    Stations and ports open a card with a Wikipedia photo and summary,
    departures, arrivals and top destinations. Hovering shows a compact
    profile. Pictures and Wikipedia text use the operator-logo open-data switch;
    an outage says so instead of looking like "no picture".

  • Station, terminal and port names on the map, spaced by the same label
    pass as airports and hotels.

  • Trips shared across servers (beta, federatedTripSharing): pair with a
    person on another TravStats server by invitation code, offer a trip, keep it
    in step both ways with conflicts shown, and end, pause or resume it. A server
    restored from backup, or a peer with a new key, catches up after
    confirmation.

  • The Companion's trip recording reaches the server: stored, drawn on the
    trip map with a day filter, exportable as GPX and deletable.

  • Recorded flight tracks (beta, flightTrackUpload): upload a GPX or KML
    export and see the flown line on the flight page and the maps.

  • Calendar subscription (beta, calendarFeed): a secret iCal URL for
    upcoming entries.

  • Imports from other flight apps: OpenFlights, AirTrail, Jetlog, Flighty
    and App in the Air exports.

  • Passport corrections: add, correct or exclude countries by hand.

  • Settings have one page per menu entry, with a Standard and an Expert
    level per account.

  • Template workshop: rail, bus, ferry and rental templates, learning from
    screenshots via OCR, and export for the community repository.

  • Inbox: per-user switches for trip and stay suggestions; stay cards show a
    map and the probable place.

  • Admin: a 24-hour import mode that lifts upload and import limits; the
    template repository URL is an instance setting.

  • A GPS jitter filter on every recording source before anything is measured;
    each recording says how much it left out.

  • Compare with friends is a leaderboard of totals. /compare ranks you and
    the people who agreed — kilometres, trips, time away, countries, places —
    per year or overall. Each person decides which figures the other may see,
    and a pending request shares nothing until it is accepted. Friends on other
    TravStats servers join through an invitation code; between servers only
    signed totals travel, never single trips.

  • Server connections in Admin → Instanz. The instance's identity and the
    servers it trusts are managed in one card; the key is generated there and
    never shown.

  • Ferry crossings can be shared with a trip and travel in the
    .travstats file.

  • A trip shows its travellers with their sharing state — linked, shares
    this trip, request open — and offers one action per person. A person who
    agreed but is not yet on the trip can be added from the share dialog.

  • One "Teilen" button in the trip head for a companion's copy or a public
    link.

  • Dawarich can suggest whole venues beyond markets. A separate opt-in adds shopping malls, parks, zoos, theme parks and museum grounds. Independent overlapping venues stay reviewable, and visits are recorded only after confirmation.

  • Markets are suggested as whole venues. With separate consent, Dawarich
    scans automatically fetch public OpenStreetMap market boundaries for coarse
    regions along your track. A visit across several stalls stays one suggestion,
    with original point IDs, boundary sources and visible coverage gaps. Cached
    maps, bounded requests and remembered decisions avoid repeated work and
    duplicate visits; only confirmation records a visit. Hidden Places pause
    scanning, and manual scans can review the last 7, 14 or 30 days.

  • Dawarich can suggest stays. With your consent, Dawarich location history
    is scanned for places you stayed. Each suggestion is reviewed, edited and
    accepted or rejected, and a rejection is remembered. A slow scan can no
    longer overwrite the result of a newer one, and a polling error disappears
    once a read succeeds.

  • Buses are part of "Upcoming". They appear with the same day-by-day
    countdown as trains.

  • Ferry crossings are a journey of their own. A ferry booked with a vehicle
    — operator, departure and arrival port with local times, crossing duration,
    booking reference, seat or cabin, vehicle dimensions, passengers, price and
    the ticket PDF — is now an entry like a rail or bus journey instead of a line
    in the expenses. Ports are found by search, a ticket can be previewed before
    it is saved, an optional AIS lookup shows the live position, and a crossing
    can be linked as a leg of a roadtrip. The domain sits behind the beta switch.

  • A moment without a trip has a place: notes. A note is a date (or a date and
    a time on the clock of the place it was written), a text, optionally a place
    and one photo — nothing else is assumed. Notes live under Mehr › Sammlungen,
    appear on a trip's timeline when their day falls inside it, and are private
    by default
    ; a note switched to shareable is shown only where you already
    share a trip (to the members of a shared trip, read-only, without position or
    photo; on a public link only if you pick "Notizen"). Sending a note twice
    from the phone creates it once.

  • A trip can be shared with a companion who has an account on the same
    server.
    Each person gets a linked copy; changes to the shared facts —
    flights, stays, cruises, rail, coach and rental rides, stops — reach the
    others as a notice in the inbox and can be undone; price, seat, booking
    reference and notes stay private. Consent is asked first and can be withdrawn,
    and a copy can be detached. A single trip also travels as a .travstats file
    to another instance, through a proposal you review before anything is created.

  • Public share links for a flight, a trip or a year in review, behind an
    instance switch that is off by default. You choose the fields; nothing
    else leaves the server (a test per field proves it), the link expires (a
    flight link two hours after landing), can be revoked at once, never appears
    in a server log (the token travels in the URL fragment) and carries photos
    without location data: the stripper keeps a short allow-list of JPEG and PNG
    parts and drops everything after the image, so the second image and the
    motion-photo video a phone appends are gone too.

  • Booking deadlines. Free cancellation until, payment due and online
    check-in opening are stored on stays, rentals, bookings and flights; a
    deadline known only as a day stays a day ("bis Ende 12. Oktober") and never
    gets an invented time. Templates may carry them, and a re-read mail fills a
    deadline only where it is empty.

  • Trip expenses grew up. A payer (a companion or a name), the exchange rate
    with its source (bank, cached or typed by hand), receipts that can be attached
    while creating the cost, and 13 categories. A home-currency total counts only
    what has a recorded rate and lists the rest per currency.

  • The inbox asks six more questions about your data, as questions and never
    as verdicts: possible duplicates, entries that cannot both be true (a flight
    leaving before the previous one landed, two houses on one night), a missing
    flight number, an unknown airport, a trip without an end, entries outside
    the trip's days.

  • Every statistic says how it is counted and opens the entries behind it —
    flights, cruises, lodging, places, roadtrips, tours, rail, rental, coach
    rides, the year in review and the overview: unit, time and zone rule, source,
    coverage and what is left out, in one "So wird gezählt" under each block, and
    a tap on any figure lists the entries it stands on. Extremes list the entries
    they were taken from; every one of the 192 badge rules shows what its
    progress stands on, under a work budget and a rate limit of its own.

  • The coach (bus) domain, behind the beta switch: logbook, detail page,
    trip map and timeline, statistics tab, night buses in the night account,
    badges, dashboard overlay, spreadsheet round trip and sync. A ride is drawn
    along the road when the instance has a routing service: the line is
    fetched once when the ride is saved and frozen, its length becomes the
    distance, and "Luftlinie" appears only for a ride that has no road line. An
    instance without a routing service says so in the form and keeps the straight
    line; one click routes the rides saved before ("Alle Luftlinien-Fahrten über
    die Straße berechnen"). One daily budget (300 per person, 1,500 per instance,
    under OpenRouteService's free 2,000) covers every call, and the shared demo
    account never calls the provider. Setup: docs/features/routing-provider.md.

  • Photos: a nightly scan and a review of many suggestions at once. An opt-in
    switch in Settings → Externe Dienste (it says what leaves the server and how
    the last run ended), and in the inbox visit suggestions show place, time span
    and reasoning together; you accept, correct or reject several in one go, and
    one that a logged visit already explains is flagged, not hidden.

  • Parsers moved out of the server. Issuer readers (Berge & Meer, Booking.com,
    TUI Cruises, DB, Sixt, airlines) are template files in the template
    repository, read by one generic engine with a per-document time budget; the
    home country orders templates and never filters them. The template workshop
    derives templates for cruises, places and package tours from rows you mark.

  • Package tours import as a trip: the operator's mail or PDF is read into a
    trip with its flights, stays and total price — after a preview — and a
    package booking can be entered by hand (operator, travellers, booking day).

  • Rental invoices and rental details: single fee lines on an invoice
    (refuelling, tolls, cleaning, extra km, damage handling…) are shown beside the
    booked price and taken over one by one without counting the cost twice; the
    provider list is data, with logos where the provider's site has one; deposit,
    odometer, hand-over evidence by what it shows and a compact return card.

  • Rail: a journey with changes is one logbook entry, the change between two
    trains can be marked tight, seats and tickets per train read at a glance, a
    DB share link imports a connection (and says plainly why it cannot when
    bahn.de refuses), and the import review shows unread booking facts instead of
    a dash.

  • Cruises: river ships and river cruises, kept apart in the statistics (a
    portless river day is not a sea day), a day card with time in port and an
    all-aboard time, and a booking read again is compared with the stored
    itinerary change by change.

  • Forms ask before they lose your input: closing, Back and navigation ask
    when a form changed; a field error sits at its field with a jump to the first;
    a save is never sent twice, and a create whose answer was lost offers a
    reload instead of a blind retry.

  • Help is reachable by tap, keyboard and screen reader: one toggletip for
    every field help; keyboard focus shows a 2 px outline on every control and
    field; touch targets follow the pointer, not the width.

  • Deleting an account removes its uploaded files. Photos, documents,
    receipts and note photos go with the account; an hourly sweep moves orphaned
    files to a quarantine and deletes them after 30 days — and returns them if a
    row points to them again, so a database restore to an older point cannot
    destroy newer files.

  • Creates from the phone's outbox are exactly-once for rail, coach rides,
    expenses, tours and notes (clientRef); a push reminder can be muted per trip
    on each phone.

  • A stale page repairs itself: after an update a browser holding an old page
    reloads once instead of staying blank, and says so if that fails.

  • One look for web and app. The web app now uses the Companion app's
    colours, spacing and type, one heading per page, and a dark mode built from
    the colour tokens. Settings are split into groups — flights, cruises and
    stays each have their own page — and the admin area is a page of its own.

  • Every figure explains itself. Clicking a statistic or a ranking row opens
    the entries behind it with each one's contribution; what cannot be assigned
    is named, not dropped, and the panel can be shared as a link. The running
    year is compared with the same period last year instead of a whole year.

  • Documents and receipts on their entry. Boarding passes, hotel invoices and
    confirmations are stored as documents on the flight, cruise or stay they
    belong to; price, currency and booking code can be taken over from them, each
    value shown first.

  • Costs that belong to no booking — tolls, ferries, parking, fuel — on a trip
    or a roadtrip section, counted in the cost statistics. Deleting a section
    hands its costs to the trip instead of dropping them.

  • Help while you enter. Forms suggest seats, flight numbers, terminals,
    frequent-flyer numbers, rooms, board, tags and recent currencies from your own
    history; a new entry lands in the trip whose dates it falls into. A suggestion
    never overwrites what you typed.

  • Loyalty programmes in one place — airline, hotel and cruise programmes with
    number and current status under Settings → Loyalty programmes, one button per
    alliance, and stays, nights or flights per year that lead to the list behind.

  • Trip suggestions in the inbox. TravStats reads from your flights, cruises,
    stays and place visits when you were away and proposes a trip, or the trip the
    entries belong to; nothing is created until you accept.

  • Places, passport and photos. Places are a full domain with lists,
    checklists and a CSV import that also takes a Google Takeout export; photos
    hang on places, stays, flights and cruises and in the trip journal.

  • The Excel export reads back — edit the spreadsheet and import it again, or
    carry it into another account. TravStats installs as a web app.

  • AI and open data, under the admin's control. The trip summary states only
    what is in the data; an admin can switch the AI parser off entirely, use an
    OpenAI-compatible provider (a provider outside your network only with explicit
    consent), and switch on weather from Open-Meteo and descriptions from
    Wikipedia. Dawarich location history counts as evidence for a country.

  • The Companion app (beta): pairing by QR code; push notifications for
    flight changes and departure reminders, end-to-end encrypted through a relay
    an admin switches on, with FlightAware AeroAPI as an optional status source;
    and a sync change log that never silently overwrites a newer version.

  • Behind the beta switch: roadtrips and day tours with elevation profiles,
    rail as a domain of its own, rental cars as a domain of their own, recorded
    GPS tracks for cruises, and hotel enrichment from OpenStreetMap.

  • A new demo account — an invented traveller from the Rhineland with ten
    years of travel. A new installation creates it and switches the beta features
    on as it does.

  • Add existing entries to a trip from the trip itself. "+ Eintrag
    hinzufügen" on a trip's timeline opens a picker with one tab per enabled
    domain; an entry that sits in another trip says so before it is moved.

  • A train ride with changes is one logbook entry (rail, behind the beta
    switch): the list shows "Augsburg → Hannover → Bielefeld" as one row with the
    total duration and the number of changes, a page for the whole ride lists its
    trains, and each train keeps its own page. Statistics still count trains.

  • A weight unit for the baggage allowance. Settings → Units & formats has a
    kg/lb choice; an allowance typed as a bare number ("23") is shown with it.

  • Reminder and account mails in the app's look, with a plain-text part,
    light and dark, and more of the entry's facts (terminal, gate, seat, booking
    reference; a stay's address, nights and board). Reminders go out only for
    domains you have switched on; invitation and password mails are bilingual.

  • Display settings follow you to every browser. Colours, map look, the
    dashboard's domain filter, hidden statistics sections and table columns are
    stored with your account instead of only in one browser. Page size and the
    open map panel stay per device.

  • Place names you can read, in every script. A place found in Seoul, Moscow,
    Tokyo or Cairo is named in Latin script where OpenStreetMap has one, and the
    name on the sign is kept beside it ("Gyeongbokgung Palace · 경복궁") — stored
    with the place and shown in the places list, on the place page, in the trip
    and on the map. A name is stored exactly as you typed it; an older place
    whose two halves sit in one string is split only where the map names the
    local half on its own, so "CU 삼청점" stays one name. A place saved under its
    Latin name in a country with another script gets the name on the sign added
    where OpenStreetMap knows the same object.

  • A visit finds its trip. A place visit saved without a trip goes into the
    trip whose days it falls on, when exactly one trip does; with none or several
    it stays unassigned.

  • iPhone photos (HEIC) can be attached to trips, places and stays. The
    original is kept; browsers get a JPEG copy. Capture time and position are now
    read from every uploaded photo.

  • Rental cars (beta) record a licence plate and suggest the common
    providers; rail and rental lists use the same table, header and filters as
    the other logbooks, and the map settings cover tours, roadtrips, rail and
    rentals — rentals optionally without the connecting line.

  • Rental cars (beta) take the odometer reading at pick-up and return; the
    kilometres driven follow from them unless the invoice states its own figure,
    and a return reading below the pick-up one is refused.

  • A seat reservation booked later finds its journeys (beta). Importing a
    Deutsche Bahn reservation offers to attach coach and seat to the train
    journeys already logged, shows what would change, and asks when several
    journeys fit.

  • Places nearby list the important ones first. Picking a place near you
    shows a longer list with sights, stations and landmarks ahead of shops and
    benches, and a place search prefers results near where you are.

  • The Companion can send a flight's recorded track and its observed takeoff
    and landing
    ; a reported landing marks the flight as flown at once, and the
    times arrive as suggestions to confirm.

Changed

  • The production dependencies carry no known vulnerability: DOMPurify (critical, used for PDF export), postal-mime 4.1 (.eml previews), body-parser, multer, fast-uri and zod are updated.

  • Rental cars, coach rides and ferry crossings are out of beta. They show whenever you enable the area in your settings.

  • Completing a stay from OpenStreetMap is out of beta, with a stricter name rule: a town or landmark word alone no longer matches a house, and English and German names are compared too. Measured on 200 real stays: 1 wrong match in 156 (was 2 in 152).

  • Detect places automatically is on by default with the stay scan; its two area switches are expert settings.

  • The export cuts privacy zones out of older recordings (trip recordings and flight tracks from before TravTrack). Stored data and the admin backup stay complete.

  • The README and store texts describe TravStats as a logbook first, with optional recording through the Companion.

  • The lodging import preview says what each row will do. The action reads "Aufenthalt hinzufügen", "Hotel und Aufenthalt anlegen", "Weiteren Aufenthalt anlegen" or "Aufenthalt aktualisieren" instead of a bare "Anlegen"; a matched hotel is shown with its stored name and city as plain text, with the import's spelling beside it where it differs; the summary counts what will be added, skipped and still needs a decision, and the reminder to decide only shows while something is undecided. A guessed match says what it rests on (name and city, name only, a similar name, the same place) instead of a green "Passendes Hotel gefunden"; several possible hotels offer a choice; "Keine Koordinaten" is gone from rows that join a stored hotel. "Anderes Hotel? Zuordnung aufheben" replaces "Nicht dasselbe Hotel — neu anlegen", which never created anything.

  • Recorded flight paths are off on the dashboard by default. The map
    shows routes; a recording belongs to one flight. A new map option
    "Aufgezeichnete Flugwege zeigen (wo vorhanden)" draws them as thin lines on
    top of the routes, which stay visible even when every flight on a route was
    recorded. On the flight page the recording is shown over the
    dashed great circle.

  • Ferry crossings stored as a straight line are re-routed along the sea once,
    in the background, after the update.

  • An invitation code that is retried after it already connected reads as
    "already connected".

  • The end-to-end encrypted transfer moved to its own page,
    /encrypted-share, behind its own beta switch.

  • A shared trip is copied for each person on their own calendar: a copy's
    status (planned, under way, done) follows the recipient's time zone.

  • If the recipient already logged the same flight or crossing on another of
    their trips, sharing moves that entry into the shared trip and links it
    instead of creating a duplicate; the notice says so and can be undone.

  • A provider change that reaches every member through the shared trip makes
    one inbox item, not one per person.

  • Ferry edits and deletes accept an optional read version. Conflicting writes
    return HTTP 409; edits claim the version atomically in their transaction.
    Older clients can continue to write without a version precondition.

  • Settings expose supported travel domains independently of enabled domains,
    allowing compatible clients to offer a disabled domain again.

  • TravPlan uses shared theme tokens and the selected application locale for
    number formatting.

  • Full data export includes saved TravPlan content and proposals; daily quota counters are explicitly excluded.

  • A sailed cruise is completed, not flown. The flight word leaked into
    cruises; flown is still accepted on write and read as completed, and
    stored rows were migrated.

  • Private files are served at addresses that do not end in an image or
    document extension
    (receipts, profile pictures, admin log pages), because a
    proxy that caches by extension served them without asking the app. The old
    addresses redirect.

  • Numbers follow the app's language, never the browser's.

  • A trip's entry count and the trip page include coach rides; the trip
    export, trip merge, micro-trip cleanup, delete question, countries and the AI
    summary brief know them, and so does sharing.

  • The what's-new dialog is short again — eight items — and describes what 2.7.0
    contains; a test keeps it from growing back.

  • Cruise kilometres go up. A cruise leg is now measured along the sea route
    the map draws; some legs used to count only as a straight line. Stored legs
    are recalculated once on the first start after the update.

  • Restoring a backup from an older version works. The restore empties the
    schema inside its own transaction, loads the archive and brings it up to this
    version's migrations before it reports success; a failed migration at startup
    now stops the container instead of starting on an outdated schema.

Fixed

  • Two members moving a shared trip's dates at the same moment both save. One of the two saves used to fail; and an undo that raced a member's own save could overwrite it with the old dates.

  • A replace import from a spreadsheet no longer starts a backup for the demo account or beside a backup already running.

  • Places count in every category they carry except the transit kind (forgejo#299).

  • A booked or cancelled cruise counts in no cruise figure.

  • The Dutch Sixt invoice's fee lines are read (forgejo#280, forgejo#237).

  • The ferry port search finds the port of the town you typed.

  • The year filter applies to the route network and the route list in the statistics.

  • The profile shows your real username and no placeholder e-mail address.

  • Ferry crossings are offered in the map's add menu; the narrow rail list names each ride's mode and line; on a phone the TravTrack map sits right under the range control; an empty inbox shows one message with one action; flight-track gaps are drawn dashed.

  • Uploading a document from the web works again. Every web upload had failed with "No file uploaded" since September.

  • A server no longer crashes when another server cannot be reached over IPv6 while checking it; addresses are tried IPv4 first.

  • A share link of a trip without dates ends after the trip's last entry.

  • Saving part of the display settings over the API no longer clears the time zone.

  • Station names of rail, bus and ferry on the trip map no longer print over each other; a cruise leg's hover shows its ports and sailings.

  • A skipped row no longer fails the whole lodging import. A skipped row with a cleared date or name made the server refuse every row; skipped rows are now sent without their fields.

  • "Auswahl importieren" is only enabled for a preview the server will accept. Names and cities over 200 characters, negative prices and stays over ten years are flagged on the row instead of failing the import, a price without a currency is flagged on updates as well, and a row set to add a stay with both dates cleared is flagged instead of creating nothing.

  • Picking one of several possible hotels checks that hotel's stays for the same check-in, and an update shows every changed field, an edited price or currency included.

  • Importing the same bahn.de connection twice no longer saves its rides twice. The repeat was looked up by the printed stop name, while the first import had stored the catalogue's name.

  • Two buses or trains leaving the same stop in the same minute are no longer taken for one ride. A ride counts as already logged only when its destination and its line or train number agree too; where one side names no line, the leg is kept ticked and marked "möglicherweise schon erfasst".

  • A ticket with a booking number finds a ride saved earlier from a bahn.de connection without one, and a busy day no longer hides the ride sought behind older rides at the same stop.

  • A recorded flight is drawn whole. Sparse fixes from a phone in the
    cabin were dropped as single points, so LH719 Seoul-Munich showed only its
    last third. Every fix is kept; recorded stretches are solid and the holes
    between them dashed.

  • A recording with holes no longer sets its distance against the great
    circle ("−60 %"), since it measures only its recorded stretches.

  • The start of a recorded flight is no longer hidden under the map
    attribution on the flight page.

  • TravPlan is refused by the server while the beta switch is off; before, its
    endpoints answered any signed-in client.

  • The import card promises AI reading only for the kinds of booking that
    have it.

  • The empty tours view no longer covers the list button.

  • A large KML file is read in linear time instead of blocking the server for
    seconds, and a very large one no longer crashes the reader.

  • Lodging enrichment never overwrites a value saved while OpenStreetMap was
    being asked.

  • A Deutsche Bahn share link no longer reads as a failed import. Such a
    link carries no booking reference, price or seat, so the review dialog now
    says so in one line instead of flagging every empty field as "not found in
    the document".

  • A train bahn.de names by number alone reads "Zug 57031" (EN "Train
    57031") on map cards, in the trip overview, the review and the ride
    pickers, instead of a bare number. The number is
    stored as the train number; a category is kept only where bahn.de states
    one. Rides imported from a share link in rc.20 read the same way.

  • Bus lines are drawn on the globe.

  • A Wikimedia Commons photo on a map card carries its author and licence
    where Commons provides them; a non-free local photo is not shown.

  • "Last here" handles date-only rides, and no longer names an older visit as
    the latest when a newer arrival's date is unknown.

  • Close and toggle buttons on iPad map cards are 44 px; the AI trip-summary
    offer wraps on narrow screens.

  • Deleting an account also deletes its pending sync changes.

  • A global API key is no longer shown to every user. The key-status
    answer carried stored values; it now carries only whether a key is set. A
    key the instance cannot decrypt no longer counts as "active for everyone".

  • The trip overview lists ferry crossings, and the trip map draws rail, ferry
    and rental — on the globe as well.

  • Overnight journeys show their arrival day on cards and tooltips.

  • A date-only journey no longer gets an invented duration.

  • The "far from your destinations" hotel warning considers arrivals by rail,
    bus and ferry, not only flights.

  • Map labels no longer print over each other in "All" and "Important", on the
    globe (where they also keep clear of the time control) and on the trip map.

  • A failed route or rental load on a map says so and can be retried instead of
    looking like no data.

  • iPad touch targets in the menu, the recording panel and settings follow the
    pointer, not the width.

  • The statistics breakdown names ferries in both languages.

  • A settings search result opens its folded group.

  • Sharing records an entry's author only where it is known and checks a
    received change's author.

  • Public-link lifetimes are calculated from the server clock, preventing a fast
    browser clock from rejecting “Until landing (+2 hours)” or “90 days”.
    Explicit expiry timestamps remain supported for existing API clients.

  • Public-link permission is now under Administration → Instance. Personal
    settings retain link management and point admins to the instance switch.

  • Backup retention keeps what it should, and a remote copy is deleted only
    when you say so.
    Old backups were pruned by the wrong identity. A WebDAV
    delete that fails with 401, 423 or 500 now keeps both copies and the
    database row.

  • Rail lines are re-fetched when their inputs change, and a failed fetch
    keeps the stored route.
    The distance is shown consistently.

  • A year-only or month-only flight stays in its year — in the year summary,
    the time series, the passport and the flight's own times — instead of landing
    on 31 December of the year before at airports west of UTC. The precision is
    stored with the flight.

  • Counting rules have one home. The busiest day, "connection", the time-travel
    index (landing earlier than you left, date included), a trip's cost, a trip's
    duration, "new this year" (in your zone), the country distribution (an end
    without an airport code proves no country) and the aircraft registration
    (one hull, whatever its case) each follow one rule everywhere they appear.

  • An empty value is shown as unknown, not as 0: business rates, average flight
    duration, a rail tile without timed rides. Seats are placed by the cabin's own
    layout, or not at all.

  • A Takeout re-import no longer repeats places: a place is found in every
    spelling of its Google id, and a trip stop within 100 m on the same day is not
    added twice.

  • First writes no longer race into a unique violation (display preferences,
    place-list entries): two settings saved at the same moment on a new account.

  • A fresh setup says it is set up, the welcome hint no longer covers the
    empty-state buttons, and a session that only exists as a cookie signs in.

  • Opening Settings no longer eats the limit for adding flights. The bulk-refresh
    preview shared the flight-creation limit of 20 an hour, so about twenty visits to
    Settings → Konto blocked adding flights for an hour; it now has its own limit,
    and the card shows one state, in plain words and in the reader's language.

  • One unreadable row no longer rejects a whole flight file; the preview names
    the line and the reason.

  • An expired reset link is said when the page opens, with a way to a new one.

  • The trip map frames a trip's coach rides and does not call the trip empty;
    the trip card counts them; the trip export no longer leaves them out.

  • Layout: the admin pages, the cruise statistics, a lodging tile and the
    backup form no longer widen the page on a phone; the flights toolbar and
    settings selects wrap.

  • Security and hardening: a refused cross-origin request answers 403 and not
    500; templates cannot impose unbounded regex cost on the server; the public
    share API is exempt from the origin list on purpose (it carries no cookie and
    answers no cross-origin read); dependency alerts that have a fix are patched.

  • Backups: an archive from an older version migrates inside the restore's own
    transaction, and a newer one is refused by name.

  • Smaller corrections you can see: a train ticket with a change of trains keeps
    every train; a day-only ride keeps its day in the form; the autumn hour that
    occurs twice keeps its occurrence on edit; a rental's actual return can no
    longer precede its actual pick-up; roadtrip station drafts survive a lost
    connection and are merged before they overwrite anything; overlapping stays
    are a notice on saving, never a block; two of your own places can be merged
    without losing a visit, photo or list; a hovered station, train or rental on
    the map says what it is; every table, dialog and list reaches the touch size
    on a coarse pointer.

  • A flight is "flown" once it has landed. It stayed "scheduled" for six
    hours after its scheduled arrival. A landing reported by the live flight
    data now counts at once, and a flight without live data turns an hour after
    its scheduled arrival; a delayed flight the live checks are still following
    is left alone until its arrival is recorded.

  • A trip lasts as long in the statistics as on its own page. A trip from
    the 15th to the 18th showed four days on its page and three as the average
    trip length, because the statistics counted nights.

  • A scanned boarding pass keeps its seat and booking reference. A barcode
    read in the browser filled flight and route, but left seat and booking
    reference empty although the barcode carried both.

  • An Excel export in the other language can be imported. An English
    export was refused as "no known sheets" under a German interface, and the
    other way round.

  • A roadtrip still underway calls its distance "Strecke · geplant" instead of
    "Gefahren", which counted legs that were still ahead.

  • A stay's page labels its per-night figure as the average of the total
    ("Ø Gesamtkosten pro Nacht"), so it no longer reads like the room rate.

  • A flight imported twice says it is already in the logbook and offers to open
    it, instead of asking you to check correct input.

  • German counts use the singular: "1 Flug", "1 Fahrt", "1 Miete", and on the
    roadtrip card "1 Nacht", "1 Station", "1 Tour".

  • Rail text import keeps operator, booking number, class and price.

  • The hotel and cruise import previews are reachable by keyboard; a dialog no
    longer loses its focus while it saves; every field of the flight review is
    named by its label.

  • A roadtrip that has not started no longer claims more days ahead than it has.

  • A plain flight confirmation keeps its booking reference and both times when
    read without an AI model.

  • The trip card counts rail and rental entries; the rental form accepts a
    German decimal comma.

  • A first import of Deutsche Bahn tickets gets through. The Online-Ticket
    layout DB prints since spring 2024 is read without an AI model; before, only
    tickets in the older layout were. Saving train journeys no longer stops after
    twenty in an hour (now 300), and reading PDFs no longer after twenty in
    fifteen minutes (now 60).

  • A Deutsche Bahn ticket in the new layout WITH a change of trains keeps every
    train, each with its coach and seat (rc.5 read only the first).

  • A dialog no longer closes when a text selection ends beside it. Selecting
    a field's text and letting go of the mouse outside the dialog closed it and
    took the form with it.

  • The flight list keeps the planned and the actual time side by side again;
    the actual time had wrapped onto a line of its own.

  • The stay reminder mail linked a page that does not exist.

  • The rail import asks the next AI provider when the first one does not
    answer. An Ollama address that was entered once and no longer runs used to
    make every ticket "AI parser not reachable" while a configured OpenAI key
    was never asked.

  • Every parser — stays, cruises, flights and the trip summary, not only rail —
    now asks the next AI provider when the first one does not answer.

  • A flight's takeoff is known while it is in the air. One live check now
    runs 30 minutes after departure; before, a long-haul flight's actual
    departure arrived only shortly before landing.

  • Hovering a train, a station or a rental on the map says what it is.

  • A rail or rental list that cannot load says so in amber with a retry, and the
    figures above those lists count the whole filtered list, not just one page.

  • Restoring a backup from an older version runs the missing migrations in
    the same transaction, so a failure leaves the database as it was; a backup
    from a newer version is refused, and the server no longer starts on a
    half-finished migration.

  • A request from a foreign web origin is refused with 403 instead of a server
    error.

  • The rail form labels the arrival delay and keeps it beside the arrival time.

  • The rental list names the car actually driven before the booked class, shows
    a status on every rental, and a rental returned where it was picked up is
    drawn as one station dot.

  • A Hawaiian place name with an okina (ʻ) is no longer treated as a foreign
    script.

  • A train ride with changes is one ride. It gets one reminder and one "next
    up" entry, named by where it ends ("Deine Fahrt nach Wien"), instead of one
    per train; a single train is named by its destination too.

  • The name on the sign is added only from the place itself: a longer map name
    counts only when it adds what kind of place it is ("Jongmyo Shrine"), not
    when it names another object ("Mount Fuji Weather Station").

  • The Companion can tell an unknown flight from a server that does not offer
    the route: the flight routes answer FLIGHT_NOT_FOUND.

Audit fixes first written for 2.6.3-rc.1

A second instance audited the tree from the outside and reported forty-two
findings; forty are fixed here, along with a crash found separately. Nothing
here adds a feature — it is the release where a number that was wrong becomes
right, and where several doors that were open get shut. Three of the fixes
change figures that are already on screen; they are named below.

Security

  • A receipt file belongs to whoever uploaded it. Knowing another account's
    receipt URL was enough to obtain the file: permission was derived from "does
    this caller own something that points at this file", and a caller writes their
    own entries — so pointing at a stranger's receipt was enough to be allowed it.
    The uploader is now recorded at upload time, from the session, where no
    request can reach it. Existing receipts keep working.
  • A stay, a cruise or a booking can only be filed under your own trip. The
    server checked the hotel a stay was nested under and then took the trip,
    booking and loyalty card from the request without asking whose they were. One
    account could file an entry against another account's trip, and it then
    appeared on that person's own timeline.
  • A read-only access token can no longer switch on two-factor or delete a
    passkey.
    Those decide who gets in, and a token that may write travel data has
    no business making them.
  • Two-factor is asked before a forced password change, on every door. An
    administrator's forced password change simply did not apply to an account with
    two-factor switched on.
  • Changing a password ends every other session. The sign-in cookie carried
    only an account and an expiry, so somebody already signed in stayed signed in
    for up to a week after the account was recovered.
  • An empty instance can only have one first administrator. Two registrations
    arriving together both counted zero users and both became admin.
  • A long API key is no longer stored unprotected. The check for "is this
    already encrypted" guessed from length and shape, and a long hex token
    satisfied the guess — so it was stored as typed and then read back as nothing,
    leaving the provider looking unconfigured while the key sat in the clear.
  • One unreadable image no longer takes the service down. A photograph the
    text recognition could not decode ended the whole server process; from outside
    it looked like a flaky gateway. It answers with an error now.
  • The map library's critical vulnerability is closed (MapLibre 6).

Fixed

  • Confirming flight detection no longer deletes your other trips. It ended by
    removing every trip with no flight on it — which is every rail trip, every
    cruise, every hotel weekend — and their stops, routes, photographs and journal
    entries went with them. It ran even when the run created nothing at all, so
    confirming the dialog with nothing selected was enough.
  • Merging two trips keeps everything on them. Hotel stays and visited places
    lost the trip they belonged to; a linked photo album was deleted, and it took
    photographs the merge had just moved onto the surviving trip with it.
  • "Tidy up" only offers trips that really are empty. A trip carrying a hotel
    stay, a visited place, a linked album, a summary, a cover image or tags counted
    as empty and was offered for removal — pre-selected.
  • A merged trip keeps its cover image. The picture survived; the link to it
    still named the trip that had just been merged away, so the cover came back
    blank.
  • Restoring a backup works, and says so honestly. Restored uploads landed one
    directory too deep and could not be found under the names the database had
    kept; a restore over an existing database reported success while changing
    nothing, because the tool logged its errors and exited zero. The restore dialog
    also offered a field the server never read and no longer shows it, and it now
    fits on a small screen, announces itself to a screen reader, and closes on
    Escape.
  • Deleting a hotel deletes its photographs. The entries went; the image files
    stayed on disk for ever, inside every backup, with nothing left that could name
    them.
  • A rejected upload does not stay on disk. One bad request was enough to
    leave a file behind, quietly, every time.
  • Clearing a hotel stay's dates clears what hung off them. The dates went,
    but the check-in and check-out times stayed on a stay with no day to hang them
    on, the status came out wrong, and the exchange-rate day stayed on the old
    date.
  • A stay's price counts the nights it actually had. A stay recorded without
    dates but with a night count got no total at all, and one dated only by month
    was billed for the whole month. An explicitly free stay was billed at the
    per-night rate instead of staying free.
  • A flight cannot arrive before it departs, and an ordinary westward flight is
    no longer refused.
    Order was decided by comparing two wall-clock times read
    off two different clocks, so Munich 10:00 to London 09:45 — forty-five minutes
    in the air — was rejected, while London 10:00 to Berlin 10:30 was stored as a
    flight that lands half an hour before take-off. This changes stored durations
    for flights that crossed a time zone.
  • A bulk import stores what a single entry stores. Cabin class, aircraft
    registration, Mode-S address and every special-flight field were accepted and
    then dropped, so a flight imported as First Class carried a first-class carbon
    figure against a blank cabin. Imported prices also had no converted amount.
  • Cost per hour and per kilometre ignore what they could not convert. A
    booking in a currency with no available rate contributed its distance and its
    hours to the average while contributing nothing to the cost, so the rates read
    far cheaper than they were. This raises the cost figures on the statistics
    page.
  • A trip without a flight follows its own dates. A hand-made trip stayed
    "completed" after being moved into the future, through the edit, an explicit
    recalculation and the nightly pass alike. Trips built from hotel stays alone
    are now derived too. This corrects the status of existing trips.
  • Trip detection keeps the flight you took, not the one that was cancelled. A
    cancelled leg beat its rebooking purely by being first in the list, and two
    genuine departures from the same airport on one day were treated as a
    duplicate.
  • A recorded track does not invent the stretch it did not record. A GPX file
    marks where recording stopped and restarted; those gaps were joined into a
    straight line and counted as distance travelled. Adopting a track for a leg
    also re-measured the simplified line and came out short of the figure shown
    beside it.
  • A change made while settings are saving is not lost. On a slow connection
    the page marked the newer edit as saved and never sent it.
  • Signing in as another account keeps that account's e-mail address. The
    guard against leftovers from the previous account ran too late and deleted the
    address the server had just supplied — and the next save wrote the blank back.
  • A bookmarked hotel, place, cruise or trip opens. Opening a detail page
    directly bounced back to the dashboard while the settings were still loading.
  • Settings survive a round trip. The cost and tail-number switches came back
    to their defaults after saving, and cruise defaults reverted in a second
    browser, taking the good values with them on the next save.
  • Seven flight fields are stored, and a delay follows its own schedule. They
    were accepted and written nowhere; a corrected departure time left the old
    delay standing beside it.
  • The profile form can be used with a screen reader, and the account name is
    shown rather than offered for editing — saving it stored a second name that the
    next load replaced.
  • Moving a stop moves the leg that ends at it. The distance stayed as it was;
    a hand-drawn line now keeps its shape and is marked as needing re-anchoring
    instead of being silently trusted.
  • The last English word in the German settings navigation is translated
    (#321).

Changed

  • An instance's own settings are one record, and are read as one. Nothing in
    the database said the settings row was unique, and eleven places created one if
    they found none — so two requests arriving together on a fresh instance could
    make two, after which a setting saved on one page was read from the other.
  • The map keeps its colours. The map rendering library stays on its current
    major version behind a compatibility bridge; the newer one draws every arc
    white.