- Add tool annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint) to all 40+ tools
- Register 3 MCP prompts: trip-summary, packing-list, budget-overview
- Add explicit mimeType: application/json to all resource registrations
- Announce capabilities with listChanged on resources, tools, prompts
- Update server name to 'TREK MCP' in MCP initialization
Handle European number formats (e.g. 1.150,32) by detecting the last
separator as decimal and stripping thousand separators. Applied to
budget inline edit cells, add item row, and reservation price field.
Fixes#498
Adds a dedicated download button (blob-based, works on iOS WebApp)
to file cards, file preview modal, and image lightbox. Previously
only "open in tab" was available which doesn't work for non-browser
file types like .gpx on iOS.
Fixes#462
- Notifications: map raw avatar filename to /uploads/avatars/ URL in
getNotifications, createNotification broadcasts, and respond handler
- Admin listUsers: include avatar field in SELECT and map to avatar_url
- Admin page: render actual avatar image instead of initial letter only
- Budget loadItemMembers: map avatar to avatar_url (fixed in prior commit)
Fixes#507
Adds a collapse/expand toggle to the day detail panel header.
Collapsed state persists across day switches. Clicking the header
or the chevron button toggles between compact header-only view
and the full detail panel.
Closes#457
Three distinct bugs caused infinite OIDC redirect loops:
1. After logout, navigating to /login with no signal to suppress the
auto-redirect caused the login page to immediately re-trigger the
OIDC flow. Fixed by passing `{ state: { noRedirect: true } }` via
React Router's navigation state (not URL params, which were fragile
due to async cleanup timing) from all logout call sites.
2. On the OIDC callback page (/login?oidc_code=...), App.tsx's
mount-level loadUser() fired concurrently with the LoginPage's
exchange fetch. The App-level call had no cookie yet and got a 401,
which (if it resolved after the successful exchange loadUser()) would
overwrite isAuthenticated back to false. Fixed by skipping loadUser()
in App.tsx when the initial path is /login.
3. React 18 StrictMode double-invokes useEffect. The first run called
window.history.replaceState to clean the oidc_code from the URL
before starting the async exchange, so the second run saw no
oidc_code and fell through to the getAppConfig auto-redirect, firing
window.location.href = '/api/auth/oidc/login' before the exchange
could complete. Fixed by adding a useRef guard to prevent
double-execution and moving replaceState into the fetch callbacks so
the URL is only cleaned after the exchange resolves.
Also adds login.oidcLoggedOut translation key in all 14 languages to
show "You have been logged out" instead of the generic OIDC-only
message when landing on /login after an intentional logout.
Closes#491
MAPS-024 and MAPS-026 were asserting < 100ms on adversarial regex input,
which passed locally but flaked on CI runners (~150-170ms). These are not
cases of catastrophic backtracking — true ReDoS would take seconds, not
~150ms. Raise the threshold to 500ms to remain meaningful while being
reliable across environments.
- Fix SEC-005: rewrite path traversal test to upload a real file, inject
traversal filename into DB, and assert the download does not succeed
- Fix SEC-007: rename misleading test description to reflect it tests
rejection of an invalid token, not acceptance of a valid one
- Delete health.test.ts: all 3 tests were exact duplicates of auth.test.ts
and misc.test.ts
- Remove duplicate describe blocks from misc.test.ts: Categories endpoint
(duplicate of categories.test.ts) and App config (duplicate of auth.test.ts)
- Remove TRIP-016 from trips.test.ts: weaker duplicate of TRIP-007 (no body
assertion)
- Remove API Keys describe block from profile.test.ts: canonical copy lives
in security.test.ts where it belongs
- Remove avatarUrl describe block from budgetService.test.ts: identical tests
already exist in authService.test.ts; drop now-unused import
- Add DB verification to ASSIGN-007 and PACK-006 reorder tests: query
day_assignments / packing_items after PUT reorder to confirm order changed
- Strengthen BUDGET-007/008/009: add member/payer setup and assert concrete
values (total_paid, per-user balance, flow direction and amount)
- Remove 6 pointless Map-semantics tests from inAppNotificationActions.test.ts;
keep only the two built-in registration checks
- Remove 5 passthrough tests from queryHelpers.test.ts; keep the 4 tests that
cover actual flat-to-nested transformation logic
- Exclude place-assigned reservations from timeline to prevent duplicate display
- Use selected day's date instead of today when entering time without date
- Pass day_id when updating reservations, not only when creating
- 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)
Bidirectional substring matching in isVisitedFeature caused unrelated
regions to be highlighted as visited (e.g. selecting Nordrhein-Westfalen
also marked Nord France due to "nord" being a substring match).
Replace the fuzzy loop with an additional exact check against the Natural
Earth name_en property to cover English-vs-native name mismatches.
Also fix Nominatim field priority to prefer state over county so
reverse-geocoded places resolve to the correct admin-1 level.
Adds integration tests ATLAS-009 through ATLAS-011 covering mark/unmark
region endpoints and user isolation.
Fixes#446
Timed places now auto-sort chronologically when a time is set.
Untimed places can be freely dragged between timed items.
Transports are inserted by time with per-day position override.
Fixes regression from multi-day spanning PR that removed timed/untimed split.
When a client disconnects mid-stream, headers are already sent so the
catch block now calls response.end() before returning, preventing the
socket from being left open and crashing the server. Fixes#445.
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.
If the budget category stored in reservation metadata was deleted, the
form would re-submit it on next save, resurrecting the deleted category.
Now validates against live budget items on form init and falls back to
auto-generation when the stored category is gone.
Closes#442
If a user's last visited tab belongs to an addon that gets disabled while
they are away, re-opening the trip now resets the active tab to 'plan'
instead of rendering the inaccessible addon page.
Closes#441
The navigateTo function was clearing lightboxInfo without re-fetching it,
causing the EXIF sidebar to disappear and nav button placement to break.
Mirrors the fetch logic already present in the thumbnail click handler.
Fixes#439