mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-02-18 00:17:39 +01:00
feat: Gate update alerts as Pro-only feature
- Add FeatureUpdateAlerts constant for Pro license gating - Add feature to all Pro tier feature lists - Add SetLicenseChecker method to alerts Manager - Check Pro license in checkDockerContainerImageUpdate before alerting - Wire license checker from router to alert manager Free users still see update badges in the UI. Pro users get proactive alerts after 24h of pending updates.
This commit is contained in:
@@ -530,6 +530,8 @@ type Manager struct {
|
||||
// When a host agent is running on a Proxmox node, we prefer the host agent
|
||||
// alerts and suppress the node alerts to avoid duplicate monitoring.
|
||||
hostAgentHostnames map[string]struct{} // Normalized hostnames (lowercase)
|
||||
// License checking for Pro-only alert features
|
||||
hasProFeature func(feature string) bool
|
||||
}
|
||||
|
||||
type ackRecord struct {
|
||||
@@ -715,6 +717,14 @@ func NewManager() *Manager {
|
||||
return m
|
||||
}
|
||||
|
||||
// SetLicenseChecker sets the function used to check Pro license features.
|
||||
// This enables gating Pro-only alert features like update alerts.
|
||||
func (m *Manager) SetLicenseChecker(checker func(feature string) bool) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.hasProFeature = checker
|
||||
}
|
||||
|
||||
// addRecentlyResolvedUnlocked records a resolved alert assuming the caller does not hold m.mu.
|
||||
func (m *Manager) addRecentlyResolvedUnlocked(alertID string, resolved *ResolvedAlert) {
|
||||
m.resolvedMutex.Lock()
|
||||
@@ -4352,8 +4362,20 @@ func (m *Manager) checkDockerContainerImageUpdate(host models.DockerHost, contai
|
||||
// Check if update detection is enabled
|
||||
m.mu.RLock()
|
||||
delayHours := m.config.DockerDefaults.UpdateAlertDelayHours
|
||||
hasProFeature := m.hasProFeature
|
||||
m.mu.RUnlock()
|
||||
|
||||
// Update alerts are a Pro-only feature
|
||||
// Free users still see update badges in the UI, but alerts require Pro
|
||||
if hasProFeature != nil && !hasProFeature("update_alerts") {
|
||||
// Not licensed for update alerts - clear any existing alert and tracking
|
||||
m.clearAlert(alertID)
|
||||
m.mu.Lock()
|
||||
delete(m.dockerUpdateFirstSeen, resourceID)
|
||||
m.mu.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
// Negative value means disabled
|
||||
if delayHours < 0 {
|
||||
m.clearAlert(alertID)
|
||||
|
||||
@@ -1183,6 +1183,16 @@ func (r *Router) setupRoutes() {
|
||||
r.aiSettingsHandler.SetMetadataProvider(metadataProvider)
|
||||
// Wire license checker for Pro feature gating (AI Patrol, Alert Analysis, Auto-Fix)
|
||||
r.aiSettingsHandler.SetLicenseChecker(r.licenseHandlers.Service())
|
||||
// Wire license checker for alert manager Pro features (Update Alerts)
|
||||
if r.monitor != nil {
|
||||
alertMgr := r.monitor.GetAlertManager()
|
||||
if alertMgr != nil {
|
||||
licSvc := r.licenseHandlers.Service()
|
||||
alertMgr.SetLicenseChecker(func(feature string) bool {
|
||||
return licSvc.HasFeature(feature)
|
||||
})
|
||||
}
|
||||
}
|
||||
r.mux.HandleFunc("/api/settings/ai", RequireAdmin(r.config, RequireScope(config.ScopeSettingsRead, r.aiSettingsHandler.HandleGetAISettings)))
|
||||
r.mux.HandleFunc("/api/settings/ai/update", RequireAdmin(r.config, RequireScope(config.ScopeSettingsWrite, r.aiSettingsHandler.HandleUpdateAISettings)))
|
||||
r.mux.HandleFunc("/api/ai/test", RequireAdmin(r.config, RequireScope(config.ScopeSettingsWrite, r.aiSettingsHandler.HandleTestAIConnection)))
|
||||
|
||||
@@ -4,12 +4,15 @@ package license
|
||||
// Feature constants represent gated features in Pulse Pro.
|
||||
// These are embedded in license JWTs and checked at runtime.
|
||||
const (
|
||||
// Pro tier features
|
||||
// Pro tier features - AI
|
||||
FeatureAIPatrol = "ai_patrol" // Background AI health monitoring
|
||||
FeatureAIAlerts = "ai_alerts" // AI analysis when alerts fire
|
||||
FeatureAIAutoFix = "ai_autofix" // Automatic remediation
|
||||
FeatureKubernetesAI = "kubernetes_ai" // AI analysis of K8s (NOT basic monitoring)
|
||||
|
||||
// Pro tier features - Monitoring
|
||||
FeatureUpdateAlerts = "update_alerts" // Alerts for pending container/package updates
|
||||
|
||||
// MSP tier features (FUTURE - not in v1 launch)
|
||||
FeatureMultiUser = "multi_user" // RBAC - NOT IMPLEMENTED YET
|
||||
FeatureWhiteLabel = "white_label" // Custom branding - NOT IMPLEMENTED YET
|
||||
@@ -39,24 +42,28 @@ var TierFeatures = map[Tier][]string{
|
||||
FeatureAIAlerts,
|
||||
FeatureAIAutoFix,
|
||||
FeatureKubernetesAI,
|
||||
FeatureUpdateAlerts,
|
||||
},
|
||||
TierProAnnual: {
|
||||
FeatureAIPatrol,
|
||||
FeatureAIAlerts,
|
||||
FeatureAIAutoFix,
|
||||
FeatureKubernetesAI,
|
||||
FeatureUpdateAlerts,
|
||||
},
|
||||
TierLifetime: {
|
||||
FeatureAIPatrol,
|
||||
FeatureAIAlerts,
|
||||
FeatureAIAutoFix,
|
||||
FeatureKubernetesAI,
|
||||
FeatureUpdateAlerts,
|
||||
},
|
||||
TierMSP: {
|
||||
FeatureAIPatrol,
|
||||
FeatureAIAlerts,
|
||||
FeatureAIAutoFix,
|
||||
FeatureKubernetesAI,
|
||||
FeatureUpdateAlerts,
|
||||
FeatureUnlimited,
|
||||
// Note: FeatureMultiUser, FeatureWhiteLabel, FeatureMultiTenant
|
||||
// are on the roadmap but NOT included until implemented
|
||||
@@ -66,6 +73,7 @@ var TierFeatures = map[Tier][]string{
|
||||
FeatureAIAlerts,
|
||||
FeatureAIAutoFix,
|
||||
FeatureKubernetesAI,
|
||||
FeatureUpdateAlerts,
|
||||
FeatureUnlimited,
|
||||
FeatureMultiUser,
|
||||
FeatureWhiteLabel,
|
||||
@@ -118,6 +126,8 @@ func GetFeatureDisplayName(feature string) string {
|
||||
return "AI Auto-Fix"
|
||||
case FeatureKubernetesAI:
|
||||
return "Kubernetes AI Analysis"
|
||||
case FeatureUpdateAlerts:
|
||||
return "Update Alerts (Container/Package Updates)"
|
||||
case FeatureMultiUser:
|
||||
return "Multi-User / RBAC"
|
||||
case FeatureWhiteLabel:
|
||||
|
||||
Reference in New Issue
Block a user