Commit Graph

338 Commits

Author SHA1 Message Date
admin 57b8f56c52 REPORT: v0.40.0 bootstrap pull+merge — live-validated on demo (guest 9201, ONLINE v0.40.0)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 13:37:10 +02:00
admin 6a594f9ec2 v0.40.0: bootstrap pull+merge onboarding (controller pulls config from hub)
Fix the onboarding 401: instead of seeding controller.yaml from the agent's
HOST hub key (which the hub's customer-scoped /api/v1/report rejects), the
controller now PULLS its full controller.yaml from the hub on first boot using
the bootstrap's retrieval passphrase (yielding the customer-scoped key) and
MERGES in the per-guest local_api block.

- internal/bootstrap: contract v1->v2 (customer.id + hub.url +
  hub.retrieval_password + local_api; drop host key/identity). MaybeIngest gains
  an injected PullFunc (keeps bootstrap free of the heavy report package),
  pulls with bounded transient-only retry, merges local_api at YAML-map level
  (preserves all hub-emitted fields), idempotent + fail-safe + never-crash.
- main.go: wire report.PullConfig as the pull adapter (maps ErrHubUnreachable
  -> ErrPullTransient; auth/not-found permanent).
- Lockstep with felhom-agent v0.19.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 13:22:37 +02:00
admin b76d8b298c REPORT: record pushed commit hash for the v0.39.1 cleanup + demo validation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 12:24:36 +02:00
admin 6e77bea4d3 v0.39.1: 8C orphan-template cleanup (delete 5 dead templates)
Remove five orphaned HTML templates left behind when slice 8C retired the
disk/storage/restore web handlers (storage_handlers.go, handler_restore.go and
the /api/storage/* + /api/restore/* routes): storage_init, storage_attach,
migrate, migrate_drive, restore. Zero .go references, zero cross-template
references, no route, no nav entry; embed is a glob so deletion is safe (14
templates remain, build + tests green). No behaviour change; the deleted pages
were already unreachable.

Also ships the live demo validation (v0.39.0) writeup in REPORT.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 12:24:13 +02:00
admin d8d1e17758 slice 9: host-health view on the monitoring page (v0.39.0)
Add agentapi HostMetrics() + a thin /api/host-metrics proxy to the agent's
new GET /host/metrics, and a 'Szerver allapota (gazdagep)' card on the
monitoring page rendering host CPU%/load/mem/CPU-temp(n/a)/uptime + per-
storage capacity bars (thin-pool fill, disk temp/wear). Polls every 8s.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 16:16:15 +02:00
admin 4c9065381b REPORT: slice 8B.2 controller half (resume at snapshotted, v0.38.0)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 15:02:30 +02:00
admin e4b69ac9e5 slice 8B.2 (controller): resume app at snapshotted, keep tracking to done (v0.38.0)
Quiesce loop resumes (StartStack + clear marker) at the snapshotted phase
instead of done -> downtime whole-backup -> until-snapshot, no consistency loss.
Keeps polling to done/failed (no overlapping backup; post-snapshot failure
observed). Stop-mode fallback to done + crash-safety preserved.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 14:54:19 +02:00
admin 6ac7167dfd REPORT: slice 8C controller half (de-privileging + disk mgmt via agent, v0.37.0)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 14:07:24 +02:00
admin 6d267b3e4d slice 8C C.3: de-privilege the controller container (legacy docker-setup template) + CHANGELOG (v0.37.0)
Dropped privileged:true + /mnt rshared + /sys + /dev + /etc/fstab + /run/udev
from the bare-metal compose template (controller no longer does disk ops). The
golden bootstrap run was already minimal (8A). Slice 8 CLOSED on the controller.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 13:59:26 +02:00
admin abe4e8e619 slice 8C Phase B.2 + C.1/C.2: retire disk subsystem + rewire disk mgmt to agent
Retired (~12.3k LOC): internal/storage/* (scan/format/attach/migrate/safety),
backup restic/crossdrive/restore_drives/disk_layout/local_infra/restore_scan/
paths + restore_app, report/infra_backup*/infra_pull, setup/scanner,
monitor/watchdog+pinger, web/storage_handlers+handler_restore. Surgically split
backup.Manager to app-data only (DB dumps + volume tars + app restore; dropped
restic + cross-drive + snapshot history). Fixed router/main/web wiring.
Added agent-backed disk API (web/agent_disk_handlers.go): /api/disks list/
assign/eject/format proxying agentapi; data-bearing format refusal -> HTTP 409
'operator authorization required'. report/config_pull.go keeps the setup
fresh-install config download. go build + go test green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 13:57:27 +02:00
admin 0294513906 slice 8C Phase B.1: agentapi disk client (Disks/AssignDisk/EjectDisk/FormatDisk)
ErrFormatRefused surfaces the agent's data-bearing refusal distinctly. Tests:
list, blank format OK, data-bearing refused, eject dependents.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 13:23:00 +02:00
admin 9788ee64fa REPORT: slice 8B controller half (app-consistent backup quiesce loop, v0.36.0)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 11:04:59 +02:00
admin 68fc153d9c slice 8B (controller half): app-consistent backup quiesce loop (v0.36.0)
internal/quiesce: poll /backup/due -> quiesce (stop app stacks) -> POST /backup
-> poll /backup/status -> unquiesce (restart exactly those). Crash-safety:
persisted marker before stopping, guaranteed unquiesce (defer), max-quiesce
guard, startup Recover, single-flight. agentapi BackupDue/StartBackup/
BackupStatus; stacks.RunningAppStacks(); config QuiesceConfig; main wiring.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 10:44:52 +02:00
admin 10685b771c REPORT: slice 8A controller half (bootstrap ingestion + pinned local-API client, v0.35.0)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 10:02:25 +02:00
admin 2a0d9a1b7a slice 8A (controller half): bootstrap.json ingestion + pinned agent local-API client (v0.35.0)
internal/bootstrap: first-run bootstrap.json ingestion (decision (c)) — seed
controller.yaml + skip setup; idempotent + fail-safe. internal/agentapi:
minimal pinned local-API client (leaf-cert SHA-256 pin, fails closed). config
LocalAPIConfig; startup /storage connectivity probe.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 09:47:54 +02:00
admin 086281b582 docs: reflow CLAUDE.md; unify REPORT/CHANGELOG convention; add no-secrets rule
Reflow removes hard mid-paragraph line wraps (code blocks and tables untouched);
rendered output unchanged. Adds the uniform CHANGELOG (cumulative) / REPORT
(overwrite-latest) convention plus a no-secrets rule. Docs/meta only, no version bump.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 20:54:45 +02:00
admin 27c945d698 update 2026-06-08 20:07:56 +02:00
admin fabb881ab8 Merge pull request 'chore: rework references for repo rename deploy-felhom-compose -> felhom-controller' (#2) from chore/rename-repo-refs into main
Reviewed-on: #2
2026-06-08 11:56:47 +00:00
admin e9ca42060c chore: rework references for repo rename deploy-felhom-compose -> felhom-controller
Repo renamed on Gitea (admin/deploy-felhom-compose -> admin/felhom-controller).
Updates clone URLs, clone dirs, the customer bootstrap URL, build.sh, BUILDING.md,
README.md, CLAUDE.md, CONTEXT.md and TASK.md to the new name. No functional change:
Go module path and Docker image path (both already 'felhom-controller') untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 13:38:27 +02:00
admin a54ec5a598 Merge pull request 'refactor: extract app-data-backup into internal/appbackup (no behaviour change)' (#1) from refactor/extract-appbackup into main
Reviewed-on: admin/deploy-felhom-compose#1
2026-06-08 10:56:51 +00:00
admin a4de90def3 refactor: extract app-data-backup into internal/appbackup (no behaviour change)
Extract the stateless, keep-side app-data backup primitives out of
internal/backup/ into a new self-contained internal/appbackup/ package:
- dbdump.go: DB dump discovery/execution (DiscoverDatabases, DumpOne, ...)
- appdata.go: StackDataProvider + app-data/volume discovery, HumanizeBytes
- paths.go: keep-side path helpers (AppDBDumpPath, AppVolumeDumpPath, AppDataDir)

backup/ keeps every name available via type/const aliases + one-line function
forwarders (appbackup_bridge.go), so the still-present delete-side code
(restic, cross-drive, drive-mount) and the both-side consumers (web/api/report)
compile unchanged. The keep-only consumers appexport and storage are rewired to
import appbackup directly and no longer import backup.

This is the Part-2 prerequisite for the Proxmox port: appbackup has zero
references to restic/cross-drive/drive-mount and does not import backup, so the
delete-side can later be removed without breaking app-data backup or appexport.

Behaviour-preserving: pure move + import/qualifier rewrites, no logic edits.
The four Manager methods (RunDBDumps/DumpAppVolumes/DumpAppVolumesSafe share the
delete-side mutex/status state; RestoreAppFromTier2 reads the cross-drive mirror)
intentionally stay on Manager and delegate to appbackup — for the re-platform step.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 11:01:39 +02:00
admin fb11c3b75a feat: backup safety — stop-before-dump, streaming restore, health check, per-app restic, infra configs (v0.34.0)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 08:56:48 +01:00
admin 783830a9d4 fix: add HasVolumeData to AppBackupRow for template rendering
The backups page template references .HasVolumeData on the status table
rows but the AppBackupRow struct was missing this field, causing a
template error.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 21:48:22 +01:00
admin c929948f27 feat: Docker volume backup, Tier 2 restore, restore dropdown fixes (v0.33.0)
- Add Docker named volume backup to Tier 1 (dump to tar, include in restic)
  and Tier 2 (copy tars to rsync mirror _volumes/ dir)
- Fix volume name resolution: use project-prefixed names (mealie_mealie_data)
- Fix double Tier 1 in restore dropdown: filter snapshots by app's home drive
- Add Tier 2 restore: RestoreAppFromTier2() restores from rsync mirror
- Show Tier 2 entry in restore dropdown when cross-drive backup succeeded
- Add .fab import link in restore section
- Volume-aware restore type banners and backup content labels

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 21:43:02 +01:00
admin 5bf13ca19d move optional config from app info page to deploy/settings page
Users couldn't find metadata provider fields (IGDB, ScreenScraper, etc.)
on the app info page. Move them to the deploy page where all other
settings (integrations, geo-restriction) already live.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 20:04:51 +01:00
admin 54390c456c move optional config from app info page to deploy/settings page
Users couldn't find metadata provider fields (IGDB, ScreenScraper, etc.)
on the app info page. Move them to the deploy page where all other
settings (integrations, geo-restriction) already live.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 20:04:28 +01:00
admin 36afd828a1 fix: FileBrowser reads stale config on fresh deployments
The gtstef/filebrowser image bakes FILEBROWSER_CONFIG=/home/filebrowser/data/config.yaml,
but controller mounts config at /home/filebrowser/config.yaml. Override the env var in both
generateFileBrowserCompose() and docker-setup.sh so FileBrowser reads the controller-managed
config with proper sources and database path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 18:51:59 +01:00
admin b4bda38fa1 feat: format empty partitions on system disk (v0.32.6)
Detect and offer to format empty (no filesystem) partitions on the system
disk. Adds IsSystemPartition() for granular per-partition safety checks
instead of blocking the entire system disk. Init wizard shows formatable
partitions with appropriate warnings. Add felhotest demo node to docs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 16:54:16 +01:00
admin 2c0064ac87 updated CF tunnel config 2026-02-27 16:29:00 +01:00
admin 9b13c0e21c feat: Tier2 backup pauses when destination drive is inactive (Inaktív)
Deactivated drives (Schedulable=false) now treated like disconnected for
Tier2 backups. New IsStoragePathSchedulable() checks active+connected+not
decommissioned. UI shows yellow "Cél meghajtó inaktív" badge, scheduler
skips silently with WARN log.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 10:59:56 +01:00
admin 4fd907a09e fix: Tier2 backup status now detects drives removed from storage (not just disconnected)
Previously, removing a storage drive from the controller only marked it as
disconnected if the StoragePath entry still existed with Disconnected:true.
Drives removed entirely from storage_paths were invisible to the check,
causing Tier2 backup UI to show green "Sikeres" and scheduler to attempt
backups to a no-longer-managed destination.

New IsStoragePathKnown() method covers both cases. UI shows yellow
"Cél meghajtó leválasztva" and scheduler skips silently.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 10:48:00 +01:00
admin dd79918234 docs: update CHANGELOG and README for v0.32.5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 10:02:03 +01:00
admin f19c6fb0c9 fix: USB badge detection for bind-mounted drives + graceful Tier2 backup on disconnected destinations
- IsUSBDevice/diskModel: strip findmnt bind-mount suffix [/subdir] before
  parsing device path (fixes USB badge not showing for attach-wizard drives)
- crossdrive.go: skip disconnected src/dest drives with WARN log instead of
  returning error (prevents noisy error status in settings.json)
- handlers.go: detect Tier2 destination disconnection, set yellow status dot
  instead of red, skip ValidateDestination for disconnected paths
- backups.html: new template branch showing "Cél meghajtó leválasztva" badge
  with grayed-out info and hidden "Futtatás most" button

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 09:59:29 +01:00
admin 1155a0522b docs: update CHANGELOG and README for v0.32.4
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 09:23:16 +01:00
admin 62d26be8ae feat: include controller in app telemetry reports
Add the felhom-controller container as a special entry in the
app_telemetry array sent to the hub. This reuses all existing hub
infrastructure (storage, aggregation, UI) with zero hub-side changes.

The controller's memory/CPU metrics and log warnings/errors are now
collected alongside app telemetry, giving the hub visibility into
controller health, memory trends, and known issues.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 09:19:27 +01:00
admin af1dd14933 fix: standardize log prefixes, remove duplicates, add missing module tags
Second-pass logging cleanup: consistent [LEVEL] [module] format across
all 41 files. Remove stale prefixes ([CF], [SYNC], [SCHED], [API],
[STORAGE], [HEALTH], [ROLLBACK]). Remove 5 duplicate log lines. Gate
ungated DEBUG lines. Fix wrong log levels (restore start WARN→INFO).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 21:20:09 +01:00
admin 8e61cd7ec4 feat: comprehensive INFO/WARN/ERROR logging across all controller modules
Add structured operational logging at INFO, WARN, and ERROR levels to
every controller module. Standardize custom prefixes ([GEO], [SCHED],
[SYNC]) to use [INFO/WARN/ERROR] [module] format. Fix misleveled logs
(WARN->ERROR for data loss scenarios, WARN->INFO for routine operations).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 19:58:27 +01:00
admin 95c821deb2 feat: comprehensive debug logging across all controller modules
Add detailed [DEBUG] logging to every controller module when
logging.level is set to "debug". Each module with stateful debug
uses SetDebug(bool) wired from main.go. Covers stacks, backup,
cloudflare, integrations, system, monitor, settings, scheduler,
web handlers, storage, metrics, API, selfupdate, and assets.

Also includes the app export/import (.fab bundles) feature from
v0.32.0 and its debug page integration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 18:14:43 +01:00
admin f6caea8067 fix: scope FileBrowser DB reset to restore-only path
Normal storage add/remove no longer nukes the FileBrowser database volume.
A .fb-reset flag file is written during restore and consumed on next startup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 15:35:22 +01:00
admin 1e9300e5a0 fix: reset FileBrowser database when sources change
FileBrowser Quantum caches user source preferences in its SQLite
database. After a restore, the config.yaml gets correct sources but
the database still references the old "srv" source from docker-setup.sh
initial install. Now SyncFileBrowserMounts() detects when sources
changed and runs docker compose down -v to reset the database before
recreating.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 15:26:38 +01:00
admin a47cf964e5 fix(setup): redirect to port 8080 after restore
After restore, the setup server (port 8081) exits and the main
controller restarts on port 8080. waitForRestart() now polls port
8080 using no-cors mode and redirects there when it responds.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 15:15:53 +01:00
admin 168a921f68 fix(docker-setup): flush tee output before exit
The exec > >(tee ...) process substitution has a race condition where
the main shell exits before tee finishes printing. The print_summary
output was written to the log file but never displayed on terminal.
Added sleep 0.5 to let tee flush.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 15:11:11 +01:00
admin 80b756f0e4 fix: mount drives after restore + poll-based redirect
Restore flow now calls MountDrivesFromLayout() after writing config,
which mounts drives by UUID and adds fstab entries. Previously drives
from the infra backup were never mounted, causing "Adattároló nem
elérhető" warnings.

Post-restore redirect now polls until the controller responds instead
of using a fixed 5-second timeout that was too short for container
restart.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 15:07:38 +01:00
admin c0cdd95e56 feat: infra backup retention + version picker
Hub: GFS retention (7d/4w/3m, ~14 versions) in new infra_backup_versions
table. Recovery endpoint supports ?version=ID. New /versions API endpoint.
Dashboard shows backup history.

Controller: local drive backups rotated into history/ (last 5 versions).
Setup wizard shows version picker for Hub restores when multiple versions
exist. Scan results enriched with app names, disk count, history badge.
Local restore supports historical versions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 14:47:40 +01:00
admin 8f49bcc4cc fix: atomicWriteFile falls back to direct write on bind mounts
Rename fails with EBUSY on Docker bind-mounted files (e.g. controller.yaml).
Fall back to os.WriteFile when os.Rename fails.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 14:13:23 +01:00
admin eec1afae23 fix(setup): start executeHubRestore goroutine in auto-process and manual hub restore
Both autoProcessHubRestore and processHubRestore rendered the progress
page (setup_restore_exec) without starting the executeHubRestore()
goroutine, causing the template to poll forever showing "Indítás...".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 14:07:28 +01:00
admin 1e8a562bd3 feat(setup): hub mode triggers setup wizard with infra backup restore
docker-setup.sh --hub-customer now generates a minimal controller.yaml
(no customer.id) instead of installing full hub config, triggering the
setup wizard on first run. Hub credentials are passed via env vars
(FELHOM_SETUP_CUSTOMER_ID, FELHOM_SETUP_PASSWORD) so the wizard
auto-fills and auto-processes Hub API calls.

Welcome page shows three options in hub mode: restore from Hub (primary),
restore from local drives, or fresh install. On error, falls back to
manual form with error displayed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 13:58:31 +01:00
admin 5f423b6510 removed ".env" references from comments, documentation 2026-02-26 09:34:00 +01:00
admin f6b09ca99e ui: brand-consistent button and card styling
Replace traffic light colors (green/yellow/red) with brand palette:
- Primary actions: blue gradient
- Secondary actions: ghost/outline
- Destructive actions: ghost with red hover (modals keep filled red)
- Running cards: blue glow instead of green border
- Bottom-aligned buttons via flexbox column layout

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 21:32:44 +01:00
admin d7e5332a11 fix(integrations): fix Nextcloud-OnlyOffice callback URL and trusted_domains
StorageUrl was missing trailing slash — NC's OO connector does string
replacement of server URL (ending with /) with StorageUrl, so without
trailing slash "apps/" merges into hostname producing "nextcloudapps".

Also add "nextcloud" to NC trusted_domains so OO Document Server's
internal callbacks (Host: nextcloud) are not rejected.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 21:19:39 +01:00