Commit Graph

104 Commits

Author SHA1 Message Date
Maurice
de859318fa feat: admin audit log — merged PR #118
Audit logging for admin actions, backups, auth events.
New AuditLogPanel in Admin tab with pagination.
Dockerfile security: run as non-root user.
i18n keys for all 9 languages.

Thanks @fgbona for the implementation!
2026-03-30 20:05:32 +02:00
fgbona
10ebf46a98 harden runtime config and automate first-run permissions
Run the container as a non-root user in production to fail fast on insecure deployments. Add DEBUG env-based request/response logging for container diagnostics, and introduce a one-shot init-permissions service in docker-compose so fresh installs automatically fix data/uploads ownership for SQLite write access.
2026-03-30 13:19:01 -03:00
Maurice
a314ba2b80 feat: public read-only share links with permissions — closes #79
Share links:
- Generate a public link in the trip share modal
- Choose what to share: Map & Plan, Bookings, Packing, Budget, Chat
- Permissions enforced server-side
- Delete link to revoke access instantly

Shared trip page (/shared/:token):
- Read-only view with TREK logo, cover image, trip details
- Tabbed navigation with Lucide icons (responsive on mobile)
- Interactive map with auto-fit bounds per day
- Day plan, Bookings, Packing, Budget, Chat views
- Language picker, TREK branding footer

Technical:
- share_tokens DB table with per-field permissions
- Public GET /shared/:token endpoint (no auth)
- Two-column share modal (max-w-5xl)
2026-03-30 18:02:53 +02:00
Maurice
0a0205fcf9 fix: ICS export — add DTSTAMP, fix time-only DTEND formatting 2026-03-30 17:14:06 +02:00
Maurice
d189d6d776 feat: email notifications, webhook support, ICS export — closes #110
Email Notifications:
- SMTP configuration in Admin > Settings (host, port, user, pass, from)
- App URL setting for email CTA links
- Webhook URL support (Discord, Slack, custom)
- Test email button with SMTP validation
- Beautiful HTML email template with TREK logo, slogan, red heart footer
- All notification texts translated in 8 languages (en/de/fr/es/nl/ru/zh/ar)
- Emails sent in each user's language preference

Notification Events:
- Trip invitation (member added)
- Booking created (new reservation)
- Vacay fusion invite
- Photos shared (Immich)
- Collab chat message
- Packing list category assignment

User Notification Preferences:
- Per-user toggle for each event type in Settings
- Addon-aware: Vacay/Collab/Photos toggles hidden when addon disabled
- Webhook opt-in per user

ICS Calendar Export:
- Download button next to PDF in day plan header
- Exports trip dates + all reservations with details
- Compatible with Google Calendar, Apple Calendar, Outlook

Technical:
- Nodemailer for SMTP
- notification_preferences DB table with per-event columns
- GET/PUT /auth/app-settings for admin config persistence
- POST /notifications/test-smtp for validation
- Dynamic imports for non-blocking notification sends
2026-03-30 17:07:33 +02:00
Maurice
262905e357 feat: import places from Google Maps URLs — closes #141
Paste a Google Maps URL into the place search bar to automatically
import name, coordinates, and address. No API key required.

Supported URL formats:
- Short URLs: maps.app.goo.gl/..., goo.gl/maps/...
- Full URLs: google.com/maps/place/.../@lat,lng
- Data params: !3dlat!4dlng embedded coordinates

Server resolves short URL redirects and extracts coordinates.
Reverse geocoding via Nominatim provides name and address.
2026-03-30 15:18:22 +02:00
Maurice
4a4643f33f feat: OIDC claim-based admin role assignment — closes #93
New environment variables:
- OIDC_ADMIN_CLAIM (default: "groups") — which claim to check
- OIDC_ADMIN_VALUE (e.g. "app-trek-admins") — value that grants admin

Admin role is resolved on every OIDC login:
- New users get admin if their claim matches
- Existing users have their role updated dynamically
- Removing a user from the group revokes admin on next login
- First user is always admin regardless of claims
- No config = previous behavior (first user admin, rest user)

Supports array claims (groups: ["a", "b"]) and string claims.
2026-03-30 15:12:27 +02:00
Maurice
a6a7edf0b2 feat: bucket list POIs with auto-search + optional dates — closes #105
- Bucket list now supports POIs (not just countries): add any place
  with auto-search via Google Places / Nominatim
- Optional target date (month/year) via CustomSelect dropdowns
- New target_date field on bucket_list table (DB migration)
- Server PUT route supports updating all fields
- Country bucket modal: date dropdowns default to empty
- CustomSelect: auto-opens upward when near bottom of viewport
- Search results open upward in the bucket add form
- i18n keys for DE and EN
2026-03-30 14:57:31 +02:00
Maurice
949d0967d2 feat: timezone support + granular backup schedule — closes #131
Based on PR #135 by @andreibrebene with adjustments:
- TZ environment variable for Docker timezone support
- Granular auto-backup schedule (hour, day of week, day of month)
- UTC timestamp fix for admin panel
- Server timezone exposed in app-config API
- Replaced native selects with CustomSelect for consistent UI
- Backup schedule UI with 12h/24h time format support

Thanks @andreibrebene for the implementation!
2026-03-30 14:02:27 +02:00
Maurice
7201380504 fix: paginate Immich photo search — no longer limited to 200 — closes #137
The Immich metadata search was hardcoded to size: 200. Now paginates
through all results (1000 per page, up to 20k photos max).
2026-03-30 13:36:04 +02:00
Andrei Brebene
6f2d7c8f5e Merge branch 'dev' into feat/auto-backup-schedule-and-timezone 2026-03-30 13:23:19 +03:00
Maurice
e6c4c22a1d feat: bulk import for packing lists + complete i18n sync — closes #133
Packing list bulk import:
- Import button in packing list header opens a modal
- Paste items or load CSV/TXT file
- Format: Category, Name, Weight (g), Bag, checked/unchecked
- Bags are auto-created if they don't exist
- Server endpoint POST /packing/import with transaction

i18n sync:
- Added all missing translation keys to fr, es, nl, ru, zh, ar
- All 8 language files now have matching key sets
- Includes memories, vacay weekdays, packing import, settlement,
  GPX import, blur booking codes, transport timeline keys
2026-03-30 12:16:00 +02:00
Maurice
da5e77f78d feat: GPX file import for places — closes #98
Upload a GPX file to automatically create places from waypoints.
Supports <wpt>, <rtept>, and <trkpt> elements with CDATA handling.
Handles lat/lon in any attribute order. Track-only files import
start and end points with the track name.

- New server endpoint POST /places/import/gpx
- Import GPX button in PlacesSidebar below Add Place
- i18n keys for DE and EN
2026-03-30 11:35:28 +02:00
Andrei Brebene
cc8be328f9 feat: add granular auto-backup scheduling and timezone support
Add UI controls for configuring auto-backup schedule with hour, day of
week, and day of month pickers. The hour picker respects the user's
12h/24h time format preference from settings.

Add TZ environment variable support via docker-compose so the container
runs in the configured timezone. The timezone is passed to node-cron for
accurate scheduling and exposed via the API so the UI displays it.

Fix SQLite UTC timestamp handling by appending Z suffix to all timestamps
sent to the client, ensuring proper timezone conversion in the browser.

Made-with: Cursor
2026-03-30 12:27:52 +03:00
Maurice
f6d08582ec feat: expense settlement — track who paid, show who owes whom — closes #41
- Click member avatars on budget items to mark who paid (green = paid)
- Multiple green chips = those people split the payment equally
- Settlement dropdown in the total budget card shows optimized payment
  flows (who owes whom how much) and net balances per person
- Info tooltip explains how the feature works
- New server endpoint GET /budget/settlement calculates net balances
  and minimized payment flows using a greedy algorithm
- Merged category legend: amount + percentage in one row
- i18n keys added for DE and EN
2026-03-30 11:12:22 +02:00
Maurice
8d9a511edf fix: auto-invalidate cache on version update — closes #121
- Add version check on app startup: compare server version with stored
  client version, clear all SW caches and reload on mismatch
- Set Cache-Control: no-cache on index.html so browsers always fetch
  the latest version instead of serving stale cached HTML
2026-03-30 10:26:23 +02:00
Maurice
3074724f2f feat: show transport bookings in day plan timeline — closes #37
Transport reservations (flights, trains, buses, cars, cruises) now appear
directly in the day plan timeline based on their reservation date/time.

- Transport cards display inline with places and notes, sorted by time
- Click to open detail modal with all booking data and linked files
- Persistent positioning via new day_plan_position field on reservations
- Free drag & drop: places can be moved between/around transport entries
- Arrow reorder works on the full visual list including transports
- Timed places show confirmation popup when reorder breaks chronology
- Custom delete confirmation popup for reservations
- DB migration adds day_plan_position column to reservations table
- New batch endpoint PUT /reservations/positions for position updates
- i18n keys added for DE and EN
2026-03-30 10:15:27 +02:00
fgbona
d04629605e feat(audit): admin audit log
Audit log
- Add audit_log table (migration + schema) with index on created_at.
- Add auditLog service (writeAudit, getClientIp) and record events for backups
  (create, restore, upload-restore, delete, auto-settings), admin actions
  (users, OIDC, invites, system update, demo baseline, bag tracking, packing
  template delete, addons), and auth (app settings, MFA enable/disable).
- Add GET /api/admin/audit-log with pagination; fix invite insert row id lookup.
- Add AuditLogPanel and Admin tab; adminApi.auditLog.
- Add admin.tabs.audit and admin.audit.* strings in all locale files.
Note: Rebase feature branches so new DB migrations stay after existing ones
  (e.g. file_links) when merging upstream.
2026-03-29 19:39:05 -03:00
Maurice
b6f9664ec2 feat: multi-link files to multiple bookings and places — closes #23
Files can now be linked to multiple bookings and places simultaneously
via a new file_links junction table. Booking modal includes a file picker
to link existing uploads. Unlinking removes the association without
deleting the file.
2026-03-29 23:32:04 +02:00
Maurice
9f8075171d feat: Immich photo integration — Photos addon with sharing, filters, lightbox
- Immich connection per user (Settings → Immich URL + API Key)
- Photos addon (admin-toggleable, trip tab)
- Manual photo selection from Immich library (date filter + all photos)
- Photo sharing with consent popup, per-photo privacy toggle
- Lightbox with liquid glass EXIF info panel (camera, lens, location, settings)
- Location filter + date sort in gallery
- WebSocket live sync when photos are added/removed/shared
- Proxy endpoints for thumbnails and originals with token auth
2026-03-29 22:41:39 +02:00
Maurice
02b907e764 fix: manually marked Atlas countries not saved when no trips exist — closes #95 2026-03-29 22:37:21 +02:00
Maurice
615c6bae58 fix: Bangladesh pins incorrectly shown as India in Atlas — add BD bounding box — closes #106 2026-03-29 22:37:21 +02:00
Maurice
62fbc26811 fix: GitHub panel blank screen — add missing releases endpoint, fix NOMAD→TREK URL — closes #107 2026-03-29 22:37:21 +02:00
Maurice
2171203a4c feat: configurable weekend days in Vacay — closes #97
Users can now select which days are weekends (default: Sat+Sun).
Useful for countries like Bangladesh (Fri+Sat) or others with
different work weeks. Settings appear under "Block weekends" toggle.
2026-03-29 19:46:24 +02:00
Maurice
b28b483b90 fix: unlimited invite links (max_uses=0) no longer blocked as fully used 2026-03-29 19:30:21 +02:00
Maurice
d2efd960b5 v2.7.0 2026-03-29 17:42:11 +02:00
Maurice
c51a27371b chore: sync server package-lock.json for clean npm ci builds 2026-03-29 17:35:55 +02:00
Maurice
8458481950 feat: atlas country marking, bucket list, trip creation UX — closes #49
Atlas:
- Click any country to mark as visited or add to bucket list
- Bucket list with country flags, planned month/year, horizontal layout
- Confirm popup with two options (mark visited / bucket list)
- Full A2/A3 country code mapping for all countries

Trip creation:
- Drag & drop cover image support
- Add travel buddies via CustomSelect dropdown when creating a trip
- Manual date entry via double-click on date picker (supports DD.MM.YYYY, ISO, etc.)
2026-03-29 16:51:35 +02:00
Maurice
e99960c3b6 feat: support OIDC_ONLY environment variable to disable password auth — closes #48 2026-03-29 15:14:41 +02:00
Maurice
c39d242cfb feat: bag tracking with weight distribution, packing UX overhaul — closes #13
- Bag tracking: optional admin setting under Packing addon, weight per item,
  bag assignment with inline creation, iOS-style weight sidebar + mobile modal
- Admin: merged Categories + Packing Templates into "Configuration" tab
- Packing UI: category-first workflow, mobile-friendly action buttons,
  stable category ordering, responsive button labels
2026-03-29 15:08:56 +02:00
Maurice
2f8a189319 feat: packing templates with category-based workflow — closes #14
- Admin: create/edit/delete packing templates with categories and items
- Trip packing: category-first workflow (add category → add items inside)
- Apply template button adds items additively (preserves existing)
- Replaces old item+category freetext input
2026-03-29 14:19:06 +02:00
Maurice
44138af11a feat: assign trip members to packing list categories — closes #71 2026-03-29 13:37:48 +02:00
Maurice
3abcc0ec76 feat: fix MFA integration — migration, otplib compat, branding, and add MFA translations for all languages 2026-03-29 13:18:53 +02:00
Maurice
530f233b7d Merge PR #76: feat/mfa — multifactor authentication (closes #46) 2026-03-29 13:01:05 +02:00
Maurice
99514ddce1 feat: add invite registration links with configurable usage limits
Admins can create one-time registration links (1–5× or unlimited uses)
with optional expiry (1d–14d or never). Recipients can register even
when public registration is disabled. Atomic usage counting prevents
race conditions, all endpoints are rate-limited.
2026-03-29 12:49:15 +02:00
Fernando Bona
e56ea068ef Merge branch 'main' into feat/mfa 2026-03-28 22:12:26 -03:00
fgbona
a091051387 feat/mfa: Removed install-server-deps.sh, .npmrc and .nvmrc 2026-03-28 22:10:49 -03:00
mauriceboe
399e4acf03 Merge pull request #69 from saswatds/helmet-fix
fix: resolve static asset SSL errors from helmet's upgrade-insecure-requests
2026-03-29 01:48:08 +01:00
Maurice
005c08dcea Merge PR #68: multiple holiday calendars per vacay plan (closes #36) 2026-03-29 01:33:06 +01:00
Saswat
e25fec4e4a fix: resolve static asset SSL errors from helmet's upgrade-insecure-requests
Helmet merges default CSP directives (including `upgrade-insecure-requests`)
into custom directives when `useDefaults` is true (the default). This caused
browsers to upgrade all HTTP sub-resource requests to HTTPS, breaking static
assets when the server runs over plain HTTP.

This commit conditionally sets `upgrade-insecure-requests` based on
FORCE_HTTPS: enabled in production (where HTTPS is available), explicitly
disabled (null) otherwise to prevent browser SSL errors on home servers
and development environments.

Also extracts `shouldForceHttps` to avoid repeated env lookups.
2026-03-28 17:30:51 -07:00
Maurice
433d780f74 security: upgrade multer 1.4.5 → 2.1.1 — fixes CVE-2025-47944, CVE-2025-47935, CVE-2025-48997, CVE-2025-7338 2026-03-29 00:35:16 +01:00
Stephen Wheet
3c4f5f7193 feat: multiple holiday calendars per vacay plan
- Add vacay_holiday_calendars table (region, label, color, sort_order)
- Lazy migration of existing holidays_region to first calendar row
- Extract applyHolidayCalendars() helper; replace inline holiday logic
- GET /vacay/plan now includes holiday_calendars array
- Add POST/PUT/DELETE /vacay/plan/holiday-calendars/:id endpoints
- Client VacayPlan/VacayEntry/HolidayInfo types updated
- loadHolidays() loops over all calendars; per-calendar color on HolidayInfo
- VacayMonthCard uses holiday.color instead of hardcoded red
- VacaySettings replaced single country picker with calendar list UI
- VacayPage legend renders one item per calendar
- i18n: addCalendar, calendarLabel, calendarColor, noCalendars (en + de)
- Fix pre-existing TS errors: VacayPlan/VacayEntry missing fields,
  SettingToggleProps icon/onChange types, packing.suggestions.items array type

Closes #36
2026-03-28 22:16:12 +00:00
Fernando Bona
66ae577b7b Merge branch 'main' into feat/mfa 2026-03-28 18:59:06 -03:00
mauriceboe
723f8a1c3d Merge pull request #66 from wheetazlab/feature-oidc-only-mode
feat: add OIDC-only mode to disable password authentication
2026-03-28 21:51:14 +01:00
Stephen Wheet
3d33191925 fix: align @types/express to v4 to match express runtime
The project uses express@^4.18.3 at runtime but had @types/express@^5.0.6
as type definitions. The v5 types widened ParamsDictionary from
string to string | string[], causing 115 type errors across all route
handlers.

Fix: downgrade @types/express to ^4.17.25 (latest v4), which correctly
types req.params as string — matching Express 4 runtime behaviour.

Removes the StringParams = Record<string, string> workaround from
types.ts and the Request<StringParams> annotations from all 15 route
files that were introduced as a workaround for the type mismatch.
2026-03-28 20:36:09 +00:00
Maurice
48e1b732d8 fix: disable Helmet HSTS when FORCE_HTTPS is not set — fixes #58 #59 2026-03-28 21:35:23 +01:00
Stephen Wheet
d50c84b755 fix: resolve all TypeScript errors via proper Express 5 typed route params
- Add StringParams = Record<string, string> to types.ts
- Use Request<StringParams> in all route handlers across 14 files
- Clean up earlier as-cast workarounds in places.ts and admin.ts
- tsconfig.json: keep original (removed bad 'types:node' addition)
- package.json: restore @types/express back to ^5.0.6
2026-03-28 20:13:24 +00:00
Stephen Wheet
fcbfeb6793 fix: resolve all TypeScript errors - node types, Express v4 types, places/scheduler fixes 2026-03-28 19:45:01 +00:00
Stephen Wheet
77f2c616de fix: type error in AdminPage handleSaveUser payload, install deps 2026-03-28 19:41:06 +00:00
Stephen Wheet
9f8d3f8d99 feat: add OIDC-only mode to disable password authentication
When OIDC is configured, admins can now enable 'Disable password
authentication' in Admin → Settings → SSO. This blocks all password-
based login and registration, forcing users through the SSO identity
provider instead.

Backend:
- routes/admin.ts: expose oidc_only flag on GET /admin/oidc and accept
  it on PUT /admin/oidc (persisted to app_settings)
- routes/auth.ts: add isOidcOnlyMode() helper; block POST /auth/login,
  POST /auth/register (for non-first-user), and PUT /auth/me/password
  with HTTP 403 when OIDC-only mode is active
- routes/auth.ts: expose oidc_only_mode boolean in GET /auth/app-config

Frontend:
- AdminPage: toggle in OIDC/SSO settings section (oidc_only saved with
  rest of OIDC config on same Save button)
- LoginPage: when oidc_only_mode is active, replace form with a
  single-button OIDC redirect; hide register toggle
- SettingsPage: hide password change section when oidc_only_mode is on
- i18n (en/de): admin.oidcOnlyMode, admin.oidcOnlyModeHint,
  login.oidcOnly
2026-03-28 19:33:18 +00:00