Merge pull request #748 from mauriceboe/docs/wiki

Docs/wiki
This commit is contained in:
Julien G.
2026-04-20 16:50:50 +02:00
committed by GitHub
118 changed files with 5589 additions and 7 deletions
+2
View File
@@ -6,6 +6,8 @@ on:
paths-ignore:
- 'docs/**'
- '**/*.md'
- 'wiki/**'
- '.github/workflows/wiki.yml'
workflow_dispatch:
inputs:
bump:
+26
View File
@@ -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
+35 -4
View File
@@ -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();
+10 -3
View File
@@ -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<string, unknown> {
const rows = db.prepare('SELECT key, value FROM settings WHERE user_id = ?').all(userId) as { key: string; value: string }[];
const userSettings: Record<string, unknown> = {};
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 {
+54
View File
@@ -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.
<!-- TODO: screenshot: accommodation list showing check-in/check-out details -->
## 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)
+34
View File
@@ -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.
+70
View File
@@ -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.
<!-- TODO: screenshot: addon toggle switches in admin panel -->
![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)
+47
View File
@@ -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.
<!-- TODO: screenshot: category list in admin panel -->
![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)
+50
View File
@@ -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.
<!-- TODO: screenshot: GitHub releases panel with release timeline -->
![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)
+48
View File
@@ -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.
<!-- TODO: screenshot: OAuth client and token list in MCP Access 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)
+65
View File
@@ -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.
<!-- TODO: screenshot: packing templates admin list with categories and items -->
![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)
+39
View File
@@ -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.
<!-- TODO: screenshot: admin panel main dashboard with tabs -->
![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)
+76
View File
@@ -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.
<!-- TODO: screenshot: permissions matrix with role dropdowns -->
![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)
+90
View File
@@ -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.
<!-- TODO: screenshot: users table with invite form -->
![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:
```
<APP_URL>/register?invite=<token>
```
### 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)
+55
View File
@@ -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).
<!-- TODO: screenshot: world map with visited countries highlighted -->
![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)
+138
View File
@@ -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.
<!-- TODO: screenshot: audit log table with action entries -->
![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)
+88
View File
@@ -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.
<!-- TODO: screenshot: backup tab with backup list and auto-backup settings -->
![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 (023).
- **Day of week** — Sunday through Saturday (for weekly backups).
- **Day of month** — 128 (for monthly backups). Day 2931 is excluded to avoid months with fewer days.
Auto-backup files are named `auto-backup-<timestamp>.zip` (manual backups use `backup-<timestamp>.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)
+83
View File
@@ -0,0 +1,83 @@
# Budget Tracking
Track trip expenses by category, split costs between members, and visualize spending.
<!-- TODO: screenshot: budget summary and expense list -->
![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)
+59
View File
@@ -0,0 +1,59 @@
# Collab Chat
Chat with your group in real time, without leaving the trip planner.
<!-- TODO: screenshot: chat panel with messages and reactions -->
![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 13 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)
+72
View File
@@ -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.
<!-- TODO: screenshot: collab notes editor with categories -->
![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)
+61
View File
@@ -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.
<!-- TODO: screenshot: poll with options and vote counts -->
![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)
+71
View File
@@ -0,0 +1,71 @@
# Creating a Trip
<!-- TODO: screenshot: trip creation form with date and cover fields -->
![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 | 130 (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)
+62
View File
@@ -0,0 +1,62 @@
# Dashboard Widgets
The My Trips dashboard includes two utility widgets: a currency converter and a timezone clock.
<!-- TODO: screenshot: widget gallery showing currency converter and 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)
+73
View File
@@ -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.
<!-- TODO: screenshot: itinerary view with assigned places and day notes -->
![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)
+62
View File
@@ -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.
<!-- TODO: screenshot: demo mode banner or try-demo button on login page -->
## 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)
+56
View File
@@ -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.
<!-- TODO: screenshot: appearance settings panel -->
![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)
+76
View File
@@ -0,0 +1,76 @@
# Documents and Files
Attach and manage documents, tickets, and other files for your trip.
<!-- TODO: screenshot: file attachment list with filter tabs -->
![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)
+85
View File
@@ -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)
+135
View File
@@ -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 <noreply@example.com>`) | — |
| `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
+42
View File
@@ -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).
+60
View File
@@ -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 |
+120
View File
@@ -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=<output of: openssl rand -hex 32>
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
+76
View File
@@ -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=<your-32-byte-hex-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
+195
View File
@@ -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=<your-secure-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
+73
View File
@@ -0,0 +1,73 @@
# Install: Unraid
Install TREK on Unraid via Community Applications or a direct template import.
<!-- TODO: screenshot: Unraid container template settings -->
## 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://<unraid-ip>:<port>
```
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
+56
View File
@@ -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)
+35
View File
@@ -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.
<!-- TODO: screenshot: invite link management form -->
![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=<token>` 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)
+61
View File
@@ -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).
<!-- TODO: screenshot: journal entries view with photos and mood indicators -->
![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)
+51
View File
@@ -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)
+77
View File
@@ -0,0 +1,77 @@
# Login and Registration
<!-- TODO: screenshot: login form with email and password fields -->
## 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.
If you have forgotten your password, click the **"Forgot password?"** link below the password field to start the self-service reset flow. See [Password-Reset](Password-Reset) for details.
### 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.
Forgot-password requests are rate-limited to **3 attempts per 15-minute window** per IP. Reset-password submissions are limited to **5 attempts per 15-minute window** per IP.
## 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) · [Password-Reset](Password-Reset)
+176
View File
@@ -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)
+49
View File
@@ -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 userclient pair, so each OAuth client has its own independent window. Sessions expire after 1 hour of inactivity.
## Endpoint
```
https://<your-trek-instance>/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
+27
View File
@@ -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)
+67
View File
@@ -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)
+141
View File
@@ -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).
<!-- TODO: screenshot: OAuth client registration form -->
![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://<your-trek-instance>/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://<your-trek-instance>/mcp",
"--static-oauth-client-info",
"{\"client_id\": \"<your_client_id>\", \"client_secret\": \"<your_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://<your-trek-instance>/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://<your-trek-instance>/mcp",
"--static-oauth-client-info",
"{\"client_id\": \"<your_client_id>\", \"client_secret\": \"<your_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://<your-trek-instance>/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)
+197
View File
@@ -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)
+70
View File
@@ -0,0 +1,70 @@
# Map Features
The trip planner map shows your places, route lines, transport overlays, and your current location in real time.
<!-- TODO: screenshot: trip map with place markers and route lines -->
![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)
+84
View File
@@ -0,0 +1,84 @@
# 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.
<!-- TODO: screenshot: map settings panel with provider selection -->
![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://console.mapbox.com/account/access-tokens/).
Required scopes are:
- STYLES:TILES
- STYLES:READ
- FONTS:READ
- DATASETS:READ
- VISION:READ
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)
+66
View File
@@ -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.
<!-- TODO: screenshot: trips grid with spotlight card -->
![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)
+88
View File
@@ -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.
<!-- TODO: screenshot: notifications panel or bell dropdown -->
![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)
+79
View File
@@ -0,0 +1,79 @@
# OIDC / Single Sign-On
<!-- TODO: screenshot: OIDC provider configuration form in admin panel -->
## 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=<code>`. The frontend immediately exchanges that code at `GET /api/auth/oidc/exchange?code=<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:
```
<APP_URL>/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 `<OIDC_ISSUER>/.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=<token>` when initiating SSO login (e.g. `GET /api/auth/oidc/login?invite=<token>`).
- **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)
+76
View File
@@ -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 1016 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.
<!-- TODO: screenshot: Offline tab showing cached trips -->
**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)
+98
View File
@@ -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.
<!-- TODO: screenshot: export options dialog or PDF preview modal -->
![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 `<iframe>` via `srcdoc`, and `iframe.contentWindow.print()` opens the browser's print dialog. There is no server-side PDF generation. The file is saved through the browser's built-in "Save as PDF" print destination.
---
## See also
- [Day-Plans-and-Notes](Day-Plans-and-Notes)
- [Journey-Journal](Journey-Journal)
- [Trip-Planner-Overview](Trip-Planner-Overview)
+92
View File
@@ -0,0 +1,92 @@
# Packing Lists
Create categorized packing checklists with member assignments and optional bag tracking.
<!-- TODO: screenshot: packing list with checked items and categories -->
![Packing Lists](assets/PackingList.png)
## Where to find it
Open the **Lists** tab inside the trip planner and select **Packing**. The tab is only visible when the Packing addon is enabled.
> **Admin:** Enable the Packing addon and optionally turn on Bag Tracking in [Admin-Addons](Admin-Addons).
## Progress bar
A progress bar shows how many items have been checked (packed) out of the total. It is hidden on small screens and visible on larger viewports. When all items are checked, a completion message replaces the bar.
## Filters
Three filter buttons let you narrow the item view:
- **All** — every item regardless of checked state.
- **Open** — unchecked items only.
- **Done** — checked items only.
## Categories
Items are grouped into categories. Each category has a colored dot that cycles through a 10-color palette. When you create a new packing list, suggested items are pre-populated in these categories: **Documents** (Passport, Travel Insurance, Visa Documents, Flight Tickets, Hotel Bookings, Vaccination Card), **Clothing** (T-Shirts (5x), Pants (2x), Underwear (7x), Socks (7x), Jacket, Swimwear, Sport Shoes), **Toiletries** (Toothbrush, Toothpaste, Shampoo, Sunscreen, Deodorant, Razor), **Electronics** (Phone Charger, Travel Adapter, Headphones, Camera, Power Bank), **Health** (First Aid Kit, Prescription Medication, Pain Medication, Insect Repellent), and **Finances** (Cash, Credit Card).
Each category header has a collapse/expand toggle and an overflow menu with these actions:
- **Check all** — mark every item in the category as packed.
- **Uncheck all** — unmark every item in the category.
- **Rename** — rename the category.
- **Delete** — delete the category and all its items.
### Assigning members to a category
Use the people-picker chip row in the category header to assign trip members to that category. Assigned members receive a packing notification. See [Notifications](Notifications) for details.
## Items
Each item row contains:
- A **checkbox** to mark the item packed.
- An editable **name** (click to rename; renaming is disabled while an item is checked).
- A **quantity** field (always visible).
- When bag tracking is enabled: a **weight** field (in grams) and a **bag picker**.
Hovering over an item reveals a **category picker** (colored dot), a **rename** button (pencil icon), and a **delete** button. Add new items using the inline "add item" row at the bottom of each category.
## Bag tracking
Bag tracking is only available when an admin has enabled it.
> **Admin:** Turn on Bag Tracking in [Admin-Addons](Admin-Addons).
When enabled, a **Bags** panel appears as a right-hand sidebar on wide screens, or as a modal sheet on narrow screens (tap the **Bags** button in the header to open it). Each bag shows:
- Name and color dot.
- Total weight and a weight-limit progress bar (if a limit is set).
- Member avatars assigned to that bag.
- Item count.
The sidebar also shows an **unassigned** section for items that have no bag, and a **total weight** line summing all items.
To use bags:
1. Click **+ Add bag** to create a bag with a name and color.
2. Assign items to a bag using the bag picker on each item row (visible when bag tracking is enabled).
3. Assign members to a bag using the member chip row on the bag card.
## Templates
You can save and reuse packing lists across trips:
- **Save as Template** — click the **Save as Template** button in the header (visible when the list has items) to save the current list's items and categories as a named template.
- **Apply Template** — if templates exist, an **Apply Template** dropdown appears in the header. Selecting a template appends its items to the current list without removing existing items.
Templates are managed by admins in [Admin-Packing-Templates](Admin-Packing-Templates).
## Permissions
All write operations require the `packing_edit` permission.
## See also
- [Packing-Templates](Packing-Templates)
- [Admin-Addons](Admin-Addons)
- [Notifications](Notifications)
- [Trip-Planner-Overview](Trip-Planner-Overview)
+30
View File
@@ -0,0 +1,30 @@
# Packing Templates
Reuse packing lists across trips using pre-built templates.
<!-- TODO: screenshot: packing template list with categories and items -->
![Packing Templates](assets/PackingTemplate.png)
## Applying a template
In the Packing Lists panel, click the **Apply Template** button (shown with a package icon in the toolbar). A dropdown lists all available templates, each showing its name and item count. Click a template to apply it.
Applying a template copies all categories and items from the template into the current trip's packing list — existing items are not removed. Items are inserted with the same category names as defined in the template, so they appear alongside any existing items that share the same category name.
Requires the `packing_edit` permission.
The Apply Template button only appears when at least one template exists and you have edit permission.
## Saving the current list as a template
In the packing panel toolbar, click the **Save as template** button (folder-plus icon) when items exist in the list. An inline name input appears in the toolbar — type a name and press **Enter** or click the confirm button. The current trip's categories and items are saved as a new reusable template.
The Save as Template button only appears when there are items in the list and you have `packing_edit` permission.
> **Admin:** Templates are created and managed in [Admin-Packing-Templates](Admin-Packing-Templates). Each template has a three-level structure: template → categories → items.
## See also
- [Packing-Lists](Packing-Lists)
- [Admin-Packing-Templates](Admin-Packing-Templates)
+69
View File
@@ -0,0 +1,69 @@
# Password Reset
## Self-service reset (Forgot password?)
TREK supports email-based self-service password reset. On the login page, click the **"Forgot password?"** link to go to `/forgot-password`. Enter your email address and submit — if the address matches a local account, a reset link is sent to that inbox. The page always shows the same confirmation message regardless of whether the email was found, to prevent account enumeration.
> **No SMTP configured?** When the server has no SMTP credentials set up, the reset link is not emailed. Instead, it is printed to the **server console** inside a clearly-fenced block so a self-hoster can copy and relay it manually. The forgot-password page also shows a visible hint that SMTP is unconfigured.
### Reset flow
1. Click **"Forgot password?"** on the login page.
2. Enter your email address and submit.
3. Open the reset link from your email (or console) — valid for **60 minutes**.
4. Enter a new password. If your account has **MFA enabled**, you must also supply a valid TOTP code or backup code before the reset completes.
5. After a successful reset you are redirected to login. **All existing sessions are invalidated** — every device is signed out immediately.
### Security properties
| Property | Detail |
|---|---|
| Token entropy | 256-bit cryptographically random, base64url-encoded |
| Storage | Only the SHA-256 hash is stored in the database — never the raw token |
| Expiry | 60 minutes, single-use; any prior unconsumed token is invalidated when a new one is issued |
| Enumeration safety | `/forgot-password` always returns `{ok:true}` with a minimum response latency pad |
| Rate limiting | 3 requests / 15-min per IP on `/forgot-password`; 5 requests / 15-min per IP on `/reset-password` |
| MFA gate | If the account has 2FA enabled, a valid TOTP code or backup code is required to complete the reset — a compromised mailbox alone cannot take over a 2FA-protected account |
| Session invalidation | Resetting the password bumps the `password_version` on the account and the `pv` claim in all JWTs, which immediately rejects every live session |
| Audit log | `user.password_reset_request`, `user.password_reset_success`, and `user.password_reset_fail` events are recorded |
### SMTP requirement
The email delivery uses the same SMTP settings as other notification emails. See [Environment-Variables](Environment-Variables) for `SMTP_*` configuration.
### OIDC accounts
Accounts that signed up via SSO and have no local password set cannot use the forgot-password flow — there is no local password to reset. The forgot-password page still shows the generic confirmation to avoid revealing whether the email is OIDC-only. Continue using [OIDC-SSO](OIDC-SSO) to sign in.
### Password login disabled
If the admin has globally disabled password login, the forgot-password endpoint returns an error and the flow is unavailable.
## Admin-initiated reset
An admin can set a new password for any user directly from the admin panel (**Admin → Users**). The admin enters a new password for the account, which is saved immediately — no email is required. The admin can also enable the **"Force password change on next login"** flag so the user is prompted to choose their own password the next time they sign in.
See [Admin-Users-and-Invites](Admin-Users-and-Invites) for step-by-step instructions.
## Password requirements
When choosing a new password (whether via the reset flow, the forced-change prompt, or the normal **Settings → Security** page) the password must:
- Be at least **8 characters** long
- Contain at least one **uppercase letter**
- Contain at least one **lowercase letter**
- Contain at least one **number**
- Contain at least one **special character**
- Not be a commonly used password
## Rate limiting
| Endpoint | Limit |
|---|---|
| `/auth/forgot-password` | 3 requests / 15-min per IP |
| `/auth/reset-password` | 5 requests / 15-min per IP |
| Password change (settings) | Rate-limited per IP |
---
**See also:** [Login-and-Registration](Login-and-Registration) · [Admin-Users-and-Invites](Admin-Users-and-Invites) · [Two-Factor-Authentication](Two-Factor-Authentication) · [OIDC-SSO](OIDC-SSO)
+71
View File
@@ -0,0 +1,71 @@
# Photo Providers
TREK can browse your personal photo library on Immich or Synology Photos and attach selected photos to trips. TREK never copies the original files — it stores only a reference (provider name + asset ID) and proxies all image streams through its own server, so your provider credentials are never sent to the browser.
> **Admin:** Two things must be enabled for photo providers to appear in Settings: the **Memories addon** and the **individual photo provider** (Immich or Synology Photos). Both are toggled separately in **Admin → Addons**. See [Admin-Addons](Admin-Addons). If your provider is on a local or private network, the server must be configured to allow internal network access. See [Internal-Network-Access](Internal-Network-Access).
---
## Supported providers
| Provider | Internal ID |
|----------|-------------|
| Immich | `immich` |
| Synology Photos | `synologyphotos` |
Both providers can be active at the same time.
---
## Configuring a provider
Go to **Settings → Integrations → Photo Providers**. Each enabled provider shows its own settings section.
<!-- TODO: screenshot: Photo Providers section in Settings > Integrations -->
### Immich
| Field | Required | Notes |
|-------|----------|-------|
| Server URL | Yes | Full URL of your Immich instance, e.g. `https://immich.example.com` |
| API Key | Yes | Stored encrypted; never returned to the browser after saving |
| Auto-upload to Immich | No | Checkbox; when enabled, photos you upload in TREK are also pushed to your Immich library |
Enter the full URL of your Immich instance and an Immich API key. The API key is stored encrypted on the TREK server and is never returned to the browser after it is saved.
### Synology Photos
| Field | Required | Notes |
|-------|----------|-------|
| Server URL | Yes | Full URL including the Photos app path, e.g. `https://your-nas:5001/photo` |
| Username | Yes | Synology account username |
| Password | Yes | Stored encrypted; leave blank to keep the existing password |
| OTP code | No | One-time password for 2FA; only needed on first connection or when re-authenticating |
| Skip SSL verification | No | Checkbox; disable TLS certificate validation for self-signed certificates |
---
## Testing the connection
Each provider section has a **Test Connection** button. Clicking it sends your current field values to the server and attempts to authenticate with the provider. A green "Connected" badge confirms success; any error message from the provider is shown if it fails.
For Synology, a successful test stores a session token so the OTP code is not required again on subsequent saves (as long as the URL and username remain the same).
---
## Multiple providers
You can configure both Immich and Synology simultaneously. TREK queries photos from all enabled providers when loading trip photos.
---
## After setup
Once a provider is connected, you can browse and attach photos to your trips. See [Documents-and-Files](Documents-and-Files) for how to manage files after setup.
---
## See also
- [Admin-Addons](Admin-Addons)
- [Internal-Network-Access](Internal-Network-Access)
+60
View File
@@ -0,0 +1,60 @@
# Places and Search
Places are the building blocks of your trip. You can add them by searching, pasting a URL, entering coordinates, or importing a file.
![Places sidebar](assets/PlaceAutocomplete.png)
## Adding a place
Click **+ Add Place** at the top of the Places sidebar to open the Place form. You can also **right-click anywhere on the map** to create a place at that exact location — the address is reverse-geocoded and pre-filled automatically.
## Searching for a place
Type in the search box at the top of the form. After 2 or more characters, with a 300 ms debounce, suggestions appear in a dropdown.
- Use **↑ / ↓** to navigate results, **Enter** to select, **Esc** to dismiss.
- Search results are biased toward the geographic center of your existing trip places. When those places span more than ~500 km, the bias is skipped.
### With a Google Maps API key
> **Admin:** A Google Maps API key is configured in [User-Settings](User-Settings).
When a key is present, the autocomplete uses the Google Places API, which can return ratings, opening hours, photos, and phone numbers from Google's database.
### Without a Google Maps API key
TREK falls back to OpenStreetMap (Nominatim) automatically — no API key needed. A notice appears above the search box explaining that OpenStreetMap is in use and that photos, ratings, and opening hours are unavailable. Results include name, address, and coordinates.
## Pasting a Google Maps URL
Paste a `maps.app.goo.gl/…`, `goo.gl/maps/…`, or `maps.google.*/…` URL directly into the search box and press the search button. TREK resolves it server-side and populates the name, address, and coordinates.
## Entering coordinates manually
Type or paste a `lat, lng` pair (e.g. `48.8566, 2.3522`) into the **Latitude** field. TREK detects the comma-separated pair and fills both coordinate fields at once.
## Place fields
<!-- TODO: screenshot: Place form with all fields visible -->
| Field | Notes |
|---|---|
| Name | Required |
| Description | Free text |
| Notes | Free text, max 2 000 characters |
| Address | Free text |
| Latitude / Longitude | Decimal degrees |
| Category | Pick an existing category or type a new name to create one inline (default color `#6366f1`, icon `MapPin`) |
| Start time / End time | Shown only when editing an existing place |
| Website | URL |
| File attachments | Images or PDFs — click the Paperclip icon or paste from the clipboard |
Two inline warnings are shown when editing times: one if the end time is set to a value before or equal to the start time, and one if the times overlap with another place already assigned to the same day.
## Importing multiple places
Drag a `.gpx`, `.kml`, or `.kmz` file onto the Places sidebar to import all waypoints or features at once. You can also import a saved-list share URL using the **Import list** button in the sidebar header — both Google Maps and Naver Maps list URLs are supported.
> **Admin:** Google Maps API key is set in [User-Settings](User-Settings). Without it, OSM search is used automatically.
**See also:** [Day-Plans-and-Notes](Day-Plans-and-Notes) · [Map-Features](Map-Features) · [Tags-and-Categories](Tags-and-Categories)
+55
View File
@@ -0,0 +1,55 @@
# Public Share Links
Share a read-only view of your trip with people who do not have a TREK account. The viewer opens in a browser without logging in.
<!-- TODO: screenshot: share link creation form with permission toggles -->
![Public share link](assets/Share.png)
## Creating a share link
Open your trip and click the **Share** button (Users icon) in the top navbar. This opens the Members & Share modal. The share link section appears on the right side of the modal and is visible only to users with the `share_manage` permission (trip owner and admins by default).
Click **Create link** to generate a token.
The share URL takes the form:
```
<your-instance>/shared/<token>
```
Copy this URL and send it to anyone you want to share the trip with. No TREK account is required to view it.
## Permission toggles
When creating or updating a share link you choose what the recipient can see. The available flags are:
| Toggle | Default | What it shows |
|--------|---------|---------------|
| **Map** | Always on | The Plan tab with the interactive map and day-by-day itinerary. This toggle is locked on and cannot be disabled from the UI. |
| **Bookings** (`share_bookings`) | **On** | The Bookings tab with reservations and transport. Also controls whether transport items appear inline in the day plan. |
| **Packing** (`share_packing`) | Off | The packing list tab, grouped by category |
| **Budget** (`share_budget`) | Off | The Budget tab with a total summary and line items grouped by category |
| **Collab** (`share_collab`) | Off | A read-only Chat tab showing messages in chronological order |
Disabled toggles hide the corresponding tab from the public viewer entirely. Permission changes take effect immediately — you do not need to recreate the link.
## What the public viewer shows
The shared trip page renders a branded read-only interface with a dark hero header showing the trip title, description, and date range. A tab bar at the top provides access to the sections you enabled. The viewer can switch the display language using a language picker in the top-right corner.
The Plan tab is always available and shows an interactive map, a collapsible day-by-day itinerary (with places, notes, and transport inline when Bookings is enabled), and accommodation badges per day.
The Collab tab (when enabled via `share_collab`) shows chat messages grouped by date with sender avatars. Viewers cannot send messages.
## Revoking a share link
Open the Share button in the navbar, then click **Delete link** in the share link section. The existing URL stops working immediately for anyone who has it.
## Journey public share
The Travel Journal (Journey addon) has a separate share mechanism with its own token namespace and permission flags (timeline, gallery, map). See [Journey-Journal](Journey-Journal) for details.
## Related pages
[Trip-Members-and-Sharing](Trip-Members-and-Sharing) · [Journey-Journal](Journey-Journal) · [Real-Time-Collaboration](Real-Time-Collaboration)
+66
View File
@@ -0,0 +1,66 @@
# Quick Start
Get TREK running in under five minutes with a single Docker command.
![Login page](assets/Login.png)
## Prerequisites
- Docker installed and running on your machine
- Port `3000` available (or choose a different host port)
## Run TREK
Generate an encryption key and start the container in one step:
```bash
ENCRYPTION_KEY=$(openssl rand -hex 32) docker run -d \
--name trek \
-p 3000:3000 \
-e ENCRYPTION_KEY=$ENCRYPTION_KEY \
-v ./data:/app/data \
-v ./uploads:/app/uploads \
--restart unless-stopped \
mauriceboe/trek:latest
```
**Flag breakdown:**
| Flag | Purpose |
|---|---|
| `-d` | Run in the background |
| `-p 3000:3000` | Map container port 3000 to host port 3000 |
| `-e ENCRYPTION_KEY=...` | At-rest encryption key for stored secrets |
| `-v ./data:/app/data` | Persist the database and secrets |
| `-v ./uploads:/app/uploads` | Persist uploaded files |
| `--restart unless-stopped` | Auto-restart on reboot |
**Why the encryption key?** TREK encrypts stored secrets (API keys, MFA seeds, OIDC credentials) using this key. If you skip it, TREK auto-generates one and saves it to `./data/.encryption_key`. Setting it explicitly means you control the key and can back it up separately.
Generate a standalone key at any time:
```bash
openssl rand -hex 32
```
## Access TREK
Open `http://localhost:3000` in your browser.
## First User
On first boot TREK automatically seeds an admin account before any user registers. The credentials depend on how you start the container:
- **With `ADMIN_EMAIL` and `ADMIN_PASSWORD` env vars set:** those values are used directly.
- **Without those env vars:** TREK creates the account with email `admin@trek.local`, username `admin`, and a randomly generated password. The credentials are printed to the container log — run `docker logs trek` to retrieve them.
You will be prompted to change the password on first login.
> **Admin:** As admin you unlock the Admin Panel — user management, addon toggles, packing templates, backups, and API key configuration.
## Next Steps
- [Install-Docker-Compose] — production setup with security hardening
- [Reverse-Proxy] — put TREK behind HTTPS (required for PWA install and secure cookies)
- [Environment-Variables] — full configuration reference
- [Admin-Panel-Overview] — explore what the admin panel can do
+55
View File
@@ -0,0 +1,55 @@
# Real-Time Collaboration
TREK keeps every trip in sync across all connected members without requiring a page refresh. A dedicated **Collab addon** adds a second layer on top of that sync: group chat, shared notes, polls, and a "What's Next" widget showing upcoming assigned places.
<!-- TODO: screenshot: collaborative editing with presence indicators -->
## Real-time sync
All changes to a trip — places, day plans, reservations, budget entries, and packing lists — are broadcast instantly to every connected member via WebSocket. You see other people's edits as they happen.
## WebSocket transport
| Parameter | Value |
|-----------|-------|
| Path | `/ws` |
| Scope | One room per trip |
| Rate limit | 30 messages per 10-second window |
| Max payload | 64 KB per message |
| Heartbeat | Ping every 30 seconds; sockets that miss a pong are terminated |
**Authentication** uses a short-lived ephemeral token passed as a query parameter on connect. If authentication fails, the server closes the connection with one of these codes:
- **4001** — missing, invalid, or expired token; user not found
- **4403** — site-wide MFA is required but the account does not have MFA enabled
## The Collab addon
The Collab addon (`collab`) must be enabled by an admin before the panel is visible inside a trip. Once enabled, it provides four sub-features that can each be toggled independently:
| Sub-feature | What it provides |
|-------------|-----------------|
| **Chat** | Group chat with reactions, replies, and URL previews |
| **Notes** | Categorized, pinnable, markdown-formatted shared notes |
| **Polls** | Single- or multiple-choice votes with optional deadlines |
| **What's Next** | Upcoming assigned places across all trip days |
> **Admin:** enable the Collab addon and individual sub-features in [Admin-Addons](Admin-Addons).
On **desktop** the panel shows Chat as a fixed 380 px column on the left when other sub-features are also enabled; if only Chat is on, it expands to fill the full width. Notes, Polls, and What's Next share the remaining space on the right. On **mobile** a tab bar at the top lets you switch between the enabled sub-features one at a time. Disabled sub-features are hidden from the tab bar.
## Conflict handling
TREK uses a **last-write-wins** model. Each mutation is applied on the server and the resulting canonical state is broadcast to all connected clients. If two members edit the same field at the same time, the change that reaches the server last is the one that sticks; all clients converge to that server-authoritative state.
On reconnect, any locally queued mutations are flushed to the server before the client re-fetches trip data, so offline changes are applied before the latest state is read back.
There is no operational-transform or CRDT merge — simultaneous edits to the same field are not merged; one silently wins.
## Access control
All Collab reads require trip membership. Writing — sending messages, creating notes, creating polls, voting — requires the `collab_edit` permission. Members without `collab_edit` can read but cannot post or interact.
## Related pages
[Collab-Chat](Collab-Chat) · [Collab-Notes](Collab-Notes) · [Collab-Polls](Collab-Polls) · [Whats-Next-Widget](Whats-Next-Widget) · [Trip-Planner-Overview](Trip-Planner-Overview) · [Admin-Addons](Admin-Addons)
+89
View File
@@ -0,0 +1,89 @@
# Reservations & Bookings
Track all your trip bookings — hotels, restaurants, events, tours, and more — in one place.
## Where to find it
Open your trip in the planner and select the **Reservations** tab. The panel lists all bookings grouped by status, with a type filter bar at the top.
![Reservations panel](assets/Bookings.png)
## Reservation types
TREK supports nine reservation types:
| Type | How to create |
|------|--------------|
| Flight | [Transport modal](Transport-Flights-Trains-Cars) |
| Train | [Transport modal](Transport-Flights-Trains-Cars) |
| Car | [Transport modal](Transport-Flights-Trains-Cars) |
| Cruise | [Transport modal](Transport-Flights-Trains-Cars) |
| Hotel | Add button in Reservations panel — see [Accommodations](Accommodations) |
| Restaurant | Add button in Reservations panel |
| Event | Add button in Reservations panel |
| Tour | Add button in Reservations panel |
| Other | Add button in Reservations panel |
Transport types (Flight, Train, Car, Cruise) are created through the dedicated Transport modal, where you can enter endpoint and transit-specific fields. All other types are created directly from the Reservations panel.
## Pending and Confirmed
Reservations are grouped into two collapsible sections: **Pending** and **Confirmed**. You can collapse or expand each section independently — the open/closed state is saved per trip so it persists across page reloads. Status is set when you create or edit a reservation.
On desktop, a type filter bar lets you show only specific types. Filter selections are kept for the current browser session.
## Reservation card contents
Each card displays:
- **Status dot** — green for Confirmed, amber for Pending
- **Type chip** — icon and label for the reservation type
- **Needs review badge** — an amber badge shown on reservations flagged by importers that may need your attention
- **Title** — the reservation name
- **Edit and delete buttons** — visible only if you have edit permission
> **Admin:** Edit and delete buttons are gated by the `reservation_edit` permission. Members without this permission see read-only cards.
- **Date and time range** — start date, and end date/time if set
- **From → To** — origin and destination endpoints, shown for transport types
- **Confirmation code** — displayed in monospace. If you have **Blur booking codes** enabled in Display Settings, the code is blurred by default and revealed on hover or tap
- **Type-specific metadata:**
- Flights: airline name, flight number
- Trains: train number, platform, seat
- Hotels: check-in window, check-out time (see [Accommodations](Accommodations))
- **Location / address** — for non-hotel, non-transport types
- **Linked accommodation** — hotel name, if this reservation is linked to an accommodation record
- **Day-plan assignment** — the day and place this reservation is linked to
- **Notes**
- **Attached files** — shown as clickable download links
## Creating a reservation
Click **Add** (or the + button) in the Reservations panel. Fill in the form:
1. **Type** — choose Hotel, Restaurant, Event, Tour, or Other
2. **Title** — required
3. **Link to day-plan assignment** — optional; search across all days and places, grouped by day. Not available for Hotel type
4. **Start date and time** — not shown for Hotel type
5. **End date and time** — not shown for Hotel type
6. **Location / address** — not shown for Hotel type
7. **Confirmation code**
8. **Status** — Pending or Confirmed
9. **Hotel-specific fields** — shown only for Hotel type, immediately after status: hotel place, check-in day, check-out day, check-in time (window start and end), and check-out time. See [Accommodations](Accommodations)
10. **Notes**
11. **Files** — attach from your device (PDF, Word documents, text files, images) or link an existing trip file. Files added before saving are uploaded automatically after the reservation is created
12. **Price and budget category** — shown only when the Budget addon is enabled. Entering a price greater than zero automatically creates a linked budget entry. See [Budget-Tracking](Budget-Tracking)
<!-- TODO: screenshot: Create Reservation modal -->
## Editing and deleting
Each card has a pencil icon to open the edit form and a trash icon to delete. Deleting requires confirmation in a dialog before the record is removed.
## Real-time sync
Reservation changes (create, update, delete) are broadcast instantly to all connected trip members via WebSocket, so everyone sees the latest state without refreshing.
---
**See also:** [Transport-Flights-Trains-Cars](Transport-Flights-Trains-Cars) · [Accommodations](Accommodations) · [Budget-Tracking](Budget-Tracking) · [Documents-and-Files](Documents-and-Files) · [Trip-Planner-Overview](Trip-Planner-Overview)
+106
View File
@@ -0,0 +1,106 @@
# Reverse Proxy
Putting TREK behind a TLS-terminating reverse proxy is strongly recommended for production.
## Why HTTPS Matters for TREK
- **PWA install** requires HTTPS — browsers block "Add to Home Screen" on plain HTTP.
- **Session cookies** — the `trek_session` cookie is marked `secure` in production, so it won't be sent over HTTP.
- **OIDC / SSO** — identity providers require the redirect URI to use HTTPS.
- **MCP** — the MCP API requires HTTPS for OAuth 2.1 auth.
## Two Hard Requirements
Whatever proxy you use, it must satisfy two constraints:
1. **WebSocket upgrades on `/ws`** — TREK uses WebSockets for real-time sync. Set `proxy_read_timeout 86400` (Nginx) or rely on Caddy's automatic upgrade handling.
2. **Body size ≥ 500 MB** — backup restore ZIPs can include the full uploads directory. Set `client_max_body_size 500m` (Nginx) or `request_body_max_size 500mb` (Caddy) if you restore large backups.
## Nginx
```nginx
server {
listen 80;
server_name trek.yourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name trek.yourdomain.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
location /ws {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 86400;
# File uploads are capped at 50 MB; backup restore ZIPs can include the full
# uploads directory and may exceed that — raise this value if restores fail.
client_max_body_size 500m;
}
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Needed for backup restore uploads — can exceed the Nginx default of 1 MB.
client_max_body_size 500m;
}
}
```
Key lines:
- `proxy_read_timeout 86400` — keeps WebSocket connections alive (86400 s = 24 h).
- `client_max_body_size 500m` — allows large backup restore uploads; set in both locations.
- `X-Forwarded-Proto $scheme` — tells TREK whether the original request was HTTPS; required for `FORCE_HTTPS` redirect and cookie security to work correctly.
## Caddy
Caddy handles WebSocket upgrades automatically:
```
trek.yourdomain.com {
reverse_proxy localhost:3000
}
```
For large backup restores, add:
```
trek.yourdomain.com {
request_body max_size 500mb
reverse_proxy localhost:3000
}
```
## HTTPS Environment Variables
Four variables control how TREK behaves behind a proxy. They work as a group:
| Variable | Purpose | Default |
|---|---|---|
| `FORCE_HTTPS` | When `true`: 301-redirects HTTP→HTTPS (except `/api/health`), sends HSTS (`max-age=31536000`), adds CSP `upgrade-insecure-requests`, forces cookie `secure` flag | `false` |
| `TRUST_PROXY` | Number of trusted proxy hops. Lets Express read the real client IP from `X-Forwarded-For`. Automatically set to `1` in production even if not explicitly configured. | `1` (production), off (development) |
| `COOKIE_SECURE` | Controls the `secure` flag on `trek_session`. Auto-derived as `true` when `NODE_ENV=production` or `FORCE_HTTPS=true`. Set to `false` explicitly to allow cookies over plain HTTP (e.g. LAN testing without TLS). | auto |
| `ALLOWED_ORIGINS` | Comma-separated list of allowed CORS origins (e.g. `https://trek.example.com`). In production without this set, all cross-origin requests are blocked. In development without this set, all origins are allowed. | blocked in prod, open in dev |
> **Note on `FORCE_HTTPS` and proxy headers:** The HTTPS redirect reads `X-Forwarded-Proto` directly from the incoming headers — it does not depend on Express's `trust proxy` setting. If you set `FORCE_HTTPS=true` and your reverse proxy correctly sends `X-Forwarded-Proto: https`, the redirect will work regardless of `TRUST_PROXY`. However, you still need `TRUST_PROXY` set so Express resolves the correct client IP from `X-Forwarded-For`.
If you access TREK directly on `http://<host>:3000` without a proxy, leave `FORCE_HTTPS` unset and do not set `TRUST_PROXY`.
See [Environment-Variables] for full documentation of these and all other variables.
## Next Steps
- [Environment-Variables] — full variable reference including OIDC
- [Install-Docker-Compose] — production compose file with proxy-ready env vars
+41
View File
@@ -0,0 +1,41 @@
# Route Optimization
TREK calculates walking and driving times between your places and can reorder them to minimize total travel distance.
<!-- TODO: screenshot: optimized route displayed on map -->
![Route Optimization](assets/OptimizeRoute.png)
## Route calculation
TREK uses **OSRM** (Open Source Routing Machine) to calculate routes between consecutive places in the selected day. No API key is required.
Segment time pills always show both a **driving** time (fetched from OSRM using the driving profile) and a **walking** time (estimated at 5 km/h from the OSRM driving distance). There is no user-selectable routing profile — the driving profile is used for all OSRM requests.
Route segments reset at any transport reservation (flight, train, car, bus, or cruise) between two places — that leg is not driven or walked, so no ground route is drawn across it.
## Route display
- Colored line segments connect consecutive places on the map.
- At zoom level 12 or higher, time pills show the estimated walking and driving time between each pair of consecutive places.
- When at least two places are on the selected day, total distance and duration are shown in the sidebar footer.
## Optimize route
The **Optimize** button in the sidebar footer reorders places in the current day to minimize total travel distance using a **nearest-neighbor algorithm**. It starts from the first place, then repeatedly visits the closest unvisited place by straight-line (Euclidean) distance.
Only unlocked places are reordered — locked places stay in their current positions.
The reorder can be undone immediately using the undo action that appears after it is applied.
## Route calculation on/off
Route calculation (segment time pills) can be toggled on or off per user in **Settings → Display**. When disabled, no OSRM requests are made and time pills are not shown.
## Export day to Google Maps
The **Open in Google Maps** button (icon next to Optimize) generates a `https://www.google.com/maps/dir/lat,lng/lat,lng/…` URL containing all places in order and opens it in a new tab.
> **Admin:** Route calculation can be disabled instance-wide via the admin settings.
**See also:** [Day-Plans-and-Notes](Day-Plans-and-Notes) · [Map-Features](Map-Features) · [Display-Settings](Display-Settings)
+90
View File
@@ -0,0 +1,90 @@
# Security Hardening
A production TREK deployment checklist. All items reference actual TREK configuration options.
## Encryption & Secrets
- [ ] Set a strong `ENCRYPTION_KEY` (generate with `openssl rand -hex 32`). See [Encryption-Key-Rotation](Encryption-Key-Rotation).
- [ ] Back up `ENCRYPTION_KEY` separately from the database backup ZIP — losing it makes all stored API keys and secrets unreadable. Stored secrets use AES-256-GCM encryption derived from this key.
- [ ] Rotate `ENCRYPTION_KEY` if it may have been exposed. See [Encryption-Key-Rotation](Encryption-Key-Rotation).
- [ ] Do **not** set `JWT_SECRET` via environment variable. TREK auto-generates it on first start, persists it to `data/.jwt_secret`, and manages rotation through the Admin Panel. Setting it via env var would override any rotation performed through the UI on next restart.
## HTTPS & Network
- [ ] Run TREK behind a TLS-terminating reverse proxy (nginx, Caddy, Traefik). See [Reverse-Proxy](Reverse-Proxy).
- [ ] Set `TRUST_PROXY=1` so client IPs are captured correctly in the audit log. In `NODE_ENV=production` this defaults to `1` automatically, but set it explicitly if you use a non-standard proxy hop count.
- [ ] Set `FORCE_HTTPS=true` to enable HSTS (`max-age=31536000`), redirect HTTP to HTTPS, and add `upgrade-insecure-requests` to the CSP. Requires `TRUST_PROXY` — omitting it causes a redirect loop.
- [ ] Keep `ALLOW_INTERNAL_NETWORK=false` unless Immich or Synology is on your LAN. See [Internal-Network-Access](Internal-Network-Access). Note: loopback (`127.x`, `::1`) and link-local (`169.254.x`) addresses are always blocked regardless of this setting.
## Authentication
- [ ] Enable two-factor authentication for your admin account. See [Two-Factor-Authentication](Two-Factor-Authentication).
- [ ] Require MFA for all users via [Admin-Permissions](Admin-Permissions) if your use case demands it. Note: you must have MFA enabled on your own admin account before you can enforce it globally.
- [ ] Disable open registration if you control who can access the instance. See [Admin-Users-and-Invites](Admin-Users-and-Invites).
- [ ] Rotate the JWT signing secret if a session may have been leaked: Admin Panel → Admin → Rotate JWT Secret (`POST /api/admin/rotate-jwt-secret`). This invalidates all active sessions immediately.
## Session Security
TREK stores sessions as JWTs in an httpOnly `trek_session` cookie (SameSite=Lax, 24-hour expiry). The `secure` flag is set automatically when `NODE_ENV=production` or `FORCE_HTTPS=true`. Tokens are also accepted via `Authorization: Bearer` header for MCP and API clients.
- [ ] Ensure `FORCE_HTTPS=true` (or `NODE_ENV=production`) so the `trek_session` cookie carries the `secure` flag and is never sent over plain HTTP.
- [ ] Set `COOKIE_SECURE=false` only as a temporary escape hatch for LAN testing without TLS — do not use in production.
## Password Policy
TREK enforces a minimum password policy on all registrations and password changes:
- Minimum 8 characters
- Must contain uppercase, lowercase, digit, and special character
- Common passwords and fully-repetitive strings are rejected
- Passwords are hashed with bcrypt (cost factor 12)
No configuration is required; this policy is always active.
## Rate Limiting
Built-in in-memory rate limits protect authentication endpoints:
| Endpoint | Limit | Window |
|---|---|---|
| Login / Register / Invite | 10 attempts | 15 minutes |
| MFA verify-login / enable | 5 attempts | 15 minutes |
| Password change | 5 attempts | 15 minutes |
| MCP token creation | 5 attempts | 15 minutes |
These limits are per source IP. If TREK is behind a reverse proxy, set `TRUST_PROXY` so the real client IP is used rather than the proxy's IP.
## Content Security Policy
Helmet applies a strict CSP on all responses. Key directives:
- `default-src 'self'`
- `script-src 'self' 'wasm-unsafe-eval'` (no `unsafe-inline`)
- `object-src 'none'`
- `frame-src 'none'`
- `frameAncestors 'self'` (prevents clickjacking from external frames)
- `upgrade-insecure-requests` (added automatically when `FORCE_HTTPS=true`)
## Backups
- [ ] Enable auto-backup with an appropriate retention window. See [Backups](Backups).
- [ ] Store backups off-site — copy backup ZIPs to a separate location outside the TREK host.
## Monitoring
- [ ] Review the audit log periodically for unexpected logins or admin changes. See [Audit-Log](Audit-Log).
- [ ] Check for TREK updates regularly. See [Admin-GitHub-Releases](Admin-GitHub-Releases) and [Updating](Updating).
## See also
- [Encryption-Key-Rotation](Encryption-Key-Rotation)
- [Reverse-Proxy](Reverse-Proxy)
- [Internal-Network-Access](Internal-Network-Access)
- [Two-Factor-Authentication](Two-Factor-Authentication)
- [Admin-Permissions](Admin-Permissions)
- [Admin-Users-and-Invites](Admin-Users-and-Invites)
- [Backups](Backups)
- [Audit-Log](Audit-Log)
- [Admin-GitHub-Releases](Admin-GitHub-Releases)
- [Updating](Updating)
- [Environment-Variables](Environment-Variables)
+38
View File
@@ -0,0 +1,38 @@
# Tags and Categories
TREK has a labeling system: **Global Place Categories** (admin-managed, shared across all users).
<!-- TODO: screenshot: tag list on place detail -->
## Global Place Categories
Categories classify places across all trips. Every user sees the same set of categories.
**Fields per category:**
- **Name** — displayed in the place form and sidebar filter.
- **Color** — used for the colored icon background on map markers and in the places sidebar. Default: `#6366f1`.
- **Icon** — a Lucide icon name (e.g. `MapPin`, `Coffee`, `Mountain`). The UI form defaults to `MapPin`; the database-level fallback is the 📍 emoji, which is also resolved to the `MapPin` Lucide icon at render time.
Categories appear in:
- The **place form** when adding or editing a place.
- The **places sidebar** as filter options.
- **Map markers** — the category icon and color are used to style each place's marker pin.
- **Map tooltips** — hovering a marker shows the category name and icon.
> **Admin:** Create and manage categories in [Admin-Categories](Admin-Categories). Only admins can create, edit, or delete categories. All users can read them.
## When to use which
| Use case | Use |
|---|---|
| Classifying a place by type (Restaurant, Museum, Hiking Trail…) | **Category** |
| Personal labels you want to apply to specific places | **Tag** |
## See also
- [Places-and-Search](Places-and-Search)
- [Admin-Categories](Admin-Categories)
- [MCP-Overview](MCP-Overview)
+78
View File
@@ -0,0 +1,78 @@
# Todos and Tasks
Manage a to-do list for trip tasks and pre-departure preparation.
<!-- TODO: screenshot: to-do list with checkboxes and priority badges -->
![Todos and Tasks](assets/Todos.png)
## Where to find it
Open the **Lists** tab inside the trip planner and select **Todo**. The Todo feature shares the Lists addon with Packing Lists, so it is only visible when that addon is enabled.
> **Admin:** Enable the Lists/Packing addon in [Admin-Addons](Admin-Addons).
## Layout
The panel is divided into two columns by default:
- **Left sidebar** — category navigation, smart filters, sort toggle, and a completion progress card.
- **Task list** — the tasks that match the active filter.
When you click a task, a **detail pane** opens as a third column on the right side of the task list (on desktop) or slides up as a bottom sheet (on mobile). The new-task form also opens as a modal overlay.
On small screens the sidebar collapses to a narrow icon rail showing only colored dots and icons with badge counts.
## Task fields
Each task has the following fields:
| Field | Notes |
|---|---|
| Name | Required. |
| Checked | Boolean — marks the task done. |
| Category | Optional grouping label. |
| Due date | Optional date. |
| Description | Optional free-text body. |
| Assignee | Optional trip member. |
| Priority | 0 (none), 1 (P1), 2 (P2), or 3 (P3). |
Click a task row to open the detail pane on the right (or a modal sheet on mobile) where you can edit all fields.
## Priority levels
| Level | Label | Color |
|---|---|---|
| 1 | P1 | Red (`#ef4444`) |
| 2 | P2 | Amber (`#f59e0b`) |
| 3 | P3 | Blue (`#3b82f6`) |
Tasks with no priority set show no badge.
## Sidebar filters
| Filter | Shows |
|---|---|
| **All** | All unchecked tasks. |
| **My tasks** | Unchecked tasks assigned to you. |
| **Overdue** | Unchecked tasks with a past due date. |
| **Done** | Checked tasks. |
| Per-category rows | All tasks in that specific category (checked and unchecked). |
## Sort by priority
Toggle the **Priority** button in the sidebar to sort the current task list from P1 → P2 → P3 (tasks with no priority appear last).
## Adding tasks
Click the **+ Add task** button in the top-right corner of the Lists panel header (visible when the **Todo** sub-tab is active). A new-task form opens as a modal where you can set all fields before saving. On mobile it slides up from the bottom of the screen.
## Permissions
All write operations require the `packing_edit` permission (shared with Packing Lists).
## See also
- [Packing-Lists](Packing-Lists)
- [Admin-Addons](Admin-Addons)
- [Trip-Planner-Overview](Trip-Planner-Overview)
+84
View File
@@ -0,0 +1,84 @@
# Transport: Flights, Trains & Cars
Log flights, trains, car rentals, and cruises with departure and arrival endpoints, times, and transit-specific details.
## Where to create
Open the **Transports** tab in the trip planner and click **Add**, or open the planner from a day view and use the transport shortcut. Transport records appear in the [Reservations](Reservations-and-Bookings) panel alongside other bookings.
## Transport types
Four types are available: **Flight**, **Train**, **Car**, **Cruise**.
## Common fields
All transport types share these fields:
| Field | Notes |
|-------|-------|
| Title | Required |
| Departure day | Linked to a trip day |
| Departure time | Optional |
| Arrival day | Linked to a trip day (can differ from departure day) |
| Arrival time | Optional |
| Booking / confirmation code | Optional |
| Status | Pending or Confirmed |
| Notes | Optional free text |
## Endpoints
### Flights
The departure and arrival fields use the **Airport picker** — type a city name or IATA code (minimum two characters) to search. Results show the IATA code, airport name, city, and country.
Once you select an airport, the **timezone** for that airport appears next to the time field. This lets you enter local departure and arrival times without confusion across time zones.
<!-- TODO: screenshot: Transport modal for a flight with airport picker and timezone -->
### Trains, cars, and cruises
Departure and arrival fields use the **generic location picker** — search by place name or enter a free-text location. Results come from the maps search service.
For **car rentals**, the departure field is labelled **Pickup date/time** and the arrival field is labelled **Return date/time**.
## Flight-specific fields
When the type is set to Flight, two additional fields appear:
- **Airline** — carrier name (e.g. Lufthansa)
- **Flight number** — (e.g. LH 123)
## Train-specific fields
When the type is set to Train, three additional fields appear:
- **Train number** — (e.g. ICE 123)
- **Platform** — platform or track number
- **Seat** — seat or coach assignment
## On the map
Transport records with both endpoints set appear as lines on the trip map:
- **Flights** and **cruises** render as geodesic great-circle curves that follow the curvature of the Earth.
- **Trains** and **cars** render as straight polylines between the two endpoints.
Confirmed bookings are drawn as solid lines; pending bookings use a dashed line. Endpoint markers are shown at each location. For flights, a midpoint label appears along the arc showing the route codes (e.g. ZRH → JFK) and flight duration and distance when enough screen space is available.
See [Map-Features](Map-Features) for details on how these overlays work.
## In the day plan
When a transport is assigned to a day, it appears inline in the day timeline between places. Multi-day transports show phase labels depending on the type:
| Type | Start day | Middle days | End day |
|------|-----------|-------------|---------|
| Flight | Departure | In transit | Arrival |
| Car rental | Pickup | Active | Return |
| Train / Cruise | Start | Ongoing | End |
See [Day-Plans-and-Notes](Day-Plans-and-Notes) for details.
---
**See also:** [Reservations-and-Bookings](Reservations-and-Bookings) · [Accommodations](Accommodations) · [Map-Features](Map-Features) · [Day-Plans-and-Notes](Day-Plans-and-Notes)
+75
View File
@@ -0,0 +1,75 @@
# Trip Members and Sharing
<!-- TODO: screenshot: trip members list with roles and share link form -->
![Trip Members](assets/Share.png)
## Opening the Members Panel
- From the **dashboard**: click the share/members icon on a trip card.
- From the **trip planner**: click the Share button in the top navigation bar.
When you have the `share_manage` permission the modal opens to a two-column layout on wider screens (members on the left, share link on the right). Without that permission only the members column is shown. On narrow screens the columns always stack.
## Members List
The left column lists everyone who has access to the trip.
- The **trip owner** is marked with a crown badge.
- Your own entry is labeled **(you)**.
- Each non-owner member shows a remove button.
### Inviting Members
If you have the `member_manage` permission (default: trip owner), an invite control appears above the list. Select a user from the searchable dropdown and click **Invite**. The user is looked up by username or email on the server, added immediately, and the list refreshes. The invited user also receives an in-app notification.
### Removing a Member
Click the remove icon next to any member's name. A confirmation prompt appears before the member is removed.
If you click the remove icon next to **your own** name, the action is labeled **Leave trip** and uses a "log out" icon. Leaving reloads the page and returns you to the dashboard.
The trip owner cannot be removed through this panel.
## Public Share Link
The right column is only visible to users with the `share_manage` permission (default: trip owner).
A share link creates a **read-only, token-based URL**:
```
<your-instance>/shared/<token>
```
Viewers do not need to log in. The link can be shared with anyone.
### Creating a Link
Click **Create share link**. A URL is generated and shown with a copy button.
### Permission Toggles
Before or after creating the link, you can control what the link exposes. Toggle each section on or off with the pill buttons:
| Toggle | Default | What it shows |
|---|---|---|
| **Map** | Always on | Trip map with place markers — cannot be disabled |
| **Bookings** | On | Reservations and accommodations |
| **Packing** | Off | Packing list |
| **Budget** | Off | Budget tab |
| **Collab** | Off | Read-only view of notes, chat, and polls |
Changes to toggles take effect immediately for an existing link.
### Deleting a Link
Click **Delete link** (red button below the URL) to revoke access. The token is invalidated and existing viewers are redirected.
> **Admin:** To invite users who do not yet have an account, create invite links in the admin panel. See [Invite-Links](Invite-Links).
## Related Pages
- [Public-Share-Links](Public-Share-Links)
- [Invite-Links](Invite-Links)
- [Creating-a-Trip](Creating-a-Trip)
- [Trip-Planner-Overview](Trip-Planner-Overview)
+82
View File
@@ -0,0 +1,82 @@
# Trip Planner Overview
The trip planner is the main workspace for building your itinerary. It opens automatically after you create a trip, or any time you click a trip card on the dashboard.
<!-- TODO: screenshot: trip planner tab bar overview -->
![Trip Planner](assets/TripPlannerWithPlane.png)
## Layout
The planner uses a **three-pane resizable layout** on desktop:
```
┌─────────────────┬──────────────────────────┬──────────────────┐
│ Day Plan │ │ Places │
│ Sidebar │ Interactive │ Sidebar │
│ (left) │ Map │ (right) │
│ │ (center) │ │
└─────────────────┴──────────────────────────┴──────────────────┘
```
- **Left sidebar** — Day plan: your list of days, assigned places, notes, and transport entries. Collapsible via the panel toggle button.
- **Center** — Interactive map showing all place markers and day routes.
- **Right sidebar** — Places list: search, category filters, and bulk actions. Collapsible.
Each sidebar has a drag handle on its inner edge for resizing.
A **Day Detail overlay** slides in over the center pane when you open a specific day, showing weather, the day's notes, reservation summaries, and the accommodation block. It can be minimized without closing it.
## Tabs
The tab bar sits directly below the main navigation bar.
| Tab | Description |
|---|---|
| **Plan** | The three-pane map view described above. Always visible. |
| **Transports** | Flights, trains, cars, cruises, and buses. |
| **Reservations** | Hotels, restaurants, events, tours, and other bookings. |
| **Lists** | Packing list and to-do list. |
| **Budget** | Budget tracking and expense logging. |
| **Files** | Document manager for receipts, tickets, and other files. |
| **Collab** | Real-time chat, shared notes, and polls. |
> **Admin:** The **Lists**, **Budget**, **Files**, and **Collab** tabs only appear when the corresponding addon is enabled. See [Admin-Addons](Admin-Addons).
The active tab is saved in `sessionStorage` per trip, so switching between trips preserves your last position.
## Mobile Layout
On screens narrower than 768 px, the two sidebars are not shown side-by-side. Instead, two floating buttons appear over the map:
- **Plan** — opens the Day Plan Sidebar as a full-screen overlay.
- **Places** — opens the Places Sidebar as a full-screen overlay.
Tap outside the overlay or use the close button to return to the map.
## Undo
The planner tracks your recent actions — adding places, assigning them to days, reordering, and removing assignments — in a short undo ring. The **Undo** button appears in the Day Plan Sidebar toolbar (at the top of the sidebar) whenever an undoable action is available. It shows the name of the last action as a tooltip on hover and reverses it when clicked.
## Splash Screen
When you first open a trip, a brief loading screen appears while the planner data and place photos are fetched. This screen shows the trip title and a loading animation. Once data is ready and a short grace period for photos has elapsed, the planner workspace appears.
## Getting Around
| Task | Where to go |
|---|---|
| Add and search places | [Places-and-Search](Places-and-Search) |
| Organize days and notes | [Day-Plans-and-Notes](Day-Plans-and-Notes) |
| Map features and routes | [Map-Features](Map-Features) |
| Weather forecasts | [Weather-Forecasts](Weather-Forecasts) |
| Reservations and bookings | [Reservations-and-Bookings](Reservations-and-Bookings) |
## Related Pages
- [Places-and-Search](Places-and-Search)
- [Day-Plans-and-Notes](Day-Plans-and-Notes)
- [Map-Features](Map-Features)
- [Weather-Forecasts](Weather-Forecasts)
- [Reservations-and-Bookings](Reservations-and-Bookings)
- [Admin-Addons](Admin-Addons)
+85
View File
@@ -0,0 +1,85 @@
# Troubleshooting
## WebSocket not connecting / real-time sync broken
**Cause:** Your reverse proxy is not forwarding WebSocket upgrade headers on the `/ws` path.
**Fix:** Add the following to your proxy config for the `/ws` location:
```nginx
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
```
Without these headers, the WebSocket handshake fails and real-time sync will not work. See [Reverse Proxy](Reverse-Proxy) for a complete nginx and Caddy configuration. Caddy handles WebSocket upgrades automatically.
---
## HTTPS redirect loop
**Cause:** `FORCE_HTTPS=true` is set but your reverse proxy is not forwarding the `X-Forwarded-Proto: https` header, so every request looks like plain HTTP and gets redirected indefinitely.
**Fix:** Ensure your proxy passes the `X-Forwarded-Proto` header to TREK. Also set `TRUST_PROXY=1` so that Express uses the forwarded IP for rate limiting and audit logs:
```yaml
environment:
- FORCE_HTTPS=true
- TRUST_PROXY=1
```
> **Note:** The `/api/health` endpoint is always exempt from the HTTPS redirect so that Docker health checks continue to work over plain HTTP.
If you are accessing TREK directly on `http://<host>:3000` with no proxy, remove `FORCE_HTTPS` entirely. See [Environment Variables](Environment-Variables).
---
## Encrypted settings lost / API keys not working after migration
**Cause:** The `ENCRYPTION_KEY` was changed or lost. All API keys, SMTP passwords, OIDC client secrets, and MFA TOTP secrets are encrypted at rest using this key. Without the original key, decryption fails.
**Fix:** See [Encryption Key Rotation](Encryption-Key-Rotation) for the migration script that re-encrypts data under a new key. If the original key is gone entirely, the encrypted values are unrecoverable and must be re-entered in the admin panel.
> **Note:** If you upgraded from an older version without setting `ENCRYPTION_KEY`, the server uses the following resolution order on startup: (1) `ENCRYPTION_KEY` env var, (2) `data/.encryption_key` file, (3) one-time fallback to `data/.jwt_secret` for legacy upgrades — the value is immediately written to `data/.encryption_key` so JWT rotation cannot break decryption later, (4) auto-generated fresh key for brand-new installs. Check `data/.encryption_key` for the key currently in use.
---
## Locked out of MFA / lost authenticator
**Fix:** If you still have access to your account, use one of the 10 backup codes generated during MFA setup to complete login. After signing in, go to **Settings > Security** to disable or reconfigure MFA.
If you no longer have access to backup codes and cannot log in, an admin must disable MFA for your account directly in the database, or use the `reset-admin.js` script to regain access to an admin account. There is no per-user MFA reset in the Admin Panel UI — the Admin Panel only controls the global "require MFA for all users" policy. See [Admin: Users and Invites](Admin-Users-and-Invites).
---
## Demo user cannot edit or create
**Cause:** The instance is running with `DEMO_MODE=true`. All write operations are blocked for the demo account by design.
**Fix:** This is intentional behavior for public demo deployments. If you are self-hosting and want full access, remove the `DEMO_MODE` variable (or set it to `false`). See [Demo Mode](Demo-Mode).
---
## Backup restore fails with "file too large"
**Cause:** Your reverse proxy has a default body size limit (commonly 1 MB or 10 MB) that is smaller than the backup ZIP. Backup archives include the full uploads directory and can be large.
**Fix:** Raise the body size limit in your proxy config. TREK's own backup upload cap is 500 MB. For nginx:
```nginx
client_max_body_size 500m;
```
Add this to the `location /` block (or the specific backup route). See [Reverse Proxy](Reverse-Proxy) and [Backups](Backups).
---
## "Cannot find module" on startup
**Likely cause:** A Docker volume mount is missing or the `/app/data` and `/app/uploads` directories are not writable by the container process. TREK automatically creates all required subdirectories on startup (`data/logs`, `data/backups`, `data/tmp`, `uploads/files`, `uploads/covers`, `uploads/avatars`, `uploads/photos`) — if this fails because the volume is read-only or owned by the wrong user, startup will abort.
**Fix:** Check your Docker volume configuration. Both `./data:/app/data` and `./uploads:/app/uploads` must be mounted and writable. Run `docker inspect <container> --format '{{json .Mounts}}'` to verify the mounts are present and point to valid host paths. If the host directories are owned by root, the container's `chown` step (which runs as root before dropping to `node`) should correct permissions automatically — but if your host filesystem is read-only or permissions are locked down, grant write access manually:
```bash
sudo chown -R 1000:1000 ./data ./uploads
```
+62
View File
@@ -0,0 +1,62 @@
# Two-Factor Authentication
<!-- TODO: screenshot: 2FA setup QR code screen -->
![2FA](assets/2FA.png)
## What it is
TREK supports Time-based One-Time Password (TOTP) two-factor authentication, compatible with Google Authenticator, Authy, 1Password, and any standard TOTP app. When 2FA is active, you enter a 6-digit code (or a backup code) after your password on each login.
## Setting up 2FA
Go to **Settings → Account** and click **"Set up two-factor authentication"**.
1. A QR code and a text secret are displayed. Scan the QR code with your authenticator app.
> **Note:** The setup session expires after **15 minutes**. If you do not complete setup within that window, start again.
2. Enter the 6-digit code shown in your authenticator app and click **Confirm**.
3. Save your **10 backup codes**. These are single-use codes shown only once — store them somewhere safe (a password manager, printed paper). Each code has the format `XXXX-XXXX`.
4. 2FA is now active on your account.
## Logging in with 2FA
After entering your email and password, TREK shows a second prompt for your TOTP code. You have **5 minutes** to complete this second step before the intermediate session token expires. Enter either:
- The current 6-digit code from your authenticator app, or
- One of your backup codes (format `XXXX-XXXX`). Each backup code can only be used once.
## Disabling 2FA
Go to **Settings → Account** and click **"Disable two-factor authentication"**. You must provide both:
- Your current account **password**
- A valid **TOTP code** from your authenticator app
> **Note:** You cannot disable 2FA while the admin has required it for all users (see below).
## Admin-enforced 2FA
An admin can require 2FA for all users. Before enabling this setting the admin must have 2FA active on their own account — the server rejects the change otherwise.
If the setting is active and your account does not have 2FA set up, any API request after login returns a 403 error and the client redirects you to **Settings → Account** with a prompt to complete 2FA setup. You cannot use the app until setup is complete. See [Admin-Permissions](Admin-Permissions).
> **Admin:** You can reset 2FA for a locked-out user from the admin panel. See [Admin-Users-and-Invites](Admin-Users-and-Invites).
## Rate limits
TREK enforces IP-based rate limits to protect against brute-force attacks:
| Endpoint | Limit |
|---|---|
| Login (`/api/auth/login`) | 10 attempts per 15 minutes |
| MFA code verification (`/api/auth/mfa/verify-login`) | 5 attempts per 15 minutes |
Exceeding a limit returns HTTP 429. Wait for the window to reset before retrying.
## Demo users
The demo user account cannot enable or disable MFA.
---
**See also:** [Login-and-Registration](Login-and-Registration) · [Admin-Permissions](Admin-Permissions) · [Admin-Users-and-Invites](Admin-Users-and-Invites) · [User-Settings](User-Settings)
+55
View File
@@ -0,0 +1,55 @@
# Updating
How to update TREK to a newer version without losing data.
## Before You Update
Back up your data first. Go to Admin Panel → Backups and create a manual backup, or copy your `./data` and `./uploads` directories to a safe location. See [Backups] for details.
## Docker Compose (Recommended)
```bash
docker compose pull && docker compose up -d
```
This pulls the latest image and recreates the container with your existing volumes. Your data is untouched.
## Docker Run
If you started TREK with `docker run`, pull the new image and replace the container:
```bash
docker pull mauriceboe/trek
docker rm -f trek
docker run -d --name trek -p 3000:3000 \
-v ./data:/app/data \
-v ./uploads:/app/uploads \
-e ENCRYPTION_KEY=<your-key> \
--restart unless-stopped \
mauriceboe/trek
```
> **Tip:** Not sure which volume paths you used? Check before removing:
> ```bash
> docker inspect trek --format '{{json .Mounts}}'
> ```
## Database Migrations
TREK runs any pending database migrations automatically at startup. No manual migration steps are required after pulling a new image.
## Encryption Key Note
If you are upgrading from a version that predates the dedicated `ENCRYPTION_KEY` (i.e. you have no `ENCRYPTION_KEY` environment variable set), TREK automatically falls back to `./data/.jwt_secret` on startup and immediately promotes it to `./data/.encryption_key`. No manual steps are required — the transition is handled at first boot after the upgrade.
If you want to rotate to a new key at any point (not required for a normal update), see [Encryption-Key-Rotation] for the full procedure.
## Unraid
In the Unraid Docker tab, click the TREK container and select **Update**. Unraid will pull the latest image and restart with the same volumes.
## Next Steps
- [Backups] — schedule automatic backups so you always have a restore point before updates
- [Encryption-Key-Rotation] — if you need to rotate or migrate the encryption key
- [Install-Docker-Compose] — switch to Compose for easier future updates
+81
View File
@@ -0,0 +1,81 @@
# User Settings
The Settings page lets you personalise every aspect of TREK — appearance, maps, notifications, offline behaviour, and your account.
<!-- TODO: screenshot: user settings page tabs -->
## Navigating to Settings
Open the user menu in the top navigation bar and select **Settings**. The page opens on the **Display** tab by default.
If your account requires MFA setup, TREK redirects you directly to the **Account** tab (via `?mfa=required`).
## Tabs
| Tab | Purpose | Shown when |
|-----|---------|------------|
| Display | Color mode, language, temperature unit, time format, route calculation, booking route labels, and blur booking codes | Always |
| Map | Map provider (Leaflet or Mapbox GL), tile presets, Mapbox style and token, 3D buildings, high-quality mode, default map center and zoom | Always |
| Notifications | Email, webhook, ntfy, and in-app notification preferences | Always |
| Integrations | Photo providers (Immich, Synology, etc.) and MCP OAuth clients / API tokens | Only when the Memories or MCP addon is enabled |
| Offline | Cached trips, pending changes, re-sync and clear cache | Always |
| Account | Username, email, password, MFA (TOTP + backup codes), avatar, delete account | Always |
| About | App version, links to Ko-fi / Buy Me a Coffee / Discord / GitHub (bug reports, feature requests) / Wiki | Only when version metadata is available |
## Display tab
The Display tab controls the following preferences, all saved immediately on change:
- **Color mode** — Light, Dark, or Auto (follows the OS setting).
- **Language** — Displayed as a button grid on desktop and a dropdown on mobile.
- **Temperature unit** — Celsius (°C) or Fahrenheit (°F).
- **Time format** — 24h (14:30) or 12h (2:30 PM).
- **Route calculation** — Enable or disable automatic route calculation between places.
- **Booking route labels** — Show or hide labels on booking routes on the map.
- **Blur booking codes** — Blur confirmation codes and reference numbers (useful when screen-sharing).
## Map tab
The Map tab requires an explicit **Save** action after making changes.
**Provider** — choose between:
- **Leaflet** — Classic 2D raster tiles. You can pick from built-in presets (OpenStreetMap, OpenStreetMap DE, CartoDB Light/Dark, Stadia Smooth) or enter a custom tile URL template.
- **Mapbox GL** (Experimental) — Vector tiles with 3D buildings and terrain. Requires a public Mapbox access token (`pk.*`). Supports built-in style presets (Mapbox Standard, Standard Satellite, Streets, Outdoors, Light, Dark, Satellite, Satellite Streets, Navigation Day, Navigation Night) or a custom `mapbox://styles/USER/ID` URL. Additional options:
- **3D Buildings & Terrain** — Pitch and real 3D building extrusions (works on every style including satellite).
- **High Quality Mode** (Experimental) — Antialiasing + globe projection for sharper edges. May impact performance on lower-end devices.
> Atlas always uses Leaflet regardless of the provider setting.
**Default map position** — Set the default latitude, longitude, and zoom level. You can also click directly on the map preview to set the center.
## Account tab summary
The Account tab lets you:
- Edit your **username** and **email address**.
- Change your **password** (hidden when the server runs in OIDC-only mode — see [OIDC-SSO](OIDC-SSO)).
- Set up or disable **two-factor authentication** (TOTP). After enabling MFA, backup codes are shown once and can be copied, downloaded, or printed. See [Two-Factor-Authentication](Two-Factor-Authentication).
- Upload or remove your **profile avatar**.
- **Delete your account** (irreversible; blocked if you are the only admin).
If your account was linked via SSO, an **SSO** badge appears next to your role and the OIDC issuer domain is shown below it.
## Integrations tab
The Integrations tab is only visible when the **Memories** or **MCP** addon is enabled. It contains:
- **Photo Providers** — Configure Immich, Synology Photos, and other photo integrations (always shown when the Integrations tab is visible).
- **MCP section** (only when MCP addon is enabled):
- Shows the MCP server endpoint URL.
- **OAuth Clients** sub-tab — Create and manage OAuth 2.1 clients (with redirect URIs and scopes). Quick-fill presets are provided for Claude.ai, Claude Desktop, Cursor, VS Code, Windsurf, and Zed. Active OAuth sessions can be viewed and revoked here.
- **API Tokens** sub-tab (Deprecated) — Create and manage personal bearer tokens for direct MCP access.
## See also
- [Display-Settings](Display-Settings)
- [Map-Settings](Map-Settings)
- [Notifications](Notifications)
- [Offline-Mode-and-PWA](Offline-Mode-and-PWA)
- [Two-Factor-Authentication](Two-Factor-Authentication)
- [Languages](Languages)
+62
View File
@@ -0,0 +1,62 @@
# Vacay
Vacay is a personal vacation day planner that lives separately from your trip planning. It tracks how many vacation days you have per year, how many you have used, and what remains.
> **Admin:** enable Vacay in [Admin-Addons](Admin-Addons).
<!-- TODO: screenshot: vacation planner calendar view -->
![Vacay screenshot](assets/Vacay.png)
## What Vacay is
While trips in TREK represent specific travel plans, Vacay tracks your annual leave entitlement — the number of vacation days granted by your employer or contract, which days you have already logged, and the balance left. It is personal by default, but you can fuse your plan with another TREK user to see each other's calendars side by side.
## Accessing Vacay
When the admin has enabled the Vacay addon, a **Vacay** entry appears in the main navigation. Each user gets their own plan automatically when they first open the page.
## Year plans
Vacay is organised by year. You can have multiple years active at once and navigate between them with the year selector in the sidebar.
For each year, your entitlement panel shows:
- **Entitlement days** — your vacation allowance for that year (editable inline by clicking the field).
- **Used** — days you have logged on the calendar.
- **Remaining** — entitlement plus any carried-over days, minus used days.
**Carry-over** — when `carry_over_enabled` is on, unused days from the previous year are automatically added to the next year's total. When you toggle this setting, the carry-over amount is recalculated across all existing year records. Turn it off to zero out all carry-over balances.
## Calendar view
The main area shows a full 12-month grid. Each cell represents one day. Click a day to log or remove a vacation entry. Logged days are colour-coded by person when collaborators are fused into your plan.
Days that overlap with any of your existing TREK trips are marked with a small blue dot in the corner.
You can also switch the calendar toolbar to **Company** mode to mark shared company holidays, which are highlighted in amber and do not deduct from personal allowances.
**Settings** (gear icon) let you configure:
- **Block weekends** — prevents logging on weekend days. You choose which days count as the weekend.
- **Week start** — Monday or Sunday.
- **Carry-over** — toggle as described above.
- **Company holidays** — enable a shared company holiday layer that any fused user can edit.
- **Public holidays** — add one or more country/region holiday calendars so that public holidays appear on the grid. Holiday data is fetched from the nager.at public holiday API. Each calendar has a label, a colour, and a country or region selector (sub-national regions such as German states or Swiss cantons are supported).
## Inviting collaborators
You can invite other TREK users to fuse their Vacay plan with yours. Once a user accepts, your plans are merged: you see each other's logged days in distinct colours, and you can log days on behalf of the other person if needed.
To invite someone, click the **+** icon in the **Persons** panel in the sidebar, choose a user, and send the invite. The recipient receives a notification and must accept before the fusion takes effect.
To undo a fusion, open Settings and use the **Dissolve** action. Each user's logged entries return to their own separate plan.
## Live sync
Changes — logged days, settings updates, fusions, invites — sync in real time to all fused collaborators via WebSocket events (`vacay:update`, `vacay:settings`, `vacay:invite`, `vacay:accepted`, `vacay:declined`, `vacay:cancelled`, `vacay:dissolved`). You do not need to refresh the page.
## See also
- [Addons-Overview](Addons-Overview)
- [Admin-Addons](Admin-Addons)
+44
View File
@@ -0,0 +1,44 @@
# Weather Forecasts
TREK shows weather forecasts and historical climate estimates for each day in your trip, powered by Open-Meteo — no API key required.
<!-- TODO: screenshot: weather forecast card on a trip day -->
![Weather forecasts](assets/Weather.png)
## Where forecasts appear
Click any day header in the left sidebar to open the **Day Detail panel**. The weather widget appears at the top of that panel.
A compact weather badge (icon + temperature) also appears inline on each day row in the sidebar.
## What is shown
The Day Detail panel weather widget displays:
- Weather icon and condition label
- Min / max temperature for the day
- Precipitation probability and total amount
- Wind speed (km/h, or mph when Fahrenheit is selected)
- Sunrise and sunset times
- **Hourly strip** — icon and temperature shown in 2-hour intervals; slots with precipitation probability above 50 % are highlighted
## Data source and time windows
| Date range | Data source | Cache TTL |
|---|---|---|
| Within 16 days (today 1 day to today +16 days) | Open-Meteo forecast API | 1 hour |
| More than 1 day in the past | Open-Meteo archive API (actual historical data) | 24 hours |
| More than 16 days in the future | Climate estimate from the same date in the prior year | 24 hours |
Far-future estimates are labeled with a **Ø** prefix (e.g. "Ø 18 °C") to make it clear they are climate estimates, not a real forecast. The compact sidebar badge re-fetches silently in the background if a cached climate estimate could be upgraded to a live forecast.
## Temperature and wind units
Temperature follows your setting in [Display-Settings](Display-Settings) — switch between °C and °F there. Wind speed is shown in km/h (°C mode) or mph (°F mode).
## Session cache
The compact sidebar weather badge caches fetched data in `sessionStorage` for the duration of your browser session, so navigating between days does not trigger repeated network requests for data you have already loaded. The Day Detail panel fetches fresh detailed weather data each time it is opened.
**See also:** [Day-Plans-and-Notes](Day-Plans-and-Notes) · [Display-Settings](Display-Settings)
+38
View File
@@ -0,0 +1,38 @@
# What's Next Widget
The What's Next widget shows the upcoming assigned places across all days of your trip at a glance — useful for quickly orienting the group before heading out.
<!-- TODO: screenshot: What's Next widget showing upcoming events -->
![What's Next widget](assets/Collab.png)
## Where to find it
Open the trip planner → **Collab** tab. On **desktop** the widget appears as a panel (alongside Chat, Notes, and Polls). On **mobile** it appears as a tab labeled "What's Next" with a sparkle icon in the Collab tab bar. The Collab addon must be enabled and the What's Next sub-feature must be turned on. See [Real-Time-Collaboration](Real-Time-Collaboration).
## What it shows
The widget displays the next **8** upcoming place assignments across all trip days, sorted by date and time. Entries are included if they fall on a future day, or if they fall on today and either have no time set (TBD) or have a start time that is still in the future. Past entries are excluded.
Each entry shows:
- **Time** — the scheduled start time (or "TBD" if none is set), and the end time if one is set
- **Place name**
- **Address** — if one is stored on the place
- **Participant chips** — the members assigned to this place. If no specific participants are assigned, all trip members are shown instead.
Entries are grouped by date with day headers: **Today**, **Tomorrow**, or the formatted weekday and date for further-out days. If a day has a title set, it appears after the date label.
## When it updates
The widget reflects the current trip data in real time — when you or another member adds, edits, or removes a day assignment, the list updates automatically without a page refresh.
## Requirements
- Collab addon enabled (admin)
- What's Next sub-feature enabled (admin)
- The trip must have days with place assignments that have future dates or times
## Related pages
[Real-Time-Collaboration](Real-Time-Collaboration) · [Collab-Chat](Collab-Chat) · [Day-Plans-and-Notes](Day-Plans-and-Notes)
+1
View File
@@ -0,0 +1 @@
[AGPL-3.0 License](https://github.com/mauriceboe/TREK/blob/main/LICENSE) · [GitHub](https://github.com/mauriceboe/TREK) · [Discord](https://discord.gg/NhZBDSd4qW) · [Security Hardening](Security-Hardening)
+94
View File
@@ -0,0 +1,94 @@
## Getting Started
- [[Home]]
- [[Quick Start|Quick-Start]]
- [[Install: Docker|Install-Docker]]
- [[Install: Docker Compose|Install-Docker-Compose]]
- [[Install: Helm|Install-Helm]]
- [[Install: Unraid|Install-Unraid]]
- [[Reverse Proxy|Reverse-Proxy]]
- [[Environment Variables|Environment-Variables]]
- [[Updating]]
## Account & Auth
- [[Login and Registration|Login-and-Registration]]
- [[OIDC SSO|OIDC-SSO]]
- [[Two-Factor Authentication|Two-Factor-Authentication]]
- [[Password Reset|Password-Reset]]
- [[User Settings|User-Settings]]
- [[Display Settings|Display-Settings]]
- [[Map Settings|Map-Settings]]
- [[Notifications]]
- [[Offline Mode and PWA|Offline-Mode-and-PWA]]
- [[Languages]]
## Planning Trips
- [[My Trips Dashboard|My-Trips-Dashboard]]
- [[Creating a Trip|Creating-a-Trip]]
- [[Trip Members and Sharing|Trip-Members-and-Sharing]]
- [[Trip Planner Overview|Trip-Planner-Overview]]
- [[Places and Search|Places-and-Search]]
- [[Day Plans and Notes|Day-Plans-and-Notes]]
- [[Map Features|Map-Features]]
- [[Route Optimization|Route-Optimization]]
- [[Weather Forecasts|Weather-Forecasts]]
## Travel Management
- [[Reservations and Bookings|Reservations-and-Bookings]]
- [[Transport: Flights, Trains, Cars|Transport-Flights-Trains-Cars]]
- [[Accommodations]]
- [[Budget Tracking|Budget-Tracking]]
- [[Packing Lists|Packing-Lists]]
- [[Packing Templates|Packing-Templates]]
- [[Todos and Tasks|Todos-and-Tasks]]
- [[Documents and Files|Documents-and-Files]]
- [[Tags and Categories|Tags-and-Categories]]
## Photos & Media
- [[Photo Providers|Photo-Providers]]
- [[PDF Export|PDF-Export]]
## Collaboration
- [[Real-Time Collaboration|Real-Time-Collaboration]]
- [[Collab Chat|Collab-Chat]]
- [[Collab Notes|Collab-Notes]]
- [[Collab Polls|Collab-Polls]]
- [[What's Next Widget|Whats-Next-Widget]]
- [[Public Share Links|Public-Share-Links]]
- [[Invite Links|Invite-Links]]
## Addons
- [[Addons Overview|Addons-Overview]]
- [[Vacay]]
- [[Atlas]]
- [[Journey Journal|Journey-Journal]]
- [[Dashboard Widgets|Dashboard-Widgets]]
## AI / MCP
- [[MCP Overview|MCP-Overview]]
- [[MCP Setup|MCP-Setup]]
- [[MCP Scopes|MCP-Scopes]]
- [[MCP Tools and Resources|MCP-Tools-and-Resources]]
- [[MCP Addon Tools|MCP-Addon-Tools]]
- [[MCP Prompts|MCP-Prompts]]
## Admin Panel
- [[Admin Panel Overview|Admin-Panel-Overview]]
- [[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]]
## Operations
- [[Backups]]
- [[Demo Mode|Demo-Mode]]
- [[Encryption Key Rotation|Encryption-Key-Rotation]]
- [[Internal Network Access|Internal-Network-Access]]
- [[Audit Log|Audit-Log]]
- [[Security Hardening|Security-Hardening]]
## Help
- [[FAQ]]
- [[Troubleshooting]]
Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 920 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 596 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Some files were not shown because too many files have changed in this diff Show More