saveEndpoints was bound at module load via db.transaction(...). When the
demo-mode hourly reset (or a self-hoster's backup restore) closes the DB
connection and reinitialises it, the bound transaction still references
the now-closed connection — every subsequent reservation save with an
endpoints field throws "The database connection is not open", which the
client surfaces as "Internal server error".
Bind the transaction lazily on each call so it always runs against the
current connection.
v3.0.0 switched the planner from rendering reservations by
reservation_time to rendering them by day_id (commit 3f61e1c), but
migration 110 only backfilled day_id for transport types. Tours,
restaurants, events and 'other' bookings kept whatever day_id was
stored in the DB — often the trip's first day, from older code paths
that defaulted it there — so after the upgrade those rows all show
up on day 1 regardless of their actual reservation_time.
- Migration 122: for every non-hotel reservation, null out any
day_id / end_day_id that does not match the reservation's time,
then backfill it from reservation_time / reservation_end_time.
Idempotent; leaves already-correct rows alone.
- reservationService.createReservation / updateReservation now
derive day_id / end_day_id from reservation_time /
reservation_end_time when the client didn't send one explicitly,
so the mismatch cannot reappear on new or edited bookings.
Hotels are skipped because they store their date range on the
linked day_accommodation.
When clearing the accommodation place from a hotel reservation, the
update branch that runs without a place_id omitted the column from its
UPDATE statement, leaving the old place linked in day_accommodations.
Collapse the two branches into one that always writes place_id (null or value).
Hotel reservations store their date range in day_accommodations rather
than on reservation_time, so the card date block never rendered. Pull
accommodation_start_day_id / accommodation_end_day_id from the SQL join
and surface them on the card.
Also apply Maurice's badge-pill pattern (day name + localized date pill)
to the day-range display, consistent with the modal day selectors.
- Remove NOT NULL constraint on day_accommodations.place_id (migration)
and change ON DELETE CASCADE → SET NULL so deleting a place no longer
cascades to the accommodation row
- Switch listAccommodations / getAccommodationWithPlace to LEFT JOIN so
accommodations without a linked place are visible to the modal
- Relax create/update guards in reservationService to only require
start_day_id + end_day_id, not place_id; place_id remains optional
- Client save guard now sends create_accommodation whenever FROM/TO days
are set, regardless of whether a hotel place was selected
- Add re-hydration useEffect in ReservationModal to back-fill hotel
fields from the accommodations prop when it arrives after modal opens
(race between isOpen and the tripAccommodations fetch)
- Fix demo-seed TDZ crash: move db Proxy declaration before DEMO_MODE
block so circular require in demo-reset resolves correctly
- Sidebar accommodation badge falls back to reservation title when
place_name is null; click/cursor disabled for placeless accommodations
- listAccommodations now joins reservations to expose reservation_title
Introduces a TransportModal for creating/editing flight, train, car, and cruise
reservations that span multiple days. Transport entries now break the map route
into disconnected segments so the polyline reflects actual travel legs.
- Add TransportModal with airport/location pickers, multi-day date range, and all transport types
- Extend DB schema with end_day_id on reservations (migration 110) and backfill from existing dates
- Refactor useRouteCalculation to emit [][][number,number] segments split at transport boundaries
- Update MapView, DayPlanSidebar, ReservationsPanel, TripPlannerPage to wire up transport flow
- Add transport i18n keys across all 15 languages
Adds from/to endpoints to flight/train/cruise/car reservations with
live map rendering. Flights use geodesic arcs and a curved duration +
distance badge; train/car/cruise render as straight or geodesic lines
with endpoint markers. Airports come from an embedded OurAirports
database (~3200 airports, offline-capable); train/cruise/car locations
via Nominatim. Per-trip connection toggle sits in the day plan
sidebar, persisted in localStorage. Clicking a map endpoint opens the
existing transport detail popup. New display setting toggles endpoint
labels on the map. Migration 105 adds the reservation_endpoints table
plus needs_review flag; existing flights are backfilled from their
IATA metadata on server startup.
- Add check_in_end column to day_accommodations (Migration 102)
- Server: create/update accommodation accepts check_in_end
- Bidirectional sync: check_in_end synced between accommodation
and linked reservation metadata (check_in_end_time)
- DayDetailPanel: shows check-in range (e.g. "14:00 – 22:00"),
new "Until" time picker in hotel form
- ReservationModal: new check-in-until field for hotel bookings
- ReservationsPanel: displays check-in range in metadata cells
- i18n: checkInUntil keys in all 15 languages
Closes#366
When a place/accommodation is deleted, existing reservations still
reference the now-gone accommodation_id. Validate that the linked
accommodation exists before updating; clear to null if it doesn't.
- Clear reservation_time fields when switching booking type to hotel (#459)
- Parse date-only reservation_end_time correctly on edit (#455)
- Show end date on booking cards for date-only values (#455)
- Add auth token to file download links in bookings (#454)
- Account for timezone offsets in flight time validation (#456)
Reordering places on one day of a multi-day reservation no longer
affects the order on other days. Transport positions are now stored
per-day in a new reservation_day_positions table instead of a single
global day_plan_position on the reservation.