Commit Graph

234 Commits

Author SHA1 Message Date
Maurice
efeff0ba9e Add upload loading indicator for journey photos (#622)
- Show spinner and "Uploading..." text on photo upload button in entry editor
- Show spinner on gallery view upload button during upload
- Disable upload buttons while upload is in progress
- Add i18n key journey.editor.uploading for all 14 languages
2026-04-14 20:12:15 +02:00
Maurice
b3571f391a Fix skeleton entry deletion and add hide suggestions toggle (#619)
- Revert filled skeleton entries back to skeleton on delete instead of permanently removing them
- Add per-user hide_skeletons preference on journey_contributors (migration 99)
- Add PATCH /journeys/:id/preferences endpoint for toggling skeleton visibility
- Add Eye/EyeOff toggle button with custom tooltip in journey detail header
- Filter skeleton entries from timeline when hidden
- Add i18n keys for all 14 languages
2026-04-14 19:58:13 +02:00
jubnl
5b99efce06
fix(places): add notes textarea to place edit form (#596)
Notes field was writable via MCP but had no UI input in PlaceFormModal.
2026-04-14 15:38:39 +02:00
Maurice
88e1d075e0 fix(build): add ScrollTrigger component, fix JSX syntax, dedup i18n
- Add missing ScrollTrigger component for infinite scroll
- Fix JSX placement inside ternary expression
- Remove 290 duplicate i18n keys across 13 translation files
- Fix it.ts duplicate memories.saveError
2026-04-13 21:55:59 +02:00
Maurice
7e3cb29c57 fix(journey): album photos, select-all, heading/hr fixes, dark mode
- Load actual album photos instead of date-range search fallback
  (new GET /albums/:id/photos for Immich + Synology)
- Add select all / deselect all toggle in photo picker
- Normalize Markdown headings to plain text in journal stories
- Fix setext headings (---) rendering as hr instead of h2
- Add remark-breaks for proper line break rendering
- Fix pros/cons dark mode gradient backgrounds
- i18n: selectAll/deselectAll in 14 languages
2026-04-13 21:06:15 +02:00
Maurice
c0c59b6d80 feat: unified photo provider abstraction layer (#584)
Introduce trek_photos as central photo registry. Frontend uses
/api/photos/:id/:kind instead of provider-specific URLs. Adding
a new photo provider is now backend-only work.

- New trek_photos table (migration 98) with photo_id FK in
  trip_photos and journey_photos
- Unified /api/photos/:id/thumbnail|original|info endpoint
- photoResolverService for central resolution and streaming
- ProviderPicker: add "All Photos" tab, rename tabs, fix i18n
- Localize all hardcoded strings in JourneyDetailPage (14 langs)
- Fix date formatting to use browser locale instead of hardcoded 'en'
- Journey stats as styled tile cards
2026-04-13 20:08:31 +02:00
Ben Haas
479ab49d67
Merge branch 'dev' into search-auto-complete 2026-04-13 08:47:36 -07:00
Ben Haas
1a51f8e3e1
Add translations for "Loading place details…" and improve place search functionality
- Integrate a loading spinner for "Name" input field during place search.
- Enhance OpenStreetMap place detail retrieval with Nominatim lookup.
- Update `authStore` to track Google Maps API key presence.
2026-04-13 08:28:34 -07:00
Marco Sadowski
18da5aed39
Merge branch 'dev' into feature/naver-support 2026-04-13 10:04:28 +02:00
Isaias Tavares
60c5755647 fix(i18n): remove only true duplicate translation keys in 8 language files 2026-04-12 20:10:07 -03:00
Isaias Tavares
b84381a8de Revert "fix(i18n): remove duplicate translation keys in 8 language files"
This reverts commit c19e65b46b.
2026-04-12 20:09:35 -03:00
Isaias Tavares
c19e65b46b fix(i18n): remove duplicate translation keys in 8 language files 2026-04-12 20:04:32 -03:00
Isaias Tavares
bf3649942c refactor(i18n): add locale to SUPPORTED_LANGUAGES and derive LOCALES from it
LOCALES is now built via Object.fromEntries from SUPPORTED_LANGUAGES,
so adding a new language only requires one change in supportedLanguages.ts.
Also types translations as Record<SupportedLanguageCode, ...> so TypeScript
enforces that every supported language has a translation entry.
2026-04-12 20:03:57 -03:00
Isaias Tavares
91f7c3778f refactor(i18n): extract SUPPORTED_LANGUAGES to avoid duplication
Move language list to supportedLanguages.ts so TranslationContext and
settingsStore can import from a single source of truth, eliminating
the hardcoded array in setLanguageTransient.
2026-04-12 20:03:57 -03:00
Isaias Tavares
abed22661a fix(login): address PR review feedback
- Use apiClient instead of raw fetch() in configApi.getPublicConfig
- Validate DEFAULT_LANGUAGE against supported codes on server startup
- Log warning instead of silently swallowing fetch errors in LoginPage
- Case-insensitive browser language matching in detectBrowserLanguage
- Guard against undefined navigator in detectBrowserLanguage
- Validate language code in setLanguageTransient before applying
- Import directly from TranslationContext instead of barrel index
2026-04-12 20:03:57 -03:00
Isaias Tavares
57503a6a10 feat(login): add language dropdown, browser auto-detection and configurable default
Replace the language cycling button on the login page with a dropdown
showing all 14 supported languages. Add automatic browser/OS language
detection via navigator.languages, falling back to a configurable
DEFAULT_LANGUAGE env var, then 'en' as last resort.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 20:03:57 -03:00
Isaias Tavares
137c6ff9dd fix(i18n): standardize ellipsis to three dots (...) for consistency
Revert common.loading and common.saving from Unicode ellipsis (…) back to
three dots (...) to match the rest of the project (e.g. "Optional caption...").
Update 4 test files that were incorrectly using the Unicode ellipsis character.
2026-04-12 17:41:14 -03:00
Isaias Tavares
af789b7f7c fix(i18n): translate hardcoded strings in JourneyDetailPage and fix ellipsis in all languages
- Replace all remaining hardcoded strings in JourneyDetailPage JourneySettingsDialog with t() calls
- Add 14 missing translation keys to all 13 non-English language files
  (trips.member*, common.expand/collapse, inspector.remove, memories.*, journey.*)
- Fix common.loading and common.saving to use Unicode ellipsis (…) instead of three dots (...)
- Update 4 test files that expected three-dot ellipsis to use Unicode ellipsis
- All 2541 tests passing
2026-04-12 17:29:11 -03:00
Isaias Tavares
0fe1c443e9 fix(i18n): translate remaining German hardcoded strings in PhotoUpload
Replace 6 hardcoded German strings in PhotoUpload.tsx with t() calls:
- 'Tag verknüpfen' → t('photos.linkDay')
- 'Kein Tag' / 'Tag N' → t('photos.noDay') / t('photos.dayLabel')
- '{N} Foto(s) ausgewählt' → t('photos.photoSelected/photosSelected')
- 'bis zu 30 Fotos' hint → t('photos.fileTypeHint')
- 'Wird hochgeladen...' → t('common.uploading')

Add all 6 new keys to all 14 language files and update test
assertions from German strings to English equivalents.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 16:53:50 -03:00
Isaias Tavares
9c42a01391 fix(i18n): comprehensive translation audit and fixes across all 14 languages
- Fix critical bug: Photos and Files pages had German text hardcoded in JSX,
  now use t() keys visible correctly in all languages
- Add 16 new translation keys (photos/files UI, login validation, common errors,
  rate limit message) across all 14 language files
- Add missing keys in packing, memories, and budget sections for br, de, it, es,
  fr, nl, pl, cs, hu, ru, zh, zh-TW, ar
- Add 152+ missing keys for zh-TW (entire sections were absent)
- Change Vacay addon name to 'Férias' in pt-BR only
- Add client-side HTTP 429 interceptor that shows translated rate limit message
- Replace hardcoded English fallbacks in TripPlannerPage, DayPlanSidebar,
  DisplaySettingsTab, MapSettingsTab, AccountTab, and TodoListPanel with t()

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 16:36:32 -03:00
Maurice
f323952012 feat: configurable week start day in Vacay (Monday or Sunday)
- New setting in Vacay Settings to choose Mon or Sun as week start
- DB migration adds week_start column to vacay_plans (default: Monday)
- Calendar grid and weekday headers adapt to the selected start day
- Weekend column highlighting works correctly for both modes
- Translations added for all 14 languages
2026-04-12 02:18:45 +02:00
jubnl
bfd2553d1e
feat(auth): split OIDC_ONLY into granular auth toggles
Replaces the coarse oidc_only + allow_registration settings with four
independent toggles: password_login, password_registration, oidc_login,
oidc_registration. Each can be enabled/disabled individually in
Admin > Settings without affecting the others.

- Add resolveAuthToggles() in authService.ts as the central resolver;
  falls back to legacy oidc_only/allow_registration keys when new keys
  are absent (backward compat)
- OIDC_ONLY env var still works and overrides DB toggles for password_*,
  with a visual lock in the admin UI when active
- Server enforces lockout prevention: cannot disable all login methods
- oidc_login gate added to OIDC /login and /callback routes
- Remove oidc_only toggle from OIDC settings panel; replaced by the
  granular toggles in the Settings tab
- Add 6 new resolveAuthToggles() unit tests; fix AUTH-DB-033 error
  message assertion
- Update OIDC_ONLY descriptions in README, docker-compose, Helm values,
  Unraid template, and .env.example to clarify override semantics

Closes #492
2026-04-11 20:21:36 +02:00
Maurice
956c4270df merge: resolve conflicts with dev, fix 7 Snyk security issues
- Resolve translation conflicts (keep both journey + OAuth scope keys)
- Resolve migrations.ts (dev OAuth migrations + journey migrations)
- Fix hono directory traversal, response splitting, input validation (CVE-2026-39407/08/09/10)
- Fix @hono/node-server directory traversal (CVE-2026-39406)
- Fix nodemailer CRLF injection (upgrade to 8.0.5)
2026-04-11 19:11:21 +02:00
Maurice
13956804c2 feat: Journey addon — travel journal with entries, photos, public sharing & PDF export
- 5-table schema (journeys, entries, photos, trips, contributors) with migrations 87-91
- Trip-to-Journey sync engine with skeleton entries and photo sync
- Full CRUD API for journeys, entries, photos with Immich/Synology integration
- Timeline, Gallery and Map views with entry editor (markdown, mood, weather, pros/cons)
- Journey frontpage with hero card, stats and trip suggestions
- Public share links with token-based access and photo proxy
- PDF photo book export (Polarsteps-inspired)
- Dashboard redesign: mobile greeting, live trip hero, quick actions, unified card design
- BottomNav profile sheet with settings/admin/logout
- DayPlan mobile inline place picker
- TripFormModal members management
- Vacay calendar trip date indicator dots
- Fix contributor photo access (403) for journey Immich/Synology photos
- Trip deletion cleanup for journey skeleton entries
- i18n: 231 new keys across all 14 languages (native translations, no fallbacks)
2026-04-11 19:01:34 +02:00
jubnl
38cd318a82
fix: replace hardcoded 'Immich' with {provider_name} in memories.saved toast
12 of 14 language files showed 'Immich-Einstellungen gespeichert' (or
equivalent) instead of the actual provider name when saving settings.
The frontend already passes provider_name to the translation function;
only the translation strings were wrong.
2026-04-11 18:55:12 +02:00
jubnl
7871c06059
feat: enhance Synology Photos integration with OTP, SSL skip, and better UX
- Fix endpoint path: users now provide full base URL (e.g. https://nas:5001/photo)
- Add OTP/2FA field for Synology login
- Add skip SSL verification option (DB column + checkbox UI)
- Add device ID (synology_did) column for session tracking
- Trigger in-app notification when Synology session is cleared
- Show disconnection banner in MemoriesPanel
- Add URL hint in provider settings
- Map Synology API error codes to human-readable messages
- Update i18n for all locales
2026-04-11 18:25:42 +02:00
xenocent
577f2b05ca feat(i18n): add Indonesian translation 2026-04-11 15:26:16 +07:00
jubnl
535c06bb3f
feat(mcp): granular OAuth scopes and per-client rate limiting
- Split `media:read` into `geo:read` and `weather:read` scopes
- Add dedicated `atlas:read/write` scopes (previously under `places`)
- Add dedicated `todos:read/write` scopes (previously under `collab`)
- Rate limiting now keyed by userId+clientId instead of userId alone
- Bind MCP sessions to the OAuth client that created them
- Log MCP tool calls to audit log with clientId
- Invalidate all MCP sessions on addon state change
- Reduce session sweep interval from 10min to 1min
- Update all translations with new scope labels
2026-04-11 02:06:32 +02:00
Marco Sadowski
6a632137ed refactor(trip): Naver List Import as Addon 2026-04-10 15:37:38 +02:00
Marco Sadowski
f82f00216b Merge remote-tracking branch 'origin/dev' into naver-list-import 2026-04-10 15:35:16 +02:00
jubnl
4b1286d53c
feat(admin): add OAuth sessions to MCP Access panel
Show active OAuth sessions (first) and static API tokens (second) in
the admin MCP Access tab. Admins can revoke any OAuth session, which
immediately terminates the live MCP transport for that client.

- Add admin-level listOAuthSessions / revokeOAuthSession in adminService
- Add GET /admin/oauth-sessions and DELETE /admin/oauth-sessions/:id routes
- Restructure AdminMcpTokensPanel into two sections; rename tab to MCP Access
- Fix stale writeAudit call in rotate-jwt-secret route (user_id → userId)
- Add admin.oauthSessions.* i18n keys across all 14 locale files
2026-04-10 06:47:35 +02:00
jubnl
9b1baaf7b8
feat(oauth): browser-initiated dynamic client registration (DCR)
Adds an OAuth 2.1 public client registration flow so MCP clients can
self-register via a user-facing consent page instead of requiring manual
setup in Settings.

Server:
- DB migration adds `is_public` and `created_via` columns to oauth_clients
- New GET /api/oauth/register/validate — validates DCR params, returns
  requested scopes; unauthenticated callers get loginRequired flag
- New POST /api/oauth/register — creates a public client, saves consent,
  and redirects with client_id (cookie auth required)
- `authenticateClient` / `refreshTokens` skip secret check for public
  clients (PKCE provides the security guarantee)
- `createOAuthClient` accepts options for isPublic/createdVia; public
  clients store an opaque secret hash instead of a usable secret
- `rotateOAuthClientSecret` blocked on public clients
- `isValidRedirectUri` extracted as a shared helper
- Discovery metadata now advertises registration_endpoint and auth method
  `none`; token/revoke endpoints no longer require client_secret for
  public clients

Client:
- New OAuthRegisterPage (/oauth/register) — loading → optional
  login-required gate → scope selection → done states
- New ScopeGroupPicker component — collapsible groups, indeterminate
  checkboxes, select-all per group or globally
- oauthApi.register.{validate,submit} added to api/client.ts
- apiClient exported so it can be reused outside api/client.ts
- IntegrationsTab tests fixed for new collapsible section structure
- collab_notes fallback changed from undefined to [] in MCP trip tools
2026-04-10 05:20:54 +02:00
jubnl
1187883c6b
feat(mcp): always register list_trips & get_trip_summary; inject deprecation notice into tool results
Navigation tools:
- list_trips and get_trip_summary are now always registered for any
  OAuth session regardless of granted scopes — they are required for
  trip ID discovery before any scoped tool can be used
- get_trip_summary filters optional sections (budget, packing, collab,
  reservations) by the client's OAuth scopes when called without trips:read

Deprecation notice:
- Inject static token deprecation warning into the first tool result
  (list_trips or get_trip_summary) via a per-session closure so Claude
  is forced to surface it — the instructions field alone is only
  background context and is not proactively shown to the user

UI:
- OAuth client creation modal: add hint explaining the always-available
  tools, remove the "must select at least one scope" submit guard
- OAuth consent screen: add "Always included" section showing list_trips
  and get_trip_summary; handles zero-scope clients gracefully (empty
  permissions section is hidden)
2026-04-10 02:45:16 +02:00
jubnl
830f6c0706
feat(mcp): introduce OAuth 2.1 auth and enforce addon gating
OAuth 2.1 authentication for MCP:
- Add OAuth 2.1 authorization server with PKCE support (routes/oauth.ts)
- Add OAuth service for client CRUD, auth-code flow, and token management (services/oauthService.ts)
- Add typed scope definitions and enforcement helpers (mcp/scopes.ts)
- Add OAuth consent UI page (OAuthAuthorizePage.tsx)
- Add client-side scope labels and descriptions (api/oauthScopes.ts)
- Integrate OAuth token auth into MCP handler alongside existing static tokens
- All OAuth endpoints gated on `mcp` addon

Addon gating across MCP tools, resources, and prompts:
- Add typed ADDON_IDS constant (server/src/addons.ts) replacing all string literals
- Gate budget tools and resources (trip-budget, per-person, settlement) on `budget` addon
- Gate packing tools and resources (trip-packing, trip-packing-bags, trip-todos) on `packing` addon
- Gate todos tools on `packing` addon (mirrors web UI Lists tab behavior)
- Expand atlas gate to cover full tool body (bucket-list + country tools no longer leak)
- Expand collab gate to cover full tool body (collab notes no longer leak)
- Gate packing-list and budget-overview MCP prompts on their respective addons
- Gate get_trip_summary sections per addon; blank packing/budget/collab_notes/todos when disabled
- Remove trip-files resource and files field from get_trip_summary
- Replace all isAddonEnabled('literal') calls with ADDON_IDS constants

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 22:25:58 +02:00
Yannis Biasutti
0e3e6df1f0 Merge remote-tracking branch 'origin/dev' into feat/places-kmz-kml-import
# Conflicts:
#	server/tests/integration/places.test.ts
2026-04-07 21:07:42 +02:00
Marco Sadowski
d9d389d090 feat: naver list import
Added Naver List Import in a similar style like the Google List Import. To keep the frontend clean I combined both list options.
2026-04-07 14:04:27 +02:00
jubnl
47b880221d
fix(oidc): resolve login/logout loop in OIDC-only mode
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
2026-04-07 13:18:24 +02:00
Yannis Biasutti
81851d8367 refactor(i18n): rename importKmlKmz to importKeyholeMarkup across all locales 2026-04-06 22:26:22 +02:00
Yannis Biasutti
2cc79b3d16 feat(client): refine KMZ/KML import dialog and localize all locales 2026-04-06 19:13:54 +02:00
Yannis Biasutti
c671b5ff17 chore(i18n): add KMZ/KML import translation keys 2026-04-06 18:32:10 +02:00
jubnl
955776b492
fix(LF): Normalize file to LF 2026-04-05 21:30:32 +02:00
Julien G.
9b11abbf4a
Merge pull request #434 from jerryhuangyu/feat/support-zh
feat(i18n): add Traditional Chinese (zh-TW) language support
2026-04-05 21:18:02 +02:00
Maurice
48bf149d01 feat(packing): item quantity, bag rename, multi-user bags, save as template
- Add quantity field to packing items (persisted, visible per item)
- Bags are now renamable (click to edit in sidebar)
- Bags support multiple user assignments with avatar display
- New packing_bag_members table for multi-user bag ownership
- Save current packing list as reusable template
- Add bag members API endpoint (PUT /bags/:bagId/members)
- Migration 74: quantity on packing_items, user_id on packing_bags, packing_bag_members table
2026-04-05 19:28:33 +02:00
Maurice
38206883ff feat(budget): bidirectional sync between reservations and budget items
- Link budget items to reservations via reservation_id column
- Update budget entry when reservation price changes (not create duplicate)
- Delete budget entry when reservation price is cleared
- Sync price back to reservation when edited in budget panel
- Lock budget item name when linked to a reservation
- Add migration 73 for reservation_id on budget_items
2026-04-05 18:16:02 +02:00
jerryhuangyu
dd21074c27 feat: Add Traditional Chinese (zh-TW) translations support 2026-04-05 23:53:26 +08:00
Maurice
cd5a6c7491 ui(settings): add about text, community links and bug/feature/wiki cards
- Add TREK description and "Made with heart" text to About tab (all 13 languages)
- Add Report Bug, Feature Request and Wiki cards to About tab and Admin GitHub panel
- Version shown as inline badge
2026-04-05 17:53:15 +02:00
Maurice
d5cc2432c4 fix(i18n): escape apostrophes in French dayCountHint translation 2026-04-05 16:25:32 +02:00
Maurice
7f077d949d feat(trips): add configurable day count for trips without dates
- Show day count input in trip form when no start/end date is set
- Backend accepts day_count param for create and update
- Remove forced date assignment for dateless trips (was always setting tomorrow + 7)
- Fix off-by-one: single-date fallback now creates 7 days instead of 8
- Add dayCount/dayCountHint translations for all 13 languages
2026-04-05 16:25:09 +02:00
Maurice
a9d6ce87c1
Merge pull request #336 from tiquis0290/test
Adding support for SynologyPhoto (immich like) and adding support to use more photo proiders not just immich
2026-04-05 15:08:50 +02:00
Maurice
67b21d5fe3 i18n(admin): rename tabs and merge notification panels
- Configuration → Personalization (all 13 languages)
- Merge Notification Channels + Admin Notifications into single Notifications tab
- Audit Log → Audit (all 13 languages)
2026-04-05 14:46:36 +02:00
Marek Maslowski
b8c3d5b3d1 Merge branch 'dev' into test 2026-04-05 10:26:09 +02:00
jubnl
4e4afe2545
feat(settings): remake settings page with admin-style tabbed layout
Replaces the 2-column masonry layout with a horizontal pill tab bar
matching the admin page pattern. Extracts all sections into self-contained
components under components/Settings/ and reduces SettingsPage.tsx from
1554 lines to 93. Adds i18n tab label keys across all 13 language files.
2026-04-05 05:32:21 +02:00
jubnl
6a36efbf1a
feat(i18n): translate missing keys across all 12 language files 2026-04-05 04:34:58 +02:00
jubnl
f03705848d
fix(translation): syntax error 2026-04-05 03:54:42 +02:00
jubnl
0c99eb1d07
chore: merge dev branch, resolve conflicts for migrations and translations
- migrations.ts: keep dev's migrations 69 (place_regions) + 70 (visited_regions), renumber our notification_channel_preferences migration to 71 and drop-old-table to 72
- translations: use dev values for existing keys, add notification system keys unique to this branch

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 03:46:53 +02:00
jubnl
71c1683bb3
feat(atlas): mark sub-national regions as visited with cascade behavior
- Add visited_regions table migration
- Mark/unmark region endpoints with auto-mark parent country
- Unmark country cascades to its regions; unmark last region cascades to country
- Region modal with mark/unmark flow and bucket list shortcut
- Viewport-based lazy loading of region GeoJSON at zoom >= 6
- i18n: add atlas.markRegionVisitedHint and atlas.confirmUnmarkRegion across all 13 locales
2026-04-05 03:17:59 +02:00
mauriceboe
6df8b2555d chore: resolve merge conflicts with dev branch
Merge dev into feat/notification-system, keeping all i18n keys from both
branches (notification system keys + reservation price/budget keys).
2026-04-05 01:43:43 +02:00
jubnl
fc29c5f7d0
feat(notifications): add unified multi-channel notification system
Introduces a fully featured notification system with three delivery
channels (in-app, email, webhook), normalized per-user/per-event/
per-channel preferences, admin-scoped notifications, scheduled trip
reminders and version update alerts.

- New notificationService.send() as the single orchestration entry point
- In-app notifications with simple/boolean/navigate types and WebSocket push
- Per-user preference matrix with normalized notification_channel_preferences table
- Admin notification preferences stored globally in app_settings
- Migration 69 normalizes legacy notification_preferences table
- Scheduler hooks for daily trip reminders and version checks
- DevNotificationsPanel for testing in dev mode
- All new tests passing, covering dispatch, preferences, migration, boolean
  responses, resilience, and full API integration (NSVC, NPREF, INOTIF,
  MIGR, VNOTIF, NROUTE series)
 - Previous tests passing
2026-04-05 01:22:18 +02:00
Marek Maslowski
399684cc19
Merge branch 'dev' into test 2026-04-05 00:36:40 +02:00
mauriceboe
b8058a2755 fix(reservations): budget category dropdown, localized auto-category, price input cleanup
- Budget category uses dropdown with existing categories instead of freetext
- Auto category uses translated booking type names (e.g. "Volo" in Italian)
- Remove number input spinner arrows, use decimal inputMode
- Add budget entry creation to PUT handler (update), not just POST (create)
- Error logging for failed budget entry creation
- i18n keys for all 13 languages
2026-04-05 00:13:07 +02:00
mauriceboe
aa244dd548 feat(reservations): add price field with automatic budget entry creation
- Optional price and budget category fields on the reservation form
- When a price is set, a budget entry is automatically created on save
- Price and category stored in reservation metadata for reference
- Hint text shown when price is entered
- i18n keys for EN and DE
2026-04-04 23:59:30 +02:00
Marek Maslowski
3413d3f77d fixing labels in english 2026-04-04 22:00:35 +02:00
mauriceboe
0b36427c09 feat(todo): add To-Do list feature with 3-column layout
- New todo_items DB table with priority, due date, description, user assignment
- Full CRUD API with WebSocket real-time sync
- 3-column UI: sidebar filters (All, My Tasks, Overdue, Done, by Priority),
  task list with inline badges, and detail/create pane
- Apple-inspired design with custom dropdowns, date picker, priority system (P1-P3)
- Mobile responsive: icon-only sidebar, bottom-sheet modals for detail/create
- Lists tab with sub-tabs (Packing List + To-Do), persisted selection
- Addon renamed from "Packing List" to "Lists"
- i18n keys for all 13 languages
- UI polish: notification colors use system theme, mobile navbar cleanup,
  settings page responsive buttons
2026-04-04 16:58:24 +02:00
Maurice
1aea2fcee8
Merge pull request #361 from lucaam/add_span_days_feature
Support multi-day spanning for reservations
2026-04-04 13:58:16 +02:00
jubnl
2469739bca
fix(admin): update stale NOMAD references to TREK
- GitHubPanel: point release fetcher to mauriceboe/TREK
- AdminPage: fix Docker update instructions (image, container name, volume paths)
- es.ts: replace all remaining NOMAD occurrences with TREK
2026-04-04 00:21:40 +02:00
jubnl
6c72295424
fix(vacay): fix entitlement counter, year deletion, and year creation bugs
- toggleCompanyHoliday now calls loadStats() so the entitlement sidebar
  updates immediately when a vacation day is converted to a company holiday
- deleteYear now deletes vacay_user_years rows for the removed year,
  preventing stale entitlement data from persisting and re-appearing
  when the year is re-created
- deleteYear recalculates carry-over for year+1 when year N is deleted,
  using the new actual previous year as the source
- removeYear store action now calls loadStats() so the sidebar reflects
  the recalculated carry-over without requiring a page refresh
- Add prev-year button (+[<] 2026 [>]+) so users can add years going
  backwards after deleting a past year; add vacay.addPrevYear i18n key
  to all 13 supported languages

Closes #371
2026-04-03 19:51:22 +02:00
Luca
0115987e52
feat: support multi-day spanning for reservations (flights, rental cars, events)
- ReservationModal: add separate departure/arrival date+time fields with
  type-specific labels (Departure/Arrival for flights, Pickup/Return for
  cars, Start/End for generic types), timezone fields for flights
- DayPlanSidebar: getTransportForDay now matches reservations across all
  days in their date range; shows phase badges (Departure/In Transit/
  Arrival etc.) with appropriate time display per day
- ReservationsPanel: show date range when end date differs from start
- All 13 translation files updated with new keys
2026-04-03 16:55:45 +02:00
jubnl
6b94c0632c
feat: add about section in user setting with trek version + discord link 2026-04-03 15:30:10 +02:00
Maurice
5dd80d5cb8 feat: Discord links, translation sync, iOS login fix, trip copy fix
- Add Discord button to admin GitHub panel and user menu
- Sync all 13 translation files to 1434 keys with native translations
- Fix duplicate keys in Polish translation (pl.ts)
- Fix iOS login race condition: sameSite strict→lax, loadUser sequence counter
- Fix trip copy route: add missing db, Trip, TRIP_SELECT imports
2026-04-03 14:39:44 +02:00
Gérnyi Márk
d48714d17a
feat: add copy/duplicate trip from dashboard (#270)
New POST /api/trips/:id/copy endpoint that deep copies all trip
planning data (days, places, assignments, reservations, budget,
packing, accommodations, day notes) with proper FK remapping
inside a transaction. Skips files, collab data, and members.

Copy button on all dashboard card types (spotlight, grid, list,
archived) gated by trip_create permission. Translations for all
12 languages.

Also adds reminder_days to Trip interface (removes as-any casts).
2026-04-03 12:38:45 +02:00
Wojciech Chrzan
a0db42fbfe
feat(i18n): add Polish language support (#252) 2026-04-03 12:28:48 +02:00
Julien G.
f4d0ccb454
Merge pull request #344 from marco783/addPeopleCount
added trip member count to dashboard
2026-04-03 11:23:10 +02:00
Marco Pasquali
a40983e65e added trip member count to dashboard
added translations for  (generated with AI, so they could be wrong)
2026-04-03 11:10:21 +02:00
jubnl
c0e9a771d6
feat: add in-app notification system with real-time delivery
Introduces a full in-app notification system with three types (simple,
boolean with server-side callbacks, navigate), three scopes (user, trip,
admin), fan-out persistence per recipient, and real-time push via
WebSocket. Includes a notification bell in the navbar, dropdown, dedicated
/notifications page, and a dev-only admin tab for testing all notification
variants.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 18:57:52 +02:00
Maurice
ffe91604b5
Merge pull request #273 from lucaam/undo_button_v2
feat: undo button for trip planner (+ fix to route preview)
2026-04-02 14:59:16 +02:00
jubnl
1a4c04e239
fix: resolve Immich 401 passthrough causing spurious login redirects
- Auth middleware now tags its 401s with code: AUTH_REQUIRED so the
  client interceptor only redirects to /login on genuine session failures,
  not on upstream API errors
- Fix /albums and album sync routes using raw encrypted API key instead
  of getImmichCredentials() (which decrypts it), causing Immich to reject
  requests with 401
- Add toast error notifications for all Immich operations in MemoriesPanel
  that previously swallowed errors silently

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 21:19:53 +02:00
Luca
e308204808
feat: undo button for trip planner
Implements a full undo history system for the Plan screen.

New hook: usePlannerHistory (client/src/hooks/usePlannerHistory.ts)
- Maintains a LIFO stack (up to 30 entries) of reversible actions
- Exposes pushUndo(label, fn), undo(), canUndo, lastActionLabel

Tracked actions:
- Assign place to day (undo: remove the assignment)
- Remove place from day (undo: re-assign at original position)
- Reorder places within a day (undo: restore previous order)
- Move place to a different day (undo: move back)
- Optimize route (undo: restore original order)
- Lock / unlock place (undo: toggle back)
- Delete place (undo: recreate place + restore all day assignments)
- Add place (undo: delete it)
- Import from GPX (undo: delete all imported places)
- Import from Google Maps list (undo: delete all imported places)

UI: Undo button (Undo2 icon) in DayPlanSidebar header. PDF, ICS and
Undo buttons all use custom instant hover tooltips instead of native
title attributes.

A toast notification confirms each undo action.

Translations: undo.* keys added to all 12 language files.
2026-04-01 18:20:14 +02:00
Julien G.
edafe01387
Merge branch 'dev' into dev 2026-04-01 17:30:31 +02:00
Maurice
ef5b381f8e feat: collapse days hides map markers, Immich test-before-save (#216)
Map markers:
- Collapsing a day in the sidebar hides its places from the map
- Places assigned to multiple days only hide when all days collapsed
- Unplanned places always stay visible

Immich settings:
- New POST /integrations/immich/test endpoint validates credentials
  without saving them
- Save button disabled until test connection passes
- Changing URL or API key resets test status
- i18n: testFirst key for all 12 languages
2026-04-01 15:30:59 +02:00
Maurice
ef9880a2a5 feat: Immich album linking with auto-sync (#206)
- Link Immich albums to trips — photos sync automatically
- Album picker shows all user's Immich albums
- Linked albums displayed as chips with sync/unlink buttons
- Auto-sync on link: fetches all album photos and adds to trip
- Manual re-sync button for each linked album
- DB migration: trip_album_links table

fix: shared Immich photos visible to other trip members

- Thumbnail/original proxy now uses photo owner's Immich credentials
  when userId query param is provided, fixing 404 for shared photos
- i18n: album keys for all 12 languages
2026-04-01 15:21:20 +02:00
Maurice
95cb81b0e5 perf: major trip planner performance overhaul (#218)
Store & re-render optimization:
- TripPlannerPage uses selective Zustand selectors instead of full store
- placesSlice only updates affected days on place update/delete
- Route calculation only reacts to selected day's assignments
- DayPlanSidebar uses stable action refs instead of full store

Map marker performance:
- Shared photoService for PlaceAvatar and MapView (single cache, no duplicate requests)
- Client-side base64 thumbnail generation via canvas (CORS-safe for Wikimedia)
- Map markers use base64 data URL <img> tags for smooth zoom (no external image decode)
- Sidebar uses same base64 thumbnails with IntersectionObserver for visible-first loading
- Icon cache prevents duplicate L.divIcon creation
- MarkerClusterGroup with animate:false and optimized chunk settings
- Photo fetch deduplication and batched state updates

Server optimizations:
- Wikimedia image size reduced to 400px (from 600px)
- Photo cache: 5min TTL for errors (was 12h), prevents stale 404 caching
- Removed unused image-proxy endpoint

UX improvements:
- Splash screen with plane animation during initial photo preload
- Markdown rendering in DayPlanSidebar place descriptions
- Missing i18n keys added, all 12 languages synced to 1376 keys
2026-04-01 14:56:01 +02:00
Maurice
7d0ae631b8 fix: mobile place editing and detail view (#269)
- PlacesSidebar mobile: tap opens action sheet with view details,
  edit, assign to day, and delete options
- PlaceInspector renders as fullscreen portal overlay on mobile
- DayPlanSidebar mobile: tapping a place closes overlay and opens
  inspector
- Inspector closes when edit or delete is triggered on mobile
- i18n: added places.viewDetails for all 12 languages
2026-04-01 12:38:44 +02:00
Maurice
4ebf9c5f11 feat: add expense date and CSV export to budget
- New expense_date column on budget items (DB migration #42)
- Date column in budget table with custom date picker
- CSV export button with BOM, semicolon separator, localized dates,
  currency in header, per-person/day calculations
- CustomDatePicker compact/borderless modes for inline table use
- i18n keys for all 12 languages
2026-04-01 12:16:11 +02:00
Julien G.
9292acb979
Merge branch 'dev' into dev 2026-04-01 10:27:51 +02:00
Maurice
040840917c feat: add Google Maps list import
Import places from shared Google Maps lists via URL.
Button in places sidebar next to GPX import opens a modal
where users can paste a shared list link. Server fetches
list data from Google Maps and creates places with name,
coordinates and notes. i18n keys added for all 12 languages.

Closes #205
2026-04-01 10:13:35 +02:00
jubnl
e03505dca2
fix: enforce consistent password policy across all auth flows
Replace duplicated inline validation with a shared validatePassword()
utility that checks minimum length (8), rejects repetitive and common
passwords, and requires uppercase, lowercase, a digit, and a special
character.

- Add server/src/services/passwordPolicy.ts as single source of truth
- Apply to registration, password change, and admin create/edit user
  (admin routes previously had zero validation)
- Fix client min-length mismatch (6 vs 8) in RegisterPage and LoginPage
- Add client-side password length guard to AdminPage forms
- Update register.passwordTooShort and settings.passwordWeak i18n keys
  in all 12 locales to reflect the corrected requirements
2026-04-01 07:58:46 +02:00
Gérnyi Márk
23edfe3dfc
fix: harden permissions system after code review
- Gate permissions in /app-config behind optionalAuth so unauthenticated
  requests don't receive admin configuration
- Fix trip_delete isMember parameter (was hardcoded false)
- Return skipped keys from savePermissions for admin visibility
- Add disabled prop to CustomSelect, use in BudgetPanel currency picker
- Fix CollabChat reaction handler returning false instead of void
- Pass canUploadFiles as prop to NoteFormModal instead of internal store read
- Make edit-only NoteFormModal props optional (onDeleteFile, note, tripId)
- Add missing trailing newlines to .gitignore and it.ts
2026-03-31 23:36:17 +02:00
Gérnyi Márk
1ff8546484
fix: i18n chat reply/delete titles, gate collab category settings 2026-03-31 23:36:17 +02:00
Gérnyi Márk
7d3b37a2a3
feat: add configurable permissions system with admin panel
Adds a full permissions management feature allowing admins to control
who can perform actions across the app (trip CRUD, files, places,
budget, packing, reservations, collab, members, share links).

- New server/src/services/permissions.ts: 16 configurable actions,
  in-memory cache, checkPermission() helper, backwards-compatible
  defaults matching upstream behaviour
- GET/PUT /admin/permissions endpoints; permissions loaded into
  app-config response so clients have them on startup
- checkPermission() applied to all mutating route handlers across
  10 server route files; getTripOwnerId() helper eliminates repeated
  inline DB queries; trips.ts and files.ts now reuse canAccessTrip()
  result to avoid redundant DB round-trips
- New client/src/store/permissionsStore.ts: Zustand store +
  useCanDo() hook; TripOwnerContext type accepts both Trip and
  DashboardTrip shapes without casting at call sites
- New client/src/components/Admin/PermissionsPanel.tsx: categorised
  UI with per-action dropdowns, customised badge, save/reset
- AdminPage, DashboardPage, FileManager, PlacesSidebar,
  TripMembersModal gated via useCanDo(); no prop drilling
- 46 perm.* translation keys added to all 12 language files
2026-03-31 23:36:15 +02:00
Andrei Brebene
7522f396e7 feat: configurable trip reminders, admin full access, and enhanced audit logging
- Add configurable trip reminder days (1, 3, 9 or custom up to 30) settable by trip owner
- Grant administrators full access to edit, archive, delete, view and list all trips
- Show trip owner email in audit logs and docker logs when admin edits/deletes another user's trip
- Show target user email in audit logs when admin edits or deletes a user account
- Use email instead of username in all notifications (Discord/Slack/email) to avoid ambiguity
- Grey out notification event toggles when no SMTP/webhook is configured
- Grey out trip reminder selector when notifications are disabled
- Skip local admin account creation when OIDC_ONLY=true with OIDC configured
- Conditional scheduler logging: show disabled reason or active reminder count
- Log per-owner reminder creation/update in docker logs
- Demote 401/403 HTTP errors to DEBUG log level to reduce noise
- Hide edit/archive/delete buttons for non-owner invited users on trip cards
- Fix literal "0" rendering on trip cards from SQLite numeric is_owner field
- Add missing translation keys across all 14 language files

Made-with: Cursor
2026-03-31 22:23:38 +03:00
Andrei Brebene
9b2f083e4b feat: notifications, audit logging, and admin improvements
- Add centralized notification service with webhook (Discord/Slack) and
  email (SMTP) support, triggered for trip invites, booking changes,
  collab messages, and trip reminders
- Webhook sends one message per event (group channel); email sends
  individually per trip member, excluding the actor
- Discord invite notifications now include the invited user's name
- Add LOG_LEVEL env var (info/debug) controlling console and file output
- INFO logs show user email, action, and IP for audit events; errors
  for HTTP requests
- DEBUG logs show every request with full body/query (passwords redacted),
  audit details, notification params, and webhook payloads
- Add persistent trek.log file logging with 10MB rotation (5 files)
  in /app/data/logs/
- Color-coded log levels in Docker console output
- Timestamps without timezone name (user sets TZ via Docker)
- Add Test Webhook and Save buttons to admin notification settings
- Move notification event toggles to admin panel
- Add daily trip reminder scheduler (9 AM, timezone-aware)
- Wire up booking create/update/delete and collab message notifications
- Add i18n keys for notification UI across all 13 languages

Made-with: Cursor
2026-03-31 22:23:23 +03:00
Maurice
1983691950 Merge branch 'feat/add-searchbar-in-atlas' of https://github.com/Akashic101/NOMAD into dev
# Conflicts:
#	client/src/i18n/translations/cs.ts
#	client/src/i18n/translations/it.ts
2026-03-31 20:29:23 +02:00
David Moll
8ff5ec486f
Merge branch 'main' into feat/add-searchbar-in-atlas 2026-03-31 12:31:14 +02:00
David Moll
5576339bcc
feat(atlas): add searchbar 2026-03-31 12:27:13 +02:00
Moritz Enderle
3aaa6e916b feat: adds better gpx track views 2026-03-31 10:29:49 +02:00
Maurice
069fd99341 Merge branch 'pr-169'
# Conflicts:
#	client/src/i18n/translations/ar.ts
#	client/src/i18n/translations/br.ts
#	client/src/i18n/translations/cs.ts
#	client/src/i18n/translations/de.ts
#	client/src/i18n/translations/en.ts
#	client/src/i18n/translations/es.ts
#	client/src/i18n/translations/fr.ts
#	client/src/i18n/translations/hu.ts
#	client/src/i18n/translations/it.ts
#	client/src/i18n/translations/nl.ts
#	client/src/i18n/translations/ru.ts
#	client/src/i18n/translations/zh.ts
#	client/src/pages/SettingsPage.tsx
2026-03-30 23:46:32 +02:00
Fernando Bona
13580ea5fb
Merge branch 'main' into feat/#155 2026-03-30 18:36:18 -03:00
Fernando Bona
aa5dd1abc6
Merge branch 'main' into fix/mfa-backup-codes 2026-03-30 18:27:46 -03:00
fgbona
de444bf770
fix(mfa-backup-codes): persist backup codes panel after enable and refresh
Keep MFA backup codes visible after enabling MFA by avoiding protected-route unmount during user reload (`loadUser({ silent: true })`) and restoring pending backup codes from sessionStorage until the user explicitly dismisses them.
2026-03-30 18:22:45 -03:00
Maurice
821f71ac28 fix: add MCP translation keys for cs, hu, it languages 2026-03-30 23:14:05 +02:00