Addresses #327 - Users behind reverse proxies (Traefik, nginx, etc) were
experiencing redirect loop issues because the redirect URL was being built
with http:// instead of https:// when X-Forwarded-Proto was set.
Changes:
- Build OIDC redirect URL dynamically from each request instead of at startup
- Respect X-Forwarded-Proto and X-Forwarded-Host headers from reverse proxies
- Update UI help text to clarify auto-detection behavior
- Add debug logging to show how redirect URL is constructed
When redirect URL is not explicitly configured, Pulse now builds it from
the incoming request headers, properly detecting HTTPS when behind a proxy.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
addresses #454
PBS host backups (created with standalone proxmox-backup-client) use
the hostname as backup-id (e.g. "delly", "krom-pc") instead of a
numeric VMID. Now the VMID column displays this hostname string for
host backups instead of incorrectly showing 0.
Changes:
- Allow vmid field to be string or number in UnifiedBackup type
- Keep backup-id as string for host backups, numeric for VMs/LXCs
- Update column header to show "VMID/Host" when host backups exist
- Fixed in both code paths: direct PBS API and PVE storage backups
- Sorting and filtering work correctly with both strings and numbers
Also includes security improvement:
- Show setup command to user before copying to clipboard
- Prevents blindly pasting commands without review
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
addresses #327
Fixed issues when PUBLIC_URL is not set:
- Better error message explaining how to fix missing redirect URL
- Help text now shows actionable guidance instead of incomplete message
- Hide IdP redirect URL hint when no default is available
Implements @solidjs/router to provide proper URL-based navigation:
- Main routes: /, /storage, /backups, /alerts, /settings
- Settings sub-routes: /settings/pve, /settings/pbs, /settings/system, etc.
- Browser back/forward buttons now work
- URLs are bookmarkable and shareable
- Clearer indication of current page in URL bar
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Related to #478
Storage was grouping by storage.instance but Node.ID uses the format
"instance-nodename". This caused node headers to not display in storage
view when grouped by node.
Applied the same fix as Dashboard - group by instance-nodename to match
the Node.ID format from the backend.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
addresses #478
The grouped view toggle wasn't working because guests were grouped by
guest.instance (e.g., "delly.lan") but node IDs are formatted as
"instance-nodename" (e.g., "delly.lan-delly"). This mismatch prevented
the node lookup from working, so grouped mode showed no node headers.
Changed the grouping key to match the Node.ID format by combining
guest.instance and guest.node.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
addresses #327
- added detailed logging when ID token verification fails
- added better error messages for common OIDC issues
- updated docs with Authentik-specific configuration
- added troubleshooting section for redirect loops and invalid_id_token errors
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
unified section headers across all alert tabs to match settings styling - all main headers now use size="md", subsection headers use consistent typography, added proper headers to history tab
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Removed the messy metadata grid and restructured the layout:
- Two buttons in a clean horizontal row
- Username shown on the right
- Removed redundant metadata (last updated, coverage, etc)
- Simplified button styles
- 136 lines removed
Result: Much cleaner, more focused interface.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The Security settings page had way too much explanatory text.
Simplified all sections to be more concise:
- Security posture: shorter status descriptions
- Auth warning: compact banner instead of essay
- Authentication panel: removed redundant explanation
- OIDC panel: 4-line setup steps instead of paragraphs
- API token: removed verbose preamble
- Misc: removed duplicate SSO explanation box
Result: 150 lines of fluff removed, much cleaner UI.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
addresses #327
Changes:
- Removed automatic redirect to OIDC when password auth is configured
- Users can now choose between password auth or SSO button
- Clarified that client_secret is optional for PKCE-supporting providers
- Improved setup instructions to mention PUBLIC_URL requirement
- Made it clear that redirect URL is auto-generated from PUBLIC_URL
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- add dedicated Temperature column in node summary table with color coding
- add temperature threshold configuration in alert settings
- default threshold: 80°C trigger / 75°C clear
- temperature alerts integrated with existing alert system
- configurable per-node or globally via alert overrides
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed from scary warnings to confident, reassuring tone:
Before:
- "⚠️ IMPORTANT: This grants SSH access..."
- Emphasized risks and compromise scenarios
- Made users feel unsafe enabling the feature
After:
- "Works just like Ansible, Saltstack, etc."
- Emphasizes this is industry-standard approach
- Compares to trusted automation tools
- Focuses on what it does, not what could go wrong
- Still transparent about security model
- Removes duplicate/contradictory sections
The feature is secure and follows best practices. The messaging should
reflect confidence in the design while still being transparent.
Users should feel good about enabling it, not scared.
- Make it clear SSH setup is OPTIONAL
- Explain security model upfront before user commits
- Detail exactly what access is being granted (root SSH, sensors only)
- Warn users to only proceed if they trust Pulse server
- Better differentiate public vs private keys
- Show exactly where the key is stored
- Explain how to revoke access
- Add comprehensive security documentation
- Include advanced option for command restrictions in authorized_keys
- Add risk assessment and best practices
This ensures users make informed decisions about SSH access to their
critical Proxmox infrastructure.
- Prompts user to set up SSH access during auto-setup
- Guides user to paste their Pulse server's public key
- Adds key to /root/.ssh/authorized_keys
- Installs lm-sensors automatically
- Runs sensors-detect --auto for proper sensor detection
- Optional: user can skip and set up later manually
- Includes validation of SSH key format
- Shows clear instructions for manual setup if skipped
This ensures temperature monitoring works out-of-the-box for users
who run the auto-setup script.
addresses #101
- Implement SSH-based temperature collector using lm-sensors
- Add Temperature struct to node models (CPU package, cores, NVMe)
- Collect temps during node polling (5s timeout, non-blocking)
- Display temperature in node cards with color coding:
- Green: <60°C
- Yellow: 60-80°C
- Red: >80°C
- Shows CPU temp or falls back to load average if unavailable
- Tooltip includes NVMe drive temps when present
- Uses root SSH access (no additional auth setup needed for now)
- Temperature data only collected for online nodes
Added detailed debug-level logs throughout the OIDC flow:
- Provider initialization (issuer, endpoints, scopes)
- Login flow tracking (client ID, redirect URL)
- Token exchange success/failure details
- Claims extraction (username, email, groups)
- Access control checks (why restrictions passed/failed)
Enhanced error logs to include issuer URL and actual error details in
audit events instead of generic "failed" messages.
Updated docs with Debug Logging section showing example output and
troubleshooting guidance for common issues like group restrictions.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Previously the quick token setup showed placeholder text like "click copy
to generate". Now it displays the actual curl command with the one-time
URL after generation, giving users transparency about what they're running.
Changes:
- Display generated curl command with URL in code block
- Update prompt text for better clarity ("above" instead of generic)
- Add visual feedback with color states (gray/blue/green)
- Store URL in setupCode state for display
- Apply to both PVE and PBS setup flows
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
addresses data loss issue where encryption key regeneration silently
orphaned all encrypted configuration (nodes, email, webhooks).
Changes:
- Check for existing .enc files before generating new encryption key
- Refuse to start if encrypted data exists but key is missing/invalid
- Forces explicit user action (restore key backup or delete .enc files)
- Prevents silent data loss from key regeneration
This ensures encrypted data is never accidentally orphaned when the
encryption key is lost or corrupted.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
addresses #477
Expanded the timezone dropdown from 11 options to 70+ common IANA
timezones covering all major regions (Africa, Americas, Asia,
Australia, Europe, Pacific).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
addresses #449
proxmox returns 'N/A' or empty string for the wearout field on disks that
don't support wear reporting (HDDs, hardware RAID controllers, etc). pulse
was expecting an integer, causing JSON unmarshal errors that prevented ALL
disks from being displayed on affected nodes.
added custom UnmarshalJSON method for the Disk type to gracefully handle:
- numeric values (SSDs with wear reporting)
- string values like 'N/A' (HDDs, RAID controllers) - converts to 0
- null values - converts to 0
this allows nodes with mixed disk types (SSDs, HDDs, RAID) to display all
their disks correctly. wearout value of 0 indicates no wear reporting
available, which is expected for HDDs.
addresses #471
when pulse restarts (service restart, container restart, etc), active alerts
are loaded from disk but notifications were never sent for these restored
alerts. this caused users to miss critical ongoing alerts that existed before
the restart.
the issue was particularly noticeable with memory alerts on VMs - if a VM's
memory was genuinely high and an alert was created, then pulse restarted, the
alert would show in 'Active Alerts' but no webhook notification would be sent.
however, manually creating a 'fake' alert by lowering thresholds would work
because those are new alerts.
fix: now sends notifications for restored critical alerts that started within
the last 2 hours. adds a 10-second delay after restart to allow the system
to stabilize before sending notifications. warning-level alerts are not
re-notified to avoid spam on restart.
addresses #454
PBS supports backing up physical hosts using proxmox-backup-client with
backup-type='host'. these backups were incorrectly displayed as 'LXC' type
because the frontend only checked for 'vm'/'qemu' types and defaulted
everything else to 'LXC'.
now properly handles all three PBS backup types: vm, ct (lxc), and host
addresses #476
when multiple nodes have the same hostname, the dashboard and storage views
were incorrectly grouping VMs/containers/storage by hostname instead of by
unique node instance ID. this caused:
- incorrect VM/container counts in node summary
- mixed display of resources from different nodes
- incorrect grouping in storage view
changed grouping logic to use guest.instance (unique node ID) instead of
guest.node (hostname). updated both Dashboard and Storage components to
properly map instance IDs to node objects for display while maintaining
correct data separation.
Addresses #450, #451, #406
- Initialize all variables at top of script to prevent "unbound variable" errors with set -u
- BUILD_FROM_SOURCE, SKIP_DOWNLOAD, IN_CONTAINER, IN_DOCKER now set at line 20-27
- ENABLE_AUTO_UPDATES, FORCE_VERSION, FORCE_CHANNEL, SOURCE_BRANCH also moved to top
- Removed duplicate assignments from argument parsing section
- Restore /bin/update command creation for ProxmoxVE LXC installations
- Creates update script that re-runs install.sh for easy updates
- Allows backend to properly detect ProxmoxVE deployment type
- Users can now run "update" in LXC console as documented
- Update deployment detection to recognize install.sh in update command
- Previously only looked for legacy "pulse.sh" reference
- Now checks for both pulse.sh and install.sh
Addresses multiple issues identified during comprehensive alert system audit:
1. Fix ZFS device loop lock issue
- Moved lock acquisition outside loop in checkZFSPoolHealth
- Changed clearAlert to clearAlertNoLock when lock already held
- Prevents multiple lock acquisitions in same iteration
2. Add alert deduplication on restore
- Prevents duplicate alerts after service restart
- Tracks seen alert IDs during LoadActiveAlerts
- Logs warnings for any duplicates found
3. Add API input validation
- validateAlertID function prevents DOS attacks
- Limit alert ID length to 500 characters
- Whitelist allowed characters (alphanumeric, -, _, :, /, .)
- Cap history limit parameter at 10,000 records
- Applied validation to acknowledge, unacknowledge, and clear endpoints
4. Add panic recovery to goroutines
- All SaveActiveAlerts goroutines now have defer/recover
- Cleanup goroutines protected from panics
- Contextual error logging for each goroutine type
5. Document lock ordering
- Added comprehensive documentation for Manager mutexes
- Explains m.mu and resolvedMutex relationship
- Clarifies acquisition rules to prevent deadlocks
- Inline comments for resolvedMutex field
These fixes improve stability, security, data integrity, and maintainability
of the alert system without breaking API compatibility.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Corrected widespread misinformation claiming API tokens cannot access guest agent data on Proxmox 9.
Changes:
- Rewrote VM_DISK_MONITORING.md with accurate technical explanation
- Deleted VM_DISK_STATS_TROUBLESHOOTING.md (contained false information)
- Updated FAQ.md with correct quick reference and troubleshooting link
- Added comprehensive VM disk troubleshooting section to TROUBLESHOOTING.md
- Fixed README.md troubleshooting reference
- Updated frontend tooltip to show accurate permission requirements
- Corrected backend log messages to remove "known limitation" language
- Updated test-vm-disk.sh diagnostic script with accurate guidance
Key corrections:
- API tokens work fine for guest agent queries on both PVE 8 and 9
- Proxmox API returning disk=0 is normal behavior, not a bug
- Both tokens and passwords work equally well
- Only requirements: guest agent installed + proper permissions
- Permission issues are config problems, not authentication method limitations
Documentation now provides clear user journey: FAQ → Troubleshooting → Full Guide
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fix deadlock in checkEscalations by releasing lock before processing alerts
- Add timeout protection in GetState when calling GetActiveAlerts
- Add read-only demo mode with middleware blocking modifications
- Add demo banner component for frontend
- Add demo server link to README (https://demo.pulserelay.pro)
addresses potential broadcast hangs in production environments
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Adds DEMO_MODE environment variable that blocks all write operations
while allowing full read/view functionality. Includes banner notification
in UI when demo mode is active.
Addresses need for safe public demo instances.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Added streaming discovery that shows servers as they're found
- Backend sends WebSocket updates for each discovered server
- Frontend displays servers immediately without waiting for full scan
- Created sync-production-config.sh to preserve nodes when switching modes
- Updated toggle-mock.sh to sync config when disabling mock mode
- Dev environment now maintains separate config that syncs from production
- Enabled discovery service in dev environment by default
addresses real-time discovery UX and mock/production mode configuration persistence
Addresses #459#461 - Consolidates variable initialization at the top
of the script alongside other defaults. Removes redundant BUILD_FROM_SOURCE
initialization from argument parsing section.
Fix TypeScript errors where catch blocks used _err but referenced err
in console.error calls. This was causing CI type-check failures.
Changes:
- Remove underscore prefix from error variables since they're used
- Fixes TS2552: Cannot find name 'err' errors
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove old RC changelog (v4.15.0-rc.6)
- Update .gitignore comment for experimental features
- Clean up repo of unused files
Pulse+ / cloud relay feature was abandoned, no telemetry or cloud
features are part of Pulse. All monitoring stays local.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fix port conflict: backend now uses 7656, frontend uses 7655
- Fix mock mode not loading: use load_env_file for proper export
- Fix pipefail crashes on port checks: disable during lsof checks
- Add error handling for /etc/pulse/.env permission issues
- Update .gitignore to exclude sensitive files and temp scripts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>