docs: v0.61.0 CHANGELOG + README (F1 mem/F17 restore/F5 route) + FIXSPEC statuses + REPORT

This commit is contained in:
2026-06-14 10:25:00 +02:00
parent 4989513a96
commit 84979932e7
5 changed files with 148 additions and 56 deletions
+25 -6
View File
@@ -160,12 +160,16 @@ The app catalog lives in a separate Git repository. The controller:
- User-configurable inputs (admin password, language, storage path) remain editable
- Section header prompts the user to note down any passwords they need
3. `checkBeforeDeploy()` JS guard fetches live state first (prevents double-deploy from another tab)
4. **Memory validation** uses real system memory from `/proc/meminfo`:
- `usable_memory = total_ram - reserved_memory_mb` (default 384MB reserved)
- `system.GetMemoryMB()` returns real-time total and used memory (not declared reservations)
- Hard block if `used_mb + new_request > usable_memory`
- `CommittedMemory()` (declared sum) still used for soft overcommit warning only
- Deploy page shows real memory usage bar (not declared reservations)
4. **Memory validation** (F1, v0.61.0): the controller runs as a Docker container inside an LXC, where
`/proc/meminfo` shows the **Proxmox host's** RAM (no lxcfs in the container) and the container's own
cgroup is unlimited (the guest cap lives on the LXC ancestor). So the guest cap is read from the
**Docker daemon** (`system.GuestMemTotalMB()``docker info` MemTotal — the daemon runs in the LXC and
reports the guest's lxcfs-backed RAM; the cgroup limit is preferred when present, e.g. non-nested):
- `usable_memory = guest_cap - reserved_memory_mb` (default 384MB reserved)
- Hard block if `committed_used + new_request > usable_memory`, where `committed_used` =
`CommittedMemory()` (sum of running apps' mem requests) — the guest-wide RSS is not observable from
the container, so the controller's own committed accounting is the accurate, cheap "used".
- `/api/system/info` reports the guest cap as total and committed memory as used.
4b. **Docker-data volume reserved-buffer gate (v0.58.0, storage-split prevention layer):** the OS rootfs
and Docker data are split onto separate volumes; infra (controller/traefik/cloudflared/filebrowser)
shares the one Docker data-root (`/var/lib/docker`) and is protected by **prevention, not placement**.
@@ -265,6 +269,12 @@ When app templates are updated (e.g., a new `APP_KEY` secret is added to `.felho
| Restarting | Yellow | "Ujrainditas..." | Restart loop |
| Not deployed | Gray | "Nincs telepitve" | Compose file exists, not deployed |
**Route-unpublished indicator (F5, v0.61.0).** Traefik's Docker provider only publishes a route to a
container that is healthy (or has no healthcheck), so an `unhealthy`/`restarting` deployed app returns a
hard **404** at its URL even though the container is running. The `routeUnpublished` template helper
(`funcmap.go`) drives a distinct "URL nem elérhető útvonal nincs publikálva" indicator on the dashboard
and stacks cards for such apps, so a dead URL isn't mistaken for a merely-degraded-but-reachable one.
#### Controller-side Health Probes (`internal/stacks/healthprobe.go`)
For apps that declare a `healthcheck:` section in `.felhom.yml`, the controller probes the container directly over the Docker network (both are on `traefik-public`). This complements Docker-level healthchecks and is the **only** health mechanism for distroless/scratch images that lack shell utilities.
@@ -404,6 +414,15 @@ backups/primary/<app>/
env comes from `StackDataProvider.GetStackRecoveryInfo` (excludes secret-named + encrypted values, so
the capture never touches a secret). `data_key` fields are marked in `.felhom.yml`
(`DeployField.DataKey`).
- **Restore replays the DB dump (F17, v0.61.0).** `RestoreFromRecoveryUnit` (and the `RestoreApp`
fallback) stops the app → restores named-volume tars → recreates the compose definition + redeploys
with the recovered env → **replays each `db-dumps/*.sql` into the now-running DB** via
`backup.reimportDBDumps``appbackup.ImportDump` (psql / mariadb client, using the live container's own
discovered credentials). The DB replay runs AFTER the volume restore, so the **logical SQL dump wins**
over any volume-tar copy of the database (the dumps use DROP/CREATE — `pg_dump --clean --if-exists`,
`mariadb-dump` default `--add-drop-table` — so replay is idempotent). Volume-restore and DB-import
failures now **surface** (restore returns an error) instead of a swallowed WARN. Prior to v0.61.0 the
per-app restore never replayed the `.sql`, so DB-resident data did not come back.
#### Tier 2 — off-drive copy (Phase 3, v0.55.x)