# 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

## Recommended Solution Architecture

### 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**:
```typescript
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

### Option 2: Site Mapping Table (RECOMMENDED)
**Description**: Create a proper many-to-one mapping between RMM sites and PSA companies, similar to the Auvik tenant mapping system.

**Database Schema**:
```sql
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**:
```typescript
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**:
```typescript
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)
- [x] 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:
```json
{
  "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:
```json
{
  "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:
```json
{
  "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.
