[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-74790":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":19,"stars90d":16,"forks30d":16,"starsTrendScore":20,"compositeScore":21,"rankGlobal":10,"rankLanguage":10,"license":22,"archived":23,"fork":23,"defaultBranch":24,"hasWiki":25,"hasPages":25,"topics":26,"createdAt":10,"pushedAt":10,"updatedAt":45,"readmeContent":46,"aiSummary":47,"trendingCount":16,"starSnapshotCount":16,"syncStatus":48,"lastSyncTime":49,"discoverSource":50},74790,"TREK","mauriceboe\u002FTREK","mauriceboe","A self-hosted travel\u002Ftrip planner with real-time collaboration, interactive maps, PWA support, SSO, budgets, packing lists, and more.","https:\u002F\u002Fdemo-nomad.pakulat.org",null,"TypeScript",5585,552,16,21,0,157,295,723,471,39.23,"GNU Affero General Public License v3.0",false,"main",true,[27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44],"budget-tracker","collaborative","open-source","opensource","packing-list","poi","real-time","routes","self-hosted","travel","travel-app","travel-planner","traveling","trip","trip-planner","wanderlog","wanderlust","webapplication","2026-06-12 02:03:28","\u003Cdiv align=\"center\">\n\n\u003Cpicture>\n  \u003Csource media=\"(prefers-color-scheme: dark)\" srcset=\"docs\u002Flogo-trek-light.gif\" \u002F>\n  \u003Csource media=\"(prefers-color-scheme: light)\" srcset=\"docs\u002Flogo-trek-dark.gif\" \u002F>\n  \u003Cimg src=\"docs\u002Flogo-trek-dark.gif\" alt=\"TREK\" height=\"96\" \u002F>\n\u003C\u002Fpicture>\n\n\u003Cbr \u002F>\n\n\u003Cpicture>\n  \u003Csource media=\"(prefers-color-scheme: dark)\" srcset=\"docs\u002Fsubtitle-light.png\" \u002F>\n  \u003Csource media=\"(prefers-color-scheme: light)\" srcset=\"docs\u002Fsubtitle-dark.png\" \u002F>\n  \u003Cimg src=\"docs\u002Fsubtitle-dark.png\" alt=\"Your trips. Your plan. Your server.\" height=\"28\" \u002F>\n\u003C\u002Fpicture>\n\nA self-hosted, real-time collaborative travel planner — with maps, budgets, packing lists, a journal, and AI built in.\n\n\u003Cbr \u002F>\n\n\u003Ca href=\"https:\u002F\u002Fdemo-nomad.pakulat.org\">\u003Cimg alt=\"Demo\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FDemo-try-111827?style=for-the-badge\" \u002F>\u003C\u002Fa>\n&nbsp;\n\u003Ca href=\"https:\u002F\u002Fhub.docker.com\u002Fr\u002Fmauriceboe\u002Ftrek\">\u003Cimg alt=\"Docker\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FDocker-ready-2496ED?style=for-the-badge\" \u002F>\u003C\u002Fa>\n&nbsp;\n\u003Ca href=\"https:\u002F\u002Fdiscord.gg\u002FNhZBDSd4qW\">\u003Cimg alt=\"Discord\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FDiscord-join-5865F2?style=for-the-badge\" \u002F>\u003C\u002Fa>\n&nbsp;\n\u003Ca href=\"https:\u002F\u002Fkanban.pakulat.org\u002Fshared\u002FI4wxF6inOOMB0C6hH6kQm3efyNxFjwyI\">\u003Cimg alt=\"Roadmap\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FRoadmap-view-0EA5E9?style=for-the-badge\" \u002F>\u003C\u002Fa>\n\u003Cbr \u002F>\n\u003Ca href=\"https:\u002F\u002Fko-fi.com\u002Fmauriceboe\">\u003Cimg alt=\"Ko-fi\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FKo--fi-support-FF5E5B?style=for-the-badge\" \u002F>\u003C\u002Fa>\n&nbsp;\n\u003Ca href=\"https:\u002F\u002Fwww.buymeacoffee.com\u002Fmauriceboe\">\u003Cimg alt=\"BMAC\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FBMAC-support-FFDD00?style=for-the-badge\" \u002F>\u003C\u002Fa>\n\u003Cbr \u002F>\n\u003Ca href=\"LICENSE\">\u003Cimg alt=\"License\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-AGPL_v3-6B7280?style=flat-square\" \u002F>\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fmauriceboe\u002FTREK\u002Freleases\">\u003Cimg alt=\"Latest Release\" src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fv\u002Frelease\u002Fmauriceboe\u002FTREK?include_prereleases&style=flat-square&color=6B7280\" \u002F>\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fhub.docker.com\u002Fr\u002Fmauriceboe\u002Ftrek\">\u003Cimg alt=\"Docker Pulls\" src=\"https:\u002F\u002Fimg.shields.io\u002Fdocker\u002Fpulls\u002Fmauriceboe\u002Ftrek?style=flat-square&color=6B7280\" \u002F>\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fmauriceboe\u002FTREK\">\u003Cimg alt=\"Stars\" src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fstars\u002Fmauriceboe\u002FTREK?style=flat-square&color=6B7280\" \u002F>\u003C\u002Fa>\n\n\u003C\u002Fdiv>\n\n---\n\n\u003Cdiv align=\"center\">\n\n\u003Cimg src=\"https:\u002F\u002Fgithub.com\u002Fmauriceboe\u002Ftrek-media\u002Freleases\u002Fdownload\u002Freadme-assets\u002FTREK1.gif\" alt=\"TREK — 60-second tour\" width=\"100%\" \u002F>\n\n\u003C\u002Fdiv>\n\n\u003Cbr \u002F>\n\n\u003Cdiv align=\"center\">\n  \u003Ca href=\"docs\u002Fscreenshots\u002Fdashboard.png\">\u003Cimg src=\"docs\u002Fscreenshots\u002Fdashboard.png\" alt=\"Dashboard\" width=\"49%\" \u002F>\u003C\u002Fa>\n  \u003Ca href=\"docs\u002Fscreenshots\u002Ftrip-planner.png\">\u003Cimg src=\"docs\u002Fscreenshots\u002Ftrip-planner.png\" alt=\"Trip planner with 3D map\" width=\"49%\" \u002F>\u003C\u002Fa>\n  \u003Ca href=\"docs\u002Fscreenshots\u002Fjourney.png\">\u003Cimg src=\"docs\u002Fscreenshots\u002Fjourney.png\" alt=\"Journey journal\" width=\"49%\" \u002F>\u003C\u002Fa>\n  \u003Ca href=\"docs\u002Fscreenshots\u002Fbudget.png\">\u003Cimg src=\"docs\u002Fscreenshots\u002Fbudget.png\" alt=\"Budget tracker\" width=\"49%\" \u002F>\u003C\u002Fa>\n  \u003Ca href=\"docs\u002Fscreenshots\u002Fatlas.png\">\u003Cimg src=\"docs\u002Fscreenshots\u002Fatlas.png\" alt=\"Atlas · visited countries\" width=\"49%\" \u002F>\u003C\u002Fa>\n  \u003Ca href=\"docs\u002Fscreenshots\u002Fvacay.png\">\u003Cimg src=\"docs\u002Fscreenshots\u002Fvacay.png\" alt=\"Vacay planner\" width=\"49%\" \u002F>\u003C\u002Fa>\n  \u003Ca href=\"docs\u002Fscreenshots\u002Ftrip-iceland.png\">\u003Cimg src=\"docs\u002Fscreenshots\u002Ftrip-iceland.png\" alt=\"Iceland Ring Road\" width=\"49%\" \u002F>\u003C\u002Fa>\n  \u003Ca href=\"docs\u002Fscreenshots\u002Fadmin.png\">\u003Cimg src=\"docs\u002Fscreenshots\u002Fadmin.png\" alt=\"Admin panel\" width=\"49%\" \u002F>\u003C\u002Fa>\n\u003C\u002Fdiv>\n\n---\n\n## What you get\n\n\u003Cpicture>\n  \u003Csource media=\"(max-width: 700px)\" srcset=\"docs\u002Ftiles\u002Fgrid-mobile.svg\" \u002F>\n  \u003Cimg src=\"docs\u002Ftiles\u002Fgrid-desktop.svg\" alt=\"TREK feature tiles\" width=\"100%\" \u002F>\n\u003C\u002Fpicture>\n\n\u003Cdetails>\n\u003Csummary>\u003Cb>See all features\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Ctable>\n\u003Ctr>\n\u003Ctd width=\"50%\" valign=\"top\">\n\n#### 🧭 Trip planning\n\n- **Drag & drop planner** — organise places into day plans with reordering and cross-day moves\n- **Interactive map** — Leaflet or Mapbox GL with 3D buildings, terrain, photo markers, clustering, route visualization\n- **Place search** — Google Places (photos, ratings, hours) or OpenStreetMap (free, no API key)\n- **Day notes** — timestamped, icon-tagged notes with drag-and-drop reordering\n- **Route optimisation** — auto-sort places and export to Google Maps\n- **Weather forecasts** — 16-day via Open-Meteo (no key) + historical climate fallback\n- **Category filter** — show only matching pins on the map\n\n\u003C\u002Ftd>\n\u003Ctd width=\"50%\" valign=\"top\">\n\n#### 🧳 Travel management\n\n- **Reservations** — flights, accommodations, restaurants with status, confirmation numbers, files\n- **Budget tracking** — category-based expenses with pie chart, per-person \u002F per-day splits, multi-currency\n- **Packing lists** — categories, templates, user assignment, progress tracking\n- **Bag tracking** — optional weight tracking with iOS-style distribution\n- **Document manager** — attach docs, tickets, PDFs to trips \u002F places \u002F reservations (≤ 50 MB each)\n- **PDF export** — full trip plan as PDF with cover page, images, notes\n\n\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd width=\"50%\" valign=\"top\">\n\n#### 👥 Collaboration\n\n- **Real-time sync** — WebSocket. Changes appear instantly across all connected users\n- **Multi-user trips** — invite members with role-based access\n- **Invite links** — one-time or reusable links with expiry\n- **SSO (OIDC)** — Google, Apple, Authentik, Keycloak, or any OIDC provider\n- **2FA** — TOTP + backup codes\n- **Collab suite** — group chat, shared notes, polls, day check-ins\n\n\u003C\u002Ftd>\n\u003Ctd width=\"50%\" valign=\"top\">\n\n#### 📱 Mobile & PWA\n\n- **Installable** — iOS and Android, straight from the browser, no App Store needed\n- **Offline support** — Service Worker caches tiles, API, uploads via Workbox\n- **Native feel** — fullscreen standalone, themed status bar, splash screen\n- **Touch optimised** — mobile-specific layouts with safe-area handling\n\n\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd width=\"50%\" valign=\"top\">\n\n#### 🧩 Addons (admin-toggleable)\n\n- **Lists** — packing lists + to-dos with templates, member assignments, optional bag tracking\n- **Budget** — expense tracker with splits, pie chart, multi-currency\n- **Documents** — file attachments on trips, places, and reservations\n- **Collab** — chat, notes, polls, day-by-day attendance\n- **Vacay** — personal vacation planner with calendar, 100+ country holidays, carry-over tracking\n- **Atlas** — world map of visited countries, bucket list, travel stats, streak tracking, liquid-glass UI\n- **Journey** — magazine-style travel journal with entries, photos (Immich\u002FSynology), maps, moods\n- **Naver List Import** — one-click import from shared Naver Maps lists\n- **MCP** — expose TREK to AI assistants via OAuth 2.1\n\n\u003C\u002Ftd>\n\u003Ctd width=\"50%\" valign=\"top\">\n\n#### 🤖 AI \u002F MCP\n\n- **Built-in MCP server** — OAuth 2.1 authenticated. 150+ tools, 30 resources\n- **Granular scopes** — 27 OAuth scopes across 13 permission groups\n- **Full automation** — AI can create trips, plan days, build packing lists, manage budgets, mark countries visited\n- **Pre-built prompts** — `trip-summary`, `packing-list`, `budget-overview`\n- **Addon-aware** — exposes Atlas, Collab, Vacay when those addons are on\n\n\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd colspan=\"2\" valign=\"top\">\n\n#### ⚙️ Admin & customisation\n\n- **Dashboard views** — card grid or compact list · **Dark mode** — full theme with matching status bar\n- **15 languages** — EN, DE, ES, FR, IT, NL, HU, RU, ZH, ZH-TW, PL, CS, AR (RTL), BR, ID\n- **Admin panel** — users, invites, packing templates, categories, addons, API keys, backups, GitHub history\n- **Auto-backups** — scheduled with configurable retention · **Units** — °C\u002F°F, 12h\u002F24h, map tile sources, default coordinates\n\n\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftable>\n\n\u003C\u002Fdetails>\n\n\u003Cbr \u002F>\n\n## Get started in 30 seconds\n\n```bash\nENCRYPTION_KEY=$(openssl rand -hex 32) docker run -d -p 3000:3000 \\\n  -e ENCRYPTION_KEY=$ENCRYPTION_KEY \\\n  -v .\u002Fdata:\u002Fapp\u002Fdata -v .\u002Fuploads:\u002Fapp\u002Fuploads mauriceboe\u002Ftrek\n```\n\nOpen `http:\u002F\u002Flocalhost:3000`. On first boot TREK seeds an admin account — if you set `ADMIN_EMAIL`\u002F`ADMIN_PASSWORD` those are used, otherwise the credentials are printed to the container log (`docker logs trek`).\n\n\u003Cdiv align=\"center\">\n\n&nbsp;&nbsp;·&nbsp;&nbsp;\u003Ca href=\"#docker-compose-production\">Docker Compose\u003C\u002Fa>&nbsp;&nbsp;·&nbsp;&nbsp;\u003Ca href=\"#helm-kubernetes\">Helm \u002F Kubernetes\u003C\u002Fa>&nbsp;&nbsp;·&nbsp;&nbsp;\u003Ca href=\"#install-as-app-pwa\">Install as PWA\u003C\u002Fa>&nbsp;&nbsp;·&nbsp;&nbsp;\u003Ca href=\"#reverse-proxy\">Reverse Proxy\u003C\u002Fa>&nbsp;&nbsp;·&nbsp;&nbsp;\n\n\u003C\u002Fdiv>\n\n\u003Cbr \u002F>\n\n## Tech stack\n\n\u003Cdiv align=\"center\">\n\n![Node.js](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FNode.js_22-339933?style=flat-square&logo=node.js&logoColor=white)\n![Express](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FExpress-000000?style=flat-square&logo=express&logoColor=white)\n![SQLite](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FSQLite-003B57?style=flat-square&logo=sqlite&logoColor=white)\n![React](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FReact_18-61DAFB?style=flat-square&logo=react&logoColor=black)\n![Vite](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FVite-646CFF?style=flat-square&logo=vite&logoColor=white)\n![TypeScript](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FTypeScript-3178C6?style=flat-square&logo=typescript&logoColor=white)\n![Tailwind](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FTailwind-06B6D4?style=flat-square&logo=tailwindcss&logoColor=white)\n![Leaflet](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FLeaflet-199900?style=flat-square&logo=leaflet&logoColor=white)\n![Docker](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FDocker-2496ED?style=flat-square&logo=docker&logoColor=white)\n\n\u003C\u002Fdiv>\n\nReal-time sync via WebSocket (`ws`). State with Zustand. Auth via JWT + OAuth 2.1 + OIDC + TOTP MFA. Weather via Open-Meteo (no key required). Maps with Leaflet and Mapbox GL.\n\n\u003Cbr \u002F>\n\n\u003Ch2 id=\"docker-compose-production\">Docker Compose (production)\u003C\u002Fh2>\n\n\u003Cdetails>\n\u003Csummary>Full compose example with secure defaults\u003C\u002Fsummary>\n\n```yaml\nservices:\n  app:\n    image: mauriceboe\u002Ftrek:latest\n    container_name: trek\n    read_only: true\n    security_opt:\n      - no-new-privileges:true\n    cap_drop:\n      - ALL\n    cap_add:\n      - CHOWN\n      - SETUID\n      - SETGID\n    tmpfs:\n      - \u002Ftmp:noexec,nosuid,size=64m\n    ports:\n      - \"3000:3000\"\n    environment:\n      - NODE_ENV=production\n      - PORT=3000\n      - ENCRYPTION_KEY=${ENCRYPTION_KEY:-}   # generate with: openssl rand -hex 32\n      - TZ=${TZ:-UTC}\n      - LOG_LEVEL=${LOG_LEVEL:-info}\n      - ALLOWED_ORIGINS=${ALLOWED_ORIGINS:-}\n      - APP_URL=${APP_URL:-}                 # required for OIDC + email links\n      # - FORCE_HTTPS=true                   # behind a TLS-terminating proxy\n      # - TRUST_PROXY=1\n      # - OIDC_ISSUER=https:\u002F\u002Fauth.example.com\n      # - OIDC_CLIENT_ID=trek\n      # - OIDC_CLIENT_SECRET=supersecret\n      # - OIDC_DISPLAY_NAME=SSO\n      # - OIDC_ADMIN_CLAIM=groups\n      # - OIDC_ADMIN_VALUE=app-trek-admins\n    volumes:\n      - .\u002Fdata:\u002Fapp\u002Fdata\n      - .\u002Fuploads:\u002Fapp\u002Fuploads\n    restart: unless-stopped\n    healthcheck:\n      test: [\"CMD\", \"wget\", \"-qO-\", \"http:\u002F\u002Flocalhost:3000\u002Fapi\u002Fhealth\"]\n      interval: 30s\n      timeout: 10s\n      retries: 3\n      start_period: 15s\n```\n\nThen:\n\n```bash\ndocker compose up -d\n```\n\n**HTTPS notes:** `FORCE_HTTPS=true` is optional — it adds a 301 redirect, HSTS, CSP upgrade-insecure-requests, and forces the `secure` cookie flag. Only use it behind a TLS-terminating reverse proxy. `TRUST_PROXY=1` tells Express how many proxies sit in front so real client IPs and `X-Forwarded-Proto` work.\n\n\u003C\u002Fdetails>\n\n\u003Cbr \u002F>\n\n\u003Ch2 id=\"helm-kubernetes\">Helm (Kubernetes)\u003C\u002Fh2>\n\n```bash\nhelm repo add trek https:\u002F\u002Fmauriceboe.github.io\u002FTREK\nhelm repo update\nhelm install trek trek\u002Ftrek\n```\n\nSee [`charts\u002FREADME.md`](https:\u002F\u002Fgithub.com\u002Fmauriceboe\u002FTREK\u002Fblob\u002Fmain\u002Fcharts\u002FREADME.md) for values.\n\n\u003Ch2 id=\"install-as-app-pwa\">Install as App (PWA)\u003C\u002Fh2>\n\nTREK works as a Progressive Web App — no App Store needed.\n\n1. Open TREK in the browser (HTTPS required)\n2. **iOS**: Share ▸ *Add to Home Screen*\n3. **Android**: Menu ▸ *Install app* (or *Add to Home Screen*)\n\nTREK then launches fullscreen with its own icon, just like a native app.\n\n\u003Cbr \u002F>\n\n## Updating\n\n**Docker Compose:**\n\n```bash\ndocker compose pull && docker compose up -d\n```\n\n**Docker run** — reuse the original volume paths:\n\n```bash\ndocker pull mauriceboe\u002Ftrek\ndocker rm -f trek\ndocker run -d --name trek -p 3000:3000 -v .\u002Fdata:\u002Fapp\u002Fdata -v .\u002Fuploads:\u002Fapp\u002Fuploads --restart unless-stopped mauriceboe\u002Ftrek\n```\n\n> Not sure which paths you used? `docker inspect trek --format '{{json .Mounts}}'` before removing the container.\n\nYour data stays in the mounted `data` and `uploads` volumes — updates never touch it.\n\n\u003Ch3>Rotating the Encryption Key\u003C\u002Fh3>\n\nIf you need to rotate `ENCRYPTION_KEY` (e.g. upgrading from a version that derived encryption from `JWT_SECRET`):\n\n```bash\ndocker exec -it trek node --import tsx scripts\u002Fmigrate-encryption.ts\n```\n\nThe script creates a timestamped DB backup before making changes and prompts for old + new keys (input is not echoed).\n\n\u003Ch2 id=\"reverse-proxy\">Reverse Proxy\u003C\u002Fh2>\n\nFor production, put TREK behind a TLS-terminating reverse proxy. TREK uses WebSockets for real-time sync, so the proxy **must** support WebSocket upgrades on `\u002Fws`.\n\n\u003Cdetails>\n\u003Csummary>Nginx\u003C\u002Fsummary>\n\n```nginx\nserver {\n    listen 80;\n    server_name trek.yourdomain.com;\n    return 301 https:\u002F\u002F$host$request_uri;\n}\n\nserver {\n    listen 443 ssl http2;\n    server_name trek.yourdomain.com;\n\n    ssl_certificate     \u002Fetc\u002Fssl\u002Ffullchain.pem;\n    ssl_certificate_key \u002Fetc\u002Fssl\u002Fprivkey.pem;\n\n    # 500 MB covers backup-restore uploads (capped at 500 MB server-side).\n    client_max_body_size 500m;\n\n    location \u002F {\n        proxy_pass http:\u002F\u002Flocalhost:3000;\n        proxy_http_version 1.1;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n    }\n\n    location \u002Fws {\n        proxy_pass http:\u002F\u002Flocalhost:3000;\n        proxy_http_version 1.1;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection \"upgrade\";\n        proxy_set_header Host $host;\n        proxy_read_timeout 86400;\n    }\n}\n```\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>Caddy\u003C\u002Fsummary>\n\n```caddy\ntrek.yourdomain.com {\n    reverse_proxy localhost:3000\n}\n```\n\nCaddy handles TLS and WebSockets automatically.\n\n\u003C\u002Fdetails>\n\n\u003Cbr \u002F>\n\n## Environment variables\n\n\u003Cdetails>\n\u003Csummary>\u003Cb>Full reference\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr \u002F>\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| **Core** | | |\n| `PORT` | Server port | `3000` |\n| `NODE_ENV` | Environment (`production` \u002F `development`) | `production` |\n| `ENCRYPTION_KEY` | At-rest encryption key for stored secrets (API keys, MFA, SMTP, OIDC). Recommended: generate with `openssl rand -hex 32`. If unset, falls back to `data\u002F.jwt_secret` (existing installs) or auto-generates a key (fresh installs). | Auto |\n| `TZ` | Timezone for logs, reminders and cron jobs (e.g. `Europe\u002FBerlin`) | `UTC` |\n| `LOG_LEVEL` | `info` = concise user actions, `debug` = verbose details | `info` |\n| `DEFAULT_LANGUAGE` | Default language on the login page for users with no saved preference. Browser\u002FOS 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` | `en` |\n| `ALLOWED_ORIGINS` | Comma-separated origins for CORS and email links | same-origin |\n| `FORCE_HTTPS` | Optional. When `true`: 301-redirects HTTP to HTTPS, sends HSTS, adds CSP `upgrade-insecure-requests`, forces the session cookie `secure` flag. Useful behind a TLS-terminating reverse proxy. Requires `TRUST_PROXY`. | `false` |\n| `HSTS_INCLUDE_SUBDOMAINS` | When `true`: adds the `includeSubDomains` directive to the HSTS header, extending HTTPS enforcement to all subdomains. Only effective when HSTS is active (`FORCE_HTTPS=true` or `NODE_ENV=production`). Leave `false` if you run other services on sibling subdomains over plain HTTP. | `false` |\n| `COOKIE_SECURE` | Controls the `secure` flag on the `trek_session` cookie. Auto-derived: on when `NODE_ENV=production` or `FORCE_HTTPS=true`. Escape hatch: set `false` to allow session cookies over plain HTTP. Not recommended in production. | auto |\n| `TRUST_PROXY` | Number of trusted reverse proxies. Tells Express to read client IP from `X-Forwarded-For` and protocol from `X-Forwarded-Proto`. Defaults to `1` in production; off in dev unless set. | `1` |\n| `ALLOW_INTERNAL_NETWORK` | Allow outbound requests to private\u002FRFC-1918 IPs (e.g. Immich on your LAN). Loopback and link-local addresses remain blocked. | `false` |\n| `APP_URL` | Public base URL of this instance (e.g. `https:\u002F\u002Ftrek.example.com`). Required when OIDC is enabled; used as base for email notification links. | — |\n| **OIDC \u002F SSO** | | |\n| `OIDC_ISSUER` | OpenID Connect provider URL | — |\n| `OIDC_CLIENT_ID` | OIDC client ID | — |\n| `OIDC_CLIENT_SECRET` | OIDC client secret | — |\n| `OIDC_DISPLAY_NAME` | Label shown on the SSO login button | `SSO` |\n| `OIDC_ONLY` | Force SSO-only mode: disables password login + registration, regardless of Admin > Settings. The first SSO login becomes admin. | `false` |\n| `OIDC_ADMIN_CLAIM` | OIDC claim used to identify admin users | — |\n| `OIDC_ADMIN_VALUE` | Value of the OIDC claim that grants admin role | — |\n| `OIDC_SCOPE` | Space-separated OIDC scopes. **Fully replaces** the default — always include `openid email profile`. | `openid email profile` |\n| `OIDC_DISCOVERY_URL` | Override the auto-constructed OIDC discovery endpoint (e.g. Authentik: `...\u002Fapplication\u002Fo\u002Ftrek\u002F.well-known\u002Fopenid-configuration`) | — |\n| **Initial setup** | | |\n| `ADMIN_EMAIL` | Email for the first admin on initial boot. Must be set together with `ADMIN_PASSWORD`. If either is omitted a random password is printed to the server log. No effect once a user exists. | `admin@trek.local` |\n| `ADMIN_PASSWORD` | Password for the first admin on initial boot. Pairs with `ADMIN_EMAIL`. | random |\n| **Other** | | |\n| `DEMO_MODE` | Enable demo mode (hourly data resets) | `false` |\n| `MCP_RATE_LIMIT` | Max MCP API requests per user per minute | `300` |\n| `MCP_MAX_SESSION_PER_USER` | Max concurrent MCP sessions per user | `20` |\n\n\u003C\u002Fdetails>\n\n\u003Cbr \u002F>\n\n## Data & Backups\n\n- **Database** — SQLite, stored in `.\u002Fdata\u002Ftravel.db`\n- **Uploads** — stored in `.\u002Fuploads\u002F`\n- **Logs** — `.\u002Fdata\u002Flogs\u002Ftrek.log` (auto-rotated)\n- **Backups** — create and restore via Admin Panel\n- **Auto-Backups** — configurable schedule and retention in Admin Panel\n\n\u003Cbr \u002F>\n\n## License\n\nTREK is [AGPL v3](LICENSE). Self-host freely for personal or internal company use. If you modify and offer TREK as a network service to third parties, your modifications must be open-sourced under the same licence.\n\n","TREK 是一个自托管的旅行计划工具，支持实时协作、互动地图、预算管理、打包清单等功能。项目采用 TypeScript 编写，具备 PWA 支持和 SSO 登录等现代 Web 应用特性，能够帮助用户高效规划行程并跟踪旅行中的各项细节。其内置的地图功能允许用户直观地查看路线和兴趣点，而预算追踪器则有助于控制旅行开销。TREK 适用于需要与他人共同规划旅行的个人或团队，特别是在追求个性化体验且重视隐私保护的情境下更为适用。",2,"2026-06-11 03:50:50","high_star"]