wulf-pulse/docs/fixes/all-systems-inventory-display.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

5.3 KiB

All Systems Inventory Display Implementation

Issue

The configuration items page was only showing devices from PSA (Autotask) and RMM (Datto RMM), but not displaying devices that exist ONLY in NMS (Auvik) or ARMM (Addigy). This violated the goals document requirement to show "the combination of inventories across all the systems."

Root Cause

The comparison logic in /app/api/rmm-devices/route.ts was:

  1. Adding RMM devices (matched or RMM-only)
  2. Adding Autotask devices (matched or Autotask-only)
  3. Matching Auvik and Addigy devices to existing Autotask devices
  4. BUT never adding unmatched Auvik-only or Addigy-only devices

Solution

Backend Changes (/app/api/rmm-devices/route.ts)

1. Added Unmatched Device Logic

After processing PSA and RMM devices, added logic to include devices that exist only in Auvik or Addigy:

// Track which Auvik and Addigy devices have been matched
const matchedAuvikIds = new Set<string>();
const matchedAddigyIds = new Set<string>();

comparison.forEach(item => {
  if (item.auvikDevice?.id) matchedAuvikIds.add(item.auvikDevice.id);
  if (item.addigyDevice?.agentid) matchedAddigyIds.add(item.addigyDevice.agentid);
});

// Add unmatched Auvik devices (NMS-only)
for (const auvikDevice of auvikDevices) {
  if (!matchedAuvikIds.has(auvikDevice.id)) {
    // Try to match with Addigy by serial number
    let addigyMatch = addigyDevices.find(d => 
      d['Serial Number']?.toLowerCase().trim() === auvikDevice.serialNumber?.toLowerCase().trim() &&
      !matchedAddigyIds.has(d.agentid)
    );
    
    comparison.push({
      auvikDevice: auvikDevice,
      addigyDevice: addigyMatch,
      status: 'rmm-only'
    });
  }
}

// Add unmatched Addigy devices (ARMM-only)
for (const addigyDevice of addigyDevices) {
  if (!matchedAddigyIds.has(addigyDevice.agentid)) {
    comparison.push({
      addigyDevice: addigyDevice,
      status: 'rmm-only'
    });
  }
}

2. Updated Sorting Logic

Enhanced device name sorting to check all four systems:

const aName = a.autotaskDevice?.referenceTitle || 
              a.rmmDevice?.hostname || 
              a.auvikDevice?.deviceName || 
              a.addigyDevice?.['Device Name'] || 
              '';

3. Added Stats for All Systems

Updated response to include counts for all four systems:

stats: {
  totalRmm: rmmDevices.length,
  totalAutotask: autotaskDevices.length,
  totalAuvik: auvikDevices.length,
  totalAddigy: addigyDevices.length,
  matched: comparison.filter(c => c.status === 'matched').length,
  autotaskOnly: comparison.filter(c => c.status === 'autotask-only').length,
  rmmOnly: comparison.filter(c => c.status === 'rmm-only').length,
}

Frontend Changes (/app/configuration-items/page.tsx)

1. Updated Device Name Display

Modified table cells to show device names from any of the four systems:

{item.autotaskDevice?.referenceTitle || 
 item.rmmDevice?.hostname || 
 item.auvikDevice?.deviceName ||
 item.addigyDevice?.['Device Name'] ||
 'Unknown Device'}

2. Updated Serial Number Display

{item.autotaskDevice?.serialNumber || 
 item.rmmDevice?.serialNumber || 
 item.auvikDevice?.serialNumber ||
 item.addigyDevice?.['Serial Number'] ||
 '-'}

3. Updated IP Address Display

{item.autotaskDevice?.rmmDeviceAuditIPAddress || 
 item.rmmDevice?.intIpAddress || 
 item.auvikDevice?.ipAddresses?.[0] ||
 item.addigyDevice?.['IP Address'] ||
 '-'}

4. Updated Stats Display

Both the compact stats badge and detailed table header now show all four systems:

Compact: PSA: X | RMM: X | NMS: X | ARMM: X

Detailed: Individual counts for PSA, RMM, NMS, ARMM, plus Matched count

Matching Priority (Per Goals Document)

The system now properly implements the matching priority across all systems:

  1. Reference UID - PSA has reference to RMM device UID
  2. Serial Number - Primary matching across all systems
  3. MAC Address - Used for Auvik matching
  4. IP Address - Used for RMM matching
  5. Hostname - Used with client/site filter

Device Status Types

  • matched - Device exists in PSA and at least one other system
  • autotask-only - Device exists only in PSA (may have NMS/ARMM matches)
  • rmm-only - Device exists in RMM, NMS, or ARMM but not in PSA

Benefits

  1. Complete Visibility - All devices from all four systems are now visible
  2. Better Asset Tracking - No devices are hidden from view
  3. Compliance with Goals - Fully implements the "combination of inventories" requirement
  4. Cross-System Matching - Auvik and Addigy devices can match each other even without PSA entry
  5. Accurate Counts - Stats show true device counts across all systems

Files Modified

  1. /app/api/rmm-devices/route.ts - Backend comparison logic
  2. /app/configuration-items/page.tsx - Frontend display logic

Testing Recommendations

  1. Select a company with devices in all four systems
  2. Verify devices appear from PSA, RMM, NMS, and ARMM
  3. Check that stats show correct counts for each system
  4. Verify devices that exist only in Auvik or Addigy are displayed
  5. Confirm matching works across all system combinations
  • /docs/configuration-item-goals.md - Original requirements
  • /docs/fixes/configuration-items-table-improvements.md - UI improvements
  • /docs/fixes/rmm-cache-invalidation-fix.md - Cache fix