diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index a8bbd3fa..bb34a512 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -6,6 +6,8 @@ on: paths-ignore: - 'docs/**' - '**/*.md' + - 'wiki/**' + - '.github/workflows/wiki.yml' workflow_dispatch: inputs: bump: diff --git a/.github/workflows/wiki.yml b/.github/workflows/wiki.yml new file mode 100644 index 00000000..440b6b7a --- /dev/null +++ b/.github/workflows/wiki.yml @@ -0,0 +1,26 @@ +name: Deploy Wiki + +on: + push: + branches: [main] + paths: + - 'wiki/**' + - '.github/workflows/wiki.yml' + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: wiki-deploy + cancel-in-progress: true + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Publish to GitHub wiki + uses: Andrew-Chen-Wang/github-wiki-action@v5 + with: + strategy: init diff --git a/server/scripts/migrate-encryption.ts b/server/scripts/migrate-encryption.ts index f5d788fb..78e19e1a 100644 --- a/server/scripts/migrate-encryption.ts +++ b/server/scripts/migrate-encryption.ts @@ -237,8 +237,8 @@ async function main() { } db.transaction(() => { - // --- app_settings: oidc_client_secret, smtp_pass --- - for (const key of ['oidc_client_secret', 'smtp_pass']) { + // --- app_settings: oidc_client_secret, smtp_pass, admin_webhook_url, admin_ntfy_token --- + for (const key of ['oidc_client_secret', 'smtp_pass', 'admin_webhook_url', 'admin_ntfy_token']) { const row = db.prepare('SELECT value FROM app_settings WHERE key = ?').get(key) as { value: string } | undefined; if (!row?.value) continue; const newVal = migrateApiKeyValue(row.value, `app_settings.${key}`); @@ -247,8 +247,8 @@ async function main() { } } - // --- users: maps_api_key, openweather_api_key, immich_api_key --- - const apiKeyColumns = ['maps_api_key', 'openweather_api_key', 'immich_api_key']; + // --- users: api key columns + synology credentials --- + const apiKeyColumns = ['maps_api_key', 'openweather_api_key', 'immich_api_key', 'synology_password', 'synology_sid', 'synology_did']; const users = db.prepare('SELECT id FROM users').all() as { id: number }[]; for (const user of users) { @@ -271,6 +271,37 @@ async function main() { } } } + // --- settings: per-user encrypted keys --- + const encryptedSettingKeys = ['webhook_url', 'ntfy_token', 'mapbox_access_token']; + const settingRows = db.prepare( + `SELECT user_id, key, value FROM settings WHERE key IN (${encryptedSettingKeys.map(() => '?').join(', ')})` + ).all(...encryptedSettingKeys) as { user_id: number; key: string; value: string }[]; + + for (const row of settingRows) { + if (!row.value) continue; + const newVal = migrateApiKeyValue(row.value, `settings[user=${row.user_id}].${row.key}`); + if (newVal !== null) { + db.prepare('UPDATE settings SET value = ? WHERE user_id = ? AND key = ?').run(newVal, row.user_id, row.key); + } + } + + // --- trip_album_links: passphrase --- + const albumLinks = db.prepare('SELECT id, passphrase FROM trip_album_links WHERE passphrase IS NOT NULL').all() as { id: number; passphrase: string }[]; + for (const row of albumLinks) { + const newVal = migrateApiKeyValue(row.passphrase, `trip_album_links[${row.id}].passphrase`); + if (newVal !== null) { + db.prepare('UPDATE trip_album_links SET passphrase = ? WHERE id = ?').run(newVal, row.id); + } + } + + // --- trek_photos: passphrase --- + const photos = db.prepare('SELECT id, passphrase FROM trek_photos WHERE passphrase IS NOT NULL').all() as { id: number; passphrase: string }[]; + for (const row of photos) { + const newVal = migrateApiKeyValue(row.passphrase, `trek_photos[${row.id}].passphrase`); + if (newVal !== null) { + db.prepare('UPDATE trek_photos SET passphrase = ? WHERE id = ?').run(newVal, row.id); + } + } })(); db.close(); diff --git a/server/src/services/settingsService.ts b/server/src/services/settingsService.ts index 7a0c3253..57f0e6c0 100644 --- a/server/src/services/settingsService.ts +++ b/server/src/services/settingsService.ts @@ -1,7 +1,10 @@ import { db } from '../db/database'; -import { maybe_encrypt_api_key } from './apiKeyCrypto'; +import { decrypt_api_key, maybe_encrypt_api_key } from './apiKeyCrypto'; -const ENCRYPTED_SETTING_KEYS = new Set(['webhook_url', 'ntfy_token']); +const ENCRYPTED_SETTING_KEYS = new Set(['webhook_url', 'ntfy_token', 'mapbox_access_token']); +// Encrypted keys that are masked (••••••••) when returned to the client. +// Keys not in this set but in ENCRYPTED_SETTING_KEYS are decrypted and returned. +const MASKED_SETTING_KEYS = new Set(['webhook_url', 'ntfy_token']); export const DEFAULTABLE_USER_SETTING_KEYS = [ 'temperature_unit', @@ -83,10 +86,14 @@ export function getUserSettings(userId: number): Record { const rows = db.prepare('SELECT key, value FROM settings WHERE user_id = ?').all(userId) as { key: string; value: string }[]; const userSettings: Record = {}; for (const row of rows) { - if (ENCRYPTED_SETTING_KEYS.has(row.key)) { + if (MASKED_SETTING_KEYS.has(row.key)) { userSettings[row.key] = row.value ? '••••••••' : ''; continue; } + if (ENCRYPTED_SETTING_KEYS.has(row.key)) { + userSettings[row.key] = row.value ? (decrypt_api_key(row.value) ?? '') : ''; + continue; + } try { userSettings[row.key] = JSON.parse(row.value); } catch { diff --git a/wiki/Accommodations.md b/wiki/Accommodations.md new file mode 100644 index 00000000..10b78753 --- /dev/null +++ b/wiki/Accommodations.md @@ -0,0 +1,54 @@ +# Accommodations + +Link an accommodation to specific check-in and check-out days so it appears for every day you are staying there. Accommodations are a distinct record type backed by the `day_accommodations` table and are separate from regular reservations, though each accommodation automatically creates a linked **Hotel** reservation. + + + +## Creating an accommodation + +There are two ways to create an accommodation: + +**From the Reservations panel:** Click **Add** and select **Hotel** as the booking type. When the type is set to Hotel, the date/time and location fields are replaced by accommodation-specific inputs (see below). Saving the form creates both the hotel reservation and the underlying accommodation record at the same time. + +**From the Day Detail panel:** Click the hotel icon or the **Add accommodation** button in the Day Detail overlay. A picker appears that lets you select a place from the trip, choose the day range, and optionally fill in check-in/check-out times and a confirmation code. This creates the accommodation record and its linked Hotel reservation together. + +![Accommodation reservation card showing check-in details](assets/Hotel-ReservationCard.png) + +## Accommodation-specific fields + +When creating or editing via the Reservations panel with type set to **Hotel**, the date/time and location fields are replaced by accommodation-specific inputs: + +| Field | Description | +|-------|-------------| +| **Accommodation** | Search for or select an existing trip place to link as the property. Selecting a place pre-fills the title if it is empty and pre-fills the location field if the place has an address | +| **From** | The check-in day | +| **To** | The check-out day | +| **Check-in** | The earliest time you can check in | +| **Check-in until** | The latest time the front desk accepts check-in | +| **Check-out** | The latest time you must check out | + +The **Confirmation code**, **Status** (Pending / Confirmed), and **Notes** fields are also available, as they are for all reservation types. + +## In the Day Detail panel + +For each day between the **From** day and **To** day (inclusive), the accommodation appears in the Day Detail panel overlay. It shows the linked place name and address, a check-in or check-out label for the relevant boundary days, and the check-in window, check-out time, and confirmation code if set. Middle nights show the place name without a check-in/check-out label. The linked Hotel reservation's status and confirmation number are also shown inline. + +![Day planner side bar with accomodation](assets/Hotel-ReservationDaySidebar.png) + +## In the day plan sidebar + +Accommodations appear as small colour-coded badges in the day header row of the day plan sidebar: + +- **Green badge** — check-in day +- **Red badge** — check-out day +- **Neutral badge** — nights in between (ongoing stay) + +Clicking a badge navigates to the linked place. Hotel-type reservations are filtered out of the inline transport card list between places; they do not appear as transport items in the timeline. + +## In the Reservations panel + +Hotel reservation cards in the Reservations panel show the linked accommodation name (place name) alongside the standard reservation fields such as the confirmation code and status. The check-in and check-out times are displayed in the metadata section of the card when they have been set. + +--- + +**See also:** [Reservations-and-Bookings](Reservations-and-Bookings) · [Transport-Flights-Trains-Cars](Transport-Flights-Trains-Cars) · [Day-Plans-and-Notes](Day-Plans-and-Notes) diff --git a/wiki/Addons-Overview.md b/wiki/Addons-Overview.md new file mode 100644 index 00000000..60a40330 --- /dev/null +++ b/wiki/Addons-Overview.md @@ -0,0 +1,34 @@ +# Addons Overview + +Addons are optional features that an admin can enable or disable for the entire TREK instance. When an addon is disabled, its navigation tabs, menu items, and API routes are hidden from all users. + +![Addon overview](assets/Addons-Overview.png) + +## What addons are + +Each addon extends TREK with functionality beyond the core trip-planning features. Addons are managed globally — you cannot enable an addon for one user only. Once enabled, the feature becomes available to all users on the instance. + +## Addon list + +The following addons are registered in the system (defined in `server/src/db/seeds.ts`; the TypeScript constant `ADDON_IDS` in `server/src/addons.ts` covers all addons except `naver_list_import`): + +| Addon ID | Type | Description | +|---|---|---| +| `mcp` | integration | Exposes TREK data and actions through the Model Context Protocol for AI assistant integrations. | +| `packing` | trip | Packing list management — create templates and lists linked to trips. See [Packing-Lists](Packing-Lists). | +| `budget` | trip | Trip budget tracking — log expenses, set budgets, and track spending per trip. See [Budget-Tracking](Budget-Tracking). | +| `documents` | trip | Document and file attachments for trips — store itineraries, visa copies, and other files. See [Documents-and-Files](Documents-and-Files). | +| `vacay` | global | Personal vacation day planner with a year calendar, holiday packs, and collaborator fusion. See [Vacay](Vacay). | +| `atlas` | global | Interactive world map showing countries and regions you have visited, plus a bucket list. See [Atlas](Atlas). | +| `collab` | trip | Notes, polls, and live chat for trip collaboration. See [Real-Time-Collaboration](Real-Time-Collaboration). | +| `journey` | global | Trip tracking and travel journal — check-ins, photos, and daily stories. See [Journey-Journal](Journey-Journal). | +| `naver_list_import` | trip | Import places from shared Naver Maps lists directly into a trip. | + + +## Enabling addons + +> **Admin:** all addons are toggled from the admin panel. Navigate to [Admin-Addons](Admin-Addons) to enable or disable individual addons for your instance. + +## Per-addon sub-features + +Some addons expose sub-features that an admin can independently toggle. The [Real-Time-Collaboration](Real-Time-Collaboration) addon, for example, lets an admin decide which of its four sub-features (chat, notes, polls, and what's next) are active across the instance. These are configured from the [Admin-Addons](Admin-Addons) panel alongside the addon's main toggle. diff --git a/wiki/Admin-Addons.md b/wiki/Admin-Addons.md new file mode 100644 index 00000000..01a418c3 --- /dev/null +++ b/wiki/Admin-Addons.md @@ -0,0 +1,70 @@ +# Admin — Addons + +The **Addons** tab lets you enable or disable optional features for the entire TREK instance. Toggling an addon affects all users immediately — disabling one hides its UI elements and blocks its API routes instance-wide. + + + +![Addon overview](assets/Addons-Overview.png) + +## What addons control + +Each addon toggle controls a feature set. When you disable an addon, users lose access to that feature everywhere in the app. No data is deleted; re-enabling the addon restores access to existing data. + +## Addon categories + +Addons are grouped into three categories, shown as labeled sections. + +### Trip addons + +Trip addons add per-trip feature panels. They appear in every trip where the addon is enabled. + +The default trip addons are: **Lists**, **Budget**, **Documents**, **Collab**, and **Naver List Import** (all enabled by default). The exact list is determined by what is registered in your TREK database. + +**Sub-toggles on trip addons:** + +- **Lists** — when enabled, a nested **Bag Tracking** toggle appears. Bag Tracking lets users assign packed items to specific bags. +- **Collab** — when enabled, four sub-toggles appear for individual collaboration features: + - **Chat** — in-trip real-time chat + - **Notes** — shared trip notes + - **Polls** — trip polls + - **What's Next** — the "what's next" widget + +Each sub-toggle can be disabled independently while the parent addon remains enabled. + +### Global addons + +Global addons add features that are not tied to a single trip. The default global addons are **Vacay**, **Atlas**, and **Journey**. + +- **Vacay** — personal vacation day planner with calendar view. Enabled by default. +- **Atlas** — world map of visited countries with travel stats. Enabled by default. +- **Journey** — trip tracking and travel journal (check-ins, photos, daily stories). **Disabled by default.** + +**Sub-items on global addons:** + +- The **Journey** addon shows photo provider toggles underneath it. Each photo provider (e.g., Immich, Synology Photos) can be enabled or disabled independently. + +### Integration addons + +Integration addons connect TREK to external services. Enabling an integration addon typically requires additional configuration (API keys, URLs) in the **Settings** tab. + +- The **MCP** addon requires `APP_URL` to be set in your environment. When enabled, the **MCP Access** tab appears in the Admin Panel. **Disabled by default.** See [MCP-Overview](MCP-Overview) for full details. + +## Enabling or disabling an addon + +Click the toggle switch on any addon row. The change is applied immediately — no save button is needed. A brief success toast confirms the update. + +If a toggle fails (e.g., network error), it rolls back to its previous state. + +## Additional configuration + +Some addons require credentials or environment variables before they are functional: + +- **Journey** — requires photo provider credentials (Immich or Synology Photos) configured per-user in their personal Settings. See [Photo-Providers](Photo-Providers). +- **MCP** — requires `APP_URL` to be set so OAuth redirect URIs resolve correctly. + +## Related pages + +- [Admin-Panel-Overview](Admin-Panel-Overview) +- [Admin-MCP-Tokens](Admin-MCP-Tokens) +- [MCP-Overview](MCP-Overview) +- [Addons-Overview](Addons-Overview) diff --git a/wiki/Admin-Categories.md b/wiki/Admin-Categories.md new file mode 100644 index 00000000..61ebdcde --- /dev/null +++ b/wiki/Admin-Categories.md @@ -0,0 +1,47 @@ +# Admin — Categories + +The **Personalization** tab → **Categories** section lets you manage global place categories. Categories are shared across all trips and all users on the instance. + + + +![Category Manager](assets/CategoryManager.png) + +## What categories are + +A category is a label consisting of a name, a color, and an icon. Users assign categories to places when creating or editing a place. Categories appear: + +- In the place form's category selector +- As colored chips on place cards +- In the places filter panel +- In the map legend + +## Creating a category + +Click **New Category** (top-right of the category section). A form appears inline: + +1. **Name** — required. Free-text label for the category. +2. **Icon** — a scrollable grid of ~47 curated Lucide icons (Pin, Hotel, Restaurant, Transport, Nature, etc.). Click any icon to select it. The default icon is `MapPin`. +3. **Color** — 12 preset color swatches plus a custom color picker (pipette button). The default color is `#6366f1` (indigo). The 12 presets are: + + `#6366f1` · `#8b5cf6` · `#ec4899` · `#ef4444` · `#f97316` · `#f59e0b` · `#10b981` · `#06b6d4` · `#3b82f6` · `#84cc16` · `#6b7280` · `#1f2937` + +4. A **live preview** chip shows how the category will appear to users as you make selections. + +Click **Create** to save. + +## Editing a category + +Click the pencil icon on any category row. The same form appears in-place with the existing values pre-filled. Change any field and click **Update**. + +## Deleting a category + +Click the trash icon on a category row and confirm. Deletion sets `category_id` to `NULL` on any places that had the category assigned — the places themselves are not affected, they become uncategorized. + +## List ordering + +Categories are always displayed in alphabetical order by name. There is no manual reordering. + +## Related pages + +- [Places-and-Search](Places-and-Search) +- [Admin-Panel-Overview](Admin-Panel-Overview) diff --git a/wiki/Admin-GitHub-Releases.md b/wiki/Admin-GitHub-Releases.md new file mode 100644 index 00000000..fc2196f2 --- /dev/null +++ b/wiki/Admin-GitHub-Releases.md @@ -0,0 +1,50 @@ +# Admin — GitHub Releases + +The **GitHub** tab shows the TREK release history fetched from GitHub and provides links to community resources and support options. + + + +![GitHub tab](assets/GithubReleases.png) + +## Support and resources + +Six cards at the top of the tab link to external resources: + +| Card | Link | +|------|------| +| **Ko-fi** | Support the project financially | +| **Buy Me a Coffee** | Alternative support link | +| **Discord** | Join the TREK community | +| **Report a Bug** | Open a GitHub issue with the bug report template | +| **Feature Request** | Open a GitHub Discussion in the feature requests category | +| **Wiki** | Open the GitHub Wiki | + +## Release timeline + +Below the support cards, a chronological timeline lists GitHub releases for the `mauriceboe/TREK` repository. Each entry shows: + +- **Version tag** (e.g., `v2.9.14`) +- A **Latest** badge on the first (most recent) entry in the displayed list +- **Release date** and author +- A **Show details / Hide details** toggle that expands the release notes (Markdown rendered inline) + +When the running server version is a stable release, pre-release entries are filtered out of the timeline. + +Releases load 10 at a time. Click **Load more** at the bottom of the timeline to fetch additional pages. + +If the admin API request fails, the timeline section shows an error message. If the server cannot reach the GitHub API, the timeline displays no releases (the server returns an empty list rather than an error). + +## Version check + +The server checks for available updates daily at 9 AM (server timezone, defaults to UTC) and sends an admin notification when a newer version is published. When an update is available, a banner also appears at the top of the Admin page on next load. + +Results are cached for 5 minutes to avoid repeated API calls. + +## When to check + +Review the GitHub tab before performing an upgrade to read the release notes for any versions between your current install and the target version. See [Updating](Updating) for the upgrade procedure. + +## Related pages + +- [Updating](Updating) +- [Admin-Panel-Overview](Admin-Panel-Overview) diff --git a/wiki/Admin-MCP-Tokens.md b/wiki/Admin-MCP-Tokens.md new file mode 100644 index 00000000..22ff210a --- /dev/null +++ b/wiki/Admin-MCP-Tokens.md @@ -0,0 +1,48 @@ +# Admin — MCP Tokens + +The **MCP Access** panel shows all active MCP OAuth sessions and API tokens across every user on the instance. As an admin you can revoke sessions and delete tokens. + +This panel is only visible when the **MCP addon** is enabled in the [Admin-Addons](Admin-Addons) panel. + + + +![MCP Access](assets/MCPAccess.png) + +## OAuth Sessions + +OAuth sessions are created when a user authorizes an MCP client via the OAuth 2.1 flow. These are the recommended way to connect MCP clients to TREK. + +**Columns:** + +| Column | Description | +|--------|-------------| +| Client name | The name of the registered OAuth client. Granted scopes are shown as badges below the name (up to 6 are shown; click "+N more" to expand) | +| Owner | The username of the user who authorized the session | +| Created | Date the session was established | +| (actions) | Trash icon button to revoke | + +**Revoking a session:** Click the trash icon on the row and confirm. The session is invalidated immediately and the revocation is recorded in the audit log. The user's MCP client will need to re-authorize before it can make further requests. + +OAuth access tokens use the prefix `trekoa_`. + +## API Tokens + +API tokens are long-lived tokens that users create in their personal settings. They are identified by the `trek_` prefix. + +**Columns:** + +| Column | Description | +|--------|-------------| +| Token name | The label the user gave the token, with its truncated prefix shown below | +| Owner | The username of the user who created it | +| Created | Date the token was created | +| Last used | Date of the most recent API call using this token, or "Never" if unused | +| (actions) | Trash icon button to delete | + +**Deleting a token:** Click the trash icon and confirm. The token is invalidated immediately. The user must create a new token in their settings if they still need access. + +## Related pages + +- [MCP-Overview](MCP-Overview) +- [MCP-Setup](MCP-Setup) +- [Admin-Panel-Overview](Admin-Panel-Overview) diff --git a/wiki/Admin-Packing-Templates.md b/wiki/Admin-Packing-Templates.md new file mode 100644 index 00000000..6ab46757 --- /dev/null +++ b/wiki/Admin-Packing-Templates.md @@ -0,0 +1,65 @@ +# Admin — Packing Templates + +The **Personalization** tab → **Packing Templates** section lets you create reusable packing list templates that users can apply to any trip. + + + +![Packing Template Manager](assets/PackingTemplate.png) + +## What templates are + +A packing template is a three-level hierarchy: + +``` +Template +└── Category + └── Item +``` + +When a user applies a template to a trip, all categories and items from that template are copied into the trip's packing list. + +## Template list + +The template list shows each template as a collapsible row displaying: + +- Template name +- Category count and item count (e.g., `3 categories · 12 items`) +- Edit (rename) and delete buttons + +## Creating a template + +1. Click **New Template** (top-right of the panel). +2. Type a name and press **Enter** or click the confirm button. +3. The new template is added to the list and automatically expanded. + +## Adding categories to a template + +With a template expanded, click **Add category** (dashed border button at the bottom of the expanded section). Type a category name and press **Enter** or click confirm. + +## Adding items to a category + +Click the `+` button inside any category header. An inline input appears below the last item. Type an item name and press **Enter** to add it. You can add multiple items in sequence without closing the input — press **Enter** after each one. + +## Editing inline + +All editing is inline: + +- **Rename a template** — click the pencil icon on the template row. The name becomes an input; press **Enter** or click away to save. +- **Rename a category** — click the pencil icon in the category header. Press **Enter** or click away to save. +- **Rename an item** — hover the item row to reveal the pencil icon, then click it. Press **Enter** or click the confirm button to save (clicking away does not save). + +## Deleting + +- **Delete a template** — click the trash icon on the template row. The template is removed. This does not affect trips that already had items from this template applied. +- **Delete a category** — click the trash icon in the category header. All items in that category are also deleted from the template. +- **Delete an item** — hover the item row to reveal the trash icon. + +## Applying templates to a trip + +Users apply templates through the **Packing** panel inside the trip planner. See [Packing-Templates](Packing-Templates) for user-facing documentation. + +## Related pages + +- [Packing-Templates](Packing-Templates) +- [Packing-Lists](Packing-Lists) +- [Admin-Panel-Overview](Admin-Panel-Overview) diff --git a/wiki/Admin-Panel-Overview.md b/wiki/Admin-Panel-Overview.md new file mode 100644 index 00000000..627e7f2a --- /dev/null +++ b/wiki/Admin-Panel-Overview.md @@ -0,0 +1,39 @@ +# Admin Panel Overview + +The Admin Panel is the central control surface for TREK instance operators. It is only accessible to users with the `admin` role. + +## Accessing the Admin Panel + +Navigate to the **Admin** link in the top navbar. If you do not see it, your account does not have admin privileges. + + + +![Admin Panel](assets/AdminPanel.png) + +## Tabs + +The Admin Panel is divided into tabs. Most tabs are always visible; a few appear only under specific conditions. + +| Tab | Purpose | Conditional? | +|-----|---------|--------------| +| **Users** | Manage users, invite links, and permissions | No | +| **Personalization** | Packing templates and place categories | No | +| **User Defaults** | Default settings applied to new users | No | +| **Addons** | Enable or disable optional features instance-wide | No | +| **Settings** | Authentication methods, MFA, allowed file types, API keys, OIDC/SSO configuration, and JWT secret rotation | No | +| **Notifications** | SMTP, webhook, ntfy, and push notification channel configuration; trip reminder toggle; admin notification preferences | No | +| **Backup** | Manual and scheduled database backups | No | +| **Audit** | Chronological activity log | No | +| **MCP Access** | OAuth sessions and static API tokens | Only when the MCP addon is enabled | +| **GitHub** | Release timeline and support links | No | +| **Dev: Notifications** | Test notification dispatch | Only in development mode (`NODE_ENV=development`) | + +## Related pages + +- [Admin-Users-and-Invites](Admin-Users-and-Invites) +- [Admin-Addons](Admin-Addons) +- [Admin-Categories](Admin-Categories) +- [Admin-Packing-Templates](Admin-Packing-Templates) +- [Admin-Permissions](Admin-Permissions) +- [Admin-MCP-Tokens](Admin-MCP-Tokens) +- [Admin-GitHub-Releases](Admin-GitHub-Releases) diff --git a/wiki/Admin-Permissions.md b/wiki/Admin-Permissions.md new file mode 100644 index 00000000..16bb08a8 --- /dev/null +++ b/wiki/Admin-Permissions.md @@ -0,0 +1,76 @@ +# Admin — Permissions + +The Permissions panel, located at the bottom of the **Users** tab, controls which role level is required to perform each action. Changes apply immediately across the entire instance. + + + +![Permissions panel](assets/PermissionSettings.png) + +## Role model + +TREK uses four permission levels, ordered from most to least privileged: + +| Level | Who it includes | +|-------|----------------| +| `admin` | Instance administrators only | +| `trip_owner` | The user who created the trip | +| `trip_member` | Any user who is a member of the trip | +| `everybody` | Any authenticated user (for `trip_create`: no trip context required; for all other actions: any authenticated user with trip access) | + +Each action is assigned a minimum required level. A user whose role is at or above that level can perform the action. Not every level is available for every action — each action exposes only the levels that make sense for it. For example, `trip_create` only allows `everybody` or `admin`, while `trip_edit` only allows `trip_owner` or `trip_member`. + +## Action categories + +Actions are grouped into five categories: + +### Trip + +| Action key | What it controls | +|------------|-----------------| +| `trip_create` | Create a new trip | +| `trip_edit` | Edit trip name, dates, description, and currency | +| `trip_delete` | Permanently delete a trip | +| `trip_archive` | Archive or unarchive a trip | +| `trip_cover_upload` | Upload or change the cover image for a trip | + +### Members + +| Action key | What it controls | +|------------|-----------------| +| `member_manage` | Invite or remove trip members | + +### Files + +| Action key | What it controls | +|------------|-----------------| +| `file_upload` | Upload files to a trip | +| `file_edit` | Edit file descriptions and links | +| `file_delete` | Move files to trash or permanently delete them | + +### Content & Schedule + +| Action key | What it controls | +|------------|-----------------| +| `place_edit` | Add, edit, or delete places | +| `day_edit` | Edit days, day notes, and place assignments | +| `reservation_edit` | Create, edit, or delete reservations | + +### Budget, Packing & Collaboration + +| Action key | What it controls | +|------------|-----------------| +| `budget_edit` | Create, edit, or delete budget items | +| `packing_edit` | Manage packing items and bags | +| `collab_edit` | Create notes, polls, and send messages | +| `share_manage` | Create or delete public share links | + +## Changing permissions + +Each action row has a dropdown. Select the minimum role level required. A **customized** badge appears next to any action that has been changed from its default. + +Click **Save** (top-right of the panel) to persist your changes. Use the **Reset to defaults** button (circular arrow icon) to revert all actions to their shipped defaults without saving — you still need to click **Save** after resetting if you want to persist the reset state. + +## Related pages + +- [Admin-Panel-Overview](Admin-Panel-Overview) +- [Admin-Users-and-Invites](Admin-Users-and-Invites) diff --git a/wiki/Admin-Users-and-Invites.md b/wiki/Admin-Users-and-Invites.md new file mode 100644 index 00000000..b44be98f --- /dev/null +++ b/wiki/Admin-Users-and-Invites.md @@ -0,0 +1,90 @@ +# Admin — Users and Invites + +The **Users** tab in the Admin Panel lets you view all registered users, manage their accounts, and create invite links so new people can register without open registration. + + + +![Users tab](assets/UsersAndInvites.png) + +## User list + +The user table shows every registered account with the following columns: + +| Column | Description | +|--------|-------------| +| **User** | Avatar, username, and an always-visible presence dot (green = online, grey = offline) | +| **Email** | Account email address | +| **Role** | Badge showing `admin` or `user` | +| **Created** | Account creation date | +| **Last Login** | Date and time of most recent login | +| **Actions** | Edit and delete buttons | + +Your own account row is highlighted. You cannot delete your own account. + +## User actions + +### Edit a user + +Click the pencil icon on any row to open the edit form. You can change: + +- **Username** +- **Email address** +- **Role** — toggle between `user` and `admin` +- **Password** — set a new password; must be at least 8 characters + +Click **Save** to apply changes. + +### Delete a user + +Click the trash icon and confirm. Deletion is permanent. The user's account is removed from the database along with their data (cascade behavior is enforced at the database level). + +You cannot delete your own account while logged in as that user. + +## Creating a user directly + +Click **Create User** (top-right of the Users tab) to create an account without an invite link. You set the username, email, password, and role at creation time. + +## Invite links + +Invite links let a specific number of people register themselves. This is useful when open registration is disabled. + +![Invite links](assets/InviteLinkForm.png) + +### Creating an invite + +Click **Create Invite** (invite links section, below the user table). Configure: + +- **Max uses** — how many times the link can be used before it expires: `1×`, `2×`, `3×`, `4×`, `5×`, or `∞` (unlimited). Defaults to `1×`. +- **Expiry** — how long the link remains valid: `1d`, `3d`, `7d`, `14d`, or `∞` (no expiry). Defaults to `7d`. + +After creation the link is copied to your clipboard automatically. Share it with the intended recipient. The URL format is: + +``` +/register?invite= +``` + +### Invite list + +Existing invites are listed below the creation button. Each row shows: + +- The invite token (truncated, monospace) +- A status badge — `active`, `used up`, or `expired` +- **Usage** — `used / max` (or `used / ∞` for unlimited) +- **Expiry** date, if set +- **Created by** — the admin who generated the link +- A **copy link** button (only shown for active invites) +- A **delete** (revoke) button + +Revoking an invite immediately invalidates it; anyone following the link after revocation will receive an error. + +## Permissions + +The **Users** tab also hosts the Permissions panel at the bottom, which controls what roles can perform which actions. See [Admin-Permissions](Admin-Permissions) for details. + +## Related pages + +- [Login-and-Registration](Login-and-Registration) +- [Invite-Links](Invite-Links) +- [Admin-Permissions](Admin-Permissions) +- [Two-Factor-Authentication](Two-Factor-Authentication) +- [Admin-Panel-Overview](Admin-Panel-Overview) diff --git a/wiki/Atlas.md b/wiki/Atlas.md new file mode 100644 index 00000000..a3fd81b5 --- /dev/null +++ b/wiki/Atlas.md @@ -0,0 +1,55 @@ +# Atlas + +Atlas is an interactive world map that shows countries and regions you have visited across all your trips, together with a bucket list of places you want to go. + +> **Admin:** enable Atlas in [Admin-Addons](Admin-Addons). + + + +![Atlas](assets/Atlas.png) + +## What Atlas is + +Atlas gives you a visual overview of your travel footprint. Visited countries are highlighted on the map. You can also mark individual sub-national regions and maintain a personal bucket list of future destinations. + +## Accessing Atlas + +When the admin has enabled the Atlas addon, an **Atlas** entry appears in the main navigation. Your visited countries are populated automatically from your existing trips. + +## Marking countries as visited + +Click any country on the map to open an action popup where you can mark it as visited or add it to your bucket list. Use the search bar at the top of the map to find and fly to a country — pressing Enter or selecting a result from the dropdown opens the same action popup. + +To remove a manually-marked country (one with no trips or places recorded in it), click it on the map and confirm removal in the popup. + +Visits detected automatically from your trips are shown in addition to any countries you mark manually. + +### Sub-national regions + +At zoom level 5 and above, the map switches to a sub-national region view (states, provinces, etc.). You can mark individual regions as visited or add them to your bucket list. Marking a region also counts the parent country as visited if it was not already. + +## Bucket list + +The bucket list is separate from "visited". Use it to track countries or places you want to visit in the future. Each bucket list item can have a name, coordinates, country code, optional notes, and a target date. + +## Statistics + +Your Atlas statistics panel shows: + +- **Countries visited** — total number of distinct countries. +- **Trips** — total number of trips across all time. +- **Places** — total number of individual places logged in trips. +- **Cities** — total number of distinct cities visited. +- **Travel days** — total days spent travelling. +- **Continent breakdown** — number of countries visited per continent (Europe, Asia, North America, South America, Africa, Oceania). +- **Travel streak** — number of consecutive years in which you have taken at least one trip. +- **Trips this year** — number of trips in the current calendar year. + +## Visual effect + +The desktop glass panel at the bottom of the map uses a liquid-glass visual effect — a dynamic inner glow and border highlight that follows your cursor across the panel. + +## See also + +- [Addons-Overview](Addons-Overview) +- [Admin-Addons](Admin-Addons) diff --git a/wiki/Audit-Log.md b/wiki/Audit-Log.md new file mode 100644 index 00000000..c6fbd52e --- /dev/null +++ b/wiki/Audit-Log.md @@ -0,0 +1,138 @@ +# Audit Log + +The audit log records significant actions taken on your TREK instance. Use it to monitor logins, admin changes, and integration configuration. + +## Where to find it + +**Admin Panel → Audit** tab. + + + +![Audit log](assets/Audit.png) + +## What the log captures + +Actions are grouped by area below. The **Action key** is the raw value stored in the log. + +### Authentication + +| Action key | Description | +|---|---| +| `user.register` | User registered | +| `user.login` | User logged in | +| `user.login_failed` | Login attempt failed | +| `user.password_change` | User changed their password | +| `user.account_delete` | User deleted their account | + +### MFA + +| Action key | Description | +|---|---| +| `user.mfa_enable` | MFA enabled on an account | +| `user.mfa_disable` | MFA disabled on an account | + +### Trips + +| Action key | Description | +|---|---| +| `trip.create` | Trip created (includes title) | +| `trip.update` | Trip updated (includes changed fields) | +| `trip.copy` | Trip duplicated (includes source and new trip IDs) | +| `trip.delete` | Trip deleted (includes trip ID and title) | + +### Admin actions + +| Action key | Description | +|---|---| +| `admin.user_create` | User created by admin | +| `admin.user_update` | User edited by admin (role, email, username, etc.) | +| `admin.user_delete` | User deleted by admin | +| `admin.invite_create` | Invite link created | +| `admin.invite_delete` | Invite link deleted | +| `admin.permissions_update` | Instance permissions updated | +| `admin.oidc_update` | OIDC/SSO settings updated | +| `admin.addon_update` | Addon enabled, disabled, or configured | +| `admin.oauth_session.revoke` | OAuth session revoked by admin | +| `admin.rotate_jwt_secret` | JWT secret rotated | +| `admin.bag_tracking` | Bag tracking feature toggled | +| `admin.places_photos` | Places photos feature toggled | +| `admin.places_autocomplete` | Places autocomplete feature toggled | +| `admin.places_details` | Places details feature toggled | +| `admin.collab_features` | Collaboration features updated | +| `admin.packing_template_delete` | Packing template deleted | +| `admin.default_user_settings_update` | Default user settings updated | +| `admin.demo_baseline_save` | Demo baseline snapshot saved | +| `settings.app_update` | App settings updated (SMTP, webhooks, MFA policy, etc.) | + +### Backups + +| Action key | Description | +|---|---| +| `backup.create` | Manual backup created | +| `backup.restore` | Restore from stored backup | +| `backup.upload_restore` | Restore from uploaded ZIP | +| `backup.delete` | Backup deleted | +| `backup.auto_settings` | Auto-backup schedule saved | + +### MCP + +| Action key | Description | +|---|---| +| `mcp.tool_call` | MCP tool invoked (resource = tool name) | + +### OAuth + +| Action key | Description | +|---|---| +| `oauth.client.create` | OAuth client application created | +| `oauth.client.rotate_secret` | OAuth client secret rotated | +| `oauth.client.delete` | OAuth client application deleted | +| `oauth.consent.grant` | User granted OAuth consent | +| `oauth.token.issue` | OAuth access token issued | +| `oauth.token.refresh` | OAuth access token refreshed | +| `oauth.token.revoke` | OAuth token revoked | +| `oauth.token.grant_failed` | OAuth token grant attempt failed | +| `oauth.token.client_auth_failed` | OAuth client authentication failed | + +### Integrations + +| Action key | Description | +|---|---| +| `immich.private_ip_configured` | Immich URL saved that resolves to a private IP | + +## Log columns + +| Column | Description | +|---|---| +| Time | Timestamp of the action | +| User | Username and email of the acting user (or `anonymous` for unauthenticated events) | +| Action | Action key (see tables above) | +| Resource | Affected resource (filename, trip ID, tool name, etc.) where applicable | +| IP | Client IP address | +| Details | Additional context in JSON format | + +## Pagination + +The panel loads 100 entries at a time by default. Click **Load more** at the bottom to fetch the next page. The total count is shown above the table. + +## IP addresses + +The client IP is read from the `X-Forwarded-For` header. When TREK is behind a reverse proxy, set `TRUST_PROXY=true` so the header is trusted and the real client IP is recorded. Without this setting, the proxy's own IP is logged instead. See [Environment-Variables](Environment-Variables). + +## Log file + +In addition to the database, audit events are written to a plain-text log file: + +- **Path:** `./data/logs/trek.log` +- **Rotation:** rotated when the file reaches 10 MB +- **Retention:** the 4 most recent rotated files are kept (`trek.log.1` through `trek.log.4`) + +## Database retention + +Audit entries in the database are never automatically deleted. They accumulate and are paginated in the UI. + +## See also + +- [Admin-Panel-Overview](Admin-Panel-Overview) +- [Security-Hardening](Security-Hardening) +- [Environment-Variables](Environment-Variables) diff --git a/wiki/Backups.md b/wiki/Backups.md new file mode 100644 index 00000000..cf6d927e --- /dev/null +++ b/wiki/Backups.md @@ -0,0 +1,88 @@ +# Backups + +TREK stores all data in a single SQLite database (`travel.db`) plus an `uploads/` directory of attachments, cover photos, and avatars. The Backup panel lets you create, download, restore, and schedule backups of both. + +## Where to find it + +**Admin Panel → Backup** tab. + + + +![Backup tab](assets/Backup.png) + +## What a backup contains + +A backup is a ZIP archive with two entries: + +| Entry | Contents | +|---|---| +| `travel.db` | The full SQLite database | +| `uploads/` | All uploaded attachments, covers, and avatars | + +**Not included:** the encryption key. Store your `ENCRYPTION_KEY` separately from the backup ZIP — for example, in a password manager. See [Encryption-Key-Rotation](Encryption-Key-Rotation). + +## Manual backup + +Click **Create Backup** in the Backup tab. The server creates the ZIP and makes it available for download. Up to 3 manual backups can be created per hour per IP address (rate-limit window: 1 hour). + +You can also download or delete any existing backup from the list. + +## Restoring a backup + +You can restore from: + +- **A stored backup** — click **Restore** next to any backup in the list. +- **An uploaded ZIP** — click **Upload & Restore** and select a backup file from your computer (maximum upload size: 500 MB). + +Before restoring, TREK runs integrity checks on the uploaded database: + +1. **SQLite `PRAGMA integrity_check`** — verifies the database file is not corrupt. +2. **Required tables present** — confirms the file contains `users`, `trips`, `trip_members`, `places`, and `days`. Files missing any of these are rejected as not being a valid TREK backup. + +> **Warning:** Restoring replaces all current data. Back up your current state first if you want to keep it. + +## Auto-backup + +Enable scheduled backups in the **Auto-Backup** section of the Backup tab. + +**Interval** options: + +- Hourly +- Daily +- Weekly +- Monthly + +**Retention** (`Keep last … days`) — enter a number of days. Backups older than that many days are pruned after each auto-backup run. Set to **0** to keep all backups indefinitely (no pruning). + +**Schedule** options (depend on interval): + +- **Hour** — time of day for daily, weekly, and monthly backups (0–23). +- **Day of week** — Sunday through Saturday (for weekly backups). +- **Day of month** — 1–28 (for monthly backups). Day 29–31 is excluded to avoid months with fewer days. + +Auto-backup files are named `auto-backup-.zip` (manual backups use `backup-.zip`). + +After each auto-backup run, **all** backup files (manual and auto) older than `keep_days` are pruned. Set `keep_days` to `0` to disable pruning entirely. + +## Before updating TREK + +Always create a manual backup before updating. See [Updating](Updating). + +## Audit log + +The following actions are recorded in the [Audit-Log](Audit-Log): + +| Action key | When | +|---|---| +| `backup.create` | Manual backup created | +| `backup.restore` | Restore from stored backup | +| `backup.upload_restore` | Restore from uploaded ZIP | +| `backup.delete` | Backup deleted | +| `backup.auto_settings` | Auto-backup settings saved | + +## See also + +- [Encryption-Key-Rotation](Encryption-Key-Rotation) +- [Admin-Panel-Overview](Admin-Panel-Overview) +- [Security-Hardening](Security-Hardening) +- [Updating](Updating) diff --git a/wiki/Budget-Tracking.md b/wiki/Budget-Tracking.md new file mode 100644 index 00000000..4839681b --- /dev/null +++ b/wiki/Budget-Tracking.md @@ -0,0 +1,83 @@ +# Budget Tracking + +Track trip expenses by category, split costs between members, and visualize spending. + + + +![Budget panel](assets/Budget.png) + +## Where to find it + +Open the **Budget** tab inside the trip planner. The tab is only visible when the Budget addon is enabled. + +> **Admin:** Budget is an addon. Enable it in [Admin-Addons](Admin-Addons). + +## Currency + +Use the currency picker in the Budget toolbar to select one currency for the entire trip. 46 currencies are supported (EUR, USD, GBP, JPY, CHF, CZK, PLN, SEK, NOK, DKK, TRY, THB, AUD, CAD, NZD, BRL, MXN, INR, IDR, MYR, PHP, SGD, KRW, CNY, HKD, TWD, ZAR, AED, SAR, ILS, EGP, MAD, HUF, RON, BGN, HRK, ISK, RUB, UAH, BDT, LKR, VND, CLP, COP, PEN, ARS). All amounts are displayed in this currency. + +## Categories + +Expenses are grouped into categories. Each category is shown with a small colored square indicator that cycles through a 12-color palette as you add more categories. + +From the toolbar you can: + +- **Add a category** — type a name and click the **+** button (or press Enter). +- **Rename a category** — click the pencil icon next to its name in the category header. +- **Reorder categories** — drag the grip handle on the left of the category header. +- **Delete a category** — click the trash icon in the category header. This deletes all expense items inside it. + +## Expense items + +Each category contains a table of items with the following columns: + +| Column | Notes | +|---|---| +| Name | Editable inline. Read-only when linked to a reservation. | +| Total | The total cost for this item. | +| Persons | Number of persons (or member chips on multi-member trips). | +| Days | Number of days. | +| Per Person | Calculated: Total ÷ Persons. | +| Per Day | Calculated: Total ÷ Days. | +| Per Person/Day | Calculated: Total ÷ (Persons × Days). | +| Date | Optional expense date. | +| Note | Free-text note. | + +Click any editable cell to edit it inline. Drag the grip handle to reorder items within a category. + +Add a new item using the inline **add row** at the bottom of each category table. + +## Splitting costs + +The **Persons** column behaves differently depending on the trip: + +- **Single-user trip** — enter a number of persons directly. +- **Multi-member trip** — a member chip picker appears. Click the edit button to assign or remove members from an expense. Click an assigned member chip again to mark them as **paid** (the chip shows a green ring). + +## Settlement calculator + +When multiple members are assigned to expenses and there are outstanding debts between members, a collapsible **Settlement** section appears inside the total card. Click the section header to expand it. It shows the minimum number of transfers needed to settle all debts (using a greedy matching algorithm), including: + +- Transfer flows: who pays whom and how much. +- Net balances: each member's overall surplus or deficit. + +## Budget summary + +The right-hand column contains two widgets: + +- **Total card** — displays the grand total in large type. On multi-member trips it also shows a per-member breakdown with a proportional bar. +- **Donut chart** — spending by category. Each segment uses that category's color. The legend always shows the amount and percentage for each category; hovering a legend row highlights it. + +## Exporting + +Click the **CSV** button in the toolbar to download a semicolon-delimited file containing all categories and items. The columns exported are: Category, Name, Date, Total, Persons, Days, Per Person, Per Day, Per Person/Day, Note. + +## Permissions + +All write operations (adding/editing/deleting items and categories, changing currency) require the `budget_edit` permission. + +## See also + +- [Admin-Addons](Admin-Addons) +- [Reservations-and-Bookings](Reservations-and-Bookings) +- [Trip-Planner-Overview](Trip-Planner-Overview) diff --git a/wiki/Collab-Chat.md b/wiki/Collab-Chat.md new file mode 100644 index 00000000..4236d93a --- /dev/null +++ b/wiki/Collab-Chat.md @@ -0,0 +1,59 @@ +# Collab Chat + +Chat with your group in real time, without leaving the trip planner. + + + +![Collab Chat](assets/Collab.png) + +## Where to find it + +Open the trip planner and select the **Collab** tab. If the Chat sub-feature is enabled, a Chat panel appears — on desktop as the left column, on mobile as the first tab in the tab bar. + +The Collab addon must be enabled by an admin and the Chat sub-feature must be turned on. See [Real-Time-Collaboration](Real-Time-Collaboration). + +## Sending messages + +Type in the input field at the bottom and press **Enter** (or click the send button) to post. Hold **Shift + Enter** to insert a line break without sending. + +Messages load in pages of 100. A **Load more** button appears at the top of the chat when older messages are available. + +## Emoji + +Click the smiley-face button in the composer to open the emoji picker. The picker has three categories: + +- **Smileys** — facial expressions and gestures +- **Reactions** — hearts, fire, thumbs, and similar +- **Travel** — planes, maps, food, cameras, and destinations + +Emoji are rendered via Twemoji for consistent appearance across platforms. + +## Reactions + +**Right-click** a message on desktop (or **double-tap** on mobile) to open the quick-reaction menu. Eight quick reactions are available: ❤️ 😂 👍 😮 😢 🔥 👏 🎉. Click any reaction to toggle it on or off. Reactions from all users aggregate beneath the message; hover a reaction badge to see who reacted. + +## Replies + +Hover a message to reveal the action buttons. Click **Reply** to quote that message. A preview of the quoted text appears above your new message in the composer; click the **×** to cancel the reply. The quoted text is displayed inline inside your bubble when sent. + +## URL link previews + +When a message contains a URL, TREK automatically fetches an Open Graph preview (title, description, and thumbnail image) and displays it below the message text. Only the first URL in a message generates a preview. + +## Message styling + +Your own messages appear **right-aligned** with a blue bubble. Other members' messages appear **left-aligned** with a gray bubble. The username is shown above the first message in a group of consecutive messages from the same person; the avatar is shown beside the **last** message in that group. Timestamps appear below the last message in each group. + +Messages that consist of only 1–3 emoji are displayed larger without a bubble. + +## Deleting messages + +Hover your own message to reveal the delete button (trash icon). The delete button is only visible when you have the `collab_edit` permission. Deleting replaces the bubble with an italicised notice — showing your username, "deleted a message", and a timestamp — visible to all members. + +## Read-only viewers + +Users without the `collab_edit` permission can read all messages but the composer is disabled — they cannot send, react, or delete messages. The reply button is visible to all users, but completing a reply still requires `collab_edit` (the send button is hidden for read-only users). + +## Related pages + +[Real-Time-Collaboration](Real-Time-Collaboration) · [Collab-Notes](Collab-Notes) · [Collab-Polls](Collab-Polls) diff --git a/wiki/Collab-Notes.md b/wiki/Collab-Notes.md new file mode 100644 index 00000000..ca1fd286 --- /dev/null +++ b/wiki/Collab-Notes.md @@ -0,0 +1,72 @@ +# Collab Notes + +Share structured, richly formatted notes with your group. Notes are organized into color-coded categories and can be pinned, attached with files, and linked to external websites. + + + +![Collab Notes](assets/Collab.png) + +## Where to find it + +Open the trip planner → **Collab** tab → **Notes** section. The Collab addon must be enabled and the Notes sub-feature must be turned on. See [Real-Time-Collaboration](Real-Time-Collaboration). + +## Categories + +Notes are grouped into categories. Each category has a name and a color chosen from six swatches: **Indigo**, **Red**, **Amber**, **Emerald**, **Blue**, and **Violet**. + +To manage categories, click the settings (gear) icon in the Notes header (only visible to users with the `collab_edit` permission). From the category settings modal you can: + +- Add a new category (type a name and click **+**) +- Rename a category by clicking its name inline +- Change a category's color by clicking a swatch +- Delete a category + +All changes (including color updates) are staged locally and applied only when you click **Save** in the modal. Saving a color change updates every note in that category. + +## Creating a note + +Click **+ New Note** in the Notes header (only visible to users with the `collab_edit` permission). A modal opens with the following fields: + +| Field | Required | Notes | +|-------|----------|-------| +| Title | Yes | Plain text | +| Body | No | Markdown | +| Category | No | Select from existing categories | +| Website | No | URL; shows an Open Graph thumbnail on the note card | +| Attachments | No | Files up to 50 MB; see restrictions below | + +Click **Create** to save. + +## Markdown support + +Note bodies are rendered as GitHub Flavored Markdown with soft line breaks. Supported syntax includes headings, bold/italic, links, ordered and unordered lists, task lists, tables, fenced code blocks, and blockquotes. + +## Pinning + +Click the pin icon on a note card to pin it. Pinned notes sort to the top of the list (above all unpinned notes, regardless of category). Click again (shown as the unpin icon) to unpin. + +## Attachments + +You can attach images, PDFs, and other files to a note (requires the `file_upload` permission). Maximum file size is **50 MB** per file. + +The following file types are blocked: `.svg`, `.html`, `.htm`, `.xml`, `.xhtml`, `.js`, `.jsx`, `.ts`, `.exe`, `.bat`, `.sh`, `.cmd`, `.msi`, `.dll`, `.com`, `.vbs`, `.ps1`, `.php`. + +Image thumbnails are shown on the note card. Click a thumbnail to open a lightbox. PDFs open in a document viewer overlay. + +You can also paste images or PDFs directly into the create/edit form (if the `file_upload` permission is granted). + +## Editing a note + +Click the pencil icon on a note card to open the edit modal. All fields, including attachments, can be updated. To remove an existing attachment, click the **×** next to it in the edit form. + +## Expanding a note + +Click the expand icon (arrows) on a note card to open a full-content view in a portal overlay. Users with the `collab_edit` permission will see a pencil button in the overlay header to switch directly to the edit modal. + +## Filtering + +Use the category filter pills below the Notes header to show only notes belonging to a specific category. Click **All** to clear the filter. + +## Related pages + +[Real-Time-Collaboration](Real-Time-Collaboration) · [Collab-Chat](Collab-Chat) · [Collab-Polls](Collab-Polls) diff --git a/wiki/Collab-Polls.md b/wiki/Collab-Polls.md new file mode 100644 index 00000000..3a4ce8a0 --- /dev/null +++ b/wiki/Collab-Polls.md @@ -0,0 +1,61 @@ +# Collab Polls + +Create group polls to make decisions collaboratively — where to eat, which hotel, what to do on a free day. + + + +![Collab Polls](assets/Collab.png) + +## Where to find it + +Open the trip planner → **Collab** tab → **Polls** section. The Collab addon must be enabled and the Polls sub-feature must be turned on. See [Real-Time-Collaboration](Real-Time-Collaboration). + +## Creating a poll + +Users with `collab_edit` permission can click **+ New** in the Polls header. A modal opens with the following fields: + +| Field | Required | Notes | +|-------|----------|-------| +| Question | Yes | The poll prompt | +| Options | Yes | At least 2 options required; add more with **+ Add option** | +| Multiple choice | No | Toggle on to allow voters to select more than one option | + +Click **Create** to save and broadcast the poll to all connected members. + +## Voting + +Click an option button to vote. A filled circle and blue highlight indicate your selection. For **multiple-choice** polls, you can click additional options to select more than one; clicking an already-selected option removes your vote for that option. For **single-choice** polls, clicking a different option moves your vote to the new selection. + +Percentage bars and voter avatars are only visible **after you have voted** or once the poll is closed or expired. + +## Results + +Each option shows: + +- A **percentage fill bar** that expands proportionally to the votes received +- Up to **3 voter avatar chips** stacked next to the option +- The **percentage** of total votes in the right margin + +The option with the most votes is highlighted when the poll is closed or expired. + +## Deadline + +Polls may have an optional deadline set via the API. When a deadline is present, a live countdown badge appears on the poll card, updating every **30 seconds**. The badge shows the remaining time in days/hours/minutes format. + +When the deadline passes, the poll is automatically treated as closed: voting is disabled and results are displayed to everyone. + +## Closing a poll manually + +Users with `collab_edit` permission can click the lock icon on an open poll to close it immediately. Once closed, voting is permanently disabled. + +## Deleting a poll + +Users with `collab_edit` permission can delete a poll using the trash icon. Deletion is permanent and removes the poll for all members. + +## Active and closed sections + +Open polls appear at the top of the list. Closed or expired polls move to a **Closed** section below the active polls. + +## Related pages + +[Real-Time-Collaboration](Real-Time-Collaboration) · [Collab-Chat](Collab-Chat) · [Collab-Notes](Collab-Notes) diff --git a/wiki/Creating-a-Trip.md b/wiki/Creating-a-Trip.md new file mode 100644 index 00000000..1e8e9bcb --- /dev/null +++ b/wiki/Creating-a-Trip.md @@ -0,0 +1,71 @@ +# Creating a Trip + + + +![Trip creation dialog](assets/TripCreate.png) + +## Opening the Dialog + +Click the **New Trip** button in the dashboard toolbar (or the **Create First Trip** button on the empty state) to open the Create Trip dialog. + +You can also open it directly via a deep link: navigate to `/dashboard?create=1`. This is the URL used by system notices that prompt you to create a trip. + +## Fields + +### Title (required) + +The trip name. Cannot be empty — saving is blocked until a title is entered. + +### Description (optional) + +A short free-text description shown on the trip card. + +### Dates + +Set a **Start date** and **End date** using the date picker. The day count is calculated automatically when both are set. + +If you leave **both** dates empty, a separate **Day count** field appears. Enter a number between **1 and 365** to create a date-less itinerary with a fixed number of days. + +You cannot set only one date and leave the other blank via normal interaction — setting a start date auto-fills or adjusts the end date to preserve the previous duration. + +### Cover Image + +The cover image is displayed on the trip card and as the background of the Spotlight card. You can add one in three ways: + +- **Drag and drop** an image file onto the dashed upload area. +- **Paste from clipboard** — if you have an image in your clipboard, paste it anywhere in the dialog. +- **File picker** — click the upload area to browse for a file. + +When **creating** a new trip the cover image field is always visible. When **editing** an existing trip it is only shown if you have the `trip_cover_upload` permission. For a new trip, the image is uploaded immediately after the trip is created. + +### Reminder + +A push notification sent before the trip departs. The field shows a set of preset options: + +| Option | Days before departure | +|---|---| +| None | 0 | +| 1 day | 1 | +| 3 days | 3 | +| 9 days | 9 | +| Custom | 1–30 (you enter the number) | + +When **creating** a new trip the reminder field is always visible. When **editing** an existing trip it is only shown to the **trip owner** or **admin** users. + +If reminders are disabled on your instance (`trip_reminders_enabled = false`), the reminder section is shown at reduced opacity with an informational message in place of the preset buttons. + +> **Admin:** Trip reminders are controlled by a server-side feature flag (`trip_reminders_enabled`). Contact your administrator to enable them. + +### Members + +Add initial trip members from the members selector. On a **new** trip, selected members are queued locally and added to the trip immediately after it is saved. The selector shows all registered users on your instance except yourself. + +## Saving + +Click **Create Trip**. The trip is saved and you are taken to the [Trip-Planner-Overview](Trip-Planner-Overview) for the new trip. + +## Related Pages + +- [Trip-Members-and-Sharing](Trip-Members-and-Sharing) +- [Trip-Planner-Overview](Trip-Planner-Overview) +- [My-Trips-Dashboard](My-Trips-Dashboard) diff --git a/wiki/Dashboard-Widgets.md b/wiki/Dashboard-Widgets.md new file mode 100644 index 00000000..98705a11 --- /dev/null +++ b/wiki/Dashboard-Widgets.md @@ -0,0 +1,62 @@ +# Dashboard Widgets + +The My Trips dashboard includes two utility widgets: a currency converter and a timezone clock. + + + +![Dashboard Widgets](assets/DashboardWidgets.png) + +## Where they appear + +On large screens (desktop/wide tablet), both widgets appear in a sticky right-hand sidebar of the [My-Trips-Dashboard](My-Trips-Dashboard). On mobile and narrow screens, the widgets are accessible via **Quick Actions** buttons on the dashboard — tapping the Currency or Timezone button opens a bottom sheet containing the full widget. + +Each user configures their own widgets independently. Whether each widget is shown or hidden is saved to your account on the server (synced across devices). The selected currency pair and saved timezone list are stored in your browser's local storage and are device-specific. + +### Showing and hiding widgets + +On desktop, click the **Settings (gear) icon** in the dashboard toolbar to reveal toggle switches for each widget. Turning a widget off removes it from the sidebar; the preference is saved to your account. + +--- + +## Currency Converter + +The currency converter lets you quickly convert an amount between two currencies. + +**How to use:** + +1. Enter an amount in the input field. +2. Select a source currency from the left selector. +3. Select a target currency from the right selector. +4. The converted amount is displayed immediately below. + +You can also click the swap arrow to reverse source and target. + +**Exchange rates** are fetched from [exchangerate-api.com](https://www.exchangerate-api.com) using the `https://api.exchangerate-api.com/v4/latest/{from}` endpoint. Rates are refreshed each time you change a currency or click the refresh icon. + +**Supported currencies:** 162 currencies are available in the selector, including all major fiat currencies (USD, EUR, GBP, JPY, etc.) and many minor ones. + +--- + +## Timezone Clock + +The timezone clock displays live clocks for multiple time zones simultaneously. + +**How to use:** + +- Your local time is always shown at the top. +- Below it, any zones you have added are listed with their current time and offset relative to your local zone. +- Click **+** to add a zone. You can pick from 18 preset city zones, or enter any IANA timezone identifier (e.g. `America/Denver`) with an optional custom label (if omitted, the city portion of the identifier is used as the label). +- Hover over a zone row and click **×** to remove it. + +**Preset zones (18):** + +New York, London, Berlin, Paris, Dubai, Mumbai, Bangkok, Tokyo, Sydney, Los Angeles, Chicago, São Paulo, Istanbul, Singapore, Hong Kong, Seoul, Moscow, Cairo. + +Clocks update every 10 seconds. The 12-hour or 24-hour format follows your display settings (see [Display-Settings](Display-Settings)). + +--- + +## See also + +- [My-Trips-Dashboard](My-Trips-Dashboard) +- [Addons-Overview](Addons-Overview) diff --git a/wiki/Day-Plans-and-Notes.md b/wiki/Day-Plans-and-Notes.md new file mode 100644 index 00000000..b26c74f1 --- /dev/null +++ b/wiki/Day-Plans-and-Notes.md @@ -0,0 +1,73 @@ +# Day Plans and Notes + +The Day Plan sidebar lets you organize places into days, add free-form notes, and manage the order of your itinerary. + + + +![Day Plan](assets/TripPlaner.png) + +## The Day Plan sidebar + +The Day Plan sidebar is the left panel in the trip planner. Each trip day is shown as a collapsible section. Expanded or collapsed state is saved per trip in `sessionStorage` (key: `day-expanded-{tripId}`), so your layout is preserved across page reloads in the same browser session. + +## Day timeline + +Each day shows a merged, time-ordered list of: + +- **Assigned places** — with time, category icon, and action buttons +- **Day notes** — with their selected icon and optional time +- **Reservations and transports** — non-hotel types (flights, trains, cars, cruises) appear inline; hotels appear in the Day Detail panel + +Items are sorted by their time or position index. + +## Assigning places to a day + +- **Drag and drop** — drag a place from the right-hand Places sidebar and drop it onto a day section or between existing items. +- **Mobile** — tap the **Add Place** button inside an expanded day section to open an inline search panel; find the place and tap it to assign. + +You can also reorder places within a day, or move them to a different day, by dragging and dropping inside the sidebar. + +## Multi-day reservations + +A reservation that spans multiple days appears in each relevant day with a phase label: + +| Reservation type | Start day | Middle days | End day | +|---|---|---|---| +| Flight | Departure | In transit | Arrival | +| Car | Pickup | Active | Return | +| Other | Start | Ongoing | End | + +Car rentals that are in the "Active" (middle) phase are shown in the day header rather than the timeline. + +## Day notes + +Click the note **+** button in any day section to add a note. Notes have three fields: + +- **Title** (required) — the main note text shown in the timeline +- **Subtitle / detail** (optional) — a free-form text field (Markdown supported) displayed beneath the title +- **Icon** — choose from 20 icons: FileText, Info, Clock, MapPin, Navigation, Train, Plane, Bus, Car, Ship, Coffee, Ticket, Star, Heart, Camera, Flag, Lightbulb, AlertTriangle, ShoppingBag, Bookmark + +Notes interleave with places and transports in the day timeline and are ordered by their `sort_order`. Use the **↑ / ↓** chevron buttons on a note to reposition it within the merged timeline. Notes can also be repositioned by dragging. + +## Day Detail panel + +Click a day header to open the Day Detail panel. It appears as a floating panel centered in the map area and shows: + +- The weather forecast for that day (see [Weather-Forecasts](Weather-Forecasts)) +- Reservations linked to assignments on that day +- Accommodation block (hotel check-in / check-out, with check-in window and confirmation number) + +The panel can be collapsed to a slim header bar or closed entirely with the **X** button. + +## Toolbar actions + +At the top of the Day Plan sidebar: + +- **Export PDF** — downloads a PDF of the full trip plan. See [PDF-Export](PDF-Export). +- **ICS** — exports the trip as a calendar file (.ics) for import into calendar apps. +- **Expand / Collapse all** — toggles all day sections open or closed at once. +- **Undo** — reverses the last drag, reorder, or assign action. + +Route calculation controls (optimize order, open in Google Maps) appear inside each expanded day section after the place list. + +**See also:** [Places-and-Search](Places-and-Search) · [Map-Features](Map-Features) · [Route-Optimization](Route-Optimization) · [Weather-Forecasts](Weather-Forecasts) · [Reservations-and-Bookings](Reservations-and-Bookings) diff --git a/wiki/Demo-Mode.md b/wiki/Demo-Mode.md new file mode 100644 index 00000000..43d62e91 --- /dev/null +++ b/wiki/Demo-Mode.md @@ -0,0 +1,62 @@ +# Demo Mode + +Demo mode lets you run a public "try before you install" instance of TREK. A shared demo account is available for visitors, write operations are blocked for that account, and the database resets automatically every hour so the instance stays in a known state. + + + +## Enabling demo mode + +Set `DEMO_MODE=true` in your environment and restart TREK. See [Environment-Variables](Environment-Variables) for how to set environment variables. + +When demo mode is active, the login page shows a one-click **"Try the demo"** button. Clicking it logs the visitor in as the demo user immediately — no credentials need to be entered and no registration is required. + +**Demo account (auto-created on first start):** + +| Field | Value | +|---|---| +| Email | `demo@trek.app` | +| Password | `demo12345` | + +## What the demo user can and cannot do + +The demo user account has read access to the shared trip data but the following operations are permanently blocked: + +- **Password change** — returns 403. +- **Account deletion** — returns 403. +- **MFA enrollment or removal** — returns 403. +- **File uploads** — avatar uploads, trip cover uploads, and document/photo file attachments are blocked and return 403. +- **All MCP write tools** — create, update, and delete operations via the MCP API are blocked for the demo user. + +Registration is also disabled while demo mode is active — visitors cannot create new accounts. + +The admin account is unaffected and retains full access. + +## Hourly reset + +TREK schedules an automatic hourly reset of the demo database. At each reset: + +1. The current `travel.db` is replaced with the saved baseline (`travel-baseline.db`). +2. The admin account's credentials (`password_hash`, API keys, avatar) are re-applied on top of the restored baseline, so admin API keys and password changes survive the reset. + +If no baseline has been saved yet, the reset is skipped and a message is logged. + +## Saving a baseline + +The baseline is the snapshot the hourly reset restores to. The admin can update it at any time: + +**Endpoint:** `POST /admin/save-demo-baseline` + +This is available in the admin panel. The baseline captures the current state of the database — including trip data, settings, and encrypted API keys — so demo features (maps, photos, weather) continue to work after each reset. + +On first start with demo mode active, TREK seeds three example trips (Tokyo & Kyoto, Barcelona Long Weekend, New York City) owned by the admin and shared with the demo user, then saves the initial baseline automatically. + +## Limitations + +- Demo mode is not for production use with real user data. The hourly reset deletes all visitor-created content. +- All demo visitors share a single account — there is no isolation between sessions. +- File uploads (photos, documents, trip covers, avatars) are disabled for the demo user. + +## See also + +- [Environment-Variables](Environment-Variables) +- [Backups](Backups) diff --git a/wiki/Display-Settings.md b/wiki/Display-Settings.md new file mode 100644 index 00000000..b35df364 --- /dev/null +++ b/wiki/Display-Settings.md @@ -0,0 +1,56 @@ +# Display Settings + +The Display tab (Settings → Display) controls the visual appearance and locale preferences of the app. All changes save immediately to your account and persist across devices. + + + +![Display Settings](assets/UsrSettings.png) + +## Color mode + +Choose between three options: + +| Option | Behaviour | +|--------|-----------| +| Light | Always uses the light theme | +| Dark | Always uses the dark theme | +| Auto | Follows your operating system / browser preference | + +## Language + +Select your preferred language from the button grid (desktop) or dropdown (mobile). The change takes effect immediately without a page reload. See [Languages](Languages) for the full list of supported languages. + +## Temperature unit + +Affects the weather widget on trip days. + +| Option | Display | +|--------|---------| +| °C Celsius | Metric | +| °F Fahrenheit | Imperial | + +## Time format + +Affects all time displays throughout the app. + +| Option | Example | +|--------|---------| +| 24h | 14:30 | +| 12h | 2:30 PM | + +## Route calculation + +Toggles automatic route calculation between places on the trip map. Set to **On** or **Off**. + +## Booking route labels + +Shows or hides labels on booking-related route segments on the map. Set to **On** or **Off**. + +## Blur booking codes + +When enabled, confirmation codes and reference numbers are blurred until you hover or tap. Set to **On** or **Off**. + +## See also + +- [Languages](Languages) +- [User-Settings](User-Settings) diff --git a/wiki/Documents-and-Files.md b/wiki/Documents-and-Files.md new file mode 100644 index 00000000..1ba09ebe --- /dev/null +++ b/wiki/Documents-and-Files.md @@ -0,0 +1,76 @@ +# Documents and Files + +Attach and manage documents, tickets, and other files for your trip. + + + +![Files](assets/Files.png) + +## Where to find it + +Open the **Files** tab inside the trip planner, or navigate directly to `/trips/:id/files`. + +> **Admin:** Files is an addon. Enable it in [Admin-Addons](Admin-Addons). + +## Uploading + +Drag and drop files onto the upload area, click it to open the file picker, or paste an image directly into the Files panel. + +- **Maximum file size:** 50 MB per file. +- **Blocked file types:** `.svg`, `.html`, `.htm`, `.xml` — these are always rejected. +- **Default allowed types:** jpg, jpeg, png, gif, webp, heic, pdf, doc, docx, xls, xlsx, txt, csv, pkpass. An admin can customize the allowed list in [Admin-Addons](Admin-Addons). + +Requires the `file_upload` permission. + +## Browsing and filtering + +The toolbar provides filter tabs: **All**, **PDF**, **Images**, **Docs**, and conditionally **Starred** (only shown when at least one file is starred) and **Collab** (only shown when files exist from collaborative notes). Each tab shows a count badge. + +## Previewing files + +Clicking a non-image file (e.g., PDF) opens an inline preview modal with options to open in a new tab or download. Clicking an image file opens a full-screen lightbox. You can: + +- Navigate between images using the **arrow buttons** or the **left/right arrow keys**. +- Swipe left/right on touch devices. +- Jump to a specific image using the **thumbnail strip** at the bottom. +- Download or open the image in a new tab from the lightbox header. + +## Starring + +Click the **star icon** on any file to favorite it. Starred files sort to the top of the list and can be filtered with the Starred tab. + +Requires the `file_edit` permission. + +## Trash + +Deleting a file moves it to the trash. Switch to the trash view using the **Trash** button in the toolbar. From the trash view you can: + +- **Restore** a file to make it active again. +- **Permanently delete** a single file. +- **Empty trash** to permanently remove all trashed files at once. + +Restore and delete operations require the `file_delete` permission. + +## Linking files to places, reservations, or assignments + +A file can be attached to multiple places and reservations at the same time (many-to-many). From the file manager, click the **link (pencil) icon** on a file to open the assign modal. From there you can toggle links to any trip place or reservation. You can also add a descriptive note to the file in the same modal. + +From a reservation modal, use the "link existing file" picker to attach files directly. + +## Downloading + +Click the download icon on any file row to download it. `.pkpass` files (Apple Wallet passes) are served with the `application/vnd.apple.pkpass` MIME type, so Safari on iOS and macOS offers to add the pass to Wallet instead of saving it as a generic download. + +## Permissions + +| Permission | Controls | +|---|---| +| `file_upload` | Uploading new files. | +| `file_edit` | Starring and linking files. | +| `file_delete` | Moving to trash, restoring, and permanently deleting. | + +## See also + +- [Reservations-and-Bookings](Reservations-and-Bookings) +- [Admin-Addons](Admin-Addons) +- [Trip-Planner-Overview](Trip-Planner-Overview) diff --git a/wiki/Encryption-Key-Rotation.md b/wiki/Encryption-Key-Rotation.md new file mode 100644 index 00000000..867e218c --- /dev/null +++ b/wiki/Encryption-Key-Rotation.md @@ -0,0 +1,85 @@ +# Encryption Key Rotation + +## What the encryption key protects + +TREK encrypts sensitive settings at rest using AES-256-GCM. The following values are stored encrypted in the database: + +- Google Maps API key (per user) +- Mapbox access token (per user) +- OpenWeather API key (per user) +- Immich API key (per user) +- Synology Photos password, session ID, and device ID (per user) +- Per-user webhook URL and ntfy notification token (in `settings` table) +- OIDC client secret (global, in `app_settings`) +- SMTP password (global, in `app_settings`) +- Admin webhook URL and admin ntfy token (global, in `app_settings`) +- MFA (TOTP) secrets for all users +- Photo passphrases for Synology shared-link photos (in `trek_photos`) + +The encryption derives a key from `ENCRYPTION_KEY` using SHA-256 (with a domain suffix per secret type), so the raw `ENCRYPTION_KEY` value is never stored in the database. + +## Key resolution order + +On startup, TREK resolves the encryption key in this order: + +1. **`ENCRYPTION_KEY` environment variable** — explicit, always takes priority. When set, the value is also written to `./data/.encryption_key` so it survives container restarts if the env var is later removed. +2. **`./data/.encryption_key` file** — present on any install that has started at least once. +3. **`./data/.jwt_secret` file** — one-time fallback for older installs that pre-date the dedicated encryption key. The value is immediately persisted to `./data/.encryption_key` so future JWT rotations cannot break decryption. +4. **Auto-generated** — fresh install with none of the above. A random 32-byte hex key is generated and written to `./data/.encryption_key`. + +## What happens if the key is lost + +All encrypted settings (API keys, SMTP password, OIDC secret, MFA secrets, notification tokens, etc.) become unreadable — TREK cannot decrypt them. They must be re-entered manually after the key is restored or replaced. Unencrypted data (trips, places, users, etc.) is unaffected. + +## Backing up the key + +Your backup ZIP does **not** include the encryption key. Store the key separately from your backups — for example, in a password manager or a secrets manager. See [Backups](Backups). + +To find your current key: check the `ENCRYPTION_KEY` environment variable or read `./data/.encryption_key`. + +## Rotating the key + +Use `scripts/migrate-encryption.ts` to re-encrypt all stored secrets without downtime or manual re-entry. + +**Docker:** + +```bash +docker exec -it trek node --import tsx scripts/migrate-encryption.ts +``` + +**Host (run from the `server/` directory):** + +```bash +node --import tsx scripts/migrate-encryption.ts +``` + +The script: + +1. Prompts for the old and new encryption keys interactively (keys are never echoed to the terminal or written to shell history). +2. Asks for confirmation before making any changes. +3. Creates a timestamped backup of the database (e.g. `travel.db.backup-1713484800000`) before modifying anything. +4. Re-encrypts all stored secrets across all tables: + - `app_settings`: `oidc_client_secret`, `smtp_pass`, `admin_webhook_url`, `admin_ntfy_token` + - `users` (per user): `maps_api_key`, `openweather_api_key`, `immich_api_key`, `synology_password`, `synology_sid`, `synology_did`, `mfa_secret` + - `settings` (per user): `webhook_url`, `ntfy_token`, `mapbox_access_token` + - `trip_album_links`: `passphrase` + - `trek_photos`: `passphrase` +5. Reports counts of migrated, already-migrated, skipped (empty), and errored values. + +After a successful migration: + +1. Update `ENCRYPTION_KEY` in your environment to the new value. +2. Restart TREK. + +If any secrets could not be migrated, the script exits with a non-zero status and the original database backup is retained. + +## Upgrading from very old versions + +Old installs may have used `./data/.jwt_secret` as the encryption source (before a dedicated `ENCRYPTION_KEY` was introduced). The key resolution chain above handles this automatically on startup — the JWT secret is read, immediately written to `./data/.encryption_key`, and JWT rotation is then safe without breaking decryption. + +## See also + +- [Backups](Backups) +- [Security-Hardening](Security-Hardening) +- [Environment-Variables](Environment-Variables) +- [User-Settings](User-Settings) diff --git a/wiki/Environment-Variables.md b/wiki/Environment-Variables.md new file mode 100644 index 00000000..9f1e658f --- /dev/null +++ b/wiki/Environment-Variables.md @@ -0,0 +1,135 @@ +# Environment Variables + +Complete reference for all environment variables TREK reads. + +## How to Set Variables + +- **Docker Compose** — use the `environment:` block or a `.env` file alongside `docker-compose.yml` +- **Docker run** — pass each variable with `-e VARIABLE=value` +- **Helm** — use `env:` for plain values and `secretEnv:` for sensitive values in `values.yaml` +- **Unraid** — set in the container template editor + +--- + +## Core + +| Variable | Description | Default | +|---|---|---| +| `PORT` | Server port | `3000` | +| `NODE_ENV` | Environment (`production` / `development`) | `production` | +| `ENCRYPTION_KEY` | At-rest encryption key — see resolution order below | auto | +| `TZ` | Timezone for logs, reminders, and cron jobs (e.g. `Europe/Berlin`) | `UTC` | +| `LOG_LEVEL` | `info` = concise user actions; `debug` = verbose details | `info` | +| `DEFAULT_LANGUAGE` | Default language on the login page — see supported codes below | `en` | +| `ALLOWED_ORIGINS` | Comma-separated origins for CORS and email notification links | same-origin | +| `ALLOW_INTERNAL_NETWORK` | Allow outbound requests to private/RFC-1918 IPs. Set `true` if Immich or other integrated services are on your local network. Loopback (`127.x`) and link-local (`169.254.x`) addresses remain blocked regardless. | `false` | +| `APP_URL` | Public base URL (e.g. `https://trek.example.com`). Required when OIDC is enabled — must match the redirect URI registered with your IdP. Also used as the base URL for email notification links. | — | + +### `ENCRYPTION_KEY` — Resolution Order + +`server/src/config.ts` resolves the encryption key in this order: + +1. **`ENCRYPTION_KEY` env var** — explicit value, always takes priority. Persisted to `data/.encryption_key` automatically. +2. **`data/.encryption_key` file** — present on any install that has started at least once. +3. **`data/.jwt_secret` file** — one-time fallback for existing installs upgrading without a pre-set key. The value is immediately persisted to `data/.encryption_key` so JWT rotation cannot break decryption later. +4. **Auto-generated** — fresh install with none of the above; persisted to `data/.encryption_key`. + +Setting `ENCRYPTION_KEY` explicitly is recommended so you can back it up independently of the data volume. + +### `DEFAULT_LANGUAGE` — Supported Codes + +Verified in `server/src/config.ts` (line 107): + +`de`, `en`, `es`, `fr`, `hu`, `nl`, `br`, `cs`, `pl`, `ru`, `zh`, `zh-TW`, `it`, `ar` + +> **Note:** `id` (Indonesian / Bahasa Indonesia) appears in `client/src/i18n/supportedLanguages.ts` but is not in the server's supported-codes list in `config.ts`. Setting `DEFAULT_LANGUAGE=id` will fall back to `en` with a warning in the server log. + +--- + +## HTTPS / Proxy + +These three variables work together behind a TLS-terminating reverse proxy. See [Reverse-Proxy] for the full explanation. + +| Variable | Description | Default | +|---|---|---| +| `FORCE_HTTPS` | When `true`: 301-redirects HTTP→HTTPS, sends HSTS (`max-age=31536000`), adds CSP `upgrade-insecure-requests`, forces cookie `secure` flag. Only useful behind a TLS proxy. Requires `TRUST_PROXY`. | `false` | +| `TRUST_PROXY` | Number of trusted proxy hops. Tells Express to read the real client IP from `X-Forwarded-For` and protocol from `X-Forwarded-Proto`. Defaults to `1` automatically in production. Required for `FORCE_HTTPS` to detect the forwarded protocol. | `1` (production) | +| `COOKIE_SECURE` | Controls the `secure` flag on the `trek_session` cookie. Auto-derived as `true` when `NODE_ENV=production` or `FORCE_HTTPS=true`. Set to `false` only as an escape hatch for LAN testing without TLS — not recommended in production. | auto | + +> **Warning:** `FORCE_HTTPS=true` without `TRUST_PROXY` set causes a redirect loop. + +--- + +## OIDC / SSO + +For setup instructions, see [OIDC-SSO]. + +| Variable | Description | Default | +|---|---|---| +| `OIDC_ISSUER` | OpenID Connect provider URL (e.g. `https://auth.example.com`) | — | +| `OIDC_CLIENT_ID` | OIDC client ID | — | +| `OIDC_CLIENT_SECRET` | OIDC client secret | — | +| `OIDC_DISPLAY_NAME` | Label shown on the SSO login button | `SSO` | +| `OIDC_ONLY` | Force SSO-only mode: disables password login and registration, overrides Admin > Settings toggles, cannot be changed at runtime. First SSO login becomes admin on a fresh instance. | `false` | +| `OIDC_ADMIN_CLAIM` | OIDC claim used to identify admin users (e.g. `groups`) | — | +| `OIDC_ADMIN_VALUE` | Value of the OIDC claim that grants admin role (e.g. `app-trek-admins`) | — | +| `OIDC_SCOPE` | Space-separated OIDC scopes to request. **Fully replaces** the default — always include `openid email profile` plus any extra scopes (e.g. add `groups` when using `OIDC_ADMIN_CLAIM`) | `openid email profile` | +| `OIDC_DISCOVERY_URL` | Override the auto-constructed OIDC discovery endpoint. Required for providers with a non-standard path (e.g. Authentik) | — | + +--- + +## Email / SMTP + +SMTP settings can be configured via the Admin panel or overridden with environment variables. Env vars take priority over the database values. + +| Variable | Description | Default | +|---|---|---| +| `SMTP_HOST` | SMTP server hostname (e.g. `smtp.example.com`) | — | +| `SMTP_PORT` | SMTP server port. Port `465` enables implicit TLS (`secure: true`); all other ports use STARTTLS or plain. | — | +| `SMTP_USER` | SMTP authentication username | — | +| `SMTP_PASS` | SMTP authentication password | — | +| `SMTP_FROM` | Sender address for outbound emails (e.g. `TREK `) | — | +| `SMTP_SKIP_TLS_VERIFY` | Set `true` to disable TLS certificate validation. Useful for self-signed certs on internal SMTP relays — not recommended in production. | `false` | + +`SMTP_HOST`, `SMTP_PORT`, and `SMTP_FROM` are all required for email delivery to work. `SMTP_USER` and `SMTP_PASS` are optional (for unauthenticated relays). + +--- + +## Initial Setup + +These variables only take effect on first boot, before any user exists. + +| Variable | Description | Default | +|---|---|---| +| `ADMIN_EMAIL` | Email for the first admin account | `admin@trek.local` | +| `ADMIN_PASSWORD` | Password for the first admin account | random | + +Both variables must be set together. If either is omitted, the account is created with email `admin@trek.local` and a randomly generated password that is printed to the server log. Once any user exists, these variables have no effect. + +--- + +## MCP + +For setup instructions, see [MCP-Overview]. + +| Variable | Description | Default | +|---|---|---| +| `MCP_RATE_LIMIT` | Max MCP API requests per user per minute | `300` | +| `MCP_MAX_SESSION_PER_USER` | Max concurrent MCP sessions per user | `20` | + +--- + +## Other + +| Variable | Description | Default | +|---|---|---| +| `DEMO_MODE` | Enable demo mode (hourly data resets). Not intended for regular use. | `false` | + +--- + +## Related Pages + +- [Reverse-Proxy] — HTTPS proxy setup and the `FORCE_HTTPS` / `TRUST_PROXY` / `COOKIE_SECURE` trio +- [OIDC-SSO] — complete OIDC configuration guide +- [MCP-Overview] — MCP server setup and rate limiting +- [Encryption-Key-Rotation] — rotating the `ENCRYPTION_KEY` without losing data diff --git a/wiki/FAQ.md b/wiki/FAQ.md new file mode 100644 index 00000000..d969c3fe --- /dev/null +++ b/wiki/FAQ.md @@ -0,0 +1,42 @@ +# FAQ + +## Do I need a Google Maps API key? + +No. When no Google Maps key is configured, TREK automatically falls back to OpenStreetMap (Nominatim) for place search — no API key or account required. If you want richer place data (photos, ratings, opening hours), an admin can optionally add a Google Maps key in [User Settings](User-Settings). + +## Can I use TREK offline? + +Yes. TREK is a Progressive Web App. After your first visit, the service worker (powered by Workbox) caches map tiles (Carto and OpenStreetMap), non-sensitive API responses, uploaded covers and avatars, and all static assets. Subsequent visits work without a network connection for already-cached content. See [Offline Mode and PWA](Offline-Mode-and-PWA) for installation instructions. + +> **Note:** Auth, admin, backup, and settings endpoints are intentionally excluded from the offline cache. + +## How many MCP tokens can I create? + +Each user can create up to **10 static API tokens**. Static tokens are deprecated — migrate to OAuth 2.1 when possible. + +For OAuth 2.1, each user can register up to **10 OAuth clients**. The default limit for concurrent MCP sessions is **20 per user** (configurable via `MCP_MAX_SESSION_PER_USER`). See [MCP Setup](MCP-Setup). + +> **Admin:** MCP must be enabled in Admin Panel > Addons before any user can access it. + +## Where is my data stored? + +| Type | Path | +|------|------| +| Database | `./data/travel.db` (SQLite) | +| Uploads | `./uploads/` | +| Logs | `./data/logs/trek.log` (auto-rotated) | +| Backups | `./data/backups/` | + +When running in Docker, mount `./data` and `./uploads` as volumes so your data survives container updates. See [Install: Docker Compose](Install-Docker-Compose). + +## How do I update TREK? + +Pull the new image and recreate the container. Your data is in the mounted volumes and is never modified by the update process. See [Updating](Updating) for the exact commands. + +## Can I restrict who can register? + +Yes. An admin can disable open registration so that new accounts can only be created via invite links. See [Admin: Users and Invites](Admin-Users-and-Invites). + +## Does TREK support single sign-on? + +Yes, via OpenID Connect (OIDC). Compatible providers include Google, Authentik, Keycloak, and any standard OIDC-compliant IdP. Set `OIDC_ONLY=true` to disable password login entirely. See [OIDC SSO](OIDC-SSO). diff --git a/wiki/Home.md b/wiki/Home.md new file mode 100644 index 00000000..a7e5332b --- /dev/null +++ b/wiki/Home.md @@ -0,0 +1,60 @@ +# TREK Wiki + +TREK is a self-hosted, real-time collaborative travel planner licensed under AGPL-3.0. + +![Dashboard](assets/DashboardWidgets.png) + +## Features + +### Planning +- **Drag & Drop Planner** — organize places into day plans with reordering and cross-day moves +- **Interactive Map** — Leaflet map with photo markers, clustering, route visualization, and customizable tile sources +- **Place Search** — Google Places (photos, ratings, hours) or OpenStreetMap (free, no API key needed) +- **Day Notes** — timestamped, icon-tagged notes per day +- **Route Optimization** — auto-optimize place order and export to Google Maps +- **Weather Forecasts** — 16-day forecasts via Open-Meteo (no API key required), historical climate averages as fallback + +### Travel Management +- **Reservations & Bookings** — track flights, accommodations, restaurants with confirmation numbers and file attachments +- **Budget Tracking** — category-based expenses with pie chart, per-person/per-day splitting, multi-currency support +- **Packing Lists** — category-based checklists with user assignment, templates, and progress tracking +- **Document Manager** — attach documents, tickets, and PDFs to trips, places, or reservations (up to 50 MB per file) +- **PDF Export** — export complete trip plans as PDF with cover page, images, and notes + +### Collaboration +- **Real-Time Sync** — WebSocket-based live sync; changes appear instantly for all connected users +- **Multi-User** — invite members with role-based access +- **Invite Links** — one-time registration links with configurable max uses and expiry +- **OIDC SSO** — sign in with Google, Apple, Authentik, Keycloak, or any OIDC provider +- **Two-Factor Authentication** — TOTP-based 2FA with QR code setup +- **Public Share Links** — share a read-only view of any trip + +### Addons _(admin-toggleable)_ +- **Vacay** — personal vacation day planner with calendar view, public holidays, and carry-over tracking +- **Atlas** — interactive world map, bucket list, travel stats, continent breakdown +- **Journey** — travel journal linking entries to trips, with contributor roles +- **Memories** — photo-focused trip memories +- **Collab** — group chat, shared notes, polls, and activity sign-ups +- **Dashboard Widgets** — currency converter and timezone clock, toggled per user + +### AI / MCP Integration +- **MCP Server** — built-in Model Context Protocol server with OAuth 2.1 authentication +- **80+ Tools** — create trips, plan itineraries, manage budgets, send messages, and more +- **24 OAuth Scopes** — granular permissions across 13 permission groups +- **Pre-built Prompts** — `trip-summary`, `packing-list`, and `budget-overview` context loaders + +### Admin +- User management, invite links, packing templates, global categories +- Addon management, API key storage, scheduled auto-backups +- System notices for onboarding and announcements + +> **Admin:** Most configuration lives in the Admin Panel. The first user to register becomes the admin automatically. + +## Get Started + +| | | +|---|---| +| [Quick Start](Quick-Start) | Install in minutes with a single Docker command | +| [My Trips Dashboard](My-Trips-Dashboard) | Start planning your first trip | +| [Admin Panel](Admin-Panel-Overview) | Configure your instance | +| [MCP / AI Integration](MCP-Overview) | Connect Claude, Cursor, or any MCP client | diff --git a/wiki/Install-Docker-Compose.md b/wiki/Install-Docker-Compose.md new file mode 100644 index 00000000..f9344617 --- /dev/null +++ b/wiki/Install-Docker-Compose.md @@ -0,0 +1,120 @@ +# Install: Docker Compose + +Production-ready setup using Docker Compose with security hardening enabled. + +## Compose File + +Create a `docker-compose.yml` with the following content (taken directly from the repository): + +```yaml +services: + app: + image: mauriceboe/trek:latest + container_name: trek + read_only: true + security_opt: + - no-new-privileges:true + cap_drop: + - ALL + cap_add: + - CHOWN + - SETUID + - SETGID + tmpfs: + - /tmp:noexec,nosuid,size=64m + ports: + - "3000:3000" + environment: + - NODE_ENV=production + - PORT=3000 + - ENCRYPTION_KEY=${ENCRYPTION_KEY:-} # Recommended. Generate with: openssl rand -hex 32. If unset, falls back to data/.jwt_secret (existing installs) or auto-generates a key (fresh installs). + - TZ=${TZ:-UTC} # Timezone for logs, reminders and scheduled tasks (e.g. Europe/Berlin) + - LOG_LEVEL=${LOG_LEVEL:-info} # info = concise user actions; debug = verbose admin-level details +# - DEFAULT_LANGUAGE=en # Default language on the login page for users with no saved preference. Browser/OS language is auto-detected first; this is the fallback. Supported: de, en, es, fr, hu, nl, br, cs, pl, ru, zh, zh-TW, it, ar + - ALLOWED_ORIGINS=${ALLOWED_ORIGINS:-} # Comma-separated origins for CORS and email notification links +# - FORCE_HTTPS=true # Optional. Enables HTTPS redirect, HSTS, CSP upgrade-insecure-requests, and secure cookies behind a TLS proxy +# - COOKIE_SECURE=false # Escape hatch: force session cookies over plain HTTP even in production. Not recommended. +# - TRUST_PROXY=1 # Trusted proxy count for X-Forwarded-For / X-Forwarded-Proto. Required for FORCE_HTTPS to work. +# - ALLOW_INTERNAL_NETWORK=false # Set to true if Immich or other services are hosted on your local network (RFC-1918 IPs). Loopback and link-local addresses remain blocked regardless. +# - APP_URL=https://trek.example.com # Public base URL — required when OIDC is enabled (must match the redirect URI registered with your IdP); also used as base URL for links in email notifications +# - OIDC_ISSUER=https://auth.example.com # OpenID Connect provider URL +# - OIDC_CLIENT_ID=trek # OpenID Connect client ID +# - OIDC_CLIENT_SECRET=supersecret # OpenID Connect client secret +# - OIDC_DISPLAY_NAME=SSO # Label shown on the SSO login button +# - OIDC_ONLY=false # Set true to force SSO-only mode: disables password login and registration, overrides Admin > Settings toggles, cannot be changed at runtime +# - OIDC_ADMIN_CLAIM=groups # OIDC claim used to identify admin users +# - OIDC_ADMIN_VALUE=app-trek-admins # Value of the OIDC claim that grants admin role +# - OIDC_SCOPE=openid email profile # Fully overrides the default. Add extra scopes as needed (e.g. add groups if using OIDC_ADMIN_CLAIM) +# - OIDC_DISCOVERY_URL= # Override the OIDC discovery endpoint for providers with non-standard paths (e.g. Authentik) +# - ADMIN_EMAIL=admin@trek.local # Initial admin e-mail — only used on first boot when no users exist +# - ADMIN_PASSWORD=changeme # Initial admin password — only used on first boot when no users exist +# - MCP_RATE_LIMIT=300 # Max MCP API requests per user per minute (default: 300) +# - MCP_MAX_SESSION_PER_USER=20 # Max concurrent MCP sessions per user (default: 20) + volumes: + - ./data:/app/data + - ./uploads:/app/uploads + restart: unless-stopped + healthcheck: + test: ["CMD", "wget", "-qO-", "http://localhost:3000/api/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 15s +``` + +## Security Hardening Explained + +The compose file ships with several hardening options enabled by default: + +| Setting | What it does | +|---|---| +| `read_only: true` | Mounts the container filesystem read-only; only the two named volumes and `/tmp` are writable | +| `security_opt: no-new-privileges:true` | Prevents the process from gaining additional Linux privileges via setuid/setgid executables | +| `cap_drop: [ALL]` | Drops all Linux capabilities from the container | +| `cap_add: [CHOWN, SETUID, SETGID]` | Adds back only the capabilities needed for the entrypoint to drop privileges to the `node` user | +| `tmpfs: /tmp:noexec,nosuid,size=64m` | Mounts a 64 MB in-memory `/tmp`; required because the container root is read-only | + +## Volumes + +| Host path | Container path | Contents | +|---|---|---| +| `./data` | `/app/data` | SQLite database, logs, `.jwt_secret`, `.encryption_key` | +| `./uploads` | `/app/uploads` | Uploaded files (photos, documents, covers, avatars) | + +## Environment Variables + +The compose file reads variables from a `.env` file placed alongside `docker-compose.yml`. At minimum, set: + +```bash +# .env +ENCRYPTION_KEY= +TZ=Europe/Berlin +ALLOWED_ORIGINS=https://trek.example.com +APP_URL=https://trek.example.com +``` + +Uncomment and fill in the OIDC, initial setup, or MCP variables as needed. For a full description of every variable, see [Environment-Variables]. + +## Start TREK + +```bash +docker compose up -d +``` + +Check the logs: + +```bash +docker compose logs -f +``` + +## HTTPS and Reverse Proxy + +This compose file is designed for deployments where a reverse proxy (nginx, Caddy, Traefik) terminates TLS in front of TREK. To enable HTTPS redirects and secure cookies, uncomment `FORCE_HTTPS=true` and `TRUST_PROXY=1`. + +See [Reverse-Proxy] for complete proxy configuration examples. + +## Next Steps + +- [Environment-Variables] — full variable reference +- [Reverse-Proxy] — HTTPS configuration +- [Updating] — how to pull a new image diff --git a/wiki/Install-Docker.md b/wiki/Install-Docker.md new file mode 100644 index 00000000..17dd3983 --- /dev/null +++ b/wiki/Install-Docker.md @@ -0,0 +1,76 @@ +# Install: Docker + +Single-container Docker run — suitable for testing or simple personal installs. + +## Run Command + +```bash +docker run -d \ + --name trek \ + -p 3000:3000 \ + -v ./data:/app/data \ + -v ./uploads:/app/uploads \ + -e ENCRYPTION_KEY= \ + --restart unless-stopped \ + mauriceboe/trek:latest +``` + +`ENCRYPTION_KEY` is strongly recommended but not strictly required. If omitted, a key is auto-generated on first start and persisted to `data/.encryption_key`. Setting it explicitly means you can recreate the container from scratch (e.g. on a new host) without losing access to stored encrypted data (API keys, SMTP credentials, OIDC secrets, MFA secrets). + +Generate an encryption key with: + +```bash +openssl rand -hex 32 +``` + +### Common optional variables + +Pass additional `-e` flags for timezone and CORS/email link support: + +```bash + -e TZ=Europe/Berlin \ + -e ALLOWED_ORIGINS=https://trek.example.com \ +``` + +See [Environment-Variables] for the full list. + +## Volume Reference + +| Volume | Container path | What lives there | +|---|---|---| +| `./data` | `/app/data` | `travel.db` (SQLite database), `logs/trek.log`, `.jwt_secret`, `.encryption_key` | +| `./uploads` | `/app/uploads` | Uploaded files (photos, documents, covers, avatars) | + +Both volumes must survive container replacement — they are your persistent state. Never remove them before pulling a new image. + +## Health Check + +The container exposes a health endpoint at: + +``` +http://localhost:3000/api/health +``` + +Docker polls it automatically (interval: 30 s, timeout: 5 s, retries: 3, start period: 15 s). You can check it manually: + +```bash +curl -s http://localhost:3000/api/health +``` + +## Verify the Container Is Running + +```bash +docker ps --filter name=trek +docker logs trek +``` + +## Limitations of `docker run` + +A bare `docker run` command has no built-in secret management and is harder to reproduce after a system reboot. For production, see [Install-Docker-Compose], which adds security hardening (`read_only`, `cap_drop`, `cap_add`, `no-new-privileges`, `tmpfs`) and makes it easy to manage environment variables through a `.env` file. + +## Next Steps + +- [Reverse-Proxy] — HTTPS is required for PWA install and the `trek_session` cookie `secure` flag +- [Install-Docker-Compose] — recommended for production +- [Environment-Variables] — full list of configurable variables +- [Updating] — how to pull a new image without losing data diff --git a/wiki/Install-Helm.md b/wiki/Install-Helm.md new file mode 100644 index 00000000..d0fca6db --- /dev/null +++ b/wiki/Install-Helm.md @@ -0,0 +1,195 @@ +# Install: Helm + +Deploy TREK on Kubernetes using the official Helm chart. + +## Add the Chart Repository + +```bash +helm repo add trek https://mauriceboe.github.io/TREK +helm repo update +``` + +## Basic Install + +```bash +helm install trek trek/trek +``` + +This deploys TREK with default values: a `ClusterIP` service on port 3000, 1 Gi PVCs for data and uploads, and no ingress. + +## Encryption Key + +`ENCRYPTION_KEY` encrypts stored secrets (API keys, MFA, SMTP, OIDC) at rest. There are three ways to handle it: + +**Option 1 — Let the chart generate a random key (recommended for new installs):** + +```bash +helm install trek trek/trek --set generateEncryptionKey=true +``` + +The chart generates a 32-character alphanumeric key at install time and preserves it across upgrades. Note that this differs from the 64-character hex key produced by `openssl rand -hex 32` — both formats are accepted by the server. + +**Option 2 — Set an explicit key:** + +```bash +helm install trek trek/trek \ + --set secretEnv.ENCRYPTION_KEY=$(openssl rand -hex 32) +``` + +**Option 3 — Use an existing Kubernetes Secret:** + +```bash +kubectl create secret generic trek-secrets \ + --from-literal=ENCRYPTION_KEY=$(openssl rand -hex 32) + +helm install trek trek/trek \ + --set existingSecret=trek-secrets +``` + +If `existingSecret` uses a different key name than `ENCRYPTION_KEY`, specify it with `--set existingSecretKey=MY_KEY_NAME`. + +> **Note:** If both `generateEncryptionKey` and `existingSecret` are set, `existingSecret` takes precedence. Only one method should be active at a time. + +> **Note:** If `ENCRYPTION_KEY` is left empty, the server resolves it automatically: existing installs fall back to `data/.jwt_secret` (encrypted data stays readable after upgrade); fresh installs auto-generate a key persisted to the data PVC. + +> **Note:** `JWT_SECRET` is managed entirely by the server — auto-generated on first start and persisted to the data PVC. It can be rotated via the admin panel (Settings → Danger Zone → Rotate JWT Secret). No Helm configuration is needed or supported for it. + +## Admin Account + +`ADMIN_EMAIL` and `ADMIN_PASSWORD` are set via `secretEnv`. They are only used on first boot when no users exist yet. **Both must be set together** — if either is missing, the server ignores both values and instead creates the admin account with email `admin@trek.local` and a random password, which is printed to the server log. + +```bash +helm install trek trek/trek \ + --set secretEnv.ADMIN_EMAIL=admin@example.com \ + --set secretEnv.ADMIN_PASSWORD= +``` + +> **Note:** When `OIDC_ONLY=true` is configured together with `OIDC_ISSUER` and `OIDC_CLIENT_ID`, no local admin account is created on first boot. Instead, the first user to log in via SSO automatically becomes admin. + +## Key `values.yaml` Settings + +### Image + +```yaml +image: + repository: mauriceboe/trek + # tag: latest # defaults to the chart's appVersion + pullPolicy: IfNotPresent + +# Optional: pull secrets for private registries +imagePullSecrets: [] + # - name: my-registry-secret +``` + +### Service + +```yaml +service: + type: ClusterIP # change to LoadBalancer or NodePort to expose externally + port: 3000 +``` + +### Plain Environment Variables (`env`) + +```yaml +env: + NODE_ENV: production + PORT: 3000 + # TZ: "Europe/Berlin" # timezone for logs, reminders, cron jobs + # LOG_LEVEL: "info" # "info" = concise, "debug" = verbose + # DEFAULT_LANGUAGE: "en" # fallback language on login page; supported: de, en, es, fr, hu, nl, br, cs, pl, ru, zh, zh-TW, it, ar + # ALLOWED_ORIGINS: "https://trek.example.com" + # APP_URL: "https://trek.example.com" + # FORCE_HTTPS: "false" # enable HTTPS redirect + HSTS; requires TRUST_PROXY + # TRUST_PROXY: "1" # proxy hops for X-Forwarded-For/Proto; defaults to 1 in production + # COOKIE_SECURE: "true" # auto-derived; set "false" only for local HTTP testing + # ALLOW_INTERNAL_NETWORK: "false" # set "true" if Immich or other services are on a private network + # DEMO_MODE: "false" # enable demo mode (hourly data resets) + # MCP_RATE_LIMIT: "300" # max MCP requests per user per minute + # OIDC_ISSUER: "https://auth.example.com" + # OIDC_CLIENT_ID: "trek" + # OIDC_DISPLAY_NAME: "SSO" + # OIDC_ONLY: "false" # force SSO-only mode; disables password login + # OIDC_ADMIN_CLAIM: "" # OIDC claim used to identify admin users + # OIDC_ADMIN_VALUE: "" # value of that claim that grants admin role + # OIDC_SCOPE: "openid email profile groups" + # OIDC_DISCOVERY_URL: "" # override for providers with non-standard discovery paths (e.g. Authentik) +``` + +### Sensitive Variables (`secretEnv`) + +These are stored in a Kubernetes Secret and injected as environment variables: + +```yaml +secretEnv: + ENCRYPTION_KEY: "" # recommended: openssl rand -hex 32 + ADMIN_EMAIL: "" # initial admin email (first boot only) + ADMIN_PASSWORD: "" # initial admin password (first boot only) + OIDC_CLIENT_SECRET: "" # set if using OIDC +``` + +Alternatively, use `generateEncryptionKey: true` to let the chart generate and manage the encryption key, or point `existingSecret` / `existingSecretKey` at an existing Kubernetes Secret. + +### Persistent Storage + +```yaml +persistence: + enabled: true + data: + size: 1Gi # SQLite database, logs, secrets + uploads: + size: 1Gi # uploaded files — increase if you expect large media uploads +``` + +### Resource Limits + +```yaml +resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi +``` + +### Ingress + +```yaml +ingress: + enabled: true + className: "nginx" # your ingress class + annotations: + nginx.ingress.kubernetes.io/proxy-read-timeout: "86400" # required for WebSockets + nginx.ingress.kubernetes.io/proxy-body-size: "500m" # required for backup restore + hosts: + - host: trek.example.com + paths: + - / + tls: + - secretName: trek-tls + hosts: + - trek.example.com +``` + +> **Important:** TREK uses WebSockets on `/ws`. Your ingress controller must support WebSocket upgrades. Set `proxy-read-timeout` to at least `86400` and `proxy-body-size` to at least `500m` for backup restores. + +> **Note:** Keep `env.ALLOWED_ORIGINS` in sync with `ingress.hosts` — the chart does not synchronize these automatically. + +> **Note:** When using ingress with TLS termination, set `env.FORCE_HTTPS: "true"` and `env.TRUST_PROXY: "1"` to enable HTTPS redirects, HSTS, and secure cookies. + +## Upgrade + +```bash +helm repo update +helm upgrade trek trek/trek +``` + +## Full Values Reference + +See the [`charts/README.md`](https://github.com/mauriceboe/TREK/blob/main/charts/README.md) for all available values. + +## Next Steps + +- [Environment-Variables] — full variable reference +- [Reverse-Proxy] — proxy configuration for non-Kubernetes deployments diff --git a/wiki/Install-Unraid.md b/wiki/Install-Unraid.md new file mode 100644 index 00000000..83e1706f --- /dev/null +++ b/wiki/Install-Unraid.md @@ -0,0 +1,73 @@ +# Install: Unraid + +Install TREK on Unraid via Community Applications or a direct template import. + + + +## Prerequisite + +Docker must be enabled in Unraid (**Settings → Docker → Enable Docker: Yes**). + +## Install via Community Applications + +1. Open the **Apps** tab in Unraid. +2. Search for **TREK**. +3. Click **Install** on the TREK result. + +If the app does not appear, you can install directly from the template URL. In **Docker → Add Container**, paste the template URL: + +``` +https://raw.githubusercontent.com/mauriceboe/TREK/main/unraid-template.xml +``` + +## Template Fields + +The Unraid template exposes the following fields in the container UI: + +### Ports & Paths + +| Field | Container path | Default host value | +|---|---|---| +| Web UI Port | `3000/tcp` | `3000` | +| Data | `/app/data` | `/mnt/user/appdata/trek/data` | +| Uploads | `/app/uploads` | `/mnt/user/appdata/trek/uploads` | + +### Core Variables (always visible) + +| Variable | Default | Notes | +|---|---|---| +| `ENCRYPTION_KEY` | *(empty)* | Set on first install. Generate with `openssl rand -hex 32` in the Unraid terminal. | +| `TZ` | `UTC` | Timezone for logs, reminders, and scheduled tasks (e.g. `Europe/Berlin`) | +| `ALLOWED_ORIGINS` | *(empty)* | Comma-separated origins for CORS and email notification links, e.g. `https://trek.example.com` | +| `APP_URL` | *(empty)* | Public base URL; required when OIDC is enabled (must match the redirect URI registered with your IdP) | +| `ADMIN_EMAIL` | *(empty)* | Email for the first admin account (first-boot only; no effect once any user exists). Must be set together with `ADMIN_PASSWORD`. | +| `ADMIN_PASSWORD` | *(empty)* | Password for the first admin account (first-boot only). Must be set together with `ADMIN_EMAIL`. If either is omitted, TREK creates the account with email `admin@trek.local` and a random password printed to the container log. | + +### Advanced Variables + +Additional variables (`PORT`, `NODE_ENV`, `LOG_LEVEL`, `DEFAULT_LANGUAGE`, `FORCE_HTTPS`, `TRUST_PROXY`, `COOKIE_SECURE`, `ALLOW_INTERNAL_NETWORK`, all OIDC variables, `MCP_RATE_LIMIT`, `MCP_MAX_SESSION_PER_USER`, `DEMO_MODE`) are available under **Advanced View** in the template editor. + +## Setting the Encryption Key + +Generate a key in the Unraid terminal (**Tools → Terminal**): + +```bash +openssl rand -hex 32 +``` + +Copy the output into the `ENCRYPTION_KEY` field before starting the container for the first time. If you skip this, TREK auto-generates a key and saves it to `data/.encryption_key` — your data is still protected, but you should record that file in your backups. + +## After Install + +Once the container starts, open your browser at: + +``` +http://: +``` + +On first boot, TREK automatically creates an admin account. The credentials are printed to the container log — check **Docker → trek → Log** in the Unraid UI. If you set both `ADMIN_EMAIL` and `ADMIN_PASSWORD`, those values are used; otherwise the email is `admin@trek.local` and a random password is generated. + +## Next Steps + +- [Environment-Variables] — complete variable reference +- [Updating] — how to pull a new image on Unraid diff --git a/wiki/Internal-Network-Access.md b/wiki/Internal-Network-Access.md new file mode 100644 index 00000000..dc93e134 --- /dev/null +++ b/wiki/Internal-Network-Access.md @@ -0,0 +1,56 @@ +# Internal Network Access + +TREK makes outbound HTTP requests when you configure integrations such as Immich or Synology Photos. By default, it blocks requests to private and local IP ranges to prevent server-side request forgery (SSRF) attacks. You need to allow internal network access when those services are hosted on your LAN. + +## Default behavior + +All outbound requests go through an SSRF guard (`ssrfGuard.ts`). The guard resolves the hostname to an IP address before allowing the connection and blocks addresses in private ranges. + +## Always blocked (no override possible) + +These ranges are blocked regardless of any setting: + +| Range | Description | +|---|---| +| `127.0.0.0/8`, `::1` | Loopback | +| `0.0.0.0/8` | Unspecified | +| `169.254.0.0/16`, `fe80::/10` | Link-local / cloud metadata endpoints | +| `::ffff:127.x.x.x`, `::ffff:169.254.x.x` | IPv4-mapped loopback and link-local | + +In addition, hostnames ending in `.local` or `.internal` are always blocked regardless of `ALLOW_INTERNAL_NETWORK`. These suffixes are readily abused for hostname-based bypasses. + +The hostname `localhost` is not blocked at the hostname stage, but it resolves to `127.0.0.1` which is caught by the loopback rule above and is therefore always blocked. + +## Blocked unless `ALLOW_INTERNAL_NETWORK=true` + +| Range | Description | +|---|---| +| `10.0.0.0/8` | RFC-1918 private | +| `172.16.0.0/12` | RFC-1918 private | +| `192.168.0.0/16` | RFC-1918 private | +| `100.64.0.0/10` | CGNAT / Tailscale shared address space | +| `fc00::/7` | IPv6 ULA | +| IPv4-mapped RFC-1918 variants | e.g. `::ffff:10.x`, `::ffff:192.168.x` | + +## When to enable + +Set `ALLOW_INTERNAL_NETWORK=true` when Immich, Synology Photos, or another integrated service is hosted on your local network and you need TREK to reach it. + +See [Environment-Variables](Environment-Variables) for how to set environment variables. + +> **Admin:** Set `ALLOW_INTERNAL_NETWORK=true` in [Environment-Variables](Environment-Variables) before configuring Immich or Synology on a LAN. + +## DNS rebinding protection + +Even with `ALLOW_INTERNAL_NETWORK=true`, TREK pins the DNS resolution to prevent rebinding attacks. When the guard checks a URL, it resolves the hostname once and records the IP. The outbound connection is then made directly to that IP using a pinned dispatcher (via undici), so the hostname cannot re-resolve to a different address between the check and the actual request. + +## Audit log + +When a user saves an Immich URL that resolves to a private IP, TREK records an `immich.private_ip_configured` entry in the [Audit-Log](Audit-Log) including the URL and the resolved IP address. This audit event is specific to Immich; Synology Photos does not emit an equivalent event. + +## See also + +- [Photo-Providers](Photo-Providers) +- [User-Settings](User-Settings) +- [Environment-Variables](Environment-Variables) +- [Security-Hardening](Security-Hardening) diff --git a/wiki/Invite-Links.md b/wiki/Invite-Links.md new file mode 100644 index 00000000..52d6224f --- /dev/null +++ b/wiki/Invite-Links.md @@ -0,0 +1,35 @@ +# Invite Links + +Invite new users to register on your TREK instance, even when open registration is disabled. Invite links work by embedding a short-lived token in the registration URL. + + + +![Invite Links](assets/UsersAndInvites.png) + +## What invite links do + +An invite link lets a person register a new TREK account without requiring the site to have open registration enabled. Visiting `/register?invite=` pre-validates the token and switches the page to the Register form. The token's use count is incremented on successful registration, and the link stops working once the use limit is reached. + +## Creating invite links + +> **Admin:** invite link management is available in [Admin-Users-and-Invites](Admin-Users-and-Invites). Only admins can create invite links. + +When creating an invite link you set two parameters: + +**Max uses** — how many times the link can be used to register an account. Choose from preset buttons: **1×, 2×, 3×, 4×, 5×**, or **∞** (unlimited). + +**Expiry** — how long until the link stops working. Choose from preset buttons: **1d, 3d, 7d, 14d**, or **∞** (no expiry). + +Once created, a 32-character hexadecimal token is generated and the URL is automatically copied to your clipboard. + +## Sharing the link + +Copy the generated URL and send it directly to the person you want to invite. The link works in any browser without any prior authentication. + +## Revoking an invite link + +Delete the invite from [Admin-Users-and-Invites](Admin-Users-and-Invites). The token is invalidated immediately and visiting the URL will no longer unlock the Register form. + +## Related pages + +[Login-and-Registration](Login-and-Registration) · [Admin-Users-and-Invites](Admin-Users-and-Invites) diff --git a/wiki/Journey-Journal.md b/wiki/Journey-Journal.md new file mode 100644 index 00000000..5dd39145 --- /dev/null +++ b/wiki/Journey-Journal.md @@ -0,0 +1,61 @@ +# Journey Journal + +Journey is a photo-first travel journal. Each journey is linked to one or more of your trips and contains per-day entries with text, photos, mood, and weather. + +> **Admin:** enable Journey in [Admin-Addons](Admin-Addons). + + + +![Journey screenshot](assets/Journey.png) + +## What Journey is + +Journey lets you write a narrative account of your travels alongside your trip plan. Entries are tied to specific days and can include prose, photos, a mood rating, weather conditions, and verdict cards. Completed journeys can be shared publicly with a read-only link. + +## Accessing Journey + +When the admin has enabled the Journey addon, a **Journey** entry appears in the main navigation. The Journey list page shows all your journals as cards with cover images, entry counts, photo counts, and place counts. + +## Creating a journey + +From the Journey list, click **Create journey**. Give it a title and optional subtitle, then select one or more existing trips to link. Linking a trip imports the trip's places as location anchors for your entries. You can link additional trips later from the journal settings. + +## Journal entries + +Each entry corresponds to a day in your journey. The entry editor provides: + +- **Title** — a short heading for the day. +- **Story** — free-form text that supports Markdown formatting. +- **Mood** — choose one of four values: + + | ID | Label | Color | + |---|---|---| + | `amazing` | Amazing | Pink | + | `good` | Good | Amber | + | `neutral` | Neutral | Grey | + | `rough` | Rough | Violet | + +- **Weather** — choose one of six values: Sunny, Partly cloudy, Cloudy, Rainy, Stormy, Cold. +- **Photos** — attach photos to the entry. The first photo becomes the card thumbnail in list views. +- **Pros / Cons** — optional verdict cards. Add items to a **Pros** list (thumbs-up) or a **Cons** list (thumbs-down) to summarise what you loved or what could have been better. These are stored in the `pros_cons.pros` and `pros_cons.cons` arrays on the entry. +- **Tags** — free-form labels (e.g. "hidden gem", "best meal"). +- **Location** — pin the entry to a map location. +- **Time** — optionally record a time of day for the entry. + +## Mobile timeline + +On mobile, entries are displayed in a horizontal scrolling timeline of card thumbnails. Tap a card to open the full entry view in a modal sheet. Each card shows the entry's first photo (or a placeholder pin), date, day number, mood icon, and weather icon. + +## Map view + +The journey detail page includes a map on the right (desktop) or an integrated map-timeline (mobile) showing all entry locations alongside the places from linked trips. + +## Public sharing + +You can share a journey with a read-only public link. When creating the link you can independently toggle which sections are visible to visitors: **Timeline** (entries and stories), **Gallery** (photos), and **Map**. Visitors can only see the sections you have enabled, and no TREK account is required. See [Public-Share-Links](Public-Share-Links) for details on the separate journey share token mechanism. + +## See also + +- [Addons-Overview](Addons-Overview) +- [Admin-Addons](Admin-Addons) +- [Public-Share-Links](Public-Share-Links) diff --git a/wiki/Languages.md b/wiki/Languages.md new file mode 100644 index 00000000..418185eb --- /dev/null +++ b/wiki/Languages.md @@ -0,0 +1,51 @@ +# Languages + +TREK ships with translations for 15 languages. You can change your language at any time without logging out. + +## Supported languages + +| Code | Language | +|------|----------| +| `de` | Deutsch | +| `en` | English | +| `es` | Español | +| `fr` | Français | +| `hu` | Magyar | +| `nl` | Nederlands | +| `br` | Português (Brasil) | +| `cs` | Česky | +| `pl` | Polski | +| `ru` | Русский | +| `zh` | 简体中文 | +| `zh-TW` | 繁體中文 | +| `it` | Italiano | +| `ar` | العربية | +| `id` | Bahasa Indonesia | + +## RTL support + +Arabic (`ar`) uses a right-to-left layout. All other languages use left-to-right. + +## How language is detected + +TREK resolves the display language in this order: + +1. **User preference** — the language saved to your account (set in Settings → Display). +2. **Browser language** — `navigator.languages` (and `navigator.language`) reported by your browser. +3. **Server default** — the `DEFAULT_LANGUAGE` environment variable set by the admin. +4. **Fallback** — English (`en`). + +## Where the language picker appears + +- **Login / Register page** — before you are signed in. +- **Settings → Display** — after you are signed in. See [Display-Settings](Display-Settings). +- **Public share pages** — trip share links. +- **Public journey pages** — public-facing journey views. + +> **Admin:** The `DEFAULT_LANGUAGE` environment variable sets the fallback language shown on the login page and for unauthenticated users. See [Environment-Variables](Environment-Variables). + +## See also + +- [Display-Settings](Display-Settings) +- [Environment-Variables](Environment-Variables) +- [User-Settings](User-Settings) diff --git a/wiki/Login-and-Registration.md b/wiki/Login-and-Registration.md new file mode 100644 index 00000000..a84733ee --- /dev/null +++ b/wiki/Login-and-Registration.md @@ -0,0 +1,73 @@ +# Login and Registration + + + +## Signing in + +Navigate to `/login` and enter your email and password. On success, the server sets a `trek_session` cookie — httpOnly, sameSite=`lax`, and secure in production — that persists your session for 24 hours across page reloads and browser restarts. You do not need to sign in again until the session expires or you explicitly log out. + +> **Note:** The `secure` flag on the cookie can be overridden by setting `COOKIE_SECURE=false` in the server environment (useful for plain-HTTP dev setups), or force-enabled with `FORCE_HTTPS=true`. + +If your account has two-factor authentication enabled, you are prompted for a TOTP code (or backup code) after the password step before the session cookie is issued. + +### Forced password change + +If an admin has marked your account as requiring a password change, a **Set new password** form is shown immediately after a successful login (or after the MFA step). The session cookie is not issued until the new password is saved. + +## Registering + +The Register form appears under one of these conditions: + +- **Open registration** — the admin has enabled password registration for the instance (`password_registration` setting). +- **Valid invite link** — you visited `/login?invite=TOKEN` with a valid token (see below). +- **First user** — no accounts exist yet; the registration form is shown automatically and the first account created becomes an admin. + +Registration fields: **username**, **email**, and **password**. + +### Password requirements + +Passwords must meet all of the following rules: + +- Minimum **8 characters** +- At least one **uppercase letter** +- At least one **lowercase letter** +- At least one **number** +- At least one **special character** +- Must not be a commonly used password +- Must not consist of a single repeated character + +> **Admin:** You can disable open registration so only invite links work. See [Admin-Users-and-Invites](Admin-Users-and-Invites). + +### Invite link flow + +When an admin shares an invite link (`/login?invite=TOKEN`), visiting it: + +1. Validates the token against the server. +2. Switches the login page to Register mode automatically. +3. Passes the token during registration so it counts against the invite's use limit. + +If the token is invalid, expired, or exhausted, an error is shown. + +## First user + +On a fresh TREK instance with no existing accounts, the registration form opens immediately. The first account created is automatically assigned the **admin** role. + +## Rate limiting + +Failed login attempts are rate-limited to **10 attempts per 15-minute window** per IP address. After exceeding the limit, further attempts return HTTP 429 until the window resets. + +MFA verification attempts are rate-limited separately to **5 attempts per 15-minute window** per IP address. + +## Demo mode + +When the server is started with `DEMO_MODE=true`, a **"Try demo"** button appears below the login form. Clicking it signs you in as the demo user without entering credentials. The demo credentials (`demo@trek.app` / `demo12345`) are also displayed in the app config for reference, but the one-click button is the intended entry point. + +## SSO + +If the admin has configured OpenID Connect, a **"Sign in with SSO"** button (labelled with the configured `OIDC_DISPLAY_NAME`, defaulting to `SSO`) appears below the login form. See [OIDC-SSO](OIDC-SSO) for details on setup and the sign-in flow. + +When OIDC-only mode is active (password login disabled), visiting `/login` automatically redirects the browser to the identity provider. The email/password form is not shown. The automatic redirect is suppressed only when you have explicitly logged out, in which case the SSO button is shown instead so you can choose to sign back in. + +--- + +**See also:** [OIDC-SSO](OIDC-SSO) · [Admin-Users-and-Invites](Admin-Users-and-Invites) diff --git a/wiki/MCP-Addon-Tools.md b/wiki/MCP-Addon-Tools.md new file mode 100644 index 00000000..daca36af --- /dev/null +++ b/wiki/MCP-Addon-Tools.md @@ -0,0 +1,176 @@ +# MCP Addon Tools and Resources + +This page covers MCP tools and resources that require specific addons to be enabled on your TREK instance. For core tools (trips, places, day planning, accommodations, transport, reservations, budget, tags, maps, and notifications) see [MCP-Tools-and-Resources](MCP-Tools-and-Resources). + +--- + +## Addon-gated tools + +### Packing _(Packing addon required)_ + +Requires `packing:read` or `packing:write` scope. + +| Tool | Description | +|---|---| +| `create_packing_item` | Add an item to the packing checklist with optional category. | +| `update_packing_item` | Rename an item or change its category. | +| `toggle_packing_item` | Check or uncheck a packing item. | +| `delete_packing_item` | Remove a packing item. | +| `reorder_packing_items` | Set the display order of packing items within a trip. | +| `bulk_import_packing` | Import multiple packing items at once from a list (with optional quantity). | +| `apply_packing_template` | Apply a saved packing template to a trip. | +| `save_packing_template` | Save the current packing list as a reusable template. | +| `list_packing_bags` | List all packing bags for a trip. | +| `create_packing_bag` | Create a new packing bag (e.g. "Carry-on", "Checked bag"). | +| `update_packing_bag` | Rename or recolor a packing bag. | +| `delete_packing_bag` | Delete a packing bag (items are unassigned, not deleted). | +| `set_bag_members` | Assign trip members to a packing bag. | +| `get_packing_category_assignees` | Get which trip members are assigned to each packing category. | +| `set_packing_category_assignees` | Assign trip members to a packing category. | + +### To-Dos _(Packing addon required)_ + +Requires `todos:read` or `todos:write` scope. + +| Tool | Description | +|---|---| +| `list_todos` | List all to-do items for a trip, ordered by position. | +| `create_todo` | Create a to-do item with name, category, due date, description, assignee, and priority. | +| `update_todo` | Update an existing to-do item. Pass `null` to clear nullable fields. | +| `toggle_todo` | Mark a to-do item as done or undone. | +| `delete_todo` | Delete a to-do item. | +| `reorder_todos` | Reorder to-do items by providing a new ordered list of IDs. | +| `get_todo_category_assignees` | Get the default assignees configured per to-do category for a trip. | +| `set_todo_category_assignees` | Set default assignees for a to-do category. Pass an empty array to clear. | + +### Atlas _(Atlas addon required)_ + +Requires `atlas:read` or `atlas:write` scope. + +| Tool | Description | +|---|---| +| `mark_country_visited` | Mark a country as visited using its ISO 3166-1 alpha-2 code (e.g. `"FR"`, `"JP"`). | +| `unmark_country_visited` | Remove a country from your visited list. | +| `get_atlas_stats` | Get atlas statistics — visited country counts, region counts, and continent breakdown. | +| `list_visited_regions` | List all manually visited sub-country regions for the current user. | +| `mark_region_visited` | Mark a sub-country region as visited (e.g. `"US-CA"`). | +| `unmark_region_visited` | Remove a region from the visited list. | +| `get_country_atlas_places` | Get places saved in the user's atlas for a specific country. | +| `create_bucket_list_item` | Add a destination to your personal bucket list with optional coordinates and country code. | +| `update_bucket_list_item` | Update a bucket list item (name, notes, coordinates, target date). | +| `delete_bucket_list_item` | Remove an item from your bucket list. | + +### Collab _(Collab addon required)_ + +Requires `collab:read` or `collab:write` scope. + +| Tool | Description | +|---|---| +| `create_collab_note` | Create a shared note visible to all trip members. Supports title, content, category, and color. | +| `update_collab_note` | Edit a collab note's content, category, color, or pin status. | +| `delete_collab_note` | Delete a collab note. | +| `list_collab_polls` | List all polls for a trip. | +| `create_collab_poll` | Create a poll with a question, options, optional multiple choice, and deadline. | +| `vote_collab_poll` | Vote on a poll option (or remove vote if already voted). | +| `close_collab_poll` | Close a poll so no more votes can be cast. | +| `delete_collab_poll` | Delete a poll and all its votes. | +| `list_collab_messages` | List chat messages for a trip (most recent 100, supports pagination via `before`). | +| `send_collab_message` | Send a chat message to a trip's collab channel, with optional reply threading. | +| `delete_collab_message` | Delete a chat message (own messages only). | +| `react_collab_message` | Toggle a reaction emoji on a chat message. | + +### Vacay _(Vacay addon required)_ + +Requires `vacay:read` or `vacay:write` scope. + +| Tool | Description | +|---|---| +| `get_vacay_plan` | Get the current user's active vacation plan. | +| `update_vacay_plan` | Update vacation plan settings (weekend blocking, holidays, carry-over). | +| `set_vacay_color` | Set the current user's color in the vacation plan calendar. | +| `get_available_vacay_users` | List users who can be invited to the current vacation plan. | +| `send_vacay_invite` | Invite a user to join the vacation plan by their user ID. | +| `accept_vacay_invite` | Accept a pending invitation to join another user's vacation plan. | +| `decline_vacay_invite` | Decline a pending vacation plan invitation. | +| `cancel_vacay_invite` | Cancel an outgoing invitation (owner only). | +| `dissolve_vacay_plan` | Dissolve the shared plan — all members return to their own individual plan. | +| `list_vacay_years` | List calendar years tracked in the current vacation plan. | +| `add_vacay_year` | Add a calendar year to the vacation plan. | +| `delete_vacay_year` | Remove a calendar year from the vacation plan. | +| `get_vacay_entries` | Get all vacation day entries for the active plan and a specific year. | +| `toggle_vacay_entry` | Toggle a day on or off as a vacation day for the current user. | +| `toggle_company_holiday` | Toggle a date as a company holiday for the whole plan. | +| `get_vacay_stats` | Get vacation statistics for a specific year (days used, remaining, carried over). | +| `update_vacay_stats` | Update the vacation day allowance for a specific user and year. | +| `add_holiday_calendar` | Add a public holiday calendar (by region code) to the vacation plan. | +| `update_holiday_calendar` | Update label or color for a holiday calendar. | +| `delete_holiday_calendar` | Remove a holiday calendar from the vacation plan. | +| `list_holiday_countries` | List countries available for public holiday calendars. | +| `list_holidays` | List public holidays for a country and year. | + +### Journey _(Journey addon required)_ + +Requires `journey:read` or `journey:write` scope. + +| Tool | Description | +|---|---| +| `list_journeys` | List all journeys owned or contributed to by the current user. | +| `get_journey` | Get a full snapshot of a journey — metadata, entries, contributors, and linked trips. | +| `create_journey` | Create a new journey with title, optional subtitle, and an initial list of trip IDs. | +| `update_journey` | Update a journey's title, subtitle, or status. | +| `delete_journey` | Delete a journey. | +| `add_journey_trip` | Link an existing trip to a journey. | +| `remove_journey_trip` | Remove a trip from a journey. | +| `list_journey_entries` | List all entries in a journey (date, text, mood, linked trip). | +| `create_journey_entry` | Add an entry with date (required), optional title, story text, time of day, location name, mood, and sort order. | +| `update_journey_entry` | Edit a journey entry's title, story, date, time of day, or mood. | +| `delete_journey_entry` | Remove an entry from a journey. | +| `reorder_journey_entries` | Reorder entries by providing the new ordered list of entry IDs. | +| `list_journey_contributors` | List the contributors of a journey (owner and editors/viewers). | +| `add_journey_contributor` | Invite a user to a journey with `editor` or `viewer` role. | +| `update_journey_contributor_role` | Change a contributor's role between `editor` and `viewer`. | +| `remove_journey_contributor` | Remove a contributor from a journey. | +| `update_journey_preferences` | Update display preferences for a journey. | +| `get_journey_suggestions` | Get suggested trips to add to journeys based on recent trip history. | +| `list_journey_available_trips` | List all trips available to the current user for linking to a journey. | +| `get_journey_share_link` | Get the current public share link for a journey. Requires `journey:share`. | +| `create_journey_share_link` | Create or update the public share link for a journey. Requires `journey:share`. | +| `delete_journey_share_link` | Revoke the public share link for a journey. Requires `journey:share`. | + +--- + +## Addon-gated resources + +Resources provide read-only access via `trek://` URIs. The following resources require their addon to be enabled. + +| URI | Addon | Scope required | Description | +|---|---|---|---| +| `trek://trips/{tripId}/budget` | Budget | `budget:read` | Budget and expense items | +| `trek://trips/{tripId}/budget/per-person` | Budget | `budget:read` | Per-person totals and split breakdown | +| `trek://trips/{tripId}/budget/settlement` | Budget | `budget:read` | Suggested transactions to settle who owes whom | +| `trek://trips/{tripId}/packing` | Packing | `packing:read` | Packing checklist | +| `trek://trips/{tripId}/packing/bags` | Packing | `packing:read` | Packing bags with their assigned members | +| `trek://trips/{tripId}/todos` | Packing | `todos:read` | To-do items ordered by position | +| `trek://trips/{tripId}/collab-notes` | Collab | `collab:read` | Shared collaborative notes | +| `trek://bucket-list` | Atlas | `atlas:read` | Your personal travel bucket list | +| `trek://visited-countries` | Atlas | `atlas:read` | Countries marked as visited in Atlas | +| `trek://atlas/stats` | Atlas | `atlas:read` | Visited country counts and continent breakdown | +| `trek://atlas/regions` | Atlas | `atlas:read` | Manually visited sub-country regions | +| `trek://trips/{tripId}/collab/polls` | Collab | `collab:read` | All polls for a trip with vote counts per option | +| `trek://trips/{tripId}/collab/messages` | Collab | `collab:read` | Most recent 100 chat messages for a trip | +| `trek://vacay/plan` | Vacay | `vacay:read` | Full snapshot of your active vacation plan (members, years, config) | +| `trek://vacay/entries/{year}` | Vacay | `vacay:read` | All vacation day entries for the active plan and a specific year | +| `trek://vacay/holidays/{year}` | Vacay | `vacay:read` | Public holidays for the plan's configured region and year | +| `trek://journeys` | Journey | `journey:read` | All journeys owned or contributed to by the current user | +| `trek://journeys/{journeyId}` | Journey | `journey:read` | Single journey with entries, contributors, and linked trips | +| `trek://journeys/{journeyId}/entries` | Journey | `journey:read` | All entries in a journey (date, text, mood, linked trip) | +| `trek://journeys/{journeyId}/contributors` | Journey | `journey:read` | Contributors (owner and collaborators) of a journey | + +--- + +## Related + +- [MCP-Tools-and-Resources](MCP-Tools-and-Resources) +- [MCP-Scopes](MCP-Scopes) +- [MCP-Prompts](MCP-Prompts) +- [MCP-Setup](MCP-Setup) diff --git a/wiki/MCP-Overview.md b/wiki/MCP-Overview.md new file mode 100644 index 00000000..2f3c2026 --- /dev/null +++ b/wiki/MCP-Overview.md @@ -0,0 +1,49 @@ +# MCP Overview + +TREK includes a built-in [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) server. MCP is an open standard that lets AI assistants read and modify data in external services through a structured API. When the MCP addon is enabled on your TREK instance, AI clients such as Claude.ai, Claude Desktop, Cursor, VS Code, and others can connect directly to your trips. + +## What you can do + +Once connected, an AI assistant can work with your TREK data in a single conversation: + +- Create and update trips, days, and itineraries +- Search for real-world places and add them to your trip +- Build and manage packing lists and to-do items +- Track budgets and expenses across trip members +- Create reservations, transport bookings, and accommodations +- Send collab messages and notes to other trip members +- Mark countries and regions as visited in Atlas +- Log vacation days in Vacay +- Write journey entries across multiple trips + +Changes made through MCP are broadcast to all connected clients in real-time — exactly like changes made in the web UI. + +## Requirements + +- **MCP addon enabled** — an administrator must enable the MCP addon (`mcp`) from the Admin Panel before the `/mcp` endpoint becomes available and the MCP section appears in user settings. +- **`APP_URL` set** — the `APP_URL` environment variable must be configured to your TREK instance's public URL so that OAuth discovery works correctly. Without it, clients that use OAuth 2.1 cannot complete authentication. + +## Rate limits and session limits + +| Setting | Default | Environment variable | +|---|---|---| +| Requests per minute per user | 300 | `MCP_RATE_LIMIT` | +| Max concurrent sessions per user | 20 | `MCP_MAX_SESSION_PER_USER` | + +Rate limits are tracked per user–client pair, so each OAuth client has its own independent window. Sessions expire after 1 hour of inactivity. + +## Endpoint + +``` +https:///mcp +``` + +If the MCP addon is not enabled, this endpoint returns `403`. If authentication fails, it returns `401`. + +> **Admin:** Enable the MCP addon in [Admin-Addons](Admin-Addons). Set `APP_URL` for OAuth discovery. Revoke tokens and manage OAuth clients from [Admin-MCP-Tokens](Admin-MCP-Tokens). Adjust rate and session limits with `MCP_RATE_LIMIT` and `MCP_MAX_SESSION_PER_USER` — see [Environment-Variables](Environment-Variables). + +## Next steps + +1. [MCP-Setup](MCP-Setup) — connect your AI client +2. [MCP-Scopes](MCP-Scopes) — choose the right permissions +3. [MCP-Tools-and-Resources](MCP-Tools-and-Resources) — browse available tools diff --git a/wiki/MCP-Prompts.md b/wiki/MCP-Prompts.md new file mode 100644 index 00000000..ea0ed846 --- /dev/null +++ b/wiki/MCP-Prompts.md @@ -0,0 +1,27 @@ +# MCP Prompts + +TREK includes built-in MCP prompts — pre-built context loaders that tell your AI client how to summarize or present your trip data in a structured way. Prompts are a standard MCP feature: compatible clients can invoke them by name to get a ready-made starting point for common tasks. + +## Built-in prompts + +| Prompt | Addon required | Description | +|---|---|---| +| `trip-summary` | — | Loads a formatted summary of a trip: dates, member list, day count, number of places per day, packing progress, budget total, reservation count, and collab note count. Use this before asking the AI to plan or modify a trip. | +| `packing-list` | Packing | Returns the full packing checklist for a trip, grouped by category, with each item marked checked or unchecked. | +| `budget-overview` | Budget | Returns a budget summary for a trip — total spend, breakdown by category (sorted descending), and a per-person cost estimate. | +| `token_auth_notice` | — | Deprecation notice for sessions authenticated with a static `trek_` token. Only available in static-token sessions. Explains that the token will stop working in a future version and how to migrate to OAuth 2.1. | + +`packing-list` and `budget-overview` are only registered when the corresponding addon is enabled on your TREK instance. + +`token_auth_notice` is only registered when the current session was authenticated with a legacy static API token — it does not appear in OAuth sessions. + +## How to use prompts + +In a compatible MCP client (such as Claude.ai or Claude Desktop), prompts typically appear as slash commands or in a prompts panel. You select the prompt, supply any required arguments (such as a `tripId`), and the client sends the formatted context to the AI before your next message. + +For example, invoking `trip-summary` with a trip ID gives the AI a compact snapshot of that trip — days, members, budget, packing — without needing to call multiple tools one by one. + +## Related + +- [MCP-Tools-and-Resources](MCP-Tools-and-Resources) +- [MCP-Setup](MCP-Setup) diff --git a/wiki/MCP-Scopes.md b/wiki/MCP-Scopes.md new file mode 100644 index 00000000..54190293 --- /dev/null +++ b/wiki/MCP-Scopes.md @@ -0,0 +1,67 @@ +# MCP Scopes + +OAuth scopes control exactly which data your AI client can read or write in TREK. You select scopes during the OAuth consent screen or when pre-creating an OAuth client. You can revoke access at any time by deleting the OAuth client or token from **Settings → Integrations → MCP**. + +![OAuth consent screen](assets/OAuthConsentDCR.png) + +## All scopes + +TREK defines 27 scopes across 13 groups. + +| Group | Scope | Permission | +|---|---|---| +| **Trips** | `trips:read` | View trips, days, day notes, and members | +| | `trips:write` | Create, update, and delete trips, days, day notes, and accommodations; manage members; duplicate trips | +| | `trips:delete` | Permanently delete entire trips (irreversible) | +| | `trips:share` | Create, update, and revoke public share links for trips | +| **Places** | `places:read` | Read places, day assignments, tags, and categories | +| | `places:write` | Create, update, and delete places, assignments, and tags | +| **Atlas** | `atlas:read` | Read visited countries, regions, and bucket list | +| | `atlas:write` | Mark countries and regions visited, manage bucket list | +| **Packing** | `packing:read` | Read packing items, bags, and category assignees | +| | `packing:write` | Add, update, delete, toggle, and reorder packing items and bags | +| **To-dos** | `todos:read` | Read trip to-do items and category assignees | +| | `todos:write` | Create, update, toggle, delete, and reorder to-do items | +| **Budget** | `budget:read` | Read budget items and expense breakdown | +| | `budget:write` | Create, update, and delete budget items | +| **Reservations** | `reservations:read` | Read reservations and accommodation details | +| | `reservations:write` | Create, update, delete, and reorder reservations | +| **Collaboration** | `collab:read` | Read collab notes, polls, and messages | +| | `collab:write` | Create, update, and delete collab notes, polls, and messages | +| **Notifications** | `notifications:read` | Read in-app notifications and unread counts | +| | `notifications:write` | Mark notifications as read or unread (individually or all at once) | +| **Vacation** | `vacay:read` | Read vacation planning data, entries, and stats | +| | `vacay:write` | Create and manage vacation entries, holidays, and team plans | +| **Geo** | `geo:read` | Search locations, resolve map URLs, and reverse-geocode coordinates | +| **Weather** | `weather:read` | Fetch weather forecasts for trip locations and dates | +| **Journey** | `journey:read` | Read journeys, entries, and contributor list | +| | `journey:write` | Create, update, and delete journeys and their entries | +| | `journey:share` | Create, update, and revoke public share links for journeys | + +## Scope rules + +- A `:write` scope implies `:read` access for the same group (e.g. `budget:write` also grants read access to budget data). +- Any `trips:*` scope (`trips:read`, `trips:write`, `trips:delete`, or `trips:share`) grants trip read access. +- `journey:read` or `journey:write` grants journey read access. `journey:share` alone does **not** grant read access — it only enables managing public share links. +- `list_trips` and `get_trip_summary` are always available regardless of scope — they are navigation tools. +- Static tokens and web session JWTs have full access equivalent to all scopes. +- Addon-gated tools (Atlas, Collab, Vacay, Journey) require both the relevant scope **and** the corresponding addon to be enabled by an admin. + +## Choosing the right scopes + +Grant only what you need. Some examples: + +| Use case | Minimum scopes | +|---|---| +| Read-only AI assistant | All `:read` scopes relevant to your data | +| Full trip planner | All scopes except `:delete` (use the Claude.ai or Claude Desktop preset) | +| Budget review only | `trips:read` + `budget:read` | +| Packing list assistant | `trips:read` + `packing:read` + `packing:write` | +| Journey writer | `trips:read` + `journey:read` + `journey:write` | + +The preset buttons in **Settings → Integrations → MCP → OAuth Clients** fill in a reasonable scope set for common clients. VS Code defaults to read-only scopes; Claude.ai and Claude Desktop default to all scopes except `:delete`. + +## Related + +- [MCP-Setup](MCP-Setup) +- [MCP-Tools-and-Resources](MCP-Tools-and-Resources) diff --git a/wiki/MCP-Setup.md b/wiki/MCP-Setup.md new file mode 100644 index 00000000..2ff069ea --- /dev/null +++ b/wiki/MCP-Setup.md @@ -0,0 +1,141 @@ +# MCP Setup + +This page explains how to connect an AI assistant to your TREK instance. TREK supports two authentication methods: OAuth 2.1 (recommended) and static API tokens (deprecated). + + + +![MCP Setup](assets/MCPConfig.png) + +## Option A: OAuth 2.1 (recommended) + +OAuth 2.1 is the preferred connection method. You grant specific scopes during the consent step and no token management is required afterward — TREK issues short-lived access tokens and automatically rotates refresh tokens. + +### Claude.ai + +Claude.ai (web) supports native MCP connections — no JSON config file required: + +1. In TREK, go to **Settings → Integrations → MCP → OAuth Clients** and click **Create**. +2. Select the **Claude.ai** preset. This fills in the redirect URI (`https://claude.ai/api/mcp/auth_callback`) and a default scope set. +3. Give the client a name, adjust scopes if needed, and save. Copy the client ID and client secret (`trekcs_` prefix) — the secret is shown only once. +4. In Claude.ai, open the MCP settings and add a new server using your TREK URL (`https:///mcp`). Claude.ai will open your browser to complete the OAuth consent flow. + +### Claude Desktop + +Claude Desktop connects via `mcp-remote`. After creating an OAuth client using the **Claude Desktop** preset (redirect URI: `http://localhost`), add the following to your Claude Desktop config: + +```json +{ + "mcpServers": { + "trek": { + "command": "npx", + "args": [ + "mcp-remote", + "https:///mcp", + "--static-oauth-client-info", + "{\"client_id\": \"\", \"client_secret\": \"\"}" + ] + } + } +} +``` + +When the client starts it opens your browser to the TREK consent screen to complete the OAuth flow. + +### Cursor, VS Code, Windsurf, and Zed + +Clients that support `mcp-remote` can connect in one of two ways. + +**Option 1 — dynamic registration (no pre-created client needed):** + +```json +{ + "mcpServers": { + "trek": { + "command": "npx", + "args": [ + "mcp-remote", + "https:///mcp" + ] + } + } +} +``` + +When the client starts, it fetches TREK's OAuth discovery document (`/.well-known/oauth-authorization-server`), registers itself automatically, and opens your browser to the TREK consent screen. You choose scopes there. + +**Option 2 — pre-created OAuth client:** + +Create a client in TREK using the appropriate preset (Cursor, VS Code, Windsurf, or Zed — all use `http://localhost` as redirect URI), then pass the credentials via `--static-oauth-client-info`: + +```json +{ + "mcpServers": { + "trek": { + "command": "npx", + "args": [ + "mcp-remote", + "https:///mcp", + "--static-oauth-client-info", + "{\"client_id\": \"\", \"client_secret\": \"\"}" + ] + } + } +} +``` + +> On Windows, `npx` may need a full path, for example `C:\PROGRA~1\nodejs\npx.cmd`. + +> **Requirement:** `APP_URL` must be set on the server for OAuth discovery to work. + +### Pre-created OAuth clients + +**Settings → Integrations → MCP → OAuth Clients** lets you create named OAuth clients before connecting. This gives you: + +- A fixed, named scope list defined up front +- A client secret (`trekcs_` prefix, shown once) for confidential client mode +- Preset buttons for Claude.ai, Claude Desktop, Cursor, VS Code, Windsurf, and Zed that fill in the correct redirect URIs and a sensible default scope set + +Each user can have up to **10 OAuth clients**. + +## Option B: Static API token (deprecated) + +> **Deprecated:** Static tokens will stop working in a future version of TREK. Migrate to OAuth 2.1. + +Static tokens grant full access to all tools and resources with no scope restrictions. Sessions using a static token will receive deprecation warnings in the AI client on every tool call. + +1. Go to **Settings → Integrations → MCP**, open the **API Tokens** sub-tab, and click **Create New Token**. +2. Give the token a name and copy it immediately — it is shown only once. The token starts with `trek_`. +3. Pass the token as a header in your client config: + +```json +{ + "mcpServers": { + "trek": { + "command": "npx", + "args": [ + "mcp-remote", + "https:///mcp", + "--header", + "Authorization: Bearer trek_your_token_here" + ] + } + } +} +``` + +Each user can create up to **10 static tokens**. + +## Authentication reference + +| Method | Token prefix | Access level | Expiry | +|---|---|---|---| +| OAuth 2.1 access token | `trekoa_` | Scoped (per-consent) | 1 hour; auto-refreshed via 30-day rolling refresh token (`trekrf_`) | +| OAuth client secret | `trekcs_` | Used during OAuth registration | No expiry (revoke via UI) | +| Static API token | `trek_` | Full access | No expiry — **deprecated** | + +## Related + +- [MCP-Overview](MCP-Overview) +- [MCP-Scopes](MCP-Scopes) +- [Admin-MCP-Tokens](Admin-MCP-Tokens) +- [Environment-Variables](Environment-Variables) diff --git a/wiki/MCP-Tools-and-Resources.md b/wiki/MCP-Tools-and-Resources.md new file mode 100644 index 00000000..8d593c66 --- /dev/null +++ b/wiki/MCP-Tools-and-Resources.md @@ -0,0 +1,197 @@ +# MCP Tools and Resources + +TREK exposes **tools** (read and write actions) and **resources** (read-only `trek://` URIs). Tools are registered per-session based on OAuth scopes and enabled addons. + +For addon-gated tools (Packing, To-Dos, Atlas, Collab, Vacay, Journey) and their resources, see [MCP-Addon-Tools](MCP-Addon-Tools). + +## Tools + +### Trip Summary + +| Tool | Description | +|---|---| +| `get_trip_summary` | Full denormalized snapshot of a trip — metadata, members, days with assignments and notes, accommodations, budget, packing, reservations, collab notes, and to-dos in one call. Use this as your context loader before making changes. | + +### Compound tools + +Compound tools collapse multi-step workflows into a single atomic transaction. If the second step fails, the first is rolled back. + +> Use compound tools only when the place or item does not yet exist. For existing records, call the individual tools directly. + +| Tool | Wraps | Description | +|---|---|---| +| `create_and_assign_place` | `create_place` + `assign_place_to_day` | Create a place and assign it to a day. Returns `{ place, assignment }`. Requires `places:write`. | +| `create_place_accommodation` | `create_place` + `create_accommodation` | Create a place and book it as an accommodation. Returns `{ place, accommodation }`. Requires `trips:write`. | +| `create_budget_item_with_members` | `create_budget_item` + `set_budget_item_members` | Create a budget item and set splitting members. If `userIds` is omitted, behaves like `create_budget_item`. Returns `{ item }`. Requires `budget:write`. | + +### Trips + +Requires `trips:read` or `trips:write` scope. + +| Tool | Description | +|---|---| +| `list_trips` | List all trips you own or are a member of. Supports `include_archived` flag. | +| `create_trip` | Create a trip with title, dates, and currency. Days are auto-generated from the date range. | +| `update_trip` | Update a trip's title, description, dates, or currency. | +| `delete_trip` | Delete a trip. Owner only. Requires `trips:delete`. | +| `list_trip_members` | List the owner and all collaborators of a trip. | +| `add_trip_member` | Add a user to a trip by username or email. Owner only. | +| `remove_trip_member` | Remove a collaborator from a trip. Owner only. | +| `copy_trip` | Duplicate a trip (days, places, itinerary, packing, budget, reservations). Packing items reset to unchecked. | +| `export_trip_ics` | Export the trip itinerary and reservations as iCalendar (`.ics`) text. | +| `get_share_link` | Get the current public share link for a trip and its permission flags. Requires `trips:share`. | +| `create_share_link` | Create or update the public share link with configurable visibility flags. Requires `trips:share`. | +| `delete_share_link` | Revoke the public share link for a trip. Requires `trips:share`. | + +### Places + +Requires `places:read` or `places:write` scope. + +| Tool | Description | +|---|---| +| `list_places` | List places in a trip, optionally filtered by assignment status, category, tag, or search query. | +| `create_place` | Add a place with name, coordinates, address, category, notes, website, phone, and optional `google_place_id` / `osm_id`. | +| `update_place` | Update any field of an existing place including transport mode, timing, and price. | +| `delete_place` | Remove a place from a trip. Also removes all day assignments. | +| `bulk_delete_places` | Delete multiple places by ID. Removes all day assignments. Cannot be undone. | +| `import_places_from_url` | Import all places from a publicly shared Google Maps or Naver Maps list URL. | +| `list_categories` | List all available place categories with id, name, icon, and color. | +| `search_place` | Search for a place by name or address. Returns `osm_id` and `google_place_id` for use in `create_place`. | + +### Day Planning + +Requires `trips:read` or `trips:write` scope. + +| Tool | Description | +|---|---| +| `update_day` | Set or clear a day's title. | +| `create_day` | Add a new day to a trip with optional date and notes. | +| `delete_day` | Delete a day from a trip. | +| `assign_place_to_day` | Pin a place to a specific day in the itinerary. Requires `places:write`. | +| `unassign_place` | Remove a place assignment from a day. Requires `places:write`. | +| `reorder_day_assignments` | Reorder places within a day by providing assignment IDs in order. Requires `places:write`. | +| `update_assignment_time` | Set start/end times for a place assignment (e.g. `"09:00"` – `"11:30"`). Pass `null` to clear. Requires `places:write`. | +| `move_assignment` | Move a place assignment to a different day. Requires `places:write`. | +| `get_assignment_participants` | Get users participating in a specific place assignment. | +| `set_assignment_participants` | Set participants for a place assignment (replaces current list). | + +### Day Notes + +Requires `trips:read` or `trips:write` scope. + +| Tool | Description | +|---|---| +| `create_day_note` | Add a note to a specific day with optional time label and emoji icon. | +| `update_day_note` | Edit a day note's text, time, or icon. | +| `delete_day_note` | Remove a note from a day. | + +### Accommodations + +Requires `trips:read` or `trips:write` scope. + +| Tool | Description | +|---|---| +| `create_accommodation` | Add an accommodation (hotel, Airbnb, etc.) linked to a place and a check-in/check-out date range. | +| `update_accommodation` | Update fields on an existing accommodation including dates, times, confirmation, and notes. | +| `delete_accommodation` | Delete an accommodation record from a trip. | + +### Transport + +Requires `reservations:write` scope. + +| Tool | Description | +|---|---| +| `create_transport` | Create a transport booking (`flight`, `train`, `car`, `cruise`) with optional multi-stop endpoints, departure/arrival times, and confirmation details. | +| `update_transport` | Update an existing transport booking. Pass `endpoints[]` to replace all stops. | +| `delete_transport` | Delete a transport booking from a trip. | + +### Reservations + +Requires `reservations:read` or `reservations:write` scope. + +| Tool | Description | +|---|---| +| `create_reservation` | Create a pending reservation — hotels, restaurants, events, tours, activities, and other types. | +| `update_reservation` | Update any field including status (`pending` / `confirmed` / `cancelled`). | +| `delete_reservation` | Delete a reservation and its linked accommodation record if applicable. | +| `reorder_reservations` | Reorder reservations within a day. | +| `link_hotel_accommodation` | Set or update a hotel reservation's check-in/out day links and place. | + +### Budget + +Requires `budget:read` or `budget:write` scope. Budget addon must be enabled. + +| Tool | Description | +|---|---| +| `create_budget_item` | Add an expense with name, category, and price. | +| `update_budget_item` | Update an expense's details, split (persons/days), or notes. | +| `delete_budget_item` | Remove a budget item. | +| `set_budget_item_members` | Set which members are splitting a budget item (replaces current list). | +| `toggle_budget_member_paid` | Mark or unmark a member as having paid their share. | + +### Tags + +Requires `places:read` or `places:write` scope. + +| Tool | Description | +|---|---| +| `list_tags` | List all tags belonging to the current user. | +| `create_tag` | Create a new tag (user-scoped label for places) with optional hex color. | +| `update_tag` | Update the name or color of an existing tag. | +| `delete_tag` | Delete a tag (removes it from all attached places). | + +### Maps & Weather + +| Tool | Scope required | Description | +|---|---|---| +| `get_place_details` | `geo:read` | Fetch detailed information (hours, photos, ratings) about a place by its Google Place ID. | +| `reverse_geocode` | `geo:read` | Get a human-readable address for given coordinates. | +| `resolve_maps_url` | `geo:read` | Resolve a Google Maps share URL to coordinates and place name. | +| `search_airports` | `geo:read` | Search for airports by name, city, or IATA code. Returns IATA code, name, city, country, timezone. | +| `get_airport` | `geo:read` | Look up an airport by IATA code (e.g. `"ZRH"`, `"CDG"`). | +| `get_weather` | `weather:read` | Get a weather forecast for a location and date. | +| `get_detailed_weather` | `weather:read` | Get an hourly/detailed weather forecast for a location and date. | + +### Notifications + +Requires `notifications:read` or `notifications:write` scope. + +| Tool | Description | +|---|---| +| `list_notifications` | List in-app notifications with pagination and optional unread filter. | +| `get_unread_notification_count` | Get the unread notification count. | +| `mark_notification_read` | Mark a notification as read. | +| `mark_notification_unread` | Mark a notification as unread. | +| `mark_all_notifications_read` | Mark all notifications as read. | + +--- + +## Resources + +Resources provide read-only access via `trek://` URIs. Read them to understand current state before making changes. + +### Core resources + +| URI | Scope required | Description | +|---|---|---| +| `trek://trips` | `trips:*` | All trips you own or are a member of | +| `trek://trips/{tripId}` | `trips:*` | Single trip with metadata and member count | +| `trek://trips/{tripId}/days` | `trips:*` | Days of a trip with their assigned places | +| `trek://trips/{tripId}/places` | `places:read` | All places in a trip. Supports `?assignment=all\|unassigned\|assigned` | +| `trek://trips/{tripId}/reservations` | `reservations:read` | Flights, hotels, restaurants, and other reservations | +| `trek://trips/{tripId}/days/{dayId}/notes` | `trips:*` | Notes for a specific day | +| `trek://trips/{tripId}/accommodations` | `trips:*` | Hotels and rentals with check-in/out details | +| `trek://trips/{tripId}/members` | `trips:*` | Owner and collaborators | +| `trek://categories` | (any) | Available place categories (id, name, icon, color) | +| `trek://notifications/in-app` | `notifications:read` | Your in-app notifications (most recent 50, unread first) | + +For addon-gated resources (Budget, Packing, To-Dos, Collab, Atlas, Vacay, Journey), see [MCP-Addon-Tools](MCP-Addon-Tools). + +--- + +## Related + +- [MCP-Addon-Tools](MCP-Addon-Tools) +- [MCP-Scopes](MCP-Scopes) +- [MCP-Prompts](MCP-Prompts) +- [MCP-Setup](MCP-Setup) diff --git a/wiki/Map-Features.md b/wiki/Map-Features.md new file mode 100644 index 00000000..878976eb --- /dev/null +++ b/wiki/Map-Features.md @@ -0,0 +1,70 @@ +# Map Features + +The trip planner map shows your places, route lines, transport overlays, and your current location in real time. + + + +![Trip Planner Map](assets/TripPlannerWithPlane.png) + +## Map renderer + +TREK uses **Leaflet** by default. If you configure a Mapbox access token in Settings → Map, the map upgrades to **Mapbox GL** with higher-quality tiles, 3D buildings, and terrain. If Mapbox GL is selected but no access token is present, TREK falls back to Leaflet automatically so the map is never blank. + +The scopes required for Mapbox GL are: +- STYLES:TILES +- STYLES:READ +- FONTS:READ +- DATASETS:WRITE +- VISION:CREATE + +## Place markers + +Each place is shown as a circular marker: + +- **Photo marker** — if the place has a photo (proxied from Google or another provider), that image appears in the circle. +- **Icon marker** — if no photo is available, a category-colored icon is shown instead. +- **Selected place** — the active place has a larger marker. +- **Order badge** — a small badge at the bottom-right of each marker shows the order number(s) of that place within the day's itinerary. If the place appears on multiple days, all order positions are shown separated by `·`. + +When zoomed out, nearby markers are grouped into clusters. Clicking a cluster zooms the map to fit its members; at maximum zoom the cluster spiderfies to show individual markers. + +## Route lines + +When you have a day selected, a dark dashed line connects consecutive places in that day's order. + +## Route time pills + +At zoom level 12 or higher, small pill-shaped labels appear between consecutive places and show the estimated **walking time** and **driving time** for each segment. Below zoom 12 they are hidden to keep the map clean. + +## Reservation and transport overlay + +Flights, trains, cars, and cruises are drawn as overlays between their endpoint places: + +- **Flights and cruises** — geodesic great-circle arcs +- **Trains and cars** — straight lines +- **Antimeridian crossings** — arcs that would cross the date line are split into sub-arcs to avoid wrapping across the map +- **Endpoint markers** — pill-shaped labels with the transport icon and the endpoint code (e.g. IATA airport code) or location name +- **Flight stats** — a floating label on the arc shows departure code → arrival code and, when times are available, the duration and great-circle distance. Stats labels are only rendered for flights. +- **Confirmed reservations** — solid line; **Pending** — dashed line + +> **Admin:** Whether endpoint labels appear is controlled by the **Show connection labels** setting (`map_booking_labels`). + +## Location button + +The location button sits in the bottom-right corner of the map on mobile devices and cycles through three states: + +| State | Icon | Behavior | +|---|---|---| +| Off | Outline locate | Location not tracked | +| Show | Solid blue locate | Your position is shown as a dot | +| Follow | Solid blue arrow | Map re-centers as you move | + +If geolocation is denied or unavailable, the button turns red. + +## Right-click / middle-click to create a place + +Right-click anywhere on the **Leaflet** map to open the Place form with the clicked coordinates and a reverse-geocoded address already filled in. + +On the **Mapbox GL** map, right-click is reserved for the built-in rotate/pitch gesture, so use **middle-click** instead to trigger the same Place form. + +**See also:** [Places-and-Search](Places-and-Search) · [Day-Plans-and-Notes](Day-Plans-and-Notes) · [Route-Optimization](Route-Optimization) · [Map-Settings](Map-Settings) · [Reservations-and-Bookings](Reservations-and-Bookings) diff --git a/wiki/Map-Settings.md b/wiki/Map-Settings.md new file mode 100644 index 00000000..61594dcd --- /dev/null +++ b/wiki/Map-Settings.md @@ -0,0 +1,77 @@ +# Map Settings + +The Map tab (Settings → Map) controls which map engine and tile source TREK uses in the Trip Planner and Journey maps. Changes take effect after clicking **Save map settings**. + +> **Note:** The Atlas view always uses Leaflet regardless of this setting. + + + +![Map Settings](assets/UsrSettingsMap.png) + +## Map provider + +Choose the rendering engine: + +| Provider | Description | +|----------|-------------| +| **Leaflet** | Classic 2D renderer. Works with any raster tile URL. | +| **Mapbox GL** *(Experimental)* | Vector tiles with 3D buildings and terrain support. Requires a Mapbox access token. | + +## Leaflet — tile source + +When Leaflet is selected, pick a preset or enter a custom tile URL. + +**Built-in presets:** + +| Name | URL | +|------|-----| +| OpenStreetMap | `https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png` | +| OpenStreetMap DE | `https://tile.openstreetmap.de/{z}/{x}/{y}.png` | +| CartoDB Light | `https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png` | +| CartoDB Dark | `https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png` | +| Stadia Smooth | `https://tiles.stadiamaps.com/tiles/alidade_smooth/{z}/{x}/{y}{r}.png` | + +You can also type any XYZ tile URL directly into the text field. + +> **Admin:** The admin can set a default map tile URL for all new users via the **User Defaults** tab in the Admin Panel. See [Admin-Panel-Overview](Admin-Panel-Overview). + +## Mapbox GL — access token and style + +Enter your **public token** (`pk.*`) from [mapbox.com → Access tokens](https://account.mapbox.com/access-tokens/). + +If Mapbox GL is selected but no token is saved, the map area shows an empty state with a prompt to configure the token under Settings → Map → Mapbox GL. + +**Built-in style presets:** + +| Style | Tags | +|-------|------| +| Mapbox Standard | 3D, Apple-like | +| Standard Satellite | 3D, Satellite | +| Streets | 3D, Classic | +| Outdoors | 3D, Terrain | +| Light | 3D, Minimal | +| Dark | 3D, Dark | +| Satellite | 3D, Satellite | +| Satellite Streets | 3D, Satellite | +| Navigation Day | 3D, Apple-like | +| Navigation Night | 3D, Dark | + +You can also enter a custom `mapbox://styles/USER/ID` URL directly. + +### 3D Buildings & Terrain + +Enables pitch and building extrusions on all styles. Terrain elevation (DEM-based height) is additionally applied on satellite styles (`Satellite` and `Satellite Streets`). On non-satellite styles only building extrusions are added; terrain is intentionally omitted on those styles because the elevation data would cause route lines to visually drift away from the HTML place markers. + +### High Quality Mode *(Experimental)* + +Enables antialiasing and globe projection for sharper edges. May impact performance on lower-end devices. + +## Default map center + +Set the default latitude, longitude, and zoom level for the map. You can also click on the map preview to move the center pin. + +## See also + +- [Map-Features](Map-Features) +- [Admin-Panel-Overview](Admin-Panel-Overview) +- [User-Settings](User-Settings) diff --git a/wiki/My-Trips-Dashboard.md b/wiki/My-Trips-Dashboard.md new file mode 100644 index 00000000..91db89bc --- /dev/null +++ b/wiki/My-Trips-Dashboard.md @@ -0,0 +1,66 @@ +# My Trips Dashboard + +The dashboard at `/dashboard` is your home base — it lists all your trips, lets you create new ones, and surfaces quick-access widgets. + + + +![My Trips Dashboard](assets/DashboardWidgets.png) + +## View Modes + +Use the toggle button in the top toolbar to switch between **grid** (card thumbnails) and **list** (compact rows). Your preference is saved in `localStorage` under the key `trek_dashboard_view` and persists across sessions. + +In grid mode the dashboard shows a large [Spotlight card](#spotlight-card) for your most relevant trip, with remaining trips in a responsive grid below. In list mode the Spotlight card is not shown separately — all trips (including the one that would be the spotlight) appear as uniform rows in the same sort order. + +## Sort Order + +Trips are always sorted in this order: + +1. **Ongoing** — trips where today falls between the start and end date. +2. **Upcoming** — future trips, sorted by start date ascending (soonest first). +3. **Past** — completed trips, sorted by start date descending (most recent first). + +Trips without dates are treated as past. + +## Spotlight Card + +The first ongoing trip — or the next upcoming trip if none is ongoing — is promoted to a full-width **Spotlight card** at the top of the grid on desktop. On mobile this card appears as a hero at the top of the page. The spotlight card shows a progress bar for ongoing trips and a stats strip (days, places, travel companions). + +If you have no trips yet, the spotlight card is not shown. + +## Archived Trips + +Archived trips are hidden from the main list and collapsed into a separate **Archived** section at the bottom of the page. Click the section header to expand it. You can **Copy**, **Restore**, or permanently **Delete** an archived trip from the row actions. + +## Greeting (Mobile) + +On mobile, the header shows a time-of-day greeting — "Good morning", "Good afternoon", or "Good evening" — along with your username and avatar. The greeting changes at 12:00 (noon) and 18:00. The mobile header also includes a **Notifications** button (bell icon) that navigates to `/notifications`. + +## Dashboard Widgets Sidebar + +On wide screens a sticky right column shows the **Currency Converter** and **Timezone Clock** widgets. Each can be toggled on or off via the Settings icon in the toolbar. On mobile, the widgets are available as a bottom sheet from the quick-action buttons at the top of the page. + +See [Dashboard-Widgets](Dashboard-Widgets) for full usage details. + +## Per-Trip Actions + +On desktop, hover over a card (or open the row actions in list view) to reveal the action buttons — they appear on mouse-over only. On mobile, action buttons are always visible directly on the card cover. The available actions are: + +| Action | Permission required | +|---|---| +| **Edit** | `trip_edit` or `trip_cover_upload` on that trip | +| **Copy** | `trip_create` | +| **Archive / Unarchive** | `trip_archive` on that trip | +| **Delete** | `trip_delete` on that trip | + +Actions not permitted for your role are hidden. Admins always see all actions. + +## Empty State + +When you have no trips, the dashboard shows an illustration and a **Plan your first trip** button that opens the [Creating-a-Trip](Creating-a-Trip) dialog. + +## Related Pages + +- [Creating-a-Trip](Creating-a-Trip) +- [Trip-Planner-Overview](Trip-Planner-Overview) +- [Dashboard-Widgets](Dashboard-Widgets) diff --git a/wiki/Notifications.md b/wiki/Notifications.md new file mode 100644 index 00000000..00af021c --- /dev/null +++ b/wiki/Notifications.md @@ -0,0 +1,88 @@ +# Notifications + +The Notifications tab (Settings → Notifications) lets you choose which events notify you and through which channels. Each toggle saves immediately. + + + +![Notifications tab](assets/NotifSettings.png) + +## Notification channels + +TREK supports four delivery channels. Which channels appear depends on what the admin has enabled server-side. + +| Channel | Description | +|---------|-------------| +| **In-app** | Bell icon in the navigation bar. Always available. Delivered in real time via WebSocket. | +| **Email** | Delivered to your account email. Requires the admin to configure SMTP. | +| **Webhook** | TREK POSTs a JSON payload to a URL you specify. Discord and Slack webhook URLs are auto-detected and receive a natively formatted payload. | +| **ntfy** | Push notifications via [ntfy.sh](https://ntfy.sh) or a self-hosted ntfy server. | + +## Notification events + +The following events are configurable in user settings: + +| Event | Description | +|-------|-------------| +| `trip_invite` | Someone invited you to a trip | +| `booking_change` | A booking was added, updated, or removed in a trip you're part of | +| `trip_reminder` | Reminder before a trip starts | +| `vacay_invite` | You were invited to fuse vacation plans | +| `photos_shared` | Photos were shared with a trip | +| `collab_message` | A new message in a collaborative trip | +| `packing_tagged` | You were assigned to a packing category in a trip | + +All user-facing events support all four channels (in-app, email, webhook, ntfy). A dash (—) in the matrix means that channel/event combination is not implemented. + +### Admin-only events + +The following events are shown in the admin panel (Admin → Notifications) and are not configurable per user: + +| Event | Description | Channels | +|-------|-------------|---------| +| `version_available` | A new TREK version is available | in-app, email, webhook, ntfy | + +### System-only events + +The following events are fired automatically and are not exposed as toggles in any settings panel: + +| Event | Description | Channels | +|-------|-------------|---------| +| `synology_session_cleared` | Your Synology account or URL changed, clearing your Photos session | in-app only | + +## Configuring the matrix + +The preferences panel shows a grid of events × channels. Toggle each intersection independently. Changes are saved automatically. + +## Webhook configuration + +Enter a URL that TREK will POST to when a notification fires. Once saved, the URL is displayed as `••••••••`. Use the **Test** button to send a test payload to the saved URL. + +TREK auto-detects the webhook destination and adjusts the payload format: + +- **Discord** (`discord.com/api/webhooks/…`) — sends a rich embed with title, description, and a timestamp. +- **Slack** (`hooks.slack.com/…`) — sends a formatted Slack message block. +- **Generic** — sends a plain JSON object with `event`, `title`, `body`, `tripName`, `link`, `timestamp`, and `source` (`"TREK"`) fields. + +## ntfy configuration + +Enter your ntfy **topic** and optionally a custom **server URL** (defaults to the server-wide ntfy server set by the admin) and an **access token** for private topics. The token is stored encrypted and displayed as `••••••••` after saving. Use the **Test** button to verify delivery. + +## In-app notification center + +The bell icon in the navigation bar shows your unread notification count. Click it to open the notification panel where you can: + +- Mark individual items read or unread. +- Mark all notifications read at once. +- Delete individual notifications or clear all at once. +- Respond to **boolean notifications** (e.g. trip invites that offer Accept / Decline actions directly in the panel). + +In-app notifications are pushed in real time via WebSocket so the badge and panel update without a page refresh. + +## Per-trip preferences + +Notification preferences are configured globally in Settings → Notifications. There are no per-trip overrides — the same toggle applies across all trips. + +## See also + +- [Environment-Variables](Environment-Variables) +- [User-Settings](User-Settings) diff --git a/wiki/OIDC-SSO.md b/wiki/OIDC-SSO.md new file mode 100644 index 00000000..69413bb0 --- /dev/null +++ b/wiki/OIDC-SSO.md @@ -0,0 +1,79 @@ +# OIDC / Single Sign-On + + + +## What OIDC gives you + +OpenID Connect (OIDC) lets users log in with an existing identity provider — Google, Authentik, Keycloak, or any OIDC-compatible IdP — instead of a local email/password. On first SSO login, a TREK account is created automatically using the email from the provider. + +## User flow + +1. Click **"Sign in with SSO"** on the login page. +2. You are redirected to your identity provider's login page. +3. Authenticate and grant consent. +4. The provider redirects back to TREK at `GET /api/auth/oidc/callback`. If this is your first login, an account is created automatically (subject to registration settings). +5. The server issues a short-lived one-time code and redirects your browser to `/login?oidc_code=`. The frontend immediately exchanges that code at `GET /api/auth/oidc/exchange?code=` to obtain the session. +6. Your `trek_session` cookie is set and you land on the dashboard. + +## Prerequisites + +Set the following environment variables before starting the server: + +| Variable | Required | Description | +|---|---|---| +| `APP_URL` | Yes | Base URL of your TREK instance (e.g. `https://trek.example.com`). Used to build the redirect URI. Can also be set via Admin → Settings. | +| `OIDC_ISSUER` | Yes | Issuer URL of your identity provider. Must use HTTPS in production. | +| `OIDC_CLIENT_ID` | Yes | OAuth 2.0 client ID registered with your IdP. | +| `OIDC_CLIENT_SECRET` | Yes | OAuth 2.0 client secret. | + +Register the following **redirect URI** with your identity provider: + +``` +/api/auth/oidc/callback +``` + +For example: `https://trek.example.com/api/auth/oidc/callback` + +## Optional environment variables + +| Variable | Description | +|---|---| +| `OIDC_DISPLAY_NAME` | Label shown on the SSO button. Defaults to `SSO`. | +| `OIDC_ONLY` | Set to `true` to disable local password login and password registration. SSO login and SSO registration remain governed by their own toggles. This is an environment-variable-only setting and cannot be toggled at runtime via the admin panel. | +| `OIDC_ADMIN_CLAIM` | OIDC claim to inspect for admin role mapping. Defaults to `groups`. The claim value may be an array or a plain string. **Env var only — not configurable via the admin panel.** | +| `OIDC_ADMIN_VALUE` | Value that must be present in `OIDC_ADMIN_CLAIM` to grant the admin role. If unset, claim-based role mapping is disabled. When set, the role is re-evaluated on every login. **Env var only — not configurable via the admin panel.** | +| `OIDC_SCOPE` | Overrides the default scope list sent to the provider. Defaults to `openid email profile`. Ensure `openid` and `email` are always included. **Env var only — not configurable via the admin panel.** | +| `OIDC_DISCOVERY_URL` | Full URL to the OIDC discovery document. Use this for providers with non-standard discovery paths (e.g. Authentik tenants). If unset, discovery is attempted at `/.well-known/openid-configuration`. The discovery document is cached for 1 hour. | + +## New-user registration via SSO + +When an SSO login matches an existing TREK account by email or OIDC subject (`sub`), that account is used and the OIDC identity is linked automatically. If no matching account exists, TREK attempts to create one. The outcome depends on the following: + +- **First user ever**: always created as admin, no invite required. +- **Open SSO registration enabled** (admin panel toggle `oidc_registration`): account is created as a regular user. +- **Invite token present** in the login URL: account is created regardless of the registration toggle. Pass the token as `?invite=` when initiating SSO login (e.g. `GET /api/auth/oidc/login?invite=`). +- **SSO registration disabled and no invite**: login is rejected with a `registration_disabled` error. + +## Admin panel (runtime configuration) + +OIDC can also be configured without environment variables via **Admin → SSO**. The following fields are settable at runtime: + +| Field | Env var equivalent | +|---|---| +| Issuer URL | `OIDC_ISSUER` | +| Client ID | `OIDC_CLIENT_ID` | +| Client Secret | `OIDC_CLIENT_SECRET` | +| Display name | `OIDC_DISPLAY_NAME` | +| Discovery URL | `OIDC_DISCOVERY_URL` | + +Environment variables take priority over database settings when both are present. + +The following variables are **env var only** and have no admin panel equivalent: `OIDC_ONLY`, `OIDC_SCOPE`, `OIDC_ADMIN_CLAIM`, `OIDC_ADMIN_VALUE`. + +The `OIDC_ONLY` env var always overrides the panel's login-method toggles. To disable password login at runtime without `OIDC_ONLY`, use the **password_login** and **password_registration** toggles in Admin → Settings instead. + +> **Note:** The admin panel prevents you from disabling all login methods simultaneously. At least one method (password or SSO) must remain active. Similarly, you cannot remove the OIDC configuration from the admin panel while password login is disabled. + +--- + +**See also:** [Login-and-Registration](Login-and-Registration) · [Environment-Variables](Environment-Variables) diff --git a/wiki/Offline-Mode-and-PWA.md b/wiki/Offline-Mode-and-PWA.md new file mode 100644 index 00000000..3f4cc08b --- /dev/null +++ b/wiki/Offline-Mode-and-PWA.md @@ -0,0 +1,76 @@ +# Offline Mode and PWA + +TREK can be installed as a Progressive Web App (PWA) and used without an internet connection for previously synced trips. + +## Install as an app (PWA) + +TREK must be served over **HTTPS** — the install prompt does not appear on plain HTTP. + +**iOS (Safari):** +1. Open TREK in Safari. +2. Tap the Share button. +3. Select **Add to Home Screen**. + +**Android (Chrome / Edge):** +1. Open TREK in the browser. +2. Tap the browser menu. +3. Select **Install app** or **Add to Home Screen**. + +Once installed, TREK launches in **standalone** mode (fullscreen, no browser UI) using the TREK icon. + +## What works offline + +TREK uses Workbox service-worker caching plus an IndexedDB database (Dexie) for structured trip data. The following content is available offline after the first sync: + +**Service-worker cache (Workbox)** + +| Content | Cache name | Strategy | Duration | Max entries | +|---------|------------|----------|----------|-------------| +| CartoDB / OpenStreetMap map tiles | `map-tiles` | CacheFirst | 30 days | 1 000 | +| Leaflet / CDN assets (unpkg) | `cdn-libs` | CacheFirst | 365 days | 30 | +| API responses (trips, places, bookings, etc.) | `api-data` | NetworkFirst (5 s timeout) | 24 hours | 200 | +| Cover images and avatars (`/uploads/covers`, `/uploads/avatars`) | `user-uploads` | CacheFirst | 7 days | 300 | +| App shell (HTML / JS / CSS) | precache | Precached | Until next deploy | — | + +> **Note:** The API cache excludes sensitive endpoints — `/api/auth`, `/api/admin`, `/api/backup`, and `/api/settings` are always fetched from the network. + +**IndexedDB (Dexie) — structured trip data** + +On login, after each trip-list refresh, and on WebSocket reconnect, TREK runs a background sync that writes full trip bundles into IndexedDB: + +- Trips, days, places, packing items, to-dos, budget items, reservations, accommodations, trip members, tags, and categories. +- Non-photo file attachments (PDFs, documents, etc.) are downloaded and stored as blobs in IndexedDB. +- Map tiles are pre-fetched into the service-worker `map-tiles` cache for zoom levels 10–16 across each trip's bounding box (capped at ~50 MB of tiles per sync). + +**Sync scope and eviction** + +- Only ongoing and future trips are cached (trips whose `end_date` is today or later, or has no end date). +- Trips that ended more than 7 days ago are automatically evicted from IndexedDB on the next sync. + +## Offline Cache (Settings → Offline) + +The **Offline Cache** section under Settings → Offline shows the current state of the local cache. + + + +**Stats panel:** +- **Cached trips** — number of trips stored in IndexedDB (Dexie). +- **Pending changes** — number of actions taken offline that are queued to sync. + +**Actions:** +- **Re-sync now** — forces a full sync with the server. Disabled when you are offline. +- **Clear cache** — removes all offline trip data from IndexedDB. You can re-sync any time while online. + +Each cached trip entry shows the trip name, date range, place count, and file count, plus the time of the last successful sync. + +## Limitations + +- New trips created while offline are queued and synced when connectivity is restored. +- Photo uploads require connectivity; non-photo file attachments are pre-cached automatically during sync. +- Real-time collaboration features require an active WebSocket connection. +- Mapbox GL tiles are not cached by the service worker (Mapbox manages its own tile cache internally). + +## See also + +- [User-Settings](User-Settings) +- [Display-Settings](Display-Settings) diff --git a/wiki/PDF-Export.md b/wiki/PDF-Export.md new file mode 100644 index 00000000..6378de3e --- /dev/null +++ b/wiki/PDF-Export.md @@ -0,0 +1,98 @@ +# PDF Export + +TREK can generate two kinds of PDFs from your trip data: a structured **Trip Plan PDF** and a photo-book-style **Journey Book PDF**. Both render as HTML in a sandboxed iframe and open the browser's native print/save dialog — no server-side processing is involved. + + + +![PDF Export](assets/PDFTrip.png) + +--- + +## Trip Plan PDF + +### How to generate + +Open the Day Plan sidebar in the trip planner. Click the **PDF** button in the toolbar at the top of the sidebar. A preview modal opens immediately; click **Save as PDF** to open your browser's print dialog and save the file. + +### Cover page + +- Blurred cover image as background (if the trip has one), with the same image in a circular badge +- Trip title and description +- Date range (first day to last day) +- Stat tiles: + - **Days** — total number of days in the trip + - **Places** — total places in your trip's place list + - **Planned** — number of unique places assigned to at least one day + - **Estimated cost** — sum of all assigned place prices in EUR (hidden if zero) + +### Per-day pages + +Each day starts on a new page with a dark header bar showing the day number, day title, date, and the day's estimated cost. + +Below the header: + +- **Accommodation block** (if an accommodation covers that day): action label (Check-in on the first day, Check-out on the last day, or Accommodation for intermediate days), time, place name, address, notes, and confirmation code (only shown on the check-in day) +- **Timeline items** sorted by their order in the day plan: + - **Places** — thumbnail (or a colored category icon if no image is available), numbered badge, name, category label, address, description, time, price, and notes + - **Notes** — icon, text, and optional time + - **Reservations** — type icon, title, time, type-specific metadata (e.g. airline + flight number + route for flights; train number + platform + seat for trains; party size for restaurants; venue for events; operator for tours), location, and confirmation code + +### Footer + +Every printed page carries a small "made with TREK" logo at the bottom. + +### Font + +Poppins, loaded from Google Fonts at render time. + +--- + +## Journey Book PDF + +### How to generate + +Open a Journey entry in the Travel Journal. Click the **download icon** button in the journal's header area. A preview modal opens; click **Save as PDF** to print. + +![Journey Book PDF Preview](assets/PDFJourney.png) + +### Format + +A4 landscape (`@page { size: A4 landscape; margin: 0 }`). Font: Inter, loaded from Google Fonts. + +### Cover page + +- Hero image (journey cover image, or the first entry photo if none is set) +- Journey title and optional subtitle +- Stat tiles: Days, Entries, Photos + +### Entry pages + +One page per journal entry, in chronological order. The first entry of each date carries a day header (day number and full date) above the content. + +Photo layout adapts to the number of photos on the entry: + +| Photos | Layout | +|--------|--------| +| 1 | Single image, full width | +| 2 | Two images side by side | +| 3 or more | Large hero image on the left, two stacked images on the right | + +Below the photos: entry time and location, entry title, journal text (rendered from Markdown), and pros/cons verdict cards if present. + +### Closing page + +A dark "The End" card. + +--- + +## How rendering works + +Both PDFs use the same mechanism: the HTML document is written into a sandboxed `