- eventbus.go: Fix send-on-closed-channel panic in SubscribeGlobal by
using a done channel; add recover() in fan-out goroutine; track active
global subs for proper cleanup on unsubscribe
- config.go: Persist JWT secret to $DATA_DIR/.jwt_secret instead of
regenerating a random one on every restart (which invalidated all sessions)
- handlers_ws.go: Replace time.After with time.Ticker to fix timer leak in
SSE keepalive loop
- handlers_jobs.go: Add recover() in fire-and-forget job goroutine; fix nil
pointer deref when GetByID fails after job creation
- handlers_machines.go: Add recover() in ProbeAllMachines goroutine
- scheduler.go: Add recover() in scheduled job run goroutine
- engine.go: Add recover() in per-machine probe goroutines