feat: add tenants/sites sync for accurate dashboard stats

- Created auvik_tenants and rmm_sites tables
- Added /api/sync/tenants-sites endpoint to sync all tenants from Auvik
  and all sites from Datto RMM for accurate mapped/unmapped counts
This commit is contained in:
root 2026-02-02 23:02:34 -05:00
parent a050157836
commit c0190c7dd1

View file

@ -0,0 +1,88 @@
import { NextRequest, NextResponse } from 'next/server';
import { postgresClient } from '@/lib/services/postgres-client';
import { getAuvikClient } from '@/lib/services/auvik-factory';
import { getDattoRMMClient } from '@/lib/services/datto-rmm-factory';
export async function POST(request: NextRequest) {
try {
const results = {
auvik: { added: 0, updated: 0, errors: [] as string[] },
rmm: { added: 0, updated: 0, errors: [] as string[] },
};
// Sync Auvik tenants
try {
const auvikClient = getAuvikClient();
const tenants = await auvikClient.getTenants();
for (const tenant of tenants) {
try {
const result = await postgresClient.query(
`INSERT INTO auvik_tenants (tenant_id, tenant_name, domain_prefix, last_sync_at)
VALUES ($1, $2, $3, CURRENT_TIMESTAMP)
ON CONFLICT (tenant_id) DO UPDATE SET
tenant_name = EXCLUDED.tenant_name,
domain_prefix = EXCLUDED.domain_prefix,
last_sync_at = CURRENT_TIMESTAMP,
updated_at = CURRENT_TIMESTAMP
RETURNING (xmax = 0) as is_new`,
[tenant.id, tenant.domainPrefix, tenant.domainPrefix]
);
if (result.rows[0]?.is_new) {
results.auvik.added++;
} else {
results.auvik.updated++;
}
} catch (error) {
results.auvik.errors.push(`Tenant ${tenant.id}: ${error instanceof Error ? error.message : String(error)}`);
}
}
} catch (error) {
results.auvik.errors.push(`Failed to fetch tenants: ${error instanceof Error ? error.message : String(error)}`);
}
// Sync RMM sites
try {
const rmmClient = getDattoRMMClient();
const sites = await rmmClient.getSites();
for (const site of sites) {
try {
const result = await postgresClient.query(
`INSERT INTO rmm_sites (site_uid, site_name, last_sync_at)
VALUES ($1, $2, CURRENT_TIMESTAMP)
ON CONFLICT (site_uid) DO UPDATE SET
site_name = EXCLUDED.site_name,
last_sync_at = CURRENT_TIMESTAMP,
updated_at = CURRENT_TIMESTAMP
RETURNING (xmax = 0) as is_new`,
[site.uid, site.name]
);
if (result.rows[0]?.is_new) {
results.rmm.added++;
} else {
results.rmm.updated++;
}
} catch (error) {
results.rmm.errors.push(`Site ${site.uid}: ${error instanceof Error ? error.message : String(error)}`);
}
}
} catch (error) {
results.rmm.errors.push(`Failed to fetch sites: ${error instanceof Error ? error.message : String(error)}`);
}
return NextResponse.json({
success: true,
message: `Synced ${results.auvik.added + results.auvik.updated} Auvik tenants and ${results.rmm.added + results.rmm.updated} RMM sites`,
results,
});
} catch (error) {
console.error('Error syncing tenants and sites:', error);
return NextResponse.json(
{ error: 'Failed to sync tenants and sites' },
{ status: 500 }
);
}
}