v0.7.0: Phase 1 — Authentication, Persistence & Settings Page

- New settings.json persistence layer (internal/settings/settings.go)
  - Atomic write (tmp + rename), thread-safe with sync.RWMutex
  - Stores password hash overrides and DB validation cache
  - Auto-creates on first save, graceful handling if missing

- Auth improvements
  - Password resolution priority: settings.json > controller.yaml > none
  - Session duration extended to 7 days (was 24h)
  - ?next= redirect after session expiry (returns to original page)
  - Flash messages on login page (used after password change)
  - Conditional logout link (hidden when auth disabled)
  - Session invalidation on password change

- New Settings page (/settings)
  - Read-only system config display (customer, domain, git, backup, monitoring)
  - Password change form with validation (min 8 chars, match check)
  - Sidebar "Beállítások" item pinned to bottom above version

- DB validation persistence
  - Validation results saved to settings.json after each dump
  - Cached data survives container restarts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-16 17:26:59 +01:00
parent 0be1f2e547
commit 4053245be8
10 changed files with 514 additions and 25 deletions
+10 -2
View File
@@ -18,6 +18,7 @@ import (
"gitea.dooplex.hu/admin/felhom-controller/internal/monitor"
"gitea.dooplex.hu/admin/felhom-controller/internal/report"
"gitea.dooplex.hu/admin/felhom-controller/internal/scheduler"
"gitea.dooplex.hu/admin/felhom-controller/internal/settings"
"gitea.dooplex.hu/admin/felhom-controller/internal/stacks"
catalogsync "gitea.dooplex.hu/admin/felhom-controller/internal/sync"
"gitea.dooplex.hu/admin/felhom-controller/internal/system"
@@ -51,6 +52,13 @@ func main() {
logger.Printf("[INFO] felhom-controller %s starting (customer: %s, domain: %s)",
Version, cfg.Customer.ID, cfg.Customer.Domain)
// --- Load settings ---
settingsPath := cfg.Paths.DataDir + "/settings.json"
sett, err := settings.Load(settingsPath, logger)
if err != nil {
logger.Fatalf("[FATAL] Failed to load settings from %s: %v", settingsPath, err)
}
// --- Initialize stack manager ---
stackMgr, err := stacks.NewManager(cfg, logger)
if err != nil {
@@ -99,7 +107,7 @@ func main() {
// --- Initialize backup manager ---
var backupMgr *backup.Manager
if cfg.Backup.Enabled {
backupMgr = backup.NewManager(cfg, pinger, logger)
backupMgr = backup.NewManager(cfg, pinger, sett, logger)
backupMgr.AfterBackup = func() {
nextDBDump := scheduler.NextDailyRun(cfg.Backup.DBDumpSchedule)
nextBackup := scheduler.NextDailyRun(cfg.Backup.ResticSchedule)
@@ -210,7 +218,7 @@ func main() {
apiRouter := api.NewRouter(cfg, stackMgr, syncer, cpuCollector, backupMgr, metricsStore, logger)
// --- Initialize web server ---
webServer := web.NewServer(cfg, stackMgr, cpuCollector, backupMgr, sched, logger, Version)
webServer := web.NewServer(cfg, stackMgr, cpuCollector, backupMgr, sched, sett, logger, Version)
// --- Build HTTP mux ---
mux := http.NewServeMux()