Admin panel reference
The admin panel is at Settings → Admin in the top nav (visible
only to users with isAdmin: true). It groups instance-wide
configuration into seven panes.
This page is the reference that maps every field to its effect.
Instance
Section titled “Instance”The basics. Most of these were set during the first-run wizard and rarely change afterwards.
| Field | What it does |
|---|---|
| Instance name | Browser title bar text, email subject prefix |
| Public URL | Used in email links (invitations, password reset). Crucial — if this is wrong, password-reset links go to the wrong host |
| Maximum users | Cap on the user count. New registrations / invitations fail when reached. Set to 0 = unlimited |
| Registration mode | public — anyone can sign up · invite — only invited users · closed — admin-created users only |
| Default UI language | New users default to this. They can change it in their personal settings |
External APIs
Section titled “External APIs”Encrypted at rest with the auto-generated encryption key under
/app/data/secrets/encryption.key.
| Field | What it unlocks | Required? |
|---|---|---|
| AirLabs API key | Live flight enrichment (today’s flights primarily) | No |
| Aviationstack API key | Historical + future flight enrichment | No |
| OpenSky Client ID + Secret | Real-time tracking position fallback | No |
| OpenAI API key | OpenAI Vision for boarding-pass scanning | No |
| Anthropic API key | Claude Vision for boarding-pass scanning | No |
| Ollama URL | Local LLM endpoint (default http://ollama:11434) | No (defaults to bundled container) |
| Ollama text model | Model used for email parsing fallback (default gemma3:12b) | No |
| Ollama vision model | Model used for boarding-pass scanning when Ollama is the cascade default | No |
Each row has a Test connection button that hits the provider’s healthcheck endpoint. Use it after pasting a key.
The pages Flight data APIs, Ollama, and Vision parsers walk through getting each key set up.
Same fields as the SMTP page — host, port, encryption, username, password, from-address, plus a Send test button. Empty fields here mean SMTP is disabled — invitations and password-resets fall back to the “ask the admin” message.
Backups
Section titled “Backups”| Field | Default |
|---|---|
| Enabled | true |
| Schedule (cron) | 0 2 * * * |
| Retention | 14 (keep last 14 backup files) |
| Compression | gzip |
| WebDAV URL | (empty — disabled) |
| WebDAV user / password | (empty) |
Plus a Run backup now button. Full deep-dive on the Backups & Restore page.
A table of all user accounts with admin actions:
- Create user — manual user creation (no email sent)
- Send invitation — generates a single-use invite link, sends it via SMTP if configured
- Promote to admin / Demote — toggle the
isAdminflag - Force password change — sets
mustChangePassword; user must change at next login - Send reset email — generates a password-reset link, mails it via SMTP
- Delete user — cascades to their flights, achievements, tokens. Confirms with a typed-in-username challenge before destruction
The table shows username, email (if any), admin flag, registration date, last login, total flights logged.
Audit log
Section titled “Audit log”Read-only tabular view of every mutation:
| Column | Contains |
|---|---|
| Timestamp | UTC, ISO 8601 |
| User | Who triggered the action (cookie or PAT-bearing user) |
| Token | Which PAT, if PAT-authenticated. Empty for cookie sessions |
| IP | Client IP (anonymised after 7 days per server-log policy) |
| Method + path | The HTTP request that was logged |
| Resource | What changed (e.g. Flight#abc-123-def) |
| Action | CREATE / UPDATE / DELETE |
| Diff | Per-field before-and-after values |
Filter by user, action, date range, resource. Export filtered results as CSV.
The audit log is the canonical “what happened on this instance” — useful for debugging “why did this flight change”, forensics if you suspect a token leak, and compliance review.
Logging
Section titled “Logging”| Field | Default | Description |
|---|---|---|
| Log level | info | One of error / warn / info / debug / trace. Persisted across restarts |
| Log retention (days) | 14 | Older log files are pruned by the daily cleanup job |
| Pino destination | /app/data/logs/ | Files: app.log (everything), error.log (errors only), http.log (request/response), parser*.log (parser pipeline traces) |
Raise to debug for one-off troubleshooting, drop back to info
afterwards. debug adds a lot of volume to app.log —
~10× growth per day.
Log files are also tail-able from the host:
docker exec travstats-app tail -f /app/data/logs/app.log | jq .System info
Section titled “System info”Read-only “about” pane — informational only:
- TravStats version — bottom of every page in the UI, also here
- Build date — when the running image was built
- Node version inside the container
- Postgres version the database is running
- Database size — total Postgres data + indexes
- Backup count — how many backup files in
/app/data/backups/ - Pending updates — link to the Pending Updates dashboard
- Health status — same as the
/healthendpoint, refreshed live
Update banner
Section titled “Update banner”In the top-right corner of every page TravStats displays a yellow Update available badge when a newer stable release exists on GitHub. The check works as follows:
- The backend hits
https://api.github.com/repos/Abrechen2/TravStats/releases/lateston the first version-endpoint call after start - The result (latest version + release URL + release notes) is cached in process memory for 6 hours; subsequent UI loads reuse the cached value
- Only stable releases trigger the banner — RC / draft / pre-release tags are filtered out
- Pre-release suffixes on your current version are stripped
before comparison, so running
1.3.0-rc.4doesn’t pop the banner when1.3.0ships (you’re effectively running the release) - Air-gapped instances: GitHub is unreachable → the check fails silently and the badge stays hidden. No retries flood the network
If you’d rather hide the banner entirely (e.g. on a corporate
deployment where you control the upgrade cadence), there’s no
runtime toggle; suppress it at the reverse-proxy by stripping
/api/v1/version’s response, or fork the frontend to comment out
the badge.
Diagnostic export
Section titled “Diagnostic export”The Diagnostic export button builds an anonymised diagnostic bundle for filing GitHub issues. Details on what’s redacted and when to send it: Troubleshooting → Diagnostic export.
What admins can’t change here
Section titled “What admins can’t change here”Some settings deliberately live in .env (deploy-time) rather than
the admin UI (runtime):
DATABASE_URL— changing the database in flight is not a thingJWT_SECRET— auto-generated, persisted to file, never editable in UI (rotation = delete file + restart, signs out everyone)COOKIE_SECURE,CORS_ORIGIN— proxy-related; almost always auto-detected correctly. Only set in.envfor unusual proxy setupsTZ— the container’s clock. Always UTC. The UI renders in user-local time
If you need to change any of these, edit .env and restart the
stack. Everything else lives in the admin UI.