Repository navigation
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.
/compareranks 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
.travstatsfile. -
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.travstatsfile
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, notflown. The flight word leaked into
cruises;flownis still accepted on write and read ascompleted, 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 answerFLIGHT_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.