Skip to content

Settings

Settings are split between per-user preferences (your own account) and instance-wide admin settings (anyone with isAdmin: true).

Anyone signed in can change these on their own account.

  • Change password — current password + new password (8+ characters). Logs you out everywhere except the current session. There’s no second factor by default; use a password manager.
  • Forgot password — sends a reset link via SMTP. Configured by the admin under Admin → Settings → SMTP; if SMTP isn’t set, the link won’t be sent and the page falls back to “contact your admin”.
  • Force password change on next login — for admins resetting another user’s password without seeing it.
  • Language — German (default) or English. Lives in your profile and follows you across browsers when you sign in elsewhere.
  • Units — kilometres / miles, °C / °F, 12 h / 24 h. The dashboard, statistics, and exports all respect this.
  • Theme — Dark (default) / Light / Auto-from-system.

Per-user email reminders before upcoming flights. Default: off, you have to opt in.

  • Notification email — separate address for reminder mails (often you don’t want them at your admin mail account, but at travel@…). Empty = reminders go to your account email
  • 24 h reminder (checkbox) — sends a mail exactly 24 h before the next flight’s departureTime (timezone-aware, departure time is resolved against the IANA timezone of the departure airport)
  • 2 h reminder (checkbox) — sends a mail 2 h before departure. Useful for check-in / gate-change polling reminders

A scheduler (reminderScheduler) runs every 15 minutes and checks which scheduled flights fall into the next 24 h ± 15 min or 2 h ± 15 min window. Each flight + reminder type gets exactly one mail (in-process sentReminders set).

If SMTP isn’t configured (no host under Admin → Settings → SMTP), reminders fire silently into the void — the scheduler logs a warning but doesn’t surface an error to you. Once SMTP is added afterwards, mails start going out.

If SMTP fails for a while (provider outage), reminders for the outage window are simply lost — there’s no backlog. Reminders are best-effort, not guaranteed; don’t rely on them for anything that absolutely must arrive on time.

Tags are personal — each user has their own set. Manage them in Settings → Tags:

  • Create — type a name; saved on first save.
  • Rename — updates every flight that carries the tag in one operation.
  • Merge — pick two tags, choose which one survives, the loser’s flights are reassigned.
  • Delete — removes the tag from every flight; the flights themselves are not touched.

API tokens for scripts and external tools. Settings → API Tokens:

  • Create — name + scope (read, write, admin). Plaintext token shown once on creation; copy it then, you can’t view it again.
  • Formatts_pat_… followed by a long random suffix. Stored as a bcrypt hash plus a lookup hash; the plaintext never touches disk.
  • UseAuthorization: Bearer ts_pat_… on any authenticated endpoint.
  • Scopesread blocks all mutations (POST/PUT/PATCH/DELETE → 403), write covers normal flight CRUD, admin is required for every /admin/* endpoint even if your account has isAdmin: true.
  • Per-token rate limits — each PAT gets its own pat:<id> rate-limit bucket so an aggressive automation script can’t lock you out of the web UI.
  • Revoke — instant. The token is rejected on the next request.

OpenAPI spec: https://your-instance/api/v1/openapi.json. Swagger UI: https://your-instance/api/v1/docs.

Only visible if isAdmin: true on your user. All instance-level settings live here so you never have to edit env vars after install.

  • Name — what the browser title says, what shows in invitation emails.
  • Public URL — used in emails. Set this to whatever URL users actually hit.
  • Maximum users — cap on the user table. Useful for invite-only setups.
  • Registration mode — public sign-up vs invite-only. Flip any time.

API keys are encrypted at rest with the auto-generated encryption key under /app/data/secrets/.

  • AirLabs — for live flight enrichment (route, aircraft, scheduled times).
  • Aviationstack — paid tier; covers more dates than AirLabs free tier.
  • OpenSky — free, real-time, but limited historical lookup.
  • Ollama URL + model — default http://ollama:11434 and gemma3:12b. Empty URL disables LLM-backed parsing.
  • Host / port / TLS / username / password / from-address — standard outbound SMTP.
  • Test mail button sends a one-line “TravStats SMTP test” to whatever address you specify.
  • Used for: invitation emails, password reset, flight reminders.
  • Schedule — cron expression, default daily at 02:00 UTC.
  • Retention — how many backup files to keep before pruning.
  • WebDAV sync — optional Nextcloud / HiDrive / Owncloud target so backups leave the host.

Tabular view of all accounts. From here:

  • Create a user (or send an invitation if SMTP is configured).
  • Promote / demote admin status.
  • Force a password change on next login.
  • Delete a user (cascades to their flights, achievements, tokens).

Every mutation gets a row: who did it, when, what changed, and what the value was before. Filter by user, by action, by date range. Exports as CSV.

The yellow Update badge in the header is global (all admins see it). The “Ignore this version” action is per-user.

LayerPersisted inExample
Per-user preferencesusers.preferences_json (Postgres)UI language, units, theme
Personal tagstags tableEach user has their own set
API tokenspersonal_access_tokens tableHashed bcrypt + lookup hash, scope, rate-limit bucket
Instance settingsinstance_settings (Postgres)Name, registration mode, max users
API keys / SMTP / Ollamainstance_settings (encrypted)AES-encrypted with /app/data/secrets/encryption.key
Boot-time secrets/app/data/secrets/ (file system)jwt.secret, encryption.key

The only env-vars TravStats reads at runtime are DATABASE_URL, COOKIE_SECURE, CORS_ORIGIN, TZ, and OLLAMA_URL (the last only to seed the default; admins can change it from the UI). Everything else is in the database, which is what makes the data volume the only thing you need to back up.