After unmounting /mnt/hdd_1 (bind) and /mnt/.felhom-raw/hdd_1 (raw),
the /mnt/hdd_1 directory remained as an empty directory. Now rmdir is
called on each bind target after unmounting so the mount point is fully
cleaned up. rmdir (not rm -rf) ensures we only remove truly empty dirs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
[ -f "$f" ] && rm -f "$f" && info "..." returns exit code 1 when the
file doesn't exist, triggering set -euo pipefail. Nuclear wipe was
silently stopping after settings.json and metrics.db (the only two
state files present), never reaching the controller/full/nuclear steps.
Fix: if [ -f "$f" ]; then rm -f "$f" && info "..."; fi
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- docker-setup.sh install_filebrowser(): removed /mnt/* auto-discovery;
FileBrowser now installed with no drive volumes. Initial config.yaml
written with /srv fallback. Controller's SyncFileBrowserMounts() takes
over on first startup and manages volumes/config going forward.
- Added ./config.yaml bind mount to initial docker-compose.yml so
FileBrowser starts correctly before controller syncs.
- Fixed ((step_num++)) → step_num=$(( step_num + 1 )) to prevent
set -euo pipefail trap when var starts at 0 (same class of bug as
the found_mounts fix in the previous commit).
- scripts/README.md: step 7 updated to reflect controller-managed volumes.
- CHANGELOG.md: added entry for all scripts changes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
((found_mounts++)) with found_mounts=0 evaluates the post-increment
expression to 0, which bash treats as exit code 1 under set -e,
silently killing the script on the first mount discovered.
Use arithmetic assignment instead to avoid the zero-exit trap.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Hub YAML is generated by Go's yaml.v3 which uses 4-space indentation.
The yaml_get helper was matching " key:" (2 spaces) so all extractions
silently returned empty — BASE_DOMAIN stayed as homeserver.local and
CF_TUNNEL_TOKEN was never set from hub config.
Strip leading whitespace before key matching, making yaml_get
indentation-agnostic.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After docker system prune, the nuclear wipe now also removes:
- /opt/docker/felhom-controller/ (compose + .env)
- /opt/docker/traefik/ (configs + acme.json)
- /opt/docker/cloudflared/ (configs)
- /opt/docker/stacks/ (empty dir)
These were left behind previously, preventing a clean redeploy since
docker-setup.sh checks for existing installations and skips steps
if directories already exist.
Also updated print_plan to show these deletions in the dry-run output.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two bugs prevented /mnt/sys_drive (and similar drives) from being detected:
1. controller.yaml is root-owned (permission denied from host), so data_dir
could not be read. Settings.json was never loaded, falling back to /mnt/*
scan only. Fix: also try `docker volume inspect felhom-controller_controller-data`
to locate the actual settings.json in the Docker volume.
2. Fallback /mnt/* scan only checked for felhom-data/ or appdata/, missing
drives that only have backups/ (e.g. sys_drive pre-v0.26.0). Fix: also
check for backups/ in the scan condition.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
'full' was ambiguously described as 'Controller + felhom-data/' making
it sound like the controller container is removed. Clarified that 'full'
runs controller-level cleanup (app containers only) and infra containers
(felhom-controller, traefik, etc.) are preserved throughout.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- NeedsSetup: only check for empty customer.id (not "demo-felhom")
- renderError: pass *http.Request to ensureCSRFToken (was nil → panic)
- Welcome template: remove redundant "v" prefix from version display
- IP detection: read HOST_IP env var for Docker container awareness
- docker-setup.sh: inject HOST_IP into generated docker-compose.yml
- Add logging for Hub config download in setup wizard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New controller features:
- Web-based setup wizard replaces docker-setup.sh interactive config
- Dual listener: :8080 (Traefik) + :8081 (direct HTTP for LAN)
- Drive scanner finds .felhom-infra-backup/ on all block devices
- Hub recovery pull (GET /api/v1/recovery/{id}) with retrieval password
- Fresh install: Hub config download or manual wizard
- CSRF protection, state persistence, Hungarian UI
- Local infra backup written to all connected drives after each backup cycle
- .felhom-infra-backup/backup.json + metadata.json with SHA256 checksum
- Hub verification: parse customer_blocked from report push response
- Limited mode after 7 days without verification
- Recovery info page on Settings + recovery-info.txt file generation
- Pending events queue: DR events sent to Hub on next report push
- docker-setup.sh v6.0.0: removed interactive wizard, minimal controller.yaml only
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- scripts/README.md: comprehensive docker-setup.sh documentation (CLI flags,
installation steps, TLS modes, hub download, wizard, safety features)
- scripts/CHANGELOG.md: version history from v1.0.0 to v5.0.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When both flags are provided, the wizard downloads a pre-configured
controller.yaml from the Hub API, extracts key variables for subsequent
setup steps, and skips the interactive wizard entirely. Falls back to
manual wizard on failure.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Major refactor of backup and storage paths:
- Per-drive restic repos at <drive>/backups/primary/restic/
- Per-app DB dumps at <drive>/backups/primary/<app>/db-dumps/
- Remove global BackupDir, DBDumpDir, ResticRepo config fields
- Add SystemDataPath config (fallback for apps without HDD)
- New backup/paths.go with pure path computation helpers
- Add GetStackHDDPath to StackDataProvider interface
- Restic methods now accept repoPath as parameter
- Cross-drive backup uses new secondary path structure
- Rename storage/ to appdata/ in scripts and compose templates
- Update protected HDD paths (storage → appdata + backups)
- Simplify backup UI (remove global path displays)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Task 1: Protected stacks with .felhom.yml (slug) are now clickable
on both dashboard and stacks pages. "Részletek" button added to
protected stack actions section. Filebrowser .felhom.yml updated
with resources metadata.
Task 2: Backup page now reads from a cached FullBackupStatus that
refreshes every 5 minutes in background + after each backup run.
Page loads instantly instead of blocking on restic/docker subprocesses.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix ValidateDump() to scan first 10 lines for header (MariaDB 11.4+ sandbox comment)
- Dashboard shows only deployed/protected stacks, heading "Telepített alkalmazások"
- Protected stacks show restart button when operational (both dashboard + stacks page)
- API blocks all actions except restart on protected stacks
- docker-setup.sh creates .felhom.yml for FileBrowser (subdomain: files)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Migrate all 7 HTML templates + CSS from Go string constants to individual
go:embed files in internal/web/templates/ (templates.go: 2150→35 lines)
- Split server.go into auth.go, handlers.go, funcmap.go (server.go: 540→120 lines)
- Rename controller subdomain from dashboard.* to felhom.* in Traefik labels
- Update documentation (CLAUDE.md, README.md, CONTEXT.md)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add orphan detection: stacks not in catalog marked as "Elavult"
- Add DELETE /api/stacks/{name} endpoint with HDD data handling
- Add GET /api/stacks/{name}/hdd-data endpoint
- Add delete confirmation modal with HDD data checkbox (Hungarian UI)
- Add filebrowser to protected stacks list
- Add scripts/hdd-setup.sh and scripts/docker-setup.sh for node setup
- Hide "Frissítés" and "Részletek" buttons for orphaned stacks
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>