docs: the key check, the restore guard, the new probes, failed offline changes and reminders

Updates the wiki for the changes in this branch: TREK refuses an
ENCRYPTION_KEY that disagrees with the key file, the rotation script
covers the AI Parsing key and moves the file along, a restore refuses a
newer backup and keeps the replaced database, the chart's startup and
readiness probes, PORT and extraEnv, retrying or discarding failed
offline changes, trip reminders catching up, and why a Portainer
recreate used to keep reporting the old version.
This commit is contained in:
Maurice
2026-10-07 17:11:56 +02:00
parent 6b037e0fa0
commit 40bce5554d
8 changed files with 39 additions and 14 deletions
@@ -36,7 +36,7 @@ let warnedUnparseable = false;
* rc of 4.0 IS 4.0.
*
* A null host NEVER blocks anything (see {@link hostSatisfies}). This is deliberate:
* APP_VERSION is a Docker build ARG that defaults to the literal string `dev`, and an
* a source install can set APP_VERSION to anything (`dev`, a branch name), and an
* unversioned build must stay fully usable. The warning exists so that a MISCONFIGURED
* APP_VERSION in production — which silently switches this whole gate off — is visible
* in the logs instead of being discovered when an incompatible plugin misbehaves.
+3
View File
@@ -40,6 +40,9 @@ 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.
3. **Not from a newer TREK** — a backup whose database a newer release migrated is refused with `This backup was made by a newer TREK version. Update TREK before restoring it.` Restoring it would leave this version unable to start.
The database being replaced is kept as `data/pre-restore-<time>.db`, so a restore of the wrong archive can be undone by hand. Delete these copies once you no longer need them.
Either way, TREK asks first in a **Restore Backup?** dialog that names the file, warns that all current data (trips, places, users, uploads) will be permanently replaced, and suggests creating a backup of the current state first. **Yes, restore** starts it; when it is done the page reloads.
+4 -4
View File
@@ -33,7 +33,7 @@ The encryption derives a key from `ENCRYPTION_KEY` using SHA-256 (with a domain
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.
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. If that file already holds a **different** key, TREK refuses to start: the stored secrets are encrypted with the file's key, and starting with another one would make them unreadable and overwrite the only copy of the old key. Set the variable back to the value in the file, remove it, or rotate the key with the script below.
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`.
@@ -85,13 +85,13 @@ The script:
- `trek_photos`: `passphrase`
- `document_connections`: `secrets` (the one encrypted blob per store and trip, including tokens the store handed out itself, such as Synology's device token)
- `trip_document_links`: `webhook_secret`
- `addons.config`: the instance-wide API key of the AI Parsing addon
5. Reports counts of migrated, already-migrated, skipped (empty), and errored values.
**Not covered by the script:** the instance-wide API key of the AI Parsing addon (`addons.config`). It stays encrypted under the old key and reads back as empty afterwards, so enter it again under **Admin > Addons** (the fields under **AI Parsing**).
6. Writes the new key to `.encryption_key` next to the database, when that file exists, so the file and the secrets agree again.
After a successful migration:
1. Update `ENCRYPTION_KEY` in your environment to the new value.
1. If you supply the key through `ENCRYPTION_KEY`, update it to the new value. (TREK refuses to start while the variable and the key file disagree.)
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.
+23 -4
View File
@@ -62,6 +62,8 @@ If `existingSecret` uses a different key name than `ENCRYPTION_KEY`, specify it
> **Note:** If both `generateEncryptionKey` and `existingSecret` are set, `existingSecret` takes precedence. Only one method should be active at a time.
> **GitOps:** `generateEncryptionKey` reads the existing secret from the cluster to keep the key across upgrades. Under `helm template`, ArgoCD or Flux the chart cannot do that and renders a new key on every sync. TREK then refuses to start rather than lose every stored secret (see [Encryption-Key-Rotation](Encryption-Key-Rotation#key-resolution-order)). Use `existingSecret` in those setups.
> **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.
@@ -196,15 +198,32 @@ resources:
### Health Probes
Liveness and readiness probes are configurable under `probes`. The defaults hit `/api/health` on port 3000 and match what the chart shipped before, so an existing install renders the same manifest.
Startup, liveness and readiness probes are configurable under `probes`:
- **startup** hits `/api/health` and gives a first boot, a long migration or a restore at boot up to ten minutes (`failureThreshold: 60` × `periodSeconds: 10`) before liveness takes over.
- **liveness** hits `/api/health`, which only says the process answers. A long restore does not fail it.
- **readiness** hits `/api/health/ready`, which also asks the database. While the database does not answer, the pod stops getting traffic without being restarted.
```bash
helm install trek trek/trek --set probes.liveness.initialDelaySeconds=60 --set probes.readiness.periodSeconds=20
helm install trek trek/trek --set probes.startup.failureThreshold=120 --set probes.readiness.periodSeconds=20
```
Raise `initialDelaySeconds` on slow storage or after a large migration, where the first start can outlast the default and leave the pod restarting in a loop. Overrides are merged over the defaults, so setting one key keeps the rest. To switch a probe to `exec` or `tcpSocket`, clear the shipped handler in the same override (`--set probes.liveness.httpGet=null`), otherwise Kubernetes rejects the pod with "may not specify more than 1 handler type". Set `probes.liveness=null` to drop a probe entirely.
Overrides are merged over the defaults, so setting one key keeps the rest. To switch a probe to `exec` or `tcpSocket`, clear the shipped handler in the same override (`--set probes.liveness.httpGet=null`), otherwise Kubernetes rejects the pod with "may not specify more than 1 handler type". Set `probes.startup=null` to drop a probe entirely.
Leave `env.PORT` at `3000`. The chart passes it to the server, but `containerPort` in `deployment.yaml` and `targetPort` in `service.yaml` are fixed at 3000, so a different value makes the server listen where nothing routes to it. Changing it means patching both templates as well as `service.port` and `probes.*.httpGet.port`; `service.port` alone is not enough.
`env.PORT` can be changed: the container port is named `http`, and the Service and every probe point at that name, so they follow it.
### Further environment variables
The `env` block lists the common settings. Anything else goes in `extraEnv` (plain values) or `extraEnvFrom` (whole ConfigMaps or Secrets):
```yaml
extraEnv:
- name: SESSION_DURATION
value: 7d
extraEnvFrom:
- secretRef:
name: trek-smtp
```
### Ingress
+1 -1
View File
@@ -43,7 +43,7 @@ The following events are configurable in user settings:
|-------|-------------|
| `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 |
| `trip_reminder` | Reminder before a trip starts. Sent once per start date, at 09:00 in the instance's `TZ`; a day the server was down is caught up on the next run, and a trip moved to a new start date is reminded again |
| `todo_due` | A to-do assigned to you, or in a trip you're part of, is due soon |
| `vacay_invite` | You were invited to fuse vacation plans |
| `vacay_share` | Someone shared their vacation calendar with you (view only) |
+1 -1
View File
@@ -92,7 +92,7 @@ If a change you made offline collides with a newer change on the server, it is s
### Stats & cache
The stats panel shows cached trips, pending changes, conflicts and failed changes. **Clear cache** removes all offline data from IndexedDB after you confirm it in TREK's dialog (you can re-sync any time while online). Each cached trip entry shows its date range, place/file count and last successful sync.
The stats panel shows cached trips, pending changes, conflicts and failed changes. A change the server keeps refusing with a server error is retried with growing gaps (from 30 seconds up to about two hours) and only holds back the other changes of its own trip; after eight attempts it counts as failed. Failed changes come with **Try again** and **Discard**: discarding keeps the server's version, and the next sync puts it back on the device. **Clear cache** removes all offline data from IndexedDB after you confirm it in TREK's dialog (you can re-sync any time while online). Each cached trip entry shows its date range, place/file count and last successful sync.
## Limitations
+4 -3
View File
@@ -1451,9 +1451,10 @@ can run rather than the newest published, so shipping a 2.0.0 that needs TREK 4
doesn't strand 3.x users. And an **update** that would move a working plugin out of
compatibility is refused rather than performed.
One gap, by design: a host whose `APP_VERSION` is not a semver version — the Docker
build arg defaults to the literal `dev` — has nothing to compare a range against, so
the check is skipped and an unversioned build installs anything. Plugins should still
One gap, by design: a host whose version is not a semver version (a source install
with `APP_VERSION` set to something like `dev`) has nothing to compare a range
against, so the check is skipped and an unversioned build installs anything. An image
built without a version argument reports the version in its `package.json`. Plugins should still
guard optional `ctx.*` namespaces.
**Permissions** — the commonly-used core subset below; the **full list of 65**
+2
View File
@@ -143,6 +143,8 @@ Open the **Stacks** list, click the TREK stack, then click **Redeploy**.
![Edit stack page with an arrow pointing to the Update the stack button](assets/portainer-update-stack.png)
Portainer's **Recreate** on a single container keeps that container's environment, which on images before 4.4 included the previous release's `APP_VERSION`. TREK then kept reporting the old version and open apps did not switch to the new interface. Images from 4.4 on take the version from a file inside the image, so a recreated container reports the image it actually runs.
See [Install-Portainer](Install-Portainer) for the full installation walkthrough.
## Unraid