wulf-pulse/docs/rmm-multi-site-integration.md
root 6eee14f8af Add comprehensive admin features and multi-system integration
- Add admin dashboard with sync controls and data browser
- Implement RMM, Auvik, and Addigy organization mappings
- Add chunked ticket sync with progress tracking
- Implement entity sync service with rate limiting
- Add analytics engine and performance optimizer
- Create data browser for all PSA entities
- Add navigation components and UI improvements
- Implement background processing and sync services
- Add comprehensive documentation and migration scripts
- Update configuration items with multi-system support
- Enhance contact management and purchase history
- Add issue type assignment and LLM analyzer
- Improve error handling and logging utilities
2025-11-19 14:18:16 -05:00

9.7 KiB

RMM Multi-Site Integration Architecture

Problem Statement

The current integration with Datto RMM only captures devices from a single site per company, leading to incomplete asset visibility for organizations with multiple locations. Since the PSA (Autotask) is the authoritative source for customers/companies, but RMM can have multiple sites per company, we're missing critical infrastructure data.

Current Implementation Limitations

Single Site Matching Issue

  • Current Behavior: getDevicesByCompanyName() finds the first matching site name and returns only those devices
  • Data Loss: Multi-site companies (branch offices, multiple locations) have devices that aren't tracked
  • No Mapping System: Unlike Auvik (NMS) integration, there's no database table or UI to map multiple RMM sites to a single PSA company

Option 1: Fuzzy Name Matching (Quick Fix)

Description: Modify the RMM client to find ALL sites that could belong to a company using pattern matching.

Implementation:

async getDevicesByCompanyName(companyName: string): Promise<DattoRMMDevice[]> {
  const sites = await this.getSites();
  
  // Find all sites that might belong to this company
  const matchingSites = sites.filter(site => {
    const siteName = site.name.toLowerCase();
    const company = companyName.toLowerCase();
    
    return siteName.includes(company) || 
           siteName.startsWith(company) ||
           // Handle patterns like "Company - Location"
           siteName.split('-')[0].trim() === company;
  });
  
  // Get devices from all matching sites
  const allDevices = await Promise.all(
    matchingSites.map(site => this.getDevicesBySite(site.uid))
  );
  
  return allDevices.flat();
}

Pros:

  • Quick to implement
  • Catches obvious naming patterns
  • No database changes required

Cons:

  • Prone to false positives/negatives
  • Not maintainable long-term
  • No audit trail
  • Can't handle complex naming schemes

Description: Create a proper many-to-one mapping between RMM sites and PSA companies, similar to the Auvik tenant mapping system.

Database Schema:

CREATE TABLE rmm_site_mappings (
  id SERIAL PRIMARY KEY,
  company_id INTEGER NOT NULL REFERENCES companies(id) ON DELETE CASCADE,
  rmm_site_uid VARCHAR(255) NOT NULL,
  rmm_site_name VARCHAR(255) NOT NULL,
  is_primary BOOLEAN DEFAULT false,
  notes TEXT,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  created_by VARCHAR(255),
  UNIQUE(company_id, rmm_site_uid)
);

CREATE INDEX idx_rmm_site_mappings_company ON rmm_site_mappings(company_id);
CREATE INDEX idx_rmm_site_mappings_site_uid ON rmm_site_mappings(rmm_site_uid);

Key Features:

  • Multiple sites per company
  • Primary site designation
  • Audit trail with timestamps
  • Notes field for documentation
  • Foreign key constraints for data integrity

Enhanced Service Method:

async getDevicesByCompanyId(companyId: number): Promise<DattoRMMDevice[]> {
  // Get all mapped site UIDs from database
  const siteMappings = await db.query(
    'SELECT rmm_site_uid FROM rmm_site_mappings WHERE company_id = $1',
    [companyId]
  );
  
  // Fetch devices from all mapped sites
  const allDevices = await Promise.all(
    siteMappings.map(mapping => 
      this.getDevicesBySite(mapping.rmm_site_uid)
    )
  );
  
  return allDevices.flat();
}

Option 3: Smart Auto-Discovery (Advanced Enhancement)

Description: Combine manual mapping with intelligent discovery and pattern recognition.

Features:

  1. Pattern Recognition: Analyze existing site names to detect patterns
  2. Company Hierarchy: Support parent/child company relationships
  3. Auto-Suggestions: When new sites appear, suggest likely company matches
  4. Custom Rules: Allow regex or pattern-based rules for automatic assignment
  5. Machine Learning: Use historical mapping decisions to improve suggestions

Auto-Discovery Algorithm:

interface SiteMatchingSuggestion {
  siteUid: string;
  siteName: string;
  suggestedCompanyId: number;
  confidence: number;
  matchReason: string;
}

async function suggestSiteMappings(): Promise<SiteMatchingSuggestion[]> {
  const unmappedSites = await getUnmappedSites();
  const companies = await getAllCompanies();
  const suggestions: SiteMatchingSuggestion[] = [];
  
  for (const site of unmappedSites) {
    // Check exact name match
    const exactMatch = companies.find(c => 
      c.name.toLowerCase() === site.name.toLowerCase()
    );
    
    if (exactMatch) {
      suggestions.push({
        siteUid: site.uid,
        siteName: site.name,
        suggestedCompanyId: exactMatch.id,
        confidence: 0.95,
        matchReason: 'Exact name match'
      });
      continue;
    }
    
    // Check partial matches and patterns
    const partialMatches = companies.filter(c => {
      const companyName = c.name.toLowerCase();
      const siteName = site.name.toLowerCase();
      
      return (
        siteName.includes(companyName) ||
        companyName.includes(siteName) ||
        levenshteinDistance(siteName, companyName) < 3
      );
    });
    
    if (partialMatches.length === 1) {
      suggestions.push({
        siteUid: site.uid,
        siteName: site.name,
        suggestedCompanyId: partialMatches[0].id,
        confidence: 0.75,
        matchReason: 'Partial name match'
      });
    }
  }
  
  return suggestions;
}

Implementation Phases

Phase 1: Foundation (Week 1)

  • Document current limitations and proposed solutions
  • Create database migration for rmm_site_mappings table
  • Build basic API endpoints for CRUD operations
  • Implement service layer for multi-site device fetching

Phase 2: User Interface (Week 2)

  • Create RMM Site Mappings page (similar to Auvik Mappings)
  • Add search and filtering capabilities
  • Implement bulk mapping operations
  • Add export/import functionality for mappings

Phase 3: Intelligence (Week 3)

  • Implement auto-discovery suggestions
  • Add pattern-based matching rules
  • Create notification system for new unmapped sites
  • Build reporting dashboard for mapping coverage

Phase 4: Optimization (Week 4)

  • Add caching layer for site mappings
  • Implement bulk device sync for multiple sites
  • Create monitoring for site changes
  • Add API rate limiting and retry logic

Additional Considerations

Performance Optimization

  • Caching: Store site mappings in Redis/memory cache
  • Batch Processing: Fetch devices from multiple sites in parallel
  • Pagination: Handle large device counts with proper pagination
  • Rate Limiting: Respect RMM API limits when fetching from multiple sites

Data Integrity

  • Validation: Ensure sites aren't mapped to multiple companies
  • Cleanup: Handle deleted sites and companies gracefully
  • Sync Status: Track last sync time per site
  • Error Handling: Implement retry logic for failed site syncs

User Experience

  • Bulk Operations: Allow mapping multiple sites at once
  • Import/Export: Support CSV import for initial setup
  • Search: Implement fuzzy search for sites and companies
  • Reporting: Show coverage metrics and unmapped sites

Security & Compliance

  • Audit Trail: Log all mapping changes with user identification
  • Permissions: Implement role-based access for mapping management
  • Data Privacy: Ensure site data doesn't leak between companies
  • Backup: Regular backup of mapping configurations

API Endpoint Specifications

GET /api/rmm/site-mappings

Returns all site mappings with optional filtering

Query Parameters:

  • companyId: Filter by specific company
  • unmapped: Show only unmapped sites
  • search: Search term for site or company names

POST /api/rmm/site-mappings

Create or update a site mapping

Request Body:

{
  "companyId": 123,
  "rmmSiteUid": "site-uid-123",
  "rmmSiteName": "Company - Branch Office",
  "isPrimary": false,
  "notes": "Main branch location"
}

DELETE /api/rmm/site-mappings/:id

Remove a site mapping

POST /api/rmm/site-mappings/suggestions

Get auto-discovery suggestions for unmapped sites

Response:

{
  "suggestions": [
    {
      "siteUid": "site-123",
      "siteName": "Acme Corp - Dallas",
      "suggestedCompanyId": 456,
      "suggestedCompanyName": "Acme Corp",
      "confidence": 0.85,
      "matchReason": "Partial name match"
    }
  ]
}

POST /api/rmm/site-mappings/bulk

Create multiple mappings at once

Request Body:

{
  "mappings": [
    {
      "companyId": 123,
      "rmmSiteUid": "site-1",
      "rmmSiteName": "Site 1"
    },
    {
      "companyId": 123,
      "rmmSiteUid": "site-2",
      "rmmSiteName": "Site 2"
    }
  ]
}

Success Metrics

  • Coverage Rate: % of RMM sites mapped to companies
  • Device Visibility: Total devices visible after multi-site implementation
  • Sync Performance: Time to sync devices across all sites
  • User Adoption: % of companies with multi-site mappings configured
  • Error Rate: Failed sync attempts per site

Migration Strategy

  1. Backup Current Data: Export existing single-site mappings
  2. Run Migration: Create new mapping table structure
  3. Import Existing: Convert current implicit mappings to explicit ones
  4. Validate: Ensure no data loss during migration
  5. Monitor: Track sync performance and error rates

Conclusion

Implementing Option 2 (Site Mapping Table) with elements of Option 3 (Smart Auto-Discovery) provides the best balance of accuracy, maintainability, and user experience. This approach mirrors the successful Auvik integration pattern while addressing the unique challenges of multi-site RMM environments.