Pulse/docs/PULSE_PRO_IMPLEMENTATION.md
rcourtman ae70d9e423 feat: add --kube-include-all-deployments flag for Kubernetes agent
Adds IncludeAllDeployments option to show all deployments, not just
problem ones (where replicas don't match desired). This provides parity
with the existing --kube-include-all-pods flag.

- Add IncludeAllDeployments to kubernetesagent.Config
- Add --kube-include-all-deployments flag and PULSE_KUBE_INCLUDE_ALL_DEPLOYMENTS env var
- Update collectDeployments to respect the new flag
- Add test for IncludeAllDeployments functionality
- Update UNIFIED_AGENT.md documentation

Addresses feedback from PR #855
2025-12-18 20:58:30 +00:00

14 KiB

Pulse Pro Implementation Plan

Goal: Gate AI features behind a Pro license to create a sustainable income stream.

Timeline: ~1-2 weeks of focused work


Phase 1: License System Architecture

1.1 License Format (Simple JWT)

// internal/license/license.go
type LicenseData struct {
    LicenseID    string    `json:"lid"`        // Unique license ID
    Email        string    `json:"email"`      // Customer email
    Tier         string    `json:"tier"`       // "pro", "msp", "enterprise"
    IssuedAt     time.Time `json:"iat"`
    ExpiresAt    time.Time `json:"exp"`        // Empty = lifetime
    MaxNodes     int       `json:"max_nodes"`  // 0 = unlimited
    Features     []string  `json:"features"`   // ["ai_chat", "ai_patrol", "ai_alerts"]
}

Why JWT?

  • Self-contained (no license server needed for validation)
  • Signed with your private key, verified with public key embedded in binary
  • Can be verified offline (important for air-gapped homelabs)
  • Standard format, easy to generate from any payment processor webhook

1.2 License Validation Flow

┌────────────────────────────────────────────────────────────────┐
│  User purchases license on LemonSqueezy/Gumroad                │
│                         ↓                                      │
│  Webhook hits your simple license API (can be CloudFlare Worker)│
│                         ↓                                      │
│  Generate JWT signed with private key                          │
│                         ↓                                      │
│  Email license key to customer                                 │
│                         ↓                                      │
│  User pastes key in Pulse Settings → Pro tab                   │
│                         ↓                                      │
│  Pulse validates signature with embedded public key            │
│                         ↓                                      │
│  Store encrypted license in config dir (license.enc)           │
└────────────────────────────────────────────────────────────────┘

Phase 2: Backend Implementation

2.1 New Files to Create

internal/license/
├── license.go       # License struct, validation, JWT parsing
├── license_test.go  # Tests
└── features.go      # Feature flags (what Pro includes)

internal/config/
└── license.go       # License persistence (store/load from disk)

2.2 License Service

// internal/license/license.go
package license

import (
    "crypto/ed25519"
    "encoding/base64"
    "errors"
    "time"
    
    "github.com/golang-jwt/jwt/v5"
)

// Embedded public key (compiled into binary)
// Generate keypair: go run ./cmd/license-keygen
var publicKeyBase64 = "YOUR_PUBLIC_KEY_HERE"

type Service struct {
    license  *LicenseData
    loaded   bool
}

func NewService() *Service {
    return &Service{}
}

func (s *Service) LoadFromKey(licenseKey string) error {
    // Parse and validate JWT
    // Store in s.license
}

func (s *Service) IsValid() bool {
    if s.license == nil {
        return false
    }
    if !s.license.ExpiresAt.IsZero() && time.Now().After(s.license.ExpiresAt) {
        return false
    }
    return true
}

func (s *Service) HasFeature(feature string) bool {
    if !s.IsValid() {
        return false
    }
    for _, f := range s.license.Features {
        if f == feature || f == "all" {
            return true
        }
    }
    return false
}

// Feature constants
const (
    FeatureAIChat       = "ai_chat"
    FeatureAIPatrol     = "ai_patrol"
    FeatureAIAlerts     = "ai_alerts"
    FeatureOIDC         = "oidc"           // SSO/OIDC authentication
    FeatureKubernetes   = "kubernetes"     // K8s cluster monitoring
    FeatureMultiUser    = "multi_user"     // Multiple user accounts
    FeatureAPIAccess    = "api_access"     // Full API access for integrations
    FeatureWhiteLabel   = "white_label"    // Custom branding (MSP tier)
    FeatureAll          = "all"
)

2.3 Integration Points

Modify these files to check license:

File What to Gate
internal/api/ai_handlers.go Chat endpoints, patrol endpoints
internal/ai/patrol.go Patrol service start
internal/ai/service.go AI chat service
internal/ai/alert_triggered.go Alert analysis
internal/api/oidc_handlers.go OIDC/SSO configuration
internal/api/kubernetes_handlers.go K8s cluster endpoints
internal/monitoring/kubernetes/ K8s monitoring service

Example gating in ai_handlers.go:

func (h *AISettingsHandler) HandleChat(w http.ResponseWriter, r *http.Request) {
    // Check Pro license
    if !h.licenseService.HasFeature(license.FeatureAIChat) {
        utils.WriteJSONError(w, http.StatusPaymentRequired, 
            "AI Chat requires Pulse Pro. Visit https://pulserelay.pro to upgrade.")
        return
    }
    // ... existing logic
}

Phase 3: Frontend Implementation

3.1 New Settings Tab: "Pro License"

Location: frontend-modern/src/routes/settings/+page.svelte (or equivalent)

┌──────────────────────────────────────────────────────────────┐
│  ⚡ Pulse Pro                                                 │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  ┌────────────────────────────────────────────────────────┐  │
│  │  License Key                                           │  │
│  │  [________________________________________________]    │  │
│  │  [Activate License]                                    │  │
│  └────────────────────────────────────────────────────────┘  │
│                                                              │
│  ✅ License Status: Active (Pro)                             │
│  📧 Licensed to: user@example.com                            │
│  📅 Expires: Never (Lifetime)                                │
│                                                              │
│  ─────────────────────────────────────────────────────────  │
│                                                              │
│  Included Features:                                          │
│  ✅ AI Chat Assistant                                        │
│  ✅ AI Patrol (Background Health Checks)                     │
│  ✅ AI Alert Analysis                                        │
│  ✅ Priority Support                                         │
│                                                              │
│  ─────────────────────────────────────────────────────────  │
│                                                              │
│  Don't have a license?                                       │
│  [Get Pulse Pro →] https://pulserelay.pro                   │
│                                                              │
└──────────────────────────────────────────────────────────────┘

3.2 Graceful Degradation for Unlicensed Users

When AI features are accessed without a license:

  • AI Settings Tab: Show features but disabled with "Upgrade to Pro" message
  • Chat Button: Show but with "Pro" badge, clicking prompts upgrade
  • Patrol Findings: Hide or show "Enable with Pro" placeholder

Don't be hostile. The free version should still feel complete. Pro is an enhancement, not a hostage situation.


Phase 4: Payment & License Generation

4.1 Payment Processor: LemonSqueezy

Why LemonSqueezy over alternatives?

  • Handles global VAT/sales tax automatically
  • Generates invoices (enterprises need this)
  • Good webhook support for automation
  • Reasonable fees (~5% + 50¢)
  • Supports both subscription and one-time payments

4.2 Pricing Structure (Suggested)

Tier Price Features Target
Pro Monthly $12/month AI features, OIDC/SSO, K8s monitoring Individuals
Pro Annual $99/year Same as monthly, 2 months free Power users
Pro Lifetime $249 one-time All Pro features, forever Homelabbers who hate subscriptions
MSP $49/month All Pro + unlimited instances, white-label, multi-tenant MSPs
Enterprise Custom All features + support SLA, on-prem license server Large orgs

4.3 Feature Matrix

Feature Free Pro MSP Enterprise
Proxmox VE/PBS/PMG monitoring
Docker/Podman monitoring
Alerts (Discord, Slack, etc.)
Metrics history
Backup explorer
AI Chat
AI Patrol
AI Alert Analysis
OIDC/SSO
Kubernetes monitoring
Unlimited instances
White-label branding
Multi-tenant mode
Priority support Email Email Dedicated
SLA

4.3 License Generation Service

A simple Cloudflare Worker or Vercel Edge Function:

// Simplified license generator (LemonSqueezy webhook handler)
addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  const webhook = await request.json()
  
  if (webhook.meta.event_name === 'order_created') {
    const license = generateLicense({
      email: webhook.data.attributes.user_email,
      tier: 'pro',
      expiresAt: null, // lifetime for now
    })
    
    // Send license via email
    await sendLicenseEmail(webhook.data.attributes.user_email, license)
  }
  
  return new Response('OK')
}

function generateLicense(data) {
  // Sign JWT with private key
  // Return base64-encoded license key
}

Phase 5: Launch Communication

5.1 Changelog Entry

## v5.0.0 - The AI Update

### 🚀 Major Changes

**Introducing Pulse Pro**

Pulse 5.0 includes powerful AI features that require a Pro license:
- **AI Chat**: Natural language interface to your infrastructure
- **AI Patrol**: Background health monitoring and insights
- **AI Alert Analysis**: Smart analysis when alerts fire

Core monitoring features remain **completely free and open source**.

Pro licenses support ongoing development and enable me to work on Pulse full-time.

[Get Pulse Pro →](https://pulserelay.pro)

---

*Pulse has grown from a weekend project to something used by thousands. 
To keep improving it, I need to make it sustainable. Thank you for your support!*

— Richard

5.2 Preemptive FAQ

Add to README or docs:

Q: Why are AI features paid? A: AI features require significant development effort and ongoing maintenance. Pro licenses let me work on Pulse sustainably while keeping core monitoring free.

Q: Will monitoring features become paid? A: No. Proxmox/Docker/K8s monitoring, alerts, history, and all current free features will remain free forever.

Q: What if I'm already using AI in the RC? A: Thank you for testing! RC users were beta testers helping shape these features. The final release requires a Pro license.

Q: I can't afford Pro. A: Email me (richard@pulserelay.pro). I offer discounts for students, hobbyists in financial hardship, and open source contributors.

Q: Can I self-host without Pro? A: Absolutely. Pulse works great without AI features. Pro is optional.


Implementation Order

  1. Week 1: Backend

    • Create internal/license/ package
    • Implement JWT validation with embedded public key
    • Add license persistence (encrypted storage)
    • Gate AI endpoints with license checks
    • Add /api/license endpoints (check, activate)
  2. Week 2: Frontend + Payment

    • Add Pro License settings tab
    • Update AI settings to show Pro-gated state
    • Set up LemonSqueezy product
    • Create license generation webhook
    • Set up pulserelay.pro landing page (can be simple)
    • Write announcement blog post
  3. Launch

    • Release v5.0.0 stable
    • Post to Reddit (/r/homelab, /r/Proxmox, /r/selfhosted)
    • Post to GitHub Discussions
    • Email mailing list (if you have one)

Security Considerations

  1. Private key: Never commit to repo. Store in password manager + secure backup.
  2. License validation: Always verify signature, never trust claims without verification.
  3. Obfuscation: Consider light obfuscation of license check code (not for security, but to discourage trivial patching).
  4. Grace period: If validation fails, maybe grant 7-day grace period before disabling (better UX).

What NOT to Do

  • Phone-home license validation (breaks air-gapped installs)
  • Aggressive license enforcement (pisses off users)
  • Remove free features to "encourage" upgrades
  • Make the free version feel crippled
  • Hide that it's paid (be upfront in README)

Success Metrics (First 90 Days)

Metric Target
Pro licenses sold 50-100
Monthly revenue $500-$1000
Churn rate <5%
Negative community reactions <10 vocal complaints
GitHub stars lost <50

If you hit these numbers, you've validated the model. Then you can expand to MSP tier, add features, etc.


This plan can be adjusted based on your preferences. Want me to help implement any specific part?