DR recipe slice (hub half), grounded in SPIKE-dr-recipe-2026-06-16. The hub
receives two additive dr_recipe halves on the existing report paths (agent
storage/guest/PBS on host-report; controller customer/apps on the controller
report), stores them PLAINTEXT in a DEDICATED dr_recipe table keyed by customer
(each half preserves the other), and AssembleDRRecipe stitches them into one
operator-readable recipe (ignore-unknown + version-skew tolerant).
View: a DR-recipe panel on the customer page + GET /customers/{id}/dr-recipe.json
download (operator-auth, no secrets to redact). Plaintext-at-rest is correct —
the recipe is the clean inverse of the retired infra-backup.
Tests: store round-trip (each half preserves the other), assemble-matches-golden,
ignore-unknown + version skew, partial halves, no-secrets sweep. Manifest tag
bumped to v0.13.0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase-1 of SPIKE-infra-backup-2026-06-15. The infra-backup mechanism was dead
since slice 8C yet stored plaintext customer secrets at rest (app-secret key,
restic password, Cloudflare tokens) — a zero-knowledge violation — and its
absence made the daily expected_backup_missed email fire for healthy customers.
- Repoint monitor.CheckBackupDeadlines backup half to the agent host-report's
PBS snapshots (+vzdump): alarm only on no-backup / >26h stale / verify failed.
Keep the db_dump half. No host-report → no backup alarm (liveness owns that).
New store.GetLatestHostReportJSON. Tests incl. a companion that fails pre-fix.
- Remove the infra-backup endpoints, store methods/types, and operator panel;
/recovery now returns config_yaml only.
- migrate(): DROP infra_backup_versions/infra_backups + VACUUM (+wal_checkpoint)
to physically reclaim the plaintext pages, gated on table existence.
Flagged out-of-scope: exposed creds need operator rotation; legacy reports table
holds historical plaintext restic_password rows (separate leak, not purged here).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Restores notify/templates.go, store/telemetry.go, web/configs.go to upstream —
those were alignment-only churn from a tree-wide gofmt, not part of slice 3. Keeps
the host-domain diff additions-only.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- hub/internal/web/templatefetcher.go: raw-template URL now points at the renamed
repo (was relying on Gitea's post-rename redirect)
- documentation/ (moved here from the felhom-agent repo): fix controller-source path
refs (deploy-felhom-compose -> felhom-controller) and the platform repo name
(proxmox-controller -> felhom-agent)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the hardcoded 60s meta-refresh with a JavaScript-based timer
and a toggle switch in the page header. The preference persists across
page loads via localStorage (enabled by default).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New infra_backup_versions table with GFS pruning (~14 versions per
customer). Recovery endpoint supports ?version=ID. New /versions API.
Dashboard shows collapsible backup history with app names and disk count.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Config form now shows Zone WAF:Edit requirement alongside DNS:Edit.
Hub README updated with permission note.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Configuration page with "Refresh Assets" button
- Replace seedIfEmpty with seedOrUpdate (SHA-256 compare on startup)
- Translate all Hungarian text on Apps pages to English
- Add Configuration tab to all template navigation
- Expand isAssetFile to match favicon patterns
- Add felhom-logo.svg to website assets for the pipeline
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds "Telemetria törlése" button that deletes all telemetry records and
known issues for a specific app. Useful after major app updates when old
data is no longer representative.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace 64-char hex retrieval passwords with 5-word Hungarian
passphrases (e.g. áldás-plazmid-palánta-süvítve-pócgém) for
better UX in disaster recovery scenarios. Embed 29K+ word list
via go:embed. API keys remain hex.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
"Current version" → "Controller version", "Latest version" → "Registry latest"
to avoid confusion when running version is ahead of registry cache.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove extra "v" prefix from ControllerVersion display (was "vv0.21.1")
- Add monitoring.ping_uuids.* to volatile keys — skipped in config diff
- Update manifest to v0.3.3
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add hubVersion template function via closure in web.New(). Version is
passed from main.go (set via ldflags at build time) and displayed in
the footer of all 6 page templates.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace broken SHA256 hash comparison with value-based YAML comparison.
Add "Show Diff" button showing per-key differences in a color-coded table.
Add "Pull Config" to import controller's current config into the Hub.
New endpoints: GET /customers/{id}/config-diff, POST /customers/{id}/pull-config.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Compare controller's config_hash from reports against Hub-generated
YAML hash. Shows sync status (in sync / mismatch / unknown) on the
unified customer detail page next to the Push Config button.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace separate config detail and report detail pages with unified
/customers/{id} page showing both config info and live report data
- Add "blocked" status for customers (hidden from dashboard, notifications
suppressed, still accepts reports)
- Dashboard now shows config-only customers as "PENDING" status
- Customers list: all rows link to /customers/{id}, show BLOCKED badge
- New actions: block/unblock, push config to controller, auto-create
config from report data
- /configs/{id} now redirects to /customers/{id}
- Add config-badge CSS classes for MANAGED/MANUAL/BLOCKED badges
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Customers page now shows ALL customers: both pre-configured (managed)
and report-only (manual) — merged from customer_configs + reports tables
- Renamed "Configurations" → "Customers" in navigation tabs
- Renamed "+ New Configuration" → "+ Add Customer"
- Status column with ok/warn/down badges, version column, managed/manual badge
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New "Configurations" section lets operators pre-configure customer settings
in the Hub, then docker-setup.sh can download a ready-made controller.yaml
using just a customer ID and retrieval password.
- Store: customer_configs table with CRUD + per-customer API key lookup
- API: GET /api/v1/config/{id} with X-Retrieval-Password auth
- Auth: per-customer API keys alongside existing global key (backward compatible)
- Web UI: /configs list, create, edit, delete, YAML preview, copy-to-clipboard
- YAML gen: deep-merge controller.yaml.example template with customer overrides
- Template fetcher: background goroutine refreshing template from Gitea repo
- Navigation: Dashboard / Configurations tabs on all pages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Hub now tracks controller_url from reports, periodically checks the Gitea
registry for the latest controller image version, and shows a "Trigger Update"
button on the customer detail page that proxies to the controller's self-update
API endpoint using the shared API key.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add infra-backup push/pull API for controller DR:
- POST /api/v1/infra-backup — controller pushes infrastructure snapshot
- GET /api/v1/infra-backup/{customer_id} — fresh controller pulls backup
- infra_backups SQLite table with per-customer snapshots
- Customer detail page shows infra backup status card
- README.md with full API docs and DR flow
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- POST /api/v1/preferences: accepts {customer_id, email, enabled_events} from controller
- GetRecentNotifications() store method for last N notification log entries
- Customer detail page: new Notifications section (email, events, recent log table)
- joinStrings template function for event list display
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add CLAUDE.md with build workflow, project overview, and key patterns
- Add .gitignore to prevent committing binaries and IDE files
- Remove hub.exe from tracking (was accidentally committed)
- Fix statusIcon: use Unicode ● character instead of HTML entities
that get double-escaped by Go html/template
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Hub service receives reports from customer controllers
- SQLite store with 90-day retention and auto-prune
- REST API: POST /api/v1/report, GET /api/v1/customers
- Dark theme dashboard with status overview table
- Customer detail page with system, storage, containers, backup, health
- Bearer token auth for report ingest, bcrypt auth for dashboard
- K8s manifest for felhom-system namespace (Deployment, Service, Ingress, PVC)
- Dockerfile with multi-stage build
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>