wulf-pulse/docs/rmm-multi-site-integration.md

307 lines
9.7 KiB
Markdown
Raw Permalink Normal View History

# 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.